import Testing @testable import PureXML /// Namespace resolution must not make parsing quadratic in nesting depth (#345). /// Each open element resolves its name against the in-scope bindings; doing that /// by walking a scope stack as deep as the document made parsing O(depth^2). The /// bindings are now maintained incrementally, so a lookup is O(1) and parsing is /// linear. The time limit turns a regression back to quadratic into a failure /// rather than a silent interactive hang: at this depth the old behaviour took /// minutes, the linear one takes well under a second. @Suite("Namespace resolution scale (#345)") struct NamespaceScaleTests { #if os(WASI) @Test("a deeply-nested document parses in linear time") #else @Test("a deeply-nested document parses in linear time", .timeLimit(.minutes(1))) #endif func test_deepNestingParsesLinearly() throws { let depth = 100_000 let xml = String(repeating: "", count: depth) + "leaf" + String(repeating: "", count: depth) let node = try PureXML.parse(xml, limits: .init(maxDepth: depth + 1)) // The parse produced the leaf at the bottom of the nesting. #expect(PureXML.serialize(node, options: .compact).contains("leaf")) } @Test("nested default-namespace bindings still resolve to the nearest in scope") func test_nearestBindingWins() throws { let xml = """ """ let node = try PureXML.parse(xml) guard case let .document(roots) = node, let root = roots.first(where: { $0.element != nil })?.element else { Issue.record("expected a document with a root element") return } #expect(root.name.namespaceURI == "urn:outer") // a let inner = root.children.first(where: { $0.element?.name.localName == "b" })?.element let outerSibling = root.children.first(where: { $0.element?.name.localName == "d" })?.element #expect(inner?.name.namespaceURI == "urn:inner") // b: nearer default binding #expect(inner?.children.first(where: { $0.element?.name.localName == "c" })?.element?.name.namespaceURI == "urn:inner") // c inherits inner #expect(outerSibling?.name.namespaceURI == "urn:outer") // d: inner binding popped, back to outer } }