xs:ID, xs:IDREF, and xs:IDREFS were validated only lexically (as NCNames); the document-wide rules that every ID is unique and every IDREF/IDREFS item matches some ID were not enforced, so duplicate IDs and dangling references passed. The tree validator now records ID and reference values during its typed walk over elements and attributes (a new IDTracker), and reports duplicate IDs and unresolved references after the whole document is seen, so a forward reference resolves against an ID declared later. XSTS: invalid instances accepted 179 to 166. Baseline updated; regression tests cover unique IDs, a forward reference, a duplicate ID, an unresolved IDREF, and IDREFS item resolution. The ID/IDREF helpers live in a ComplexValidator extension to keep the type within the file/body length limits. Refs #147, #129.
41 lines
1.9 KiB
Swift
41 lines
1.9 KiB
Swift
@testable import PureXML
|
|
import Testing
|
|
|
|
/// Length facets on the built-in list datatypes (`NMTOKENS`, `IDREFS`,
|
|
/// `ENTITIES`) count list items, not characters (#146). A restriction of one of
|
|
/// these built-ins had collapsed to an atomic string, so `length` measured
|
|
/// characters and rejected valid instances across the XSTS NIST list sets.
|
|
@Suite("List datatype length facets")
|
|
struct SchemaListFacetTests {
|
|
private func schema(_ base: String, _ 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="\(base)">\(facet)</xs:restriction>
|
|
</xs:simpleType>
|
|
</xs:element>
|
|
</xs:schema>
|
|
""")
|
|
}
|
|
|
|
@Test("length on NMTOKENS counts items, not characters")
|
|
func test_nmtokensLength() throws {
|
|
let doc = try schema("xs:NMTOKENS", #"<xs:length value="3"/>"#)
|
|
#expect(try doc.validate("<v>alpha beta gamma</v>").isEmpty) // 3 items: valid
|
|
#expect(try !doc.validate("<v>alpha beta</v>").isEmpty) // 2 items: invalid
|
|
#expect(try !doc.validate("<v>alpha beta gamma delta</v>").isEmpty) // 4 items: invalid
|
|
}
|
|
|
|
/// ENTITIES would drag in entity declarations and IDREFS in document-scoped
|
|
/// reference resolution; NMTOKENS isolates the list length facet itself.
|
|
@Test("minLength and maxLength on a built-in list count items")
|
|
func test_listMinMax() throws {
|
|
let doc = try schema("xs:NMTOKENS", #"<xs:minLength value="2"/><xs:maxLength value="3"/>"#)
|
|
#expect(try doc.validate("<v>a b</v>").isEmpty) // 2 items: valid
|
|
#expect(try doc.validate("<v>a b c</v>").isEmpty) // 3 items: valid
|
|
#expect(try !doc.validate("<v>a</v>").isEmpty) // 1 item: invalid
|
|
#expect(try !doc.validate("<v>a b c d</v>").isEmpty) // 4 items: invalid
|
|
}
|
|
}
|