PureXML/Tests/ValidationConfigurationTests.swift
Mihaela Mihaljevic 1c836d50f2 fix(schema): reject global form in included/imported documents
The top-level declaration constraints (a global element/attribute may not carry
the local-only form/use/ref/minOccurs/maxOccurs; a global definition needs a
name) apply to every document in a schema composition, but the existing check
ran only over the document being compiled. A violation inside an xs:include,
xs:import, or xs:redefine target was therefore missed and the composed schema
wrongly accepted. The same global-component check now runs over the other
schema-document roots in the composition (the main document is excluded as
already covered; redefine entries are skipped because each schema root walks its
own redefine children). The constraint is absolute and position-independent, so
no valid schema is newly rejected; libxml2 rejects both cases for the same
reason. Catches attQ016 (import) and attQ018 (include). XSTS invalid-schemas-
accepted 20 to 18, valid-schemas-rejected held at 0.
2026-06-22 17:50:53 +02:00

130 lines
6.4 KiB
Swift

import Testing
@testable import PureXML
/// 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",
"Top-level declarations in included or imported documents follow the global-component constraints",
"Global schema component names are unique within their symbol spaces",
"Simple-type final controls are declared consistently",
"Schema content models are deterministic (UPA)",
"Attribute declarations are not in the XSI namespace",
"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)
}
}