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.
122 lines
5.2 KiB
Swift
122 lines
5.2 KiB
Swift
import Testing
|
|
@testable import PureXML
|
|
|
|
/// Per-rule isolation tests (Validation rules XSD): Validation rules XSD: derivation and identifiers.
|
|
@Suite("Validation rules XSD: derivation and identifiers")
|
|
struct ValidationRuleXSDDerivationTests {
|
|
// MARK: xsiTypeSubstitutionValid / xsiTypeOverrideResolves
|
|
|
|
private let abstractDerivedSchema = """
|
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
|
<xs:complexType name="T" abstract="true"><xs:sequence><xs:element name="a" type="xs:string" minOccurs="0"/></xs:sequence></xs:complexType>
|
|
<xs:complexType name="C"><xs:complexContent><xs:extension base="T"/></xs:complexContent></xs:complexType>
|
|
<xs:element name="n" type="T"/>
|
|
</xs:schema>
|
|
"""
|
|
|
|
@Test("xsiTypeSubstitutionValid rejects an abstract declared type with no xsi:type override")
|
|
func test_xsiTypeSubstitutionValid() throws {
|
|
let errors = try ValidationRuleTestSupport.xsdErrors(PureXML.Validation.XSD.xsiTypeSubstitutionValid, schema: abstractDerivedSchema, instance: "<n/>", rootName: "n")
|
|
#expect(errors.count == 1)
|
|
#expect(errors.first?.reason.contains("abstract type") == true)
|
|
}
|
|
|
|
@Test("xsiTypeSubstitutionValid accepts an xsi:type naming a concrete derived type")
|
|
func test_xsiTypeSubstitutionValid_succeeds() throws {
|
|
let errors = try ValidationRuleTestSupport.xsdErrors(
|
|
PureXML.Validation.XSD.xsiTypeSubstitutionValid,
|
|
schema: abstractDerivedSchema,
|
|
instance: "<n \(ValidationRuleTestSupport.xsiNS) xsi:type=\"C\"/>",
|
|
rootName: "n",
|
|
)
|
|
#expect(errors.isEmpty)
|
|
}
|
|
|
|
private let simpleStringSchema = """
|
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
|
<xs:element name="n" type="xs:string"/>
|
|
</xs:schema>
|
|
"""
|
|
|
|
@Test("xsiTypeOverrideResolves rejects an xsi:type naming an unknown type")
|
|
func test_xsiTypeOverrideResolves() throws {
|
|
let errors = try ValidationRuleTestSupport.xsdErrors(
|
|
PureXML.Validation.XSD.xsiTypeOverrideResolves,
|
|
schema: simpleStringSchema,
|
|
instance: "<n \(ValidationRuleTestSupport.xsiNS) xsi:type=\"totallyUnknownType\">text</n>",
|
|
rootName: "n",
|
|
)
|
|
#expect(errors.count == 1)
|
|
#expect(errors.first?.reason.contains("unknown xsi:type") == true)
|
|
}
|
|
|
|
@Test("xsiTypeOverrideResolves accepts an xsi:type naming a resolvable type")
|
|
func test_xsiTypeOverrideResolves_succeeds() throws {
|
|
let errors = try ValidationRuleTestSupport.xsdErrors(
|
|
PureXML.Validation.XSD.xsiTypeOverrideResolves,
|
|
schema: simpleStringSchema,
|
|
instance: "<n \(ValidationRuleTestSupport.xsiNS) xsi:type=\"xs:string\">text</n>",
|
|
rootName: "n",
|
|
)
|
|
#expect(errors.isEmpty)
|
|
}
|
|
|
|
// MARK: idIdrefConsistent
|
|
|
|
private let idElementSchema = """
|
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
|
<xs:element name="n">
|
|
<xs:complexType><xs:sequence><xs:element name="a" maxOccurs="unbounded">
|
|
<xs:complexType><xs:attribute name="id" type="xs:ID"/></xs:complexType>
|
|
</xs:element></xs:sequence></xs:complexType>
|
|
</xs:element>
|
|
</xs:schema>
|
|
"""
|
|
|
|
@Test("idIdrefConsistent rejects a duplicate xs:ID value")
|
|
func test_idIdrefConsistent() throws {
|
|
let errors = try ValidationRuleTestSupport.xsdErrors(
|
|
PureXML.Validation.XSD.idIdrefConsistent,
|
|
schema: idElementSchema,
|
|
instance: "<n><a id=\"x1\"/><a id=\"x1\"/></n>",
|
|
rootName: "n",
|
|
)
|
|
#expect(!errors.isEmpty)
|
|
}
|
|
|
|
@Test("idIdrefConsistent accepts distinct xs:ID values")
|
|
func test_idIdrefConsistent_succeeds() throws {
|
|
let errors = try ValidationRuleTestSupport.xsdErrors(
|
|
PureXML.Validation.XSD.idIdrefConsistent,
|
|
schema: idElementSchema,
|
|
instance: "<n><a id=\"x1\"/><a id=\"x2\"/></n>",
|
|
rootName: "n",
|
|
)
|
|
#expect(errors.isEmpty)
|
|
}
|
|
|
|
// MARK: xsdStreamingIdConsistency
|
|
|
|
@Test("xsdStreamingIdConsistency rejects a duplicate xs:ID recorded during streaming")
|
|
func test_xsdStreamingIdConsistency() {
|
|
let validator = PureXML.Schema.ComplexValidator()
|
|
validator.recordIDs(PureXML.Schema.SimpleType(base: .id), value: "x1", at: [])
|
|
validator.recordIDs(PureXML.Schema.SimpleType(base: .id), value: "x1", at: [])
|
|
let errors = PureXML.Validation.Validator<Void>.blank
|
|
.validating(PureXML.Schema.ComplexValidator.idConsistency)
|
|
.errors(for: validator, in: ())
|
|
#expect(!errors.isEmpty)
|
|
}
|
|
|
|
@Test("xsdStreamingIdConsistency accepts distinct xs:ID values recorded during streaming")
|
|
func test_xsdStreamingIdConsistency_succeeds() {
|
|
let validator = PureXML.Schema.ComplexValidator()
|
|
validator.recordIDs(PureXML.Schema.SimpleType(base: .id), value: "x1", at: [])
|
|
validator.recordIDs(PureXML.Schema.SimpleType(base: .id), value: "x2", at: [])
|
|
let errors = PureXML.Validation.Validator<Void>.blank
|
|
.validating(PureXML.Schema.ComplexValidator.idConsistency)
|
|
.errors(for: validator, in: ())
|
|
#expect(errors.isEmpty)
|
|
}
|
|
}
|