import Testing
@testable import PureXML
/// Schematron conformance, driven through the validation framework (kept in its
/// own suite so the main corpus stays under the type-body cap).
@Suite("Conformance corpus: Schematron")
struct ConformanceSchematronTests {
private struct SchematronSpec {
let name: String
let rule: String
let xml: String
let valid: Bool
}
/// An `assert` fires when its test is false, a `report` when its test is true,
/// and a rule whose context matches nothing is inert.
private func schematronCorpus() throws -> [PureXML.Validation.ConformanceCase] {
let assertRule = "missing b"
let ageRule = "too high"
let reportRule = "flagged"
let specs = [
SchematronSpec(name: "assert-satisfied", rule: assertRule, xml: "", valid: true),
SchematronSpec(name: "assert-violated", rule: assertRule, xml: "", valid: false),
SchematronSpec(name: "context-no-match-inert", rule: "never", xml: "", valid: true),
SchematronSpec(name: "number-comparison-ok", rule: ageRule, xml: "50", valid: true),
SchematronSpec(name: "number-comparison-fail", rule: ageRule, xml: "150", valid: false),
SchematronSpec(name: "report-not-fired", rule: reportRule, xml: "", valid: true),
SchematronSpec(name: "report-fired", rule: reportRule, xml: "", valid: false),
]
return try specs.map { spec in
let schema = "\(spec.rule)"
let errors = try PureXML.Validation.Schematron(schema: schema).validate(spec.xml)
return PureXML.Validation.ConformanceCase(
name: spec.name,
actual: errors.isEmpty ? "valid" : "invalid",
expected: spec.valid ? "valid" : "invalid",
)
}
}
@Test("The Schematron conformance corpus passes with no located failures")
func test_schematronCorpusConforms() throws {
let failures = try PureXML.Validation.Conformance.failures(in: schematronCorpus())
#expect(failures.isEmpty, "\(failures.map(\.reason))")
}
}