layout/style/test/test_selectors.html

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 <!DOCTYPE HTML>
     2 <html>
     3 <head>
     4   <title>Test for CSS Selectors</title>
     5   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
     6   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
     7 </head>
     8 <body onload="run()">
     9 <p id="display"><iframe id="iframe" src="about:blank"></iframe><iframe id="cloneiframe" src="about:blank"></iframe></p>
    10 <pre id="test">
    11 <script class="testbody" type="text/javascript">
    13 SimpleTest.waitForExplicitFinish();
    15 var cloneiframe;
    17 function run() {
    19     var iframe = document.getElementById("iframe");
    20     var ifwin = iframe.contentWindow;
    21     var ifdoc = iframe.contentDocument;
    23     cloneiframe = document.getElementById("cloneiframe");
    25     var style_elem = ifdoc.createElement("style");
    26     style_elem.setAttribute("type", "text/css");
    27     ifdoc.getElementsByTagName("head")[0].appendChild(style_elem);
    28     var style_text = ifdoc.createTextNode("");
    29     style_elem.appendChild(style_text);
    31     var gCounter = 0;
    33     /*
    34      * selector: the selector to test
    35      * body_contents: what to set the body's innerHTML to
    36      * match_fn: a function that, given the document object into which
    37      *   body_contents has been inserted, produces an array of nodes that
    38      *   should match selector
    39      * notmatch_fn: likewise, but for nodes that should not match
    40      * namespaces (optional): @namespace rules to be included in the sheet
    41      */
    42     function test_selector_in_html(selector, body_contents, match_fn, notmatch_fn, namespaces)
    43     {
    44         var zi = ++gCounter;
    45         if (typeof(body_contents) == "string") {
    46             ifdoc.body.innerHTML = body_contents;
    47         } else {
    48             // It's a function.
    49             ifdoc.body.innerHTML = "";
    50             body_contents(ifdoc.body);
    51         }
    52         if (!namespaces) {
    53             namespaces = "";
    54         }
    55         style_text.data = namespaces + selector + "{ z-index: " + zi + " }";
    57         var idx = style_text.parentNode.sheet.cssRules.length - 1;
    58         if (namespaces == "") {
    59             is(idx, 0, "unexpected rule index");
    60         }
    61         if (idx < 0 ||
    62             style_text.parentNode.sheet.cssRules[idx].type !=
    63                 CSSRule.STYLE_RULE)
    64         {
    65             ok(false, "selector " + selector + " could not be parsed");
    66             return;
    67         }
    69         var should_match = match_fn(ifdoc);
    70         var should_not_match = notmatch_fn(ifdoc);
    71         if (should_match.length + should_not_match.length == 0) {
    72             ok(false, "nothing to check");
    73         }
    75         for (var i = 0; i < should_match.length; ++i) {
    76             var e = should_match[i];
    77             is(ifwin.getComputedStyle(e, "").zIndex, zi,
    78                "element in " + body_contents + " matched " + selector);
    79         }
    80         for (var i = 0; i < should_not_match.length; ++i) {
    81             var e = should_not_match[i];
    82             is(ifwin.getComputedStyle(e, "").zIndex, "auto",
    83                "element in " + body_contents + " did not match " + selector);
    84         }
    86         // Now, since we're here, may as well make sure serialization
    87         // works correctly.  It need not produce the exact same text,
    88         // but it should produce a selector that matches the same
    89         // elements.
    90         zi = ++gCounter;
    91         var ser1 = style_text.parentNode.sheet.cssRules[idx].selectorText;
    92         style_text.data = namespaces + ser1 + "{ z-index: " + zi + " }";
    93         for (var i = 0; i < should_match.length; ++i) {
    94             var e = should_match[i];
    95             is(ifwin.getComputedStyle(e, "").zIndex, zi,
    96                "element in " + body_contents + " matched " + ser1 +
    97                " which is the reserialization of " + selector);
    98         }
    99         for (var i = 0; i < should_not_match.length; ++i) {
   100             var e = should_not_match[i];
   101             is(ifwin.getComputedStyle(e, "").zIndex, "auto",
   102                "element in " + body_contents + " did not match " + ser1 +
   103                " which is the reserialization of " + selector);
   104         }
   106         // But when we serialize the serialized result, we should get
   107         // the same text.
   108         var ser2 = style_text.parentNode.sheet.cssRules[idx].selectorText;
   109         is(ser2, ser1, "parse+serialize of selector \"" + selector +
   110                        "\" is idempotent");
   112         ifdoc.body.innerHTML = "";
   113         style_text.data = "";
   115         // And now test that when we clone the style sheet, we end up
   116         // with the same selector (serializes to same string, and
   117         // matches the same things).
   118         zi = ++gCounter;
   119         var style_sheet = "data:text/css," +
   120             escape(namespaces + selector + "{ z-index: " + zi + " }");
   121         var style_sheet_link =
   122             "<link rel='stylesheet' href='" + style_sheet + "'>";
   123         var html_doc = "<!DOCTYPE HTML>" +
   124                        style_sheet_link + style_sheet_link +
   125                        "<body>";
   126         if (typeof(body_contents) == "string") {
   127             html_doc += body_contents;
   128         }
   129         var docurl = "data:text/html," + escape(html_doc);
   130         defer_clonedoc_tests(docurl, function() {
   131             var clonedoc = cloneiframe.contentDocument;
   132             var clonewin = cloneiframe.contentWindow;
   134             if (typeof(body_contents) != "string") {
   135                 body_contents(clonedoc.body);
   136             }
   138             var links = clonedoc.getElementsByTagName("link");
   139             // cause a clone
   140             links[1].sheet.insertRule("#nonexistent { color: purple}", idx + 1);
   141             // remove the uncloned sheet
   142             links[0].parentNode.removeChild(links[0]);
   144             var should_match = match_fn(clonedoc);
   145             var should_not_match = notmatch_fn(clonedoc);
   147             if (should_match.length + should_not_match.length == 0) {
   148                 ok(false, "nothing to check");
   149             }
   151             for (var i = 0; i < should_match.length; ++i) {
   152                 var e = should_match[i];
   153                 is(clonewin.getComputedStyle(e, "").zIndex, zi,
   154                    "element in " + body_contents + " matched clone of " +
   155                    selector);
   156             }
   157             for (var i = 0; i < should_not_match.length; ++i) {
   158                 var e = should_not_match[i];
   159                 is(clonewin.getComputedStyle(e, "").zIndex, "auto",
   160                    "element in " + body_contents + " did not match clone of " +
   161                    selector);
   162             }
   164             var ser3 = links[0].sheet.cssRules[idx].selectorText;
   165             is(ser3, ser1,
   166                "selector " + selector + " serializes correctly after cloning");
   167         });
   168     }
   170     function should_serialize_to(selector, serialization)
   171     {
   172         style_text.data = selector + "{ z-index: 0 }";
   173         is(style_text.parentNode.sheet.cssRules[0].selectorText,
   174            serialization,
   175            "selector '" + selector + "' should serialize to '" +
   176              serialization + "'.");
   177     }
   179     function test_parseable(selector)
   180     {
   181         ifdoc.body.innerHTML = "<p></p>";
   183         var zi = ++gCounter;
   184         style_text.data = "p, " + selector + "{ z-index: " + zi + " }";
   185         var should_match = ifdoc.getElementsByTagName("p")[0];
   186         var parsed = ifwin.getComputedStyle(should_match, "").zIndex == zi;
   187         ok(parsed, "selector " + selector + " was parsed");
   188         if (!parsed) {
   189             return;
   190         }
   192         // Test that it serializes to something that is also parseable.
   193         var ser1 = style_elem.sheet.cssRules[0].selectorText;
   194         zi = ++gCounter;
   195         style_text.data = ser1 + "{ z-index: " + zi + " }";
   196         is(ifwin.getComputedStyle(should_match, "").zIndex, zi,
   197            "serialization " + ser1 + " of selector p, " + selector +
   198            " was parsed");
   199         var ser2 = style_elem.sheet.cssRules[0].selectorText;
   200         is(ser2, ser1,
   201            "parse+serialize of selector " + selector + " is idempotent");
   203         ifdoc.body.innerHTML = "";
   204         style_text.data = "";
   206         // Test that it clones to the same thing it serializes to.
   207         zi = ++gCounter;
   208         var style_sheet = "data:text/css," +
   209                           escape("p, " + selector + "{ z-index: " + zi + " }");
   210         var style_sheet_link =
   211             "<link rel='stylesheet' href='" + style_sheet + "'>";
   212         var html_doc = "<!DOCTYPE HTML>" +
   213                        style_sheet_link + style_sheet_link +
   214                        "<p></p>";
   215         var docurl = "data:text/html," + escape(html_doc);
   217         defer_clonedoc_tests(docurl, function() {
   218             var clonedoc = cloneiframe.contentDocument;
   219             var clonewin = cloneiframe.contentWindow;
   220             var links = clonedoc.getElementsByTagName("link");
   221             // cause a clone
   222             links[1].sheet.insertRule("#nonexistent { color: purple}", 0);
   223             // remove the uncloned sheet
   224             links[0].parentNode.removeChild(links[0]);
   226             should_match = clonedoc.getElementsByTagName("p")[0];
   227             is(clonewin.getComputedStyle(should_match, "").zIndex, zi,
   228                "selector " + selector + " was cloned correctly");
   229             var ser3 = links[0].sheet.cssRules[1].selectorText;
   230             is(ser3, ser1,
   231                "selector " + selector + " serializes correctly after cloning");
   232         });
   233     }
   235     function test_unparseable_via_api(selector)
   236     {
   237         try {
   238           // Test that it is also unparseable when followed by EOF.
   239           ifdoc.body.mozMatchesSelector(selector);
   240           ok(false, "selector '" + selector + "' plus EOF is parse error");
   241         } catch(ex) {
   242           is(ex.name, "SyntaxError",
   243              "selector '" + selector + "' plus EOF is parse error");
   244           is(ex.code, DOMException.SYNTAX_ERR,
   245              "selector '" + selector + "' plus EOF is parse error");
   246         }
   247     }
   249     function test_parseable_via_api(selector)
   250     {
   251         var threw = false;
   252         try {
   253           // Test that a selector is parseable when followed by EOF.
   254           ifdoc.body.mozMatchesSelector(selector);
   255         } catch(ex) {
   256           threw = true;
   257         }
   258         ok(!threw, "selector '" + selector + "' was parsed");
   259     }
   261     function test_balanced_unparseable(selector)
   262     {
   263         var zi1 = ++gCounter;
   264         var zi2 = ++gCounter;
   265         ifdoc.body.innerHTML = "<p></p><div></div>";
   266         style_text.data = "p, " + selector + "{ z-index: " + zi1 + " }" +
   267                           "div { z-index: " + zi2 + " }";
   268         var should_not_match = ifdoc.getElementsByTagName("p")[0];
   269         var should_match = ifdoc.getElementsByTagName("div")[0];
   270         is(ifwin.getComputedStyle(should_not_match, "").zIndex, "auto",
   271            "selector " + selector + " was a parser error");
   272         is(ifwin.getComputedStyle(should_match, "").zIndex, zi2,
   273            "selector " + selector + " error was recovered from");
   274         ifdoc.body.innerHTML = "";
   275         style_text.data = "";
   276         test_unparseable_via_api(selector);
   277     }
   279     function test_unbalanced_unparseable(selector)
   280     {
   281         var zi1 = ++gCounter;
   282         var zi2 = ++gCounter;
   283         ifdoc.body.innerHTML = "<p></p>";
   284         style_text.data = "p, " + selector + "{ z-index: " + zi1 + " }";
   285         var should_not_match = ifdoc.getElementsByTagName("p")[0];
   286         is(ifwin.getComputedStyle(should_not_match, "").zIndex, "auto",
   287            "selector " + selector + " was a parser error");
   288         is(style_text.parentNode.sheet.cssRules.length, 0,
   289            "sheet should have no rules since " + selector + " is parse error");
   290         ifdoc.body.innerHTML = "";
   291         style_text.data = "";
   292         test_unparseable_via_api(selector);
   293     }
   296     // [attr= ] selector
   297     test_parseable("[attr=\"x\"]");
   298     test_parseable("[attr='x']");
   299     test_parseable("[attr=x]");
   300     test_parseable("[attr=\"\"]");
   301     test_parseable("[attr='']");
   302     test_parseable("[attr=\"foo bar\"]");
   304     test_balanced_unparseable("[attr=]");
   305     test_balanced_unparseable("[attr=foo bar]");
   307     test_selector_in_html(
   308         '[title=""]',
   309         '<p title=""></p>'
   310         + '<div lang=" "></div><div lang="\t"></div><div lang="\n"></div>',
   311         function(doc) { return doc.getElementsByTagName("p"); },
   312         function(doc) { return doc.getElementsByTagName("div"); }
   313     );
   315     // [attr~= ] selector
   316     test_parseable("[attr~=\"x\"]");
   317     test_parseable("[attr~='x']");
   318     test_parseable("[attr~=x]");
   319     test_parseable("[attr~=\"\"]");
   320     test_parseable("[attr~='']");
   321     test_parseable("[attr~=\"foo bar\"]");
   323     test_balanced_unparseable("[attr~=]");
   324     test_balanced_unparseable("[attr~=foo bar]");
   326     test_selector_in_html(
   327         '[class~="x x"]',
   328         '<div class="x x"></div><div class="x"></div><div class="x\tx"></div>div class="x\nx"></div>',
   329         function(doc) { return []; },
   330         function(doc) { return doc.getElementsByTagName("div"); }
   331     );
   333     // [attr|="x"]
   334     test_parseable('[attr|="x"]');
   335     test_parseable("[attr|='x']");
   336     test_parseable('[attr|=x]');
   338     test_parseable('[attr|=""]');
   339     test_parseable("[attr|='']");
   340     test_balanced_unparseable('[attr|=]');
   342     test_selector_in_html(
   343         '[lang|=""]',
   344         '<p lang=""></p><p lang="-"></p><p lang="-GB"></p>'
   345         + '<div lang="en-GB"></div><div lang="en-"></div>',
   346         function(doc) { return doc.getElementsByTagName("p"); },
   347         function(doc) { return doc.getElementsByTagName("div"); }
   348     );
   350     // [attr$= ] selector
   351     test_parseable("[attr$=\"x\"]");
   352     test_parseable("[attr$='x']");
   353     test_parseable("[attr$=x]");
   354     test_parseable("[attr$=\"\"]");
   355     test_parseable("[attr$='']");
   356     test_parseable("[attr$=\"foo bar\"]");
   358     test_balanced_unparseable("[attr$=]");
   359     test_balanced_unparseable("[attr$=foo bar]");
   361     // [attr^= ] selector
   362     test_parseable("[attr^=\"x\"]");
   363     test_parseable("[attr^='x']");
   364     test_parseable("[attr^=x]");
   365     test_parseable("[attr^=\"\"]");
   366     test_parseable("[attr^='']");
   367     test_parseable("[attr^=\"foo bar\"]");
   369     test_balanced_unparseable("[attr^=]");
   370     test_balanced_unparseable("[attr^=foo bar]");
   372     // attr[*= ] selector
   373     test_parseable("[attr*=\"x\"]");
   374     test_parseable("[attr*='x']");
   375     test_parseable("[attr*=x]");
   376     test_parseable("[attr*=\"\"]");
   377     test_parseable("[attr*='']");
   378     test_parseable("[attr*=\"foo bar\"]");
   380     test_balanced_unparseable("[attr*=]");
   381     test_balanced_unparseable("[attr*=foo bar]");
   384     // Bug 420814
   385     test_selector_in_html(
   386         "div ~ div p",
   387         "<div></div><div><div><p>match</p></div></div>",
   388         function(doc) { return doc.getElementsByTagName("p"); },
   389         function(doc) { return []; }
   390     );
   392     // Bug 420245
   393     test_selector_in_html(
   394         "p[attr$=\"\"]",
   395         "<p attr=\"foo\">This should not match</p>",
   396         function(doc) { return []; },
   397         function(doc) { return doc.getElementsByTagName("p"); }
   398     );
   399     test_selector_in_html(
   400         "div + p[attr~=\"\"]",
   401         "<div>Dummy</div><p attr=\"foo\">This should not match</p>",
   402         function(doc) { return []; },
   403         function(doc) { return doc.getElementsByTagName("p"); }
   404     );
   405     test_selector_in_html(
   406         "div[attr^=\"\"]",
   407         "<div attr=\"dummy1\">Dummy</div><div attr=\"dummy2\">Dummy</div>",
   408         function(doc) { return []; },
   409         function(doc) { return doc.getElementsByTagName("div"); }
   410     );
   411     test_selector_in_html(
   412         "div[attr*=\"\"]",
   413         "<div attr=\"dummy1\">Dummy</div><div attr=\"dummy2\">Dummy</div>",
   414         function(doc) { return []; },
   415         function(doc) { return doc.getElementsByTagName("div"); }
   416     );
   418     // :nth-child(), etc.
   419     // Follow the whitespace rules as proposed in
   420     // http://lists.w3.org/Archives/Public/www-style/2008Mar/0121.html
   421     test_balanced_unparseable(":nth-child()");
   422     test_balanced_unparseable(":nth-of-type( )");
   423     test_parseable(":nth-last-child( odd)");
   424     test_parseable(":nth-last-of-type(even )");
   425     test_parseable(":nth-child(n )");
   426     test_parseable(":nth-of-type( 2n)");
   427     test_parseable(":nth-last-child( -n)");
   428     test_parseable(":nth-last-of-type(-2n )");
   429     test_balanced_unparseable(":nth-child(- n)");
   430     test_balanced_unparseable(":nth-of-type(-2 n)");
   431     test_balanced_unparseable(":nth-last-of-type(2n1)");
   432     test_balanced_unparseable(":nth-child(2n++1)");
   433     test_balanced_unparseable(":nth-of-type(2n-+1)");
   434     test_balanced_unparseable(":nth-last-child(2n+-1)");
   435     test_balanced_unparseable(":nth-last-of-type(2n--1)");
   436     test_parseable(":nth-child( 3n + 1 )");
   437     test_parseable(":nth-child( +3n - 2 )");
   438     test_parseable(":nth-child( -n+ 6)");
   439     test_parseable(":nth-child( +6 )");
   440     test_balanced_unparseable(":nth-child(3 n)");
   441     test_balanced_unparseable(":nth-child(+ 2n)");
   442     test_balanced_unparseable(":nth-child(+ 2)");
   443     test_parseable(":nth-child(3)");
   444     test_parseable(":nth-of-type(-3)");
   445     test_parseable(":nth-last-child(+3)");
   446     test_parseable(":nth-last-of-type(0)");
   447     test_parseable(":nth-child(-0)");
   448     test_parseable(":nth-of-type(3n)");
   449     test_parseable(":nth-last-child(-3n)");
   450     test_parseable(":nth-last-of-type(+3n)");
   451     test_parseable(":nth-last-of-type(0n)");
   452     test_parseable(":nth-child(-0n)");
   453     test_parseable(":nth-of-type(n)");
   454     test_parseable(":nth-last-child(-n)");
   455     test_parseable(":nth-last-of-type(2n+1)");
   456     test_parseable(":nth-child(2n-1)");
   457     test_parseable(":nth-of-type(2n+0)");
   458     test_parseable(":nth-last-child(2n-0)");
   459     test_parseable(":nth-child(-0n+0)");
   460     test_parseable(":nth-of-type(n+1)");
   461     test_parseable(":nth-last-child(n-1)");
   462     test_parseable(":nth-last-of-type(-n+1)");
   463     test_parseable(":nth-child(-n-1)");
   464     test_balanced_unparseable(":nth-child(2-n)");
   465     test_balanced_unparseable(":nth-child(2-n-1)");
   466     test_balanced_unparseable(":nth-child(n-2-1)");
   467     // Bug 750388
   468     test_parseable(":nth-child(+n)");
   469     test_balanced_unparseable(":nth-child(+ n)");
   470     test_parseable(":nth-child(+n+2)");
   471     test_parseable(":nth-child(+n-2)");
   472     test_parseable(":nth-child(+n + 2)");
   473     test_parseable(":nth-child(+n - 2)");
   474     test_balanced_unparseable(":nth-child(+ n+2)");
   475     test_balanced_unparseable(":nth-child(+ n-2)");
   476     test_balanced_unparseable(":nth-child(+ n + 2)");
   477     test_balanced_unparseable(":nth-child(+ n - 2)");
   478     test_parseable(":nth-child(+n-100)");
   479     test_parseable(":nth-child(+n - 100)");
   480     test_balanced_unparseable(":nth-child(+ n-100)");
   481     test_balanced_unparseable(":nth-child(+-n+2)");
   482     test_balanced_unparseable(":nth-child(+ -n+2)");
   483     test_balanced_unparseable(":nth-child(+-n-100)");
   484     test_balanced_unparseable(":nth-child(+ -n-100)");
   485     test_balanced_unparseable(":nth-child(++n-100)");
   486     test_balanced_unparseable(":nth-child(-+n-100)");
   487     test_balanced_unparseable(":nth-child(++2n - 100)");
   488     test_balanced_unparseable(":nth-child(+-2n - 100)");
   489     test_balanced_unparseable(":nth-child(-+2n - 100)");
   490     test_balanced_unparseable(":nth-child(--2n - 100)");
   491     test_balanced_unparseable(":nth-child(+/**/+2n - 100)");
   492     test_balanced_unparseable(":nth-child(+/**/-2n - 100)");
   493     test_balanced_unparseable(":nth-child(-/**/+2n - 100)");
   494     test_balanced_unparseable(":nth-child(-/**/-2n - 100)");
   495     test_balanced_unparseable(":nth-child(+/**/+/**/2n - 100)");
   496     test_balanced_unparseable(":nth-child(+/**/-/**/2n - 100)");
   497     test_balanced_unparseable(":nth-child(-/**/+/**/2n - 100)");
   498     test_balanced_unparseable(":nth-child(-/**/-/**/2n - 100)");
   499     test_balanced_unparseable(":nth-child(++/**/2n - 100)");
   500     test_balanced_unparseable(":nth-child(+-/**/2n - 100)");
   501     test_balanced_unparseable(":nth-child(-+/**/2n - 100)");
   502     test_balanced_unparseable(":nth-child(--/**/2n - 100)");
   503     test_balanced_unparseable(":nth-child(-even)");
   504     test_balanced_unparseable(":nth-child(-odd)");
   505     test_balanced_unparseable(":nth-child(+even)");
   506     test_balanced_unparseable(":nth-child(+odd)");
   507     test_balanced_unparseable(":nth-child(+ even)");
   508     test_balanced_unparseable(":nth-child(+ odd)");
   509     test_balanced_unparseable(":nth-child(+-n)");
   510     test_balanced_unparseable(":nth-child(+-n-)");
   511     test_balanced_unparseable(":nth-child(-+n)");
   512     test_balanced_unparseable(":nth-child(+n--)");
   513     test_parseable(":nth-child(n+2)");
   514     test_parseable(":nth-child(n/**/+/**/2)");
   515     test_parseable(":nth-child(n-2)");
   516     test_parseable(":nth-child(n/**/-/**/2)");
   517     test_balanced_unparseable(":nth-child(n++2)");
   518     test_balanced_unparseable(":nth-child(n+-2)");
   519     test_balanced_unparseable(":nth-child(n-+2)");
   520     test_balanced_unparseable(":nth-child(n--2)");
   521     test_balanced_unparseable(":nth-child(n/**/++2)");
   522     test_balanced_unparseable(":nth-child(n/**/+-2)");
   523     test_balanced_unparseable(":nth-child(n/**/-+2)");
   524     test_balanced_unparseable(":nth-child(n/**/--2)");
   525     test_balanced_unparseable(":nth-child(n/**/+/**/+2)");
   526     test_balanced_unparseable(":nth-child(n/**/+/**/-2)");
   527     test_balanced_unparseable(":nth-child(n/**/-/**/+2)");
   528     test_balanced_unparseable(":nth-child(n/**/-/**/-2)");
   529     test_balanced_unparseable(":nth-child(n+/**/+2)");
   530     test_balanced_unparseable(":nth-child(n+/**/-2)");
   531     test_balanced_unparseable(":nth-child(n-/**/+2)");
   532     test_balanced_unparseable(":nth-child(n-/**/-2)");
   533     test_balanced_unparseable(":nth-child(n++/**/2)");
   534     test_balanced_unparseable(":nth-child(n+-/**/2)");
   535     test_balanced_unparseable(":nth-child(n-+/**/2)");
   536     test_balanced_unparseable(":nth-child(n--/**/2)");
   537     test_balanced_unparseable(":nth-child(n/**/++/**/2)");
   538     test_balanced_unparseable(":nth-child(n/**/+-/**/2)");
   539     test_balanced_unparseable(":nth-child(n/**/-+/**/2)");
   540     test_balanced_unparseable(":nth-child(n/**/--/**/2)");
   541     test_balanced_unparseable(":nth-child(n/**/+/**/+/**/2)");
   542     test_balanced_unparseable(":nth-child(n/**/+/**/-/**/2)");
   543     test_balanced_unparseable(":nth-child(n/**/-/**/+/**/2)");
   544     test_balanced_unparseable(":nth-child(n/**/-/**/-/**/2)");
   545     test_balanced_unparseable(":nth-child(n+/**/+/**/2)");
   546     test_balanced_unparseable(":nth-child(n+/**/-/**/2)");
   547     test_balanced_unparseable(":nth-child(n-/**/+/**/2)");
   548     test_balanced_unparseable(":nth-child(n-/**/-/**/2)");
   549     test_parseable(":nth-child(2n+2)");
   550     test_parseable(":nth-child(2n/**/+/**/2)");
   551     test_parseable(":nth-child(2n-2)");
   552     test_parseable(":nth-child(2n/**/-/**/2)");
   553     test_balanced_unparseable(":nth-child(2n++2)");
   554     test_balanced_unparseable(":nth-child(2n+-2)");
   555     test_balanced_unparseable(":nth-child(2n-+2)");
   556     test_balanced_unparseable(":nth-child(2n--2)");
   557     test_balanced_unparseable(":nth-child(2n/**/++2)");
   558     test_balanced_unparseable(":nth-child(2n/**/+-2)");
   559     test_balanced_unparseable(":nth-child(2n/**/-+2)");
   560     test_balanced_unparseable(":nth-child(2n/**/--2)");
   561     test_balanced_unparseable(":nth-child(2n/**/+/**/+2)");
   562     test_balanced_unparseable(":nth-child(2n/**/+/**/-2)");
   563     test_balanced_unparseable(":nth-child(2n/**/-/**/+2)");
   564     test_balanced_unparseable(":nth-child(2n/**/-/**/-2)");
   565     test_balanced_unparseable(":nth-child(2n+/**/+2)");
   566     test_balanced_unparseable(":nth-child(2n+/**/-2)");
   567     test_balanced_unparseable(":nth-child(2n-/**/+2)");
   568     test_balanced_unparseable(":nth-child(2n-/**/-2)");
   569     test_balanced_unparseable(":nth-child(2n++/**/2)");
   570     test_balanced_unparseable(":nth-child(2n+-/**/2)");
   571     test_balanced_unparseable(":nth-child(2n-+/**/2)");
   572     test_balanced_unparseable(":nth-child(2n--/**/2)");
   573     test_balanced_unparseable(":nth-child(2n/**/++/**/2)");
   574     test_balanced_unparseable(":nth-child(2n/**/+-/**/2)");
   575     test_balanced_unparseable(":nth-child(2n/**/-+/**/2)");
   576     test_balanced_unparseable(":nth-child(2n/**/--/**/2)");
   577     test_balanced_unparseable(":nth-child(2n/**/+/**/+/**/2)");
   578     test_balanced_unparseable(":nth-child(2n/**/+/**/-/**/2)");
   579     test_balanced_unparseable(":nth-child(2n/**/-/**/+/**/2)");
   580     test_balanced_unparseable(":nth-child(2n/**/-/**/-/**/2)");
   581     test_balanced_unparseable(":nth-child(2n+/**/+/**/2)");
   582     test_balanced_unparseable(":nth-child(2n+/**/-/**/2)");
   583     test_balanced_unparseable(":nth-child(2n-/**/+/**/2)");
   584     test_balanced_unparseable(":nth-child(2n-/**/-/**/2)");
   585     test_parseable(":nth-child(+/**/n+2)");
   586     test_parseable(":nth-child(+n/**/+2)");
   587     test_parseable(":nth-child(+n/**/+2)");
   588     test_parseable(":nth-child(+n+/**/2)");
   589     test_parseable(":nth-child(+n+2/**/)");
   590     test_parseable(":nth-child(+1/**/n+2)");
   591     test_parseable(":nth-child(+1n/**/+2)");
   592     test_parseable(":nth-child(+1n/**/+2)");
   593     test_parseable(":nth-child(+1n+/**/2)");
   594     test_parseable(":nth-child(+1n+2/**/)");
   595     test_parseable(":nth-child(-/**/n+2)");
   596     test_parseable(":nth-child(-n/**/+2)");
   597     test_parseable(":nth-child(-n/**/+2)");
   598     test_parseable(":nth-child(-n+/**/2)");
   599     test_parseable(":nth-child(-n+2/**/)");
   600     test_parseable(":nth-child(-1/**/n+2)");
   601     test_parseable(":nth-child(-1n/**/+2)");
   602     test_parseable(":nth-child(-1n/**/+2)");
   603     test_parseable(":nth-child(-1n+/**/2)");
   604     test_parseable(":nth-child(-1n+2/**/)");
   605     test_balanced_unparseable(":nth-child(-/**/ n+2)");
   606     test_balanced_unparseable(":nth-child(- /**/n+2)");
   607     test_balanced_unparseable(":nth-child(+/**/ n+2)");
   608     test_balanced_unparseable(":nth-child(+ /**/n+2)");
   609     test_parseable(":nth-child(+/**/n-2)");
   610     test_parseable(":nth-child(+n/**/-2)");
   611     test_parseable(":nth-child(+n/**/-2)");
   612     test_parseable(":nth-child(+n-/**/2)");
   613     test_parseable(":nth-child(+n-2/**/)");
   614     test_parseable(":nth-child(+1/**/n-2)");
   615     test_parseable(":nth-child(+1n/**/-2)");
   616     test_parseable(":nth-child(+1n/**/-2)");
   617     test_parseable(":nth-child(+1n-/**/2)");
   618     test_parseable(":nth-child(+1n-2/**/)");
   619     test_parseable(":nth-child(-/**/n-2)");
   620     test_parseable(":nth-child(-n/**/-2)");
   621     test_parseable(":nth-child(-n/**/-2)");
   622     test_parseable(":nth-child(-n-/**/2)");
   623     test_parseable(":nth-child(-n-2/**/)");
   624     test_parseable(":nth-child(-1/**/n-2)");
   625     test_parseable(":nth-child(-1n/**/-2)");
   626     test_parseable(":nth-child(-1n/**/-2)");
   627     test_parseable(":nth-child(-1n-/**/2)");
   628     test_parseable(":nth-child(-1n-2/**/)");
   629     test_balanced_unparseable(":nth-child(-/**/ n-2)");
   630     test_balanced_unparseable(":nth-child(- /**/n-2)");
   631     test_balanced_unparseable(":nth-child(+/**/ n-2)");
   632     test_balanced_unparseable(":nth-child(+ /**/n-2)");
   633     test_parseable(":nth-child( +n + 1 )");
   634     test_parseable(":nth-child( +/**/n + 1 )");
   635     test_parseable(":nth-child( -/**/2/**/n/**/+/**/4 )");
   636     test_balanced_unparseable(":nth-child( -/**/ 2/**/n/**/+/**/4 )");
   637     test_balanced_unparseable(":nth-child( -/**/2 /**/n/**/+/**/4 )");
   638     test_balanced_unparseable(":nth-child( -/**/2/**/ n/**/+/**/4 )");
   639     test_parseable(":nth-child( -/**/2/**/n /**/+/**/4 )");
   640     test_parseable(":nth-child( -/**/2/**/n/**/ +/**/4 )");
   641     test_parseable(":nth-child(+1/**/n-1)");
   642     test_parseable(":nth-child(1/**/n-1)");
   643     // bug 876570
   644     test_balanced_unparseable(":nth-child(+2n-)");
   645     test_balanced_unparseable(":nth-child(+n-)");
   646     test_balanced_unparseable(":nth-child(-2n-)");
   647     test_balanced_unparseable(":nth-child(-n-)");
   648     test_balanced_unparseable(":nth-child(2n-)");
   649     test_balanced_unparseable(":nth-child(n-)");
   650     test_balanced_unparseable(":nth-child(+2n+)");
   651     test_balanced_unparseable(":nth-child(+n+)");
   652     test_balanced_unparseable(":nth-child(-2n+)");
   653     test_balanced_unparseable(":nth-child(-n+)");
   654     test_balanced_unparseable(":nth-child(2n+)");
   655     test_balanced_unparseable(":nth-child(n+)");
   657     // exercise the an+b matching logic particularly hard for
   658     // :nth-child() (since we know we use the same code for all 4)
   659     var seven_ps = "<p></p><p></p><p></p><p></p><p></p><p></p><p></p>";
   660     function pset(indices) { // takes an array of 1-based indices
   661         return function pset_filter(doc) {
   662             var a = doc.getElementsByTagName("p");
   663             var result = [];
   664             for (var i in indices)
   665                 result.push(a[indices[i] - 1]);
   666             return result;
   667         }
   668     }
   669     test_selector_in_html(":nth-child(0)", seven_ps,
   670                           pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
   671     test_selector_in_html(":nth-child(-3)", seven_ps,
   672                           pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
   673     test_selector_in_html(":nth-child(3)", seven_ps,
   674                           pset([3]), pset([1, 2, 4, 5, 6, 7]));
   675     test_selector_in_html(":nth-child(0n+3)", seven_ps,
   676                           pset([3]), pset([1, 2, 4, 5, 6, 7]));
   677     test_selector_in_html(":nth-child(-0n+3)", seven_ps,
   678                           pset([3]), pset([1, 2, 4, 5, 6, 7]));
   679     test_selector_in_html(":nth-child(8)", seven_ps,
   680                           pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
   681     test_selector_in_html(":nth-child(odd)", seven_ps,
   682                           pset([1, 3, 5, 7]), pset([2, 4, 6]));
   683     test_selector_in_html(":nth-child(even)", seven_ps,
   684                           pset([2, 4, 6]), pset([1, 3, 5, 7]));
   685     test_selector_in_html(":nth-child(2n-1)", seven_ps,
   686                           pset([1, 3, 5, 7]), pset([2, 4, 6]));
   687     test_selector_in_html(":nth-child( 2n - 1 )", seven_ps,
   688                           pset([1, 3, 5, 7]), pset([2, 4, 6]));
   689     test_selector_in_html(":nth-child(2n+1)", seven_ps,
   690                           pset([1, 3, 5, 7]), pset([2, 4, 6]));
   691     test_selector_in_html(":nth-child( 2n + 1 )", seven_ps,
   692                           pset([1, 3, 5, 7]), pset([2, 4, 6]));
   693     test_selector_in_html(":nth-child(2n+0)", seven_ps,
   694                           pset([2, 4, 6]), pset([1, 3, 5, 7]));
   695     test_selector_in_html(":nth-child(2n-0)", seven_ps,
   696                           pset([2, 4, 6]), pset([1, 3, 5, 7]));
   697     test_selector_in_html(":nth-child(-n+3)", seven_ps,
   698                           pset([1, 2, 3]), pset([4, 5, 6, 7]));
   699     test_selector_in_html(":nth-child(-n-3)", seven_ps,
   700                           pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
   701     test_selector_in_html(":nth-child(n)", seven_ps,
   702                           pset([1, 2, 3, 4, 5, 6, 7]), pset([]));
   703     test_selector_in_html(":nth-child(n-3)", seven_ps,
   704                           pset([1, 2, 3, 4, 5, 6, 7]), pset([]));
   705     test_selector_in_html(":nth-child(n+3)", seven_ps,
   706                           pset([3, 4, 5, 6, 7]), pset([1, 2]));
   707     test_selector_in_html(":nth-child(2n+3)", seven_ps,
   708                           pset([3, 5, 7]), pset([1, 2, 4, 6]));
   709     test_selector_in_html(":nth-child(2n)", seven_ps,
   710                           pset([2, 4, 6]), pset([1, 3, 5, 7]));
   711     test_selector_in_html(":nth-child(2n-3)", seven_ps,
   712                           pset([1, 3, 5, 7]), pset([2, 4, 6]));
   713     test_selector_in_html(":nth-child(-1n+3)", seven_ps,
   714                           pset([1, 2, 3]), pset([4, 5, 6, 7]));
   715     test_selector_in_html(":nth-child(-2n+3)", seven_ps,
   716                           pset([1, 3]), pset([2, 4, 5, 6, 7]));
   717     // And a few spot-checks for the other :nth-* selectors
   718     test_selector_in_html(":nth-child(4n+1)", seven_ps,
   719                           pset([1, 5]), pset([2, 3, 4, 6, 7]));
   720     test_selector_in_html(":nth-last-child(4n+1)", seven_ps,
   721                           pset([3, 7]), pset([1, 2, 4, 5, 6]));
   722     test_selector_in_html(":nth-of-type(4n+1)", seven_ps,
   723                           pset([1, 5]), pset([2, 3, 4, 6, 7]));
   724     test_selector_in_html(":nth-last-of-type(4n+1)", seven_ps,
   725                           pset([3, 7]), pset([1, 2, 4, 5, 6]));
   726     test_selector_in_html(":nth-child(6)", seven_ps,
   727                           pset([6]), pset([1, 2, 3, 4, 5, 7]));
   728     test_selector_in_html(":nth-last-child(6)", seven_ps,
   729                           pset([2]), pset([1, 3, 4, 5, 6, 7]));
   730     test_selector_in_html(":nth-of-type(6)", seven_ps,
   731                           pset([6]), pset([1, 2, 3, 4, 5, 7]));
   732     test_selector_in_html(":nth-last-of-type(6)", seven_ps,
   733                           pset([2]), pset([1, 3, 4, 5, 6, 7]));
   735     // Test [first|last|only]-[child|node|of-type]
   736     var interesting_doc = "<!----> <div id='p1'> <!---->x<p id='s1'></p> <!----><p id='s2'></p> <!----></div> <!----><p id='p2'> <!----><span id='s3'></span> <!----><span id='s4'></span> <!---->x</p> <!----><div id='p3'> <!----><p id='s5'></p> <!----></div> <!---->";
   737     function idset(ids) { // takes an array of ids
   738         return function idset_filter(doc) {
   739             var result = [];
   740             for (var id of ids)
   741                 result.push(doc.getElementById(id));
   742             return result;
   743         }
   744     }
   745     function classset(classes) { // takes an array of classes
   746         return function classset_filter(doc) {
   747             var i, j, els;
   748             var result = [];
   749             for (i = 0; i < classes.length; i++) {
   750                 els = doc.getElementsByClassName(classes[i]);
   751                 for (j = 0; j < els.length; j++) {
   752                     result.push(els[j]);
   753                 }
   754             }
   755             return result;
   756         }
   757     }
   758     function emptyset(doc) { return []; }
   759     test_parseable(":first-child");
   760     test_parseable(":last-child");
   761     test_parseable(":only-child");
   762     test_parseable(":-moz-first-node");
   763     test_parseable(":-moz-last-node");
   764     test_parseable(":first-of-type");
   765     test_parseable(":last-of-type");
   766     test_parseable(":only-of-type");
   767     test_selector_in_html(":first-child", seven_ps,
   768                           pset([1]), pset([2, 3, 4, 5, 6, 7]));
   769     test_selector_in_html(":first-child", interesting_doc,
   770                           idset(["p1", "s1", "s3", "s5"]),
   771                           idset(["s2", "p2", "s4", "p3"]));
   772     test_selector_in_html(":-moz-first-node", interesting_doc,
   773                           idset(["p1", "s3", "s5"]),
   774                           idset(["s1", "s2", "p2", "s4", "p3"]));
   775     test_selector_in_html(":last-child", seven_ps,
   776                           pset([7]), pset([1, 2, 3, 4, 5, 6]));
   777     test_selector_in_html(":last-child", interesting_doc,
   778                           idset(["s2", "s4", "p3", "s5"]),
   779                           idset(["p1", "s1", "p2", "s3"]));
   780     test_selector_in_html(":-moz-last-node", interesting_doc,
   781                           idset(["s2", "p3", "s5"]),
   782                           idset(["p1", "s1", "p2", "s3", "s4"]));
   783     test_selector_in_html(":only-child", seven_ps,
   784                           pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
   785     test_selector_in_html(":only-child", interesting_doc,
   786                           idset(["s5"]),
   787                           idset(["p1", "s1", "s2", "p2", "s3", "s4", "p3"]));
   788     test_selector_in_html(":first-of-type", seven_ps,
   789                           pset([1]), pset([2, 3, 4, 5, 6, 7]));
   790     test_selector_in_html(":first-of-type", interesting_doc,
   791                           idset(["p1", "s1", "p2", "s3", "s5"]),
   792                           idset(["s2", "s4", "p3"]));
   793     test_selector_in_html(":last-of-type", seven_ps,
   794                           pset([7]), pset([1, 2, 3, 4, 5, 6]));
   795     test_selector_in_html(":last-of-type", interesting_doc,
   796                           idset(["s2", "p2", "s4", "p3", "s5"]),
   797                           idset(["p1", "s1", "s3"]));
   798     test_selector_in_html(":only-of-type", seven_ps,
   799                           pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
   800     test_selector_in_html(":only-of-type", interesting_doc,
   801                           idset(["p2", "s5"]),
   802                           idset(["p1", "s1", "s2", "s3", "s4", "p3"]));
   804     // And a bunch of tests for the of-type aspect of :nth-of-type() and
   805     // :nth-last-of-type().  Note that the last div here contains two
   806     // children.
   807     var mixed_elements="<p></p><p></p><div></div><p></p><div><p></p><address></address></div><address></address>";
   808     function pdaset(ps, divs, addresses) { // takes an array of 1-based indices
   809         var l = { p: ps, div: divs, address: addresses };
   810         return function pdaset_filter(doc) {
   811             var result = [];
   812             for (var tag in l) {
   813                 var a = doc.getElementsByTagName(tag);
   814                 var indices = l[tag];
   815                 for (var i in indices)
   816                     result.push(a[indices[i] - 1]);
   817             }
   818             return result;
   819         }
   820     }
   821     test_selector_in_html(":nth-of-type(odd)", mixed_elements,
   822                           pdaset([1, 3, 4], [1], [1, 2]),
   823                           pdaset([2], [2], []));
   824     test_selector_in_html(":nth-of-type(2n-0)", mixed_elements,
   825                           pdaset([2], [2], []),
   826                           pdaset([1, 3, 4], [1], [1, 2]));
   827     test_selector_in_html(":nth-last-of-type(even)", mixed_elements,
   828                           pdaset([2], [1], []),
   829                           pdaset([1, 3, 4], [2], [1, 2]));
   831     // Test greediness of descendant combinators.
   832     var four_children="<div id='a'><div id='b'><div id='c'><div id='d'><\/div><\/div><\/div><\/div>";
   833     test_selector_in_html("#a > div div", four_children,
   834                           idset(["c", "d"]), idset(["a", "b"]));
   835     test_selector_in_html("#a > #b div", four_children,
   836                           idset(["c", "d"]), idset(["a", "b"]));
   837     test_selector_in_html("#a div > div", four_children,
   838                           idset(["c", "d"]), idset(["a", "b"]));
   839     test_selector_in_html("#a #b > div", four_children,
   840                           idset(["c"]), idset(["a", "b", "d"]));
   841     test_selector_in_html("#a > #b div", four_children,
   842                           idset(["c", "d"]), idset(["a", "b"]));
   843     test_selector_in_html("#a #c > div", four_children,
   844                           idset(["d"]), idset(["a", "b", "c"]));
   845     test_selector_in_html("#a > #c div", four_children,
   846                           idset([]), idset(["a", "b", "c", "d"]));
   848     // More descendant combinator greediness (bug 511147)
   849     test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="b"></div><div class="match"></div></div>',
   850                          classset(["match"]), classset(["a", "b"]));
   851     test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="b"></div><div class="x"></div><div class="match"></div></div>',
   852                          classset(["match"]), classset(["a", "b", "x"]));
   853     test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="b"><p>filler filler <i>filler</i> filler</p></div><div class="match"></div></div>',
   854                          classset(["match"]), classset(["a", "b", "x"]));
   855     test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="x"><p>filler filler <i>filler</i> filler</p></div><div></div><div class="b"></div><div></div><div class="x"><p>filler filler <i>filler</i> filler</p></div><div class="match"></div></div>',
   856                          classset(["match"]), classset(["a", "b", "x"]));
   857     test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="b"></div><div class="match"></div><div class="match"></div></div>',
   858                          classset(["match"]), classset(["a", "b"]));
   860     test_selector_in_html(".a > .b ~ .nomatch", '<div class="a"><div><div class="b"></div><div class="nomatch"></div></div></div>',
   861                          emptyset, classset(["a", "b", "nomatch"]));
   862     test_selector_in_html(".a > .b ~ .nomatch", '<div class="a"><div><div class="b"></div><div class="nomatch"></div></div><div class="nomatch"></div></div>',
   863                          emptyset, classset(["a", "b", "nomatch"]));
   864     test_selector_in_html(".a > .b ~ .nomatch", '<div class="a"><div class="b"></div><div><div class="nomatch"></div></div><div></div></div>',
   865                          emptyset, classset(["a", "b", "nomatch"]));
   866     test_selector_in_html(".a > .b ~ .nomatch", '<div class="a"><div class="b"></div></div><div class="nomatch"></div>',
   867                          emptyset, classset(["a", "b", "nomatch"]));
   869     // Test serialization of pseudo-elements.
   870     should_serialize_to("p:first-letter", "p:first-letter");
   871     should_serialize_to("div>p:first-letter", "div > p:first-letter");
   872     should_serialize_to("span +div:first-line", "span + div:first-line");
   874     // Test default namespaces, including inside :not().
   875     var html_default_ns = "@namespace url(http://www.w3.org/1999/xhtml);";
   876     var html_ns = "@namespace html url(http://www.w3.org/1999/xhtml);";
   877     var xul_default_ns = "@namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);";
   878     var single_a = "<a id='a' href='data:text/plain,this_better_be_unvisited'></a>";
   879     var set_single = idset(['a']);
   880     var empty_set = idset([]);
   881     test_selector_in_html("a", single_a, set_single, empty_set,
   882                           html_default_ns);
   883     test_selector_in_html("a", single_a, empty_set, set_single,
   884                           xul_default_ns);
   885     test_selector_in_html("*|a", single_a, set_single, empty_set,
   886                           xul_default_ns);
   887     test_selector_in_html("html|a", single_a, set_single, empty_set,
   888                           xul_default_ns + html_ns);
   889     // Type selectors inside :not() bring in default namespaces, but
   890     // non-type selectors don't.
   891     test_selector_in_html("*|a:not(*)", single_a, set_single, empty_set,
   892                           xul_default_ns);
   893     test_selector_in_html("*|a:not(a)", single_a, set_single, empty_set,
   894                           xul_default_ns);
   895     test_selector_in_html("*|a:not(*|*)", single_a, empty_set, set_single,
   896                           xul_default_ns);
   897     test_selector_in_html("*|a:not(*|a)", single_a, empty_set, set_single,
   898                           xul_default_ns);
   899     test_selector_in_html("*|a:not(:link)", single_a + "<a id='b'></a>",
   900                           idset(["b"]), set_single,
   901                           xul_default_ns);
   902     test_selector_in_html("*|a:not(:visited)", single_a + "<a id='b'></a>",
   903                           idset(["a", "b"]), empty_set,
   904                           xul_default_ns);
   905     test_selector_in_html("*|a:not(html|*)", single_a, empty_set, set_single,
   906                           xul_default_ns + html_ns);
   907     test_selector_in_html("*|a:not(html|a)", single_a, empty_set, set_single,
   908                           xul_default_ns + html_ns);
   909     test_selector_in_html("*|a:not(|*)", single_a, set_single, empty_set,
   910                           xul_default_ns + html_ns);
   911     test_selector_in_html("*|a:not(|a)", single_a, set_single, empty_set,
   912                           xul_default_ns + html_ns);
   913     test_selector_in_html("html|a:not(|*)", single_a, set_single, empty_set,
   914                           xul_default_ns + html_ns);
   915     test_selector_in_html("html|a:not(|a)", single_a, set_single, empty_set,
   916                           xul_default_ns + html_ns);
   917     test_selector_in_html("html|a:not(*|*)", single_a, empty_set, set_single,
   918                           xul_default_ns + html_ns);
   919     test_selector_in_html("html|a:not(*|a)", single_a, empty_set, set_single,
   920                           xul_default_ns + html_ns);
   922     // Test -moz-locale-dir
   923     test_parseable(":-moz-locale-dir(ltr)");
   924     test_parseable(":-moz-locale-dir(rtl)");
   925     test_parseable(":-moz-locale-dir(rTl)");
   926     test_parseable(":-moz-locale-dir(LTR)");
   927     if (document.body.mozMatchesSelector(":-moz-locale-dir(ltr)")) {
   928         test_selector_in_html("a:-moz-locale-dir(LTr)", single_a,
   929                               set_single, empty_set);
   930         test_selector_in_html("a:-moz-locale-dir(ltR)", single_a,
   931                               set_single, empty_set);
   932         test_selector_in_html("a:-moz-locale-dir(LTR)", single_a,
   933                               set_single, empty_set);
   934         test_selector_in_html("a:-moz-locale-dir(RTl)", single_a,
   935                               empty_set, set_single);
   936     } else {
   937         test_selector_in_html("a:-moz-locale-dir(RTl)", single_a,
   938                               set_single, empty_set);
   939         test_selector_in_html("a:-moz-locale-dir(rtL)", single_a,
   940                               set_single, empty_set);
   941         test_selector_in_html("a:-moz-locale-dir(RTL)", single_a,
   942                               set_single, empty_set);
   943         test_selector_in_html("a:-moz-locale-dir(LTr)", single_a,
   944                               empty_set, set_single);
   945     }
   947     test_balanced_unparseable(":-moz-locale-dir(other)");
   948     test_balanced_unparseable(":-moz-locale-dir()");
   949     test_balanced_unparseable(":-moz-locale-dir(())");
   950     test_balanced_unparseable(":-moz-locale-dir(3())");
   951     test_balanced_unparseable(":-moz-locale-dir(f{})");
   952     test_balanced_unparseable(":-moz-locale-dir('ltr')");
   953     test_balanced_unparseable(":-moz-locale-dir(ltr, other)");
   954     test_balanced_unparseable(":-moz-locale-dir");
   956     // Test :-moz-dir()
   957     test_parseable(":-moz-dir(ltr)");
   958     test_parseable(":-moz-dir(rtl)");
   959     test_parseable(":-moz-dir(rTl)");
   960     test_parseable(":-moz-dir(LTR)");
   961     if (document.body.mozMatchesSelector(":-moz-dir(ltr)")) {
   962         test_selector_in_html("a:-moz-dir(LTr)", single_a,
   963                               set_single, empty_set);
   964         test_selector_in_html("a:-moz-dir(ltR)", single_a,
   965                               set_single, empty_set);
   966         test_selector_in_html("a:-moz-dir(LTR)", single_a,
   967                               set_single, empty_set);
   968         test_selector_in_html("a:-moz-dir(RTl)", single_a,
   969                               empty_set, set_single);
   970     } else {
   971         test_selector_in_html("a:-moz-dir(RTl)", single_a,
   972                               set_single, empty_set);
   973         test_selector_in_html("a:-moz-dir(rtL)", single_a,
   974                               set_single, empty_set);
   975         test_selector_in_html("a:-moz-dir(RTL)", single_a,
   976                               set_single, empty_set);
   977         test_selector_in_html("a:-moz-dir(LTr)", single_a,
   978                               empty_set, set_single);
   979     }
   981     test_balanced_unparseable(":-moz-dir(other)");
   982     test_balanced_unparseable(":-moz-dir()");
   983     test_balanced_unparseable(":-moz-dir(())");
   984     test_balanced_unparseable(":-moz-dir(3())");
   985     test_balanced_unparseable(":-moz-dir(f{})");
   986     test_balanced_unparseable(":-moz-dir('ltr')");
   987     test_balanced_unparseable(":-moz-dir(ltr, other)");
   988     test_balanced_unparseable(":-moz-dir");
   990     // Test -moz-lwtheme and -moz-lwtheme-[darktext|brighttext]
   991     test_parseable(":-moz-lwtheme");
   992     test_parseable(":-moz-lwtheme-brighttext");
   993     test_parseable(":-moz-lwtheme-darktext");
   995     test_parseable(":-moz-tree-row(selected)");
   996     test_parseable("::-moz-tree-row(selected)");
   997     test_parseable(":-moz-tree-row(selected focus)");
   998     test_parseable(":-moz-tree-row(selected , focus)");
   999     test_parseable("::-moz-tree-row(selected ,focus)");
  1000     test_parseable(":-moz-tree-row(selected, focus)");
  1001     test_parseable("::-moz-tree-row(selected,focus)");
  1002     test_parseable(":-moz-tree-row(selected     focus)");
  1003     test_parseable("::-moz-tree-row(selected    ,   focus)");
  1004     test_parseable("::-moz-tree-twisty(  hover open  )");
  1005     test_balanced_unparseable("::-moz-tree-row(selected {[]} )");
  1006     test_balanced_unparseable(":-moz-tree-twisty(open())");
  1007     test_balanced_unparseable("::-moz-tree-twisty(hover ())");
  1009     test_parseable(":-moz-window-inactive");
  1010     test_parseable("div p:-moz-window-inactive:hover span");
  1012     // Plugin pseudoclasses
  1013     test_parseable(":-moz-type-unsupported");
  1014     test_parseable(":-moz-handler-disabled");
  1015     test_parseable(":-moz-handler-blocked");
  1016     test_parseable(":-moz-handler-crashed");
  1018     // Case sensitivity of tag selectors
  1019     function setup_cased_spans(body) {
  1020       var data = [
  1021         { tag: "span" },
  1022         { tag: "sPaN" },
  1023         { tag: "Span" },
  1024         { tag: "SPAN" },
  1025         { ns: "http://www.w3.org/1999/xhtml", tag: "span" },
  1026         { ns: "http://www.w3.org/1999/xhtml", tag: "sPaN" },
  1027         { ns: "http://www.w3.org/1999/xhtml", tag: "Span" },
  1028         { ns: "http://www.w3.org/1999/xhtml", tag: "SPAN" },
  1029         { ns: "http://example.com/useless", tag: "span" },
  1030         { ns: "http://example.com/useless", tag: "sPaN" },
  1031         { ns: "http://example.com/useless", tag: "Span" },
  1032         { ns: "http://example.com/useless", tag: "SPAN" },
  1034       for (var i in data) {
  1035         var ent = data[i];
  1036         var elem;
  1037         if ("ns" in ent) {
  1038           elem = body.ownerDocument.createElementNS(ent.ns, ent.tag);
  1039         } else {
  1040           elem = body.ownerDocument.createElement(ent.tag);
  1042         body.appendChild(elem);
  1045     function bodychildset(indices) {
  1046       return function bodychildset_filter(doc) {
  1047         var body = doc.body;
  1048         var result = [];
  1049         for (var i in indices) {
  1050           result.push(body.childNodes[indices[i]]);
  1052         return result;
  1055     test_selector_in_html("span", setup_cased_spans,
  1056                           bodychildset([0, 1, 2, 3, 4, 8]),
  1057                           bodychildset([5, 6, 7, 9, 10, 11]));
  1058     test_selector_in_html("sPaN", setup_cased_spans,
  1059                           bodychildset([0, 1, 2, 3, 4, 9]),
  1060                           bodychildset([5, 6, 7, 8, 10, 11]));
  1061     test_selector_in_html("Span", setup_cased_spans,
  1062                           bodychildset([0, 1, 2, 3, 4, 10]),
  1063                           bodychildset([5, 6, 7, 8, 9, 11]));
  1064     test_selector_in_html("SPAN", setup_cased_spans,
  1065                           bodychildset([0, 1, 2, 3, 4, 11]),
  1066                           bodychildset([5, 6, 7, 8, 9, 10]));
  1068     // bug 528096 (tree pseudos)
  1069     test_unbalanced_unparseable(":-moz-tree-column((){} a");
  1070     test_unbalanced_unparseable(":-moz-tree-column(x(){} a");
  1071     test_unbalanced_unparseable(":-moz-tree-column(a b (){} a");
  1072     test_unbalanced_unparseable(":-moz-tree-column(a, b (){} a");
  1074     // Bug 543428 (escaping)
  1075     test_selector_in_html("\\32|a", single_a, set_single, empty_set,
  1076                           "@namespace \\32  url(http://www.w3.org/1999/xhtml);");
  1077     test_selector_in_html("-\\32|a", single_a, set_single, empty_set,
  1078                           "@namespace -\\32  url(http://www.w3.org/1999/xhtml);");
  1079     test_selector_in_html("\\2|a", single_a, set_single, empty_set,
  1080                           "@namespace \\0002  url(http://www.w3.org/1999/xhtml);");
  1081     test_selector_in_html("-\\2|a", single_a, set_single, empty_set,
  1082                           "@namespace -\\000002  url(http://www.w3.org/1999/xhtml);");
  1083     var spans = "<span class='2'></span><span class='&#x2;'></span>" +
  1084                 "<span id='2'></span><span id='&#x2;'></span>"
  1085     test_selector_in_html(".\\32", spans,
  1086                           bodychildset([0]), bodychildset([1, 2, 3]));
  1087     test_selector_in_html("[class=\\32]", spans,
  1088                           bodychildset([0]), bodychildset([1, 2, 3]));
  1089     test_selector_in_html(".\\2", spans,
  1090                           bodychildset([1]), bodychildset([0, 2, 3]));
  1091     test_selector_in_html("[class=\\2]", spans,
  1092                           bodychildset([1]), bodychildset([0, 2, 3]));
  1093     test_selector_in_html("#\\32", spans,
  1094                           bodychildset([2]), bodychildset([0, 1, 3]));
  1095     test_selector_in_html("[id=\\32]", spans,
  1096                           bodychildset([2]), bodychildset([0, 1, 3]));
  1097     test_selector_in_html("#\\2", spans,
  1098                           bodychildset([3]), bodychildset([0, 1, 2]));
  1099     test_selector_in_html("[id=\\2]", spans,
  1100                           bodychildset([3]), bodychildset([0, 1, 2]));
  1101     test_balanced_unparseable("#2");
  1103     // Bug 553805:  :not() containing nothing is forbidden
  1104     test_balanced_unparseable(":not()");
  1105     test_balanced_unparseable(":not( )");
  1106     test_balanced_unparseable(":not( \t\n )");
  1107     test_balanced_unparseable(":not(/*comment*/)");
  1108     test_balanced_unparseable(":not( /*comment*/  /* comment */  )");
  1109     test_balanced_unparseable("p :not()");
  1110     test_balanced_unparseable("p :not( )");
  1111     test_balanced_unparseable("p :not( \t\n )");
  1112     test_balanced_unparseable("p :not(/*comment*/)");
  1113     test_balanced_unparseable("p :not( /*comment*/  /* comment */  )");
  1114     test_balanced_unparseable("p:not()");
  1115     test_balanced_unparseable("p:not( )");
  1116     test_balanced_unparseable("p:not( \t\n )");
  1117     test_balanced_unparseable("p:not(/*comment*/)");
  1118     test_balanced_unparseable("p:not( /*comment*/  /* comment */  )");
  1120     test_balanced_unparseable(":not(:nth-child(2k))");
  1121     test_balanced_unparseable(":not(:nth-child(()))");
  1123     // :-moz-any()
  1124     test_balanced_unparseable(":-moz-any()");
  1125     test_balanced_unparseable(":-moz-any(div p)");
  1126     test_balanced_unparseable(":-moz-any(div ~ p)");
  1127     test_balanced_unparseable(":-moz-any(div~p)");
  1128     test_balanced_unparseable(":-moz-any(div + p)");
  1129     test_balanced_unparseable(":-moz-any(div+p)");
  1130     test_balanced_unparseable(":-moz-any(div > p)");
  1131     test_balanced_unparseable(":-moz-any(div>p)");
  1132     test_parseable(":-moz-any(div, p)");
  1133     test_parseable(":-moz-any( div , p  )");
  1134     test_parseable(":-moz-any(div,p)");
  1135     test_parseable(":-moz-any(div)");
  1136     test_parseable(":-moz-any(div,p,:link,span:focus)");
  1137     test_parseable(":-moz-any(:active,:focus)");
  1138     test_parseable(":-moz-any(:active,:link:focus)");
  1139     test_balanced_unparseable(":-moz-any(div,:nonexistentpseudo)");
  1140     var any_elts = "<input type='text'><a href='http://www.example.com/'></a><div></div><a name='foo'>";
  1141     test_selector_in_html(":-moz-any(a,input)", any_elts,
  1142                           bodychildset([0, 1, 3]), bodychildset([2]));
  1143     test_selector_in_html(":-moz-any(:link,:not(a))", any_elts,
  1144                           bodychildset([0, 1, 2]), bodychildset([3]));
  1145     test_selector_in_html(":-moz-any([href],input[type],input[name])", any_elts,
  1146                           bodychildset([0, 1]), bodychildset([2, 3]));
  1147     test_selector_in_html(":-moz-any(div,a):-moz-any([type],[href],[name])",
  1148                           any_elts,
  1149                           bodychildset([1, 3]), bodychildset([0, 2]));
  1151     test_selector_in_html(":-moz-table-border-nonzero",
  1152                           "<p></p>" +
  1153                           "<p border='2'></p>" +
  1154                           "<table border='2'></table>" +
  1155                           "<table border></table>" +
  1156                           "<table></table>" +
  1157                           "<table frame='border'></table>" +
  1158                           "<table border='0'></table>" +
  1159                           "<table border='0pt'></table>" +
  1160                           "<table border='3pt'></table>",
  1161                           bodychildset([2, 3, 8]),
  1162                           bodychildset([0, 1, 4, 5, 6, 7]));
  1164     // Test that we don't tokenize an empty HASH.
  1165     test_balanced_unparseable("#");
  1166     test_balanced_unparseable("# ");
  1167     test_balanced_unparseable("#, p");
  1168     test_balanced_unparseable("# , p");
  1169     test_balanced_unparseable("p #");
  1170     test_balanced_unparseable("p # ");
  1171     test_balanced_unparseable("p #, p");
  1172     test_balanced_unparseable("p # , p");
  1174     // Test that a backslash alone at EOF outside of a string is treated
  1175     // as U+FFFD.
  1176     test_parseable_via_api("#a\\");
  1177     test_parseable_via_api("#\\");
  1178     test_parseable_via_api("\\");
  1180     // Test that newline escapes are only supported in strings.
  1181     test_balanced_unparseable("di\\\nv");
  1182     test_balanced_unparseable("div \\\n p");
  1183     test_balanced_unparseable("div\\\n p");
  1184     test_balanced_unparseable("div \\\np");
  1185     test_balanced_unparseable("div\\\np");
  1187     // Test that :-moz-placeholder is parsable.
  1188     test_parseable(":-moz-placeholder");
  1190     run_deferred_tests();
  1193 var deferred_tests = [];
  1195 function defer_clonedoc_tests(docurl, onloadfunc)
  1197     deferred_tests.push( { docurl: docurl, onloadfunc: onloadfunc } );
  1200 function run_deferred_tests()
  1202     if (deferred_tests.length == 0) {
  1203         SimpleTest.finish();
  1204         return;
  1207     cloneiframe.onload = deferred_tests_onload;
  1208     cloneiframe.src = deferred_tests[0].docurl;
  1211 function deferred_tests_onload(event)
  1213     if (event.target != cloneiframe)
  1214         return;
  1216     deferred_tests[0].onloadfunc();
  1217     deferred_tests.shift();
  1219     run_deferred_tests();
  1222 </script>
  1223 </pre>
  1224 </body>
  1225 </html>

mercurial