test(dtd): verify parameter-entity and external-subset depth
Add depth tests confirming the existing DTD machinery handles parameter entities within element-model and attribute-list declarations, deep (5-level) PE composition, and an external subset that itself loads a further external parameter entity through the resolver. The Tier-3 DTD PE / external-subset depth item was already implemented; these lock it to full depth. (The XML 1.0 PE-reference spacing rule, leading/trailing space on DTD-content inclusion, remains a known minor non-conformance.) Part of #105 (Tier 3)
This commit is contained in:
parent
69678d31a1
commit
f29deec723
@ -88,7 +88,7 @@ flowchart TB
|
||||
OutEnc["#106 output encodings: complete"]:::done
|
||||
StreamVal["#107 streaming validation: DTD, RELAX NG, XSD"]:::done
|
||||
MoreEnc["#108 encodings: ISO-2022-JP, EUC-TW"]:::done
|
||||
Depth["Tier 2 conformance corpora; Tier 3 DTD PE depth (C14N 1.1, EXSLT done); frontier #104"]:::todo
|
||||
Depth["Tier 3 done (C14N 1.1, EXSLT, DTD PE depth); Tier 2 conformance corpora; frontier #104"]:::todo
|
||||
Epic105 --> OutEnc
|
||||
OutEnc --> StreamVal
|
||||
StreamVal --> MoreEnc
|
||||
@ -99,7 +99,7 @@ flowchart TB
|
||||
|
||||
PureXML is a working, dependency-free XML library today: parse, emit, validate,
|
||||
query, and stream documents on macOS, Linux, Windows, and WASM. The test suite
|
||||
currently runs **801 tests in 123 suites** (`swift test`).
|
||||
currently runs **805 tests in 124 suites** (`swift test`).
|
||||
|
||||
### Shipped (libxml2-aligned surface)
|
||||
|
||||
|
||||
61
Tests/DTDParameterEntityDepthTests.swift
Normal file
61
Tests/DTDParameterEntityDepthTests.swift
Normal file
@ -0,0 +1,61 @@
|
||||
@testable import PureXML
|
||||
import Testing
|
||||
|
||||
@Suite("DTD parameter-entity and external-subset depth")
|
||||
struct DTDParameterEntityDepthTests {
|
||||
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 rootText(_ node: PureXML.Model.Node) -> String {
|
||||
guard case let .document(children) = node else { return "" }
|
||||
for case let .element(element) in children {
|
||||
return element.text
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
@Test("A parameter entity expands within an element-model declaration")
|
||||
func test_parameterEntityInElementModel() throws {
|
||||
let dtd = try documentType("<!DOCTYPE r [<!ENTITY % m \"(a|b)\"><!ELEMENT r %m;>]><r/>")
|
||||
#expect(dtd.elementModels["r"] == "(a|b)")
|
||||
}
|
||||
|
||||
@Test("A parameter entity expands within an attribute-list declaration")
|
||||
func test_parameterEntityInAttlist() throws {
|
||||
let xml = "<!DOCTYPE r [<!ELEMENT r EMPTY><!ENTITY % atts \"code CDATA #REQUIRED\"><!ATTLIST r %atts;>]><r/>"
|
||||
// The attribute is declared via the PE, so a missing required code is caught.
|
||||
let errors = try PureXML.validateAgainstInternalDTD(xml)
|
||||
#expect(errors.contains { $0.reason.contains("code") })
|
||||
}
|
||||
|
||||
@Test("Deeply nested parameter entities compose fully")
|
||||
func test_deepNesting() throws {
|
||||
let xml = """
|
||||
<!DOCTYPE r [
|
||||
<!ENTITY % a "1">
|
||||
<!ENTITY % b "%a;2">
|
||||
<!ENTITY % c "%b;3">
|
||||
<!ENTITY % d "%c;4">
|
||||
<!ENTITY e "%d;5">
|
||||
]><r>&e;</r>
|
||||
"""
|
||||
try #expect(rootText(PureXML.parse(xml, limits: dtdAllowed)) == "12345")
|
||||
}
|
||||
|
||||
@Test("An external subset can itself load a further external parameter entity")
|
||||
func test_recursiveExternalLoading() throws {
|
||||
let resolver = PureXML.Parsing.EntityResolver(resolveExternalSubset: { id in
|
||||
switch id.systemID {
|
||||
case "a.dtd": "<!ENTITY % inner SYSTEM \"b.dtd\">%inner;<!ELEMENT r (#PCDATA)>"
|
||||
case "b.dtd": "<!ENTITY deep \"found\">"
|
||||
default: nil
|
||||
}
|
||||
})
|
||||
let xml = "<!DOCTYPE r [<!ENTITY % ext SYSTEM \"a.dtd\">%ext;]><r>&deep;</r>"
|
||||
let node = try PureXML.parse(xml, limits: dtdAllowed, resolver: resolver)
|
||||
#expect(rootText(node) == "found")
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user