diff options
Diffstat (limited to 'vendor/github.com/andybalholm/cascadia/selector_test.go')
-rw-r--r-- | vendor/github.com/andybalholm/cascadia/selector_test.go | 654 |
1 files changed, 654 insertions, 0 deletions
diff --git a/vendor/github.com/andybalholm/cascadia/selector_test.go b/vendor/github.com/andybalholm/cascadia/selector_test.go new file mode 100644 index 0000000..7ff77e6 --- /dev/null +++ b/vendor/github.com/andybalholm/cascadia/selector_test.go @@ -0,0 +1,654 @@ +package cascadia + +import ( + "bytes" + "strings" + "testing" + + "golang.org/x/net/html" +) + +type selectorTest struct { + HTML, selector string + results []string +} + +func nodeString(n *html.Node) string { + buf := bytes.NewBufferString("") + html.Render(buf, n) + return buf.String() +} + +var selectorTests = []selectorTest{ + { + `<body><address>This address...</address></body>`, + "address", + []string{ + "<address>This address...</address>", + }, + }, + { + `<!-- comment --><html><head></head><body>text</body></html>`, + "*", + []string{ + "<html><head></head><body>text</body></html>", + "<head></head>", + "<body>text</body>", + }, + }, + { + `<html><head></head><body></body></html>`, + "*", + []string{ + "<html><head></head><body></body></html>", + "<head></head>", + "<body></body>", + }, + }, + { + `<p id="foo"><p id="bar">`, + "#foo", + []string{ + `<p id="foo"></p>`, + }, + }, + { + `<ul><li id="t1"><p id="t1">`, + "li#t1", + []string{ + `<li id="t1"><p id="t1"></p></li>`, + }, + }, + { + `<ol><li id="t4"><li id="t44">`, + "*#t4", + []string{ + `<li id="t4"></li>`, + }, + }, + { + `<ul><li class="t1"><li class="t2">`, + ".t1", + []string{ + `<li class="t1"></li>`, + }, + }, + { + `<p class="t1 t2">`, + "p.t1", + []string{ + `<p class="t1 t2"></p>`, + }, + }, + { + `<div class="test">`, + "div.teST", + []string{}, + }, + { + `<p class="t1 t2">`, + ".t1.fail", + []string{}, + }, + { + `<p class="t1 t2">`, + "p.t1.t2", + []string{ + `<p class="t1 t2"></p>`, + }, + }, + { + `<p><p title="title">`, + "p[title]", + []string{ + `<p title="title"></p>`, + }, + }, + { + `<address><address title="foo"><address title="bar">`, + `address[title="foo"]`, + []string{ + `<address title="foo"><address title="bar"></address></address>`, + }, + }, + { + `<address><address title="foo"><address title="bar">`, + `address[title!="foo"]`, + []string{ + `<address><address title="foo"><address title="bar"></address></address></address>`, + `<address title="bar"></address>`, + }, + }, + { + `<p title="tot foo bar">`, + `[ title ~= foo ]`, + []string{ + `<p title="tot foo bar"></p>`, + }, + }, + { + `<p title="hello world">`, + `[title~="hello world"]`, + []string{}, + }, + { + `<p lang="en"><p lang="en-gb"><p lang="enough"><p lang="fr-en">`, + `[lang|="en"]`, + []string{ + `<p lang="en"></p>`, + `<p lang="en-gb"></p>`, + }, + }, + { + `<p title="foobar"><p title="barfoo">`, + `[title^="foo"]`, + []string{ + `<p title="foobar"></p>`, + }, + }, + { + `<p title="foobar"><p title="barfoo">`, + `[title$="bar"]`, + []string{ + `<p title="foobar"></p>`, + }, + }, + { + `<p title="foobarufoo">`, + `[title*="bar"]`, + []string{ + `<p title="foobarufoo"></p>`, + }, + }, + { + `<p class=" ">This text should be green.</p><p>This text should be green.</p>`, + `p[class$=" "]`, + []string{}, + }, + { + `<p class="">This text should be green.</p><p>This text should be green.</p>`, + `p[class$=""]`, + []string{}, + }, + { + `<p class=" ">This text should be green.</p><p>This text should be green.</p>`, + `p[class^=" "]`, + []string{}, + }, + { + `<p class="">This text should be green.</p><p>This text should be green.</p>`, + `p[class^=""]`, + []string{}, + }, + { + `<p class=" ">This text should be green.</p><p>This text should be green.</p>`, + `p[class*=" "]`, + []string{}, + }, + { + `<p class="">This text should be green.</p><p>This text should be green.</p>`, + `p[class*=""]`, + []string{}, + }, + { + `<input type="radio" name="Sex" value="F"/>`, + `input[name=Sex][value=F]`, + []string{ + `<input type="radio" name="Sex" value="F"/>`, + }, + }, + { + `<table border="0" cellpadding="0" cellspacing="0" style="table-layout: fixed; width: 100%; border: 0 dashed; border-color: #FFFFFF"><tr style="height:64px">aaa</tr></table>`, + `table[border="0"][cellpadding="0"][cellspacing="0"]`, + []string{ + `<table border="0" cellpadding="0" cellspacing="0" style="table-layout: fixed; width: 100%; border: 0 dashed; border-color: #FFFFFF"><tbody><tr style="height:64px"></tr></tbody></table>`, + }, + }, + { + `<p class="t1 t2">`, + ".t1:not(.t2)", + []string{}, + }, + { + `<div class="t3">`, + `div:not(.t1)`, + []string{ + `<div class="t3"></div>`, + }, + }, + { + `<div><div class="t2"><div class="t3">`, + `div:not([class="t2"])`, + []string{ + `<div><div class="t2"><div class="t3"></div></div></div>`, + `<div class="t3"></div>`, + }, + }, + { + `<ol><li id=1><li id=2><li id=3></ol>`, + `li:nth-child(odd)`, + []string{ + `<li id="1"></li>`, + `<li id="3"></li>`, + }, + }, + { + `<ol><li id=1><li id=2><li id=3></ol>`, + `li:nth-child(even)`, + []string{ + `<li id="2"></li>`, + }, + }, + { + `<ol><li id=1><li id=2><li id=3></ol>`, + `li:nth-child(-n+2)`, + []string{ + `<li id="1"></li>`, + `<li id="2"></li>`, + }, + }, + { + `<ol><li id=1><li id=2><li id=3></ol>`, + `li:nth-child(3n+1)`, + []string{ + `<li id="1"></li>`, + }, + }, + { + `<ol><li id=1><li id=2><li id=3><li id=4></ol>`, + `li:nth-last-child(odd)`, + []string{ + `<li id="2"></li>`, + `<li id="4"></li>`, + }, + }, + { + `<ol><li id=1><li id=2><li id=3><li id=4></ol>`, + `li:nth-last-child(even)`, + []string{ + `<li id="1"></li>`, + `<li id="3"></li>`, + }, + }, + { + `<ol><li id=1><li id=2><li id=3><li id=4></ol>`, + `li:nth-last-child(-n+2)`, + []string{ + `<li id="3"></li>`, + `<li id="4"></li>`, + }, + }, + { + `<ol><li id=1><li id=2><li id=3><li id=4></ol>`, + `li:nth-last-child(3n+1)`, + []string{ + `<li id="1"></li>`, + `<li id="4"></li>`, + }, + }, + { + `<p>some text <span id="1">and a span</span><span id="2"> and another</span></p>`, + `span:first-child`, + []string{ + `<span id="1">and a span</span>`, + }, + }, + { + `<span>a span</span> and some text`, + `span:last-child`, + []string{ + `<span>a span</span>`, + }, + }, + { + `<address></address><p id=1><p id=2>`, + `p:nth-of-type(2)`, + []string{ + `<p id="2"></p>`, + }, + }, + { + `<address></address><p id=1><p id=2></p><a>`, + `p:nth-last-of-type(2)`, + []string{ + `<p id="1"></p>`, + }, + }, + { + `<address></address><p id=1><p id=2></p><a>`, + `p:last-of-type`, + []string{ + `<p id="2"></p>`, + }, + }, + { + `<address></address><p id=1><p id=2></p><a>`, + `p:first-of-type`, + []string{ + `<p id="1"></p>`, + }, + }, + { + `<div><p id="1"></p><a></a></div><div><p id="2"></p></div>`, + `p:only-child`, + []string{ + `<p id="2"></p>`, + }, + }, + { + `<div><p id="1"></p><a></a></div><div><p id="2"></p><p id="3"></p></div>`, + `p:only-of-type`, + []string{ + `<p id="1"></p>`, + }, + }, + { + `<p id="1"><!-- --><p id="2">Hello<p id="3"><span>`, + `:empty`, + []string{ + `<head></head>`, + `<p id="1"><!-- --></p>`, + `<span></span>`, + }, + }, + { + `<div><p id="1"><table><tr><td><p id="2"></table></div><p id="3">`, + `div p`, + []string{ + `<p id="1"><table><tbody><tr><td><p id="2"></p></td></tr></tbody></table></p>`, + `<p id="2"></p>`, + }, + }, + { + `<div><p id="1"><table><tr><td><p id="2"></table></div><p id="3">`, + `div table p`, + []string{ + `<p id="2"></p>`, + }, + }, + { + `<div><p id="1"><div><p id="2"></div><table><tr><td><p id="3"></table></div>`, + `div > p`, + []string{ + `<p id="1"></p>`, + `<p id="2"></p>`, + }, + }, + { + `<p id="1"><p id="2"></p><address></address><p id="3">`, + `p ~ p`, + []string{ + `<p id="2"></p>`, + `<p id="3"></p>`, + }, + }, + { + `<p id="1"></p> + <!--comment--> + <p id="2"></p><address></address><p id="3">`, + `p + p`, + []string{ + `<p id="2"></p>`, + }, + }, + { + `<ul><li></li><li></li></ul><p>`, + `li, p`, + []string{ + "<li></li>", + "<li></li>", + "<p></p>", + }, + }, + { + `<p id="1"><p id="2"></p><address></address><p id="3">`, + `p +/*This is a comment*/ p`, + []string{ + `<p id="2"></p>`, + }, + }, + { + `<p>Text block that <span>wraps inner text</span> and continues</p>`, + `p:contains("that wraps")`, + []string{ + `<p>Text block that <span>wraps inner text</span> and continues</p>`, + }, + }, + { + `<p>Text block that <span>wraps inner text</span> and continues</p>`, + `p:containsOwn("that wraps")`, + []string{}, + }, + { + `<p>Text block that <span>wraps inner text</span> and continues</p>`, + `:containsOwn("inner")`, + []string{ + `<span>wraps inner text</span>`, + }, + }, + { + `<p>Text block that <span>wraps inner text</span> and continues</p>`, + `p:containsOwn("block")`, + []string{ + `<p>Text block that <span>wraps inner text</span> and continues</p>`, + }, + }, + { + `<div id="d1"><p id="p1"><span>text content</span></p></div><div id="d2"/>`, + `div:has(#p1)`, + []string{ + `<div id="d1"><p id="p1"><span>text content</span></p></div>`, + }, + }, + { + `<div id="d1"><p id="p1"><span>contents 1</span></p></div> + <div id="d2"><p>contents <em>2</em></p></div>`, + `div:has(:containsOwn("2"))`, + []string{ + `<div id="d2"><p>contents <em>2</em></p></div>`, + }, + }, + { + `<body><div id="d1"><p id="p1"><span>contents 1</span></p></div> + <div id="d2"><p id="p2">contents <em>2</em></p></div></body>`, + `body :has(:containsOwn("2"))`, + []string{ + `<div id="d2"><p id="p2">contents <em>2</em></p></div>`, + `<p id="p2">contents <em>2</em></p>`, + }, + }, + { + `<body><div id="d1"><p id="p1"><span>contents 1</span></p></div> + <div id="d2"><p id="p2">contents <em>2</em></p></div></body>`, + `body :haschild(:containsOwn("2"))`, + []string{ + `<p id="p2">contents <em>2</em></p>`, + }, + }, + { + `<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`, + `p:matches([\d])`, + []string{ + `<p id="p1">0123456789</p>`, + `<p id="p3">0123ABCD</p>`, + }, + }, + { + `<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`, + `p:matches([a-z])`, + []string{ + `<p id="p2">abcdef</p>`, + }, + }, + { + `<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`, + `p:matches([a-zA-Z])`, + []string{ + `<p id="p2">abcdef</p>`, + `<p id="p3">0123ABCD</p>`, + }, + }, + { + `<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`, + `p:matches([^\d])`, + []string{ + `<p id="p2">abcdef</p>`, + `<p id="p3">0123ABCD</p>`, + }, + }, + { + `<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`, + `p:matches(^(0|a))`, + []string{ + `<p id="p1">0123456789</p>`, + `<p id="p2">abcdef</p>`, + `<p id="p3">0123ABCD</p>`, + }, + }, + { + `<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`, + `p:matches(^\d+$)`, + []string{ + `<p id="p1">0123456789</p>`, + }, + }, + { + `<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`, + `p:not(:matches(^\d+$))`, + []string{ + `<p id="p2">abcdef</p>`, + `<p id="p3">0123ABCD</p>`, + }, + }, + { + `<div><p id="p1">01234<em>567</em>89</p><div>`, + `div :matchesOwn(^\d+$)`, + []string{ + `<p id="p1">01234<em>567</em>89</p>`, + `<em>567</em>`, + }, + }, + { + `<ul> + <li><a id="a1" href="http://www.google.com/finance"></a> + <li><a id="a2" href="http://finance.yahoo.com/"></a> + <li><a id="a2" href="http://finance.untrusted.com/"/> + <li><a id="a3" href="https://www.google.com/news"/> + <li><a id="a4" href="http://news.yahoo.com"/> + </ul>`, + `[href#=(fina)]:not([href#=(\/\/[^\/]+untrusted)])`, + []string{ + `<a id="a1" href="http://www.google.com/finance"></a>`, + `<a id="a2" href="http://finance.yahoo.com/"></a>`, + }, + }, + { + `<ul> + <li><a id="a1" href="http://www.google.com/finance"/> + <li><a id="a2" href="http://finance.yahoo.com/"/> + <li><a id="a3" href="https://www.google.com/news"></a> + <li><a id="a4" href="http://news.yahoo.com"/> + </ul>`, + `[href#=(^https:\/\/[^\/]*\/?news)]`, + []string{ + `<a id="a3" href="https://www.google.com/news"></a>`, + }, + }, + { + `<form> + <label>Username <input type="text" name="username" /></label> + <label>Password <input type="password" name="password" /></label> + <label>Country + <select name="country"> + <option value="ca">Canada</option> + <option value="us">United States</option> + </select> + </label> + <label>Bio <textarea name="bio"></textarea></label> + <button>Sign up</button> + </form>`, + `:input`, + []string{ + `<input type="text" name="username"/>`, + `<input type="password" name="password"/>`, + `<select name="country"> + <option value="ca">Canada</option> + <option value="us">United States</option> + </select>`, + `<textarea name="bio"></textarea>`, + `<button>Sign up</button>`, + }, + }, + { + `<html><head></head><body></body></html>`, + ":root", + []string{ + "<html><head></head><body></body></html>", + }, + }, + { + `<html><head></head><body></body></html>`, + "*:root", + []string{ + "<html><head></head><body></body></html>", + }, + }, + { + `<html><head></head><body></body></html>`, + "*:root:first-child", + []string{}, + }, + { + `<html><head></head><body></body></html>`, + "*:root:nth-child(1)", + []string{}, + }, + { + `<html><head></head><body><a href="http://www.foo.com"></a></body></html>`, + "a:not(:root)", + []string{ + `<a href="http://www.foo.com"></a>`, + }, + }, +} + +func TestSelectors(t *testing.T) { + for _, test := range selectorTests { + s, err := Compile(test.selector) + if err != nil { + t.Errorf("error compiling %q: %s", test.selector, err) + continue + } + + doc, err := html.Parse(strings.NewReader(test.HTML)) + if err != nil { + t.Errorf("error parsing %q: %s", test.HTML, err) + continue + } + + matches := s.MatchAll(doc) + if len(matches) != len(test.results) { + t.Errorf("selector %s wanted %d elements, got %d instead", test.selector, len(test.results), len(matches)) + continue + } + + for i, m := range matches { + got := nodeString(m) + if got != test.results[i] { + t.Errorf("selector %s wanted %s, got %s instead", test.selector, test.results[i], got) + } + } + + firstMatch := s.MatchFirst(doc) + if len(test.results) == 0 { + if firstMatch != nil { + t.Errorf("MatchFirst: selector %s want nil, got %s", test.selector, nodeString(firstMatch)) + } + } else { + got := nodeString(firstMatch) + if got != test.results[0] { + t.Errorf("MatchFirst: selector %s want %s, got %s", test.selector, test.results[0], got) + } + } + } +} |