PureXML/Tests/SchemaParticleTypeRestrictionTests.swift
Mihaela Mihaljevic ee676cb470 fix(schema): restriction may not narrow an element to an extension-derived type
XSD 1.0 cos-particle-restrict NameAndTypeOK.2.2: when a complexContent
restriction narrows an element, the element's type must be validly derived
from the base element's type EXCLUDING extension (and list/union), i.e. by
restriction only. The element-type check followed the derivation chain
regardless of method, so a type derived from the base by extension was wrongly
accepted as a valid restriction (corpus particlesIj008).

Add typeDerivesByRestriction (as typeDerivesOrEqual, but the user-declared
chain is followed across restriction steps only; an extension step breaks the
walk) and use it on the non-union fall-through of elementTypeRestrictionOK.
The shared typeDerivesOrEqual is untouched, so substitution-group validity
(where extension is legal) is unaffected. Built-in lattice and union-base
derivation are unchanged, so valid restrictions, including the union-member
restriction addB150, still compile.

XSTS invalid-schemas-accepted 37 -> 36; valid-schemas-rejected held at 0
across all 14383 groups. Union-base (Ik011/Ik025/Ik027) and substitution-group
(V020) cases need the by-name union-member and ref-resolution clauses and stay
deferred.
2026-06-20 18:34:50 +02:00

45 lines
2.2 KiB
Swift

import Testing
@testable import PureXML
/// XSD 1.0 cos-particle-restrict NameAndTypeOK.2.2 (#158): when a complexContent
/// restriction narrows an element, the element's type must be validly derived from
/// the base element's type EXCLUDING extension (by restriction only). A type derived
/// from the base type by extension is not a valid restriction (corpus particlesIj008).
@Suite("XSD NameAndTypeOK restriction-only type derivation (#158)")
struct SchemaParticleTypeRestrictionTests {
private func compiles(_ derivedC1Type: String) -> Bool {
let schema = """
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="foo"><xs:sequence><xs:element name="a" type="xs:string"/></xs:sequence></xs:complexType>
<xs:complexType name="barExt">
<xs:complexContent><xs:extension base="foo"><xs:sequence><xs:element name="b" type="xs:string"/></xs:sequence></xs:extension></xs:complexContent>
</xs:complexType>
<xs:complexType name="barRes">
<xs:complexContent><xs:restriction base="foo"><xs:sequence><xs:element name="a" type="xs:string"/></xs:sequence></xs:restriction></xs:complexContent>
</xs:complexType>
<xs:complexType name="B"><xs:sequence><xs:element name="c1" type="foo"/></xs:sequence></xs:complexType>
<xs:complexType name="R">
<xs:complexContent><xs:restriction base="B"><xs:sequence><xs:element name="c1" type="\(derivedC1Type)"/></xs:sequence></xs:restriction></xs:complexContent>
</xs:complexType>
<xs:element name="doc" type="R"/>
</xs:schema>
"""
return (try? PureXML.Schema.Document(schema)) != nil
}
@Test("restricting an element to a type derived by EXTENSION is rejected (particlesIj008)")
func test_extensionDerivedTypeRejected() {
#expect(!compiles("barExt"))
}
@Test("restricting an element to a type derived by RESTRICTION is accepted")
func test_restrictionDerivedTypeAccepted() {
#expect(compiles("barRes"))
}
@Test("restricting an element to the same type is accepted")
func test_sameTypeAccepted() {
#expect(compiles("foo"))
}
}