PureYAML/Tests/ParsingErrorPathTests.swift
Mihaela M 3291a3701f fix(parsing): treat a dangling anchor or tag as an empty node
A node property always attaches to a node, and an empty node is allowed, so
an anchor or tag with nothing after it (a bare '&anchor', a 'key: &a', or a
'!!str'/'!!null' with no value) denotes that property applied to a null
node. parseNode rejected it as a missing node.

parseNode now emits a null scalar carrying the properties when a node
position holds only an anchor or tag, via a small helper to stay within the
complexity limit; with no properties, a missing node is still an error. A
'!!str' empty node resolves to the empty string and '!!null' to null. The
error-path test that asserted a dangling property throws is corrected, as
the construct is valid per the grammar and the official test-suite.

Measured against the official YAML test-suite, parse-level conformance
rises from 287/333 (86.2%) to 288/333 (86.5%), with value-level up one and
no regression.
2026-06-28 03:21:04 +02:00

43 lines
1.8 KiB
Swift

@testable import PureYAML
import Testing
@Suite("Parsing Error Paths")
struct ParsingErrorPathTests {
@Test("A node property with no following node is an empty (null) node")
func test_danglingNodePropertyIsEmptyNode() throws {
// A property always attaches to a node, and an empty node is allowed, so a dangling anchor
// or tag denotes a null node carrying that property rather than being an error.
#expect(try PureYAML.parse("&anchor\n") == .null)
#expect(try PureYAML.parse("root:\n key: &a\nother: 1\n") == .mapping(.init([
.init(key: "root", value: .mapping(.init([.init(key: "key", value: .null)]))),
.init(key: "other", value: .int(1)),
])))
}
@Test("An unterminated flow mapping throws at stream end")
func test_unterminatedFlowMappingThrows() {
expectParseError("x: {a: b", .unexpectedToken(
expected: "flow entry or flow mapping end",
actual: "streamEnd",
line: 1,
column: 9,
))
}
@Test("Block scalar content less indented than the explicit indicator throws")
func test_explicitBlockScalarIndentationUnderIndentThrows() {
expectParseError("k: |2\n a\n", .unexpectedIndentation(line: 2))
}
@Test("Diagnostic validation reports an invalid merge value via the buffered composer")
func test_diagnosticValidationRejectsInvalidMergeValue() {
let report = PureYAML.diagnosticValidationReport("a: &x 1\nb:\n <<: *x\n", file: "merge.yaml")
#expect(!report.isValid)
#expect(report.diagnostics.count == 1)
let diagnostic = report.diagnostics.first
#expect(diagnostic?.kind == .parse)
#expect(diagnostic?.code == "invalidMergeValue")
#expect(diagnostic?.line == 3)
}
}