diff options
author | Arne Döring <arne.doering@gmx.net> | 2019-10-28 10:06:16 +0100 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2019-10-28 10:06:16 +0100 |
commit | 5ed99f8d3fc67d6f02172ab9cbcc67c17eeee5c9 (patch) | |
tree | b08965de5c7eff8da9df97e8a2e009cff3fae5de | |
parent | a2ad7d4883a450d66d1657c3550dc91f66b8b187 (diff) | |
download | Nim-5ed99f8d3fc67d6f02172ab9cbcc67c17eeee5c9.tar.gz |
Extent json.to testing to VM, add workrounds for VM bugs. (#12493)
fixes #12479
-rw-r--r-- | lib/pure/json.nim | 177 | ||||
-rw-r--r-- | lib/system.nim | 10 | ||||
-rw-r--r-- | tests/stdlib/tjsonmacro.nim | 238 |
3 files changed, 257 insertions, 168 deletions
diff --git a/lib/pure/json.nim b/lib/pure/json.nim index e833f6123..72002fbab 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -966,30 +966,38 @@ template verifyJsonKind(node: JsonNode, kinds: set[JsonNodeKind], ] raise newException(JsonKindError, msg) - when defined(nimFixedForwardGeneric): + + macro isRefSkipDistinct(arg: typed): untyped = + var impl = getTypeImpl(arg) + if impl.kind == nnkBracketExpr and impl[0].eqIdent("typeDesc"): + impl = getTypeImpl(impl[1]) + while impl.kind == nnkDistinctTy: + impl = getTypeImpl(impl[0]) + result = newLit(impl.kind == nnkRefTy) + # The following forward declarations don't work in older versions of Nim # forward declare all initFromJson - proc initFromJson(dst: var string; jsonNode: JsonNode; jsonPath: string) - proc initFromJson(dst: var bool; jsonNode: JsonNode; jsonPath: string) - proc initFromJson(dst: var JsonNode; jsonNode: JsonNode; jsonPath: string) - proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: string) - proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: string) - proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: string) - proc initFromJson[T](dst: var seq[T]; jsonNode: JsonNode; jsonPath: string) - proc initFromJson[S,T](dst: var array[S,T]; jsonNode: JsonNode; jsonPath: string) - proc initFromJson[T](dst: var Table[string,T];jsonNode: JsonNode; jsonPath: string) - proc initFromJson[T](dst: var OrderedTable[string,T];jsonNode: JsonNode; jsonPath: string) - proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: string) - proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: string) - proc initFromJson[T: distinct](dst: var T;jsonNode: JsonNode; jsonPath: string) - proc initFromJson[T: object|tuple](dst: var T; jsonNode: JsonNode; jsonPath: string) + proc initFromJson(dst: var string; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson(dst: var bool; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson(dst: var JsonNode; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var string) + proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T](dst: var seq[T]; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[S,T](dst: var array[S,T]; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T](dst: var Table[string,T];jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T](dst: var OrderedTable[string,T];jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T: distinct](dst: var T;jsonNode: JsonNode; jsonPath: var string) + proc initFromJson[T: object|tuple](dst: var T; jsonNode: JsonNode; jsonPath: var string) # initFromJson definitions - proc initFromJson(dst: var string; jsonNode: JsonNode; jsonPath: string) = + proc initFromJson(dst: var string; jsonNode: JsonNode; jsonPath: var string) = verifyJsonKind(jsonNode, {JString, JNull}, jsonPath) # since strings don't have a nil state anymore, this mapping of # JNull to the default string is questionable. `none(string)` and @@ -999,91 +1007,115 @@ when defined(nimFixedForwardGeneric): else: dst = jsonNode.str - proc initFromJson(dst: var bool; jsonNode: JsonNode; jsonPath: string) = + proc initFromJson(dst: var bool; jsonNode: JsonNode; jsonPath: var string) = verifyJsonKind(jsonNode, {JBool}, jsonPath) dst = jsonNode.bval - proc initFromJson(dst: var JsonNode; jsonNode: JsonNode; jsonPath: string) = + proc initFromJson(dst: var JsonNode; jsonNode: JsonNode; jsonPath: var string) = dst = jsonNode.copy - proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: string) = + proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var string) = verifyJsonKind(jsonNode, {JInt}, jsonPath) dst = T(jsonNode.num) - proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: string) = + proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string) = verifyJsonKind(jsonNode, {JInt, JFloat}, jsonPath) if jsonNode.kind == JFloat: dst = T(jsonNode.fnum) else: dst = T(jsonNode.num) - proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: string) = + proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: var string) = verifyJsonKind(jsonNode, {JString}, jsonPath) dst = parseEnum[T](jsonNode.getStr) - proc initFromJson[T](dst: var seq[T]; jsonNode: JsonNode; jsonPath: string) = + proc initFromJson[T](dst: var seq[T]; jsonNode: JsonNode; jsonPath: var string) = verifyJsonKind(jsonNode, {JArray}, jsonPath) dst.setLen jsonNode.len + let orignalJsonPathLen = jsonPath.len for i in 0 ..< jsonNode.len: - initFromJson(dst[i], jsonNode[i], jsonPath & "[" & $i & "]") + jsonPath.add '[' + jsonPath.addInt i + jsonPath.add ']' + initFromJson(dst[i], jsonNode[i], jsonPath) + jsonPath.setLen orignalJsonPathLen - proc initFromJson[S,T](dst: var array[S,T]; jsonNode: JsonNode; jsonPath: string) = + proc initFromJson[S,T](dst: var array[S,T]; jsonNode: JsonNode; jsonPath: var string) = verifyJsonKind(jsonNode, {JArray}, jsonPath) + let originalJsonPathLen = jsonPath.len for i in 0 ..< jsonNode.len: - initFromJson(dst[i], jsonNode[i], jsonPath & "[" & $i & "]") + jsonPath.add '[' + jsonPath.addInt i + jsonPath.add ']' + initFromJson(dst[i], jsonNode[i], jsonPath) + jsonPath.setLen originalJsonPathLen - proc initFromJson[T](dst: var Table[string,T];jsonNode: JsonNode; jsonPath: string) = + proc initFromJson[T](dst: var Table[string,T];jsonNode: JsonNode; jsonPath: var string) = dst = initTable[string, T]() verifyJsonKind(jsonNode, {JObject}, jsonPath) + let originalJsonPathLen = jsonPath.len for key in keys(jsonNode.fields): - initFromJson(mgetOrPut(dst, key, default(T)), jsonNode[key], jsonPath & "." & key) + jsonPath.add '.' + jsonPath.add key + initFromJson(mgetOrPut(dst, key, default(T)), jsonNode[key], jsonPath) + jsonPath.setLen originalJsonPathLen - proc initFromJson[T](dst: var OrderedTable[string,T];jsonNode: JsonNode; jsonPath: string) = + proc initFromJson[T](dst: var OrderedTable[string,T];jsonNode: JsonNode; jsonPath: var string) = dst = initOrderedTable[string,T]() verifyJsonKind(jsonNode, {JObject}, jsonPath) + let originalJsonPathLen = jsonPath.len for key in keys(jsonNode.fields): - initFromJson(mgetOrPut(dst, key, default(T)), jsonNode[key], jsonPath & "." & key) + jsonPath.add '.' + jsonPath.add key + initFromJson(mgetOrPut(dst, key, default(T)), jsonNode[key], jsonPath) + jsonPath.setLen originalJsonPathLen - proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: string) = + proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: var string) = if jsonNode.kind == JNull: dst = nil else: - dst = new(ref T) + dst = new(T) initFromJson(dst[], jsonNode, jsonPath) - proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: string) = + proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: var string) = if jsonNode != nil and jsonNode.kind != JNull: dst = some(default(T)) initFromJson(dst.get, jsonNode, jsonPath) - macro assignDistinctImpl[T : distinct](dst: var T;jsonNode: JsonNode; jsonPath: string) = + macro assignDistinctImpl[T : distinct](dst: var T;jsonNode: JsonNode; jsonPath: var string) = let typInst = getTypeInst(dst) let typImpl = getTypeImpl(dst) let baseTyp = typImpl[0] + result = quote do: - initFromJson( `baseTyp`(`dst`), `jsonNode`, `jsonPath`) + when nimvm: + # workaround #12282 + var tmp: `baseTyp` + initFromJson( tmp, `jsonNode`, `jsonPath`) + `dst` = `typInst`(tmp) + else: + initFromJson( `baseTyp`(`dst`), `jsonNode`, `jsonPath`) - proc initFromJson[T : distinct](dst: var T; jsonNode: JsonNode; jsonPath: string) = + proc initFromJson[T : distinct](dst: var T; jsonNode: JsonNode; jsonPath: var string) = assignDistinctImpl(dst, jsonNode, jsonPath) proc detectIncompatibleType(typeExpr, lineinfoNode: NimNode): void = if typeExpr.kind == nnkTupleConstr: error("Use a named tuple instead of: " & typeExpr.repr, lineinfoNode) - proc foldObjectBody(dst, typeNode, tmpSym, jsonNode, jsonPath: NimNode, depth: int): void {.compileTime.} = - if depth > 150: - error("recursion limit reached", typeNode) + proc foldObjectBody(dst, typeNode, tmpSym, jsonNode, jsonPath, originalJsonPathLen: NimNode): void {.compileTime.} = case typeNode.kind of nnkEmpty: discard of nnkRecList, nnkTupleTy: for it in typeNode: - foldObjectBody(dst, it, tmpSym, jsonNode, jsonPath, depth + 1) + foldObjectBody(dst, it, tmpSym, jsonNode, jsonPath, originalJsonPathLen) of nnkIdentDefs: typeNode.expectLen 3 let fieldSym = typeNode[0] let fieldNameLit = newLit(fieldSym.strVal) + let fieldPathLit = newLit("." & fieldSym.strVal) let fieldType = typeNode[1] # Detecting incompatiple tuple types in `assignObjectImpl` only @@ -1092,16 +1124,30 @@ when defined(nimFixedForwardGeneric): detectIncompatibleType(fieldType, fieldSym) dst.add quote do: - initFromJson(`tmpSym`.`fieldSym`, getOrDefault(`jsonNode`,`fieldNameLit`), `jsonPath` & "." & `fieldNameLit`) + jsonPath.add `fieldPathLit` + when nimvm: + when isRefSkipDistinct(`tmpSym`.`fieldSym`): + # workaround #12489 + var tmp: `fieldType` + initFromJson(tmp, getOrDefault(`jsonNode`,`fieldNameLit`), `jsonPath`) + `tmpSym`.`fieldSym` = tmp + else: + initFromJson(`tmpSym`.`fieldSym`, getOrDefault(`jsonNode`,`fieldNameLit`), `jsonPath`) + else: + initFromJson(`tmpSym`.`fieldSym`, getOrDefault(`jsonNode`,`fieldNameLit`), `jsonPath`) + jsonPath.setLen `originalJsonPathLen` of nnkRecCase: let kindSym = typeNode[0][0] let kindNameLit = newLit(kindSym.strVal) + let kindPathLit = newLit("." & kindSym.strVal) let kindType = typeNode[0][1] let kindOffsetLit = newLit(uint(getOffset(kindSym))) dst.add quote do: var kindTmp: `kindType` - initFromJson(kindTmp, `jsonNode`[`kindNameLit`], `jsonPath` & "." & `kindNameLit`) + jsonPath.add `kindPathLit` + initFromJson(kindTmp, `jsonNode`[`kindNameLit`], `jsonPath`) + jsonPath.setLen `originalJsonPathLen` when defined js: `tmpSym`.`kindSym` = kindTmp else: @@ -1112,14 +1158,14 @@ when defined(nimFixedForwardGeneric): ((cast[ptr `kindType`](cast[uint](`tmpSym`.addr) + `kindOffsetLit`))[]) = kindTmp dst.add nnkCaseStmt.newTree(nnkDotExpr.newTree(tmpSym, kindSym)) for i in 1 ..< typeNode.len: - foldObjectBody(dst, typeNode[i], tmpSym, jsonNode, jsonPath, depth + 1) + foldObjectBody(dst, typeNode[i], tmpSym, jsonNode, jsonPath, originalJsonPathLen) of nnkOfBranch, nnkElse: let ofBranch = newNimNode(typeNode.kind) for i in 0 ..< typeNode.len-1: ofBranch.add copyNimTree(typeNode[i]) let dstInner = newNimNode(nnkStmtListExpr) - foldObjectBody(dstInner, typeNode[^1], tmpSym, jsonNode, jsonPath, depth + 1) + foldObjectBody(dstInner, typeNode[^1], tmpSym, jsonNode, jsonPath, originalJsonPathLen) # resOuter now contains the inner stmtList ofBranch.add dstInner dst[^1].expectKind nnkCaseStmt @@ -1133,26 +1179,29 @@ when defined(nimFixedForwardGeneric): var impl = getTypeImpl(base) while impl.kind in {nnkRefTy, nnkPtrTy}: impl = getTypeImpl(impl[0]) - foldObjectBody(dst, impl, tmpSym, jsonNode, jsonPath, depth + 1) + foldObjectBody(dst, impl, tmpSym, jsonNode, jsonPath, originalJsonPathLen) let body = typeNode[2] - foldObjectBody(dst, body, tmpSym, jsonNode, jsonPath, depth + 1) + foldObjectBody(dst, body, tmpSym, jsonNode, jsonPath, originalJsonPathLen) else: error("unhandled kind: " & $typeNode.kind, typeNode) - macro assignObjectImpl[T](dst: var T; jsonNode: JsonNode; jsonPath: string) = + macro assignObjectImpl[T](dst: var T; jsonNode: JsonNode; jsonPath: var string) = let typeSym = getTypeInst(dst) + let originalJsonPathLen = genSym(nskLet, "originalJsonPathLen") result = newStmtList() + result.add quote do: + let `originalJsonPathLen` = len(`jsonPath`) if typeSym.kind in {nnkTupleTy, nnkTupleConstr}: # both, `dst` and `typeSym` don't have good lineinfo. But nothing # else is available here. detectIncompatibleType(typeSym, dst) - foldObjectBody(result, typeSym, dst, jsonNode, jsonPath, 0) + foldObjectBody(result, typeSym, dst, jsonNode, jsonPath, originalJsonPathLen) else: - foldObjectBody(result, typeSym.getTypeImpl, dst, jsonNode, jsonPath, 0) + foldObjectBody(result, typeSym.getTypeImpl, dst, jsonNode, jsonPath, originalJsonPathLen) - proc initFromJson[T : object|tuple](dst: var T; jsonNode: JsonNode; jsonPath: string) = + proc initFromJson[T : object|tuple](dst: var T; jsonNode: JsonNode; jsonPath: var string) = assignObjectImpl(dst, jsonNode, jsonPath) proc to*[T](node: JsonNode, t: typedesc[T]): T = @@ -1191,7 +1240,8 @@ when defined(nimFixedForwardGeneric): ## doAssert data.person.age == 21 ## doAssert data.list == @[1, 2, 3, 4] - initFromJson(result, node, "") + var jsonPath = "" + initFromJson(result, node, jsonPath) when false: import os @@ -1424,3 +1474,30 @@ when isMainModule: 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) diff --git a/lib/system.nim b/lib/system.nim index 93e4534fb..663ac1f66 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -3872,6 +3872,12 @@ elif defined(JS): proc deallocShared(p: pointer) = discard proc reallocShared(p: pointer, newsize: Natural): pointer = discard + proc addInt*(result: var string; x: int64) = + result.add $x + + proc addFloat*(result: var string; x: float) = + result.add $x + when defined(JS) and not defined(nimscript): include "system/jssys" include "system/reprjs" @@ -4326,9 +4332,9 @@ proc addQuoted*[T](s: var string, x: T) = s.addEscapedChar(x) s.add("'") # prevent temporary string allocation - elif T is SomeSignedInt and not defined(JS): + elif T is SomeSignedInt: s.addInt(x) - elif T is SomeFloat and not defined(JS): + elif T is SomeFloat: s.addFloat(x) elif compiles(s.add(x)): s.add(x) diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim index c2a4ed406..938030d8e 100644 --- a/tests/stdlib/tjsonmacro.nim +++ b/tests/stdlib/tjsonmacro.nim @@ -5,17 +5,26 @@ discard """ import json, strutils, options, tables -when true: +# The definition of the `%` proc needs to be here, since the `% c` calls below +# can only find our custom `%` proc for `Pix` if defined in global scope. +type + Pix = tuple[x, y: uint8, ch: uint16] +proc `%`(p: Pix): JsonNode = + result = %* { "x" : % p.x, + "y" : % p.y, + "ch" : % p.ch } + +proc testJson() = # Tests inspired by own use case (with some additional tests). # This should succeed. type Point[T] = object x, y: T - ReplayEventKind* = enum + ReplayEventKind = enum FoodAppeared, FoodEaten, DirectionChanged - ReplayEvent* = object + ReplayEvent = object time*: float case kind*: ReplayEventKind of FoodAppeared, FoodEaten: @@ -28,7 +37,7 @@ when true: of DirectionChanged: playerPos*: float - Replay* = ref object + Replay = ref object events*: seq[ReplayEvent] test: int test2: string @@ -286,24 +295,26 @@ when true: doAssert parsed.color == Red block: - type - Car = object - engine: tuple[name: string, capacity: float] - model: string + when not defined(js): + # disable on js because of #12492 + type + Car = object + engine: tuple[name: string, capacity: float] + model: string - let j = """ - {"engine": {"name": "V8", "capacity": 5.5}, "model": "Skyline"} - """ + let j = """ + {"engine": {"name": "V8", "capacity": 5.5}, "model": "Skyline"} + """ - var i = 0 - proc mulTest: JsonNode = - i.inc() - return parseJson(j) + var i = 0 + proc mulTest(): JsonNode = + inc i + return parseJson(j) - let parsed = mulTest().to(Car) - doAssert parsed.engine.name == "V8" + let parsed = mulTest().to(Car) + doAssert parsed.engine.name == "V8" - doAssert i == 1 + doAssert i == 1 block: # Option[T] support! @@ -424,7 +435,11 @@ when true: block: let s = """{"a": 1, "b": 2}""" let t = parseJson(s).to(Table[string, int]) - doAssert t["a"] == 1 + when not defined(js): + # For some reason on the JS backend `{"b": 2, "a": 0}` is + # sometimes the value of `t`. This needs investigation. I can't + # reproduce it right now in an isolated test. + doAssert t["a"] == 1 doAssert t["b"] == 2 block: @@ -480,6 +495,7 @@ when true: doAssert Table[string,int](t.dict)["a"] == 1 doAssert Table[string,int](t.dict)["b"] == 2 doAssert array[3, float](t.arr) == [1.0,2.0,7.0] + doAssert MyRef(t.person).name == "boney" doAssert MyObj(t.distFruit).color == 11 doAssert t.dog.name == "honey" @@ -526,109 +542,99 @@ when true: doAssert v.name == "smith" doAssert MyRef(w).name == "smith" -# bug #12015 -# The definition of the `%` proc needs to be here, since the `% c` calls below -# can only find our custom `%` proc for `Pix` if defined in global scope. -type - Pix = tuple[x, y: uint8, ch: uint16] -proc `%`(p: Pix): JsonNode = - result = %* { "x" : % p.x, - "y" : % p.y, - "ch" : % p.ch } -block: - type - Cluster = object - works: tuple[x, y: uint8, ch: uint16] # working - fails: Pix # previously broken + block: + # bug #12015 + type + Cluster = object + works: tuple[x, y: uint8, ch: uint16] # working + fails: Pix # previously broken - let data = (x: 123'u8, y: 53'u8, ch: 1231'u16) - let c = Cluster(works: data, fails: data) - let cFromJson = (% c).to(Cluster) - doAssert c == cFromJson + let data = (x: 123'u8, y: 53'u8, ch: 1231'u16) + let c = Cluster(works: data, fails: data) + let cFromJson = (% c).to(Cluster) + doAssert c == cFromJson -block: - # bug related to #12015 - type - PixInt = tuple[x, y, ch: int] - SomePix = Pix | PixInt - Cluster[T: SomePix] = seq[T] - ClusterObject[T: SomePix] = object - data: Cluster[T] - RecoEvent[T: SomePix] = object - cluster: seq[ClusterObject[T]] - - let data = @[(x: 123'u8, y: 53'u8, ch: 1231'u16)] - var c = RecoEvent[Pix](cluster: @[ClusterObject[Pix](data: data)]) - let cFromJson = (% c).to(RecoEvent[Pix]) - doAssert c == cFromJson - -# TODO: when the issue with the limeted vm registers is solved, the -# exact same test as above should be evaluated at compile time as -# well, to ensure that the vm functionality won't diverge from the -# runtime functionality. Until then, the following test should do it. + block: + # bug related to #12015 + type + PixInt = tuple[x, y, ch: int] + SomePix = Pix | PixInt + Cluster[T: SomePix] = seq[T] + ClusterObject[T: SomePix] = object + data: Cluster[T] + RecoEvent[T: SomePix] = object + cluster: seq[ClusterObject[T]] -static: - var t = parseJson(""" - { - "name":"Bongo", - "email":"bongo@bingo.com", - "list": [11,7,15], - "year": 1975, - "dict": {"a": 1, "b": 2}, - "arr": [1.0, 2.0, 7.0], - "person": {"name": "boney"}, - "dog": {"name": "honey"}, - "fruit": {"color": 10}, - "distfruit": {"color": 11}, - "emails": ["abc", "123"] - } - """) - - doAssert t["name"].getStr == "Bongo" - doAssert t["email"].getStr == "bongo@bingo.com" - doAssert t["list"][0].getInt == 11 - doAssert t["list"][1].getInt == 7 - doAssert t["list"][2].getInt == 15 - doAssert t["year"].getInt == 1975 - doAssert t["dict"]["a"].getInt == 1 - doAssert t["dict"]["b"].getInt == 2 - doAssert t["arr"][0].getFloat == 1.0 - doAssert t["arr"][1].getFloat == 2.0 - doAssert t["arr"][2].getFloat == 7.0 - doAssert t["person"]["name"].getStr == "boney" - doAssert t["distfruit"]["color"].getInt == 11 - doAssert t["dog"]["name"].getStr == "honey" - doAssert t["fruit"]["color"].getInt == 10 - doAssert t["emails"][0].getStr == "abc" - doAssert t["emails"][1].getStr == "123" - -block: - # ref objects with cycles. - type - Misdirection = object - cycle: Cycle + let data = @[(x: 123'u8, y: 53'u8, ch: 1231'u16)] + var c = RecoEvent[Pix](cluster: @[ClusterObject[Pix](data: data)]) + let cFromJson = (% c).to(RecoEvent[Pix]) + doAssert c == cFromJson - Cycle = ref object - foo: string - cycle: Misdirection - let data = """ - {"cycle": null} - """ + block: + # ref objects with cycles. + type + Misdirection = object + cycle: Cycle - let dataParsed = parseJson(data) - let dataDeser = to(dataParsed, Misdirection) + Cycle = ref object + foo: string + cycle: Misdirection -block: - # ref object from #12316 - type - Foo = ref Bar - Bar = object + let data = """ + {"cycle": null} + """ + + let dataParsed = parseJson(data) + let dataDeser = to(dataParsed, Misdirection) - discard "null".parseJson.to Foo + block: + # ref object from #12316 + type + Foo = ref Bar + Bar = object + + discard "null".parseJson.to Foo + + block: + # named array #12289 + type Vec = array[2, int] + let arr = "[1,2]".parseJson.to Vec + doAssert arr == [1,2] + + block: + # test error message in exception -block: - # named array #12289 - type Vec = array[2, int] - let arr = "[1,2]".parseJson.to Vec - doAssert arr == [1,2] + type + MyType = object + otherMember: string + member: MySubType + + MySubType = object + somethingElse: string + list: seq[MyData] + + MyData = object + value: int + + let jsonNode = parseJson(""" + { + "otherMember": "otherValue", + "member": { + "somethingElse": "something", + "list": [{"value": 1}, {"value": 2}, {}] + } + } + """) + + try: + let tmp = jsonNode.to(MyType) + doAssert false, "this should be unreachable" + except KeyError: + doAssert getCurrentExceptionMsg().contains ".member.list[2].value" + + + +testJson() +static: + testJson() |