PureYAML/Tests/LibYAMLPortConformanceTests.swift
Mihaela Mihaljevic 6eddb64dcd fix(parsing): reject a tab where a token must start, add port differential
The scanner now errors with "found character that cannot start any token"
when a tab leads a token in block context, matching libyaml's final guard
in fetch_next_token (a plain scalar may not begin with a blank). Adds a
differential harness (env-gated) that dumps the ported pipeline's yeast
events for the whole suite.

Verified against the libyaml reference dumper across all 308 vendored
valid cases: the port is byte-for-byte identical to libyaml on 307, and
the single difference (L24T/01) is the port matching the canonical
test.event where libyaml drops a trailing line break. 333 tests.
2026-06-24 17:12:36 +02:00

67 lines
2.6 KiB
Swift

import Foundation
@testable import PureYAML
import Testing
/// Differential measurement of the ported libyaml scanner+parser against the full
/// vendored YAML test suite, using the same yeast serializer as the canonical
/// gate. Gated by an environment flag so it only runs when measuring; it prints a
/// score and the failing ids split into throws vs wrong-stream.
@Suite("LibYAML Port Conformance")
struct LibYAMLPortConformanceTests {
@Test("measure the ported pipeline against the suite")
func test_measure() throws {
guard ProcessInfo.processInfo.environment["PUREYAML_PORT_MEASURE"] == "1" else { return }
var pass = 0
var throwing: [String] = []
var wrong: [String] = []
let cases = CanonicalEventCorpus.validCases()
for testCase in cases {
guard let yaml = testCase.input, let expected = testCase.expectedEvents else { continue }
do {
var parser = try PureYAML.Parsing.LibYAML.Parser(yaml)
let actual = try parser.parse().map(CanonicalEventCorpus.serialize).joined(separator: "\n")
if actual == expected.trimmedTrailing {
pass += 1
} else {
wrong.append(testCase.id)
}
} catch {
throwing.append(testCase.id)
}
}
print("PORT-SCORE pass=\(pass) wrong=\(wrong.count) throws=\(throwing.count) total=\(cases.count)")
print("PORT-WRONG \(wrong.sorted().joined(separator: " "))")
print("PORT-THROWS \(throwing.sorted().joined(separator: " "))")
}
@Test("dump port yeast for ids in PUREYAML_PORT_DUMP_IDS")
func test_dump() throws {
guard let ids = ProcessInfo.processInfo.environment["PUREYAML_PORT_DUMP_IDS"] else { return }
let cases = ids == "ALL"
? CanonicalEventCorpus.validCases().map(\.id)
: ids.split(separator: ",").map(String.init)
for id in cases {
let testCase = CanonicalEventCorpus.Case(id: id)
guard let yaml = testCase.input else { continue }
print("@@@ID@@@ \(id)")
do {
var parser = try PureYAML.Parsing.LibYAML.Parser(yaml)
try print(parser.parse().map(CanonicalEventCorpus.serialize).joined(separator: "\n"))
} catch {
print("@@@ERROR@@@ \(error)")
}
print("@@@END@@@")
}
}
}
private extension String {
var trimmedTrailing: String {
var copy = self
while copy.hasSuffix("\n") {
copy.removeLast()
}
return copy
}
}