PureYAML/Tests/FlowExplicitKeyTests.swift
Mihaela M 95c5ff3966 fix(parsing): parse an explicit key inside a flow collection
A flow `?` did not mark an explicit key, so the scalar after it synthesized
its own implicit key: `{? foo : bar}` parsed as `{{foo: bar}: null}` instead of
`{foo: bar}`, and `[? foo : bar]` the same way.

Track the explicit-key state per flow level on the flow context: set it at a
flow `?`, clear it at that level's `:` or a `,`, and discard it with the
context when the collection closes. The key scalar then is not turned into an
implicit key, the pair's `:` is its value indicator, and a nested collection's
`:` does not affect an outer key (`{? {a: b} : c}`). The continuation fold for
a multi-line explicit key now also consults the flow context, restoring
`[? foo\n bar : baz]` to the single key `foo bar`.

The block explicit-key flag is left untouched, since it is not cleared between
valueless `? a` / `? b` entries and folding it into this check regressed
block sets; only the flow path is changed here.

Raises yaml-test-suite value-level conformance to 192/194 (99.0%) with the
parse-level and should-error rejection rates unchanged. 472 tests pass.
2026-06-29 01:17:26 +02:00

59 lines
2.4 KiB
Swift

@testable import PureYAML
import Testing
/// An explicit key (`?`) inside a flow collection makes the following scalar the key itself, not a new
/// implicit key, and lets that key span lines. The explicit-key state is tracked per flow level, so a
/// nested collection's `:` does not affect an outer key, a `,` ends it, and the closing bracket
/// discards it. Ordinary flow mappings, where each `a: b` is an implicit pair, are unaffected.
@Suite("Flow explicit key")
struct FlowExplicitKeyTests {
@Test("A flow mapping explicit key takes its value")
func test_flowMappingExplicitKey() throws {
#expect(try PureYAML.parse("{? foo : bar}\n") == .mapping(.init([
.init(key: "foo", value: .string("bar")),
])))
}
@Test("A flow sequence explicit-key entry is a single-pair mapping")
func test_flowSequenceExplicitKey() throws {
#expect(try PureYAML.parse("[? foo : bar]\n") == .sequence([
.mapping(.init([.init(key: "foo", value: .string("bar"))])),
]))
}
@Test("An explicit key spans lines, folding to a single key")
func test_multilineExplicitKey() throws {
#expect(try PureYAML.parse("[? foo\n bar : baz]\n") == .sequence([
.mapping(.init([.init(key: "foo bar", value: .string("baz"))])),
]))
}
@Test("Explicit and implicit pairs mix in one flow mapping")
func test_mixedPairs() throws {
#expect(try PureYAML.parse("{a: 1, ? b : 2}\n") == .mapping(.init([
.init(key: "a", value: .int(1)),
.init(key: "b", value: .int(2)),
])))
#expect(try PureYAML.parse("{? a, ? b, c: 1}\n") == .mapping(.init([
.init(key: "a", value: .null),
.init(key: "b", value: .null),
.init(key: "c", value: .int(1)),
])))
}
@Test("A nested collection key is unaffected by the outer explicit key")
func test_nestedCollectionKey() throws {
#expect(try PureYAML.parse("{? {a: b} : c}\n") == .mapping(.init([
.init(keyNode: .mapping(.init([.init(key: "a", value: .string("b"))])), value: .string("c")),
])))
}
@Test("An ordinary flow mapping is unchanged")
func test_ordinaryFlowMapping() throws {
#expect(try PureYAML.parse("{a: 1, b: 2}\n") == .mapping(.init([
.init(key: "a", value: .int(1)),
.init(key: "b", value: .int(2)),
])))
}
}