PureXML/Tests/SchemaQNameLengthTests.swift
Mihaela Mihaljevic c6305c9d93 fix(schema): treat QName length facets as non-constraining
XSD 1.0 Datatypes 4.3.1 defines the unit of length only for string, anyURI,
binary, and list; for QName it is implementation-defined. We had counted
characters, rejecting valid QName values. Like Xerces and the XSTS NIST set we
now treat length/minLength/maxLength on QName as always satisfied. Lexical
QName validity is still enforced.

The suite's contributors disagree here (NIST: non-constraining; Microsoft: a
character count), which the spec does not resolve, so a single behavior cannot
satisfy both. Net XSTS: valid instances rejected 547 to 502; 4 Microsoft cases
move to invalid instances accepted (257 to 261), recorded as a deliberate
interpretation in docs/xsts-deviations.md.

Refs #147, #129.
2026-06-13 18:04:25 +02:00

35 lines
1.4 KiB
Swift

@testable import PureXML
import Testing
/// `length`, `minLength`, and `maxLength` on `xs:QName` do not constrain the
/// value: XSD 1.0 Datatypes 4.3.1 leaves the unit of length unspecified for
/// QName, so (like Xerces and the XSTS NIST oracle) any QName satisfies them
/// (#147). Lexical QName validity is still enforced.
@Suite("QName length facets")
struct SchemaQNameLengthTests {
private func schema(_ facet: String) throws -> PureXML.Schema.Document {
try PureXML.Schema.Document("""
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="v">
<xs:simpleType>
<xs:restriction base="xs:QName">\(facet)</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:schema>
""")
}
@Test("length, minLength, and maxLength never reject a valid QName")
func test_lengthIsNonConstraining() throws {
#expect(try schema(#"<xs:length value="1"/>"#).validate("<v>abcdefghij</v>").isEmpty)
#expect(try schema(#"<xs:maxLength value="2"/>"#).validate("<v>abcdefghij</v>").isEmpty)
#expect(try schema(#"<xs:minLength value="20"/>"#).validate("<v>abc</v>").isEmpty)
}
@Test("Lexical QName validity is still enforced")
func test_qnameStillValidated() throws {
// A leading digit is not a valid NCName, so not a valid QName.
#expect(try !schema(#"<xs:length value="1"/>"#).validate("<v>1bad</v>").isEmpty)
}
}