PureYAML/Tests/LibYAMLSimpleKeyTests.swift
Mihaela Mihaljevic 9ce57e86e5 feat(parsing): port libyaml simple-key mechanism to Swift
Stage 2 of the faithful libyaml scanner port. Translates yaml_parser_save_simple_key, yaml_parser_remove_simple_key, yaml_parser_stale_simple_keys, and the flow-level push/pop (yaml_parser_increase_flow_level / decrease) onto a new PureYAML.Parsing.LibYAML.Scanner aggregate that embeds the indent engine. The simple-key mechanism is what lets a quoted scalar, a nested collection, or a property-carrying node become a mapping key when a ':' follows, and is required exactly at the block indent. Modelled faithfully: a potential key goes stale once it spans a line break or exceeds 1024 characters, and a required key that is removed or goes stale is the 'could not find expected colon' error. Unit-tested for the required/not-required, removal-error, staleness, and flow-level cases. No public behavior changed yet.
2026-06-24 02:55:07 +02:00

67 lines
2.9 KiB
Swift

@testable import PureYAML
import Testing
/// Verifies the ported simple-key mechanism (`save_simple_key`,
/// `remove_simple_key`, `stale_simple_keys`, flow-level push/pop) reproduces
/// libyaml's behavior.
@Suite("LibYAML Simple Key")
struct LibYAMLSimpleKeyTests {
private func mark(line: Int, column: Int, index: Int) -> PureYAML.Parsing.Mark {
PureYAML.Parsing.Mark(line: line, column: column, index: index)
}
@Test("saves a possible key, required when it sits at the block indent")
func test_saveSimpleKeyRequiredAtIndent() throws {
var scanner = PureYAML.Parsing.LibYAML.Scanner()
scanner.indentEngine.rollIndent(column: 0, number: -1, type: .blockMappingStart, mark: .start)
scanner.mark = mark(line: 1, column: 0, index: 0)
try scanner.saveSimpleKey()
#expect(scanner.simpleKeys.last?.possible == true)
#expect(scanner.simpleKeys.last?.required == true)
}
@Test("a key not at the block indent is possible but not required")
func test_saveSimpleKeyNotRequired() throws {
var scanner = PureYAML.Parsing.LibYAML.Scanner()
scanner.indentEngine.rollIndent(column: 0, number: -1, type: .blockMappingStart, mark: .start)
scanner.mark = mark(line: 1, column: 4, index: 4)
try scanner.saveSimpleKey()
#expect(scanner.simpleKeys.last?.possible == true)
#expect(scanner.simpleKeys.last?.required == false)
}
@Test("removing a required possible key is an error")
func test_removeRequiredKeyThrows() throws {
var scanner = PureYAML.Parsing.LibYAML.Scanner()
scanner.indentEngine.rollIndent(column: 0, number: -1, type: .blockMappingStart, mark: .start)
scanner.mark = mark(line: 1, column: 0, index: 0)
try scanner.saveSimpleKey()
#expect(throws: PureYAML.Parsing.LibYAML.ScannerError.self) {
try scanner.removeSimpleKey()
}
}
@Test("a non-required key on an earlier line goes stale without error")
func test_staleNonRequiredKey() throws {
var scanner = PureYAML.Parsing.LibYAML.Scanner()
scanner.indentEngine.rollIndent(column: 0, number: -1, type: .blockMappingStart, mark: .start)
scanner.mark = mark(line: 1, column: 4, index: 4)
try scanner.saveSimpleKey()
scanner.mark = mark(line: 2, column: 0, index: 10)
try scanner.staleSimpleKeys()
#expect(scanner.simpleKeys.last?.possible == false)
}
@Test("flow level pushes and pops a simple-key slot")
func test_flowLevelStack() {
var scanner = PureYAML.Parsing.LibYAML.Scanner()
#expect(scanner.simpleKeys.count == 1)
scanner.increaseFlowLevel()
#expect(scanner.flowLevel == 1)
#expect(scanner.simpleKeys.count == 2)
scanner.decreaseFlowLevel()
#expect(scanner.flowLevel == 0)
#expect(scanner.simpleKeys.count == 1)
}
}