structured-field-values
Version:
Implementation of Structured Field Values from IETF httpbis RFC8941
686 lines (626 loc) • 27.3 kB
JavaScript
import assert from "node:assert"
import test from "node:test"
import {
Item,
encodeItem,
encodeList,
encodeDict,
decodeItem,
decodeList,
decodeDict,
serializeList,
// serializeInnerList,
// serializeParams,
serializeKey,
serializeDict,
// serializeItem,
serializeBareItem,
serializeInteger,
serializeDecimal,
serializeString,
serializeToken,
serializeBoolean,
serializeByteSequence,
parseList,
parseItemOrInnerList,
parseInnerList,
parseDictionary,
parseItem,
parseBareItem,
parseParameters,
parseKey,
parseIntegerOrDecimal,
parseString,
parseToken,
parseByteSequence,
parseBoolean,
parseDate,
base64decode,
base64encode,
} from "../index.js"
import {
log,
j,
s,
ss,
read,
format,
formatItem,
formatList,
formatDict,
} from "./test.util.js"
test("test serializeList", () => {
assert.deepStrictEqual(serializeList([1, 2, 3]), "1, 2, 3")
assert.deepStrictEqual(serializeList([]), "")
assert.throws(() => serializeList({}), /failed to serialize "{}" as List/)
})
test("test serializeKey", () => {
assert.deepStrictEqual(serializeKey(`a`), "a")
assert.deepStrictEqual(serializeKey(`*`), "*")
assert.deepStrictEqual(serializeKey(`*-_.*`), "*-_.*")
assert.deepStrictEqual(serializeKey(`****`), "****")
assert.deepStrictEqual(serializeKey(`a*`), "a*")
assert.deepStrictEqual(serializeKey(`a*0-_.*`), "a*0-_.*")
assert.throws(() => serializeKey(`#`), /failed to serialize "#" as Key/)
assert.throws(() => serializeKey(`?`), /failed to serialize "\?" as Key/)
assert.throws(() => serializeKey(0), /failed to serialize "0" as Key/)
})
test("test serializeDict", () => {
assert.deepStrictEqual(serializeDict(new Map()), "")
assert.deepStrictEqual(serializeDict(new Map([["a", 2]])), "a=2")
assert.throws(() => serializeDict(0), /failed to serialize "0" as Dict/)
})
test("test serializeBareItem", () => {
assert.throws(() => serializeBareItem([]), /failed to serialize "\[\]" as Bare Item/)
assert.throws(() => serializeBareItem({}), /failed to serialize "{}" as Bare Item/)
assert.throws(() => serializeBareItem(NaN), /failed to serialize "NaN" as Bare Item/)
assert.throws(() => serializeBareItem(Infinity), /failed to serialize "Infinity" as Bare Item/)
})
test("test serializeInteger", () => {
assert.deepStrictEqual(serializeInteger(0), "0")
assert.deepStrictEqual(serializeInteger(1), "1")
assert.deepStrictEqual(serializeInteger(-1), "-1")
assert.deepStrictEqual(serializeInteger( 999_999_999_999_999), "999999999999999")
assert.deepStrictEqual(serializeInteger(-999_999_999_999_999), "-999999999999999")
assert.throws(() => serializeInteger( 1_000_000_000_000_000), /failed to serialize "1000000000000000" as Integer/)
assert.throws(() => serializeInteger(-1_000_000_000_000_000), /failed to serialize "-1000000000000000" as Integer/)
})
test("test serializeDecimal", () => {
assert.deepStrictEqual(serializeDecimal(0), "0.0")
assert.deepStrictEqual(serializeDecimal(1.0), "1.0")
assert.deepStrictEqual(serializeDecimal(1.01), "1.01")
assert.deepStrictEqual(serializeDecimal(1.0021), "1.002")
assert.deepStrictEqual(serializeDecimal(1.0029), "1.003")
assert.deepStrictEqual(serializeDecimal(1.0025), "1.002")
assert.deepStrictEqual(serializeDecimal(1.0035), "1.004")
assert.deepStrictEqual(serializeDecimal(-1.0035), "-1.004")
assert.deepStrictEqual(serializeDecimal( 999_999_999_999.999), "999999999999.999")
assert.deepStrictEqual(serializeDecimal(-999_999_999_999.999), "-999999999999.999")
assert.throws(() => serializeDecimal( 1_000_000_000_000.0), /failed to serialize "1000000000000" as Decimal/)
assert.throws(() => serializeDecimal(-1_000_000_000_000.0), /failed to serialize "-1000000000000" as Decimal/)
})
test("test serializeString", () => {
assert.deepStrictEqual(serializeString("string"), `"string"`)
assert.deepStrictEqual(serializeString("str\\ing"), `"str\\\\ing"`)
assert.deepStrictEqual(serializeString("str\"ing"), `"str\\"ing"`)
assert.throws(() => serializeString("str\x00ing"), /failed to serialize "str\x00ing" as string/)
assert.throws(() => serializeString("str\x1fing"), /failed to serialize "str\x1fing" as string/)
assert.throws(() => serializeString("str\x7fing"), /failed to serialize "str\x7fing" as string/)
})
test("test serializeToken", () => {
assert.deepStrictEqual(serializeToken(s("token")), `token`)
assert.deepStrictEqual(serializeToken(s(`to!ken`)), `to!ken`)
assert.deepStrictEqual(serializeToken(s(`to#ken`)), `to#ken`)
assert.deepStrictEqual(serializeToken(s(`to$ken`)), `to$ken`)
assert.deepStrictEqual(serializeToken(s(`to%ken`)), `to%ken`)
assert.deepStrictEqual(serializeToken(s(`to&ken`)), `to&ken`)
assert.deepStrictEqual(serializeToken(s(`to'ken`)), `to'ken`)
assert.deepStrictEqual(serializeToken(s(`to*ken`)), `to*ken`)
assert.deepStrictEqual(serializeToken(s(`to+ken`)), `to+ken`)
assert.deepStrictEqual(serializeToken(s(`to-ken`)), `to-ken`)
assert.deepStrictEqual(serializeToken(s(`to.ken`)), `to.ken`)
assert.deepStrictEqual(serializeToken(s(`to^ken`)), `to^ken`)
assert.deepStrictEqual(serializeToken(s(`to_ken`)), `to_ken`)
assert.deepStrictEqual(serializeToken(s('to`ken')), 'to`ken')
assert.deepStrictEqual(serializeToken(s(`to|ken`)), `to|ken`)
assert.deepStrictEqual(serializeToken(s(`to~ken`)), `to~ken`)
assert.deepStrictEqual(serializeToken(s(`towken`)), `towken`)
assert.deepStrictEqual(serializeToken(s(`to:ken`)), `to:ken`)
assert.deepStrictEqual(serializeToken(s(`to/ken`)), `to/ken`)
assert.throws(() => serializeToken(s(`to"ken`)), /failed to serialize "to\"ken" as token/)
assert.throws(() => serializeToken(s(`to(ken`)), /failed to serialize "to\(ken" as token/)
assert.throws(() => serializeToken(s(`to)ken`)), /failed to serialize "to\)ken" as token/)
assert.throws(() => serializeToken(s(`to,ken`)), /failed to serialize "to\,ken" as token/)
assert.throws(() => serializeToken(s(`to;ken`)), /failed to serialize "to\;ken" as token/)
assert.throws(() => serializeToken(s(`to<ken`)), /failed to serialize "to\<ken" as token/)
assert.throws(() => serializeToken(s(`to=ken`)), /failed to serialize "to\=ken" as token/)
assert.throws(() => serializeToken(s(`to>ken`)), /failed to serialize "to\>ken" as token/)
assert.throws(() => serializeToken(s(`to?ken`)), /failed to serialize "to\?ken" as token/)
assert.throws(() => serializeToken(s(`to@ken`)), /failed to serialize "to\@ken" as token/)
assert.throws(() => serializeToken(s(`to[ken`)), /failed to serialize "to\[ken" as token/)
assert.throws(() => serializeToken(s(`to\\ken`)), /failed to serialize "to\\ken" as token/)
assert.throws(() => serializeToken(s(`to]ken`)), /failed to serialize "to\]ken" as token/)
assert.throws(() => serializeToken(s(`to{ken`)), /failed to serialize "to\{ken" as token/)
assert.throws(() => serializeToken(s(`to}ken`)), /failed to serialize "to\}ken" as token/)
})
test("test serializeBoolean", () => {
assert.deepStrictEqual(serializeBoolean(true), `?1`)
assert.deepStrictEqual(serializeBoolean(false), `?0`)
assert.throws(() => serializeBoolean(0), /failed to serialize "0" as boolean/)
assert.throws(() => serializeBoolean(null), /failed to serialize "null" as boolean/)
assert.throws(() => serializeBoolean(undefined), /failed to serialize "undefined" as boolean/)
})
test("test serializeByteSequence", () => {
const value = Uint8Array.from([
112, 114, 101, 116, 101, 110, 100, 32, 116, 104, 105, 115,
32, 105, 115, 32, 98, 105, 110, 97, 114, 121, 32, 99,
111, 110, 116, 101, 110, 116, 46
])
assert.deepStrictEqual(serializeByteSequence(value), `:cHJldGVuZCB0aGlzIGlzIGJpbmFyeSBjb250ZW50Lg==:`)
assert.throws(() => serializeByteSequence([1,2,3]), /failed to serialize "\[1,2,3\]" as Byte Sequence/)
})
test("test decode", () => {
assert.deepStrictEqual(decodeItem(`"a"`), new Item("a"))
assert.deepStrictEqual(decodeItem(`?1`), new Item(true))
assert.deepStrictEqual(decodeItem(`1`), new Item(1))
assert.deepStrictEqual(decodeItem(`a`), new Item(Symbol.for('a')))
assert.deepStrictEqual(decodeItem(`:AQID:`), new Item(new Uint8Array([1, 2, 3])))
assert.deepStrictEqual(decodeItem(`@1659578233`), new Item(new Date(1659578233*1000)))
assert.throws(() => decodeItem(`1;`), (err) => {
assert.deepStrictEqual(err.message, `failed to parse "1;" as Item`)
assert.deepStrictEqual(err.cause.message, `failed to parse "" as Key`)
return true
})
assert.deepStrictEqual(decodeList(``), [])
assert.deepStrictEqual(decodeList(`("foo"; a=1;b=2);lvl=5, ("bar" "baz");lvl=1`), [
new Item([
new Item("foo", { "a": 1, "b": 2 })
], { "lvl": 5 }),
new Item(["bar", "baz"], { "lvl": 1 }),
])
assert.throws(() => decodeList(`1,2,3)`), (err) => {
assert.deepStrictEqual(err.message, `failed to parse "1,2,3)" as List`)
assert.deepStrictEqual(err.cause.message, `failed to parse ")" as List`)
return true
})
assert.throws(() => decodeList(`1,2,`), (err) => {
assert.deepStrictEqual(err.message, `failed to parse "1,2," as List`)
assert.deepStrictEqual(err.cause.message, `failed to parse "" as List`)
return true
})
assert.deepStrictEqual(decodeDict(``), {})
assert.deepStrictEqual(decodeDict(`a=(1 2), b=3, c=4;aa=bb, d=(5 6);valid`), {
"a": new Item([1,2]),
"b": new Item(3),
"c": new Item(4, { "aa": s("bb") }),
"d": new Item([5,6], { "valid": true })
})
assert.throws(() => decodeDict(`a=1, b=2)`), (err) => {
assert.deepStrictEqual(err.message, `failed to parse "a=1, b=2)" as Dict`)
assert.deepStrictEqual(err.cause.message, `failed to parse ")" as Dict`)
return true
})
})
test("test encode_item", () => {
assert.deepStrictEqual(encodeItem("a"), `"a"`)
assert.deepStrictEqual(encodeItem(true), `?1`)
assert.deepStrictEqual(encodeItem(1), `1`)
assert.deepStrictEqual(encodeItem(Symbol.for('a')), `a`)
assert.deepStrictEqual(encodeItem(new Uint8Array([1,2,3])), `:AQID:`)
assert.deepStrictEqual(encodeItem(new Item("a")), `"a"`)
assert.deepStrictEqual(encodeItem(new Item(true)), `?1`)
assert.deepStrictEqual(encodeItem(new Item(1)), `1`)
assert.deepStrictEqual(encodeItem(new Item(Symbol.for('a'))), `a`)
assert.deepStrictEqual(encodeItem(new Item(new Uint8Array([1,2,3]))), `:AQID:`)
assert.deepStrictEqual(encodeItem(new Item(new Date(1659578233000))), `@1659578233`)
assert.throws(() => encodeItem(function(){}), /failed to serialize "function\(\)\{\}" as Bare Item/)
assert.throws(() => encodeItem(() => {}), /failed to serialize "\(\) => \{\}" as Bare Item/)
assert.throws(() => encodeItem(999n), /failed to serialize "999" as Bare Item/)
assert.throws(() => encodeItem([]), /failed to serialize "\[\]" as Bare Item/)
assert.throws(() => encodeItem(new Map()), /failed to serialize "Map{}" as Bare Item/)
assert.throws(() => encodeItem(new Set()), /failed to serialize "Set{}" as Bare Item/)
assert.throws(() => encodeItem(null), /failed to serialize "null" as Bare Item/)
assert.throws(() => encodeItem(undefined), /failed to serialize "undefined" as Bare Item/)
})
test("test encode_list", () => {
assert.deepStrictEqual(encodeList([]), ``)
assert.deepStrictEqual(encodeList([1,2,3]), `1, 2, 3`)
assert.deepStrictEqual(encodeList([
new Item(1),
new Item(2),
new Item(3)
]), `1, 2, 3`)
assert.deepStrictEqual(encodeList([
new Item(1, {a: 2}),
new Item(2, {a: 2}),
new Item(3, {a: 2})
]), `1;a=2, 2;a=2, 3;a=2`)
})
test("test encode_dict", () => {
assert.deepStrictEqual(encodeDict({}), ``)
assert.deepStrictEqual(encodeDict(new Map()), ``)
assert.deepStrictEqual(
encodeDict({
a: 10,
b: 20,
c: 30,
}),
`a=10, b=20, c=30`
)
assert.deepStrictEqual(
encodeDict(new Map([
['a', 10],
['b', 20],
['c', 30],
])),
`a=10, b=20, c=30`
)
assert.deepStrictEqual(
encodeDict({
a: 1,
b: false,
c: "x",
d: Symbol.for("y"),
e: new Uint8Array([1,2,3])
}),
`a=1, b=?0, c="x", d=y, e=:AQID:`
)
assert.deepStrictEqual(
encodeDict({
a: new Item(1),
b: new Item(false),
c: new Item("x"),
d: new Item(Symbol.for("y")),
e: new Item(new Uint8Array([1,2,3])),
}),
`a=1, b=?0, c="x", d=y, e=:AQID:`
)
assert.deepStrictEqual(
encodeDict(new Map([
['a', new Item(1)],
['b', new Item(false)],
['c', new Item("x")],
['d', new Item(Symbol.for("y"))],
['e', new Item(new Uint8Array([1,2,3]))],
])),
`a=1, b=?0, c="x", d=y, e=:AQID:`
)
})
test("test parseIntegerOrDecimal", () => {
assert.deepStrictEqual(parseIntegerOrDecimal(`42`), {value: 42, input_string: ``})
assert.deepStrictEqual(parseIntegerOrDecimal(`-42`), {value: -42, input_string: ``})
assert.deepStrictEqual(parseIntegerOrDecimal(`4.2`), {value: 4.2, input_string: ``})
assert.deepStrictEqual(parseIntegerOrDecimal(`4a`), {value: 4, input_string: `a`})
assert.deepStrictEqual(parseIntegerOrDecimal(`4.5`), {value: 4.5, input_string: ``})
assert.deepStrictEqual(parseIntegerOrDecimal(`-4.5`), {value: -4.5, input_string: ``})
assert.deepStrictEqual(parseIntegerOrDecimal(`4.0`), {value: 4, input_string: ``})
assert.throws(() => parseIntegerOrDecimal(`a`), /failed to parse "a" as Integer or Decimal/)
assert.throws(() => parseIntegerOrDecimal(`-`), /failed to parse "-" as Integer or Decimal/)
assert.throws(() => parseIntegerOrDecimal(`1.`), /failed to parse "1." as Integer or Decimal/)
assert.throws(() => parseIntegerOrDecimal(``), /failed to parse "" as Integer or Decimal/)
// 7.3.1. when decimal and integer length is larger than 12
assert.deepStrictEqual(
parseIntegerOrDecimal(`123456789012.1`),
{value: 123456789012.1, input_string: ``}
)
assert.throws(() => parseIntegerOrDecimal(`1234567890123.1`), /failed to parse "1234567890123.1" as Integer or Decimal/)
// 7.3.5. If type is "integer" and input_number contains more than 15 characters, fail parsing.
assert.deepStrictEqual(
parseIntegerOrDecimal(`123456789012345`),
{value: 123456789012345, input_string: ``}
)
assert.throws(() => parseIntegerOrDecimal(`1234567890123456`), /failed to parse "1234567890123456" as Integer or Decimal/)
// 7.3.6. If type is "decimal" and input_number contains more than 16 characters, fail parsing.
assert.deepStrictEqual(
parseIntegerOrDecimal(`123456789012.456`),
{value: 123456789012.456, input_string: ``}
)
assert.throws(() => parseIntegerOrDecimal(`1234567890123.456`), /failed to parse "1234567890123.456" as Integer or Decimal/)
// 9.2. If the number of characters after "." in input_number is greater than three, fail parsing.
assert.deepStrictEqual(
parseIntegerOrDecimal(`0.123`),
{value: 0.123, input_string: ``}
)
assert.throws(() => parseIntegerOrDecimal(`0.1234`), /failed to parse "0.1234" as Integer or Decimal/)
// 2. If output_number is outside the range -999,999,999,999,999 to 999,999,999,999,999 inclusive, fail parsing.
assert.deepStrictEqual(
parseIntegerOrDecimal(`-999999999999999`),
{value: -999999999999999, input_string: ``}
)
assert.throws(() => parseIntegerOrDecimal(`-999999999999999.1`), /failed to parse "-999999999999999.1" as Integer or Decimal/)
assert.throws(() => parseIntegerOrDecimal(`-1000000000000000`), /failed to parse "-1000000000000000" as Integer or Decimal/)
assert.deepStrictEqual(
parseIntegerOrDecimal(`999999999999999`),
{value: 999999999999999, input_string: ``}
)
assert.throws(() => parseIntegerOrDecimal(`999999999999999.1`), /failed to parse "999999999999999.1" as Integer or Decimal/)
assert.throws(() => parseIntegerOrDecimal(`1000000000000000`), /failed to parse "1000000000000000" as Integer or Decimal/)
})
test("test parseString", () => {
assert.deepStrictEqual(parseString(`"asdf"`), {value: `asdf`, input_string: ``})
assert.deepStrictEqual(parseString(`"!#[]"`), {value: `!#[]`, input_string: ``})
assert.deepStrictEqual(parseString(`"a""`), {value: `a`, input_string: `"`})
assert.deepStrictEqual(parseString(`"a\\\""`), {value: `a"`, input_string: ``})
assert.deepStrictEqual(parseString(`"a\\\\c"`), {value: `a\\c`, input_string: ``})
assert.throws(() => parseString(`"a\\"`), /failed to parse "\"a\\"\" as String/)
assert.throws(() => parseString(`"\\a"`), /failed to parse "\"\\a"\" as String/)
assert.throws(() => parseString(``), /failed to parse "" as String/)
})
test("test parseToken", () => {
assert.deepStrictEqual(parseToken(`*foo123/456`), {value: s(`*foo123/456`), input_string: ``})
assert.deepStrictEqual(parseToken(`foo123;456`), {value: s(`foo123`), input_string: `;456`})
assert.deepStrictEqual(parseToken(`ABC!#$%&'*+-.^_'|~:/012`), {value: s(`ABC!#$%&'*+-.^_'|~:/012`), input_string: ``})
assert.throws(() => parseToken(``), /failed to parse "" as Token/)
})
test("test parseByteSequence", () => {
const value = Uint8Array.from([
112, 114, 101, 116, 101, 110, 100, 32, 116, 104, 105, 115, 32,
105, 115, 32, 98, 105, 110, 97, 114, 121, 32, 99, 111, 110, 116,
101, 110, 116, 46
])
assert.deepStrictEqual(parseByteSequence(`:cHJldGVuZCB0aGlzIGlzIGJpbmFyeSBjb250ZW50Lg==:`), {value, input_string: ``})
assert.throws(() => parseByteSequence(``), /failed to parse "" as Byte Sequence/)
})
test("test parseBoolean", () => {
assert.deepStrictEqual(parseBoolean(`?0`), {value: false, input_string: ``})
assert.deepStrictEqual(parseBoolean(`?1`), {value: true, input_string: ``})
assert.throws(() => parseBoolean(``), /failed to parse "" as Boolean/)
})
test("test parseDate", () => {
assert.deepStrictEqual(parseDate(`@1659578233`), {value: new Date(1659578233000), input_string: ``})
assert.deepStrictEqual(parseDate(`@-1659578233`), {value: new Date('1917-05-30 22:02:47Z'), input_string: ``})
assert.throws(() => parseDate(``), /failed to parse "" as Date/)
})
test("test parseList", () => {
assert.deepStrictEqual(
parseList(`"foo", "bar", "It was the best of times."`),
{ value: [
new Item(`foo`),
new Item(`bar`),
new Item(`It was the best of times.`)
], input_string: ``}
)
assert.deepStrictEqual(
parseList(`foo, bar`),
{ value: [
new Item(s(`foo`)),
new Item(s(`bar`)),
], input_string: ``}
)
assert.deepStrictEqual(
parseList(`1, 1.23, a, "a", ?1, :AQID:, @1659578233`),
{ value: [
new Item(1),
new Item(1.23),
new Item(s("a")),
new Item("a"),
new Item(true),
new Item(new Uint8Array([1, 2, 3])),
new Item(new Date(1659578233*1000))
], input_string: ``}
)
assert.deepStrictEqual(
parseList(`("foo" "bar"), ("baz"), ("bat" "one"), ()`),
{ value: [
new Item(["foo", "bar"]),
new Item(["baz", ]),
new Item(["bat", "one"]),
new Item([])
], input_string: ``}
)
assert.deepStrictEqual(parseList(`("foo"; a=1;b=2);lvl=5, ("bar" "baz");lvl=1`), {value: [
new Item([
new Item("foo", { "a": 1, "b": 2 })
], { "lvl": 5 }),
new Item(["bar", "baz"], { "lvl": 1 }),
], input_string: ``})
assert.throws(() => parseList(`("aaa").`), /failed to parse "." as List/)
assert.throws(() => parseList(`("aaa"),`), /failed to parse "" as List/)
})
test("test parseInnerList", () => {
assert.deepStrictEqual(parseInnerList(`( 1 2 3 )`), {
value: new Item([1, 2, 3]),
input_string: ``
})
assert.deepStrictEqual(parseInnerList(`(1)`), {
value: new Item([1]),
input_string: ``
})
assert.deepStrictEqual(parseInnerList(`()`), {
value: new Item([]),
input_string: ``
})
assert.deepStrictEqual(parseList(`(1 1.23 a "a" ?1 :AQID: @1659578233)`), {
value: [
new Item([
1,
1.23,
s("a"),
"a",
true,
new Uint8Array([1, 2, 3]),
new Date(1659578233*1000)
])
], input_string: ``}
)
assert.throws(() => parseInnerList(`[1 2 3)`), /failed to parse "\[1 2 3\)" as Inner List/)
assert.throws(() => parseInnerList(`(1 2 3]`), /failed to parse "\]" as Inner List/)
assert.throws(() => parseInnerList(`(`), /failed to parse "" as Inner List/)
})
test("test parseDictionary", () => {
assert.deepStrictEqual(parseDictionary(
`int=1, dec=1.23, token=a, str="a", bool=?1, bin=:AQID:, date=@1659578233`
), {
value: {
"int": new Item(1),
"dec": new Item(1.23),
"token": new Item(s("a")),
"str": new Item("a"),
"bool": new Item(true),
"bin": new Item(new Uint8Array([1, 2, 3])),
"date": new Item(new Date(1659578233*1000))
},
input_string: ``
})
assert.deepEqual(parseDictionary(`a=?0, b, c; foo=bar`), {
value: {
"a": new Item(false),
"b": new Item(true),
"c": new Item(true, { "foo": s("bar")}),
},
input_string: ``
})
assert.deepStrictEqual(parseDictionary(`rating=1.5, feelings=(joy sadness)`), {
value: {
"rating": new Item(1.5),
"feelings": new Item([s("joy"), s("sadness")])
},
input_string:``
})
assert.deepStrictEqual(parseDictionary(`a=(1 2), b=3, c=4;aa=bb, d=(5 6);valid`), {
value: {
"a": new Item([1,2]),
"b": new Item(3),
"c": new Item(4, { "aa": s("bb") }),
"d": new Item([5,6], { "valid": true })
},
input_string: ``
})
assert.throws(() => parseDictionary(`a=1&`), /failed to parse "&" as Dict/)
assert.throws(() => parseDictionary(`a=1,`), /failed to parse "" as Dict/)
})
test("test parseItem", () => {
assert.deepStrictEqual(parseItem(`123;a=1;b`), {value: new Item(123, {"a":1, "b":true}), input_string: ``})
assert.throws(() => parseItem(``), /failed to parse "" as Token/)
})
test("test bareItem", () => {
assert.deepStrictEqual(parseBareItem(`"string"`), {value: "string", input_string: ``})
assert.deepStrictEqual(parseBareItem(`123`), {value: 123, input_string: ``})
assert.deepStrictEqual(parseBareItem(`3.14`), {value: 3.14, input_string: ``})
assert.deepStrictEqual(parseBareItem(`?1`), {value: true, input_string: ``})
const binary = new Uint8Array([1,2,3,4,5])
assert.deepStrictEqual(parseBareItem(`:${base64encode(binary)}:`), {value: binary, input_string: ``})
assert.deepStrictEqual(parseBareItem(`token`), {value: s(`token`), input_string: ``})
assert.deepStrictEqual(parseBareItem(`foo123;456`), {value: s(`foo123`), input_string: `;456`})
assert.deepStrictEqual(parseBareItem(`@1659578233`), {value: new Date(1659578233000), input_string: ``})
assert.throws(() => parseBareItem(`&`), /failed to parse "&" as Bare Item/)
})
test("test parseParameters", () => {
assert.deepStrictEqual(parseParameters(`;a=0`), {value: {"a": 0}, input_string: ``})
assert.deepStrictEqual(parseParameters(`;a`), {value: {"a": true}, input_string: ``})
assert.deepStrictEqual(parseParameters(`; a; b=?0`), {value: {"a": true, "b": false}, input_string: ``})
assert.deepStrictEqual(parseParameters(`;a;b=?0;c=10`), {value: {"a": true, "b": false, "c": 10}, input_string: ``})
})
test("test parseKey", () => {
assert.deepStrictEqual(parseKey(`a123_-.*`), {value: `a123_-.*`, input_string: ``})
assert.deepStrictEqual(parseKey(`*a123`), {value: `*a123`, input_string: ``})
assert.throws(() => parseKey(`&`), /failed to parse "&" as Key/)
})
test("structured_field_tests", () => {
const suites = [
...read(`binary`),
...read(`boolean`),
...read(`date`),
...read(`dictionary`),
...read(`examples`),
...read(`item`),
...read(`key-generated`),
...read(`large-generated`),
...read(`list`),
...read(`listlist`),
...read(`number-generated`),
...read(`number`),
...read(`param-dict`),
...read(`param-list`),
...read(`param-listlist`),
...read(`string-generated`),
...read(`string`),
...read(`token-generated`),
...read(`token`),
]
suites.forEach((suite) => {
const ignore = [
// number.json
`negative zero`, // -0 & +0 are no equal in deepStrictEqual
// list.json
`two line list`,
// dictionary.json
`two lines dictionary`,
// param-dict.json
`two lines parameterised list`,
// example.json
`Example-Hdr (list on two lines)`,
`Example-Hdr (dictionary on two lines)`,
]
if (ignore.includes(suite.name)) return
if (suite.name.endsWith("0 decimal")) return // .0 is Integer in JS
// console.debug(suite.name)
try {
if (suite.header_type === `item`) {
// decode
const obj = formatItem(suite.expected)
const decoded = decodeItem(suite.raw[0])
assert.deepStrictEqual(decoded, obj, suite.name)
// encode
const str = suite?.canonical?.[0] || suite.raw[0]
const encoded = encodeItem(obj)
assert.deepStrictEqual(str, encoded, suite.name)
}
if (suite.header_type === `list`) {
// decode
const obj = formatList(suite.expected)
const decoded = decodeList(suite.raw[0])
assert.deepStrictEqual(decoded, obj, suite.name)
// encode
if ([
// 1.0 is 1 in JS
`single item parameterised list`,
`missing parameter value parameterised list`,
`missing terminal parameter value parameterised list`,
].includes(suite.name)) return
const str = suite?.canonical?.[0] || suite.raw[0]
const encoded = encodeList(obj)
assert.deepStrictEqual(str, encoded, suite.name)
}
if (suite.header_type === `dictionary`) {
// decode
const obj = formatDict(suite.expected)
const decoded = decodeDict(suite.raw[0])
assert.deepStrictEqual(decoded, obj, suite.name)
// encode
if ([
// 1.0 is 1 in JS
`single item parameterised dict`,
`list item parameterised dictionary`,
].includes(suite.name)) return
const str = suite?.canonical?.[0] || suite.raw[0]
const encoded = encodeDict(obj)
assert.deepStrictEqual(str, encoded, suite.name)
}
} catch(err) {
assert.deepStrictEqual(suite.must_fail, true, err)
}
})
})
test("serialisation_tests", () => {
const suites = [
...read("serialisation-tests/key-generated"),
...read("serialisation-tests/number"),
...read("serialisation-tests/string-generated"),
...read("serialisation-tests/token-generated"),
]
suites.forEach((suite) => {
// console.debug(suite.name)
try {
if (suite.header_type === `item`) {
// encode
const obj = formatItem(suite.expected)
const encoded = encodeItem(obj)
const str = suite.canonical[0]
assert.deepStrictEqual(str, encoded, suite.name)
}
} catch(err) {
assert.deepStrictEqual(suite.must_fail, true, err)
}
})
})