A complex type's simpleContent derivation can name another complex type with simpleContent as its base. simpleContentType resolved a non-XSD, non-simpleType base via context.simpleTypes only, so a complex-type base (absent from that map) fell back to xs:string and left the content unconstrained: text invalid for the real base type was accepted (baseTD00101, where Test restricts Test2 which extends xs:int, yet "b" was accepted). simpleContentBaseType now resolves the base to an XSD built-in, a named simple type, or, when the base is a complex type with simpleContent, that type's own resolved simple type by recursing through complexTypeNodes (cycle-guarded by a visited set); the deriving node's facets are then applied over the resolved base's facets. So Test resolves to int and non-int text is rejected, while a valid int and the accumulated facets along the chain are honoured. invalid-instances-accepted 39 to 37, no false positive (valid-instances-rejected and valid-schemas-rejected held at 0), no other bucket moved. An adversarial review exercised facet accumulation, named-simpleType bases in the chain, multi-level and extension chains, and cycles, and found no over-rejection.
39 lines
1.8 KiB
Swift
39 lines
1.8 KiB
Swift
@testable import PureXML
|
|
import Testing
|
|
|
|
/// A `simpleContent` derivation whose base is another complex type with
|
|
/// simpleContent resolves through the chain to the underlying simple type, so the
|
|
/// element's text is validated against it. A type restricting (or extending) a
|
|
/// complex type that ultimately derives from `xs:int` validates its content as an
|
|
/// int, not as unconstrained string (W3C sun baseTD00101).
|
|
@Suite("simpleContent base chain")
|
|
struct SchemaSimpleContentChainTests {
|
|
private func schema(method: String) throws -> PureXML.Schema.Document {
|
|
try PureXML.Schema.Document("""
|
|
<xsd:schema xmlns="u" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="u">
|
|
<xsd:element name="root" type="Test"/>
|
|
<xsd:complexType name="Test"><xsd:simpleContent>
|
|
<xsd:\(method) base="Test2"/>
|
|
</xsd:simpleContent></xsd:complexType>
|
|
<xsd:complexType name="Test2"><xsd:simpleContent>
|
|
<xsd:extension base="xsd:int"/>
|
|
</xsd:simpleContent></xsd:complexType>
|
|
</xsd:schema>
|
|
""")
|
|
}
|
|
|
|
@Test("text invalid for the chained int base is rejected, valid int accepted")
|
|
func test_restrictionChainValidatesAsInt() throws {
|
|
let restriction = try schema(method: "restriction")
|
|
#expect(try !restriction.validate(#"<root xmlns="u">b</root>"#).isEmpty)
|
|
#expect(try restriction.validate(#"<root xmlns="u">42</root>"#).isEmpty)
|
|
}
|
|
|
|
@Test("an extension chain to int also validates the content as int")
|
|
func test_extensionChainValidatesAsInt() throws {
|
|
let extension0 = try schema(method: "extension")
|
|
#expect(try !extension0.validate(#"<root xmlns="u">b</root>"#).isEmpty)
|
|
#expect(try extension0.validate(#"<root xmlns="u">42</root>"#).isEmpty)
|
|
}
|
|
}
|