2015-12-23 11:35:07 +00:00
|
|
|
import "../src/yaml"
|
2015-12-26 17:40:23 +00:00
|
|
|
import streams, tables
|
2015-12-07 21:09:57 +00:00
|
|
|
|
|
|
|
import unittest
|
|
|
|
|
2015-12-26 12:39:43 +00:00
|
|
|
proc startDoc(): YamlStreamEvent =
|
2015-12-07 21:09:57 +00:00
|
|
|
result.kind = yamlStartDocument
|
|
|
|
|
2015-12-26 12:39:43 +00:00
|
|
|
proc endDoc(): YamlStreamEvent =
|
2015-12-07 21:09:57 +00:00
|
|
|
result.kind = yamlEndDocument
|
|
|
|
|
2015-12-23 17:12:51 +00:00
|
|
|
proc scalar(content: string, typeHint: YamlTypeHint,
|
|
|
|
tag: TagId = tagQuestionMark, anchor: AnchorId = anchorNone):
|
2015-12-26 12:39:43 +00:00
|
|
|
YamlStreamEvent =
|
2015-12-07 21:09:57 +00:00
|
|
|
result.kind = yamlScalar
|
|
|
|
result.scalarAnchor = anchor
|
|
|
|
result.scalarTag = tag
|
|
|
|
result.scalarContent = content
|
2015-12-23 17:12:51 +00:00
|
|
|
result.scalarType = typeHint
|
|
|
|
|
|
|
|
proc scalar(content: string,
|
|
|
|
tag: TagId = tagQuestionMark, anchor: AnchorId = anchorNone):
|
2015-12-26 12:39:43 +00:00
|
|
|
YamlStreamEvent =
|
2015-12-23 17:12:51 +00:00
|
|
|
result = scalar(content, yTypeUnknown, tag, anchor)
|
2015-12-07 21:09:57 +00:00
|
|
|
|
2015-12-22 15:28:35 +00:00
|
|
|
proc startSequence(tag: TagId = tagQuestionMark,
|
|
|
|
anchor: AnchorId = anchorNone):
|
2015-12-26 12:39:43 +00:00
|
|
|
YamlStreamEvent =
|
2015-12-07 21:09:57 +00:00
|
|
|
result.kind = yamlStartSequence
|
|
|
|
result.objAnchor = anchor
|
|
|
|
result.objTag = tag
|
|
|
|
|
2015-12-26 12:39:43 +00:00
|
|
|
proc endSequence(): YamlStreamEvent =
|
2015-12-07 21:09:57 +00:00
|
|
|
result.kind = yamlEndSequence
|
|
|
|
|
2015-12-22 15:28:35 +00:00
|
|
|
proc startMap(tag: TagId = tagQuestionMark, anchor: AnchorId = anchorNone):
|
2015-12-26 12:39:43 +00:00
|
|
|
YamlStreamEvent =
|
2015-12-07 21:09:57 +00:00
|
|
|
result.kind = yamlStartMap
|
|
|
|
result.objAnchor = anchor
|
|
|
|
result.objTag = tag
|
|
|
|
|
2015-12-26 12:39:43 +00:00
|
|
|
proc endMap(): YamlStreamEvent =
|
2015-12-07 21:09:57 +00:00
|
|
|
result.kind = yamlEndMap
|
|
|
|
|
2015-12-26 12:39:43 +00:00
|
|
|
proc alias(target: AnchorId): YamlStreamEvent =
|
2015-12-22 15:28:35 +00:00
|
|
|
result.kind = yamlAlias
|
|
|
|
result.aliasTarget = target
|
|
|
|
|
2015-12-26 12:39:43 +00:00
|
|
|
proc printDifference(expected, actual: YamlStreamEvent) =
|
2015-12-07 21:09:57 +00:00
|
|
|
if expected.kind != actual.kind:
|
|
|
|
echo "expected " & $expected.kind & ", got " & $actual.kind
|
|
|
|
if actual.kind == yamlError:
|
2015-12-11 21:55:21 +00:00
|
|
|
echo "Error message: (", actual.line, ", ", actual.column, ") ",
|
|
|
|
actual.description
|
2015-12-07 21:09:57 +00:00
|
|
|
elif actual.kind == yamlWarning:
|
|
|
|
echo "Warning message: " & actual.description
|
|
|
|
else:
|
|
|
|
case expected.kind
|
|
|
|
of yamlScalar:
|
|
|
|
if expected.scalarTag != actual.scalarTag:
|
2015-12-21 20:58:28 +00:00
|
|
|
echo "[\"", actual.scalarContent, "\".tag] expected tag ",
|
|
|
|
expected.scalarTag, ", got ", actual.scalarTag
|
2015-12-07 21:09:57 +00:00
|
|
|
elif expected.scalarAnchor != actual.scalarAnchor:
|
2015-12-22 15:28:35 +00:00
|
|
|
echo "[scalar] expected anchor ", expected.scalarAnchor,
|
|
|
|
", got ", actual.scalarAnchor
|
2015-12-07 21:09:57 +00:00
|
|
|
elif expected.scalarContent != actual.scalarContent:
|
2015-12-17 20:44:41 +00:00
|
|
|
let msg = "[scalar] expected content \"" &
|
|
|
|
expected.scalarContent & "\", got \"" &
|
|
|
|
actual.scalarContent & "\" "
|
2015-12-22 21:28:27 +00:00
|
|
|
if expected.scalarContent.len != actual.scalarContent.len:
|
|
|
|
echo msg, "(length does not match)"
|
|
|
|
else:
|
|
|
|
for i in 0..expected.scalarContent.high:
|
|
|
|
if expected.scalarContent[i] != actual.scalarContent[i]:
|
|
|
|
echo msg, "(first different char at pos ", i,
|
|
|
|
": expected ",
|
|
|
|
cast[int](expected.scalarContent[i]),
|
|
|
|
", got ",
|
|
|
|
cast[int](actual.scalarContent[i]), ")"
|
|
|
|
break
|
2015-12-23 17:12:51 +00:00
|
|
|
elif expected.scalarType != actual.scalarType:
|
|
|
|
echo "[scalar] expected type hint ", expected.scalarType,
|
|
|
|
", got ", actual.scalarType
|
2015-12-07 21:09:57 +00:00
|
|
|
else:
|
|
|
|
echo "[scalar] Unknown difference"
|
2015-12-21 20:40:27 +00:00
|
|
|
of yamlStartMap, yamlStartSequence:
|
|
|
|
if expected.objTag != actual.objTag:
|
2015-12-22 15:28:35 +00:00
|
|
|
echo "[object.tag] expected ", expected.objTag, ", got ",
|
2015-12-21 20:58:28 +00:00
|
|
|
actual.objTag
|
2015-12-22 15:28:35 +00:00
|
|
|
else:
|
|
|
|
echo "[object.tag] Unknown difference"
|
|
|
|
of yamlAlias:
|
|
|
|
if expected.aliasTarget != actual.aliasTarget:
|
|
|
|
echo "[alias] expected ", expected.aliasTarget, ", got ",
|
|
|
|
actual.aliasTarget
|
|
|
|
else:
|
|
|
|
echo "[alias] Unknown difference"
|
2015-12-07 21:09:57 +00:00
|
|
|
else:
|
|
|
|
echo "Unknown difference in event kind " & $expected.kind
|
|
|
|
|
2015-12-26 12:39:43 +00:00
|
|
|
template ensure(input: string, expected: varargs[YamlStreamEvent]) {.dirty.} =
|
2015-12-23 11:35:07 +00:00
|
|
|
var
|
2015-12-26 17:40:23 +00:00
|
|
|
parser = newParser(tagLib)
|
2015-12-23 11:35:07 +00:00
|
|
|
i = 0
|
|
|
|
events = parser.parse(newStringStream(input))
|
2015-12-07 21:09:57 +00:00
|
|
|
|
2015-12-23 11:35:07 +00:00
|
|
|
for token in events():
|
2015-12-07 21:09:57 +00:00
|
|
|
if i >= expected.len:
|
|
|
|
echo "received more tokens than expected (next token = ",
|
|
|
|
token.kind, ")"
|
|
|
|
fail()
|
|
|
|
break
|
|
|
|
if token != expected[i]:
|
|
|
|
echo "at token #" & $i & ":"
|
|
|
|
printDifference(expected[i], token)
|
|
|
|
fail()
|
|
|
|
break
|
|
|
|
i.inc()
|
|
|
|
|
|
|
|
suite "Parsing":
|
2015-12-21 22:10:42 +00:00
|
|
|
setup:
|
2015-12-26 17:40:23 +00:00
|
|
|
var tagLib = coreTagLibrary()
|
2015-12-21 22:10:42 +00:00
|
|
|
|
2015-12-07 21:09:57 +00:00
|
|
|
test "Parsing: Simple Scalar":
|
|
|
|
ensure("Scalar", startDoc(), scalar("Scalar"), endDoc())
|
|
|
|
test "Parsing: Simple Sequence":
|
2015-12-23 17:12:51 +00:00
|
|
|
ensure("- false", startDoc(), startSequence(),
|
|
|
|
scalar("false", yTypeBoolean), endSequence(), endDoc())
|
2015-12-07 21:09:57 +00:00
|
|
|
test "Parsing: Simple Map":
|
2015-12-23 17:12:51 +00:00
|
|
|
ensure("42: value\nkey2: -7.5", startDoc(), startMap(),
|
|
|
|
scalar("42", yTypeInteger), scalar("value"), scalar("key2"),
|
|
|
|
scalar("-7.5", yTypeFloat), endMap(), endDoc())
|
2015-12-10 22:02:06 +00:00
|
|
|
test "Parsing: Explicit Map":
|
2015-12-23 17:12:51 +00:00
|
|
|
ensure("? null\n: value\n? true\n: value2", startDoc(), startMap(),
|
|
|
|
scalar("null", yTypeNull), scalar("value"),
|
|
|
|
scalar("true", yTypeBoolean), scalar("value2"),
|
2015-12-10 22:02:06 +00:00
|
|
|
endMap(), endDoc())
|
2015-12-22 20:08:58 +00:00
|
|
|
test "Parsing: Mixed Map (explicit to implicit)":
|
2015-12-23 17:12:51 +00:00
|
|
|
ensure("? a\n: 13\n1.5: d", startDoc(), startMap(), scalar("a"),
|
|
|
|
scalar("13", yTypeInteger), scalar("1.5", yTypeFloat),
|
|
|
|
scalar("d"), endMap(), endDoc())
|
2015-12-22 20:08:58 +00:00
|
|
|
test "Parsing: Mixed Map (implicit to explicit)":
|
2015-12-23 17:12:51 +00:00
|
|
|
ensure("a: 4.2\n? 23\n: d", startDoc(), startMap(), scalar("a"),
|
|
|
|
scalar("4.2", yTypeFloat), scalar("23", yTypeInteger),
|
|
|
|
scalar("d"), endMap(), endDoc())
|
2015-12-22 21:28:27 +00:00
|
|
|
test "Parsing: Missing values in map":
|
|
|
|
ensure("? a\n? b\nc:", startDoc(), startMap(), scalar("a"), scalar(""),
|
|
|
|
scalar("b"), scalar(""), scalar("c"), scalar(""), endMap(),
|
|
|
|
endDoc())
|
|
|
|
test "Parsing: Missing keys in map":
|
|
|
|
ensure(": a\n: b", startDoc(), startMap(), scalar(""), scalar("a"),
|
|
|
|
scalar(""), scalar("b"), endMap(), endDoc())
|
|
|
|
test "Parsing: Multiline scalars in explicit map":
|
2015-12-23 17:12:51 +00:00
|
|
|
ensure("? a\n true\n: null\n d\n? e\n 42", startDoc(), startMap(),
|
|
|
|
scalar("a true"), scalar("null d"), scalar("e 42"), scalar(""),
|
2015-12-22 21:28:27 +00:00
|
|
|
endMap(), endDoc())
|
2015-12-10 19:53:43 +00:00
|
|
|
test "Parsing: Map in Sequence":
|
2015-12-24 14:21:49 +00:00
|
|
|
ensure(" - key: value\n key2: value2\n -\n key3: value3",
|
|
|
|
startDoc(), startSequence(), startMap(), scalar("key"),
|
|
|
|
scalar("value"), scalar("key2"), scalar("value2"), endMap(),
|
|
|
|
startMap(), scalar("key3"), scalar("value3"), endMap(),
|
|
|
|
endSequence(), endDoc())
|
2015-12-10 19:53:43 +00:00
|
|
|
test "Parsing: Sequence in Map":
|
|
|
|
ensure("key:\n - item1\n - item2", startDoc(), startMap(),
|
|
|
|
scalar("key"), startSequence(), scalar("item1"), scalar("item2"),
|
|
|
|
endSequence(), endMap(), endDoc())
|
|
|
|
test "Parsing: Sequence in Sequence":
|
|
|
|
ensure("- - l1_i1\n - l1_i2\n- l2_i1", startDoc(), startSequence(),
|
|
|
|
startSequence(), scalar("l1_i1"), scalar("l1_i2"), endSequence(),
|
2015-12-10 21:28:57 +00:00
|
|
|
scalar("l2_i1"), endSequence(), endDoc())
|
|
|
|
test "Parsing: Flow Sequence":
|
2015-12-23 17:12:51 +00:00
|
|
|
ensure("[2, b]", startDoc(), startSequence(), scalar("2", yTypeInteger),
|
|
|
|
scalar("b"), endSequence(), endDoc())
|
2015-12-10 21:28:57 +00:00
|
|
|
test "Parsing: Flow Map":
|
2015-12-23 17:12:51 +00:00
|
|
|
ensure("{a: true, 1.337: d}", startDoc(), startMap(), scalar("a"),
|
|
|
|
scalar("true", yTypeBoolean), scalar("1.337", yTypeFloat),
|
|
|
|
scalar("d"), endMap(), endDoc())
|
2015-12-10 21:28:57 +00:00
|
|
|
test "Parsing: Flow Sequence in Flow Sequence":
|
|
|
|
ensure("[a, [b, c]]", startDoc(), startSequence(), scalar("a"),
|
|
|
|
startSequence(), scalar("b"), scalar("c"), endSequence(),
|
|
|
|
endSequence(), endDoc())
|
|
|
|
test "Parsing: Flow Sequence in Flow Map":
|
2015-12-22 15:28:35 +00:00
|
|
|
ensure("{a: [b, c], [d, e]: f}", startDoc(), startMap(), scalar("a"),
|
2015-12-10 21:28:57 +00:00
|
|
|
startSequence(), scalar("b"), scalar("c"), endSequence(),
|
2015-12-22 15:28:35 +00:00
|
|
|
startSequence(), scalar("d"), scalar("e"), endSequence(),
|
|
|
|
scalar("f"), endMap(), endDoc())
|
2015-12-10 21:28:57 +00:00
|
|
|
test "Parsing: Flow Sequence in Map":
|
|
|
|
ensure("a: [b, c]", startDoc(), startMap(), scalar("a"),
|
|
|
|
startSequence(), scalar("b"), scalar("c"), endSequence(),
|
|
|
|
endMap(), endDoc())
|
|
|
|
test "Parsing: Flow Map in Sequence":
|
|
|
|
ensure("- {a: b}", startDoc(), startSequence(), startMap(), scalar("a"),
|
2015-12-14 20:26:34 +00:00
|
|
|
scalar("b"), endMap(), endSequence(), endDoc())
|
|
|
|
test "Parsing: Multiline scalar (top level)":
|
|
|
|
ensure("a\nb \n c\nd", startDoc(), scalar("a b c d"), endDoc())
|
|
|
|
test "Parsing: Multiline scalar (in map)":
|
|
|
|
ensure("a: b\n c\nd:\n e\n f", startDoc(), startMap(), scalar("a"),
|
2015-12-17 20:44:41 +00:00
|
|
|
scalar("b c"), scalar("d"), scalar("e f"), endMap(), endDoc())
|
|
|
|
test "Parsing: Block scalar (literal)":
|
|
|
|
ensure("a: |\x0A ab\x0A \x0A cd\x0A ef\x0A \x0A", startDoc(),
|
|
|
|
startMap(), scalar("a"), scalar("ab\x0A\x0Acd\x0Aef\x0A"),
|
|
|
|
endMap(), endDoc())
|
|
|
|
test "Parsing: Block scalar (folded)":
|
|
|
|
ensure("a: >\x0A ab\x0A cd\x0A \x0Aef\x0A\x0A\x0Agh\x0A", startDoc(),
|
|
|
|
startMap(), scalar("a"), scalar("ab cd\x0Aef\x0Agh\x0A"),
|
|
|
|
endMap(), endDoc())
|
|
|
|
test "Parsing: Block scalar (keep)":
|
|
|
|
ensure("a: |+\x0A ab\x0A \x0A \x0A", startDoc(), startMap(),
|
|
|
|
scalar("a"), scalar("ab\x0A\x0A \x0A"), endMap(), endDoc())
|
|
|
|
test "Parsing: Block scalar (strip)":
|
|
|
|
ensure("a: |-\x0A ab\x0A \x0A \x0A", startDoc(), startMap(),
|
2015-12-21 20:58:28 +00:00
|
|
|
scalar("a"), scalar("ab"), endMap(), endDoc())
|
|
|
|
test "Parsing: non-specific tags of quoted strings":
|
2015-12-23 17:12:51 +00:00
|
|
|
ensure("\"a\"", startDoc(),
|
|
|
|
scalar("a", yTypeString, tagExclamationMark), endDoc())
|
2015-12-21 22:10:42 +00:00
|
|
|
test "Parsing: explicit non-specific tag":
|
2015-12-22 15:28:35 +00:00
|
|
|
ensure("! a", startDoc(), scalar("a", tagExclamationMark), endDoc())
|
2015-12-21 22:10:42 +00:00
|
|
|
test "Parsing: secondary tag handle resolution":
|
2015-12-26 17:40:23 +00:00
|
|
|
ensure("!!str a", startDoc(), scalar("a", tagString), endDoc())
|
2015-12-21 22:10:42 +00:00
|
|
|
test "Parsing: resolving custom tag handles":
|
2015-12-26 17:40:23 +00:00
|
|
|
let fooId = tagLib.registerUri("tag:example.com,2015:foo")
|
2015-12-21 22:10:42 +00:00
|
|
|
ensure("%TAG !t! tag:example.com,2015:\n---\n!t!foo a", startDoc(),
|
2015-12-26 17:40:23 +00:00
|
|
|
scalar("a", fooId), endDoc())
|
2015-12-21 22:10:42 +00:00
|
|
|
test "Parsing: tags in sequence":
|
|
|
|
ensure(" - !!str a\n - b\n - !!int c\n - d", startDoc(),
|
2015-12-26 17:40:23 +00:00
|
|
|
startSequence(), scalar("a", tagString), scalar("b"),
|
|
|
|
scalar("c", tagInteger), scalar("d"), endSequence(), endDoc())
|
2015-12-21 22:10:42 +00:00
|
|
|
test "Parsing: tags in implicit map":
|
|
|
|
ensure("!!str a: b\nc: !!int d\ne: !!str f\ng: h", startDoc(), startMap(),
|
2015-12-26 17:40:23 +00:00
|
|
|
scalar("a", tagString), scalar("b"), scalar("c"),
|
|
|
|
scalar("d", tagInteger), scalar("e"), scalar("f", tagString),
|
|
|
|
scalar("g"), scalar("h"), endMap(), endDoc())
|
2015-12-21 22:10:42 +00:00
|
|
|
test "Parsing: tags in explicit map":
|
|
|
|
ensure("? !!str a\n: !!int b\n? c\n: !!str d", startDoc(), startMap(),
|
2015-12-26 17:40:23 +00:00
|
|
|
scalar("a", tagString), scalar("b", tagInteger), scalar("c"),
|
|
|
|
scalar("d", tagString), endMap(), endDoc())
|
2015-12-21 22:10:42 +00:00
|
|
|
test "Parsing: tags for flow objects":
|
2015-12-26 17:40:23 +00:00
|
|
|
ensure("!!map { k: !!seq [ a, !!str b] }", startDoc(), startMap(tagMap),
|
|
|
|
scalar("k"), startSequence(tagSequence), scalar("a"),
|
|
|
|
scalar("b", tagString), endSequence(), endMap(), endDoc())
|
2015-12-22 17:51:16 +00:00
|
|
|
test "Parsing: Tag after directives end":
|
2015-12-26 17:40:23 +00:00
|
|
|
ensure("--- !!str\nfoo", startDoc(), scalar("foo", tagString), endDoc())
|
2015-12-22 15:28:35 +00:00
|
|
|
test "Parsing: Simple Anchor":
|
|
|
|
ensure("&a str", startDoc(), scalar("str", tagQuestionMark,
|
|
|
|
0.AnchorId), endDoc())
|
|
|
|
test "Parsing: Anchors in sequence":
|
|
|
|
ensure(" - &a a\n - b\n - &c c\n - &a d", startDoc(), startSequence(),
|
|
|
|
scalar("a", tagQuestionMark, 0.AnchorId), scalar("b"),
|
|
|
|
scalar("c", tagQuestionMark, 1.AnchorId),
|
|
|
|
scalar("d", tagQuestionMark, 0.AnchorId), endSequence(),
|
|
|
|
endDoc())
|
|
|
|
test "Parsing: Anchors in map":
|
|
|
|
ensure("&a a: b\nc: &d d", startDoc(), startMap(),
|
|
|
|
scalar("a", tagQuestionMark, 0.AnchorId),
|
|
|
|
scalar("b"), scalar("c"),
|
|
|
|
scalar("d", tagQuestionMark, 1.AnchorId),
|
|
|
|
endMap(), endDoc())
|
|
|
|
test "Parsing: Anchors and tags":
|
|
|
|
ensure(" - &a !!str a\n - !!int b\n - &c !!int c\n - &d d", startDoc(),
|
2015-12-26 17:40:23 +00:00
|
|
|
startSequence(), scalar("a", tagString, 0.AnchorId),
|
|
|
|
scalar("b", tagInteger), scalar("c", tagInteger, 1.AnchorId),
|
2015-12-22 15:28:35 +00:00
|
|
|
scalar("d", tagQuestionMark, 2.AnchorId), endSequence(),
|
|
|
|
endDoc())
|
|
|
|
test "Parsing: Aliases in sequence":
|
|
|
|
ensure(" - &a a\n - &b b\n - *a\n - *b", startDoc(), startSequence(),
|
|
|
|
scalar("a", tagQuestionMark, 0.AnchorId),
|
|
|
|
scalar("b", tagQuestionMark, 1.AnchorId), alias(0.AnchorId),
|
|
|
|
alias(1.AnchorId), endSequence(), endDoc())
|
|
|
|
test "Parsing: Aliases in map":
|
|
|
|
ensure("&a a: &b b\n*a: *b", startDoc(), startMap(),
|
|
|
|
scalar("a", tagQuestionMark, 0.AnchorId),
|
|
|
|
scalar("b", tagQuestionMark, 1.AnchorId), alias(0.AnchorId),
|
|
|
|
alias(1.AnchorId), endMap(), endDoc())
|
|
|
|
test "Parsing: Aliases in flow":
|
|
|
|
ensure("{ &a [a, &b b]: *b, *a: [c, *b, d]}", startDoc(), startMap(),
|
|
|
|
startSequence(tagQuestionMark, 0.AnchorId), scalar("a"),
|
|
|
|
scalar("b", tagQuestionMark, 1.AnchorId), endSequence(),
|
|
|
|
alias(1.AnchorId), alias(0.AnchorId), startSequence(),
|
|
|
|
scalar("c"), alias(1.AnchorId), scalar("d"), endSequence(),
|
2015-12-22 22:35:03 +00:00
|
|
|
endMap(), endDoc())
|
2015-12-23 17:12:51 +00:00
|
|
|
test "Parsing: Tags on empty scalars":
|
2015-12-22 22:35:03 +00:00
|
|
|
ensure("!!str : a\nb: !!int\n!!str : !!str", startDoc(), startMap(),
|
2015-12-26 17:40:23 +00:00
|
|
|
scalar("", tagString), scalar("a"), scalar("b"),
|
|
|
|
scalar("", tagInteger), scalar("", tagString),
|
|
|
|
scalar("", tagString), endMap(), endDoc())
|
2015-12-23 17:12:51 +00:00
|
|
|
test "Parsing: Anchors on empty scalars":
|
2015-12-22 22:35:03 +00:00
|
|
|
ensure("&a : a\nb: &b\n&c : &a", startDoc(), startMap(),
|
|
|
|
scalar("", tagQuestionMark, 0.AnchorId), scalar("a"),
|
|
|
|
scalar("b"), scalar("", tagQuestionMark, 1.AnchorId),
|
|
|
|
scalar("", tagQuestionMark, 2.AnchorId),
|
|
|
|
scalar("", tagQuestionMark, 0.AnchorId), endMap(), endDoc())
|