A non-self-referencing model group redefined inside xs:redefine must be a valid
restriction of the group it redefines (cos-group-restrict / src-redefine 6.1.2),
so its content model may not widen the original's language. The check reuses the
particle-restriction oracle used for complex-type restriction, resolves the
original group by namespaced identity with a {}name chameleon fallback, and runs
post-compile where element type compatibility is available.
Now rejected: adding required content to an empty base (schZ006), dropping a
required all member (schL1), reordering an all (schL5/L6, the Recurse rule is
order-preserving even for all), growing to a superset (schL8), and the
multi-document/chained redefines schN4/5/6/7 and schL10. To stay
false-positive-free the check skips a redefinition carrying a self-reference and
declines to judge a base with a maxOccurs=0 pointless particle (the contested
case W3C accepts, mgO013); genuine restrictions (dropping an optional member, an
unchanged redefinition) are accepted.
XSTS invalid-schemas-accepted 64 -> 51, no false positive (valid-schemas-rejected
and valid-instances-rejected held at 0; an over-rejection of mgO013 surfaced by
the gate was fixed before commit, and an adversarial critic confirmed FP-safety),
no other bucket moved. Disclosed under-rejections: self-referencing redefinitions
(schN10) and maxOccurs=0-base redefines.
128 lines
6.2 KiB
Swift
128 lines
6.2 KiB
Swift
@testable import PureXML
|
|
import Testing
|
|
|
|
/// Configuration-pin tests: every validator variant lists exactly its active rule
|
|
/// descriptions, so adding or rewording a rule fails a test before it is accidental.
|
|
@Suite("Validation configuration pins")
|
|
struct ValidationConfigurationTests {
|
|
@Test("The structural default validator lists its rules")
|
|
func test_structuralDefault() {
|
|
#expect(PureXML.Validation.Validator<Void>().validationDescriptions == [
|
|
"Element attribute names are unique",
|
|
])
|
|
}
|
|
|
|
@Test("The blank validator carries no rules")
|
|
func test_blank() {
|
|
#expect(PureXML.Validation.Validator<Void>.blank.validationDescriptions.isEmpty)
|
|
#expect(PureXML.Validation.Validator<PureXML.Validation.DTDSchema>.blank.validationDescriptions.isEmpty)
|
|
}
|
|
|
|
@Test("The lenient DTD validator lists its non-strict rules in order")
|
|
func test_dtdLenient() {
|
|
let validator = PureXML.Validation.DTD.validator(strict: false)
|
|
#expect(validator.nonReferenceValidationDescriptions == [
|
|
"Element content matches its DTD content model",
|
|
"Required DTD attributes are present",
|
|
"#FIXED DTD attributes hold their fixed value",
|
|
"Enumerated DTD attributes hold a listed value",
|
|
"Tokenized DTD attributes match their declared type",
|
|
"NOTATION DTD attributes name a declared notation",
|
|
"The DTD declarations satisfy their validity constraints",
|
|
"The root element matches the DOCTYPE name",
|
|
"Standalone documents do not depend on external attribute declarations",
|
|
"Standalone documents have no whitespace in externally-declared element content",
|
|
"Parse-time DTD advisories are reviewed",
|
|
])
|
|
#expect(validator.referenceValidationDescriptions == [
|
|
"DTD ID values are unique and IDREFs resolve",
|
|
])
|
|
}
|
|
|
|
@Test("The strict DTD validator appends undeclared element and attribute rules to the reference tier")
|
|
func test_dtdStrict() {
|
|
let validator = PureXML.Validation.DTD.validator(strict: true)
|
|
#expect(validator.referenceValidationDescriptions.suffix(2) == [
|
|
"Element is declared in the DTD",
|
|
"Every attribute is declared in the DTD",
|
|
])
|
|
}
|
|
|
|
@Test("The HTML validator splits local and document-scoped rules across tiers")
|
|
func test_html() {
|
|
let validator = PureXML.Validation.HTML.validator()
|
|
#expect(validator.nonReferenceValidationDescriptions == [
|
|
"Void HTML elements have no content",
|
|
"HTML elements appear inside their required parent",
|
|
])
|
|
#expect(validator.referenceValidationDescriptions == [
|
|
"HTML id attributes are unique",
|
|
])
|
|
}
|
|
|
|
@Test("The XSD instance validator splits content and identity rules across tiers")
|
|
func test_xsdInstance() {
|
|
let validator = PureXML.Validation.XSD.validator()
|
|
#expect(validator.nonReferenceValidationDescriptions == [
|
|
"The document element is valid against its XSD type",
|
|
])
|
|
#expect(validator.referenceValidationDescriptions == [
|
|
"XSD identity constraints hold",
|
|
])
|
|
}
|
|
|
|
@Test("The XSD schema-consistency validator lists named-type rules in tier order")
|
|
func test_xsdSchemaConsistency() {
|
|
let validator = PureXML.Validation.XSDSchema.validator()
|
|
#expect(validator.nonReferenceValidationDescriptions == [
|
|
"A type derives from its base only by methods the base permits",
|
|
])
|
|
#expect(validator.referenceValidationDescriptions == [
|
|
"A restriction's content model accepts a subset of its base's",
|
|
])
|
|
}
|
|
|
|
@Test("The schema compile validators pin their pre and post rule sets")
|
|
func test_schemaCompile() {
|
|
#expect(PureXML.Validation.SchemaCompile.preCompileValidator().validationDescriptions == [
|
|
"Schema component id attributes are valid NCNames and unique",
|
|
"Schema vocabulary elements follow the schema-for-schemas structure",
|
|
"Global schema component names are unique within their symbol spaces",
|
|
"Simple-type final controls are declared consistently",
|
|
"Schema content models are deterministic (UPA)",
|
|
"A resolved schemaLocation reference is a valid schema",
|
|
"A redefined type restricts or extends itself",
|
|
"A redefined group or attribute group has a well-formed self-reference",
|
|
"A redefined attribute group keeps the original's required attributes",
|
|
"Type derivation chains contain no cycles",
|
|
"Schema type references contain no cycles",
|
|
"xs:all group references appear only where permitted",
|
|
"Included schemas are chameleon or match the includer targetNamespace",
|
|
])
|
|
#expect(PureXML.Validation.SchemaCompile.postCompileValidator().validationDescriptions == [
|
|
"Attribute uses are unique and declare at most one ID attribute",
|
|
"An attribute's type is a simple type",
|
|
"ID-typed value constraints are valid",
|
|
"Element value constraints are valid against their declared types",
|
|
"Complex types extending xs:all groups satisfy XSD placement rules",
|
|
"Anonymous complex-type restrictions accept a subset of their base's",
|
|
"A content-model derivation is consistent with its base type",
|
|
"A redefined model group restricts the group it redefines",
|
|
"Attribute restrictions are faithful to their bases",
|
|
"Simple types do not derive from complex types",
|
|
"Simple-type varieties are declared consistently",
|
|
"Notation declarations are valid",
|
|
"Simple-type facets are valid for their base type",
|
|
"Every schema reference resolves to a declared component",
|
|
"Substitution-group members derive correctly from their head",
|
|
])
|
|
}
|
|
|
|
@Test("Every builtin description is unique and pinned")
|
|
func test_builtinRegistry() {
|
|
let descriptions = PureXML.Validation.BuiltinValidation.allDescriptions
|
|
#expect(descriptions.count == Set(descriptions).count)
|
|
#expect(descriptions.count == 24)
|
|
}
|
|
}
|