PureXML/Tests/SchemaIDREFDefaultTests.swift
Mihaela Mihaljevic 9966e254e0 fix(schema): resolve defaulted/fixed IDREF attributes against IDs
cvc-id: when an instance omits an attribute, its default/fixed value applies, so
a defaulted or fixed xs:IDREF/xs:IDREFS must still resolve to a matching xs:ID.
The reference was recorded only for attributes physically present, so a dangling
defaulted IDREF was wrongly accepted. The supplied value is now recorded for
document-scoped ID/IDREF checking exactly as a present value would be (shared by
the tree and streaming validators, which both call validateAttributes). A
required absent attribute is still reported as missing, recordIDs is a no-op for
non-ID types, and a defaulted IDREF that does resolve stays valid. Catches
idZ012. XSTS invalid-instances-accepted 20 to 19, valid-instances-rejected held
at 0.
2026-06-22 18:56:36 +02:00

57 lines
2.0 KiB
Swift

import Testing
@testable import PureXML
/// A defaulted or fixed `xs:IDREF`/`xs:IDREFS` attribute supplies its value when
/// the instance omits the attribute, so that value must still resolve to a
/// matching `xs:ID` (cvc-id). The reference was recorded only for present
/// attributes, so a dangling defaulted IDREF was wrongly accepted. Mirrors XSTS
/// idZ012.
@Suite("defaulted/fixed IDREF resolution")
struct SchemaIDREFDefaultTests {
private func errors(_ xsd: String, _ xml: String) throws -> [PureXML.Validation.ValidationError] {
try PureXML.Schema.Document(xsd).validate(xml)
}
private let defaultedIDREFS = """
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root">
<xs:complexType>
<xs:attribute name="drefs" type="xs:IDREFS" default="abc"/>
</xs:complexType>
</xs:element>
</xs:schema>
"""
@Test("a defaulted IDREFS with no matching ID is rejected")
func test_danglingDefaultedIDREFS() throws {
#expect(try !errors(defaultedIDREFS, "<root/>").isEmpty)
}
private let resolvable = """
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element name="t" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="id" type="xs:ID"/>
<xs:attribute name="dref" type="xs:IDREF" default="abc"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
"""
@Test("a defaulted IDREF that resolves to a present ID stays valid")
func test_resolvableDefaultedIDREF() throws {
#expect(try errors(resolvable, #"<root><t id="abc"/></root>"#).isEmpty)
}
@Test("a present IDREF with no matching ID is still rejected (unchanged)")
func test_danglingPresentIDREF() throws {
#expect(try !errors(resolvable, #"<root><t dref="zzz"/></root>"#).isEmpty)
}
}