PureYAML/Tests/ExplicitKeyTests.swift
Mihaela M ae29059530 fix(parsing): parse a property-only explicit mapping key as an empty key
An explicit key that is only a node property (`? &e` then `: &a`) parsed to an
`expectedNode` error. Unlike the implicit form (`&a : v`), the scanner emits no
synthesized empty scalar for an explicit key, so the block parser read the key
via parseNode, consumed the property, then hit the `:` value indicator with no
node and threw.

parseNode now treats a `:` in node position as an empty key carrying any
properties, reusing emitEmptyNodeOrThrow (the node it already produced for a
property at end of input) without consuming the `:`, so the mapping machinery
reads the `:` as the value indicator. To stay within the cyclomatic-complexity
limit, the scalar case is extracted to parseScalarNode.

yaml-test-suite PW8X now passes (parse-level 314/333 to 315/333). should-error
rejections and value-level matches are unchanged, and a value-level test pins
the produced tree for the anchored and tagged property-only explicit keys.
2026-06-29 08:56:58 +02:00

48 lines
1.6 KiB
Swift

@testable import PureYAML
import Testing
@Suite("Explicit keys")
struct ExplicitKeyTests {
@Test("Explicit keys with no value each map to null")
func test_explicitKeysWithoutValuesMapToNull() throws {
// Several `? key` entries in a row (a set, for instance) are valid; each maps to null.
let value = try PureYAML.parse("""
? a
? b
c:
""")
#expect(value == .mapping(.init([
.init(key: "a", value: .null),
.init(key: "b", value: .null),
.init(key: "c", value: .null),
])))
}
@Test("Explicit keys with values still parse")
func test_explicitKeysWithValues() throws {
let value = try PureYAML.parse("""
? a
: b
? c
: d
""")
#expect(value == .mapping(.init([
.init(key: "a", value: .string("b")),
.init(key: "c", value: .string("d")),
])))
}
@Test("An explicit key that is only a property is an empty key carrying it")
func test_explicitPropertyOnlyKey() throws {
// `? &e` is an anchored empty key, `: &a` an anchored empty value: an empty plain scalar
// resolves to the empty string as a key and to null as a value, the property binding to each
// during construction. The key is no longer rejected for having no scalar before its `:`.
#expect(try PureYAML.parse("? &e\n: &a\n") == .mapping(.init([
.init(keyNode: .string(""), value: .null),
])))
#expect(try PureYAML.parse("? !!str\n: !!null\n") == .mapping(.init([
.init(keyNode: .string(""), value: .null),
])))
}
}