123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 |
- discard """
- matrix: "--mm:refc"
- targets: "c cpp js"
- """
- #[
- Note: Macro tests are in tests/stdlib/tjsonmacro.nim
- ]#
- import std/[json,parsejson,strutils]
- from std/math import isNaN
- when not defined(js):
- import std/streams
- import stdtest/testutils
- from std/fenv import epsilon
- import std/[assertions, objectdollar]
- proc testRoundtrip[T](t: T, expected: string) =
- # checks that `T => json => T2 => json2` is such that json2 = json
- let j = %t
- doAssert $j == expected, $j
- doAssert %(j.to(T)) == j
- proc testRoundtripVal[T](t: T, expected: string) =
- # similar to testRoundtrip, but also checks that the `T => json => T2` is such that `T2 == T`
- # note that this isn't always possible, e.g. for pointer-like types or nans
- let j = %t
- doAssert $j == expected, $j
- let j2 = ($j).parseJson
- doAssert $j2 == expected, $(j2, t)
- let t2 = j2.to(T)
- doAssert t2 == t
- doAssert $(%* t2) == expected # sanity check, because -0.0 = 0.0 but their json representation differs
- let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd", "c": "\ud83c\udf83", "d": "\u00E6"}"""
- # nil passthrough
- doAssert(testJson{"doesnt_exist"}{"anything"}.isNil)
- testJson{["e", "f"]} = %true
- doAssert(testJson["e"]["f"].bval)
- # make sure UTF-16 decoding works.
- doAssert(testJson["c"].str == "🎃")
- doAssert(testJson["d"].str == "æ")
- # make sure no memory leek when parsing invalid string
- let startMemory = getOccupiedMem()
- for i in 0 .. 10000:
- try:
- discard parseJson"""{ invalid"""
- except:
- discard
- # memory diff should less than 4M
- doAssert(abs(getOccupiedMem() - startMemory) < 4 * 1024 * 1024) # todo fixme doesn;t work for ORC
- # test `$`
- let stringified = $testJson
- let parsedAgain = parseJson(stringified)
- doAssert(parsedAgain["b"].str == "asd")
- parsedAgain["abc"] = %5
- doAssert parsedAgain["abc"].num == 5
- # Bounds checking
- when compileOption("boundChecks"):
- try:
- let a = testJson["a"][9]
- doAssert(false, "IndexDefect not thrown")
- except IndexDefect:
- discard
- try:
- let a = testJson["a"][-1]
- doAssert(false, "IndexDefect not thrown")
- except IndexDefect:
- discard
- try:
- doAssert(testJson["a"][0].num == 1, "Index doesn't correspond to its value")
- except:
- doAssert(false, "IndexDefect thrown for valid index")
- doAssert(testJson{"b"}.getStr() == "asd", "Couldn't fetch a singly nested key with {}")
- doAssert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil")
- doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
- doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
- doAssert(testJson{"a"} == parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found")
- doAssert(isNil(parseJson("[1, 2, 3]"){"foo"}), "Indexing directly into a list should return nil")
- # Generator:
- var j = %* [{"name": "John", "age": 30}, {"name": "Susan", "age": 31}]
- doAssert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
- var j2 = %*
- [
- {
- "name": "John",
- "age": 30
- },
- {
- "name": "Susan",
- "age": 31
- }
- ]
- doAssert j2 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
- var name = "John"
- let herAge = 30
- const hisAge = 31
- var j3 = %*
- [ {"name": "John"
- , "age": herAge
- }
- , {"name": "Susan"
- , "age": hisAge
- }
- ]
- doAssert j3 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
- var j4 = %*{"test": nil}
- doAssert j4 == %{"test": newJNull()}
- let seqOfNodes = @[%1, %2]
- let jSeqOfNodes = %seqOfNodes
- doAssert(jSeqOfNodes[1].num == 2)
- type MyObj = object
- a, b: int
- s: string
- f32: float32
- f64: float64
- next: ref MyObj
- var m: MyObj
- m.s = "hi"
- m.a = 5
- let jMyObj = %m
- doAssert(jMyObj["a"].num == 5)
- doAssert(jMyObj["s"].str == "hi")
- # Test loading of file.
- when not defined(js):
- var parsed = parseFile("tests/testdata/jsontest.json")
- try:
- discard parsed["key2"][12123]
- doAssert(false)
- except IndexDefect: doAssert(true)
- var parsed2 = parseFile("tests/testdata/jsontest2.json")
- doAssert(parsed2{"repository", "description"}.str ==
- "IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
- doAssert escapeJsonUnquoted("\10Foo🎃barÄ") == "\\nFoo🎃barÄ"
- doAssert escapeJsonUnquoted("\0\7\20") == "\\u0000\\u0007\\u0014" # for #7887
- doAssert escapeJson("\10Foo🎃barÄ") == "\"\\nFoo🎃barÄ\""
- doAssert escapeJson("\0\7\20") == "\"\\u0000\\u0007\\u0014\"" # for #7887
- # Test with extra data
- when not defined(js):
- try:
- discard parseJson("123 456")
- doAssert(false)
- except JsonParsingError:
- doAssert getCurrentExceptionMsg().contains(errorMessages[errEofExpected])
- try:
- discard parseFile("tests/testdata/jsonwithextradata.json")
- doAssert(false)
- except JsonParsingError:
- doAssert getCurrentExceptionMsg().contains(errorMessages[errEofExpected])
- # bug #6438
- doAssert($ %*[] == "[]")
- doAssert($ %*{} == "{}")
- doAssert(not compiles(%{"error": "No messages"}))
- # bug #9111
- block:
- type
- Bar = string
- Foo = object
- a: int
- b: Bar
- let
- js = """{"a": 123, "b": "abc"}""".parseJson
- foo = js.to Foo
- doAssert(foo.b == "abc")
- # Generate constructors for range[T] types
- block:
- type
- Q1 = range[0'u8 .. 50'u8]
- Q2 = range[0'u16 .. 50'u16]
- Q3 = range[0'u32 .. 50'u32]
- Q4 = range[0'i8 .. 50'i8]
- Q5 = range[0'i16 .. 50'i16]
- Q6 = range[0'i32 .. 50'i32]
- Q7 = range[0'f32 .. 50'f32]
- Q8 = range[0'f64 .. 50'f64]
- Q9 = range[0 .. 50]
- X = object
- m1: Q1
- m2: Q2
- m3: Q3
- m4: Q4
- m5: Q5
- m6: Q6
- m7: Q7
- m8: Q8
- m9: Q9
- let obj = X(
- m1: Q1(42),
- m2: Q2(42),
- m3: Q3(42),
- m4: Q4(42),
- m5: Q5(42),
- m6: Q6(42),
- m7: Q7(42),
- m8: Q8(42),
- m9: Q9(42)
- )
- doAssert(obj == to(%obj, type(obj)))
- when not defined(js):
- const fragments = """[1,2,3] {"hi":3} 12 [] """
- var res = ""
- for x in parseJsonFragments(newStringStream(fragments)):
- res.add($x)
- res.add " "
- doAssert res == fragments
- # test isRefSkipDistinct
- type
- MyRef = ref object
- MyObject = object
- MyDistinct = distinct MyRef
- MyOtherDistinct = distinct MyRef
- var x0: ref int
- var x1: MyRef
- var x2: MyObject
- var x3: MyDistinct
- var x4: MyOtherDistinct
- doAssert isRefSkipDistinct(x0)
- doAssert isRefSkipDistinct(x1)
- doAssert not isRefSkipDistinct(x2)
- doAssert isRefSkipDistinct(x3)
- doAssert isRefSkipDistinct(x4)
- doAssert isRefSkipDistinct(ref int)
- doAssert isRefSkipDistinct(MyRef)
- doAssert not isRefSkipDistinct(MyObject)
- doAssert isRefSkipDistinct(MyDistinct)
- doAssert isRefSkipDistinct(MyOtherDistinct)
- let x = parseJson("9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999")
- doAssert x.kind == JString
- block: # bug #15835
- type
- Foo = object
- ii*: int
- data*: JsonNode
- block:
- const jt = """{"ii": 123, "data": ["some", "data"]}"""
- let js = parseJson(jt)
- discard js.to(Foo)
- block:
- const jt = """{"ii": 123}"""
- let js = parseJson(jt)
- doAssertRaises(KeyError):
- echo js.to(Foo)
- type
- ContentNodeKind* = enum
- P,
- Br,
- Text,
- ContentNode* = object
- case kind*: ContentNodeKind
- of P: pChildren*: seq[ContentNode]
- of Br: nil
- of Text: textStr*: string
- let mynode = ContentNode(kind: P, pChildren: @[
- ContentNode(kind: Text, textStr: "mychild"),
- ContentNode(kind: Br)
- ])
- doAssert $mynode == """(kind: P, pChildren: @[(kind: Text, textStr: "mychild"), (kind: Br)])"""
- let jsonNode = %*mynode
- doAssert $jsonNode == """{"kind":"P","pChildren":[{"kind":"Text","textStr":"mychild"},{"kind":"Br"}]}"""
- doAssert $jsonNode.to(ContentNode) == """(kind: P, pChildren: @[(kind: Text, textStr: "mychild"), (kind: Br)])"""
- block: # bug #17383
- testRoundtrip(int32.high): "2147483647"
- testRoundtrip(uint32.high): "4294967295"
- when int.sizeof == 4:
- testRoundtrip(int.high): "2147483647"
- testRoundtrip(uint.high): "4294967295"
- else:
- testRoundtrip(int.high): "9223372036854775807"
- testRoundtrip(uint.high): "18446744073709551615"
- when not defined(js):
- testRoundtrip(int64.high): "9223372036854775807"
- testRoundtrip(uint64.high): "18446744073709551615"
- block: # bug #18007
- testRoundtrip([NaN, Inf, -Inf, 0.0, -0.0, 1.0]): """["nan","inf","-inf",0.0,-0.0,1.0]"""
- # pending https://github.com/nim-lang/Nim/issues/18025 use:
- # testRoundtrip([float32(NaN), Inf, -Inf, 0.0, -0.0, 1.0])
- let inf = float32(Inf)
- testRoundtrip([float32(NaN), inf, -inf, 0.0, -0.0, 1.0]): """["nan","inf","-inf",0.0,-0.0,1.0]"""
- when not defined(js): # because of Infinity vs inf
- testRoundtripVal([inf, -inf, 0.0, -0.0, 1.0]): """["inf","-inf",0.0,-0.0,1.0]"""
- let a = parseJson($(%NaN)).to(float)
- doAssert a.isNaN
- whenRuntimeJs: discard # refs bug #18009
- do:
- testRoundtripVal(0.0): "0.0"
- testRoundtripVal(-0.0): "-0.0"
- block: # bug #15397, bug #13196
- testRoundtripVal(1.0 + epsilon(float64)): "1.0000000000000002"
- testRoundtripVal(0.12345678901234567890123456789): "0.12345678901234568"
- block:
- let a = "18446744073709551615"
- let b = a.parseJson
- doAssert b.kind == JString
- let c = $b
- when defined(js):
- doAssert c == "18446744073709552000"
- else:
- doAssert c == "18446744073709551615"
- block:
- let a = """
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
- """
- when not defined(js):
- try:
- discard parseJson(a)
- except JsonParsingError:
- doAssert getCurrentExceptionMsg().contains("] expected")
|