nim-json-serialization/tests/test_json_flavor.nim

202 lines
5.4 KiB
Nim

# json-serialization
# Copyright (c) 2019-2023 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
std/[strutils, options],
unittest2,
results,
serialization,
../json_serialization/stew/results,
../json_serialization/std/options,
../json_serialization
createJsonFlavor StringyJson
proc writeValue*(
w: var JsonWriter[StringyJson], val: SomeInteger) {.raises: [IOError].} =
writeValue(w, $val)
proc readValue*(r: var JsonReader[StringyJson], v: var SomeSignedInt) =
try:
v = type(v) parseBiggestInt readValue(r, string)
except ValueError as err:
r.raiseUnexpectedValue("A signed integer encoded as string " & err.msg)
proc readValue*(r: var JsonReader[StringyJson], v: var SomeUnsignedInt) =
try:
v = type(v) parseBiggestUInt readValue(r, string)
except ValueError as err:
r.raiseUnexpectedValue("An unsigned integer encoded as string " & err.msg)
type
Container = object
name: string
x: int
y: uint64
list: seq[int64]
OptionalFields = object
one: Opt[string]
two: Option[int]
SpecialTypes = object
one: JsonVoid
two: JsonNumber[uint64]
three: JsonNumber[string]
four: JsonValueRef[uint64]
ListOnly = object
list: JsonString
Container.useDefaultSerializationIn StringyJson
createJsonFlavor OptJson
OptionalFields.useDefaultSerializationIn OptJson
const
jsonText = """
{
"one": "this text will gone",
"two": -789.0009E-19,
"three": 999.776000E+33,
"four" : {
"apple": [1, true, "three"],
"banana": {
"chip": 123,
"z": null,
"v": false
}
}
}
"""
jsonTextWithNullFields = """
{
"list": null
}
"""
createJsonFlavor NullyFields,
skipNullFields = true,
requireAllFields = false
Container.useDefaultSerializationIn NullyFields
ListOnly.useDefaultSerializationIn NullyFields
suite "Test JsonFlavor":
test "basic test":
let c = Container(name: "c", x: -10, y: 20, list: @[1'i64, 2, 25])
let encoded = StringyJson.encode(c)
check encoded == """{"name":"c","x":"-10","y":"20","list":["1","2","25"]}"""
let decoded = StringyJson.decode(encoded, Container)
check decoded == Container(name: "c", x: -10, y: 20, list: @[1, 2, 25])
test "optional fields":
let a = OptionalFields(one: Opt.some("hello"))
let b = OptionalFields(two: some(567))
let c = OptionalFields(one: Opt.some("burn"), two: some(333))
let aa = OptJson.encode(a)
check aa == """{"one":"hello"}"""
let bb = OptJson.encode(b)
check bb == """{"two":567}"""
let cc = OptJson.encode(c)
check cc == """{"one":"burn","two":333}"""
test "Write special types":
let vv = Json.decode(jsonText, SpecialTypes)
let xx = Json.encode(vv)
var ww = Json.decode(xx, SpecialTypes)
ww.three.expSign = JsonSign.Pos # the rest of it should identical to vv
check:
ww == vv
xx == """{"two":-789.0009e-19,"three":999.776000e33,"four":{"apple":[1,true,"three"],"banana":{"chip":123,"z":null,"v":false}}}"""
test "object with null fields":
expect JsonReaderError:
let x = Json.decode(jsonTextWithNullFields, Container)
discard x
let x = NullyFields.decode(jsonTextWithNullFields, Container)
check x.list.len == 0
# field should not processed at all
let y = NullyFields.decode(jsonTextWithNullFields, ListOnly)
check y.list.string.len == 0
test "Enum value representation primitives":
when NullyFields.flavorEnumRep() == EnumAsString:
check true
elif NullyFields.flavorEnumRep() == EnumAsNumber:
check false
elif NullyFields.flavorEnumRep() == EnumAsStringifiedNumber:
check false
NullyFields.flavorEnumRep(EnumAsNumber)
when NullyFields.flavorEnumRep() == EnumAsString:
check false
elif NullyFields.flavorEnumRep() == EnumAsNumber:
check true
elif NullyFields.flavorEnumRep() == EnumAsStringifiedNumber:
check false
NullyFields.flavorEnumRep(EnumAsStringifiedNumber)
when NullyFields.flavorEnumRep() == EnumAsString:
check false
elif NullyFields.flavorEnumRep() == EnumAsNumber:
check false
elif NullyFields.flavorEnumRep() == EnumAsStringifiedNumber:
check true
test "Enum value representation of custom flavor":
type
ExoticFruits = enum
DragonFruit
SnakeFruit
StarFruit
NullyFields.flavorEnumRep(EnumAsNumber)
let u = NullyFields.encode(DragonFruit)
check u == "0"
NullyFields.flavorEnumRep(EnumAsString)
let v = NullyFields.encode(SnakeFruit)
check v == "\"SnakeFruit\""
NullyFields.flavorEnumRep(EnumAsStringifiedNumber)
let w = NullyFields.encode(StarFruit)
check w == "\"2\""
test "EnumAsString of custom flavor":
type
Fruit = enum
Banana = "BaNaNa"
Apple = "ApplE"
JackFruit = "VVV"
NullyFields.flavorEnumRep(EnumAsString)
let u = NullyFields.encode(Banana)
check u == "\"BaNaNa\""
let v = NullyFields.encode(Apple)
check v == "\"ApplE\""
let w = NullyFields.encode(JackFruit)
check w == "\"VVV\""
NullyFields.flavorEnumRep(EnumAsStringifiedNumber)
let x = NullyFields.encode(JackFruit)
check x == "\"2\""
NullyFields.flavorEnumRep(EnumAsNumber)
let z = NullyFields.encode(Banana)
check z == "0"