PureXML/PublicAPITests/PublicSurfaceTests.swift
Mihaela Mihaljevic 9e345ea0fe feat(xpath,parsing): public streaming surface, linear document-order at scale
EventReader.next(), both initializers, and the Event alias are public
(an internal typealias in a split file had been shadowing the public
Parsing.Event); a new PureXMLPublicAPITests target compiles without
testable import so facade gaps fail CI. The large-corpus benchmarks
exposed document-order sorting as quadratic on flat fan-outs; the fix's
first attempt was itself worse (an eager sibling table built per
predicate evaluation), caught by sampling the live run, and replaced
with a lazy table: single-node sets never touch order keys and a
parent's table builds on its second lookup. XPath at 42 MB drops
27.1 s to 1.57 s (190x to 11.7x); at 210 MB PureXML completes in 9.4 s
the query libxml2 refuses at its 10M node-set cap (#143 tracks our
configurable budget). Benchmark harness: size series to 210 MB, CORPUS
mode for real files (NASA, SwissProt measured), SAX stage,
refusal-aware table, NULL-safe C driver. All conformance suites,
Linux, and WASM verified. Closes #142.
2026-06-11 06:06:31 +02:00

52 lines
2.0 KiB
Swift

// Deliberately NOT @testable: these tests compile against the public
// surface exactly as an external package would, so a public facade over
// internal members (the #142 class of gap: a public EventReader whose
// next() was internal) fails CI instead of hiding behind testability.
import PureXML
import Testing
@Suite("Public API surface")
struct PublicSurfaceTests {
@Test("Parse, query, and serialize work through the public surface")
func test_parseQuerySerialize() throws {
let document = try PureXML.parse("<r><a k=\"v\">x</a><a>y</a></r>")
let query = try PureXML.XPath.Query("count(//a)")
#expect(try query.number(over: document) == 2)
#expect(PureXML.serialize(document).contains("<a k=\"v\">x</a>"))
}
@Test("The streaming reader pulls events publicly, bounded memory")
func test_streamingPull() throws {
var reader = PureXML.events("<r><a>x</a><!--c--></r>")
var names: [String] = []
var texts: [String] = []
var comments = 0
while let event = try reader.next() {
switch event {
case let .startElement(name, _): names.append(name.description)
case let .characters(text): texts.append(text)
case .comment: comments += 1
default: break
}
}
#expect(names == ["r", "a"])
#expect(texts == ["x"])
#expect(comments == 1)
}
@Test("The streaming reader accepts a chunked pull source")
func test_streamingFromChunks() throws {
var chunks = ["<r><a>", "hello", "</a></r>"].makeIterator()
var characters: [Character] = []
var reader = PureXML.Parsing.EventReader(pulling: {
if characters.isEmpty, let chunk = chunks.next() { characters = Array(chunk) }
return characters.isEmpty ? nil : characters.removeFirst()
})
var events = 0
while try reader.next() != nil {
events += 1
}
#expect(events == 5)
}
}