More comprehensive test suite; Depends on Fixes in Nim 1.2
This commit is contained in:
parent
0eab8cfeee
commit
68e9ef7901
|
@ -122,7 +122,7 @@ macro enumAllSerializedFieldsImpl(T: type, body: untyped): untyped =
|
||||||
# TODO: This is a work-around for a classic Nim issue:
|
# TODO: This is a work-around for a classic Nim issue:
|
||||||
type `FieldTypeSym` {.used.} = type(`field`)
|
type `FieldTypeSym` {.used.} = type(`field`)
|
||||||
`body`
|
`body`
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
template enumAllSerializedFields*(T: type, body): untyped =
|
template enumAllSerializedFields*(T: type, body): untyped =
|
||||||
|
@ -181,21 +181,20 @@ proc makeFieldReadersTable(RecordType, Reader: distinct type):
|
||||||
when RecordType is tuple:
|
when RecordType is tuple:
|
||||||
const i = fieldName.parseInt
|
const i = fieldName.parseInt
|
||||||
try:
|
try:
|
||||||
|
|
||||||
type F = FieldTag[RecordType, fieldName, type(FieldType)]
|
type F = FieldTag[RecordType, fieldName, type(FieldType)]
|
||||||
when RecordType is not tuple:
|
when RecordType is tuple:
|
||||||
obj.field(fieldName) = readFieldIMPL(F, reader)
|
|
||||||
else:
|
|
||||||
obj[i] = readFieldIMPL(F, reader)
|
obj[i] = readFieldIMPL(F, reader)
|
||||||
|
else:
|
||||||
|
field(obj, fieldName) = readFieldIMPL(F, reader)
|
||||||
except SerializationError:
|
except SerializationError:
|
||||||
raise
|
raise
|
||||||
except CatchableError as err:
|
except CatchableError as err:
|
||||||
when RecordType is not tuple:
|
reader.handleReadException(
|
||||||
let field = obj.field(fieldName)
|
`RecordType`,
|
||||||
else:
|
fieldName,
|
||||||
let field = obj[i]
|
when RecordType is tuple: obj[i] else: field(obj, fieldName),
|
||||||
reader.handleReadException(`RecordType`, fieldName,
|
err)
|
||||||
field, err)
|
|
||||||
result.add((fieldName, readField))
|
result.add((fieldName, readField))
|
||||||
|
|
||||||
proc fieldReadersTable*(RecordType, Reader: distinct type):
|
proc fieldReadersTable*(RecordType, Reader: distinct type):
|
||||||
|
|
|
@ -14,30 +14,40 @@ type
|
||||||
ignored*: int
|
ignored*: int
|
||||||
|
|
||||||
Transaction* = object
|
Transaction* = object
|
||||||
amount: int
|
amount*: int
|
||||||
time: DateTime
|
time*: DateTime
|
||||||
sender: string
|
sender*: string
|
||||||
receiver: string
|
receiver*: string
|
||||||
|
|
||||||
|
DerivedFromRoot* = object of RootObj
|
||||||
|
a*: string
|
||||||
|
b*: int
|
||||||
|
|
||||||
|
DerivedFromRootRef = ref DerivedFromRoot
|
||||||
|
|
||||||
|
RefTypeDerivedFromRoot* = ref object of RootObj
|
||||||
|
a*: int
|
||||||
|
b*: string
|
||||||
|
|
||||||
Foo = object
|
Foo = object
|
||||||
x: uint64
|
x*: uint64
|
||||||
y: string
|
y*: string
|
||||||
z: seq[int]
|
z*: seq[int]
|
||||||
|
|
||||||
Bar = object
|
Bar = object
|
||||||
b: string
|
b*: string
|
||||||
f: Foo
|
f*: Foo
|
||||||
|
|
||||||
ListOfLists = object
|
|
||||||
lists: seq[ListOfLists]
|
|
||||||
|
|
||||||
# Baz should use custom serialization
|
# Baz should use custom serialization
|
||||||
# The `i` field should be multiplied by two while deserializing and
|
# The `i` field should be multiplied by two while deserializing and
|
||||||
# `ignored` field should be set to 10
|
# `ignored` field should be set to 10
|
||||||
Baz = object
|
Baz = object
|
||||||
f: Foo
|
f*: Foo
|
||||||
i: int
|
i*: int
|
||||||
ignored {.dontSerialize.}: int
|
ignored* {.dontSerialize.}: int
|
||||||
|
|
||||||
|
ListOfLists = object
|
||||||
|
lists*: seq[ListOfLists]
|
||||||
|
|
||||||
NoExpectedResult = distinct int
|
NoExpectedResult = distinct int
|
||||||
|
|
||||||
|
@ -46,7 +56,7 @@ type
|
||||||
B
|
B
|
||||||
|
|
||||||
CaseObject* = object
|
CaseObject* = object
|
||||||
case kind: ObjectKind:
|
case kind*: ObjectKind:
|
||||||
of A:
|
of A:
|
||||||
a*: int
|
a*: int
|
||||||
other*: CaseObjectRef
|
other*: CaseObjectRef
|
||||||
|
@ -55,6 +65,9 @@ type
|
||||||
|
|
||||||
CaseObjectRef* = ref CaseObject
|
CaseObjectRef* = ref CaseObject
|
||||||
|
|
||||||
|
HoldsCaseObject* = object
|
||||||
|
value: CaseObject
|
||||||
|
|
||||||
HoldsSet* = object
|
HoldsSet* = object
|
||||||
a*: int
|
a*: int
|
||||||
s*: HashSet[string]
|
s*: HashSet[string]
|
||||||
|
@ -111,22 +124,30 @@ func caseObjectEquals(a, b: CaseObject): bool =
|
||||||
func `==`*(a, b: CaseObject): bool =
|
func `==`*(a, b: CaseObject): bool =
|
||||||
caseObjectEquals(a, b)
|
caseObjectEquals(a, b)
|
||||||
|
|
||||||
|
template maybeDefer(x: auto): auto =
|
||||||
|
when type(x) is ref:
|
||||||
|
x[]
|
||||||
|
else:
|
||||||
|
x
|
||||||
|
|
||||||
template roundtripChecks*(Format: type, value: auto, expectedResult: auto) =
|
template roundtripChecks*(Format: type, value: auto, expectedResult: auto) =
|
||||||
let v = value
|
let origValue = value
|
||||||
let serialized = encode(Format, v)
|
let serialized = encode(Format, origValue)
|
||||||
checkpoint "(encoded value): " & $serialized
|
checkpoint "(encoded value): " & $serialized
|
||||||
|
|
||||||
when not (expectedResult is NoExpectedResult):
|
when not (expectedResult is NoExpectedResult):
|
||||||
check serialized == expectedResult
|
check serialized == expectedResult
|
||||||
|
|
||||||
try:
|
try:
|
||||||
let decoded = Format.decode(serialized, type(v))
|
let decoded = Format.decode(serialized, type(origValue))
|
||||||
checkpoint "(decoded value): " & repr(decoded)
|
checkpoint "(decoded value): " & repr(decoded)
|
||||||
let decodedValueMatchesOriginal = decoded == v
|
let success = maybeDefer(decoded) == maybeDefer(origValue)
|
||||||
check decodedValueMatchesOriginal
|
check success
|
||||||
|
|
||||||
except SerializationError as err:
|
except SerializationError as err:
|
||||||
checkpoint "(serialization error): " & err.formatMsg("(encoded value)")
|
checkpoint "(serialization error): " & err.formatMsg("(encoded value)")
|
||||||
fail()
|
fail()
|
||||||
|
|
||||||
except:
|
except:
|
||||||
when compiles($value):
|
when compiles($value):
|
||||||
checkpoint "unexpected failure in roundtrip test for " & $value
|
checkpoint "unexpected failure in roundtrip test for " & $value
|
||||||
|
@ -158,11 +179,8 @@ proc executeRoundtripTests*(Format: type) =
|
||||||
template intTests(T: untyped) =
|
template intTests(T: untyped) =
|
||||||
roundtrip low(T)
|
roundtrip low(T)
|
||||||
roundtrip high(T)
|
roundtrip high(T)
|
||||||
when false:
|
for i in 0..1000:
|
||||||
# TODO:
|
roundtrip rand(T)
|
||||||
# rand(low..high) produces an overflow error in Nim 1.0.2
|
|
||||||
for i in 0..1000:
|
|
||||||
roundtrip rand(low(T)..(high(T) div 2))
|
|
||||||
|
|
||||||
intTests int8
|
intTests int8
|
||||||
intTests int16
|
intTests int16
|
||||||
|
@ -194,9 +212,8 @@ proc executeRoundtripTests*(Format: type) =
|
||||||
f: Foo(x: 5'u64, y: "hocus pocus", z: @[100, 200, 300]))
|
f: Foo(x: 5'u64, y: "hocus pocus", z: @[100, 200, 300]))
|
||||||
roundtrip b
|
roundtrip b
|
||||||
|
|
||||||
when false:
|
when false and supports(Format, Transaction):
|
||||||
# TODO: This requires the test suite of each format to implement
|
# Some formats may not support the DateTime type.
|
||||||
# support for the DateTime type.
|
|
||||||
var t = Transaction(time: now(), amount: 1000, sender: "Alice", receiver: "Bob")
|
var t = Transaction(time: now(), amount: 1000, sender: "Alice", receiver: "Bob")
|
||||||
roundtrip t
|
roundtrip t
|
||||||
|
|
||||||
|
@ -205,21 +222,32 @@ proc executeRoundtripTests*(Format: type) =
|
||||||
# and give it a more proper name. The custom serialization demands
|
# and give it a more proper name. The custom serialization demands
|
||||||
# that the `ignored` field is populated with a value depending on
|
# that the `ignored` field is populated with a value depending on
|
||||||
# the `i` value. `i` itself is doubled on deserialization.
|
# the `i` value. `i` itself is doubled on deserialization.
|
||||||
var origVal = Baz(f: Foo(x: 10'u64, y: "y", z: @[]), ignored: 5)
|
let
|
||||||
bytes = Format.encode(origVal)
|
origVal = Baz(f: Foo(x: 10'u64, y: "y", z: @[]), ignored: 5)
|
||||||
var restored = Format.decode(bytes, Baz)
|
encoded = Format.encode(origVal)
|
||||||
|
restored = Format.decode(encoded, Baz)
|
||||||
|
|
||||||
check:
|
check:
|
||||||
origVal.f.x == restored.f.x
|
origVal.f.x == restored.f.x
|
||||||
origVal.f.i == restored.f.i div 2
|
|
||||||
origVal.f.y.len == restored.f.y.len
|
origVal.f.y.len == restored.f.y.len
|
||||||
|
origVal.i == restored.i div 2
|
||||||
restored.ignored == 10
|
restored.ignored == 10
|
||||||
|
|
||||||
|
block:
|
||||||
|
let
|
||||||
|
a = DerivedFromRoot(a: "test", b: -1000)
|
||||||
|
b = DerivedFromRootRef(a: "another test", b: 2000)
|
||||||
|
c = RefTypeDerivedFromRoot(a: high(int), b: "")
|
||||||
|
|
||||||
|
roundtrip a
|
||||||
|
roundtrip b
|
||||||
|
roundtrip c
|
||||||
|
|
||||||
test "case objects":
|
test "case objects":
|
||||||
var
|
var
|
||||||
c1 = CaseObjectRef(kind: B, b: 100)
|
c1 = CaseObjectRef(kind: B, b: 100)
|
||||||
c2 = CaseObjectRef(kind: A, a: 80, other: CaseObjectRef(kind: B))
|
c2 = CaseObjectRef(kind: A, a: 80, other: CaseObjectRef(kind: B))
|
||||||
c3 = CaseObject(kind: A, a: 60, other: nil)
|
c3 = HoldsCaseObject(value: CaseObject(kind: A, a: 60, other: c1))
|
||||||
|
|
||||||
roundtrip c1
|
roundtrip c1
|
||||||
roundtrip c2
|
roundtrip c2
|
||||||
|
@ -263,11 +291,11 @@ proc executeRoundtripTests*(Format: type) =
|
||||||
roundtrip s1
|
roundtrip s1
|
||||||
roundtrip s2
|
roundtrip s2
|
||||||
|
|
||||||
test "tuple":
|
test "tuple":
|
||||||
var t = (0, "e")
|
var t = (0, "e")
|
||||||
var namedT = (a: 0, b: "e")
|
var namedT = (a: 0, b: "e")
|
||||||
roundtrip t
|
roundtrip t
|
||||||
roundtrip namedT
|
roundtrip namedT
|
||||||
|
|
||||||
proc executeReaderWriterTests*(Format: type) =
|
proc executeReaderWriterTests*(Format: type) =
|
||||||
mixin init, ReaderType, WriterType
|
mixin init, ReaderType, WriterType
|
||||||
|
|
Loading…
Reference in New Issue