@testable import PureXML
import Testing
@Suite("Streaming XSD validation")
struct StreamingXSDTests {
private let schema = """
"""
/// Streaming validation must agree with the tree validator on the same
/// document (these schemas carry no identity constraints, so the tree output
/// is exactly the content/attribute errors streaming produces). Agreement on
/// every document is the correctness proof.
private func check(_ xml: String, expectValid: Bool) throws {
let document = try PureXML.Schema.Document(schema)
let tree = try document.validate(xml).map(\.reason).sorted()
let streamed = try document.validate(streaming: xml).map(\.reason).sorted()
#expect(tree == streamed, "streaming disagreed with tree on: \(xml)\n tree: \(tree)\n stream: \(streamed)")
#expect(streamed.isEmpty == expectValid, "wrong verdict for: \(xml) -> \(streamed)")
}
@Test("Valid documents agree and pass")
func test_valid() throws {
try check("1- x2
", expectValid: true)
// Repeated item (maxOccurs unbounded), optional ref omitted.
try check(
"1- x2
"
+ "- y9
",
expectValid: true,
)
}
@Test("Invalid documents agree and fail")
func test_invalid() throws {
// Missing required attribute sku.
try check("1- x2
", expectValid: false)
// A bad xs:int value for id.
try check("notanint- x2
", expectValid: false)
// A bad xs:positiveInteger value for qty.
try check("1- x0
", expectValid: false)
// Missing required child qty.
try check("1- x
", expectValid: false)
// Children out of order.
try check("1- 2x
", expectValid: false)
// An undeclared extra child.
try check("1- x2
", expectValid: false)
// An undeclared attribute.
try check("1- x2
", expectValid: false)
// No items at all (item is required, maxOccurs unbounded but minOccurs 1).
try check("1", expectValid: false)
}
@Test("The streaming content check is a composable Validation value")
func test_shallowValidityRule() {
// The streaming content check applied directly through the Validation rule.
let validator = PureXML.Schema.ComplexValidator()
let rule = PureXML.Schema.ComplexValidator.shallowValidity
#expect(rule.description == "Each streamed element is valid against its declared XSD type")
// An empty-content element carrying a child element is invalid.
let bad = PureXML.Schema.ResolvedElement(
element: PureXML.Model.Element("v", children: [.element(.init("child"))]),
type: .complex(PureXML.Schema.ComplexType(content: .empty)),
)
let errors = rule.apply(to: bad, at: [.element("v")], in: validator)
#expect(errors.contains { $0.reason.contains("must be empty") })
#expect(errors.first?.codingPath.map(\.stringValue) == ["v"])
}
}