@testable import PureXML import Testing @Suite("XSD Particle Valid (Restriction)") struct XSDParticleRestrictionTests { private let xsNamespace = "xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"" private func schema(base: String, restriction: String) -> String { """ \(base) \(restriction) """ } private func compiles(base: String, restriction: String) -> Bool { (try? PureXML.Schema.Document(schema(base: base, restriction: restriction))) != nil } private func restrictionError(base: String, restriction: String) -> String? { do { _ = try PureXML.Schema.Document(schema(base: base, restriction: restriction)) return nil } catch let error as PureXML.Schema.SchemaError { return String(describing: error) } catch { return String(describing: error) } } @Test("Valid restrictions compile: drop an optional, narrow a choice, keep order") func test_validRestrictions() { // Dropping an optional element. #expect(compiles( base: "", restriction: "", )) // Narrowing a choice to one branch. #expect(compiles( base: "", restriction: "", )) // Narrowing an occurrence range. #expect(compiles( base: "", restriction: "", )) } @Test("A restriction widening the occurrence range is rejected") func test_wideningOccurrenceRejected() { let error = restrictionError( base: "", restriction: "", ) #expect(error?.contains("not a valid restriction") == true, "\(String(describing: error))") } @Test("A restriction introducing a new element name is rejected") func test_newNameRejected() { let error = restrictionError( base: "", restriction: "", ) #expect(error?.contains("not a valid restriction") == true) } @Test("A restriction reordering a sequence is rejected") func test_reorderRejected() { let error = restrictionError( base: "", restriction: "", ) #expect(error?.contains("not a valid restriction") == true) } @Test("Restricting to empty requires an emptiable base") func test_emptyRestriction() { // Emptiable base: fine. #expect(compiles( base: "", restriction: "", )) // Required base content: rejected. let error = restrictionError( base: "", restriction: "", ) #expect(error?.contains("cannot be EMPTY") == true, "\(String(describing: error))") } @Test("An element restricts a wildcard only when its namespace is admitted") func test_wildcardRestriction() { // ##any admits the unqualified element. #expect(compiles( base: "", restriction: "", )) // ##other refuses an unqualified element. let error = restrictionError( base: "", restriction: "", ) #expect(error?.contains("not a valid restriction") == true) } @Test("Conformance: the restriction corpus passes through the harness") func test_conformanceCases() { let valid = compiles( base: "", restriction: "", ) let invalid = compiles( base: "", restriction: "", ) let cases = [ PureXML.Validation.ConformanceCase(name: "faithful-restriction-accepted", actual: valid ? "valid" : "invalid", expected: "valid"), PureXML.Validation.ConformanceCase(name: "additive-restriction-rejected", actual: invalid ? "valid" : "invalid", expected: "invalid"), ] let failures = PureXML.Validation.Conformance.failures(in: cases) #expect(failures.isEmpty, "\(failures.map(\.reason))") } @Test("NameAndTypeOK: a same-name element must keep a type that derives from the base's") func test_elementTypeDerivation() { // Renaming the element's type to an incompatible one (string -> int) is not a // valid restriction: int does not derive from string. #expect(!compiles( base: "", restriction: "", )) // Narrowing to a derived type (integer -> int) is valid. #expect(compiles( base: "", restriction: "", )) // Keeping the same type is valid. #expect(compiles( base: "", restriction: "", )) } @Test("NameAndTypeOK: widening a concrete-typed element to the ur-type is rejected") func test_elementUrTypeWidening() { // Restricting a string element to anyType/anySimpleType is widening, invalid. #expect(!compiles( base: "", restriction: "", )) #expect(!compiles( base: "", restriction: "", )) // The reverse (base is the ur-type, restriction narrows it) is valid. #expect(compiles( base: "", restriction: "", )) // A user type whose local name is "anyType" (not the XSD ur-type) must not be // mistaken for it: this is a valid same-type restriction. #expect((try? PureXML.Schema.Document(""" """)) != nil) } @Test("NameAndTypeOK over named user and union types") func test_elementUserTypeDerivation() { func doc(_ elementC1: String, base baseC1: String, types: String) -> PureXML.Schema.Document? { try? PureXML.Schema.Document(""" \(types) """) } let userTypes = """ """ // bar restricts foo: a valid narrowing of a user type. #expect(doc("bar", base: "foo", types: userTypes) != nil) // foo restricting bar widens (foo is bar's base): invalid. #expect(doc("foo", base: "bar", types: userTypes) == nil) // two unrelated user types: invalid. #expect(doc("other", base: "foo", types: userTypes) == nil) // a union member (xs:string) validly restricts the union-typed base element. #expect(doc("xs:string", base: "u", types: userTypes) != nil) } }