PureXML/Tests/ValidationRuleXSDTests.swift
Mihaela Mihaljevic 380160cc2b refactor(validation): decompose XSD instance validation into composable rules
The two monolithic XSD content/identity rules only satisfied the OpenAPIKit
validation idiom at the wrong granularity: no per-constraint removability,
no isolable failing/near-miss tests. Split them into 32 named rules, each
finding tagged at its origin and cached per XSDContext so the walk still
runs once per document (the #101 decision against duplicating XSD's
recursive type resolution still holds). Wired the streaming path's ID/IDREF
and identity checks through the same framework instead of calling the
validators imperatively, and added the unwrapAndLookup combinator the rule
already named as required.

Also includes the mandated repo-wide swiftformat/swiftlint pass.
2026-07-12 14:12:17 +02:00

85 lines
4.5 KiB
Swift

import Testing
@testable import PureXML
/// Per-rule isolation tests (Validation rules XSD): the schema-consistency layer
/// (`PureXML.Validation.XSDSchema`), unrelated to instance validation.
@Suite("Validation rules XSD")
struct ValidationRuleXSDTests {
// MARK: XSDSchema (unchanged, schema-consistency layer)
@Test("XSDSchema.finalRespected rejects a derivation forbidden by final")
func test_xsdFinalRespected() throws {
let xsd = """
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="ShapeT" final="extension">
<xs:sequence><xs:element name="name" type="xs:string"/></xs:sequence>
</xs:complexType>
<xs:complexType name="CircleT">
<xs:complexContent><xs:extension base="ShapeT"><xs:sequence><xs:element name="radius" type="xs:integer"/></xs:sequence></xs:extension></xs:complexContent>
</xs:complexType>
</xs:schema>
"""
let compiled = try PureXML.Schema.XSDParser.parse(xsd)
let facts = PureXML.Schema.CompiledSchemaFacts(types: compiled.types, typeDerivation: compiled.typeDerivation, typeFinal: compiled.typeFinal)
let fact = PureXML.Schema.SchemaTypeFact(name: "CircleT", derivation: compiled.typeDerivation["CircleT"])
let errors = PureXML.Validation.BuiltinValidation.xsdFinalRespected.apply(to: fact, at: [.element("CircleT")], in: facts)
#expect(errors.count == 1)
}
@Test("XSDSchema.finalRespected accepts a derivation the base permits")
func test_xsdFinalRespected_succeeds() throws {
let xsd = """
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="ShapeT"><xs:sequence><xs:element name="name" type="xs:string"/></xs:sequence></xs:complexType>
</xs:schema>
"""
let compiled = try PureXML.Schema.XSDParser.parse(xsd)
let facts = PureXML.Schema.CompiledSchemaFacts(types: compiled.types, typeDerivation: compiled.typeDerivation, typeFinal: compiled.typeFinal)
let fact = PureXML.Schema.SchemaTypeFact(name: "ShapeT", derivation: nil)
#expect(PureXML.Validation.BuiltinValidation.xsdFinalRespected.apply(to: fact, at: [.element("ShapeT")], in: facts).isEmpty)
}
@Test("XSDSchema.restrictionsAreSubsets rejects an unfaithful restriction")
func test_xsdRestrictionsAreSubsets() throws {
let xsd = """
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="B"><xs:sequence><xs:element name="a" type="xs:string"/></xs:sequence></xs:complexType>
<xs:complexType name="R">
<xs:complexContent>
<xs:restriction base="B">
<xs:sequence>
<xs:element name="a" type="xs:string"/>
<xs:element name="b" type="xs:string"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>
"""
let compiled = try PureXML.Schema.XSDParser.parse(xsd)
let facts = PureXML.Schema.CompiledSchemaFacts(types: compiled.types, typeDerivation: compiled.typeDerivation, typeFinal: compiled.typeFinal)
let fact = PureXML.Schema.SchemaTypeFact(name: "R", derivation: compiled.typeDerivation["R"])
#expect(!PureXML.Validation.BuiltinValidation.xsdRestrictionsAreSubsets.apply(to: fact, at: [.element("R")], in: facts).isEmpty)
}
@Test("XSDSchema.restrictionsAreSubsets accepts a faithful restriction")
func test_xsdRestrictionsAreSubsets_succeeds() throws {
let xsd = """
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="B"><xs:sequence><xs:element name="a" type="xs:string"/></xs:sequence></xs:complexType>
<xs:complexType name="R">
<xs:complexContent>
<xs:restriction base="B">
<xs:sequence><xs:element name="a" type="xs:string"/></xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>
"""
let compiled = try PureXML.Schema.XSDParser.parse(xsd)
let facts = PureXML.Schema.CompiledSchemaFacts(types: compiled.types, typeDerivation: compiled.typeDerivation, typeFinal: compiled.typeFinal)
let fact = PureXML.Schema.SchemaTypeFact(name: "R", derivation: compiled.typeDerivation["R"])
#expect(PureXML.Validation.BuiltinValidation.xsdRestrictionsAreSubsets.apply(to: fact, at: [.element("R")], in: facts).isEmpty)
}
}