2016-02-27 12:09:50 +00:00
|
|
|
# NimYAML - YAML implementation in Nim
|
2023-08-29 21:23:15 +00:00
|
|
|
# (c) Copyright 2015-2023 Felix Krause
|
2016-02-27 12:09:50 +00:00
|
|
|
#
|
|
|
|
# See the file "copying.txt", included in this
|
|
|
|
# distribution, for details about the copyright.
|
|
|
|
|
2016-02-12 19:44:38 +00:00
|
|
|
import "../yaml"
|
2020-03-08 18:58:02 +00:00
|
|
|
import unittest, strutils, tables, times, math, options
|
2023-07-31 17:16:24 +00:00
|
|
|
import commonTestUtils
|
2015-12-29 14:09:37 +00:00
|
|
|
|
2016-02-01 18:48:42 +00:00
|
|
|
type
|
2016-04-02 15:48:22 +00:00
|
|
|
MyTuple = tuple
|
|
|
|
str: string
|
|
|
|
i: int32
|
|
|
|
b: bool
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-04-02 15:48:22 +00:00
|
|
|
TrafficLight = enum
|
|
|
|
tlGreen, tlYellow, tlRed
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-04-02 15:48:22 +00:00
|
|
|
Person = object
|
|
|
|
firstnamechar: char
|
|
|
|
surname: string
|
|
|
|
age: int32
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-04-02 15:48:22 +00:00
|
|
|
Node = object
|
|
|
|
value: string
|
|
|
|
next: ref Node
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-04-04 18:44:16 +00:00
|
|
|
BetterInt = distinct int
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-06-08 17:15:50 +00:00
|
|
|
AnimalKind = enum
|
|
|
|
akCat, akDog
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-06-08 17:15:50 +00:00
|
|
|
Animal = object
|
|
|
|
name: string
|
|
|
|
case kind: AnimalKind
|
|
|
|
of akCat:
|
|
|
|
purringIntensity: int
|
2016-11-30 17:01:03 +00:00
|
|
|
of akDog: barkometer: int
|
2016-04-04 18:44:16 +00:00
|
|
|
|
2016-10-15 15:58:29 +00:00
|
|
|
DumbEnum = enum
|
2020-06-26 19:29:41 +00:00
|
|
|
deA, deB, deC
|
2016-10-15 15:58:29 +00:00
|
|
|
|
|
|
|
NonVariantWithTransient = object
|
2020-06-26 19:29:41 +00:00
|
|
|
a {.transient.}, b, c {.transient.}, d: string
|
2016-10-15 15:58:29 +00:00
|
|
|
|
|
|
|
VariantWithTransient = object
|
2020-06-26 19:29:41 +00:00
|
|
|
gStorable: string
|
|
|
|
gTemporary {.transient.}: string
|
2016-10-15 15:58:29 +00:00
|
|
|
case kind: DumbEnum
|
2020-06-26 19:29:41 +00:00
|
|
|
of deA:
|
|
|
|
cStorable: string
|
|
|
|
cTemporary {.transient.}: string
|
|
|
|
of deB:
|
2016-10-15 15:58:29 +00:00
|
|
|
alwaysThere: int
|
2020-06-26 19:29:41 +00:00
|
|
|
of deC:
|
|
|
|
neverThere {.transient.}: int
|
2016-10-15 15:58:29 +00:00
|
|
|
|
2016-10-26 16:32:54 +00:00
|
|
|
WithDefault = object
|
2020-06-26 19:29:41 +00:00
|
|
|
a, b {.defaultVal: "b".}, c, d {.defaultVal: "d".}: string
|
2016-10-26 16:32:54 +00:00
|
|
|
|
2020-06-26 19:29:41 +00:00
|
|
|
WithIgnoredField {.ignore: ["z"].} = object
|
2016-10-27 15:58:14 +00:00
|
|
|
x, y: int
|
|
|
|
|
2023-04-04 17:29:20 +00:00
|
|
|
Parent = object of RootObj
|
|
|
|
i*: int
|
|
|
|
Child = object of Parent
|
|
|
|
s*: string
|
|
|
|
|
2016-04-04 18:44:16 +00:00
|
|
|
proc `$`(v: BetterInt): string {.borrow.}
|
2016-08-17 20:50:37 +00:00
|
|
|
proc `==`(left, right: BetterInt): bool {.borrow.}
|
2016-02-01 18:48:42 +00:00
|
|
|
|
2021-03-23 17:51:05 +00:00
|
|
|
setTag(TrafficLight, Tag("!tl"))
|
|
|
|
setTag(Node, Tag("!example.net:Node"))
|
|
|
|
setTag(BetterInt, Tag("!test:BetterInt"))
|
2016-02-16 18:24:55 +00:00
|
|
|
|
2023-08-29 18:46:26 +00:00
|
|
|
const yamlDir = "---"
|
|
|
|
const yamlTagDirs = "%TAG !n! tag:nimyaml.org,2016:\n---"
|
|
|
|
|
|
|
|
proc representObject*(
|
2023-08-29 21:23:15 +00:00
|
|
|
ctx : var SerializationContext,
|
2023-08-29 18:46:26 +00:00
|
|
|
value: BetterInt,
|
2023-08-29 21:23:15 +00:00
|
|
|
tag : Tag
|
2023-08-29 18:46:26 +00:00
|
|
|
) {.raises: [].} =
|
2016-09-01 18:56:34 +00:00
|
|
|
var
|
|
|
|
val = $value
|
|
|
|
i = val.len - 3
|
|
|
|
while i > 0:
|
|
|
|
val.insert("_", i)
|
|
|
|
i -= 3
|
2023-08-29 18:46:26 +00:00
|
|
|
ctx.put(scalarEvent(val, tag, yAnchorNone))
|
2016-02-16 18:24:55 +00:00
|
|
|
|
2023-08-29 21:23:15 +00:00
|
|
|
proc constructObject*(
|
|
|
|
ctx : var ConstructionContext,
|
|
|
|
result: var BetterInt,
|
|
|
|
) {.raises: [YamlConstructionError, YamlStreamError].} =
|
|
|
|
ctx.input.constructScalarItem(item, BetterInt):
|
2016-04-02 15:48:22 +00:00
|
|
|
result = BetterInt(parseBiggestInt(item.scalarContent) + 1)
|
2016-02-15 18:46:21 +00:00
|
|
|
|
2016-09-24 14:45:49 +00:00
|
|
|
template expectConstructionError(li, co: int, message: string, body: typed) =
|
2016-09-23 13:42:24 +00:00
|
|
|
try:
|
|
|
|
body
|
|
|
|
echo "Expected YamlConstructionError, but none was raised!"
|
|
|
|
fail()
|
2023-03-18 12:54:45 +00:00
|
|
|
except YamlConstructionError as e:
|
2020-11-06 15:21:58 +00:00
|
|
|
doAssert li == e.mark.line, "Expected error line " & $li & ", was " & $e.mark.line
|
|
|
|
doAssert co == e.mark.column, "Expected error column " & $co & ", was " & $e.mark.column
|
2016-10-19 20:04:46 +00:00
|
|
|
doAssert message == e.msg, "Expected error message \n" & escape(message) &
|
|
|
|
", got \n" & escape(e.msg)
|
2016-09-23 13:42:24 +00:00
|
|
|
|
2016-01-28 21:57:14 +00:00
|
|
|
proc newNode(v: string): ref Node =
|
2016-04-02 15:48:22 +00:00
|
|
|
new(result)
|
|
|
|
result.value = v
|
|
|
|
result.next = nil
|
2015-12-29 14:09:37 +00:00
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
template dualTest(name: string, body: untyped) =
|
|
|
|
test name:
|
|
|
|
body
|
|
|
|
|
|
|
|
# fix for compiler problem (comptime doesn't work when included from tests.nim)
|
|
|
|
# possibly this issue: https://github.com/nim-lang/Nim/issues/18103
|
|
|
|
when isMainModule:
|
|
|
|
test name & " [comptime]":
|
|
|
|
static: body
|
|
|
|
|
2016-08-17 20:50:37 +00:00
|
|
|
suite "Serialization":
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load integer without fixed length":
|
2017-02-13 16:10:56 +00:00
|
|
|
var input = "-4247"
|
2016-04-04 18:44:16 +00:00
|
|
|
var result: int
|
|
|
|
load(input, result)
|
2016-09-20 19:53:38 +00:00
|
|
|
assert result == -4247, "result is " & $result
|
|
|
|
|
2017-02-13 16:10:56 +00:00
|
|
|
input = $(int64(int32.high) + 1'i64)
|
2016-04-04 18:44:16 +00:00
|
|
|
var gotException = false
|
|
|
|
try: load(input, result)
|
2023-08-29 18:46:26 +00:00
|
|
|
except YamlConstructionError: gotException = true
|
2016-04-04 18:44:16 +00:00
|
|
|
assert gotException, "Expected exception, got none."
|
|
|
|
|
2016-09-14 16:31:09 +00:00
|
|
|
test "Dump integer without fixed length":
|
2016-04-04 18:44:16 +00:00
|
|
|
var input = -4247
|
2023-08-29 18:46:26 +00:00
|
|
|
var output = blockOnlyDumper().dump(input)
|
|
|
|
assertStringEqual "\"-4247\"\n", output
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-04-04 18:44:16 +00:00
|
|
|
when sizeof(int) == sizeof(int64):
|
|
|
|
input = int(int32.high) + 1
|
|
|
|
var gotException = false
|
2023-08-29 18:46:26 +00:00
|
|
|
try: output = blockOnlyDumper().dump(input)
|
|
|
|
except YamlSerializationError: gotException = true
|
2016-04-04 18:44:16 +00:00
|
|
|
assert gotException, "Expected exception, got none."
|
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load Hex byte (0xFF)":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input = "0xFF"
|
2016-09-19 18:51:50 +00:00
|
|
|
var result: byte
|
|
|
|
load(input, result)
|
|
|
|
assert(result == 255)
|
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load Hex byte (0xC)":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input = "0xC"
|
2016-09-19 18:51:50 +00:00
|
|
|
var result: byte
|
|
|
|
load(input, result)
|
|
|
|
assert(result == 12)
|
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load Octal byte (0o14)":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input = "0o14"
|
2016-09-19 18:51:50 +00:00
|
|
|
var result: byte
|
|
|
|
load(input, result)
|
|
|
|
assert(result == 12)
|
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load byte (14)":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input = "14"
|
2016-09-19 18:51:50 +00:00
|
|
|
var result: byte
|
|
|
|
load(input, result)
|
|
|
|
assert(result == 14)
|
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load Hex int (0xFF)":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input = "0xFF"
|
2016-09-19 18:51:50 +00:00
|
|
|
var result: int
|
|
|
|
load(input, result)
|
|
|
|
assert(result == 255)
|
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load Hex int (0xC)":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input = "0xC"
|
2016-09-19 18:51:50 +00:00
|
|
|
var result: int
|
|
|
|
load(input, result)
|
|
|
|
assert(result == 12)
|
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load Octal int (0o14)":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input = "0o14"
|
2016-09-19 18:51:50 +00:00
|
|
|
var result: int
|
|
|
|
load(input, result)
|
|
|
|
assert(result == 12)
|
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load int (14)":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input = "14"
|
2016-09-19 18:51:50 +00:00
|
|
|
var result: int
|
|
|
|
load(input, result)
|
|
|
|
assert(result == 14)
|
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load floats":
|
2016-11-10 09:12:32 +00:00
|
|
|
let input = "[6.8523015e+5, 685.230_15e+03, 685_230.15, -.inf, .NaN]"
|
|
|
|
var result: seq[float]
|
|
|
|
load(input, result)
|
|
|
|
for i in 0..2:
|
|
|
|
assert result[i] == 6.8523015e+5
|
|
|
|
assert result[3] == NegInf
|
|
|
|
assert classify(result[4]) == fcNan
|
|
|
|
|
2016-11-08 20:13:01 +00:00
|
|
|
test "Load timestamps":
|
|
|
|
let input = "[2001-12-15T02:59:43.1Z, 2001-12-14t21:59:43.10-05:00, 2001-12-14 21:59:43.10-5]"
|
|
|
|
var result: seq[Time]
|
|
|
|
load(input, result)
|
|
|
|
assert result.len() == 3
|
|
|
|
# currently, there is no good way of checking the result content, because
|
|
|
|
# the parsed Time may have any timezone offset.
|
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load string sequence":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input = " - a\n - b"
|
2016-04-02 15:48:22 +00:00
|
|
|
var result: seq[string]
|
|
|
|
load(input, result)
|
|
|
|
assert result.len == 2
|
|
|
|
assert result[0] == "a"
|
|
|
|
assert result[1] == "b"
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-09-14 16:31:09 +00:00
|
|
|
test "Dump string sequence":
|
2016-04-02 15:48:22 +00:00
|
|
|
var input = @["a", "b"]
|
2023-08-29 18:46:26 +00:00
|
|
|
var output = blockOnlyDumper().dump(input)
|
|
|
|
assertStringEqual "- a\n- b\n", output
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load char set":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input = "- a\n- b"
|
2016-04-02 16:29:26 +00:00
|
|
|
var result: set[char]
|
|
|
|
load(input, result)
|
|
|
|
assert result.card == 2
|
|
|
|
assert 'a' in result
|
|
|
|
assert 'b' in result
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-09-14 16:31:09 +00:00
|
|
|
test "Dump char set":
|
2016-04-02 16:29:26 +00:00
|
|
|
var input = {'a', 'b'}
|
2023-08-29 18:46:26 +00:00
|
|
|
var output = blockOnlyDumper().dump(input)
|
|
|
|
assertStringEqual "- a\n- b\n", output
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load array":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input = "- 23\n- 42\n- 47"
|
2016-04-03 09:29:49 +00:00
|
|
|
var result: array[0..2, int32]
|
|
|
|
load(input, result)
|
|
|
|
assert result[0] == 23
|
|
|
|
assert result[1] == 42
|
|
|
|
assert result[2] == 47
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-09-14 16:31:09 +00:00
|
|
|
test "Dump array":
|
2016-04-03 09:29:49 +00:00
|
|
|
let input = [23'i32, 42'i32, 47'i32]
|
2023-08-29 18:46:26 +00:00
|
|
|
var output = blockOnlyDumper().dump(input)
|
|
|
|
assertStringEqual "- 23\n- 42\n- 47\n", output
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load Option":
|
2020-03-08 18:58:02 +00:00
|
|
|
let input = "- Some\n- !!null ~"
|
|
|
|
var result: array[0..1, Option[string]]
|
|
|
|
load(input, result)
|
|
|
|
assert result[0].isSome
|
|
|
|
assert result[0].get() == "Some"
|
|
|
|
assert not result[1].isSome
|
2020-06-26 19:29:41 +00:00
|
|
|
|
2020-03-08 18:58:02 +00:00
|
|
|
test "Dump Option":
|
|
|
|
let input = [none(int32), some(42'i32), none(int32)]
|
2023-08-29 18:46:26 +00:00
|
|
|
let output = blockOnlyDumper().dump(input)
|
|
|
|
assertStringEqual "- !!null ~\n- 42\n- !!null ~\n", output
|
2020-03-08 18:58:02 +00:00
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load Table[int, string]":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input = "23: dreiundzwanzig\n42: zweiundvierzig"
|
2016-04-02 15:48:22 +00:00
|
|
|
var result: Table[int32, string]
|
|
|
|
load(input, result)
|
|
|
|
assert result.len == 2
|
|
|
|
assert result[23] == "dreiundzwanzig"
|
|
|
|
assert result[42] == "zweiundvierzig"
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-09-14 16:31:09 +00:00
|
|
|
test "Dump Table[int, string]":
|
2016-04-02 15:48:22 +00:00
|
|
|
var input = initTable[int32, string]()
|
|
|
|
input[23] = "dreiundzwanzig"
|
|
|
|
input[42] = "zweiundvierzig"
|
2023-08-29 18:46:26 +00:00
|
|
|
var output = blockOnlyDumper().dump(input)
|
|
|
|
assertStringEqual("23: dreiundzwanzig\n42: zweiundvierzig\n",
|
2016-09-19 17:33:29 +00:00
|
|
|
output)
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load OrderedTable[tuple[int32, int32], string]":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input = "- {a: 23, b: 42}: drzw\n- {a: 13, b: 47}: drsi"
|
2016-04-02 15:48:22 +00:00
|
|
|
var result: OrderedTable[tuple[a, b: int32], string]
|
2016-08-15 19:30:49 +00:00
|
|
|
load(input, result)
|
2016-04-02 15:48:22 +00:00
|
|
|
var i = 0
|
|
|
|
for key, value in result.pairs:
|
|
|
|
case i
|
|
|
|
of 0:
|
|
|
|
assert key == (a: 23'i32, b: 42'i32)
|
|
|
|
assert value == "drzw"
|
|
|
|
of 1:
|
|
|
|
assert key == (a: 13'i32, b: 47'i32)
|
|
|
|
assert value == "drsi"
|
|
|
|
else: assert false
|
|
|
|
i.inc()
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-09-14 16:31:09 +00:00
|
|
|
test "Dump OrderedTable[tuple[int32, int32], string]":
|
2016-04-02 15:48:22 +00:00
|
|
|
var input = initOrderedTable[tuple[a, b: int32], string]()
|
2020-11-06 15:21:58 +00:00
|
|
|
input[(a: 23'i32, b: 42'i32)] = "dreiundzwanzigzweiundvierzig"
|
|
|
|
input[(a: 13'i32, b: 47'i32)] = "dreizehnsiebenundvierzig"
|
2023-08-29 18:46:26 +00:00
|
|
|
var dumper = blockOnlyDumper()
|
|
|
|
dumper.serialization.tagStyle = tsRootOnly
|
|
|
|
dumper.serialization.handles = initNimYamlTagHandle()
|
|
|
|
var output = dumper.dump(input)
|
|
|
|
assertStringEqual(yamlTagDirs &
|
2023-07-31 17:16:24 +00:00
|
|
|
" !n!tables:OrderedTable(tag:nimyaml.org;2016:tuple(tag:nimyaml.org;2016:system:int32;tag:nimyaml.org;2016:system:int32);tag:yaml.org;2002:str)\n" &
|
|
|
|
"- ? a: 23\n" &
|
2020-11-06 20:39:50 +00:00
|
|
|
" b: 42\n" &
|
|
|
|
" : dreiundzwanzigzweiundvierzig\n" &
|
2023-07-31 17:16:24 +00:00
|
|
|
"- ? a: 13\n" &
|
2020-11-06 20:39:50 +00:00
|
|
|
" b: 47\n" &
|
2022-09-07 13:11:59 +00:00
|
|
|
" : dreizehnsiebenundvierzig\n", output)
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load Sequences in Sequence":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input = " - [1, 2, 3]\n - [4, 5]\n - [6]"
|
2016-04-02 15:48:22 +00:00
|
|
|
var result: seq[seq[int32]]
|
|
|
|
load(input, result)
|
|
|
|
assert result.len == 3
|
|
|
|
assert result[0] == @[1.int32, 2.int32, 3.int32]
|
|
|
|
assert result[1] == @[4.int32, 5.int32]
|
|
|
|
assert result[2] == @[6.int32]
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-09-14 16:31:09 +00:00
|
|
|
test "Dump Sequences in Sequence":
|
2016-04-02 15:48:22 +00:00
|
|
|
let input = @[@[1.int32, 2.int32, 3.int32], @[4.int32, 5.int32], @[6.int32]]
|
2023-08-29 18:46:26 +00:00
|
|
|
var output = Dumper().dump(input)
|
|
|
|
assertStringEqual "- [1, 2, 3]\n- [4, 5]\n- [6]\n", output
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load Enum":
|
2016-09-19 17:33:29 +00:00
|
|
|
let input =
|
2017-02-13 16:10:56 +00:00
|
|
|
"!<tag:nimyaml.org,2016:system:seq(tl)>\n- !tl tlRed\n- tlGreen\n- tlYellow"
|
2016-04-02 15:48:22 +00:00
|
|
|
var result: seq[TrafficLight]
|
|
|
|
load(input, result)
|
|
|
|
assert result.len == 3
|
|
|
|
assert result[0] == tlRed
|
|
|
|
assert result[1] == tlGreen
|
|
|
|
assert result[2] == tlYellow
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-09-14 16:31:09 +00:00
|
|
|
test "Dump Enum":
|
2016-04-02 15:48:22 +00:00
|
|
|
let input = @[tlRed, tlGreen, tlYellow]
|
2023-08-29 18:46:26 +00:00
|
|
|
var output = blockOnlyDumper().dump(input)
|
|
|
|
assertStringEqual "- tlRed\n- tlGreen\n- tlYellow\n", output
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load Tuple":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input = "str: value\ni: 42\nb: true"
|
2016-04-02 15:48:22 +00:00
|
|
|
var result: MyTuple
|
|
|
|
load(input, result)
|
|
|
|
assert result.str == "value"
|
|
|
|
assert result.i == 42
|
|
|
|
assert result.b == true
|
2016-02-01 18:48:42 +00:00
|
|
|
|
2016-09-14 16:31:09 +00:00
|
|
|
test "Dump Tuple":
|
2016-04-02 15:48:22 +00:00
|
|
|
let input = (str: "value", i: 42.int32, b: true)
|
2023-08-29 18:46:26 +00:00
|
|
|
var output = Dumper().dump(input)
|
|
|
|
assertStringEqual "str: value\ni: 42\nb: true\n", output
|
2016-09-19 18:51:50 +00:00
|
|
|
|
2016-09-21 13:40:03 +00:00
|
|
|
test "Load Tuple - unknown field":
|
|
|
|
let input = "str: value\nfoo: bar\ni: 42\nb: true"
|
|
|
|
var result: MyTuple
|
2016-09-24 14:45:49 +00:00
|
|
|
expectConstructionError(2, 1, "While constructing MyTuple: Unknown field: \"foo\""):
|
2016-09-21 13:40:03 +00:00
|
|
|
load(input, result)
|
|
|
|
|
|
|
|
test "Load Tuple - missing field":
|
|
|
|
let input = "str: value\nb: true"
|
|
|
|
var result: MyTuple
|
2020-11-10 14:40:01 +00:00
|
|
|
expectConstructionError(1, 1, "While constructing MyTuple: Missing field: \"i\""):
|
2016-09-21 13:40:03 +00:00
|
|
|
load(input, result)
|
|
|
|
|
|
|
|
test "Load Tuple - duplicate field":
|
|
|
|
let input = "str: value\ni: 42\nb: true\nb: true"
|
|
|
|
var result: MyTuple
|
2016-09-24 14:45:49 +00:00
|
|
|
expectConstructionError(4, 1, "While constructing MyTuple: Duplicate field: \"b\""):
|
2016-09-21 13:40:03 +00:00
|
|
|
load(input, result)
|
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load Multiple Documents":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input = "1\n---\n2"
|
2016-09-19 18:51:50 +00:00
|
|
|
var result: seq[int]
|
|
|
|
loadMultiDoc(input, result)
|
2016-09-19 20:51:33 +00:00
|
|
|
assert(result.len == 2)
|
2016-09-19 18:51:50 +00:00
|
|
|
assert result[0] == 1
|
|
|
|
assert result[1] == 2
|
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load Multiple Documents (Single Doc)":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input = "1"
|
2016-09-19 18:51:50 +00:00
|
|
|
var result: seq[int]
|
|
|
|
loadMultiDoc(input, result)
|
2016-09-19 20:51:33 +00:00
|
|
|
assert(result.len == 1)
|
2016-09-19 18:51:50 +00:00
|
|
|
assert result[0] == 1
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load custom object":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input = "firstnamechar: P\nsurname: Pan\nage: 12"
|
2016-04-02 15:48:22 +00:00
|
|
|
var result: Person
|
|
|
|
load(input, result)
|
|
|
|
assert result.firstnamechar == 'P'
|
2018-10-11 12:20:09 +00:00
|
|
|
assert result.surname == "Pan"
|
2016-04-02 15:48:22 +00:00
|
|
|
assert result.age == 12
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-09-14 16:31:09 +00:00
|
|
|
test "Dump custom object":
|
2016-04-02 15:48:22 +00:00
|
|
|
let input = Person(firstnamechar: 'P', surname: "Pan", age: 12)
|
2023-08-29 18:46:26 +00:00
|
|
|
var output = blockOnlyDumper().dump(input)
|
|
|
|
assertStringEqual(
|
|
|
|
"firstnamechar: P\nsurname: Pan\nage: 12\n", output)
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-09-21 13:40:03 +00:00
|
|
|
test "Load custom object - unknown field":
|
2016-09-23 13:42:24 +00:00
|
|
|
let input = " firstnamechar: P\n surname: Pan\n age: 12\n occupation: free"
|
2016-09-21 13:40:03 +00:00
|
|
|
var result: Person
|
2016-09-24 14:45:49 +00:00
|
|
|
expectConstructionError(4, 3, "While constructing Person: Unknown field: \"occupation\""):
|
2016-09-21 13:40:03 +00:00
|
|
|
load(input, result)
|
|
|
|
|
|
|
|
test "Load custom object - missing field":
|
2016-09-23 13:42:24 +00:00
|
|
|
let input = "surname: Pan\nage: 12\n "
|
2016-09-21 13:40:03 +00:00
|
|
|
var result: Person
|
2020-11-10 14:40:01 +00:00
|
|
|
expectConstructionError(1, 1, "While constructing Person: Missing field: \"firstnamechar\""):
|
2016-09-21 13:40:03 +00:00
|
|
|
load(input, result)
|
|
|
|
|
|
|
|
test "Load custom object - duplicate field":
|
|
|
|
let input = "firstnamechar: P\nsurname: Pan\nage: 12\nsurname: Pan"
|
|
|
|
var result: Person
|
2016-09-24 14:45:49 +00:00
|
|
|
expectConstructionError(4, 1, "While constructing Person: Duplicate field: \"surname\""):
|
2016-09-21 13:40:03 +00:00
|
|
|
load(input, result)
|
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load sequence with explicit tags":
|
2023-08-29 18:46:26 +00:00
|
|
|
let input = yamlTagDirs & " !n!system:seq(" &
|
2017-02-13 16:10:56 +00:00
|
|
|
"tag:yaml.org;2002:str)\n- !!str one\n- !!str two"
|
2016-04-02 15:48:22 +00:00
|
|
|
var result: seq[string]
|
|
|
|
load(input, result)
|
|
|
|
assert result[0] == "one"
|
|
|
|
assert result[1] == "two"
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-09-14 16:31:09 +00:00
|
|
|
test "Dump sequence with explicit tags":
|
2016-04-02 15:48:22 +00:00
|
|
|
let input = @["one", "two"]
|
2023-08-29 18:46:26 +00:00
|
|
|
var dumper = blockOnlyDumper()
|
|
|
|
dumper.serialization.tagStyle = tsAll
|
|
|
|
dumper.serialization.handles = initNimYamlTagHandle()
|
|
|
|
var output = dumper.dump(input)
|
|
|
|
assertStringEqual(yamlTagDirs & " !n!system:seq(" &
|
2023-07-31 17:16:24 +00:00
|
|
|
"tag:yaml.org;2002:str)\n- !!str one\n- !!str two\n", output)
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load custom object with explicit root tag":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input =
|
|
|
|
"--- !<tag:nimyaml.org,2016:custom:Person>\nfirstnamechar: P\nsurname: Pan\nage: 12"
|
2016-04-02 15:48:22 +00:00
|
|
|
var result: Person
|
|
|
|
load(input, result)
|
|
|
|
assert result.firstnamechar == 'P'
|
2018-10-11 12:20:09 +00:00
|
|
|
assert result.surname == "Pan"
|
|
|
|
assert result.age == 12
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-09-14 16:31:09 +00:00
|
|
|
test "Dump custom object with explicit root tag":
|
2016-04-02 15:48:22 +00:00
|
|
|
let input = Person(firstnamechar: 'P', surname: "Pan", age: 12)
|
2023-08-29 18:46:26 +00:00
|
|
|
var dumper = blockOnlyDumper()
|
|
|
|
dumper.serialization.tagStyle = tsRootOnly
|
|
|
|
dumper.serialization.handles = initNimYamlTagHandle()
|
|
|
|
var output = dumper.dump(input)
|
|
|
|
assertStringEqual(yamlTagDirs &
|
2023-07-31 17:16:24 +00:00
|
|
|
" !n!custom:Person\nfirstnamechar: P\nsurname: Pan\nage: 12\n", output)
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load object with inherited fields":
|
2023-04-04 17:29:20 +00:00
|
|
|
let input =
|
|
|
|
"i: 4\ns: hello"
|
|
|
|
var result: Child
|
|
|
|
load(input, result)
|
|
|
|
assert result.i == 4
|
|
|
|
assert result.s == "hello"
|
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load custom variant object":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input =
|
2016-06-08 17:15:50 +00:00
|
|
|
"---\n- - name: Bastet\n - kind: akCat\n - purringIntensity: 7\n" &
|
2017-02-13 16:10:56 +00:00
|
|
|
"- - name: Anubis\n - kind: akDog\n - barkometer: 13"
|
2016-06-08 17:15:50 +00:00
|
|
|
var result: seq[Animal]
|
|
|
|
load(input, result)
|
|
|
|
assert result.len == 2
|
|
|
|
assert result[0].name == "Bastet"
|
|
|
|
assert result[0].kind == akCat
|
|
|
|
assert result[0].purringIntensity == 7
|
|
|
|
assert result[1].name == "Anubis"
|
|
|
|
assert result[1].kind == akDog
|
|
|
|
assert result[1].barkometer == 13
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-09-14 16:31:09 +00:00
|
|
|
test "Dump custom variant object":
|
2016-06-08 17:15:50 +00:00
|
|
|
let input = @[Animal(name: "Bastet", kind: akCat, purringIntensity: 7),
|
|
|
|
Animal(name: "Anubis", kind: akDog, barkometer: 13)]
|
2023-08-29 18:46:26 +00:00
|
|
|
var output = blockOnlyDumper().dump(input)
|
|
|
|
assertStringEqual "" &
|
2023-07-31 17:16:24 +00:00
|
|
|
"- - name: Bastet\n" &
|
|
|
|
" - kind: akCat\n" &
|
|
|
|
" - purringIntensity: 7\n" &
|
|
|
|
"- - name: Anubis\n" &
|
|
|
|
" - kind: akDog\n" &
|
|
|
|
" - barkometer: 13\n", output
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-09-21 13:40:03 +00:00
|
|
|
test "Load custom variant object - missing field":
|
2016-09-23 13:42:24 +00:00
|
|
|
let input = "[{name: Bastet}, {kind: akCat}]"
|
2016-09-21 13:40:03 +00:00
|
|
|
var result: Animal
|
2020-11-10 14:40:01 +00:00
|
|
|
expectConstructionError(1, 1, "While constructing Animal: Missing field: \"purringIntensity\""):
|
2016-09-21 13:40:03 +00:00
|
|
|
load(input, result)
|
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load non-variant object with transient fields":
|
2016-10-19 20:04:46 +00:00
|
|
|
let input = "{b: b, d: d}"
|
|
|
|
var result: NonVariantWithTransient
|
|
|
|
load(input, result)
|
2018-10-03 17:51:47 +00:00
|
|
|
assert result.a.len == 0
|
2016-10-19 20:04:46 +00:00
|
|
|
assert result.b == "b"
|
2018-10-03 17:51:47 +00:00
|
|
|
assert result.c.len == 0
|
2016-10-19 20:04:46 +00:00
|
|
|
assert result.d == "d"
|
|
|
|
|
|
|
|
test "Load non-variant object with transient fields - unknown field":
|
|
|
|
let input = "{b: b, c: c, d: d}"
|
|
|
|
var result: NonVariantWithTransient
|
2020-11-10 14:40:01 +00:00
|
|
|
expectConstructionError(1, 8, "While constructing NonVariantWithTransient: Field \"c\" is transient and may not occur in input"):
|
2016-10-19 20:04:46 +00:00
|
|
|
load(input, result)
|
|
|
|
|
2016-10-15 15:58:29 +00:00
|
|
|
test "Dump non-variant object with transient fields":
|
|
|
|
let input = NonVariantWithTransient(a: "a", b: "b", c: "c", d: "d")
|
2023-08-29 18:46:26 +00:00
|
|
|
let output = blockOnlyDumper().dump(input)
|
|
|
|
assertStringEqual "b: b\nd: d\n", output
|
2016-10-15 15:58:29 +00:00
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load variant object with transient fields":
|
2020-06-26 19:29:41 +00:00
|
|
|
let input = "[[gStorable: gs, kind: deA, cStorable: cs], [gStorable: a, kind: deC]]"
|
2016-10-19 20:04:46 +00:00
|
|
|
var result: seq[VariantWithTransient]
|
|
|
|
load(input, result)
|
|
|
|
assert result.len == 2
|
2020-06-26 19:29:41 +00:00
|
|
|
assert result[0].kind == deA
|
2016-10-19 20:04:46 +00:00
|
|
|
assert result[0].gStorable == "gs"
|
|
|
|
assert result[0].cStorable == "cs"
|
2020-06-26 19:29:41 +00:00
|
|
|
assert result[1].kind == deC
|
2016-10-19 20:04:46 +00:00
|
|
|
assert result[1].gStorable == "a"
|
|
|
|
|
2020-06-26 19:29:41 +00:00
|
|
|
test "Load variant object with transient fields, error":
|
|
|
|
let input = "[gStorable: gc, kind: deC, neverThere: foo]"
|
2016-10-19 20:04:46 +00:00
|
|
|
var result: VariantWithTransient
|
2020-11-10 14:40:01 +00:00
|
|
|
expectConstructionError(1, 28, "While constructing VariantWithTransient: Field \"neverThere\" is transient and may not occur in input"):
|
2016-10-19 20:04:46 +00:00
|
|
|
load(input, result)
|
|
|
|
|
2016-10-15 15:58:29 +00:00
|
|
|
test "Dump variant object with transient fields":
|
2020-06-26 19:29:41 +00:00
|
|
|
let input = @[VariantWithTransient(kind: deA, gStorable: "gs",
|
2016-10-15 15:58:29 +00:00
|
|
|
gTemporary: "gt", cStorable: "cs", cTemporary: "ct"),
|
2020-06-26 19:29:41 +00:00
|
|
|
VariantWithTransient(kind: deC, gStorable: "a", gTemporary: "b",
|
2016-10-15 15:58:29 +00:00
|
|
|
neverThere: 42)]
|
2023-08-29 18:46:26 +00:00
|
|
|
let output = blockOnlyDumper().dump(input)
|
|
|
|
assertStringEqual "" &
|
2023-07-31 17:16:24 +00:00
|
|
|
"- - gStorable: gs\n" &
|
|
|
|
" - kind: deA\n" &
|
|
|
|
" - cStorable: cs\n" &
|
|
|
|
"- - gStorable: a\n" &
|
|
|
|
" - kind: deC\n", output
|
2016-10-15 15:58:29 +00:00
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load object with ignored key":
|
2016-10-27 15:58:14 +00:00
|
|
|
let input = "[{x: 1, y: 2}, {x: 3, z: 4, y: 5}, {z: [1, 2, 3], x: 4, y: 5}]"
|
|
|
|
var result: seq[WithIgnoredField]
|
|
|
|
load(input, result)
|
|
|
|
assert result.len == 3
|
|
|
|
assert result[0].x == 1
|
|
|
|
assert result[0].y == 2
|
|
|
|
assert result[1].x == 3
|
|
|
|
assert result[1].y == 5
|
|
|
|
assert result[2].x == 4
|
|
|
|
assert result[2].y == 5
|
|
|
|
|
|
|
|
test "Load object with ignored key - unknown field":
|
|
|
|
let input = "{x: 1, y: 2, zz: 3}"
|
|
|
|
var result: WithIgnoredField
|
2020-11-10 14:40:01 +00:00
|
|
|
expectConstructionError(1, 14, "While constructing WithIgnoredField: Unknown field: \"zz\""):
|
2016-10-27 15:58:14 +00:00
|
|
|
load(input, result)
|
|
|
|
|
2017-02-13 16:10:56 +00:00
|
|
|
when not defined(JS):
|
|
|
|
test "Dump cyclic data structure":
|
|
|
|
var
|
|
|
|
a = newNode("a")
|
|
|
|
b = newNode("b")
|
|
|
|
c = newNode("c")
|
|
|
|
a.next = b
|
|
|
|
b.next = c
|
|
|
|
c.next = a
|
2023-08-29 18:46:26 +00:00
|
|
|
var dumper = blockOnlyDumper()
|
|
|
|
dumper.serialization.tagStyle = tsRootOnly
|
|
|
|
var output = dumper.dump(a)
|
|
|
|
assertStringEqual yamlDir & " !example.net:Node &a\n" &
|
2020-11-10 14:40:01 +00:00
|
|
|
"value: a\n" &
|
2023-07-31 17:16:24 +00:00
|
|
|
"next:\n" &
|
2020-11-10 14:40:01 +00:00
|
|
|
" value: b\n" &
|
2023-07-31 17:16:24 +00:00
|
|
|
" next:\n" &
|
2020-11-10 14:40:01 +00:00
|
|
|
" value: c\n" &
|
2022-09-07 13:11:59 +00:00
|
|
|
" next: *a\n", output
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2017-02-13 16:10:56 +00:00
|
|
|
test "Load cyclic data structure":
|
2023-08-29 18:46:26 +00:00
|
|
|
let input = yamlTagDirs & """ !n!system:seq(example.net:Node)
|
2020-11-06 15:21:58 +00:00
|
|
|
- &a
|
2017-02-13 16:10:56 +00:00
|
|
|
value: a
|
2020-06-26 19:29:41 +00:00
|
|
|
next: &b
|
2017-02-13 16:10:56 +00:00
|
|
|
value: b
|
2020-06-26 19:29:41 +00:00
|
|
|
next: &c
|
2017-02-13 16:10:56 +00:00
|
|
|
value: c
|
|
|
|
next: *a
|
|
|
|
- *b
|
|
|
|
- *c
|
|
|
|
"""
|
|
|
|
var result: seq[ref Node]
|
|
|
|
try: load(input, result)
|
|
|
|
except YamlConstructionError:
|
|
|
|
let ex = (ref YamlConstructionError)(getCurrentException())
|
2020-11-06 15:21:58 +00:00
|
|
|
echo "line ", ex.mark.line, ", column ", ex.mark.column, ": ", ex.msg
|
2017-02-13 16:10:56 +00:00
|
|
|
echo ex.lineContent
|
|
|
|
raise ex
|
|
|
|
|
|
|
|
assert(result.len == 3)
|
|
|
|
assert(result[0].value == "a")
|
|
|
|
assert(result[1].value == "b")
|
|
|
|
assert(result[2].value == "c")
|
|
|
|
assert(result[0].next == result[1])
|
|
|
|
assert(result[1].next == result[2])
|
|
|
|
assert(result[2].next == result[0])
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load object with default values":
|
2016-10-26 16:32:54 +00:00
|
|
|
let input = "a: abc\nc: dce"
|
|
|
|
var result: WithDefault
|
|
|
|
load(input, result)
|
|
|
|
assert result.a == "abc"
|
|
|
|
assert result.b == "b"
|
|
|
|
assert result.c == "dce"
|
|
|
|
assert result.d == "d"
|
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Load object with partly default values":
|
2016-10-26 16:32:54 +00:00
|
|
|
let input = "a: abc\nb: bcd\nc: cde"
|
|
|
|
var result: WithDefault
|
|
|
|
load(input, result)
|
|
|
|
assert result.a == "abc"
|
|
|
|
assert result.b == "bcd"
|
|
|
|
assert result.c == "cde"
|
|
|
|
assert result.d == "d"
|
|
|
|
|
2023-08-30 19:14:31 +00:00
|
|
|
dualTest "Custom constructObject":
|
2017-02-13 16:10:56 +00:00
|
|
|
let input = "- 1\n- !test:BetterInt 2"
|
2016-04-02 15:48:22 +00:00
|
|
|
var result: seq[BetterInt]
|
|
|
|
load(input, result)
|
|
|
|
assert(result.len == 2)
|
2016-04-04 18:44:16 +00:00
|
|
|
assert(result[0] == 2.BetterInt)
|
|
|
|
assert(result[1] == 3.BetterInt)
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2016-09-14 16:31:09 +00:00
|
|
|
test "Custom representObject":
|
2016-04-02 15:48:22 +00:00
|
|
|
let input = @[1.BetterInt, 9998887.BetterInt, 98312.BetterInt]
|
2023-08-29 18:46:26 +00:00
|
|
|
var dumper = blockOnlyDumper()
|
|
|
|
dumper.serialization.tagStyle = tsAll
|
|
|
|
dumper.serialization.handles = initNimYamlTagHandle()
|
|
|
|
var output = dumper.dump(input)
|
|
|
|
assertStringEqual yamlTagDirs & " !n!system:seq(test:BetterInt)\n" &
|
2020-11-10 14:40:01 +00:00
|
|
|
"- !test:BetterInt 1\n" &
|
|
|
|
"- !test:BetterInt 9_998_887\n" &
|
2022-09-07 13:11:59 +00:00
|
|
|
"- !test:BetterInt 98_312\n", output
|