import Testing @testable import PureXML @Suite("DTD conditional sections, notations, NDATA") struct DTDConditionalNotationTests { private let dtdAllowed = PureXML.Parsing.Limits(allowDoctype: true) private func documentType(_ xml: String, resolver: PureXML.Parsing.EntityResolver = .refusing) throws -> PureXML.Parsing.DocumentType { try PureXML.Parsing.Parser().parseWithDocumentType(xml, limits: dtdAllowed, resolver: resolver).documentType } private func validate(_ xml: String) throws -> [PureXML.Validation.ValidationError] { try PureXML.validateAgainstInternalDTD(xml) } // MARK: Conditional sections @Test("An INCLUDE conditional section's declarations take effect") func test_includeSection() throws { let xml = "]]>]>" let type = try documentType(xml) #expect(type.elementModels["r"] != nil) } @Test("An IGNORE conditional section's declarations are discarded") func test_ignoreSection() throws { let xml = "]]>]>" let type = try documentType(xml) #expect(type.elementModels["r"] == nil) } @Test("A parameter-entity keyword selects the conditional section") func test_conditionalKeywordFromParameterEntity() throws { let xml = "]]>]>" let type = try documentType(xml) #expect(type.elementModels["r"] != nil) } @Test("A nested IGNORE inside an INCLUDE is honored") func test_nestedConditional() throws { let xml = "]]>]]>]>" let type = try documentType(xml) #expect(type.elementModels["r"] != nil) #expect(type.elementModels["skip"] == nil) } // MARK: Notations and NDATA @Test("A declaration is parsed and stored") func test_notationStored() throws { let xml = "]>" let type = try documentType(xml) #expect(type.notations["gif"]?.systemID == "image/gif") } @Test("An NDATA unparsed entity records its notation") func test_unparsedEntity() throws { let xml = "]>" let type = try documentType(xml) #expect(type.unparsedEntities["logo"]?.notation == "gif") #expect(type.unparsedEntities["logo"]?.id.systemID == "l.gif") // An unparsed entity is not a general entity. #expect(type.entities["logo"] == nil) } // MARK: External parameter entities @Test("An external parameter entity is loaded only through a resolver") func test_externalParameterEntity() throws { let xml = "%ext;]>" // Refused by default: the external parameter entity is not loaded. #expect(try documentType(xml).elementModels["r"] == nil) // With a resolver, its declarations take effect. let resolver = PureXML.Parsing.EntityResolver(resolveExternalSubset: { _ in "" }) #expect(try documentType(xml, resolver: resolver).elementModels["r"] != nil) } // MARK: NOTATION attribute validation @Test("A NOTATION attribute value must be a declared, listed notation") func test_notationAttribute() throws { let dtd = "" #expect(try validate("").isEmpty) // A value outside the declaration's list fails. #expect(try !validate("").isEmpty) } @Test("A NOTATION attribute listing an undeclared notation fails") func test_notationAttributeUndeclared() throws { // 'bmp' is listed in the ATTLIST but never declared with . let dtd = "" #expect(try !validate("").isEmpty) } }