use std::borrow::ToOwned;
use sxd_document::{dom, parser};
use sxd_xpath::{context, function, nodeset};
use sxd_xpath::{evaluate_xpath, Context, Factory, Value};
#[test]
fn functions_accept_arguments() {
with_document("", |doc| {
let result = evaluate_xpath(&doc, "concat('hello', ' ', 'world')");
assert_eq!(Ok(Value::String("hello world".to_owned())), result);
});
}
#[test]
fn functions_implicitly_coerce_argument_types() {
with_document("true", |doc| {
// We are searching a nodeset for a boolean. Both should be
// converted to strings by `contains`.
let result = evaluate_xpath(&doc, "count(//*[contains(., true)])");
assert_eq!(Ok(Value::Number(1.0)), result);
});
}
#[test]
fn axis_predicate_order() {
with_document("", |doc| {
// All the `c` elements that are the first child
let result = evaluate_xpath(&doc, "//c[1]");
let a = doc.root().children()[0].element().expect("No element a");
let b0 = a.children()[0].element().expect("No element b0");
let b1 = a.children()[1].element().expect("No element b1");
let c0 = b0.children()[0].element().expect("No element c0");
let c1 = b1.children()[0].element().expect("No element c1");
assert_eq!(Ok(Value::Nodeset(nodeset![c0, c1])), result);
});
}
#[test]
fn position_function_in_predicate() {
with_document("", |doc| {
let result = evaluate_xpath(&doc, "count(//a/*[position() = 2])");
assert_eq!(Ok(Value::Number(1.0)), result);
});
}
#[test]
fn variables_with_qualified_names() {
with_document("", |doc| {
let mut setup = Setup::new();
setup.context.set_variable(("uri:namespace", "name"), 42.0);
setup.context.set_namespace("prefix", "uri:namespace");
let result = setup.evaluate(&doc, "$prefix:name");
assert_eq!(42.0, result);
});
}
#[test]
fn functions_with_qualified_names() {
with_document("", |doc| {
let mut setup = Setup::new();
setup
.context
.set_function(("uri:namespace", "constant"), ConstantValueFunction(42.0));
setup.context.set_namespace("prefix", "uri:namespace");
let result = setup.evaluate(&doc, "prefix:constant()");
assert_eq!(42.0, result);
});
}
#[test]
fn nodesets_are_unique() {
with_document("", |doc| {
let result = evaluate_xpath(&doc, "/ | /");
assert_eq!(Ok(Value::Nodeset(nodeset![doc.root()])), result);
});
}
fn with_document(xml: &str, f: F)
where
F: FnOnce(dom::Document<'_>),
{
let package = parser::parse(xml).expect("Unable to parse test XML");
f(package.as_document());
}
#[derive(Default)]
struct Setup<'d> {
context: Context<'d>,
factory: Factory,
}
impl<'d> Setup<'d> {
fn new() -> Setup<'d> {
Default::default()
}
fn evaluate(&self, doc: &'d dom::Document<'d>, xpath: &str) -> Value<'d> {
let xpath = self.factory.build(xpath).expect("Unable to build XPath");
xpath
.evaluate(&self.context, doc.root())
.expect("Unable to evaluate XPath")
}
}
struct ConstantValueFunction(f64);
impl function::Function for ConstantValueFunction {
fn evaluate<'c, 'd>(
&self,
_context: &context::Evaluation<'c, 'd>,
_args: Vec>,
) -> Result, function::Error> {
Ok(Value::Number(self.0))
}
}