import Testing
@testable import PureXML
/// The standalone validity constraints (2.9) and the standalone entity WFC:
/// a document declaring standalone='yes' must not depend on declarations in
/// the external subset.
@Suite("Standalone validity")
struct DTDStandaloneTests {
private let externalDTD = """
"""
private func resolver() -> PureXML.Parsing.EntityResolver {
let dtd = externalDTD
return PureXML.Parsing.EntityResolver(
resolveEntity: { _, _ in nil },
resolveExternalSubset: { _ in dtd },
)
}
private func errors(_ xml: String) throws -> [String] {
try PureXML.validateAgainstInternalDTD(xml, resolver: resolver()).map(\.reason)
}
@Test("An externally-declared default firing is a standalone violation")
func test_externalDefault() throws {
let xml = "\n\n"
#expect(try errors(xml).contains { $0.contains("externally-declared default") })
// standalone='no' is fine.
let declared = "\n\n"
#expect(try !errors(declared).contains { $0.contains("externally-declared") })
}
@Test("External normalization needed is a standalone violation, supplied values are fine")
func test_externalNormalization() throws {
let needs = "\n\n"
#expect(try errors(needs).contains { $0.contains("externally-declared normalization") })
let clean = "\n\n"
#expect(try !errors(clean).contains { $0.contains("normalization") })
}
@Test("Whitespace in externally-declared element content is a standalone violation")
func test_externalElementWhitespace() throws {
let xml = "\n\n\n x\n"
#expect(try errors(xml).contains { $0.contains("whitespace in the externally-declared element content") })
}
@Test("Internally-declared attributes do not trip the standalone rules")
func test_internalDeclarationsExempt() throws {
let xml = """
]>
"""
// token is internally redeclared (first wins), so its default and
// normalization are internal facts; only external facts may fire.
#expect(try !errors(xml).contains { $0.contains("'token'") })
}
@Test("A standalone document may not reference an externally-declared entity")
func test_standaloneEntityWFC() {
let xml = "\n\n&outside;"
#expect(throws: PureXML.Parsing.ParseError.self) {
_ = try PureXML.parse(xml, limits: .init(allowDoctype: true), resolver: resolver())
}
// Without standalone the reference resolves.
let loose = "\n&outside;"
#expect((try? PureXML.parse(loose, limits: .init(allowDoctype: true), resolver: resolver())) != nil)
}
}