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)) } }