import Testing @testable import PureXML @Suite("DTD validation") struct DTDValidationTests { private func issues(_ xml: String, strict: Bool = false) throws -> [PureXML.Validation.ValidationError] { try PureXML.validateAgainstInternalDTD(xml, strict: strict) } @Test("EMPTY element accepts no content and rejects content") func test_empty() throws { try #expect(issues("]>").isEmpty) try #expect(!issues("]>x").isEmpty) try #expect(!issues("]>").isEmpty) } @Test("(#PCDATA) accepts text and rejects child elements") func test_pcdata() throws { try #expect(issues("]>hello").isEmpty) try #expect(!issues("]>").isEmpty) } @Test("Sequence content model enforces order and presence") func test_sequence() throws { let dtd = "]>" try #expect(issues("\(dtd)").isEmpty) try #expect(!issues("\(dtd)").isEmpty) try #expect(!issues("\(dtd)").isEmpty) } @Test("Choice content model accepts exactly one alternative") func test_choice() throws { let dtd = "]>" try #expect(issues("\(dtd)").isEmpty) try #expect(issues("\(dtd)").isEmpty) try #expect(!issues("\(dtd)").isEmpty) } @Test("Occurrence indicators bound repetition") func test_occurrence() throws { let star = "]>" try #expect(issues("\(star)").isEmpty) try #expect(issues("\(star)").isEmpty) let plus = "]>" try #expect(!issues("\(plus)").isEmpty) let optional = "]>" try #expect(issues("\(optional)").isEmpty) } @Test("Mixed content allows only the declared elements") func test_mixed() throws { let dtd = "]>" try #expect(issues("\(dtd)textmore").isEmpty) try #expect(!issues("\(dtd)").isEmpty) } @Test("Element content rejects character data") func test_elementContentRejectsText() throws { let dtd = "]>" try #expect(!issues("\(dtd)text").isEmpty) } @Test("Strict mode rejects undeclared elements") func test_strictUndeclared() throws { let dtd = "]>" try #expect(issues("\(dtd)", strict: false).isEmpty) try #expect(!issues("\(dtd)", strict: true).isEmpty) } @Test("A document without a DTD reports no content-model issues") func test_noDTD() throws { try #expect(issues("").isEmpty) } @Test("A content-model violation is located by coding path") func test_violationCarriesPath() throws { let dtd = "]>" let found = try issues("\(dtd)oops") #expect(found.count == 1) #expect(String(describing: found[0]) == "element is declared EMPTY but has content at path: r/a") } }