PureYAML/Tests/FlowMultilineValueTests.swift
Mihaela M d1d5b1a37c fix(parsing): parse a flow mapping value on the next line
In a flow mapping the value is a flow node and may sit on any line; flow is line
insensitive. parseMappingPair gated value parsing on hasNodeOnSameLine, a
block-only rule, so a value after `:` on the next line was treated as null and
left unconsumed, failing the whole flow mapping. Thread an inFlow flag and, in
flow, parse the value as a flow node line-insensitively (only a flow terminator
leaves it null), bypassing the block-only same-line and indentation branches.

Pretty-printed JSON (a YAML 1.2 superset) relies on this. Against the JSON Schema
Test Suite corpus this fixes all 27 files that previously failed to parse
(432/432 now); the YAML test-suite (318/333, value-level 206/206) and the full
suite stay green.
2026-06-29 21:40:12 +02:00

50 lines
2.1 KiB
Swift

@testable import PureYAML
import Testing
/// In a flow mapping the value is a flow node and may sit on any line: flow is line insensitive,
/// unlike a block mapping whose value must be on the key's line or an indented block below it.
/// A value after `:` on the next line is the value, not a null. Pretty-printed JSON (a YAML 1.2
/// superset) relies on this throughout, which is why it must hold. Only a flow terminator leaves
/// the value empty.
@Suite("Flow multi-line value")
struct FlowMultilineValueTests {
@Test("A flow mapping value on the line after the colon is the value")
func test_valueOnNextLine() throws {
#expect(try PureYAML.parse("{\"a\":\n\"b\"}") == .mapping(.init([
.init(key: "a", value: .string("b")),
])))
}
@Test("Several flow values, each on its own line, each bind to their key")
func test_severalNextLineValues() throws {
let yaml = "{\n\"a\":\n \"x\",\n\"b\":\n \"y\"\n}"
#expect(try PureYAML.parse(yaml) == .mapping(.init([
.init(key: "a", value: .string("x")),
.init(key: "b", value: .string("y")),
])))
}
@Test("A flow value that is itself a flow node spanning lines is parsed")
func test_nextLineValueIsFlowNode() throws {
#expect(try PureYAML.parse("{\"a\":\n[1, 2]}") == .mapping(.init([
.init(key: "a", value: .sequence([.int(1), .int(2)])),
])))
}
@Test("Near miss: a flow value omitted before a terminator is null, not the next entry")
func test_emptyFlowValueStaysNull() throws {
#expect(try PureYAML.parse("{\"a\": , \"b\": \"c\"}") == .mapping(.init([
.init(key: "a", value: .null),
.init(key: "b", value: .string("c")),
])))
}
@Test("Pretty-printed JSON (an array of objects with values on their own lines) parses")
func test_prettyPrintedJSON() throws {
let yaml = "[\n {\n \"k\":\n \"v\"\n }\n]"
#expect(try PureYAML.parse(yaml) == .sequence([
.mapping(.init([.init(key: "k", value: .string("v"))])),
]))
}
}