PureYAML/Tests/FlowMappingEmptyKeyTests.swift
Mihaela M 31da488055 fix(parsing): allow a flow mapping entry with no value
A flow mapping entry may omit its `:` value indicator, in which case its key
maps to null: `{ a }` and `{ a, b }` are flow sets. parseFlowMappingPair
required a `:` after every key, so it rejected these entries, and rejected a
valueless key that spanned lines (`{ multi\n  line, a: b}`) with them.

Parse a value only when a `:` follows the key; otherwise emit a null value for
the key. A unit test that asserted `{ a, }` was an error is corrected to expect
the set `{a: null}`, the behaviour the yaml-test-suite cases 8KB6 and 9BXH
require.

Raises yaml-test-suite parse-level conformance to 304/333 (91.3%) and
value-level to 195/197, with the should-error rejection rate unchanged.
480 tests pass.
2026-06-29 01:42:02 +02:00

54 lines
2.2 KiB
Swift

@testable import PureYAML
import Testing
/// A flow mapping entry may begin with its `:` indicator, giving an empty (null) key, e.g. `{ : v }`,
/// or carry only properties before the `:`, e.g. `{ !!str : v }`. Both resolve to a null key, which
/// the parser now emits rather than demanding a node before the `:`. The allowance is local to flow
/// mapping key position, so an entry with no `:` at all (`{ a, }`) is still an error.
@Suite("Flow mapping empty key")
struct FlowMappingEmptyKeyTests {
@Test("A flow mapping entry that begins with a colon has an empty key")
func test_emptyKey() throws {
#expect(try PureYAML.parse("{ : a }\n") == .mapping(.init([
.init(keyNode: .string(""), value: .string("a")),
])))
}
@Test("An empty key sits alongside ordinary entries")
func test_emptyKeyAmongEntries() throws {
#expect(try PureYAML.parse("{ a: b, : c }\n") == .mapping(.init([
.init(key: "a", value: .string("b")),
.init(keyNode: .string(""), value: .string("c")),
])))
}
@Test("Both key and value may be empty in one entry")
func test_emptyKeyAndValue() throws {
#expect(try PureYAML.parse("{ : }\n") == .mapping(.init([
.init(keyNode: .string(""), value: .null),
])))
}
@Test("A key carrying only a tag is a null key and parses")
func test_propertyOnlyKey() throws {
// `{ foo : !!str, !!str : bar }`: the first value and the second key are property-only nulls.
_ = try PureYAML.parse("{ foo : !!str, !!str : bar }\n")
}
@Test("An empty value is still accepted, unchanged")
func test_emptyValueUnchanged() throws {
#expect(try PureYAML.parse("{ a: }\n") == .mapping(.init([
.init(key: "a", value: .null),
])))
}
@Test("A flow mapping entry with no colon is a set-style key mapping to null")
func test_entryWithoutColonIsNullValue() throws {
// `{ a, }` is a flow set: the entry has no `:`, so its key maps to null. The trailing comma
// is allowed.
#expect(try PureYAML.parse("{ a, }\n") == .mapping(.init([
.init(key: "a", value: .null),
])))
}
}