PureXML/Tests/SchemaAttributeRefTests.swift
Mihaela Mihaljevic 9ff7ed360f fix(schema): resolve <xs:attribute ref> to global attribute declarations
An <xs:attribute ref="..."> reference has no name attribute, so attributeUse
returned nil and the referenced attribute was dropped, making it look undeclared
on the instance (nested attributeGroup refs were already flattened, but the
per-attribute reference was not). References now resolve through a new global
attribute index to the declaration's type, with use/default/fixed taken from the
reference site and the name qualified to the target namespace.

XSTS: valid instances rejected 338 to 311. Baseline updated; regression tests
cover a referenced attribute admitted, its type enforced, and an attribute
outside the group still rejected. The attribute-parsing functions move to
XSDAttributeParser.swift to keep XSDParser within the type-body length limit.

Refs #147, #129.
2026-06-13 19:30:11 +02:00

45 lines
1.7 KiB
Swift

@testable import PureXML
import Testing
/// An `<xs:attribute ref="...">` resolves to a global attribute declaration,
/// taking its type from the global node and its use/default/fixed from the
/// reference site (#147, XSTS attgD set). References were dropped (they have no
/// `name`), so a referenced attribute looked undeclared on the instance.
@Suite("Attribute references in attribute groups")
struct SchemaAttributeRefTests {
private var schema: PureXML.Schema.Document {
get throws {
try PureXML.Schema.Document("""
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:attribute name="a1" type="xs:string"/>
<xs:element name="doc">
<xs:complexType>
<xs:attributeGroup ref="g"/>
</xs:complexType>
</xs:element>
<xs:attributeGroup name="g">
<xs:attribute ref="a1"/>
<xs:attribute name="a2" type="xs:int"/>
</xs:attributeGroup>
</xs:schema>
""")
}
}
@Test("A referenced global attribute is admitted on the instance")
func test_referencedAttributeAdmitted() throws {
#expect(try schema.validate(#"<doc a1="x" a2="5"/>"#).isEmpty)
}
@Test("The referenced attribute keeps the global declaration's type")
func test_refTypeEnforced() throws {
// a2 is xs:int via inline declaration; a non-integer is rejected.
#expect(try !schema.validate(#"<doc a1="x" a2="notint"/>"#).isEmpty)
}
@Test("An attribute outside the (nested) group is still undeclared")
func test_undeclaredStillRejected() throws {
#expect(try !schema.validate(#"<doc a1="x" a2="5" a3="y"/>"#).isEmpty)
}
}