The two monolithic XSD content/identity rules only satisfied the OpenAPIKit validation idiom at the wrong granularity: no per-constraint removability, no isolable failing/near-miss tests. Split them into 32 named rules, each finding tagged at its origin and cached per XSDContext so the walk still runs once per document (the #101 decision against duplicating XSD's recursive type resolution still holds). Wired the streaming path's ID/IDREF and identity checks through the same framework instead of calling the validators imperatively, and added the unwrapAndLookup combinator the rule already named as required. Also includes the mandated repo-wide swiftformat/swiftlint pass.
161 lines
8.5 KiB
Swift
161 lines
8.5 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 == [
|
|
"An element carries xsi:nil only when it is declared nillable",
|
|
"A nilled element has no content",
|
|
"A nilled element carries no fixed value constraint",
|
|
"A fixed element has no element children",
|
|
"A fixed element's content equals its fixed value",
|
|
"An empty-content element has no element children",
|
|
"A simple-content element has no element children",
|
|
"A simple-content element's text is valid against its type",
|
|
"An element-only or empty-content element carries no text",
|
|
"A strict wildcard-matched element has a global declaration",
|
|
"A simple-typed element carries only schema-instance and namespace attributes",
|
|
"A simple-typed element has no element children",
|
|
"A simple-typed element's value is valid against its type",
|
|
"A type reference resolves to a known, non-circular type",
|
|
"An element's children conform to its content model",
|
|
"A declared attribute's value is valid against its type",
|
|
"A declared attribute's value equals its fixed value",
|
|
"A required attribute is present",
|
|
"An element carries at most one attribute of type ID",
|
|
"An attribute is declared or permitted by a wildcard",
|
|
"A strict wildcard-matched attribute has a global declaration",
|
|
"A wildcard-matched attribute's value is valid against its type",
|
|
"A wildcard-matched attribute's value equals its fixed value",
|
|
"An xsi:type substitution is validly derived and not blocked",
|
|
"An xsi:type override names a known, validly derived type",
|
|
"Every xs:ID is unique and every xs:IDREF resolves to one",
|
|
])
|
|
#expect(validator.referenceValidationDescriptions == [
|
|
"An identity constraint's selector and field XPaths compile",
|
|
"A key constraint's fields are all present",
|
|
"A key or unique constraint's values are distinct",
|
|
"A keyref constraint's value matches a key or unique in scope",
|
|
"An identity constraint field selects at most one node",
|
|
"An identity constraint field identifies a node with simple content",
|
|
])
|
|
}
|
|
|
|
@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",
|
|
"Attribute wildcard unions in type extensions are expressible",
|
|
"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 == 55)
|
|
}
|
|
}
|