PureXML/Tests/SchemaXSTSRegressionTests.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

192 lines
9.6 KiB
Swift

import Foundation
import Testing
@testable import PureXML
/// Opt-in regressions drawn from XSTS clusters fixed for #146. Requires
/// `XSTS_ROOT` pointing at the 2006-11-06 suite (same as ``XSTSSuiteTests``).
@Suite("XSTS instance regressions (opt-in via XSTS_ROOT)")
struct SchemaXSTSRegressionTests {
private var root: String? {
ProcessInfo.processInfo.environment["XSTS_ROOT"]
}
@Test("attgD019: attributeGroup anyAttribute is inherited")
func test_attgD019() throws {
guard let root else { return }
let base = root.appending("/msData/attributeGroup")
let mainXSD = try String(contentsOfFile: "\(base)/attgD019.xsd", encoding: .utf8)
let otherXSD = try String(contentsOfFile: "\(base)/attgD019a.xsd", encoding: .utf8)
let xml = try String(contentsOfFile: "\(base)/attgD019.xml", encoding: .utf8)
let doc = try PureXML.Schema.Document(mainXSD)
let loader: (String) -> String? = { loc in loc.hasSuffix("attgD019a.xsd") ? otherXSD : nil }
#expect(try doc.validate(xml, schemaLoader: loader).isEmpty)
}
@Test("schA1: multi-schema xsi:schemaLocation with distinct ct-A variants")
func test_schA1() throws {
guard let root else { return }
let base = root.appending("/msData/schema")
let mainXSD = try String(contentsOfFile: "\(base)/schA1_a.xsd", encoding: .utf8)
let xml = try String(contentsOfFile: "\(base)/schA1.xml", encoding: .utf8)
let doc = try PureXML.Schema.Document(mainXSD)
let loader: (String) -> String? = { loc in
if loc.hasSuffix("schA1_b.xsd") {
return try? String(contentsOfFile: "\(base)/schA1_b.xsd", encoding: .utf8)
}
if loc.hasSuffix("schA1_c.xsd") {
return try? String(contentsOfFile: "\(base)/schA1_c.xsd", encoding: .utf8)
}
return nil
}
#expect(try doc.validate(xml, schemaLoader: loader).isEmpty)
}
@Test("ipo2: imported address schema with default XSD namespace")
func test_ipo2() throws {
guard let root else { return }
let base = root.appending("/boeingData/ipo2")
let mainXSD = try String(contentsOfFile: "\(base)/ipo.xsd", encoding: .utf8)
let xml = try String(contentsOfFile: "\(base)/ipo_1.xml", encoding: .utf8)
let addXSD = try String(contentsOfFile: "\(base)/address.xsd", encoding: .utf8)
let doc = try PureXML.Schema.Document(mainXSD, schemaLoader: { loc in loc == "address.xsd" ? addXSD : nil })
let loader: (String) -> String? = { loc in
loc == "address.xsd" ? addXSD : (loc.hasSuffix("ipo.xsd") ? mainXSD : nil)
}
#expect(try doc.validate(xml, schemaLoader: loader).isEmpty)
}
@Test("attgC007: redefined attributeGroup self-reference merges base attrs")
func test_attgC007() throws {
guard let root else { return }
let base = root.appending("/msData/attributeGroup")
let mainXSD = try String(contentsOfFile: "\(base)/attgC007.xsd", encoding: .utf8)
let xml = try String(contentsOfFile: "\(base)/attgC007.xml", encoding: .utf8)
let redXSD = try String(contentsOfFile: "\(base)/attgC007vRed.xsd", encoding: .utf8)
let loader: (String) -> String? = { loc in loc.hasSuffix("attgC007vRed.xsd") ? redXSD : nil }
let doc = try PureXML.Schema.Document(mainXSD, schemaLoader: loader)
#expect(try doc.validate(xml, schemaLoader: loader).isEmpty)
}
@Test("idF025: redefined complexType extension keeps base particles")
func test_idF025() throws {
guard let root else { return }
let base = root.appending("/msData/identityConstraint")
let mainXSD = try String(contentsOfFile: "\(base)/idF025.xsd", encoding: .utf8)
let xml = try String(contentsOfFile: "\(base)/idF025.xml", encoding: .utf8)
let redXSD = try String(contentsOfFile: "\(base)/idF025.red", encoding: .utf8)
let loader: (String) -> String? = { loc in loc.hasSuffix("idF025.red") ? redXSD : nil }
let doc = try PureXML.Schema.Document(mainXSD, schemaLoader: loader)
#expect(try doc.validate(xml, schemaLoader: loader).isEmpty)
}
@Test("identity test suite 001: key/keyref decimal value space")
func test_identity001() throws {
guard let root else { return }
let base = root.appending("/sunData/combined/identity/IdentityTestSuite/001")
let xsd = try String(contentsOfFile: "\(base)/test.xsd", encoding: .utf8)
let xml = try String(contentsOfFile: "\(base)/test.1.v.xml", encoding: .utf8)
#expect(try PureXML.Schema.Document(xsd).validate(xml).isEmpty)
}
@Test("ipo3: xsi:type resolves imported complex type")
func test_ipo3() throws {
guard let root else { return }
let base = root.appending("/boeingData/ipo3")
let mainXSD = try String(contentsOfFile: "\(base)/ipo.xsd", encoding: .utf8)
let xml = try String(contentsOfFile: "\(base)/ipo_1.xml", encoding: .utf8)
let addXSD = try String(contentsOfFile: "\(base)/address.xsd", encoding: .utf8)
let itemXSD = try String(contentsOfFile: "\(base)/itematt.xsd", encoding: .utf8)
let loader: (String) -> String? = { loc in
if loc.hasSuffix("address.xsd") {
return addXSD
}
if loc.hasSuffix("itematt.xsd") {
return itemXSD
}
return nil
}
let doc = try PureXML.Schema.Document(mainXSD, schemaLoader: loader)
#expect(try doc.validate(xml, schemaLoader: loader).isEmpty)
}
@Test("ipo4: redefine address type with xsi:type USAddress")
func test_ipo4() throws {
guard let root else { return }
let base = root.appending("/boeingData/ipo4")
let mainXSD = try String(contentsOfFile: "\(base)/ipo.xsd", encoding: .utf8)
let xml = try String(contentsOfFile: "\(base)/ipo_1.xml", encoding: .utf8)
let addXSD = try String(contentsOfFile: "\(base)/address.xsd", encoding: .utf8)
let itemXSD = try String(contentsOfFile: "\(base)/itematt.xsd", encoding: .utf8)
let loader: (String) -> String? = { loc in
if loc.hasSuffix("address.xsd") {
return addXSD
}
if loc.hasSuffix("itematt.xsd") {
return itemXSD
}
return nil
}
let doc = try PureXML.Schema.Document(mainXSD, schemaLoader: loader)
let errors = try doc.validate(xml, schemaLoader: loader)
if !errors.isEmpty {
print("ipo4 errors:", errors.map(\.description).joined(separator: " | "))
}
#expect(errors.isEmpty)
}
@Test("identity test suite 002: QName key/keyref value space")
func test_identity002() throws {
guard let root else { return }
let base = root.appending("/sunData/combined/identity/IdentityTestSuite/002")
let xsd = try String(contentsOfFile: "\(base)/test.xsd", encoding: .utf8)
let xml = try String(contentsOfFile: "\(base)/test.2.v.xml", encoding: .utf8)
let errors = try PureXML.Schema.Document(xsd).validate(xml)
if !errors.isEmpty {
print("identity002 errors:", errors.map(\.description).joined(separator: " | "))
}
#expect(errors.isEmpty)
}
@Test("identity test suite 003: decimal key/keyref with union field xpath")
func test_identity003() throws {
guard let root else { return }
let base = root.appending("/sunData/combined/identity/IdentityTestSuite/003")
let xsd = try String(contentsOfFile: "\(base)/test.xsd", encoding: .utf8)
let xml = try String(contentsOfFile: "\(base)/test.1.v.xml", encoding: .utf8)
#expect(try PureXML.Schema.Document(xsd).validate(xml).isEmpty)
}
@Test("particlesZ003: imported element ref resolves namespace prefix on node")
func test_particlesZ003() throws {
guard let root else { return }
let base = root.appending("/msData/particles")
let mainXSD = try String(contentsOfFile: "\(base)/particlesZ003.xsd", encoding: .utf8)
let xml = try String(contentsOfFile: "\(base)/particlesZ003.xml", encoding: .utf8)
let impXSD = try String(contentsOfFile: "\(base)/particlesZ003.imp", encoding: .utf8)
let loader: (String) -> String? = { loc in loc.hasSuffix("particlesZ003.imp") ? impXSD : nil }
let doc = try PureXML.Schema.Document(mainXSD, schemaLoader: loader)
#expect(try doc.validate(xml, schemaLoader: loader).isEmpty)
}
@Test("ctE018: chameleon include promotes type to parent target namespace")
func test_ctE018() throws {
guard let root else { return }
let base = root.appending("/msData/complexType")
let mainXSD = try String(contentsOfFile: "\(base)/ctE018_a.xsd", encoding: .utf8)
let xml = try String(contentsOfFile: "\(base)/ctE018.xml", encoding: .utf8)
let incXSD = try String(contentsOfFile: "\(base)/ctE018_b.xsd", encoding: .utf8)
let loader: (String) -> String? = { loc in loc.hasSuffix("ctE018_b.xsd") ? incXSD : nil }
let doc = try PureXML.Schema.Document(mainXSD, schemaLoader: loader)
#expect(try doc.validate(xml, schemaLoader: loader).isEmpty)
}
@Test("Arabic block pattern matches per Unicode scalar")
func test_arabicBlockPattern() throws {
guard let root else { return }
let base = root.appending("/msData/regex")
let xsd = try String(contentsOfFile: "\(base)/Arabic.xsd", encoding: .utf8)
let xml = try String(contentsOfFile: "\(base)/Arabic.xml", encoding: .utf8)
#expect(try PureXML.Schema.Document(xsd).validate(xml).isEmpty)
}
}