PureXML/Tests/ValidationRuleRegistryTests.swift
Mihaela Mihaljevic 380160cc2b refactor(validation): decompose XSD instance validation into composable rules
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.
2026-07-12 14:12:17 +02:00

84 lines
7.1 KiB
Swift

import Testing
@testable import PureXML
/// Meta-tests for validation-rules.md exhaustive coverage: every shipped builtin
/// rule must have a fail and a near-miss succeed isolation test in
/// ``ValidationRule*Tests`` suites (update ``pairs`` when adding a rule or test).
@Suite("Validation rule registry")
struct ValidationRuleRegistryTests {
private typealias RuleTestPair = (fail: String, succeed: String)
/// Maps each ``BuiltinValidation/allRuleIDs`` entry to its isolation test names.
private static let pairs: [String: RuleTestPair] = [
"uniqueAttributes": ("test_uniqueAttributes", "test_uniqueAttributes_succeeds"),
"dtdContentModel": ("test_contentModel", "test_dtdContentModel_succeeds"),
"dtdRequiredAttributes": ("test_requiredAttributes", "test_dtdRequiredAttributes_succeeds"),
"dtdFixedAttributeValues": ("test_fixedAttributeValues", "test_dtdFixedAttributeValues_succeeds"),
"dtdEnumeratedAttributeValues": ("test_enumeratedAttributeValues", "test_dtdEnumeratedAttributeValues_succeeds"),
"dtdTokenizedAttributeTypes": ("test_tokenizedAttributeTypes", "test_dtdTokenizedAttributeTypes_succeeds"),
"dtdNotationAttributes": ("test_notationAttributes", "test_dtdNotationAttributes_succeeds"),
"dtdUndeclaredElement": ("test_undeclaredElement", "test_dtdUndeclaredElement_succeeds"),
"dtdUndeclaredAttributes": ("test_dtdUndeclaredAttributes", "test_dtdUndeclaredAttributes_succeeds"),
"dtdDeclarationValidity": ("test_dtdDeclarationValidity", "test_dtdDeclarationValidity_succeeds"),
"dtdRootElementType": ("test_dtdRootElementType", "test_dtdRootElementType_succeeds"),
"dtdIdentifierIntegrity": ("test_identifierIntegrity", "test_dtdIdentifierIntegrity_succeeds"),
"dtdStandaloneAttributes": ("test_dtdStandaloneAttributes", "test_dtdStandaloneAttributes_succeeds"),
"dtdStandaloneElementWhitespace": ("test_dtdStandaloneElementWhitespace", "test_dtdStandaloneElementWhitespace_succeeds"),
"dtdParseAdvisories": ("test_dtdParseAdvisories", "test_dtdParseAdvisories_succeeds"),
"htmlVoidElementsAreEmpty": ("test_htmlVoidElementsAreEmpty", "test_htmlVoidElementsAreEmpty_succeeds"),
"htmlRequiredParent": ("test_htmlRequiredParent", "test_htmlRequiredParent_succeeds"),
"htmlUniqueIdentifiers": ("test_htmlUniqueIdentifiers", "test_htmlUniqueIdentifiers_succeeds"),
"xsdNilAttributeRequiresNillable": ("test_nilAttributeRequiresNillable", "test_nilAttributeRequiresNillable_succeeds"),
"xsdNilElementMustBeEmpty": ("test_nilElementMustBeEmpty", "test_nilElementMustBeEmpty_succeeds"),
"xsdNilElementNoFixedConstraint": ("test_nilElementNoFixedConstraint", "test_nilElementNoFixedConstraint_succeeds"),
"xsdFixedElementNoChildren": ("test_fixedElementNoChildren", "test_fixedElementNoChildren_succeeds"),
"xsdFixedElementValueMatches": ("test_fixedElementValueMatches", "test_fixedElementValueMatches_succeeds"),
"xsdEmptyContentForbidsChildren": ("test_emptyContentForbidsChildren", "test_emptyContentForbidsChildren_succeeds"),
"xsdSimpleContentForbidsChildren": ("test_simpleContentForbidsChildren", "test_simpleContentForbidsChildren_succeeds"),
"xsdSimpleContentTypeValid": ("test_simpleContentTypeValid", "test_simpleContentTypeValid_succeeds"),
"xsdTextForbidden": ("test_textForbidden", "test_textForbidden_succeeds"),
"xsdWildcardElementUndeclared": ("test_wildcardElementUndeclared", "test_wildcardElementUndeclared_succeeds"),
"xsdSimpleTypeDisallowedAttribute": ("test_simpleTypeDisallowedAttribute", "test_simpleTypeDisallowedAttribute_succeeds"),
"xsdSimpleTypeForbidsChildren": ("test_simpleTypeForbidsChildren", "test_simpleTypeForbidsChildren_succeeds"),
"xsdSimpleTypeValueValid": ("test_simpleTypeValueValid", "test_simpleTypeValueValid_succeeds"),
"xsdTypeReferenceResolves": ("test_typeReferenceResolves", "test_typeReferenceResolves_succeeds"),
"xsdContentModelStructure": ("test_contentModelStructure", "test_contentModelStructure_succeeds"),
"xsdAttributeTypeValid": ("test_attributeTypeValid", "test_attributeTypeValid_succeeds"),
"xsdAttributeFixedMatches": ("test_attributeFixedMatches", "test_attributeFixedMatches_succeeds"),
"xsdAttributeRequiredPresent": ("test_attributeRequiredPresent", "test_attributeRequiredPresent_succeeds"),
"xsdAttributeSingleID": ("test_attributeSingleID", "test_attributeSingleID_succeeds"),
"xsdAttributeDeclaredOrPermitted": ("test_attributeDeclaredOrPermitted", "test_attributeDeclaredOrPermitted_succeeds"),
"xsdWildcardAttributeUndeclared": ("test_wildcardAttributeUndeclared", "test_wildcardAttributeUndeclared_succeeds"),
"xsdWildcardAttributeTypeValid": ("test_wildcardAttributeTypeValid", "test_wildcardAttributeTypeValid_succeeds"),
"xsdWildcardAttributeFixedMatches": ("test_wildcardAttributeFixedMatches", "test_wildcardAttributeFixedMatches_succeeds"),
"xsdXsiTypeSubstitutionValid": ("test_xsiTypeSubstitutionValid", "test_xsiTypeSubstitutionValid_succeeds"),
"xsdXsiTypeOverrideResolves": ("test_xsiTypeOverrideResolves", "test_xsiTypeOverrideResolves_succeeds"),
"xsdIdIdrefConsistent": ("test_idIdrefConsistent", "test_idIdrefConsistent_succeeds"),
"xsdIdentityConstraintXPathsValid": ("test_identityConstraintXPathsValid", "test_identityConstraintXPathsValid_succeeds"),
"xsdIdentityKeyFieldPresent": ("test_identityKeyFieldPresent", "test_identityKeyFieldPresent_succeeds"),
"xsdIdentityValueUnique": ("test_identityValueUnique", "test_identityValueUnique_succeeds"),
"xsdIdentityKeyrefResolves": ("test_identityKeyrefResolves", "test_identityKeyrefResolves_succeeds"),
"xsdIdentityFieldCardinality": ("test_identityFieldCardinality", "test_identityFieldCardinality_succeeds"),
"xsdIdentityFieldMustBeSimple": ("test_identityFieldMustBeSimple", "test_identityFieldMustBeSimple_succeeds"),
"xsdFinalRespected": ("test_xsdFinalRespected", "test_xsdFinalRespected_succeeds"),
"xsdRestrictionsAreSubsets": ("test_xsdRestrictionsAreSubsets", "test_xsdRestrictionsAreSubsets_succeeds"),
"conformanceMatchesExpected": ("test_conformanceMatchesExpected", "test_conformanceMatchesExpected_succeeds"),
"xsdStreamingShallowValidity": ("test_xsdStreamingShallowValidity", "test_xsdStreamingShallowValidity_succeeds"),
"xsdStreamingIdConsistency": ("test_xsdStreamingIdConsistency", "test_xsdStreamingIdConsistency_succeeds"),
]
@Test("Every builtin rule id has a fail and succeed test registered")
func test_allRulesPaired() {
let ids = PureXML.Validation.BuiltinValidation.allRuleIDs
#expect(Set(Self.pairs.keys) == Set(ids), "pairs keys must match allRuleIDs")
#expect(ids.count == 55)
}
@Test("Builtin descriptions stay unique")
func test_descriptionsUnique() {
let all = PureXML.Validation.BuiltinValidation.allDescriptions
#expect(all.count == Set(all).count)
#expect(all.count == PureXML.Validation.BuiltinValidation.allRuleIDs.count)
}
}