github.com/suntong/cascadia@v1.3.0/cascadia_test.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "strings" 6 "testing" 7 ) 8 9 func TestSelectors(t *testing.T) { 10 for _, test := range selectorTests { 11 buf := bytes.NewBufferString("") 12 Opts.CSS, Opts.Piece, Opts.Deli, 13 Opts.WrapHTML, Opts.TextOut, Opts.TextRaw, Opts.Quiet = 14 []string{test.selector}, PieceStyleMap{}, ",", 15 false, false, false, false 16 Cascadia(strings.NewReader(test.HTML), buf, Opts) 17 got := buf.String() 18 if len(got) == 0 && len(test.results) == 0 { 19 // correct 20 continue 21 } 22 want := strings.Join(test.results, "\n") + "\n" 23 if got != want { 24 t.Errorf("wanted %s, got %s instead", want, got) 25 } 26 } 27 } 28 29 // ////////////////////////////////////////////////////////////////////////// 30 // The following is taken from 31 // https://github.com/andybalholm/cascadia/blob/c56252c33997d9b9991f4c1e3b5fbc82d6d656b3/selector_test.go 32 type selectorTest struct { 33 HTML, selector string 34 results []string 35 } 36 37 var selectorTests = []selectorTest{ 38 { 39 `<html><head></head><body></body></html>`, 40 "*", 41 []string{ 42 "<html><head></head><body></body></html>", 43 "<head></head>", 44 "<body></body>", 45 }, 46 }, 47 { 48 `<p id="foo"><p id="bar">`, 49 "#foo", 50 []string{ 51 `<p id="foo"></p>`, 52 }, 53 }, 54 { 55 `<ul><li id="t1"><p id="t1">`, 56 "li#t1", 57 []string{ 58 `<li id="t1"><p id="t1"></p></li>`, 59 }, 60 }, 61 { 62 `<ol><li id="t4"><li id="t44">`, 63 "*#t4", 64 []string{ 65 `<li id="t4"></li>`, 66 }, 67 }, 68 { 69 `<ul><li class="t1"><li class="t2">`, 70 ".t1", 71 []string{ 72 `<li class="t1"></li>`, 73 }, 74 }, 75 { 76 `<p class="t1 t2">`, 77 "p.t1", 78 []string{ 79 `<p class="t1 t2"></p>`, 80 }, 81 }, 82 { 83 `<div class="test">`, 84 "div.teST", 85 []string{}, 86 }, 87 { 88 `<p class="t1 t2">`, 89 ".t1.fail", 90 []string{}, 91 }, 92 { 93 `<p class="t1 t2">`, 94 "p.t1.t2", 95 []string{ 96 `<p class="t1 t2"></p>`, 97 }, 98 }, 99 { 100 `<p><p title="title">`, 101 "p[title]", 102 []string{ 103 `<p title="title"></p>`, 104 }, 105 }, 106 { 107 `<address><address title="foo"><address title="bar">`, 108 `address[title="foo"]`, 109 []string{ 110 `<address title="foo"><address title="bar"></address></address>`, 111 }, 112 }, 113 { 114 `<address><address title="foo"><address title="bar">`, 115 `address[title!="foo"]`, 116 []string{ 117 `<address><address title="foo"><address title="bar"></address></address></address>`, 118 `<address title="bar"></address>`, 119 }, 120 }, 121 { 122 `<p title="tot foo bar">`, 123 `[ title ~= foo ]`, 124 []string{ 125 `<p title="tot foo bar"></p>`, 126 }, 127 }, 128 { 129 `<p title="hello world">`, 130 `[title~="hello world"]`, 131 []string{}, 132 }, 133 { 134 `<p lang="en"><p lang="en-gb"><p lang="enough"><p lang="fr-en">`, 135 `[lang|="en"]`, 136 []string{ 137 `<p lang="en"></p>`, 138 `<p lang="en-gb"></p>`, 139 }, 140 }, 141 { 142 `<p title="foobar"><p title="barfoo">`, 143 `[title^="foo"]`, 144 []string{ 145 `<p title="foobar"></p>`, 146 }, 147 }, 148 { 149 `<p title="foobar"><p title="barfoo">`, 150 `[title$="bar"]`, 151 []string{ 152 `<p title="foobar"></p>`, 153 }, 154 }, 155 { 156 `<p title="foobarufoo">`, 157 `[title*="bar"]`, 158 []string{ 159 `<p title="foobarufoo"></p>`, 160 }, 161 }, 162 { 163 `<input type="radio" name="Sex" value="F"/>`, 164 `input[name=Sex][value=F]`, 165 []string{ 166 `<input type="radio" name="Sex" value="F"/>`, 167 }, 168 }, 169 { 170 `<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>`, 171 `table[border="0"][cellpadding="0"][cellspacing="0"]`, 172 []string{ 173 `<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>`, 174 }, 175 }, 176 { 177 `<p class="t1 t2">`, 178 ".t1:not(.t2)", 179 []string{}, 180 }, 181 { 182 `<div class="t3">`, 183 `div:not(.t1)`, 184 []string{ 185 `<div class="t3"></div>`, 186 }, 187 }, 188 { 189 `<div><div class="t2"><div class="t3">`, 190 `div:not([class="t2"])`, 191 []string{ 192 `<div><div class="t2"><div class="t3"></div></div></div>`, 193 `<div class="t3"></div>`, 194 }, 195 }, 196 { 197 `<ol><li id=1><li id=2><li id=3></ol>`, 198 `li:nth-child(odd)`, 199 []string{ 200 `<li id="1"></li>`, 201 `<li id="3"></li>`, 202 }, 203 }, 204 { 205 `<ol><li id=1><li id=2><li id=3></ol>`, 206 `li:nth-child(even)`, 207 []string{ 208 `<li id="2"></li>`, 209 }, 210 }, 211 { 212 `<ol><li id=1><li id=2><li id=3></ol>`, 213 `li:nth-child(-n+2)`, 214 []string{ 215 `<li id="1"></li>`, 216 `<li id="2"></li>`, 217 }, 218 }, 219 { 220 `<ol><li id=1><li id=2><li id=3></ol>`, 221 `li:nth-child(3n+1)`, 222 []string{ 223 `<li id="1"></li>`, 224 }, 225 }, 226 { 227 `<ol><li id=1><li id=2><li id=3><li id=4></ol>`, 228 `li:nth-last-child(odd)`, 229 []string{ 230 `<li id="2"></li>`, 231 `<li id="4"></li>`, 232 }, 233 }, 234 { 235 `<ol><li id=1><li id=2><li id=3><li id=4></ol>`, 236 `li:nth-last-child(even)`, 237 []string{ 238 `<li id="1"></li>`, 239 `<li id="3"></li>`, 240 }, 241 }, 242 { 243 `<ol><li id=1><li id=2><li id=3><li id=4></ol>`, 244 `li:nth-last-child(-n+2)`, 245 []string{ 246 `<li id="3"></li>`, 247 `<li id="4"></li>`, 248 }, 249 }, 250 { 251 `<ol><li id=1><li id=2><li id=3><li id=4></ol>`, 252 `li:nth-last-child(3n+1)`, 253 []string{ 254 `<li id="1"></li>`, 255 `<li id="4"></li>`, 256 }, 257 }, 258 { 259 `<p>some text <span id="1">and a span</span><span id="2"> and another</span></p>`, 260 `span:first-child`, 261 []string{ 262 `<span id="1">and a span</span>`, 263 }, 264 }, 265 { 266 `<span>a span</span> and some text`, 267 `span:last-child`, 268 []string{ 269 `<span>a span</span>`, 270 }, 271 }, 272 { 273 `<address></address><p id=1><p id=2>`, 274 `p:nth-of-type(2)`, 275 []string{ 276 `<p id="2"></p>`, 277 }, 278 }, 279 { 280 `<address></address><p id=1><p id=2></p><a>`, 281 `p:nth-last-of-type(2)`, 282 []string{ 283 `<p id="1"></p>`, 284 }, 285 }, 286 { 287 `<address></address><p id=1><p id=2></p><a>`, 288 `p:last-of-type`, 289 []string{ 290 `<p id="2"></p>`, 291 }, 292 }, 293 { 294 `<address></address><p id=1><p id=2></p><a>`, 295 `p:first-of-type`, 296 []string{ 297 `<p id="1"></p>`, 298 }, 299 }, 300 { 301 `<div><p id="1"></p><a></a></div><div><p id="2"></p></div>`, 302 `p:only-child`, 303 []string{ 304 `<p id="2"></p>`, 305 }, 306 }, 307 { 308 `<div><p id="1"></p><a></a></div><div><p id="2"></p><p id="3"></p></div>`, 309 `p:only-of-type`, 310 []string{ 311 `<p id="1"></p>`, 312 }, 313 }, 314 { 315 `<p id="1"><!-- --><p id="2">Hello<p id="3"><span>`, 316 `:empty`, 317 []string{ 318 `<head></head>`, 319 `<p id="1"><!-- --></p>`, 320 `<span></span>`, 321 }, 322 }, 323 { 324 `<div><p id="1"><table><tr><td><p id="2"></table></div><p id="3">`, 325 `div p`, 326 []string{ 327 `<p id="1"><table><tbody><tr><td><p id="2"></p></td></tr></tbody></table></p>`, 328 `<p id="2"></p>`, 329 }, 330 }, 331 { 332 `<div><p id="1"><table><tr><td><p id="2"></table></div><p id="3">`, 333 `div table p`, 334 []string{ 335 `<p id="2"></p>`, 336 }, 337 }, 338 { 339 `<div><p id="1"><div><p id="2"></div><table><tr><td><p id="3"></table></div>`, 340 `div > p`, 341 []string{ 342 `<p id="1"></p>`, 343 `<p id="2"></p>`, 344 }, 345 }, 346 { 347 `<p id="1"><p id="2"></p><address></address><p id="3">`, 348 `p ~ p`, 349 []string{ 350 `<p id="2"></p>`, 351 `<p id="3"></p>`, 352 }, 353 }, 354 { 355 `<p id="1"></p> 356 <!--comment--> 357 <p id="2"></p><address></address><p id="3">`, 358 `p + p`, 359 []string{ 360 `<p id="2"></p>`, 361 }, 362 }, 363 { 364 `<ul><li></li><li></li></ul><p>`, 365 `li, p`, 366 []string{ 367 "<li></li>", 368 "<li></li>", 369 "<p></p>", 370 }, 371 }, 372 { 373 `<p id="1"><p id="2"></p><address></address><p id="3">`, 374 `p +/*This is a comment*/ p`, 375 []string{ 376 `<p id="2"></p>`, 377 }, 378 }, 379 { 380 `<p>Text block that <span>wraps inner text</span> and continues</p>`, 381 `p:contains("that wraps")`, 382 []string{ 383 `<p>Text block that <span>wraps inner text</span> and continues</p>`, 384 }, 385 }, 386 { 387 `<p>Text block that <span>wraps inner text</span> and continues</p>`, 388 `p:containsOwn("that wraps")`, 389 []string{}, 390 }, 391 { 392 `<p>Text block that <span>wraps inner text</span> and continues</p>`, 393 `:containsOwn("inner")`, 394 []string{ 395 `<span>wraps inner text</span>`, 396 }, 397 }, 398 { 399 `<p>Text block that <span>wraps inner text</span> and continues</p>`, 400 `p:containsOwn("block")`, 401 []string{ 402 `<p>Text block that <span>wraps inner text</span> and continues</p>`, 403 }, 404 }, 405 { 406 `<div id="d1"><p id="p1"><span>text content</span></p></div><div id="d2"/>`, 407 `div:has(#p1)`, 408 []string{ 409 `<div id="d1"><p id="p1"><span>text content</span></p></div>`, 410 }, 411 }, 412 { 413 `<div id="d1"><p id="p1"><span>contents 1</span></p></div> 414 <div id="d2"><p>contents <em>2</em></p></div>`, 415 `div:has(:containsOwn("2"))`, 416 []string{ 417 `<div id="d2"><p>contents <em>2</em></p></div>`, 418 }, 419 }, 420 { 421 `<body><div id="d1"><p id="p1"><span>contents 1</span></p></div> 422 <div id="d2"><p id="p2">contents <em>2</em></p></div></body>`, 423 `body :has(:containsOwn("2"))`, 424 []string{ 425 `<div id="d2"><p id="p2">contents <em>2</em></p></div>`, 426 `<p id="p2">contents <em>2</em></p>`, 427 }, 428 }, 429 { 430 `<body><div id="d1"><p id="p1"><span>contents 1</span></p></div> 431 <div id="d2"><p id="p2">contents <em>2</em></p></div></body>`, 432 `body :haschild(:containsOwn("2"))`, 433 []string{ 434 `<p id="p2">contents <em>2</em></p>`, 435 }, 436 }, 437 { 438 `<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`, 439 `p:matches([\d])`, 440 []string{ 441 `<p id="p1">0123456789</p>`, 442 `<p id="p3">0123ABCD</p>`, 443 }, 444 }, 445 { 446 `<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`, 447 `p:matches([a-z])`, 448 []string{ 449 `<p id="p2">abcdef</p>`, 450 }, 451 }, 452 { 453 `<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`, 454 `p:matches([a-zA-Z])`, 455 []string{ 456 `<p id="p2">abcdef</p>`, 457 `<p id="p3">0123ABCD</p>`, 458 }, 459 }, 460 { 461 `<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`, 462 `p:matches([^\d])`, 463 []string{ 464 `<p id="p2">abcdef</p>`, 465 `<p id="p3">0123ABCD</p>`, 466 }, 467 }, 468 { 469 `<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`, 470 `p:matches(^(0|a))`, 471 []string{ 472 `<p id="p1">0123456789</p>`, 473 `<p id="p2">abcdef</p>`, 474 `<p id="p3">0123ABCD</p>`, 475 }, 476 }, 477 { 478 `<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`, 479 `p:matches(^\d+$)`, 480 []string{ 481 `<p id="p1">0123456789</p>`, 482 }, 483 }, 484 { 485 `<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`, 486 `p:not(:matches(^\d+$))`, 487 []string{ 488 `<p id="p2">abcdef</p>`, 489 `<p id="p3">0123ABCD</p>`, 490 }, 491 }, 492 { 493 `<div><p id="p1">01234<em>567</em>89</p><div>`, 494 `div :matchesOwn(^\d+$)`, 495 []string{ 496 `<p id="p1">01234<em>567</em>89</p>`, 497 `<em>567</em>`, 498 }, 499 }, 500 { 501 `<ul> 502 <li><a id="a1" href="http://www.google.com/finance"></a> 503 <li><a id="a2" href="http://finance.yahoo.com/"></a> 504 <li><a id="a2" href="http://finance.untrusted.com/"/> 505 <li><a id="a3" href="https://www.google.com/news"/> 506 <li><a id="a4" href="http://news.yahoo.com"/> 507 </ul>`, 508 `[href#=(fina)]:not([href#=(\/\/[^\/]+untrusted)])`, 509 []string{ 510 `<a id="a1" href="http://www.google.com/finance"></a>`, 511 `<a id="a2" href="http://finance.yahoo.com/"></a>`, 512 }, 513 }, 514 { 515 `<ul> 516 <li><a id="a1" href="http://www.google.com/finance"/> 517 <li><a id="a2" href="http://finance.yahoo.com/"/> 518 <li><a id="a3" href="https://www.google.com/news"></a> 519 <li><a id="a4" href="http://news.yahoo.com"/> 520 </ul>`, 521 `[href#=(^https:\/\/[^\/]*\/?news)]`, 522 []string{ 523 `<a id="a3" href="https://www.google.com/news"></a>`, 524 }, 525 }, 526 { 527 `<form> 528 <label>Username <input type="text" name="username" /></label> 529 <label>Password <input type="password" name="password" /></label> 530 <label>Country 531 <select name="country"> 532 <option value="ca">Canada</option> 533 <option value="us">United States</option> 534 </select> 535 </label> 536 <label>Bio <textarea name="bio"></textarea></label> 537 <button>Sign up</button> 538 </form>`, 539 `:input`, 540 []string{ 541 `<input type="text" name="username"/>`, 542 `<input type="password" name="password"/>`, 543 `<select name="country"> 544 <option value="ca">Canada</option> 545 <option value="us">United States</option> 546 </select>`, 547 `<textarea name="bio"></textarea>`, 548 `<button>Sign up</button>`, 549 }, 550 }, 551 }