//! Tests for XSLT defined generically use pkg_version::{pkg_version_major, pkg_version_minor, pkg_version_patch}; use std::rc::Rc; use url::Url; use xrust::item::{Item, Node, Sequence, SequenceTrait}; use xrust::namespace::NamespaceMap; use xrust::transform::context::StaticContextBuilder; use xrust::xdmerror::{Error, ErrorKind}; use xrust::xslt::from_document; fn test_rig( src: impl AsRef, style: impl AsRef, parse_from_str: G, _parse_from_str_with_ns: J, make_doc: H, ) -> Result, Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let srcdoc = parse_from_str(src.as_ref()).map_err(|e| { Error::new( e.kind, format!("error parsing source document: {}", e.message), ) })?; let styledoc = parse_from_str(style.as_ref()) .map_err(|e| Error::new(e.kind, format!("error parsing stylesheet: {}", e.message)))?; let mut stctxt = StaticContextBuilder::new() .message(|_| Ok(())) .fetcher(|_| Err(Error::new(ErrorKind::NotImplemented, "not implemented"))) .parser(|_| Err(Error::new(ErrorKind::NotImplemented, "not implemented"))) .build(); let mut ctxt = from_document(styledoc, None, |s| parse_from_str(s), |_| Ok(String::new()))?; ctxt.context(vec![Item::Node(srcdoc.clone())], 0); ctxt.result_document(make_doc()?); ctxt.populate_key_values(&mut stctxt, srcdoc.clone())?; ctxt.evaluate(&mut stctxt) } fn test_msg_rig( src: impl AsRef, style: impl AsRef, parse_from_str: G, _parse_from_str_with_ns: J, make_doc: H, ) -> Result<(Sequence, Vec), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let srcdoc = parse_from_str(src.as_ref())?; let styledoc = parse_from_str(style.as_ref())?; let mut msgs: Vec = vec![]; let mut stctxt = StaticContextBuilder::new() .message(|m| { msgs.push(String::from(m)); Ok(()) }) .fetcher(|_| Err(Error::new(ErrorKind::NotImplemented, "not implemented"))) .parser(|_| Err(Error::new(ErrorKind::NotImplemented, "not implemented"))) .build(); let mut ctxt = from_document(styledoc, None, |s| parse_from_str(s), |_| Ok(String::new()))?; ctxt.context(vec![Item::Node(srcdoc.clone())], 0); ctxt.result_document(make_doc()?); let seq = ctxt.evaluate(&mut stctxt)?; Ok((seq, msgs)) } pub fn generic_literal_text( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "onetwo", r#" Found the document "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; if result.to_string() == "Found the document" { Ok(()) } else { Err(Error::new( ErrorKind::Unknown, format!( "got result \"{}\", expected \"Found the document\"", result.to_string() ), )) } } pub fn generic_sys_prop( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "onetwo", r#" - "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; if result.to_string() == format!( "0.9-{}.{}.{}", pkg_version_major!(), pkg_version_minor!(), pkg_version_patch!() ) { Ok(()) } else { Err(Error::new( ErrorKind::Unknown, format!( "got result \"{}\", expected \"{}\"", result.to_string(), format!( "0.9-{}.{}.{}", pkg_version_major!(), pkg_version_minor!(), pkg_version_patch!() ) ), )) } } pub fn generic_value_of_1( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "special < less than", r#" "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; if result.to_string() == "special < less than" { Ok(()) } else { Err(Error::new( ErrorKind::Unknown, format!( "got result \"{}\", expected \"special < less than\"", result.to_string() ), )) } } pub fn generic_value_of_2( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "special < less than", r#" "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; if result.to_string() == "special < less than" { Ok(()) } else { Err(Error::new( ErrorKind::Unknown, format!( "got result \"{}\", expected \"special < less than\"", result.to_string() ), )) } } pub fn generic_literal_element( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "onetwo", r#" Made an element "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; if result.to_xml() == "Made an element" { Ok(()) } else { Err(Error::new( ErrorKind::Unknown, format!( "got result \"{}\", expected \"Made an element\"", result.to_string() ), )) } } pub fn generic_element( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "onetwo", r#" Made an element "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; if result.to_xml() == "Made an element" { Ok(()) } else { Err(Error::new( ErrorKind::Unknown, format!( "got result \"{}\", expected \"Made an element\"", result.to_string() ), )) } } pub fn generic_apply_templates_1( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "onetwo", r#" found text "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; if result.to_xml() == "found textfound text" { Ok(()) } else { Err(Error::new( ErrorKind::Unknown, format!( "got result \"{}\", expected \"found textfound text\"", result.to_string() ), )) } } pub fn generic_apply_templates_2( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "onetwothreefour", r#" found Level1 element "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; if result.to_xml() == "onetwothreefour" { Ok(()) } else { Err(Error::new( ErrorKind::Unknown, format!( "got result \"{}\", expected \"onetwothreefour\"", result.to_string() ), )) } } pub fn generic_apply_templates_mode( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "oneatwobthreecfourd", r#"

should not see this
"#, parse_from_str, parse_from_str_with_ns, make_doc, )?; if result.to_xml() == "

a

b

c

d

a

b

c

d

" { Ok(()) } else { Err(Error::new( ErrorKind::Unknown, format!( "got result \"{}\", expected \"

a

b

c

d

a

b

c

d

\"", result.to_xml() ), )) } } pub fn generic_apply_templates_sort( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "oneatwobthreecfourd", r#"

"#, parse_from_str, parse_from_str_with_ns, make_doc, )?; if result.to_xml() == "abcd

four

one

three

two

" { Ok(()) } else { Err(Error::new( ErrorKind::Unknown, format!( "got result \"{}\", expected \"abcd

four

one

three

two

\"", result.to_xml() ), )) } } pub fn generic_comment( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "onetwothreefour", r#" this is a level 1 element "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; if result.to_xml() == "onetwothreefour" { Ok(()) } else { Err(Error::new(ErrorKind::Unknown, format!("got result \"{}\", expected \"onetwothreefour\"", result.to_string()))) } } pub fn generic_pi( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "onetwothreefour", r#" this is a level 1 element "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; if result.to_xml() == "onetwothreefour" { Ok(()) } else { Err(Error::new(ErrorKind::Unknown, format!("got result \"{}\", expected \"onetwothreefour\"", result.to_string()))) } } pub fn generic_current( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "I am fooI am one", r#" "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; if result.to_xml() == "I am one" { Ok(()) } else { Err(Error::new( ErrorKind::Unknown, format!( "got result \"{}\", expected \"I am one\"", result.to_string() ), )) } } pub fn generic_key_1( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "blueyellowgreenblue", r#" #blue = shouldn't see this "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; if result.to_xml() == "#blue = 2" { Ok(()) } else { Err(Error::new( ErrorKind::Unknown, format!( "got result \"{}\", expected \"#blue = 2\"", result.to_string() ), )) } } // Although we have the source and stylesheet in files, // they are inlined here to avoid dependency on I/O libraries pub fn generic_issue_58( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( r#" XSLT in Rust A simple document. "#, r#" "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; if result.to_xml() == r#" XSLT in Rust A simple document. "# { Ok(()) } else { Err(Error::new( ErrorKind::Unknown, format!("not expected result"), )) } } pub fn generic_message_1( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let (result, msgs) = test_msg_rig( "onetwothreefour", r#" here is a level 1 element "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; if result.to_xml() == "onetwothreefour" { if msgs.len() == 4 { if msgs[0] == "here is a level 1 element" { Ok(()) } else { Err(Error::new( ErrorKind::Unknown, format!( "got message \"{}\", expected \"here is a level 1 element\"", msgs[0] ), )) } } else { Err(Error::new( ErrorKind::Unknown, format!("got {} messages, expected 4", msgs.len()), )) } } else { Err(Error::new( ErrorKind::Unknown, format!( "got result \"{}\", expected \"onetwothreefour\"", result.to_string() ), )) } } pub fn generic_message_term( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { match test_msg_rig( "onetwothreefour", r#" here is a level 1 element "#, parse_from_str, parse_from_str_with_ns, make_doc, ) { Err(e) => { if e.kind == ErrorKind::Terminated && e.message == "here is a level 1 element" && e.code.unwrap().to_string() == "XTMM9000" { Ok(()) } else { Err(Error::new(ErrorKind::Unknown, "incorrect error")) } } Ok(_) => Err(Error::new( ErrorKind::Unknown, "evaluation succeeded when it should have failed", )), } } pub fn generic_callable_named_1( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "blueyellowgreenblue", r#" default value There are child elements "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; if result.to_string() == "There are 4 child elements" { Ok(()) } else { Err(Error::new( ErrorKind::Unknown, format!( "got result \"{}\", expected \"There are 4 child elements\"", result.to_string() ), )) } } pub fn generic_callable_posn_1( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "blueyellowgreenblue", r#" There are child elements "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; if result.to_string() == "There are 4 child elements" { Ok(()) } else { Err(Error::new( ErrorKind::Unknown, format!( "got result \"{}\", expected \"There are 4 child elements\"", result.to_string() ), )) } } pub fn generic_include( parse_from_str: G, _parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let srcdoc = parse_from_str("onetwothreefour")?; let styledoc = parse_from_str( " found Level1 element ", )?; let pwd = std::env::current_dir().expect("unable to get current directory"); let pwds = pwd .into_os_string() .into_string() .expect("unable to convert pwd"); let mut stctxt = StaticContextBuilder::new() .message(|_| Ok(())) .fetcher(|_| Err(Error::new(ErrorKind::NotImplemented, "not implemented"))) .parser(|_| Err(Error::new(ErrorKind::NotImplemented, "not implemented"))) .build(); let mut ctxt = from_document( styledoc, Some( Url::parse(format!("file://{}/tests/xsl/including.xsl", pwds.as_str()).as_str()) .expect("unable to parse URL"), ), |s| parse_from_str(s), |_| Ok(String::new()), )?; ctxt.context(vec![Item::Node(srcdoc.clone())], 0); ctxt.result_document(make_doc()?); let result = ctxt.evaluate(&mut stctxt)?; if result.to_string() == "onefound Level1 elementtwofound Level2 elementthreefound Level3 elementfour" { Ok(()) } else { Err(Error::new(ErrorKind::Unknown, format!("got result \"{}\", expected \"onefound Level1 elementtwofound Level2 elementthreefound Level3 elementfour\"", result.to_string()))) } } pub fn generic_document_1( parse_from_str: G, _parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let srcdoc = parse_from_str("on the inside")?; let styledoc = parse_from_str( r##" | found internal element found external element "##, )?; let mut stctxt = StaticContextBuilder::new() .message(|_| Ok(())) .fetcher(|_url| { Ok(String::from( "from outside", )) }) .parser(|s| parse_from_str(s)) .build(); let mut ctxt = from_document(styledoc, None, |s| parse_from_str(s), |_| Ok(String::new()))?; ctxt.context(vec![Item::Node(srcdoc.clone())], 0); ctxt.result_document(make_doc()?); let result = ctxt.evaluate(&mut stctxt)?; if result.to_string() == "found internal element|found external element" { Ok(()) } else { Err(Error::new(ErrorKind::Unknown, format!("got result \"{}\", expected \"onefound Level1 elementtwofound Level2 elementthreefound Level3 elementfour\"", result.to_string()))) } } pub fn generic_number_1( parse_from_str: G, _parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let srcdoc = parse_from_str("onetwothree")?; let styledoc = parse_from_str( r##" t element "##, )?; let mut stctxt = StaticContextBuilder::new() .message(|_| Ok(())) .fetcher(|_url| Ok(String::new())) .parser(|s| parse_from_str(s)) .build(); let mut ctxt = from_document(styledoc, None, |s| parse_from_str(s), |_| Ok(String::new()))?; ctxt.context(vec![Item::Node(srcdoc.clone())], 0); ctxt.result_document(make_doc()?); let result = ctxt.evaluate(&mut stctxt)?; assert_eq!(result.to_string(), "t element 1t element 2t element 3"); Ok(()) } pub fn attr_set_1( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "onetwo", r#" from set foo "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; assert_eq!( result.to_xml(), "" ); Ok(()) } pub fn attr_set_2( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "onetwo", r#" from set foo "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; assert_eq!(result.to_xml(), "onetwo"); Ok(()) } pub fn attr_set_3( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "onetwo", r#" from set foo "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; assert_eq!( result.to_xml(), "onetwo" ); Ok(()) } pub fn issue_96_abs( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "onetwo", r#" found an Example element "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; assert_eq!(result.to_xml(), "found an Example element"); Ok(()) } pub fn issue_96_rel( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "onetwo", r#" found an Example element "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; assert_eq!(result.to_xml(), "found an Example element"); Ok(()) } pub fn issue_96_mixed( parse_from_str: G, parse_from_str_with_ns: J, make_doc: H, ) -> Result<(), Error> where G: Fn(&str) -> Result, H: Fn() -> Result, J: Fn(&str) -> Result<(N, Rc), Error>, { let result = test_rig( "onetwo", r#" found a Level1 element "#, parse_from_str, parse_from_str_with_ns, make_doc, )?; assert_eq!( result.to_xml(), "found a Level1 elementfound a Level1 element" ); Ok(()) }