PureXML/Tests/TreeNodeIdentityTests.swift

96 lines
4.1 KiB
Swift

@testable import PureXML
import Testing
@Suite("TreeNode DOM identity: structural kinds, ownerDocument, adoption")
struct TreeNodeIdentityTests {
private typealias Tree = PureXML.Model.TreeNode
@Test("Doctype node carries name, identifiers, and internal subset")
func test_doctype() {
let doctype = Tree.doctype(
name: "html",
publicID: "-//W3C//DTD XHTML 1.0//EN",
systemID: "xhtml1.dtd",
internalSubset: "<!ENTITY x \"y\">",
)
#expect(doctype.kind == .doctype)
#expect(doctype.doctypeName == "html")
#expect(doctype.publicID == "-//W3C//DTD XHTML 1.0//EN")
#expect(doctype.systemID == "xhtml1.dtd")
#expect(doctype.internalSubset == "<!ENTITY x \"y\">")
#expect(doctype.stringValue.isEmpty)
}
@Test("A doctype child drops out of the content projection")
func test_doctypeNotProjected() {
let document = Tree.document(children: [
Tree.doctype(name: "html"),
Tree.element("html"),
])
guard case let .document(children) = document.node else { Issue.record("not a document")
return
}
#expect(children.count == 1)
#expect(children.first == .element(.init(name: .init("html"))))
}
@Test("An entity-reference node splices its replacement into the content")
func test_entityReferenceProjection() {
let reference = Tree.entityReference("ref", children: [Tree.element("b"), Tree.text("tail")])
let element = Tree.element("a", children: [Tree.text("head"), reference])
#expect(reference.entityReferenceName == "ref")
#expect(element.stringValue == "headtail")
guard case let .element(projected) = element.node else { Issue.record("not an element")
return
}
#expect(projected.children == [.text("head"), .element(.init(name: .init("b"))), .text("tail")])
}
@Test("A namespace node binds a prefix to a URI")
func test_namespaceNode() {
let bound = Tree.namespace(prefix: "p", uri: "urn:x")
#expect(bound.kind == .namespace)
#expect(bound.namespacePrefix == "p")
#expect(bound.namespaceBinding == "urn:x")
#expect(bound.stringValue == "urn:x")
let defaultNS = Tree.namespace(prefix: "", uri: "urn:d")
#expect(defaultNS.namespacePrefix == nil)
#expect(defaultNS.namespaceBinding == "urn:d")
}
@Test("ownerDocument is the document root, or nil when detached")
func test_ownerDocument() {
let child = Tree.element("b")
let document = Tree.document(children: [Tree.element("a", children: [child])])
#expect(child.ownerDocument === document)
child.removeFromParent()
#expect(child.ownerDocument == nil)
// A subtree not rooted at a document has no owner document.
let loose = Tree.element("a", children: [Tree.element("b")])
#expect(loose.children[0].ownerDocument == nil)
}
@Test("adopt detaches a node and re-declares its inherited namespaces")
func test_adoptRebindsNamespaces() throws {
let source = try PureXML.parseTree("<root xmlns:p=\"urn:x\"><p:child p:k=\"v\"/></root>")
let child = source.children[0].children[0]
#expect(child.attributeValue("xmlns:p") == nil)
let target = Tree.document()
let adopted = target.adopt(child)
#expect(adopted.parent == nil)
// The prefix that was declared on the outer <root> now travels with the node.
#expect(adopted.attributeValue("xmlns:p") == "urn:x")
}
@Test("importNode copies a self-contained subtree without moving the original")
func test_importNode() throws {
let source = try PureXML.parseTree("<root xmlns:p=\"urn:x\"><p:child/></root>")
let child = source.children[0].children[0]
let target = Tree.document()
let imported = target.importNode(child)
#expect(imported !== child)
#expect(child.parent === source.children[0]) // original stays put
#expect(imported.attributeValue("xmlns:p") == "urn:x")
}
}