896 lines
34 KiB
Nim
896 lines
34 KiB
Nim
# json-serialization
|
|
# Copyright (c) 2019-2024 Status Research & Development GmbH
|
|
# Licensed under either of
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
|
# at your option.
|
|
# This file may not be copied, modified, or distributed except according to
|
|
# those terms.
|
|
|
|
import
|
|
faststreams,
|
|
unittest2
|
|
|
|
# we want to test lexer internals
|
|
# hence use include instead of import
|
|
include
|
|
../json_serialization/lexer
|
|
|
|
template testScanInt(input: string, output: untyped, limit: int = 32, error: JsonErrorKind = errNone) =
|
|
var stream = unsafeMemoryInput(input)
|
|
var lex = init(JsonLexer, stream)
|
|
type T = type output
|
|
var value: T
|
|
discard lex.scanInt(value, limit)
|
|
check:
|
|
value == output
|
|
lex.err == error
|
|
|
|
template testScanBool(input: string, expectedOutput: untyped, error: JsonErrorKind = errNone) =
|
|
var stream = unsafeMemoryInput(input)
|
|
var lex = init(JsonLexer, stream)
|
|
check:
|
|
lex.scanBool() == expectedOutput
|
|
lex.err == error
|
|
|
|
template testScanNull(input: string, error: JsonErrorKind = errNone) =
|
|
var stream = unsafeMemoryInput(input)
|
|
var lex = init(JsonLexer, stream)
|
|
lex.scanNull()
|
|
check:
|
|
lex.err == error
|
|
|
|
template testScanString(input: string, output: untyped,
|
|
limit: int = 64,
|
|
error: JsonErrorKind = errNone) =
|
|
var stream = unsafeMemoryInput(input)
|
|
var lex = init(JsonLexer, stream)
|
|
type T = type output
|
|
var value: T
|
|
lex.scanString(value, limit)
|
|
check:
|
|
value == output
|
|
lex.err == error
|
|
|
|
template testScanString(input: string, output: untyped,
|
|
limit: int = 64,
|
|
error: JsonErrorKind = errNone,
|
|
flags: JsonReaderFlags) =
|
|
var stream = unsafeMemoryInput(input)
|
|
var lex = init(JsonLexer, stream, flags)
|
|
type T = type output
|
|
var value: T
|
|
lex.scanString(value, limit)
|
|
check:
|
|
value == output
|
|
lex.err == error
|
|
|
|
template testScanNumber(input: string, output: untyped,
|
|
error: JsonErrorKind = errNone,
|
|
conf: JsonReaderConf = defaultJsonReaderConf) =
|
|
var stream = unsafeMemoryInput(input)
|
|
var lex = init(JsonLexer, stream, defaultJsonReaderFlags, conf)
|
|
type T = type output
|
|
var value: T
|
|
lex.scanNumber(value)
|
|
check:
|
|
value == output
|
|
lex.err == error
|
|
|
|
template testScanNumber(input: string, output: untyped,
|
|
error: JsonErrorKind = errNone,
|
|
conf: JsonReaderConf = defaultJsonReaderConf,
|
|
flags: JsonReaderFlags) =
|
|
var stream = unsafeMemoryInput(input)
|
|
var lex = init(JsonLexer, stream, flags, conf)
|
|
type T = type output
|
|
var value: T
|
|
lex.scanNumber(value)
|
|
check:
|
|
value == output
|
|
lex.err == error
|
|
|
|
template testScanValue(input: string, output: untyped,
|
|
error: JsonErrorKind = errNone,
|
|
conf: JsonReaderConf = defaultJsonReaderConf) =
|
|
var stream = unsafeMemoryInput(input)
|
|
var lex = init(JsonLexer, stream, defaultJsonReaderFlags, conf)
|
|
type T = type output
|
|
var value: T
|
|
lex.scanValue(value)
|
|
check:
|
|
value == output
|
|
lex.err == error
|
|
|
|
template testScanValue(input: string, output: untyped,
|
|
error: JsonErrorKind = errNone,
|
|
conf: JsonReaderConf = defaultJsonReaderConf,
|
|
flags: JsonReaderFlags) =
|
|
var stream = unsafeMemoryInput(input)
|
|
var lex = init(JsonLexer, stream, flags, conf)
|
|
type T = type output
|
|
var value: T
|
|
lex.scanValue(value)
|
|
check:
|
|
value == output
|
|
lex.err == error
|
|
|
|
suite "lexer test suite":
|
|
test "scanInt string":
|
|
testScanInt("1234567890", "1234567890")
|
|
testScanInt("01234567890", "0", error = errLeadingZero)
|
|
testScanInt("0", "0")
|
|
testScanInt("0a1234567890", "0")
|
|
testScanInt("00", "0", error = errLeadingZero)
|
|
|
|
testScanInt("1234", "123", limit = 3, error = errIntDigitLimit)
|
|
testScanInt("01234", "0", limit = 3, error = errLeadingZero)
|
|
|
|
test "scanInt uint64":
|
|
testScanInt("1234567890", 1234567890'u64)
|
|
testScanInt("01234567890", 0'u64, error = errLeadingZero)
|
|
testScanInt("0", 0'u64)
|
|
testScanInt("0a1234567890", 0'u64)
|
|
testScanInt("00", 0'u64, error = errLeadingZero)
|
|
|
|
testScanInt("18446744073709551615", 18446744073709551615'u64)
|
|
testScanInt("18446744073709551616", 18446744073709551615'u64, error = errU64Overflow)
|
|
|
|
testScanInt("1234", 123'u64, limit = 3, error = errIntDigitLimit)
|
|
|
|
test "scanInt JsonVoid":
|
|
testScanInt("1234567890", JsonVoid())
|
|
testScanInt("01234567890", JsonVoid(), error = errLeadingZero)
|
|
testScanInt("0", JsonVoid())
|
|
testScanInt("0a1234567890", JsonVoid())
|
|
testScanInt("00", JsonVoid(), error = errLeadingZero)
|
|
|
|
testScanInt("18446744073709551615", JsonVoid())
|
|
testScanInt("18446744073709551616", JsonVoid())
|
|
|
|
testScanInt("1234", JsonVoid(), limit = 3, error = errIntDigitLimit)
|
|
|
|
test "scanBool":
|
|
testScanBool("true", true)
|
|
testScanBool("false", false)
|
|
|
|
testScanBool("trur", false, error = errInvalidBool)
|
|
testScanBool("t", false, error = errInvalidBool)
|
|
testScanBool("tr", false, error = errInvalidBool)
|
|
testScanBool("tru", false, error = errInvalidBool)
|
|
|
|
testScanBool("f", false, error = errInvalidBool)
|
|
testScanBool("fa", false, error = errInvalidBool)
|
|
testScanBool("fal", false, error = errInvalidBool)
|
|
testScanBool("fals", false, error = errInvalidBool)
|
|
|
|
test "scanNull":
|
|
testScanNull("null")
|
|
testScanNull("n", error = errInvalidNull)
|
|
testScanNull("nu", error = errInvalidNull)
|
|
testScanNull("nul", error = errInvalidNull)
|
|
|
|
test "scanString unicode":
|
|
testScanString("\"\\u0\"", "", error = errHexCharExpected)
|
|
testScanString("\"\\u111\"", "", error = errHexCharExpected)
|
|
testScanString("\"\\U0", "", error = errRelaxedEscape)
|
|
testScanString("\"\\x00\"", "", error = errEscapeHex)
|
|
testScanString("\"\\u0011\"", "\x11")
|
|
|
|
## surrogate pair
|
|
testScanString("\"\\uD800\"", "", error = errOrphanSurrogate)
|
|
testScanString("\"\\uDFFF\"", "\uDFFF")
|
|
testScanString("\"\\uD7FF\"", "\uD7FF")
|
|
testScanString("\"\\uE000\"", "\uE000")
|
|
testScanString("\"\\u0000\"", "\x00")
|
|
|
|
testScanString("\"\\u111\"", "", error = errHexCharExpected)
|
|
|
|
testScanString("\"\\7\"", "7", flags = {JsonReaderFlag.relaxedEscape})
|
|
testScanString("\"\\x12\"", "\x12", flags = {JsonReaderFlag.escapeHex})
|
|
|
|
testScanString("\"\\7\\x12ab\"", "7\x12a",
|
|
limit = 3,
|
|
flags = {JsonReaderFlag.relaxedEscape, JsonReaderFlag.escapeHex},
|
|
error = errStringLengthLimit)
|
|
|
|
test "scanString basic":
|
|
testScanString("\"\"", "")
|
|
testScanString("\"hello\"", "hello")
|
|
testScanString("\"hel\\nlo\"", "hel\nlo")
|
|
|
|
testScanString("\"he\nllo\"", "he", error = errQuoteExpected)
|
|
testScanString("\"hello", "hello", error = errUnexpectedEof)
|
|
|
|
|
|
testScanString("\"hello\\uD7FF\"", "hello\uD7FF")
|
|
testScanString("\"\\\"\\\\\\b\\f\\n\\r\\t\"", "\"\\\b\f\n\r\t")
|
|
|
|
testScanString("\"Обычный текст в кодировке UTF-8\"",
|
|
"Обычный текст в кодировке UTF-8")
|
|
|
|
test "scanString unicode JsonVoid":
|
|
testScanString("\"\\u0\"", JsonVoid(), error = errHexCharExpected)
|
|
testScanString("\"\\u111\"", JsonVoid(), error = errHexCharExpected)
|
|
testScanString("\"\\U0", JsonVoid(), error = errRelaxedEscape)
|
|
testScanString("\"\\x00\"", JsonVoid(), error = errEscapeHex)
|
|
testScanString("\"\\u0011\"", JsonVoid())
|
|
|
|
# surrogate pair
|
|
testScanString("\"\\uD800\"", JsonVoid(), error = errOrphanSurrogate)
|
|
testScanString("\"\\uDFFF\"", JsonVoid())
|
|
testScanString("\"\\uD7FF\"", JsonVoid())
|
|
testScanString("\"\\uE000\"", JsonVoid())
|
|
testScanString("\"\\u0000\"", JsonVoid())
|
|
|
|
testScanString("\"\\u111\"", JsonVoid(), error = errHexCharExpected)
|
|
|
|
testScanString("\"\\7\"", JsonVoid(), flags = {JsonReaderFlag.relaxedEscape})
|
|
testScanString("\"\\x12\"", JsonVoid(), flags = {JsonReaderFlag.escapeHex})
|
|
|
|
testScanString("\"\\7\\x12ab\"", JsonVoid(),
|
|
limit = 3,
|
|
flags = {JsonReaderFlag.relaxedEscape, JsonReaderFlag.escapeHex},
|
|
error = errStringLengthLimit)
|
|
|
|
test "scanString basic JsonVoid":
|
|
testScanString("\"\"", JsonVoid())
|
|
testScanString("\"hello\"", JsonVoid())
|
|
testScanString("\"hel\\nlo\"", JsonVoid())
|
|
|
|
testScanString("\"he\nllo\"", JsonVoid(), error = errQuoteExpected)
|
|
testScanString("\"hello", JsonVoid(), error = errUnexpectedEof)
|
|
|
|
|
|
testScanString("\"hello\\uD7FF\"", JsonVoid())
|
|
testScanString("\"\\\"\\\\\\b\\f\\n\\r\\t\"", JsonVoid())
|
|
|
|
testScanString("\"Обычный текст в кодировке UTF-8\"", JsonVoid())
|
|
|
|
test "scanNumber integer part string":
|
|
testScanNumber("0", "0")
|
|
testScanNumber("+0", "+0")
|
|
testScanNumber("-0", "-0")
|
|
|
|
testScanNumber("+", "+", error = errNumberExpected)
|
|
testScanNumber("-", "-", error = errNumberExpected)
|
|
|
|
testScanNumber("+a", "+", error = errNumberExpected)
|
|
testScanNumber("-b", "-", error = errNumberExpected)
|
|
|
|
testScanNumber("01", "0", error = errLeadingZero)
|
|
testScanNumber("+01", "+0", error = errLeadingZero)
|
|
testScanNumber("-01", "-0", error = errLeadingZero)
|
|
|
|
testScanNumber("1234", "1234")
|
|
|
|
var conf = defaultJsonReaderConf
|
|
conf.integerDigitsLimit = 3
|
|
testScanNumber("1234", "123", error = errIntDigitLimit, conf = conf)
|
|
|
|
test "scanNumber fractional part string":
|
|
testScanNumber("0.0", "0.0")
|
|
testScanNumber("+0.1", "+0.1")
|
|
testScanNumber("-0.2", "-0.2")
|
|
|
|
testScanNumber(".1", "", flags = {}, error = errLeadingFraction)
|
|
testScanNumber(".1", ".1")
|
|
|
|
var conf = defaultJsonReaderConf
|
|
conf.fractionDigitsLimit = 3
|
|
testScanNumber(".1234", ".123", error = errFracDigitLimit, conf = conf)
|
|
|
|
testScanNumber("1234.5555", "1234.5555")
|
|
|
|
conf = defaultJsonReaderConf
|
|
conf.fractionDigitsLimit = 3
|
|
testScanNumber("1234.1234", "1234.123", error = errFracDigitLimit, conf = conf)
|
|
|
|
test "scanNumber exponent part string":
|
|
testScanNumber("0.0E1", "0.0E1")
|
|
testScanNumber("+0.1e2", "+0.1e2")
|
|
testScanNumber("-0.2e9", "-0.2e9")
|
|
|
|
testScanNumber("0.0E-1", "0.0E-1")
|
|
testScanNumber("+0.1e-2", "+0.1e-2")
|
|
testScanNumber("-0.2e-9", "-0.2e-9")
|
|
|
|
testScanNumber("0.0E+1", "0.0E+1")
|
|
testScanNumber("+0.1e+2", "+0.1e+2")
|
|
testScanNumber("-0.2e+9", "-0.2e+9")
|
|
|
|
testScanNumber("0.0E", "0.0E", error = errNumberExpected)
|
|
testScanNumber("+0.1e", "+0.1e", error = errNumberExpected)
|
|
testScanNumber("-0.2e", "-0.2e", error = errNumberExpected)
|
|
|
|
testScanNumber("0.0E-", "0.0E-", error = errNumberExpected)
|
|
testScanNumber("+0.1e+", "+0.1e+", error = errNumberExpected)
|
|
testScanNumber("-0.2e+", "-0.2e+", error = errNumberExpected)
|
|
|
|
var conf = defaultJsonReaderConf
|
|
conf.exponentDigitsLimit = 3
|
|
testScanNumber("-0.2e+1234", "-0.2e+123", error = errExpDigitLimit, conf = conf)
|
|
|
|
test "scanNumber integer part JsonVoid":
|
|
testScanNumber("0", JsonVoid())
|
|
testScanNumber("+0", JsonVoid())
|
|
testScanNumber("-0", JsonVoid())
|
|
|
|
testScanNumber("+", JsonVoid(), error = errNumberExpected)
|
|
testScanNumber("-", JsonVoid(), error = errNumberExpected)
|
|
|
|
testScanNumber("+a", JsonVoid(), error = errNumberExpected)
|
|
testScanNumber("-b", JsonVoid(), error = errNumberExpected)
|
|
|
|
testScanNumber("01", JsonVoid(), error = errLeadingZero)
|
|
testScanNumber("+01", JsonVoid(), error = errLeadingZero)
|
|
testScanNumber("-01", JsonVoid(), error = errLeadingZero)
|
|
|
|
testScanNumber("1234", JsonVoid())
|
|
|
|
var conf = defaultJsonReaderConf
|
|
conf.integerDigitsLimit = 3
|
|
testScanNumber("1234", JsonVoid(), error = errIntDigitLimit, conf = conf)
|
|
|
|
test "scanNumber fractional part JsonVoid":
|
|
testScanNumber("0.0", JsonVoid())
|
|
testScanNumber("+0.1", JsonVoid())
|
|
testScanNumber("-0.2", JsonVoid())
|
|
|
|
testScanNumber(".1", JsonVoid(), flags = {}, error = errLeadingFraction)
|
|
testScanNumber(".1", JsonVoid())
|
|
|
|
var conf = defaultJsonReaderConf
|
|
conf.fractionDigitsLimit = 3
|
|
testScanNumber(".1234", JsonVoid(), error = errFracDigitLimit, conf = conf)
|
|
|
|
testScanNumber("1234.5555", JsonVoid())
|
|
|
|
conf = defaultJsonReaderConf
|
|
conf.fractionDigitsLimit = 3
|
|
testScanNumber("1234.1234", JsonVoid(), error = errFracDigitLimit, conf = conf)
|
|
|
|
test "scanNumber exponent part JsonVoid":
|
|
testScanNumber("0.0E1", JsonVoid())
|
|
testScanNumber("+0.1e2", JsonVoid())
|
|
testScanNumber("-0.2e9", JsonVoid())
|
|
|
|
testScanNumber("0.0E-1", JsonVoid())
|
|
testScanNumber("+0.1e-2", JsonVoid())
|
|
testScanNumber("-0.2e-9", JsonVoid())
|
|
|
|
testScanNumber("0.0E+1", JsonVoid())
|
|
testScanNumber("+0.1e+2", JsonVoid())
|
|
testScanNumber("-0.2e+9", JsonVoid())
|
|
|
|
testScanNumber("0.0E", JsonVoid(), error = errNumberExpected)
|
|
testScanNumber("+0.1e", JsonVoid(), error = errNumberExpected)
|
|
testScanNumber("-0.2e", JsonVoid(), error = errNumberExpected)
|
|
|
|
testScanNumber("0.0E-", JsonVoid(), error = errNumberExpected)
|
|
testScanNumber("+0.1e+", JsonVoid(), error = errNumberExpected)
|
|
testScanNumber("-0.2e+", JsonVoid(), error = errNumberExpected)
|
|
|
|
var conf = defaultJsonReaderConf
|
|
conf.exponentDigitsLimit = 3
|
|
testScanNumber("-0.2e+1234", JsonVoid(), error = errExpDigitLimit, conf = conf)
|
|
|
|
test "scanNumber integer part JsonNumber[string]":
|
|
testScanNumber("0", JsonNumber[string](integer: "0"))
|
|
testScanNumber("+0", JsonNumber[string](sign: JsonSign.Pos, integer: "0"))
|
|
testScanNumber("-0", JsonNumber[string](sign: JsonSign.Neg, integer: "0"))
|
|
|
|
testScanNumber("+", JsonNumber[string](sign: JsonSign.Pos), error = errNumberExpected)
|
|
testScanNumber("-", JsonNumber[string](sign: JsonSign.Neg), error = errNumberExpected)
|
|
|
|
testScanNumber("+a", JsonNumber[string](sign: JsonSign.Pos), error = errNumberExpected)
|
|
testScanNumber("-b", JsonNumber[string](sign: JsonSign.Neg), error = errNumberExpected)
|
|
|
|
testScanNumber("01", JsonNumber[string](integer: "0"), error = errLeadingZero)
|
|
testScanNumber("+01", JsonNumber[string](sign: JsonSign.Pos,
|
|
integer: "0"), error = errLeadingZero)
|
|
testScanNumber("-01", JsonNumber[string](sign: JsonSign.Neg,
|
|
integer: "0"), error = errLeadingZero)
|
|
|
|
testScanNumber("1234", JsonNumber[string](integer: "1234"))
|
|
|
|
var conf = defaultJsonReaderConf
|
|
conf.integerDigitsLimit = 3
|
|
testScanNumber("1234", JsonNumber[string](integer: "123"),
|
|
error = errIntDigitLimit, conf = conf)
|
|
|
|
test "scanNumber fractional part JsonNumber[string]":
|
|
testScanNumber("0.0", JsonNumber[string](integer: "0", fraction: "0"))
|
|
testScanNumber("+0.1", JsonNumber[string](sign: JsonSign.Pos, integer: "0", fraction: "1"))
|
|
testScanNumber("-0.2", JsonNumber[string](sign: JsonSign.Neg, integer: "0", fraction: "2"))
|
|
|
|
testScanNumber(".1", JsonNumber[string](), flags = {}, error = errLeadingFraction)
|
|
testScanNumber(".1", JsonNumber[string](fraction: "1"))
|
|
|
|
var conf = defaultJsonReaderConf
|
|
conf.fractionDigitsLimit = 3
|
|
testScanNumber(".1234", JsonNumber[string](fraction: "123"),
|
|
error = errFracDigitLimit, conf = conf)
|
|
|
|
testScanNumber("1234.5555", JsonNumber[string](integer: "1234", fraction: "5555"))
|
|
|
|
conf = defaultJsonReaderConf
|
|
conf.fractionDigitsLimit = 3
|
|
testScanNumber("1234.1234", JsonNumber[string](integer: "1234", fraction: "123"),
|
|
error = errFracDigitLimit, conf = conf)
|
|
|
|
test "scanNumber exponent part JsonNumber[string]":
|
|
testScanNumber("0.0E1", JsonNumber[string](integer: "0", fraction: "0", exponent: "1"))
|
|
testScanNumber("+0.1e2", JsonNumber[string](sign: JsonSign.Pos,
|
|
integer: "0", fraction: "1", exponent: "2"))
|
|
testScanNumber("-0.2e9", JsonNumber[string](sign: JsonSign.Neg,
|
|
integer: "0", fraction: "2", exponent: "9"))
|
|
|
|
testScanNumber("0.0E-1", JsonNumber[string](integer: "0", fraction: "0",
|
|
expSign: JsonSign.Neg, exponent: "1"))
|
|
testScanNumber("+0.1e-2", JsonNumber[string](sign: JsonSign.Pos,
|
|
integer: "0", fraction: "1", expSign: JsonSign.Neg, exponent: "2"))
|
|
testScanNumber("-0.2e-9", JsonNumber[string](sign: JsonSign.Neg,
|
|
integer: "0", fraction: "2", expSign: JsonSign.Neg, exponent: "9"))
|
|
|
|
testScanNumber("0.0E+1", JsonNumber[string](integer: "0",
|
|
fraction: "0", expSign: JsonSign.Pos, exponent: "1"))
|
|
testScanNumber("+0.1e+2", JsonNumber[string](sign: JsonSign.Pos,
|
|
integer: "0", fraction: "1", expSign: JsonSign.Pos, exponent: "2"))
|
|
testScanNumber("-0.2e+9", JsonNumber[string](sign: JsonSign.Neg,
|
|
integer: "0", fraction: "2", expSign: JsonSign.Pos, exponent: "9"))
|
|
|
|
testScanNumber("0.0E", JsonNumber[string](integer: "0", fraction: "0"),
|
|
error = errNumberExpected)
|
|
testScanNumber("+0.1e", JsonNumber[string](sign: JsonSign.Pos,
|
|
integer: "0", fraction: "1"), error = errNumberExpected)
|
|
testScanNumber("-0.2e", JsonNumber[string](sign: JsonSign.Neg,
|
|
integer: "0", fraction: "2"), error = errNumberExpected)
|
|
|
|
testScanNumber("0.0E-", JsonNumber[string](integer: "0", fraction: "0",
|
|
expSign: JsonSign.Neg), error = errNumberExpected)
|
|
testScanNumber("+0.1e+", JsonNumber[string](sign: JsonSign.Pos,
|
|
integer: "0", fraction: "1", expSign: JsonSign.Pos), error = errNumberExpected)
|
|
testScanNumber("-0.2e+", JsonNumber[string](sign: JsonSign.Neg,
|
|
integer: "0", fraction: "2", expSign: JsonSign.Pos), error = errNumberExpected)
|
|
|
|
var conf = defaultJsonReaderConf
|
|
conf.exponentDigitsLimit = 3
|
|
testScanNumber("-0.2e+1234", JsonNumber[string](sign: JsonSign.Neg,
|
|
integer: "0", fraction: "2", expSign: JsonSign.Pos, exponent: "123"),
|
|
error = errExpDigitLimit, conf = conf)
|
|
|
|
test "scanNumber integer part JsonNumber[uint64]":
|
|
testScanNumber("0", JsonNumber[uint64](integer: 0))
|
|
testScanNumber("+0", JsonNumber[uint64](sign: JsonSign.Pos, integer: 0))
|
|
testScanNumber("-0", JsonNumber[uint64](sign: JsonSign.Neg, integer: 0))
|
|
|
|
testScanNumber("+", JsonNumber[uint64](sign: JsonSign.Pos), error = errNumberExpected)
|
|
testScanNumber("-", JsonNumber[uint64](sign: JsonSign.Neg), error = errNumberExpected)
|
|
|
|
testScanNumber("+a", JsonNumber[uint64](sign: JsonSign.Pos), error = errNumberExpected)
|
|
testScanNumber("-b", JsonNumber[uint64](sign: JsonSign.Neg), error = errNumberExpected)
|
|
|
|
testScanNumber("01", JsonNumber[uint64](integer: 0), error = errLeadingZero)
|
|
testScanNumber("+01", JsonNumber[uint64](sign: JsonSign.Pos,
|
|
integer: 0), error = errLeadingZero)
|
|
testScanNumber("-01", JsonNumber[uint64](sign: JsonSign.Neg,
|
|
integer: 0), error = errLeadingZero)
|
|
|
|
testScanNumber("1234", JsonNumber[uint64](integer: 1234))
|
|
|
|
var conf = defaultJsonReaderConf
|
|
conf.integerDigitsLimit = 3
|
|
testScanNumber("1234", JsonNumber[uint64](integer: 123),
|
|
error = errIntDigitLimit, conf = conf)
|
|
|
|
test "scanNumber fractional part JsonNumber[uint64]":
|
|
testScanNumber("3.0", JsonNumber[uint64](integer: 3, fraction: "0"))
|
|
testScanNumber("+3.1", JsonNumber[uint64](sign: JsonSign.Pos,
|
|
integer: 3, fraction: "1"))
|
|
testScanNumber("-3.2", JsonNumber[uint64](sign: JsonSign.Neg,
|
|
integer: 3, fraction: "2"))
|
|
|
|
testScanNumber(".1", JsonNumber[uint64](), flags = {}, error = errLeadingFraction)
|
|
testScanNumber(".1", JsonNumber[uint64](fraction: "1"))
|
|
|
|
var conf = defaultJsonReaderConf
|
|
conf.fractionDigitsLimit = 4
|
|
testScanNumber(".12345", JsonNumber[uint64](fraction: "1234"),
|
|
error = errFracDigitLimit, conf = conf)
|
|
|
|
testScanNumber("1234.5555", JsonNumber[uint64](integer: 1234, fraction: "5555"))
|
|
|
|
conf = defaultJsonReaderConf
|
|
conf.fractionDigitsLimit = 3
|
|
testScanNumber("1234.1234", JsonNumber[uint64](integer: 1234, fraction: "123"),
|
|
error = errFracDigitLimit, conf = conf)
|
|
|
|
test "scanNumber exponent part JsonNumber[uint64]":
|
|
testScanNumber("4.0E1", JsonNumber[uint64](integer: 4, fraction: "0", exponent: 1))
|
|
testScanNumber("+4.1e2", JsonNumber[uint64](sign: JsonSign.Pos,
|
|
integer: 4, fraction: "1", exponent: 2))
|
|
testScanNumber("-4.2e9", JsonNumber[uint64](sign: JsonSign.Neg,
|
|
integer: 4, fraction: "2", exponent: 9))
|
|
|
|
testScanNumber("0.0E-1", JsonNumber[uint64](integer: 0, fraction: "0",
|
|
expSign: JsonSign.Neg, exponent: 1))
|
|
testScanNumber("+0.1e-2", JsonNumber[uint64](sign: JsonSign.Pos,
|
|
integer: 0, fraction: "1", expSign: JsonSign.Neg, exponent: 2))
|
|
testScanNumber("-0.2e-9", JsonNumber[uint64](sign: JsonSign.Neg,
|
|
integer: 0, fraction: "2", expSign: JsonSign.Neg, exponent: 9))
|
|
|
|
testScanNumber("0.0E+1", JsonNumber[uint64](integer: 0, fraction: "0",
|
|
expSign: JsonSign.Pos, exponent: 1))
|
|
testScanNumber("+0.1e+2", JsonNumber[uint64](sign: JsonSign.Pos,
|
|
integer: 0, fraction: "1", expSign: JsonSign.Pos, exponent: 2))
|
|
testScanNumber("-0.2e+9", JsonNumber[uint64](sign: JsonSign.Neg,
|
|
integer: 0, fraction: "2", expSign: JsonSign.Pos, exponent: 9))
|
|
|
|
testScanNumber("0.0E", JsonNumber[uint64](integer: 0, fraction: "0"),
|
|
error = errNumberExpected)
|
|
testScanNumber("+0.1e", JsonNumber[uint64](sign: JsonSign.Pos,
|
|
integer: 0, fraction: "1"), error = errNumberExpected)
|
|
testScanNumber("-0.2e", JsonNumber[uint64](sign: JsonSign.Neg,
|
|
integer: 0, fraction: "2"), error = errNumberExpected)
|
|
|
|
testScanNumber("0.0E-", JsonNumber[uint64](integer: 0, fraction: "0",
|
|
expSign: JsonSign.Neg), error = errNumberExpected)
|
|
testScanNumber("+0.1e+", JsonNumber[uint64](sign: JsonSign.Pos,
|
|
integer: 0, fraction: "1", expSign: JsonSign.Pos), error = errNumberExpected)
|
|
testScanNumber("-0.2e+", JsonNumber[uint64](sign: JsonSign.Neg,
|
|
integer: 0, fraction: "2", expSign: JsonSign.Pos), error = errNumberExpected)
|
|
|
|
var conf = defaultJsonReaderConf
|
|
conf.exponentDigitsLimit = 5
|
|
testScanNumber("-0.2e+123456", JsonNumber[uint64](sign: JsonSign.Neg,
|
|
integer: 0, fraction: "2", expSign: JsonSign.Pos, exponent: 12345),
|
|
error = errExpDigitLimit, conf = conf)
|
|
|
|
test "scanValue string":
|
|
testScanValue("\"hello world\"", "\"hello world\"")
|
|
testScanValue("-0.2e+9", "-0.2e+9")
|
|
testScanValue("true", "true")
|
|
testScanValue("false", "false")
|
|
testScanValue("null", "null")
|
|
testScanValue("[\"abc\", 1234.456, true, false , null ]",
|
|
"[\"abc\",1234.456,true,false,null]")
|
|
testScanValue("""{ "apple" : 1 , "banana" : true }""",
|
|
"""{"apple":1,"banana":true}""")
|
|
|
|
testScanValue("b", "", error = errUnknownChar)
|
|
testScanValue("[,", "[", error = errMissingFirstElement)
|
|
testScanValue("{,", "{", error = errMissingFirstElement)
|
|
|
|
testScanValue("[,", "[", error = errMissingFirstElement,
|
|
flags = {JsonReaderFlag.trailingComma})
|
|
testScanValue("{,", "{", error = errMissingFirstElement,
|
|
flags = {JsonReaderFlag.trailingComma})
|
|
|
|
testScanValue("{\"a\":1,}", "{\"a\":1", flags = {}, error = errTrailingComma)
|
|
testScanValue("[1,]", "[1", flags = {}, error = errTrailingComma)
|
|
|
|
testScanValue("{\"a\":1,}", "{\"a\":1}")
|
|
testScanValue("[1,]", "[1]")
|
|
|
|
testScanValue("[]", "[]")
|
|
testScanValue("{}", "{}")
|
|
|
|
var conf = defaultJsonReaderConf
|
|
conf.arrayElementsLimit = 3
|
|
conf.objectMembersLimit = 3
|
|
|
|
testScanValue("[1,2,3,4]", "[1,2,3,", error = errArrayElementsLimit, conf = conf)
|
|
testScanValue("{\"a\":1, \"b\":2, \"C\":3, \"d\": 4}",
|
|
"{\"a\":1,\"b\":2,\"C\":3,", error = errObjectMembersLimit, conf = conf)
|
|
|
|
testScanValue("[[[1]]]", "[[[1]]]")
|
|
|
|
conf.nestedDepthLimit = 3
|
|
testScanValue("[[[[1]]]]", "[[[", error = errNestedDepthLimit, conf = conf)
|
|
testScanValue("[ { \"a\": [ { \"b\": 3}] } ]", "[{\"a\":[",
|
|
error = errNestedDepthLimit, conf = conf)
|
|
|
|
testScanValue("{ \"a\": 1234.567 // comments\n }",
|
|
"{\"a\":1234.567", flags = {}, error = errCommentNotAllowed)
|
|
testScanValue("{ \"a\": 1234.567 // comments\n }",
|
|
"{\"a\":1234.567}")
|
|
|
|
test "scanValue JsonVoid":
|
|
testScanValue("\"hello world\"", JsonVoid())
|
|
testScanValue("-0.2e+9", JsonVoid())
|
|
testScanValue("true", JsonVoid())
|
|
testScanValue("false", JsonVoid())
|
|
testScanValue("null", JsonVoid())
|
|
testScanValue("[\"abc\", 1234.456, true, false , null ]", JsonVoid())
|
|
testScanValue("""{ "apple" : 1 , "banana" : true }""", JsonVoid())
|
|
|
|
testScanValue("b", JsonVoid(), error = errUnknownChar)
|
|
testScanValue("[,", JsonVoid(), error = errMissingFirstElement)
|
|
testScanValue("{,", JsonVoid(), error = errMissingFirstElement)
|
|
|
|
testScanValue("[,", JsonVoid(), error = errMissingFirstElement,
|
|
flags = {JsonReaderFlag.trailingComma})
|
|
testScanValue("{,", JsonVoid(), error = errMissingFirstElement,
|
|
flags = {JsonReaderFlag.trailingComma})
|
|
|
|
testScanValue("{\"a\":1,}", JsonVoid(), flags = {}, error = errTrailingComma)
|
|
testScanValue("[1,]", JsonVoid(), flags = {}, error = errTrailingComma)
|
|
|
|
testScanValue("{\"a\":1,}", JsonVoid())
|
|
testScanValue("[1,]", JsonVoid())
|
|
|
|
testScanValue("[]", JsonVoid())
|
|
testScanValue("{}", JsonVoid())
|
|
|
|
var conf = defaultJsonReaderConf
|
|
conf.arrayElementsLimit = 3
|
|
conf.objectMembersLimit = 3
|
|
|
|
testScanValue("[1,2,3,4]", JsonVoid(), error = errArrayElementsLimit, conf = conf)
|
|
testScanValue("{\"a\":1, \"b\":2, \"C\":3, \"d\": 4}",
|
|
JsonVoid(), error = errObjectMembersLimit, conf = conf)
|
|
|
|
testScanValue("[[[1]]]", JsonVoid())
|
|
|
|
conf.nestedDepthLimit = 3
|
|
testScanValue("[[[[1]]]]", JsonVoid(), error = errNestedDepthLimit, conf = conf)
|
|
testScanValue("[ { \"a\": [ { \"b\": 3}] } ]",
|
|
JsonVoid(), error = errNestedDepthLimit, conf = conf)
|
|
|
|
testScanValue("{ \"a\": 1234.567 // comments\n }",
|
|
JsonVoid(), flags = {}, error = errCommentNotAllowed)
|
|
testScanValue("{ \"a\": 1234.567 // comments\n }",
|
|
JsonVoid())
|
|
|
|
testScanValue("{ \"a\": 1234.567 /* comments */ }",
|
|
JsonVoid(), flags = {}, error = errCommentNotAllowed)
|
|
testScanValue("{ \"a\": 1234.567 /* comments */ }",
|
|
JsonVoid())
|
|
|
|
test "scanValue JsonValueRef[uint64]":
|
|
proc jsonString(x: string): JsonValueRef[uint64] =
|
|
JsonValueRef[uint64](kind: JsonValueKind.String, strVal: x)
|
|
|
|
proc jsonNumber(sign: JsonSign, integer: uint64,
|
|
fraction: string, expSign: JsonSign, exponent: uint64): JsonValueRef[uint64] =
|
|
JsonValueRef[uint64](kind: JsonValueKind.Number,
|
|
numVal: JsonNumber[uint64](
|
|
sign: sign,
|
|
integer: integer,
|
|
fraction: fraction,
|
|
expSign: expSign,
|
|
exponent: exponent
|
|
)
|
|
)
|
|
|
|
proc jsonNumber(integer: uint64, fraction: string = ""): JsonValueRef[uint64] =
|
|
JsonValueRef[uint64](kind: JsonValueKind.Number,
|
|
numVal: JsonNumber[uint64](
|
|
integer: integer,
|
|
fraction: fraction,
|
|
)
|
|
)
|
|
|
|
proc jsonBool(x: bool): JsonValueRef[uint64] =
|
|
JsonValueRef[uint64](kind: JsonValueKind.Bool, boolVal: x)
|
|
|
|
proc jsonNull(): JsonValueRef[uint64] =
|
|
JsonValueRef[uint64](kind: JsonValueKind.Null)
|
|
|
|
testScanValue("\"hello world\"", jsonString("hello world"))
|
|
testScanValue("-0.2e+9", jsonNumber(JsonSign.Neg, 0, "2", JsonSign.Pos, 9))
|
|
|
|
testScanValue("true", jsonBool(true))
|
|
testScanValue("false", jsonBool(false))
|
|
testScanValue("null", jsonNull())
|
|
|
|
testScanValue("[\"abc\", 1234.456, true, false , null ]",
|
|
JsonValueRef[uint64](kind: JsonValueKind.Array, arrayVal: @[
|
|
jsonString("abc"),
|
|
jsonNumber(1234, "456"),
|
|
jsonBool(true),
|
|
jsonBool(false),
|
|
jsonNull(),
|
|
]))
|
|
|
|
|
|
testScanValue("""{ "apple" : "hello" , "banana" : true }""",
|
|
JsonValueRef[uint64](kind: JsonValueKind.Object,
|
|
objVal: [
|
|
("apple", jsonString("hello")),
|
|
("banana", jsonBool(true))
|
|
].toOrderedTable
|
|
))
|
|
|
|
testScanValue("b", JsonValueRef[uint64](nil), error = errUnknownChar)
|
|
testScanValue("[,", JsonValueRef[uint64](kind: JsonValueKind.Array),
|
|
error = errMissingFirstElement)
|
|
testScanValue("{,", JsonValueRef[uint64](kind: JsonValueKind.Object),
|
|
error = errMissingFirstElement)
|
|
|
|
testScanValue("[,", JsonValueRef[uint64](kind: JsonValueKind.Array),
|
|
error = errMissingFirstElement, flags = {JsonReaderFlag.trailingComma})
|
|
testScanValue("{,", JsonValueRef[uint64](kind: JsonValueKind.Object),
|
|
error = errMissingFirstElement, flags = {JsonReaderFlag.trailingComma})
|
|
|
|
testScanValue("{\"a\": true,}",
|
|
JsonValueRef[uint64](kind: JsonValueKind.Object,
|
|
objVal: [("a", jsonBool(true))].toOrderedTable
|
|
), flags = {}, error = errTrailingComma)
|
|
|
|
testScanValue("[true,]",
|
|
JsonValueRef[uint64](kind: JsonValueKind.Array,
|
|
arrayVal: @[
|
|
jsonBool(true)
|
|
]
|
|
), flags = {}, error = errTrailingComma)
|
|
|
|
testScanValue("{\"a\": true,}",
|
|
JsonValueRef[uint64](kind: JsonValueKind.Object,
|
|
objVal: [("a", jsonBool(true))].toOrderedTable
|
|
))
|
|
|
|
testScanValue("[true,]",
|
|
JsonValueRef[uint64](kind: JsonValueKind.Array,
|
|
arrayVal: @[
|
|
jsonBool(true)
|
|
]
|
|
))
|
|
|
|
testScanValue("[]", JsonValueRef[uint64](kind: JsonValueKind.Array))
|
|
testScanValue("{}", JsonValueRef[uint64](kind: JsonValueKind.Object))
|
|
|
|
|
|
var conf = defaultJsonReaderConf
|
|
conf.arrayElementsLimit = 3
|
|
conf.objectMembersLimit = 3
|
|
|
|
testScanValue("[1,2,3,4]", JsonValueRef[uint64](kind: JsonValueKind.Array,
|
|
arrayVal: @[
|
|
jsonNumber(1),
|
|
jsonNumber(2),
|
|
jsonNumber(3),
|
|
]), error = errArrayElementsLimit, conf = conf)
|
|
|
|
testScanValue("{\"a\":1, \"b\":2, \"C\":3, \"d\": 4}",
|
|
JsonValueRef[uint64](kind: JsonValueKind.Object,
|
|
objVal: [
|
|
("a", jsonNumber(1)),
|
|
("b", jsonNumber(2)),
|
|
("C", jsonNumber(3)),
|
|
].toOrderedTable
|
|
), error = errObjectMembersLimit, conf = conf)
|
|
|
|
testScanValue("[[[1]]]", JsonValueRef[uint64](kind: JsonValueKind.Array,
|
|
arrayVal: @[
|
|
JsonValueRef[uint64](kind: JsonValueKind.Array,
|
|
arrayVal: @[
|
|
JsonValueRef[uint64](kind: JsonValueKind.Array,
|
|
arrayVal: @[
|
|
jsonNumber(1)
|
|
])
|
|
])
|
|
])
|
|
)
|
|
|
|
conf.nestedDepthLimit = 3
|
|
testScanValue("[[[[1]]]]", JsonValueRef[uint64](kind: JsonValueKind.Array,
|
|
arrayVal: @[
|
|
JsonValueRef[uint64](kind: JsonValueKind.Array,
|
|
arrayVal: @[
|
|
JsonValueRef[uint64](kind: JsonValueKind.Array,
|
|
arrayVal: @[
|
|
JsonValueRef[uint64](kind: JsonValueKind.Array)
|
|
])
|
|
])
|
|
]), error = errNestedDepthLimit, conf = conf)
|
|
|
|
testScanValue("[ { \"a\": [ { \"b\": 3}] } ]",
|
|
JsonValueRef[uint64](kind: JsonValueKind.Array,
|
|
arrayVal: @[
|
|
JsonValueRef[uint64](kind: JsonValueKind.Object,
|
|
objVal: [
|
|
("a", JsonValueRef[uint64](kind: JsonValueKind.Array,
|
|
arrayVal: @[
|
|
JsonValueRef[uint64](kind: JsonValueKind.Object)
|
|
])
|
|
)
|
|
].toOrderedTable)
|
|
]), error = errNestedDepthLimit, conf = conf)
|
|
|
|
testScanValue("{ \"a\": 1234.567 // comments\n }",
|
|
JsonValueRef[uint64](kind: JsonValueKind.Object,
|
|
objVal: [
|
|
("a", jsonNumber(1234, "567"))
|
|
].toOrderedTable
|
|
), flags = {}, error = errCommentNotAllowed)
|
|
|
|
testScanValue("{ \"a\": 1234.567 // comments\n }",
|
|
JsonValueRef[uint64](kind: JsonValueKind.Object,
|
|
objVal: [
|
|
("a", jsonNumber(1234, "567"))
|
|
].toOrderedTable
|
|
))
|
|
|
|
testScanValue("{ \"a\": 1234.567 /* comments */ }",
|
|
JsonValueRef[uint64](kind: JsonValueKind.Object,
|
|
objVal: [
|
|
("a", jsonNumber(1234, "567"))
|
|
].toOrderedTable
|
|
), flags = {}, error = errCommentNotAllowed)
|
|
|
|
testScanValue("{ \"a\": 1234.567 /* comments */ }",
|
|
JsonValueRef[uint64](kind: JsonValueKind.Object,
|
|
objVal: [
|
|
("a", jsonNumber(1234, "567"))
|
|
].toOrderedTable
|
|
))
|
|
|
|
test "spec test cases":
|
|
testScanNumber("20E1", "20E1")
|
|
testScanNumber("20E1", JsonVoid())
|
|
testScanNumber("20E1", JsonNumber[uint64](integer:20, exponent:1))
|
|
|
|
testScanNumber("1.0000005", "1.0000005")
|
|
testScanNumber("1.0000005", JsonVoid())
|
|
|
|
# both fraction and exponent support leading zeros
|
|
# the meaning of leading zeros in fraction is clear.
|
|
# but the meaning of leading zeros in exponent is questionable or even needed.
|
|
testScanNumber("1.0000005E004",
|
|
JsonNumber[string](
|
|
integer:"1",
|
|
fraction:"0000005",
|
|
exponent:"004"
|
|
))
|
|
|
|
testScanNumber("1.0000005E004",
|
|
JsonNumber[uint64](
|
|
integer:1,
|
|
fraction:"0000005",
|
|
exponent:4
|
|
))
|
|
|
|
testScanValue("[-2.]", "[-2.", error = errEmptyFraction)
|
|
testScanNumber("-2.", "-2.", error = errEmptyFraction)
|
|
testScanNumber("0.e1", "0.", error = errEmptyFraction)
|
|
testScanNumber("2.e+3", "2.", error = errEmptyFraction)
|
|
testScanNumber("2.e-3", "2.", error = errEmptyFraction)
|
|
testScanNumber("2.e3", "2.", error = errEmptyFraction)
|
|
testScanNumber("1.", "1.", error = errEmptyFraction)
|
|
|
|
testScanValue("[+1]", "[", flags = {}, error = errIntPosSign)
|
|
testScanValue("[+1]", "[+1]")
|
|
testScanValue("[1+2]", "[1", error = errCommaExpected)
|
|
|
|
testScanValue("[1 true]", "[1", error = errCommaExpected)
|
|
testScanValue("[1,,2]", "[1,", error = errValueExpected)
|
|
testScanValue("[3 [4]]", "[3", error = errCommaExpected)
|
|
|
|
testScanValue("{\"a\":true,,\"c\":false}", "{\"a\":true,", error = errValueExpected)
|
|
testScanValue("{\"a\":true \"c\":false}", "{\"a\":true", error = errCommaExpected)
|
|
|
|
testScanValue("{\"a\":true ", "{\"a\":true", error = errCurlyRiExpected)
|
|
|
|
for c in '\x00'..'\x1F':
|
|
if c notin {'\r', '\n'}:
|
|
testScanString("\"a" & c & "a\"", "a", error = errEscapeControlChar)
|
|
|
|
testScanValue("{123:true}", "{", error = errStringExpected)
|
|
testScanValue("{123:true}", JsonVoid(), error = errStringExpected)
|
|
testScanValue("{123:true}", JsonValueRef[uint64](kind: JsonValueKind.Object), error = errStringExpected)
|
|
|
|
testScanValue("{\"123:true}", "{\"123:true}", error = errUnexpectedEof)
|
|
|
|
testScanValue("{\"123\":\"tru", "{\"123\":\"tru\"", error = errUnexpectedEof)
|
|
testScanValue("{\"123\":\"tr", "{\"123\":\"tr\"", error = errUnexpectedEof)
|
|
testScanValue("{\"123\":\"t", "{\"123\":\"t\"", error = errUnexpectedEof)
|
|
testScanValue("{\"123\":\"nul", "{\"123\":\"nul\"", error = errUnexpectedEof)
|
|
testScanValue("{\"123\":\"nu", "{\"123\":\"nu\"", error = errUnexpectedEof)
|
|
testScanValue("{\"123\":\"n", "{\"123\":\"n\"", error = errUnexpectedEof)
|
|
testScanValue("{\"123\":\"fals", "{\"123\":\"fals\"", error = errUnexpectedEof)
|
|
testScanValue("{\"123\":\"fal", "{\"123\":\"fal\"", error = errUnexpectedEof)
|
|
testScanValue("{\"123\":\"fa", "{\"123\":\"fa\"", error = errUnexpectedEof)
|
|
testScanValue("{\"123\":\"f", "{\"123\":\"f\"", error = errUnexpectedEof)
|