mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-06 20:04:18 +00:00
Extent json.to testing to VM, add workrounds for VM bugs. (#12493)
fixes #12479
This commit is contained in:
committed by
Andreas Rumpf
parent
a2ad7d4883
commit
5ed99f8d3f
@@ -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]]
|
||||
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
|
||||
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:
|
||||
# ref objects with cycles.
|
||||
type
|
||||
Misdirection = object
|
||||
cycle: Cycle
|
||||
|
||||
Cycle = ref object
|
||||
foo: string
|
||||
cycle: Misdirection
|
||||
|
||||
let data = """
|
||||
{"cycle": null}
|
||||
"""
|
||||
|
||||
let dataParsed = parseJson(data)
|
||||
let dataDeser = to(dataParsed, Misdirection)
|
||||
|
||||
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
|
||||
|
||||
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:
|
||||
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
|
||||
|
||||
Cycle = ref object
|
||||
foo: string
|
||||
cycle: Misdirection
|
||||
|
||||
let data = """
|
||||
{"cycle": null}
|
||||
"""
|
||||
|
||||
let dataParsed = parseJson(data)
|
||||
let dataDeser = to(dataParsed, Misdirection)
|
||||
|
||||
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]
|
||||
testJson()
|
||||
|
||||
Reference in New Issue
Block a user