extern crate victoria_dom; use victoria_dom::DOM; #[test] fn empty_vals() { assert_eq!(DOM::new("").to_string(), ""); assert_eq!(DOM::new("").content(), ""); assert!(DOM::new("").at("p").is_none()); assert_eq!(DOM::new("").text(), ""); } #[test] fn nodestroy() { // fix issue #4 let dom = DOM::new("").childs(None); assert_eq!(dom[0].text(), ""); } #[test] fn basic1() { // Simple (basics) let dom = DOM::new(r#"
A
B
"#); assert_eq!(dom.at("#b").unwrap().text(), "B"); assert_eq!(dom.find("div[id]").iter().map(|x| x.text()).collect::>(), ["A", "B"]); assert_eq!(dom.at("#a").unwrap().attr("foo"), Some("0")); assert!(dom.at("#b").unwrap().attrs().contains_key("myattr")); assert_eq!(dom.find("[id]").iter().map(|x| x.attr("id").unwrap()).collect::>(), ["a", "b"]); assert_eq!(dom.to_string(), r#"
A
B
"#); } #[test] fn basic2() { // Select based on parent let dom = DOM::new(r#"
test1
test2
"#); assert_eq!(dom.find("body > div").get(0).unwrap().text(), "test1"); // right text assert_eq!(dom.find("body > div").get(1).unwrap().text(), ""); // no content assert_eq!(dom.find("body > div").len(), 2); // right number of elements assert_eq!(dom.find("body > div > div").get(0).unwrap().text(), "test2"); // right text assert_eq!(dom.find("body > div > div").len(), 1); // right number of elements } #[test] fn basic3() { // Basic navigation let dom = DOM::new(r#" test easy works well < very broken
more text
"#); assert!(dom.tag().is_none()); // no tag assert!(!dom.attrs().contains_key("foo")); assert_eq!( dom.to_string(), r#" test easy works well < very broken
more text
"#); let simple = dom.at("foo simple.working[class^=\"wor\"]").unwrap(); assert_eq!(simple.parent().unwrap().text_all(), "test easy works well yada yada < very broken more text"); assert_eq!(simple.tag().unwrap(), "simple"); assert_eq!(simple.attr("class").unwrap(), "working"); assert_eq!(simple.text(), "easy"); assert_eq!(simple.parent().unwrap().tag().unwrap(), "foo"); assert_eq!(simple.parent().unwrap().attr("bar").unwrap(), "baeasy"); assert_eq!(dom.at("test#test").unwrap().tag().unwrap(), "test"); assert_eq!(dom.at("[class$=\"ing\"]").unwrap().tag().unwrap(), "simple"); assert_eq!(dom.at("[class$=ing]").unwrap().tag().unwrap(), "simple"); assert_eq!(dom.at("[class=\"working\"]").unwrap().tag().unwrap(), "simple"); assert_eq!(dom.at("[class=working][class]").unwrap().tag().unwrap(), "simple"); assert_eq!(dom.at("foo > simple").unwrap().next().unwrap().tag().unwrap(), "test"); assert_eq!(dom.at("foo > simple").unwrap().next().unwrap().next().unwrap().tag().unwrap(), "a"); assert_eq!(dom.at("foo > test").unwrap().prev().unwrap().tag().unwrap(), "simple"); assert!(dom.next().is_none()); assert!(dom.prev().is_none()); assert!(dom.at("foo > a").unwrap().next().is_none()); assert!(dom.at("foo > simple").unwrap().prev().is_none()); assert_eq!(dom.at("simple").unwrap().ancestors(None).iter().map(|x| x.tag().unwrap()).collect::>(), ["foo"]); } #[test] fn class_and_id() { // Class and ID let dom = DOM::new(r#"
a
"#); assert_eq!(dom.at("div#id.class").unwrap().text(), "a"); } #[test] fn deep_nesting() { // Deep nesting (parent combinator) let dom = DOM::new(r#" Foo

Bar

More stuff
"#); let p = dom.find("body > #container > div p[id]"); assert_eq!(p.len(), 1); assert_eq!(p.get(0).unwrap().attr("id").unwrap(), "foo"); assert_eq!( dom.find("div").iter().map(|x| x.attr("id").unwrap()).collect::>(), ["container", "header", "logo", "buttons", "buttons", "content"] ); assert_eq!( dom.find("p").iter().map(|x| x.attr("id").unwrap()).collect::>(), ["foo", "bar"] ); assert_eq!( dom.at("p").unwrap().ancestors(None).iter().map(|x| x.tag().unwrap()).collect::>(), ["div", "div", "div", "body", "html"] ); assert_eq!(dom.at("html").unwrap().ancestors(None).len(), 0); assert_eq!(dom.ancestors(None).len(), 0); } #[test] fn script_tag() { let dom = DOM::new(r#""#); assert_eq!(dom.at("script").unwrap().text(), "alert('world');"); } #[test] fn html5_base() { // HTML5 (unquoted values) let dom = DOM::new(r#"
works
"#); assert_eq!(dom.at("#test").unwrap().text(), "works"); assert_eq!(dom.at("div").unwrap().text(), "works"); assert_eq!(dom.at("[foo=bar][foo=\"bar\"]").unwrap().text(), "works"); assert!(dom.at("[foo=\"ba\"]").is_none()); assert_eq!(dom.at("[foo=bar]").unwrap().text(), "works"); assert!(dom.at("[foo=ba]").is_none()); assert_eq!(dom.at(".tset").unwrap().text(), "works"); assert_eq!(dom.at("[bar=/baz/]").unwrap().text(), "works"); assert_eq!(dom.at("[baz=//]").unwrap().text(), "works"); } #[test] fn html1_mix() { // HTML1 (single quotes, uppercase tags and whitespace in attributes) let dom = DOM::new(r#"
works
"#); assert_eq!(dom.at("#test").unwrap().text(), "works"); assert_eq!(dom.at("div").unwrap().text(), "works"); assert_eq!(dom.at("[foo=\"bar\"]").unwrap().text(), "works"); assert!(dom.at("[foo=\"ba\"]").is_none()); assert_eq!(dom.at("[foo=bar]").unwrap().text(), "works"); assert!(dom.at("[foo=ba]").is_none()); assert_eq!(dom.at(".tset").unwrap().text(), "works"); } #[test] fn unicode_snowman() { // Already decoded Unicode snowman and quotes in selector let dom = DOM::new(r#"
"#); assert_eq!(dom.at(r#"[id="snow'm\"an"]"#).unwrap().text(), "☃"); assert_eq!(dom.at(r#"[id="snow'm\22 an"]"#).unwrap().text(), "☃"); assert_eq!(dom.at(r#"[id="snow\'m\000022an"]"#).unwrap().text(), "☃"); assert_eq!(dom.at("[id='snow\\'m\"an']").unwrap().text(), "☃"); assert_eq!(dom.at("[id='snow\\27m\"an']").unwrap().text(), "☃"); assert!(dom.at(r#"[id="snow'm\22an"]"#).is_none()); assert!(dom.at(r#"[id="snow'm\21 an"]"#).is_none()); assert!(dom.at(r#"[id="snow'm\000021an"]"#).is_none()); assert!(dom.at(r#"[id="snow'm\000021 an"]"#).is_none()); } #[test] fn unicode_selectors() { // Unicode and escaped selectors let html = r#"
Snowman
Heart
"#; let dom = DOM::new(html); assert_eq!(dom.at("#\\\n\\002603x").unwrap().text(), "Snowman"); assert_eq!(dom.at("#\\2603 x").unwrap().text(), "Snowman"); assert_eq!(dom.at("#\\\n\\2603 x").unwrap().text(), "Snowman"); assert_eq!(dom.at("[id=\"\\\n\\2603 x\"]").unwrap().text(), "Snowman"); assert_eq!(dom.at("[id=\"\\\n\\002603x\"]").unwrap().text(), "Snowman"); assert_eq!(dom.at("[id=\"\\\\2603 x\"]").unwrap().text(), "Snowman"); assert_eq!(dom.at("html #\\\n\\002603x").unwrap().text(), "Snowman"); assert_eq!(dom.at("html #\\2603 x").unwrap().text(), "Snowman"); assert_eq!(dom.at("html #\\\n\\2603 x").unwrap().text(), "Snowman"); assert_eq!(dom.at("html [id=\"\\\n\\2603 x\"]").unwrap().text(), "Snowman"); assert_eq!(dom.at("html [id=\"\\\n\\002603x\"]").unwrap().text(), "Snowman"); assert_eq!(dom.at("html [id=\"\\\\2603 x\"]").unwrap().text(), "Snowman"); assert_eq!(dom.at("#☃x").unwrap().text(), "Snowman"); assert_eq!(dom.at("html div#☃x").unwrap().text(), "Snowman"); assert_eq!(dom.at("[id^=\"☃\"]").unwrap().text(), "Snowman"); assert_eq!(dom.at("div[id^=\"☃\"]").unwrap().text(), "Snowman"); assert_eq!(dom.at("html div[id^=\"☃\"]").unwrap().text(), "Snowman"); assert_eq!(dom.at("html > div[id^=\"☃\"]").unwrap().text(), "Snowman"); assert_eq!(dom.at("[id^=☃]").unwrap().text(), "Snowman"); assert_eq!(dom.at("div[id^=☃]").unwrap().text(), "Snowman"); assert_eq!(dom.at("html div[id^=☃]").unwrap().text(), "Snowman"); assert_eq!(dom.at("html > div[id^=☃]").unwrap().text(), "Snowman"); assert_eq!(dom.at(".\\\n\\002665").unwrap().text(), "Heart"); assert_eq!(dom.at(".\\2665").unwrap().text(), "Heart"); assert_eq!(dom.at("html .\\\n\\002665").unwrap().text(), "Heart"); assert_eq!(dom.at("html .\\2665").unwrap().text(), "Heart"); assert_eq!(dom.at("html [class$=\"\\\n\\002665\"]").unwrap().text(), "Heart"); assert_eq!(dom.at("html [class$=\"\\2665\"]").unwrap().text(), "Heart"); assert_eq!(dom.at("[class$=\"\\\n\\002665\"]").unwrap().text(), "Heart"); assert_eq!(dom.at("[class$=\"\\2665\"]").unwrap().text(), "Heart"); assert_eq!(dom.at(".x").unwrap().text(), "Heart"); assert_eq!(dom.at("html .x").unwrap().text(), "Heart"); assert_eq!(dom.at(".♥").unwrap().text(), "Heart"); assert_eq!(dom.at("html .♥").unwrap().text(), "Heart"); assert_eq!(dom.at("div.♥").unwrap().text(), "Heart"); assert_eq!(dom.at("html div.♥").unwrap().text(), "Heart"); assert_eq!(dom.at("[class$=\"♥\"]").unwrap().text(), "Heart"); assert_eq!(dom.at("div[class$=\"♥\"]").unwrap().text(), "Heart"); assert_eq!(dom.at("html div[class$=\"♥\"]").unwrap().text(), "Heart"); assert_eq!(dom.at("html > div[class$=\"♥\"]").unwrap().text(), "Heart"); assert_eq!(dom.at("[class$=♥]").unwrap().text(), "Heart"); assert_eq!(dom.at("div[class$=♥]").unwrap().text(), "Heart"); assert_eq!(dom.at("html div[class$=♥]").unwrap().text(), "Heart"); assert_eq!(dom.at("html > div[class$=♥]").unwrap().text(), "Heart"); assert_eq!(dom.at("[class~=\"♥\"]").unwrap().text(), "Heart"); assert_eq!(dom.at("div[class~=\"♥\"]").unwrap().text(), "Heart"); assert_eq!(dom.at("html div[class~=\"♥\"]").unwrap().text(), "Heart"); assert_eq!(dom.at("html > div[class~=\"♥\"]").unwrap().text(), "Heart"); assert_eq!(dom.at("[class~=♥]").unwrap().text(), "Heart"); assert_eq!(dom.at("div[class~=♥]").unwrap().text(), "Heart"); assert_eq!(dom.at("html div[class~=♥]").unwrap().text(), "Heart"); assert_eq!(dom.at("html > div[class~=♥]").unwrap().text(), "Heart"); assert_eq!(dom.at("[class~=\"x\"]").unwrap().text(), "Heart"); assert_eq!(dom.at("div[class~=\"x\"]").unwrap().text(), "Heart"); assert_eq!(dom.at("html div[class~=\"x\"]").unwrap().text(), "Heart"); assert_eq!(dom.at("html > div[class~=\"x\"]").unwrap().text(), "Heart"); assert_eq!(dom.at("[class~=x]").unwrap().text(), "Heart"); assert_eq!(dom.at("div[class~=x]").unwrap().text(), "Heart"); assert_eq!(dom.at("html div[class~=x]").unwrap().text(), "Heart"); assert_eq!(dom.at("html > div[class~=x]").unwrap().text(), "Heart"); assert_eq!(dom.at("html").unwrap().to_string(), html); assert_eq!(dom.at("#☃x").unwrap().parent().unwrap().to_string(), html); assert_eq!(dom.to_string(), html); assert_eq!(dom.content(), html); let dom = DOM::new(r#"☃☃"#); assert_eq!(dom.at("title").unwrap().text(), "♥"); assert_eq!(dom.at("*").unwrap().text(), "♥"); assert_eq!(dom.at(".test").unwrap().text(), "♥"); } #[test] fn attrs_on_multiple_lines() { // Attributes on multiple lines let dom = DOM::new("
"); assert_eq!(dom.at("div.x").unwrap().attr("test").unwrap(), "23"); assert_eq!(dom.at("[foo=\"bar\"]").unwrap().attr("class").unwrap(), "x"); } #[test] fn markup_chars_in_attr_vals() { // Markup characters in attribute values let dom = DOM::new("
\" \n test='='>Test
"); assert_eq!(dom.at("div[id=\"\"]").unwrap().attrs().get("test").unwrap().clone(), Some("=".to_owned())); assert_eq!(dom.at("[id=\"\"]").unwrap().text(), "Test"); assert_eq!(dom.at("[id=\"><\"]").unwrap().attrs().get("id").unwrap().clone(), Some("><".to_owned())); } #[test] fn empty_attrs() { // Empty attributes let dom = DOM::new("
"); assert_eq!(dom.at("div").unwrap().attr("test").unwrap(), ""); assert_eq!(dom.at("div").unwrap().attr("test2").unwrap(), ""); assert_eq!(dom.at("[test]").unwrap().tag().unwrap(), "div"); assert_eq!(dom.at("[test=\"\"]").unwrap().tag().unwrap(), "div"); assert_eq!(dom.at("[test2]").unwrap().tag().unwrap(), "div"); assert_eq!(dom.at("[test2=\"\"]").unwrap().tag().unwrap(), "div"); assert!(dom.at("[test3]").is_none()); assert!(dom.at("[test3=\"\"]").is_none()); } #[test] fn multi_line_attr() { // Multi-line attribute let dom = DOM::new("
"); assert_eq!(dom.at("div").unwrap().attr("class").unwrap(), "line1\nline2"); assert_eq!(dom.at(".line1").unwrap().tag().unwrap(), "div"); assert_eq!(dom.at(".line2").unwrap().tag().unwrap(), "div"); assert!(dom.at(".line3").is_none()); } #[test] fn entities_in_attrs() { assert_eq!(DOM::new("").at("a").unwrap().attr("href").unwrap(), "/?foo<=bar"); assert_eq!(DOM::new("").at("a").unwrap().attr("href").unwrap(), "/?f<oo=bar"); assert_eq!(DOM::new("").at("a").unwrap().attr("href").unwrap(), "/?f<-oo=bar"); assert_eq!(DOM::new("").at("a").unwrap().attr("href").unwrap(), "/?foo=<"); assert_eq!(DOM::new("").at("a").unwrap().attr("href").unwrap(), "/?fcontent
"); assert!(dom.at("div").is_some()); assert_eq!(dom.at("div").unwrap().text(), "content"); } #[test] fn class_with_hyphen() { // Class with hyphen let dom = DOM::new(r#"
A
A1
"#); assert_eq!(dom.find(".a").iter().map(|x| x.text()).collect::>(), ["A"]); // found first element only assert_eq!(dom.find(".a-1").iter().map(|x| x.text()).collect::>(), ["A1"]); // found last element only } #[test] fn empty_tags() { // Empty tags let dom = DOM::new("



"); assert_eq!(dom.to_string(), "



"); } #[test] fn inner_html() { let dom = DOM::new("xxxxxxx"); assert_eq!(dom.at("a").unwrap().content(), "xxxxxxx"); assert_eq!(dom.content(), "xxxxxxx"); } #[test] fn multiple_selectors() { // Multiple selectors let dom = DOM::new("
A
B
C

D

"); assert_eq!(dom.find("p, div").iter().map(|x| x.text()).collect::>(), ["A", "B", "C", "D"]); assert_eq!(dom.find("#a, #c").iter().map(|x| x.text()).collect::>(), ["A", "C"]); assert_eq!(dom.find("div#a, div#b").iter().map(|x| x.text()).collect::>(), ["A", "B"]); assert_eq!(dom.find("div[id=\"a\"], div[id=\"c\"]").iter().map(|x| x.text()).collect::>(), ["A", "C"]); let dom2 = DOM::new("
A
B
C
"); assert_eq!(dom2.find("#☃, #♥x").iter().map(|x| x.text()).collect::>(), ["A", "C"]); assert_eq!(dom2.find("div#☃, div#b").iter().map(|x| x.text()).collect::>(), ["A", "B"]); assert_eq!(dom2.find("div[id=\"☃\"], div[id=\"♥x\"]").iter().map(|x| x.text()).collect::>(), ["A", "C"]); } #[test] fn multiple_attributes() { // Multiple attributes let dom = DOM::new(r#"
A
B
C
D
"#); assert_eq!(dom.find("div[foo=\"bar\"][bar=\"baz\"]").iter().map(|x| x.text()).collect::>(), ["A", "C"]); assert_eq!(dom.find("div[foo^=\"b\"][foo$=\"r\"]").iter().map(|x| x.text()).collect::>(), ["A", "B", "C"]); assert!(dom.at("[foo=\"bar\"]").unwrap().prev().is_none()); assert_eq!(dom.at("[foo=\"bar\"]").unwrap().next().unwrap().text(), "B"); assert_eq!(dom.at("[foo=\"bar\"]").unwrap().next().unwrap().prev().unwrap().text(), "A"); assert!(dom.at("[foo=\"bar\"]").unwrap().next().unwrap().next().unwrap().next().unwrap().next().is_none()); } #[test] fn pseudo_classes() { // Pseudo-classes let dom = DOM::new(r#"

test 123

"#); assert_eq!(dom.find(":root").len(), 1); assert_eq!(dom.find(":root").get(0).unwrap().tag(), Some("form")); assert_eq!(dom.find("*:root").get(0).unwrap().tag(), Some("form")); assert_eq!(dom.find("form:root").get(0).unwrap().tag(), Some("form")); assert_eq!(dom.find(":checked").len(), 4); assert_eq!(dom.find(":checked").get(0).unwrap().attr("name").unwrap(), "groovy"); assert_eq!(dom.find("option:checked").get(0).unwrap().attr("value").unwrap(), "e"); assert_eq!(dom.find(":checked").get(1).unwrap().text(), "E"); assert_eq!(dom.find("*:checked").get(1).unwrap().text(), "E"); assert_eq!(dom.find(":checked").get(2).unwrap().text(), "H"); assert_eq!(dom.find(":checked").get(3).unwrap().attr("name").unwrap(), "I"); assert_eq!(dom.find("option[selected]").len(), 2); assert_eq!(dom.find("option[selected]").get(0).unwrap().attr("value").unwrap(), "e"); assert_eq!(dom.find("option[selected]").get(1).unwrap().text(), "H"); assert_eq!(dom.find(":checked[value=\"e\"]").get(0).unwrap().text(), "E"); assert_eq!(dom.find("*:checked[value=\"e\"]").get(0).unwrap().text(), "E"); assert_eq!(dom.find("option:checked[value=\"e\"]").get(0).unwrap().text(), "E"); assert_eq!(dom.at("optgroup option:checked[value=\"e\"]").unwrap().text(), "E"); assert_eq!(dom.at("select option:checked[value=\"e\"]").unwrap().text(), "E"); assert_eq!(dom.at("select :checked[value=\"e\"]").unwrap().text(), "E"); assert_eq!(dom.at("optgroup > :checked[value=\"e\"]").unwrap().text(), "E"); assert_eq!(dom.at("select *:checked[value=\"e\"]").unwrap().text(), "E"); assert_eq!(dom.at("optgroup > *:checked[value=\"e\"]").unwrap().text(), "E"); assert_eq!(dom.find(":checked[value=\"e\"]").len(), 1); assert_eq!(dom.find(":empty").get(0).unwrap().attr("name").unwrap(), "user"); assert_eq!(dom.find("input:empty").get(0).unwrap().attr("name").unwrap(), "user"); assert_eq!(dom.at(":empty[type^=\"ch\"]").unwrap().attr("name").unwrap(), "groovy"); assert_eq!(dom.at("p").unwrap().attr("id").unwrap(), "content"); assert_eq!(dom.at("p:empty").unwrap().attr("id").unwrap(), "no_content"); // More pseudo-classes let dom = DOM::new("
  • A
  • B
  • C
  • D
  • E
  • F
  • G
  • H
"); assert_eq!(dom.find("li:nth-child(odd)").iter().map(|x| x.text()).collect::>(), ["A", "C", "E", "G"]); assert_eq!(dom.find("li:NTH-CHILD(ODD)").iter().map(|x| x.text()).collect::>(), ["A", "C", "E", "G"]); assert_eq!(dom.find("li:nth-last-child(odd)").iter().map(|x| x.text()).collect::>(), ["B", "D", "F", "H"]); assert_eq!(dom.find(":nth-child(odd)").get(0).unwrap().tag().unwrap(), "ul"); assert_eq!(dom.find(":nth-child(odd)").get(1).unwrap().text(), "A"); assert_eq!(dom.find(":nth-child(1)").get(0).unwrap().tag().unwrap(), "ul"); assert_eq!(dom.find(":nth-child(1)").get(1).unwrap().text(), "A"); assert_eq!(dom.find(":nth-last-child(odd)").get(0).unwrap().tag().unwrap(), "ul"); assert_eq!(dom.find(":nth-last-child(odd)").last().unwrap().text(), "H"); assert_eq!(dom.find(":nth-last-child(1)").get(0).unwrap().tag().unwrap(), "ul"); assert_eq!(dom.find(":nth-last-child(1)").get(1).unwrap().text(), "H"); assert_eq!(dom.find("li:nth-child(2n+1)").iter().map(|x| x.text()).collect::>(), ["A", "C", "E", "G"]); assert_eq!(dom.find("li:nth-child(2n + 1)").iter().map(|x| x.text()).collect::>(), ["A", "C", "E", "G"]); assert_eq!(dom.find("li:nth-last-child(2n+1)").iter().map(|x| x.text()).collect::>(), ["B", "D", "F", "H"]); assert_eq!(dom.find("li:nth-child(even)").iter().map(|x| x.text()).collect::>(), ["B", "D", "F", "H"]); assert_eq!(dom.find("li:NTH-CHILD(EVEN)").iter().map(|x| x.text()).collect::>(), ["B", "D", "F", "H"]); assert_eq!(dom.find("li:nth-last-child( even )").iter().map(|x| x.text()).collect::>(), ["A", "C", "E", "G"]); assert_eq!(dom.find("li:nth-child(2n+2)").iter().map(|x| x.text()).collect::>(), ["B", "D", "F", "H"]); assert_eq!(dom.find("li:nTh-chILd(2N+2)").iter().map(|x| x.text()).collect::>(), ["B", "D", "F", "H"]); assert_eq!(dom.find("li:nth-child( 2n + 2 )").iter().map(|x| x.text()).collect::>(), ["B", "D", "F", "H"]); assert_eq!(dom.find("li:nth-last-child(2n+2)").iter().map(|x| x.text()).collect::>(), ["A", "C", "E", "G"]); assert_eq!(dom.find("li:nth-child(4n+1)").iter().map(|x| x.text()).collect::>(), ["A", "E"]); assert_eq!(dom.find("li:nth-last-child(4n+1)").iter().map(|x| x.text()).collect::>(), ["D", "H"]); assert_eq!(dom.find("li:nth-child(4n+4)").iter().map(|x| x.text()).collect::>(), ["D", "H"]); assert_eq!(dom.find("li:nth-last-child(4n+4)").iter().map(|x| x.text()).collect::>(), ["A", "E"]); assert_eq!(dom.find("li:nth-child(4n)").iter().map(|x| x.text()).collect::>(), ["D", "H"]); assert_eq!(dom.find("li:nth-child( 4n )").iter().map(|x| x.text()).collect::>(), ["D", "H"]); assert_eq!(dom.find("li:nth-last-child(4n)").iter().map(|x| x.text()).collect::>(), ["A", "E"]); assert_eq!(dom.find("li:nth-child(5n-2)").iter().map(|x| x.text()).collect::>(), ["C", "H"]); assert_eq!(dom.find("li:nth-child( 5n - 2 )").iter().map(|x| x.text()).collect::>(), ["C", "H"]); assert_eq!(dom.find("li:nth-last-child(5n-2)").iter().map(|x| x.text()).collect::>(), ["A", "F"]); assert_eq!(dom.find("li:nth-child(-n+3)").iter().map(|x| x.text()).collect::>(), ["A", "B", "C"]); assert_eq!(dom.find("li:nth-child( -n + 3 )").iter().map(|x| x.text()).collect::>(), ["A", "B", "C"]); assert_eq!(dom.find("li:nth-last-child(-n+3)").iter().map(|x| x.text()).collect::>(), ["F", "G", "H"]); assert_eq!(dom.find("li:nth-child(-1n+3)").iter().map(|x| x.text()).collect::>(), ["A", "B", "C"]); assert_eq!(dom.find("li:nth-last-child(-1n+3)").iter().map(|x| x.text()).collect::>(), ["F", "G", "H"]); assert_eq!(dom.find("li:nth-child(3n)").iter().map(|x| x.text()).collect::>(), ["C", "F"]); assert_eq!(dom.find("li:nth-last-child(3n)").iter().map(|x| x.text()).collect::>(), ["C", "F"]); assert_eq!(dom.find("li:NTH-LAST-CHILD(3N)").iter().map(|x| x.text()).collect::>(), ["C", "F"]); assert_eq!(dom.find("li:Nth-Last-Child(3N)").iter().map(|x| x.text()).collect::>(), ["C", "F"]); assert_eq!(dom.find("li:nth-child( 3 )").iter().map(|x| x.text()).collect::>(), ["C"]); assert_eq!(dom.find("li:nth-last-child( +3 )").iter().map(|x| x.text()).collect::>(), ["F"]); assert_eq!(dom.find("li:nth-child(1n+0)").iter().map(|x| x.text()).collect::>(), ["A", "B", "C", "D", "E", "F", "G"]); assert_eq!(dom.find("li:nth-child(1n-0)").iter().map(|x| x.text()).collect::>(), ["A", "B", "C", "D", "E", "F", "G"]); assert_eq!(dom.find("li:nth-child(n+0)").iter().map(|x| x.text()).collect::>(), ["A", "B", "C", "D", "E", "F", "G"]); assert_eq!(dom.find("li:nth-child(n)").iter().map(|x| x.text()).collect::>(), ["A", "B", "C", "D", "E", "F", "G"]); assert_eq!(dom.find("li:nth-child(n+0)").iter().map(|x| x.text()).collect::>(), ["A", "B", "C", "D", "E", "F", "G"]); assert_eq!(dom.find("li:NTH-CHILD(N+0)").iter().map(|x| x.text()).collect::>(), ["A", "B", "C", "D", "E", "F", "G"]); assert_eq!(dom.find("li:Nth-Child(N+0)").iter().map(|x| x.text()).collect::>(), ["A", "B", "C", "D", "E", "F", "G"]); assert_eq!(dom.find("li:nth-child(n)").iter().map(|x| x.text()).collect::>(), ["A", "B", "C", "D", "E", "F", "G"]); assert_eq!(dom.find("li:nth-child(0n+1)").iter().map(|x| x.text()).collect::>(), ["A"]); assert_eq!(dom.find("li:nth-child(0n+0)").len(), 0); assert_eq!(dom.find("li:nth-child(0)").len(), 0); assert_eq!(dom.find("li:nth-child()").len(), 0); assert_eq!(dom.find("li:nth-child(whatever)").len(), 0); assert_eq!(dom.find("li:whatever(whatever)").len(), 0); // Even more pseudo-classes let dom = DOM::new(r#"
  • A
  • B

  • C
  • D

  • E
  • F
  • G

  • H
  • I
J
"#); assert_eq!(dom.find("ul :nth-child(odd)").iter().map(|x| x.text()).collect::>(), ["A", "C", "E", "G", "I"]); assert_eq!(dom.find("li:nth-of-type(odd)").iter().map(|x| x.text()).collect::>(), ["A", "E", "H"]); assert_eq!(dom.find("li:nth-last-of-type( odd )").iter().map(|x| x.text()).collect::>(), ["C", "F", "I"]); assert_eq!(dom.find("p:nth-of-type(odd)").iter().map(|x| x.text()).collect::>(), ["B", "G"]); assert_eq!(dom.find("p:nth-last-of-type(odd)").iter().map(|x| x.text()).collect::>(), ["B", "G"]); assert_eq!(dom.find("ul :nth-child(1)").iter().map(|x| x.text()).collect::>(), ["A"]); assert_eq!(dom.find("ul :first-child").iter().map(|x| x.text()).collect::>(), ["A"]); assert_eq!(dom.find("p:nth-of-type(1)").iter().map(|x| x.text()).collect::>(), ["B"]); assert_eq!(dom.find("p:first-of-type").iter().map(|x| x.text()).collect::>(), ["B"]); assert_eq!(dom.find("li:nth-of-type(1)").iter().map(|x| x.text()).collect::>(), ["A"]); assert_eq!(dom.find("li:first-of-type").iter().map(|x| x.text()).collect::>(), ["A"]); assert_eq!(dom.find("ul :nth-last-child(-n+1)").iter().map(|x| x.text()).collect::>(), ["I"]); assert_eq!(dom.find("ul :last-child").iter().map(|x| x.text()).collect::>(), ["I"]); assert_eq!(dom.find("p:nth-last-of-type(-n+1)").iter().map(|x| x.text()).collect::>(), ["G"]); assert_eq!(dom.find("p:last-of-type").iter().map(|x| x.text()).collect::>(), ["G"]); assert_eq!(dom.find("li:nth-last-of-type(-n+1)").iter().map(|x| x.text()).collect::>(), ["I"]); assert_eq!(dom.find("li:last-of-type").iter().map(|x| x.text()).collect::>(), ["I"]); assert_eq!(dom.find("ul :nth-child(-n+3):not(li)").iter().map(|x| x.text()).collect::>(), ["B"]); assert_eq!(dom.find("ul :nth-child(-n+3):NOT(li)").iter().map(|x| x.text()).collect::>(), ["B"]); assert_eq!(dom.find("ul :nth-child(-n+3):not(:first-child)").iter().map(|x| x.text()).collect::>(), ["B", "C"]); assert_eq!(dom.find("ul :nth-child(-n+3):not(.♥)").iter().map(|x| x.text()).collect::>(), ["A", "B"]); assert_eq!(dom.find("ul :nth-child(-n+3):not([class$=\"♥\"])").iter().map(|x| x.text()).collect::>(), ["A", "B"]); assert_eq!(dom.find("ul :nth-child(-n+3):not(li[class$=\"♥\"])").iter().map(|x| x.text()).collect::>(), ["A", "B"]); assert_eq!(dom.find("ul :nth-child(-n+3):not([class$=\"♥\"][class^=\"test\"])").iter().map(|x| x.text()).collect::>(), ["A", "B"]); assert_eq!(dom.find("ul :nth-child(-n+3):not(*[class$=\"♥\"])").iter().map(|x| x.text()).collect::>(), ["A", "B"]); assert_eq!(dom.find("ul :nth-child(-n+3):not(:nth-child(-n+2))").iter().map(|x| x.text()).collect::>(), ["C"]); assert_eq!(dom.find("ul :nth-child(-n+3):not(:nth-child(1)):not(:nth-child(2))").iter().map(|x| x.text()).collect::>(), ["C"]); assert_eq!(dom.find(":only-child").iter().map(|x| x.text()).collect::>(), ["J"]); assert_eq!(dom.find("div :only-of-type").iter().map(|x| x.text()).collect::>(), ["J", "K"]); assert_eq!(dom.find("div:only-child").iter().map(|x| x.text()).collect::>(), ["J"]); assert_eq!(dom.find("div div:only-of-type").iter().map(|x| x.text()).collect::>(), ["J", "K"]); }