import Testing
@testable import PureXML
@Suite("EXSLT functions: common, math, sets")
struct EXSLTTests {
private let namespaces = [
"exsl": PureXML.XPath.EXSLT.common,
"math": PureXML.XPath.EXSLT.math,
"set": PureXML.XPath.EXSLT.sets,
]
private func value(_ expression: String, _ xml: String) throws -> PureXML.XPath.Value {
let document = try PureXML.parseTree(xml)
return try PureXML.XPath.Query(expression).value(at: document, namespaces: namespaces)
}
@Test("math:min, max, abs, sqrt")
func test_mathScalars() throws {
let numbers = "312"
try #expect(value("math:max(//n)", numbers).number == 3)
try #expect(value("math:min(//n)", numbers).number == 1)
try #expect(value("math:abs(-5)", numbers).number == 5)
try #expect(value("math:sqrt(9)", numbers).number == 3)
// A non-numeric node makes min/max NaN (the EXSLT rule).
try #expect(value("math:max(//n)", "3x").number.isNaN)
}
@Test("math:highest and math:lowest return the extreme nodes")
func test_mathNodes() throws {
let numbers = "313"
// Two nodes share the maximum value 3.
try #expect(value("math:highest(//n)", numbers).nodes?.count == 2)
try #expect(value("math:lowest(//n)", numbers).nodes?.count == 1)
try #expect(value("math:lowest(//n)", numbers).string == "1")
}
@Test("set:distinct, difference, intersection, has-same-node")
func test_sets() throws {
let values = "xxy"
try #expect(value("count(set:distinct(//n))", values).number == 2)
let abc = ""
try #expect(value("count(set:difference(//r/*, //b))", abc).number == 2) // a, c
try #expect(value("count(set:intersection(//r/*, //b))", abc).number == 1) // b
try #expect(value("set:has-same-node(//a, //r/*)", abc).boolean == true)
try #expect(value("set:has-same-node(//a, //b)", abc).boolean == false)
}
@Test("set:leading and set:trailing relative to the first node of the second set")
func test_setsRelative() throws {
let abc = ""
// Of a, b, c, those before b are [a]; those after b are [c].
try #expect(value("count(set:leading(//r/*, //b))", abc).number == 1)
try #expect(value("count(set:trailing(//r/*, //b))", abc).number == 1)
try #expect(value("local-name(set:trailing(//r/*, //b))", abc).string == "c")
}
@Test("exsl:object-type reports the value type")
func test_objectType() throws {
let doc = ""
try #expect(value("exsl:object-type(/r)", doc).string == "node-set")
try #expect(value("exsl:object-type(1)", doc).string == "number")
try #expect(value("exsl:object-type('s')", doc).string == "string")
try #expect(value("exsl:object-type(true())", doc).string == "boolean")
}
@Test("An EXSLT function under an unbound prefix is an unknown function")
func test_unboundPrefix() throws {
#expect(throws: (any Error).self) {
_ = try PureXML.XPath.Query("math:max(//n)").value(at: PureXML.parseTree("1"))
}
}
}