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.
52 lines
2.7 KiB
Swift
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)
|
|
}
|
|
}
|
|
}
|