PureYAML/Tests/ValidationCoverageMetaTests.swift
Mihaela M f901a3f04c test(validation): make finding coverage a tested law
Add the meta-test the validation idiom mandates: every rule in the default
validator ships a failing fixture and a near-miss (just-valid) fixture, kept
in a registry keyed by rule description. One meta-test asserts the registry
covers exactly the default rule set, naming any default rule without
fixtures or any orphaned fixture; another exercises each rule in isolation,
failing its failing fixture and passing its near miss so nothing proves a
rule quiet on valid input by accident.

A planted orphan fixture was confirmed to fail the set-equality meta-test
before being removed. Adding a default rule without its fixtures now fails a
test before the change is deliberate.
2026-06-28 10:17:48 +02:00

52 lines
2.7 KiB
Swift

@testable import PureYAML
import Testing
/// "Coverage is itself a tested law" (validation-rules.md): every rule in the default validator must
/// ship a failing fixture and a near-miss succeeding fixture, and a meta-test asserts the registry
/// covers exactly the default rule set, naming any gap. Adding a default rule without its fixtures,
/// or leaving a fixture for a rule that no longer ships, fails a test before it is deliberate.
@Suite("Validation finding-coverage law")
struct ValidationCoverageMetaTests {
/// One failing document and one near-miss (just-valid) document per default rule, keyed by the
/// rule's description (the same identity the validator removes and lists by).
private static let fixtures: [String: (failing: PureYAML.Model.Value, nearMiss: PureYAML.Model.Value)] = [
"Mapping keys are unique": (
failing: .mapping(.init([
.init(key: "a", value: .int(1)),
.init(key: "a", value: .int(2)),
])),
// The boundary the rule almost trips: two keys one character apart.
nearMiss: .mapping(.init([
.init(key: "a", value: .int(1)),
.init(key: "b", value: .int(2)),
]))
),
]
@Test("Every default rule has a failing and a near-miss fixture, and no fixture is orphaned")
func test_fixturesCoverExactlyTheDefaultRuleSet() {
let ruled = Set(PureYAML.Validation.Validator().validationDescriptions)
let covered = Set(Self.fixtures.keys)
let missing = ruled.subtracting(covered)
let orphaned = covered.subtracting(ruled)
#expect(missing.isEmpty, "default rules without coverage fixtures: \(missing.sorted())")
#expect(orphaned.isEmpty, "coverage fixtures for rules that no longer ship: \(orphaned.sorted())")
}
@Test("Each default rule fails its failing fixture and passes its near-miss in isolation")
func test_eachRuleFailsAndNearMisses() throws {
for (description, fixture) in Self.fixtures {
guard let rule = PureYAML.Validation.Validator().rules.first(where: { $0.description == description }) else {
Issue.record("no default rule named '\(description)'")
continue
}
let isolated = PureYAML.Validation.Validator.blank.validating(rule)
#expect(throws: PureYAML.Validation.Issue.Collection.self, "rule '\(description)' did not fail its failing fixture") {
try isolated.validate(fixture.failing)
}
// The near miss must pass: nothing proves the rule stays quiet on valid input otherwise.
_ = try isolated.validate(fixture.nearMiss)
}
}
}