layout/style/test/test_selectors.html

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/style/test/test_selectors.html	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1225 @@
     1.4 +<!DOCTYPE HTML>
     1.5 +<html>
     1.6 +<head>
     1.7 +  <title>Test for CSS Selectors</title>
     1.8 +  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
     1.9 +  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
    1.10 +</head>
    1.11 +<body onload="run()">
    1.12 +<p id="display"><iframe id="iframe" src="about:blank"></iframe><iframe id="cloneiframe" src="about:blank"></iframe></p>
    1.13 +<pre id="test">
    1.14 +<script class="testbody" type="text/javascript">
    1.15 +
    1.16 +SimpleTest.waitForExplicitFinish();
    1.17 +
    1.18 +var cloneiframe;
    1.19 +
    1.20 +function run() {
    1.21 +
    1.22 +    var iframe = document.getElementById("iframe");
    1.23 +    var ifwin = iframe.contentWindow;
    1.24 +    var ifdoc = iframe.contentDocument;
    1.25 +
    1.26 +    cloneiframe = document.getElementById("cloneiframe");
    1.27 +
    1.28 +    var style_elem = ifdoc.createElement("style");
    1.29 +    style_elem.setAttribute("type", "text/css");
    1.30 +    ifdoc.getElementsByTagName("head")[0].appendChild(style_elem);
    1.31 +    var style_text = ifdoc.createTextNode("");
    1.32 +    style_elem.appendChild(style_text);
    1.33 +
    1.34 +    var gCounter = 0;
    1.35 +
    1.36 +    /*
    1.37 +     * selector: the selector to test
    1.38 +     * body_contents: what to set the body's innerHTML to
    1.39 +     * match_fn: a function that, given the document object into which
    1.40 +     *   body_contents has been inserted, produces an array of nodes that
    1.41 +     *   should match selector
    1.42 +     * notmatch_fn: likewise, but for nodes that should not match
    1.43 +     * namespaces (optional): @namespace rules to be included in the sheet
    1.44 +     */
    1.45 +    function test_selector_in_html(selector, body_contents, match_fn, notmatch_fn, namespaces)
    1.46 +    {
    1.47 +        var zi = ++gCounter;
    1.48 +        if (typeof(body_contents) == "string") {
    1.49 +            ifdoc.body.innerHTML = body_contents;
    1.50 +        } else {
    1.51 +            // It's a function.
    1.52 +            ifdoc.body.innerHTML = "";
    1.53 +            body_contents(ifdoc.body);
    1.54 +        }
    1.55 +        if (!namespaces) {
    1.56 +            namespaces = "";
    1.57 +        }
    1.58 +        style_text.data = namespaces + selector + "{ z-index: " + zi + " }";
    1.59 +
    1.60 +        var idx = style_text.parentNode.sheet.cssRules.length - 1;
    1.61 +        if (namespaces == "") {
    1.62 +            is(idx, 0, "unexpected rule index");
    1.63 +        }
    1.64 +        if (idx < 0 ||
    1.65 +            style_text.parentNode.sheet.cssRules[idx].type !=
    1.66 +                CSSRule.STYLE_RULE)
    1.67 +        {
    1.68 +            ok(false, "selector " + selector + " could not be parsed");
    1.69 +            return;
    1.70 +        }
    1.71 +
    1.72 +        var should_match = match_fn(ifdoc);
    1.73 +        var should_not_match = notmatch_fn(ifdoc);
    1.74 +        if (should_match.length + should_not_match.length == 0) {
    1.75 +            ok(false, "nothing to check");
    1.76 +        }
    1.77 +
    1.78 +        for (var i = 0; i < should_match.length; ++i) {
    1.79 +            var e = should_match[i];
    1.80 +            is(ifwin.getComputedStyle(e, "").zIndex, zi,
    1.81 +               "element in " + body_contents + " matched " + selector);
    1.82 +        }
    1.83 +        for (var i = 0; i < should_not_match.length; ++i) {
    1.84 +            var e = should_not_match[i];
    1.85 +            is(ifwin.getComputedStyle(e, "").zIndex, "auto",
    1.86 +               "element in " + body_contents + " did not match " + selector);
    1.87 +        }
    1.88 +
    1.89 +        // Now, since we're here, may as well make sure serialization
    1.90 +        // works correctly.  It need not produce the exact same text,
    1.91 +        // but it should produce a selector that matches the same
    1.92 +        // elements.
    1.93 +        zi = ++gCounter;
    1.94 +        var ser1 = style_text.parentNode.sheet.cssRules[idx].selectorText;
    1.95 +        style_text.data = namespaces + ser1 + "{ z-index: " + zi + " }";
    1.96 +        for (var i = 0; i < should_match.length; ++i) {
    1.97 +            var e = should_match[i];
    1.98 +            is(ifwin.getComputedStyle(e, "").zIndex, zi,
    1.99 +               "element in " + body_contents + " matched " + ser1 +
   1.100 +               " which is the reserialization of " + selector);
   1.101 +        }
   1.102 +        for (var i = 0; i < should_not_match.length; ++i) {
   1.103 +            var e = should_not_match[i];
   1.104 +            is(ifwin.getComputedStyle(e, "").zIndex, "auto",
   1.105 +               "element in " + body_contents + " did not match " + ser1 +
   1.106 +               " which is the reserialization of " + selector);
   1.107 +        }
   1.108 +
   1.109 +        // But when we serialize the serialized result, we should get
   1.110 +        // the same text.
   1.111 +        var ser2 = style_text.parentNode.sheet.cssRules[idx].selectorText;
   1.112 +        is(ser2, ser1, "parse+serialize of selector \"" + selector +
   1.113 +                       "\" is idempotent");
   1.114 +
   1.115 +        ifdoc.body.innerHTML = "";
   1.116 +        style_text.data = "";
   1.117 +
   1.118 +        // And now test that when we clone the style sheet, we end up
   1.119 +        // with the same selector (serializes to same string, and
   1.120 +        // matches the same things).
   1.121 +        zi = ++gCounter;
   1.122 +        var style_sheet = "data:text/css," +
   1.123 +            escape(namespaces + selector + "{ z-index: " + zi + " }");
   1.124 +        var style_sheet_link =
   1.125 +            "<link rel='stylesheet' href='" + style_sheet + "'>";
   1.126 +        var html_doc = "<!DOCTYPE HTML>" +
   1.127 +                       style_sheet_link + style_sheet_link +
   1.128 +                       "<body>";
   1.129 +        if (typeof(body_contents) == "string") {
   1.130 +            html_doc += body_contents;
   1.131 +        }
   1.132 +        var docurl = "data:text/html," + escape(html_doc);
   1.133 +        defer_clonedoc_tests(docurl, function() {
   1.134 +            var clonedoc = cloneiframe.contentDocument;
   1.135 +            var clonewin = cloneiframe.contentWindow;
   1.136 +
   1.137 +            if (typeof(body_contents) != "string") {
   1.138 +                body_contents(clonedoc.body);
   1.139 +            }
   1.140 +
   1.141 +            var links = clonedoc.getElementsByTagName("link");
   1.142 +            // cause a clone
   1.143 +            links[1].sheet.insertRule("#nonexistent { color: purple}", idx + 1);
   1.144 +            // remove the uncloned sheet
   1.145 +            links[0].parentNode.removeChild(links[0]);
   1.146 +
   1.147 +            var should_match = match_fn(clonedoc);
   1.148 +            var should_not_match = notmatch_fn(clonedoc);
   1.149 +
   1.150 +            if (should_match.length + should_not_match.length == 0) {
   1.151 +                ok(false, "nothing to check");
   1.152 +            }
   1.153 +
   1.154 +            for (var i = 0; i < should_match.length; ++i) {
   1.155 +                var e = should_match[i];
   1.156 +                is(clonewin.getComputedStyle(e, "").zIndex, zi,
   1.157 +                   "element in " + body_contents + " matched clone of " +
   1.158 +                   selector);
   1.159 +            }
   1.160 +            for (var i = 0; i < should_not_match.length; ++i) {
   1.161 +                var e = should_not_match[i];
   1.162 +                is(clonewin.getComputedStyle(e, "").zIndex, "auto",
   1.163 +                   "element in " + body_contents + " did not match clone of " +
   1.164 +                   selector);
   1.165 +            }
   1.166 +
   1.167 +            var ser3 = links[0].sheet.cssRules[idx].selectorText;
   1.168 +            is(ser3, ser1,
   1.169 +               "selector " + selector + " serializes correctly after cloning");
   1.170 +        });
   1.171 +    }
   1.172 +
   1.173 +    function should_serialize_to(selector, serialization)
   1.174 +    {
   1.175 +        style_text.data = selector + "{ z-index: 0 }";
   1.176 +        is(style_text.parentNode.sheet.cssRules[0].selectorText,
   1.177 +           serialization,
   1.178 +           "selector '" + selector + "' should serialize to '" +
   1.179 +             serialization + "'.");
   1.180 +    }
   1.181 +
   1.182 +    function test_parseable(selector)
   1.183 +    {
   1.184 +        ifdoc.body.innerHTML = "<p></p>";
   1.185 +
   1.186 +        var zi = ++gCounter;
   1.187 +        style_text.data = "p, " + selector + "{ z-index: " + zi + " }";
   1.188 +        var should_match = ifdoc.getElementsByTagName("p")[0];
   1.189 +        var parsed = ifwin.getComputedStyle(should_match, "").zIndex == zi;
   1.190 +        ok(parsed, "selector " + selector + " was parsed");
   1.191 +        if (!parsed) {
   1.192 +            return;
   1.193 +        }
   1.194 +
   1.195 +        // Test that it serializes to something that is also parseable.
   1.196 +        var ser1 = style_elem.sheet.cssRules[0].selectorText;
   1.197 +        zi = ++gCounter;
   1.198 +        style_text.data = ser1 + "{ z-index: " + zi + " }";
   1.199 +        is(ifwin.getComputedStyle(should_match, "").zIndex, zi,
   1.200 +           "serialization " + ser1 + " of selector p, " + selector +
   1.201 +           " was parsed");
   1.202 +        var ser2 = style_elem.sheet.cssRules[0].selectorText;
   1.203 +        is(ser2, ser1,
   1.204 +           "parse+serialize of selector " + selector + " is idempotent");
   1.205 +
   1.206 +        ifdoc.body.innerHTML = "";
   1.207 +        style_text.data = "";
   1.208 +
   1.209 +        // Test that it clones to the same thing it serializes to.
   1.210 +        zi = ++gCounter;
   1.211 +        var style_sheet = "data:text/css," +
   1.212 +                          escape("p, " + selector + "{ z-index: " + zi + " }");
   1.213 +        var style_sheet_link =
   1.214 +            "<link rel='stylesheet' href='" + style_sheet + "'>";
   1.215 +        var html_doc = "<!DOCTYPE HTML>" +
   1.216 +                       style_sheet_link + style_sheet_link +
   1.217 +                       "<p></p>";
   1.218 +        var docurl = "data:text/html," + escape(html_doc);
   1.219 +
   1.220 +        defer_clonedoc_tests(docurl, function() {
   1.221 +            var clonedoc = cloneiframe.contentDocument;
   1.222 +            var clonewin = cloneiframe.contentWindow;
   1.223 +            var links = clonedoc.getElementsByTagName("link");
   1.224 +            // cause a clone
   1.225 +            links[1].sheet.insertRule("#nonexistent { color: purple}", 0);
   1.226 +            // remove the uncloned sheet
   1.227 +            links[0].parentNode.removeChild(links[0]);
   1.228 +
   1.229 +            should_match = clonedoc.getElementsByTagName("p")[0];
   1.230 +            is(clonewin.getComputedStyle(should_match, "").zIndex, zi,
   1.231 +               "selector " + selector + " was cloned correctly");
   1.232 +            var ser3 = links[0].sheet.cssRules[1].selectorText;
   1.233 +            is(ser3, ser1,
   1.234 +               "selector " + selector + " serializes correctly after cloning");
   1.235 +        });
   1.236 +    }
   1.237 +
   1.238 +    function test_unparseable_via_api(selector)
   1.239 +    {
   1.240 +        try {
   1.241 +          // Test that it is also unparseable when followed by EOF.
   1.242 +          ifdoc.body.mozMatchesSelector(selector);
   1.243 +          ok(false, "selector '" + selector + "' plus EOF is parse error");
   1.244 +        } catch(ex) {
   1.245 +          is(ex.name, "SyntaxError",
   1.246 +             "selector '" + selector + "' plus EOF is parse error");
   1.247 +          is(ex.code, DOMException.SYNTAX_ERR,
   1.248 +             "selector '" + selector + "' plus EOF is parse error");
   1.249 +        }
   1.250 +    }
   1.251 +
   1.252 +    function test_parseable_via_api(selector)
   1.253 +    {
   1.254 +        var threw = false;
   1.255 +        try {
   1.256 +          // Test that a selector is parseable when followed by EOF.
   1.257 +          ifdoc.body.mozMatchesSelector(selector);
   1.258 +        } catch(ex) {
   1.259 +          threw = true;
   1.260 +        }
   1.261 +        ok(!threw, "selector '" + selector + "' was parsed");
   1.262 +    }
   1.263 +
   1.264 +    function test_balanced_unparseable(selector)
   1.265 +    {
   1.266 +        var zi1 = ++gCounter;
   1.267 +        var zi2 = ++gCounter;
   1.268 +        ifdoc.body.innerHTML = "<p></p><div></div>";
   1.269 +        style_text.data = "p, " + selector + "{ z-index: " + zi1 + " }" +
   1.270 +                          "div { z-index: " + zi2 + " }";
   1.271 +        var should_not_match = ifdoc.getElementsByTagName("p")[0];
   1.272 +        var should_match = ifdoc.getElementsByTagName("div")[0];
   1.273 +        is(ifwin.getComputedStyle(should_not_match, "").zIndex, "auto",
   1.274 +           "selector " + selector + " was a parser error");
   1.275 +        is(ifwin.getComputedStyle(should_match, "").zIndex, zi2,
   1.276 +           "selector " + selector + " error was recovered from");
   1.277 +        ifdoc.body.innerHTML = "";
   1.278 +        style_text.data = "";
   1.279 +        test_unparseable_via_api(selector);
   1.280 +    }
   1.281 +
   1.282 +    function test_unbalanced_unparseable(selector)
   1.283 +    {
   1.284 +        var zi1 = ++gCounter;
   1.285 +        var zi2 = ++gCounter;
   1.286 +        ifdoc.body.innerHTML = "<p></p>";
   1.287 +        style_text.data = "p, " + selector + "{ z-index: " + zi1 + " }";
   1.288 +        var should_not_match = ifdoc.getElementsByTagName("p")[0];
   1.289 +        is(ifwin.getComputedStyle(should_not_match, "").zIndex, "auto",
   1.290 +           "selector " + selector + " was a parser error");
   1.291 +        is(style_text.parentNode.sheet.cssRules.length, 0,
   1.292 +           "sheet should have no rules since " + selector + " is parse error");
   1.293 +        ifdoc.body.innerHTML = "";
   1.294 +        style_text.data = "";
   1.295 +        test_unparseable_via_api(selector);
   1.296 +    }
   1.297 +
   1.298 +
   1.299 +    // [attr= ] selector
   1.300 +    test_parseable("[attr=\"x\"]");
   1.301 +    test_parseable("[attr='x']");
   1.302 +    test_parseable("[attr=x]");
   1.303 +    test_parseable("[attr=\"\"]");
   1.304 +    test_parseable("[attr='']");
   1.305 +    test_parseable("[attr=\"foo bar\"]");
   1.306 +
   1.307 +    test_balanced_unparseable("[attr=]");
   1.308 +    test_balanced_unparseable("[attr=foo bar]");
   1.309 +
   1.310 +    test_selector_in_html(
   1.311 +        '[title=""]',
   1.312 +        '<p title=""></p>'
   1.313 +        + '<div lang=" "></div><div lang="\t"></div><div lang="\n"></div>',
   1.314 +        function(doc) { return doc.getElementsByTagName("p"); },
   1.315 +        function(doc) { return doc.getElementsByTagName("div"); }
   1.316 +    );
   1.317 +
   1.318 +    // [attr~= ] selector
   1.319 +    test_parseable("[attr~=\"x\"]");
   1.320 +    test_parseable("[attr~='x']");
   1.321 +    test_parseable("[attr~=x]");
   1.322 +    test_parseable("[attr~=\"\"]");
   1.323 +    test_parseable("[attr~='']");
   1.324 +    test_parseable("[attr~=\"foo bar\"]");
   1.325 +
   1.326 +    test_balanced_unparseable("[attr~=]");
   1.327 +    test_balanced_unparseable("[attr~=foo bar]");
   1.328 +
   1.329 +    test_selector_in_html(
   1.330 +        '[class~="x x"]',
   1.331 +        '<div class="x x"></div><div class="x"></div><div class="x\tx"></div>div class="x\nx"></div>',
   1.332 +        function(doc) { return []; },
   1.333 +        function(doc) { return doc.getElementsByTagName("div"); }
   1.334 +    );
   1.335 +
   1.336 +    // [attr|="x"]
   1.337 +    test_parseable('[attr|="x"]');
   1.338 +    test_parseable("[attr|='x']");
   1.339 +    test_parseable('[attr|=x]');
   1.340 +
   1.341 +    test_parseable('[attr|=""]');
   1.342 +    test_parseable("[attr|='']");
   1.343 +    test_balanced_unparseable('[attr|=]');
   1.344 +
   1.345 +    test_selector_in_html(
   1.346 +        '[lang|=""]',
   1.347 +        '<p lang=""></p><p lang="-"></p><p lang="-GB"></p>'
   1.348 +        + '<div lang="en-GB"></div><div lang="en-"></div>',
   1.349 +        function(doc) { return doc.getElementsByTagName("p"); },
   1.350 +        function(doc) { return doc.getElementsByTagName("div"); }
   1.351 +    );
   1.352 +
   1.353 +    // [attr$= ] selector
   1.354 +    test_parseable("[attr$=\"x\"]");
   1.355 +    test_parseable("[attr$='x']");
   1.356 +    test_parseable("[attr$=x]");
   1.357 +    test_parseable("[attr$=\"\"]");
   1.358 +    test_parseable("[attr$='']");
   1.359 +    test_parseable("[attr$=\"foo bar\"]");
   1.360 +
   1.361 +    test_balanced_unparseable("[attr$=]");
   1.362 +    test_balanced_unparseable("[attr$=foo bar]");
   1.363 +
   1.364 +    // [attr^= ] selector
   1.365 +    test_parseable("[attr^=\"x\"]");
   1.366 +    test_parseable("[attr^='x']");
   1.367 +    test_parseable("[attr^=x]");
   1.368 +    test_parseable("[attr^=\"\"]");
   1.369 +    test_parseable("[attr^='']");
   1.370 +    test_parseable("[attr^=\"foo bar\"]");
   1.371 +
   1.372 +    test_balanced_unparseable("[attr^=]");
   1.373 +    test_balanced_unparseable("[attr^=foo bar]");
   1.374 +
   1.375 +    // attr[*= ] selector
   1.376 +    test_parseable("[attr*=\"x\"]");
   1.377 +    test_parseable("[attr*='x']");
   1.378 +    test_parseable("[attr*=x]");
   1.379 +    test_parseable("[attr*=\"\"]");
   1.380 +    test_parseable("[attr*='']");
   1.381 +    test_parseable("[attr*=\"foo bar\"]");
   1.382 +
   1.383 +    test_balanced_unparseable("[attr*=]");
   1.384 +    test_balanced_unparseable("[attr*=foo bar]");
   1.385 +
   1.386 +
   1.387 +    // Bug 420814
   1.388 +    test_selector_in_html(
   1.389 +        "div ~ div p",
   1.390 +        "<div></div><div><div><p>match</p></div></div>",
   1.391 +        function(doc) { return doc.getElementsByTagName("p"); },
   1.392 +        function(doc) { return []; }
   1.393 +    );
   1.394 +
   1.395 +    // Bug 420245
   1.396 +    test_selector_in_html(
   1.397 +        "p[attr$=\"\"]",
   1.398 +        "<p attr=\"foo\">This should not match</p>",
   1.399 +        function(doc) { return []; },
   1.400 +        function(doc) { return doc.getElementsByTagName("p"); }
   1.401 +    );
   1.402 +    test_selector_in_html(
   1.403 +        "div + p[attr~=\"\"]",
   1.404 +        "<div>Dummy</div><p attr=\"foo\">This should not match</p>",
   1.405 +        function(doc) { return []; },
   1.406 +        function(doc) { return doc.getElementsByTagName("p"); }
   1.407 +    );
   1.408 +    test_selector_in_html(
   1.409 +        "div[attr^=\"\"]",
   1.410 +        "<div attr=\"dummy1\">Dummy</div><div attr=\"dummy2\">Dummy</div>",
   1.411 +        function(doc) { return []; },
   1.412 +        function(doc) { return doc.getElementsByTagName("div"); }
   1.413 +    );
   1.414 +    test_selector_in_html(
   1.415 +        "div[attr*=\"\"]",
   1.416 +        "<div attr=\"dummy1\">Dummy</div><div attr=\"dummy2\">Dummy</div>",
   1.417 +        function(doc) { return []; },
   1.418 +        function(doc) { return doc.getElementsByTagName("div"); }
   1.419 +    );
   1.420 +
   1.421 +    // :nth-child(), etc.
   1.422 +    // Follow the whitespace rules as proposed in
   1.423 +    // http://lists.w3.org/Archives/Public/www-style/2008Mar/0121.html
   1.424 +    test_balanced_unparseable(":nth-child()");
   1.425 +    test_balanced_unparseable(":nth-of-type( )");
   1.426 +    test_parseable(":nth-last-child( odd)");
   1.427 +    test_parseable(":nth-last-of-type(even )");
   1.428 +    test_parseable(":nth-child(n )");
   1.429 +    test_parseable(":nth-of-type( 2n)");
   1.430 +    test_parseable(":nth-last-child( -n)");
   1.431 +    test_parseable(":nth-last-of-type(-2n )");
   1.432 +    test_balanced_unparseable(":nth-child(- n)");
   1.433 +    test_balanced_unparseable(":nth-of-type(-2 n)");
   1.434 +    test_balanced_unparseable(":nth-last-of-type(2n1)");
   1.435 +    test_balanced_unparseable(":nth-child(2n++1)");
   1.436 +    test_balanced_unparseable(":nth-of-type(2n-+1)");
   1.437 +    test_balanced_unparseable(":nth-last-child(2n+-1)");
   1.438 +    test_balanced_unparseable(":nth-last-of-type(2n--1)");
   1.439 +    test_parseable(":nth-child( 3n + 1 )");
   1.440 +    test_parseable(":nth-child( +3n - 2 )");
   1.441 +    test_parseable(":nth-child( -n+ 6)");
   1.442 +    test_parseable(":nth-child( +6 )");
   1.443 +    test_balanced_unparseable(":nth-child(3 n)");
   1.444 +    test_balanced_unparseable(":nth-child(+ 2n)");
   1.445 +    test_balanced_unparseable(":nth-child(+ 2)");
   1.446 +    test_parseable(":nth-child(3)");
   1.447 +    test_parseable(":nth-of-type(-3)");
   1.448 +    test_parseable(":nth-last-child(+3)");
   1.449 +    test_parseable(":nth-last-of-type(0)");
   1.450 +    test_parseable(":nth-child(-0)");
   1.451 +    test_parseable(":nth-of-type(3n)");
   1.452 +    test_parseable(":nth-last-child(-3n)");
   1.453 +    test_parseable(":nth-last-of-type(+3n)");
   1.454 +    test_parseable(":nth-last-of-type(0n)");
   1.455 +    test_parseable(":nth-child(-0n)");
   1.456 +    test_parseable(":nth-of-type(n)");
   1.457 +    test_parseable(":nth-last-child(-n)");
   1.458 +    test_parseable(":nth-last-of-type(2n+1)");
   1.459 +    test_parseable(":nth-child(2n-1)");
   1.460 +    test_parseable(":nth-of-type(2n+0)");
   1.461 +    test_parseable(":nth-last-child(2n-0)");
   1.462 +    test_parseable(":nth-child(-0n+0)");
   1.463 +    test_parseable(":nth-of-type(n+1)");
   1.464 +    test_parseable(":nth-last-child(n-1)");
   1.465 +    test_parseable(":nth-last-of-type(-n+1)");
   1.466 +    test_parseable(":nth-child(-n-1)");
   1.467 +    test_balanced_unparseable(":nth-child(2-n)");
   1.468 +    test_balanced_unparseable(":nth-child(2-n-1)");
   1.469 +    test_balanced_unparseable(":nth-child(n-2-1)");
   1.470 +    // Bug 750388
   1.471 +    test_parseable(":nth-child(+n)");
   1.472 +    test_balanced_unparseable(":nth-child(+ n)");
   1.473 +    test_parseable(":nth-child(+n+2)");
   1.474 +    test_parseable(":nth-child(+n-2)");
   1.475 +    test_parseable(":nth-child(+n + 2)");
   1.476 +    test_parseable(":nth-child(+n - 2)");
   1.477 +    test_balanced_unparseable(":nth-child(+ n+2)");
   1.478 +    test_balanced_unparseable(":nth-child(+ n-2)");
   1.479 +    test_balanced_unparseable(":nth-child(+ n + 2)");
   1.480 +    test_balanced_unparseable(":nth-child(+ n - 2)");
   1.481 +    test_parseable(":nth-child(+n-100)");
   1.482 +    test_parseable(":nth-child(+n - 100)");
   1.483 +    test_balanced_unparseable(":nth-child(+ n-100)");
   1.484 +    test_balanced_unparseable(":nth-child(+-n+2)");
   1.485 +    test_balanced_unparseable(":nth-child(+ -n+2)");
   1.486 +    test_balanced_unparseable(":nth-child(+-n-100)");
   1.487 +    test_balanced_unparseable(":nth-child(+ -n-100)");
   1.488 +    test_balanced_unparseable(":nth-child(++n-100)");
   1.489 +    test_balanced_unparseable(":nth-child(-+n-100)");
   1.490 +    test_balanced_unparseable(":nth-child(++2n - 100)");
   1.491 +    test_balanced_unparseable(":nth-child(+-2n - 100)");
   1.492 +    test_balanced_unparseable(":nth-child(-+2n - 100)");
   1.493 +    test_balanced_unparseable(":nth-child(--2n - 100)");
   1.494 +    test_balanced_unparseable(":nth-child(+/**/+2n - 100)");
   1.495 +    test_balanced_unparseable(":nth-child(+/**/-2n - 100)");
   1.496 +    test_balanced_unparseable(":nth-child(-/**/+2n - 100)");
   1.497 +    test_balanced_unparseable(":nth-child(-/**/-2n - 100)");
   1.498 +    test_balanced_unparseable(":nth-child(+/**/+/**/2n - 100)");
   1.499 +    test_balanced_unparseable(":nth-child(+/**/-/**/2n - 100)");
   1.500 +    test_balanced_unparseable(":nth-child(-/**/+/**/2n - 100)");
   1.501 +    test_balanced_unparseable(":nth-child(-/**/-/**/2n - 100)");
   1.502 +    test_balanced_unparseable(":nth-child(++/**/2n - 100)");
   1.503 +    test_balanced_unparseable(":nth-child(+-/**/2n - 100)");
   1.504 +    test_balanced_unparseable(":nth-child(-+/**/2n - 100)");
   1.505 +    test_balanced_unparseable(":nth-child(--/**/2n - 100)");
   1.506 +    test_balanced_unparseable(":nth-child(-even)");
   1.507 +    test_balanced_unparseable(":nth-child(-odd)");
   1.508 +    test_balanced_unparseable(":nth-child(+even)");
   1.509 +    test_balanced_unparseable(":nth-child(+odd)");
   1.510 +    test_balanced_unparseable(":nth-child(+ even)");
   1.511 +    test_balanced_unparseable(":nth-child(+ odd)");
   1.512 +    test_balanced_unparseable(":nth-child(+-n)");
   1.513 +    test_balanced_unparseable(":nth-child(+-n-)");
   1.514 +    test_balanced_unparseable(":nth-child(-+n)");
   1.515 +    test_balanced_unparseable(":nth-child(+n--)");
   1.516 +    test_parseable(":nth-child(n+2)");
   1.517 +    test_parseable(":nth-child(n/**/+/**/2)");
   1.518 +    test_parseable(":nth-child(n-2)");
   1.519 +    test_parseable(":nth-child(n/**/-/**/2)");
   1.520 +    test_balanced_unparseable(":nth-child(n++2)");
   1.521 +    test_balanced_unparseable(":nth-child(n+-2)");
   1.522 +    test_balanced_unparseable(":nth-child(n-+2)");
   1.523 +    test_balanced_unparseable(":nth-child(n--2)");
   1.524 +    test_balanced_unparseable(":nth-child(n/**/++2)");
   1.525 +    test_balanced_unparseable(":nth-child(n/**/+-2)");
   1.526 +    test_balanced_unparseable(":nth-child(n/**/-+2)");
   1.527 +    test_balanced_unparseable(":nth-child(n/**/--2)");
   1.528 +    test_balanced_unparseable(":nth-child(n/**/+/**/+2)");
   1.529 +    test_balanced_unparseable(":nth-child(n/**/+/**/-2)");
   1.530 +    test_balanced_unparseable(":nth-child(n/**/-/**/+2)");
   1.531 +    test_balanced_unparseable(":nth-child(n/**/-/**/-2)");
   1.532 +    test_balanced_unparseable(":nth-child(n+/**/+2)");
   1.533 +    test_balanced_unparseable(":nth-child(n+/**/-2)");
   1.534 +    test_balanced_unparseable(":nth-child(n-/**/+2)");
   1.535 +    test_balanced_unparseable(":nth-child(n-/**/-2)");
   1.536 +    test_balanced_unparseable(":nth-child(n++/**/2)");
   1.537 +    test_balanced_unparseable(":nth-child(n+-/**/2)");
   1.538 +    test_balanced_unparseable(":nth-child(n-+/**/2)");
   1.539 +    test_balanced_unparseable(":nth-child(n--/**/2)");
   1.540 +    test_balanced_unparseable(":nth-child(n/**/++/**/2)");
   1.541 +    test_balanced_unparseable(":nth-child(n/**/+-/**/2)");
   1.542 +    test_balanced_unparseable(":nth-child(n/**/-+/**/2)");
   1.543 +    test_balanced_unparseable(":nth-child(n/**/--/**/2)");
   1.544 +    test_balanced_unparseable(":nth-child(n/**/+/**/+/**/2)");
   1.545 +    test_balanced_unparseable(":nth-child(n/**/+/**/-/**/2)");
   1.546 +    test_balanced_unparseable(":nth-child(n/**/-/**/+/**/2)");
   1.547 +    test_balanced_unparseable(":nth-child(n/**/-/**/-/**/2)");
   1.548 +    test_balanced_unparseable(":nth-child(n+/**/+/**/2)");
   1.549 +    test_balanced_unparseable(":nth-child(n+/**/-/**/2)");
   1.550 +    test_balanced_unparseable(":nth-child(n-/**/+/**/2)");
   1.551 +    test_balanced_unparseable(":nth-child(n-/**/-/**/2)");
   1.552 +    test_parseable(":nth-child(2n+2)");
   1.553 +    test_parseable(":nth-child(2n/**/+/**/2)");
   1.554 +    test_parseable(":nth-child(2n-2)");
   1.555 +    test_parseable(":nth-child(2n/**/-/**/2)");
   1.556 +    test_balanced_unparseable(":nth-child(2n++2)");
   1.557 +    test_balanced_unparseable(":nth-child(2n+-2)");
   1.558 +    test_balanced_unparseable(":nth-child(2n-+2)");
   1.559 +    test_balanced_unparseable(":nth-child(2n--2)");
   1.560 +    test_balanced_unparseable(":nth-child(2n/**/++2)");
   1.561 +    test_balanced_unparseable(":nth-child(2n/**/+-2)");
   1.562 +    test_balanced_unparseable(":nth-child(2n/**/-+2)");
   1.563 +    test_balanced_unparseable(":nth-child(2n/**/--2)");
   1.564 +    test_balanced_unparseable(":nth-child(2n/**/+/**/+2)");
   1.565 +    test_balanced_unparseable(":nth-child(2n/**/+/**/-2)");
   1.566 +    test_balanced_unparseable(":nth-child(2n/**/-/**/+2)");
   1.567 +    test_balanced_unparseable(":nth-child(2n/**/-/**/-2)");
   1.568 +    test_balanced_unparseable(":nth-child(2n+/**/+2)");
   1.569 +    test_balanced_unparseable(":nth-child(2n+/**/-2)");
   1.570 +    test_balanced_unparseable(":nth-child(2n-/**/+2)");
   1.571 +    test_balanced_unparseable(":nth-child(2n-/**/-2)");
   1.572 +    test_balanced_unparseable(":nth-child(2n++/**/2)");
   1.573 +    test_balanced_unparseable(":nth-child(2n+-/**/2)");
   1.574 +    test_balanced_unparseable(":nth-child(2n-+/**/2)");
   1.575 +    test_balanced_unparseable(":nth-child(2n--/**/2)");
   1.576 +    test_balanced_unparseable(":nth-child(2n/**/++/**/2)");
   1.577 +    test_balanced_unparseable(":nth-child(2n/**/+-/**/2)");
   1.578 +    test_balanced_unparseable(":nth-child(2n/**/-+/**/2)");
   1.579 +    test_balanced_unparseable(":nth-child(2n/**/--/**/2)");
   1.580 +    test_balanced_unparseable(":nth-child(2n/**/+/**/+/**/2)");
   1.581 +    test_balanced_unparseable(":nth-child(2n/**/+/**/-/**/2)");
   1.582 +    test_balanced_unparseable(":nth-child(2n/**/-/**/+/**/2)");
   1.583 +    test_balanced_unparseable(":nth-child(2n/**/-/**/-/**/2)");
   1.584 +    test_balanced_unparseable(":nth-child(2n+/**/+/**/2)");
   1.585 +    test_balanced_unparseable(":nth-child(2n+/**/-/**/2)");
   1.586 +    test_balanced_unparseable(":nth-child(2n-/**/+/**/2)");
   1.587 +    test_balanced_unparseable(":nth-child(2n-/**/-/**/2)");
   1.588 +    test_parseable(":nth-child(+/**/n+2)");
   1.589 +    test_parseable(":nth-child(+n/**/+2)");
   1.590 +    test_parseable(":nth-child(+n/**/+2)");
   1.591 +    test_parseable(":nth-child(+n+/**/2)");
   1.592 +    test_parseable(":nth-child(+n+2/**/)");
   1.593 +    test_parseable(":nth-child(+1/**/n+2)");
   1.594 +    test_parseable(":nth-child(+1n/**/+2)");
   1.595 +    test_parseable(":nth-child(+1n/**/+2)");
   1.596 +    test_parseable(":nth-child(+1n+/**/2)");
   1.597 +    test_parseable(":nth-child(+1n+2/**/)");
   1.598 +    test_parseable(":nth-child(-/**/n+2)");
   1.599 +    test_parseable(":nth-child(-n/**/+2)");
   1.600 +    test_parseable(":nth-child(-n/**/+2)");
   1.601 +    test_parseable(":nth-child(-n+/**/2)");
   1.602 +    test_parseable(":nth-child(-n+2/**/)");
   1.603 +    test_parseable(":nth-child(-1/**/n+2)");
   1.604 +    test_parseable(":nth-child(-1n/**/+2)");
   1.605 +    test_parseable(":nth-child(-1n/**/+2)");
   1.606 +    test_parseable(":nth-child(-1n+/**/2)");
   1.607 +    test_parseable(":nth-child(-1n+2/**/)");
   1.608 +    test_balanced_unparseable(":nth-child(-/**/ n+2)");
   1.609 +    test_balanced_unparseable(":nth-child(- /**/n+2)");
   1.610 +    test_balanced_unparseable(":nth-child(+/**/ n+2)");
   1.611 +    test_balanced_unparseable(":nth-child(+ /**/n+2)");
   1.612 +    test_parseable(":nth-child(+/**/n-2)");
   1.613 +    test_parseable(":nth-child(+n/**/-2)");
   1.614 +    test_parseable(":nth-child(+n/**/-2)");
   1.615 +    test_parseable(":nth-child(+n-/**/2)");
   1.616 +    test_parseable(":nth-child(+n-2/**/)");
   1.617 +    test_parseable(":nth-child(+1/**/n-2)");
   1.618 +    test_parseable(":nth-child(+1n/**/-2)");
   1.619 +    test_parseable(":nth-child(+1n/**/-2)");
   1.620 +    test_parseable(":nth-child(+1n-/**/2)");
   1.621 +    test_parseable(":nth-child(+1n-2/**/)");
   1.622 +    test_parseable(":nth-child(-/**/n-2)");
   1.623 +    test_parseable(":nth-child(-n/**/-2)");
   1.624 +    test_parseable(":nth-child(-n/**/-2)");
   1.625 +    test_parseable(":nth-child(-n-/**/2)");
   1.626 +    test_parseable(":nth-child(-n-2/**/)");
   1.627 +    test_parseable(":nth-child(-1/**/n-2)");
   1.628 +    test_parseable(":nth-child(-1n/**/-2)");
   1.629 +    test_parseable(":nth-child(-1n/**/-2)");
   1.630 +    test_parseable(":nth-child(-1n-/**/2)");
   1.631 +    test_parseable(":nth-child(-1n-2/**/)");
   1.632 +    test_balanced_unparseable(":nth-child(-/**/ n-2)");
   1.633 +    test_balanced_unparseable(":nth-child(- /**/n-2)");
   1.634 +    test_balanced_unparseable(":nth-child(+/**/ n-2)");
   1.635 +    test_balanced_unparseable(":nth-child(+ /**/n-2)");
   1.636 +    test_parseable(":nth-child( +n + 1 )");
   1.637 +    test_parseable(":nth-child( +/**/n + 1 )");
   1.638 +    test_parseable(":nth-child( -/**/2/**/n/**/+/**/4 )");
   1.639 +    test_balanced_unparseable(":nth-child( -/**/ 2/**/n/**/+/**/4 )");
   1.640 +    test_balanced_unparseable(":nth-child( -/**/2 /**/n/**/+/**/4 )");
   1.641 +    test_balanced_unparseable(":nth-child( -/**/2/**/ n/**/+/**/4 )");
   1.642 +    test_parseable(":nth-child( -/**/2/**/n /**/+/**/4 )");
   1.643 +    test_parseable(":nth-child( -/**/2/**/n/**/ +/**/4 )");
   1.644 +    test_parseable(":nth-child(+1/**/n-1)");
   1.645 +    test_parseable(":nth-child(1/**/n-1)");
   1.646 +    // bug 876570
   1.647 +    test_balanced_unparseable(":nth-child(+2n-)");
   1.648 +    test_balanced_unparseable(":nth-child(+n-)");
   1.649 +    test_balanced_unparseable(":nth-child(-2n-)");
   1.650 +    test_balanced_unparseable(":nth-child(-n-)");
   1.651 +    test_balanced_unparseable(":nth-child(2n-)");
   1.652 +    test_balanced_unparseable(":nth-child(n-)");
   1.653 +    test_balanced_unparseable(":nth-child(+2n+)");
   1.654 +    test_balanced_unparseable(":nth-child(+n+)");
   1.655 +    test_balanced_unparseable(":nth-child(-2n+)");
   1.656 +    test_balanced_unparseable(":nth-child(-n+)");
   1.657 +    test_balanced_unparseable(":nth-child(2n+)");
   1.658 +    test_balanced_unparseable(":nth-child(n+)");
   1.659 +
   1.660 +    // exercise the an+b matching logic particularly hard for
   1.661 +    // :nth-child() (since we know we use the same code for all 4)
   1.662 +    var seven_ps = "<p></p><p></p><p></p><p></p><p></p><p></p><p></p>";
   1.663 +    function pset(indices) { // takes an array of 1-based indices
   1.664 +        return function pset_filter(doc) {
   1.665 +            var a = doc.getElementsByTagName("p");
   1.666 +            var result = [];
   1.667 +            for (var i in indices)
   1.668 +                result.push(a[indices[i] - 1]);
   1.669 +            return result;
   1.670 +        }
   1.671 +    }
   1.672 +    test_selector_in_html(":nth-child(0)", seven_ps,
   1.673 +                          pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
   1.674 +    test_selector_in_html(":nth-child(-3)", seven_ps,
   1.675 +                          pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
   1.676 +    test_selector_in_html(":nth-child(3)", seven_ps,
   1.677 +                          pset([3]), pset([1, 2, 4, 5, 6, 7]));
   1.678 +    test_selector_in_html(":nth-child(0n+3)", seven_ps,
   1.679 +                          pset([3]), pset([1, 2, 4, 5, 6, 7]));
   1.680 +    test_selector_in_html(":nth-child(-0n+3)", seven_ps,
   1.681 +                          pset([3]), pset([1, 2, 4, 5, 6, 7]));
   1.682 +    test_selector_in_html(":nth-child(8)", seven_ps,
   1.683 +                          pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
   1.684 +    test_selector_in_html(":nth-child(odd)", seven_ps,
   1.685 +                          pset([1, 3, 5, 7]), pset([2, 4, 6]));
   1.686 +    test_selector_in_html(":nth-child(even)", seven_ps,
   1.687 +                          pset([2, 4, 6]), pset([1, 3, 5, 7]));
   1.688 +    test_selector_in_html(":nth-child(2n-1)", seven_ps,
   1.689 +                          pset([1, 3, 5, 7]), pset([2, 4, 6]));
   1.690 +    test_selector_in_html(":nth-child( 2n - 1 )", seven_ps,
   1.691 +                          pset([1, 3, 5, 7]), pset([2, 4, 6]));
   1.692 +    test_selector_in_html(":nth-child(2n+1)", seven_ps,
   1.693 +                          pset([1, 3, 5, 7]), pset([2, 4, 6]));
   1.694 +    test_selector_in_html(":nth-child( 2n + 1 )", seven_ps,
   1.695 +                          pset([1, 3, 5, 7]), pset([2, 4, 6]));
   1.696 +    test_selector_in_html(":nth-child(2n+0)", seven_ps,
   1.697 +                          pset([2, 4, 6]), pset([1, 3, 5, 7]));
   1.698 +    test_selector_in_html(":nth-child(2n-0)", seven_ps,
   1.699 +                          pset([2, 4, 6]), pset([1, 3, 5, 7]));
   1.700 +    test_selector_in_html(":nth-child(-n+3)", seven_ps,
   1.701 +                          pset([1, 2, 3]), pset([4, 5, 6, 7]));
   1.702 +    test_selector_in_html(":nth-child(-n-3)", seven_ps,
   1.703 +                          pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
   1.704 +    test_selector_in_html(":nth-child(n)", seven_ps,
   1.705 +                          pset([1, 2, 3, 4, 5, 6, 7]), pset([]));
   1.706 +    test_selector_in_html(":nth-child(n-3)", seven_ps,
   1.707 +                          pset([1, 2, 3, 4, 5, 6, 7]), pset([]));
   1.708 +    test_selector_in_html(":nth-child(n+3)", seven_ps,
   1.709 +                          pset([3, 4, 5, 6, 7]), pset([1, 2]));
   1.710 +    test_selector_in_html(":nth-child(2n+3)", seven_ps,
   1.711 +                          pset([3, 5, 7]), pset([1, 2, 4, 6]));
   1.712 +    test_selector_in_html(":nth-child(2n)", seven_ps,
   1.713 +                          pset([2, 4, 6]), pset([1, 3, 5, 7]));
   1.714 +    test_selector_in_html(":nth-child(2n-3)", seven_ps,
   1.715 +                          pset([1, 3, 5, 7]), pset([2, 4, 6]));
   1.716 +    test_selector_in_html(":nth-child(-1n+3)", seven_ps,
   1.717 +                          pset([1, 2, 3]), pset([4, 5, 6, 7]));
   1.718 +    test_selector_in_html(":nth-child(-2n+3)", seven_ps,
   1.719 +                          pset([1, 3]), pset([2, 4, 5, 6, 7]));
   1.720 +    // And a few spot-checks for the other :nth-* selectors
   1.721 +    test_selector_in_html(":nth-child(4n+1)", seven_ps,
   1.722 +                          pset([1, 5]), pset([2, 3, 4, 6, 7]));
   1.723 +    test_selector_in_html(":nth-last-child(4n+1)", seven_ps,
   1.724 +                          pset([3, 7]), pset([1, 2, 4, 5, 6]));
   1.725 +    test_selector_in_html(":nth-of-type(4n+1)", seven_ps,
   1.726 +                          pset([1, 5]), pset([2, 3, 4, 6, 7]));
   1.727 +    test_selector_in_html(":nth-last-of-type(4n+1)", seven_ps,
   1.728 +                          pset([3, 7]), pset([1, 2, 4, 5, 6]));
   1.729 +    test_selector_in_html(":nth-child(6)", seven_ps,
   1.730 +                          pset([6]), pset([1, 2, 3, 4, 5, 7]));
   1.731 +    test_selector_in_html(":nth-last-child(6)", seven_ps,
   1.732 +                          pset([2]), pset([1, 3, 4, 5, 6, 7]));
   1.733 +    test_selector_in_html(":nth-of-type(6)", seven_ps,
   1.734 +                          pset([6]), pset([1, 2, 3, 4, 5, 7]));
   1.735 +    test_selector_in_html(":nth-last-of-type(6)", seven_ps,
   1.736 +                          pset([2]), pset([1, 3, 4, 5, 6, 7]));
   1.737 +
   1.738 +    // Test [first|last|only]-[child|node|of-type]
   1.739 +    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> <!---->";
   1.740 +    function idset(ids) { // takes an array of ids
   1.741 +        return function idset_filter(doc) {
   1.742 +            var result = [];
   1.743 +            for (var id of ids)
   1.744 +                result.push(doc.getElementById(id));
   1.745 +            return result;
   1.746 +        }
   1.747 +    }
   1.748 +    function classset(classes) { // takes an array of classes
   1.749 +        return function classset_filter(doc) {
   1.750 +            var i, j, els;
   1.751 +            var result = [];
   1.752 +            for (i = 0; i < classes.length; i++) {
   1.753 +                els = doc.getElementsByClassName(classes[i]);
   1.754 +                for (j = 0; j < els.length; j++) {
   1.755 +                    result.push(els[j]);
   1.756 +                }
   1.757 +            }
   1.758 +            return result;
   1.759 +        }
   1.760 +    }
   1.761 +    function emptyset(doc) { return []; }
   1.762 +    test_parseable(":first-child");
   1.763 +    test_parseable(":last-child");
   1.764 +    test_parseable(":only-child");
   1.765 +    test_parseable(":-moz-first-node");
   1.766 +    test_parseable(":-moz-last-node");
   1.767 +    test_parseable(":first-of-type");
   1.768 +    test_parseable(":last-of-type");
   1.769 +    test_parseable(":only-of-type");
   1.770 +    test_selector_in_html(":first-child", seven_ps,
   1.771 +                          pset([1]), pset([2, 3, 4, 5, 6, 7]));
   1.772 +    test_selector_in_html(":first-child", interesting_doc,
   1.773 +                          idset(["p1", "s1", "s3", "s5"]),
   1.774 +                          idset(["s2", "p2", "s4", "p3"]));
   1.775 +    test_selector_in_html(":-moz-first-node", interesting_doc,
   1.776 +                          idset(["p1", "s3", "s5"]),
   1.777 +                          idset(["s1", "s2", "p2", "s4", "p3"]));
   1.778 +    test_selector_in_html(":last-child", seven_ps,
   1.779 +                          pset([7]), pset([1, 2, 3, 4, 5, 6]));
   1.780 +    test_selector_in_html(":last-child", interesting_doc,
   1.781 +                          idset(["s2", "s4", "p3", "s5"]),
   1.782 +                          idset(["p1", "s1", "p2", "s3"]));
   1.783 +    test_selector_in_html(":-moz-last-node", interesting_doc,
   1.784 +                          idset(["s2", "p3", "s5"]),
   1.785 +                          idset(["p1", "s1", "p2", "s3", "s4"]));
   1.786 +    test_selector_in_html(":only-child", seven_ps,
   1.787 +                          pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
   1.788 +    test_selector_in_html(":only-child", interesting_doc,
   1.789 +                          idset(["s5"]),
   1.790 +                          idset(["p1", "s1", "s2", "p2", "s3", "s4", "p3"]));
   1.791 +    test_selector_in_html(":first-of-type", seven_ps,
   1.792 +                          pset([1]), pset([2, 3, 4, 5, 6, 7]));
   1.793 +    test_selector_in_html(":first-of-type", interesting_doc,
   1.794 +                          idset(["p1", "s1", "p2", "s3", "s5"]),
   1.795 +                          idset(["s2", "s4", "p3"]));
   1.796 +    test_selector_in_html(":last-of-type", seven_ps,
   1.797 +                          pset([7]), pset([1, 2, 3, 4, 5, 6]));
   1.798 +    test_selector_in_html(":last-of-type", interesting_doc,
   1.799 +                          idset(["s2", "p2", "s4", "p3", "s5"]),
   1.800 +                          idset(["p1", "s1", "s3"]));
   1.801 +    test_selector_in_html(":only-of-type", seven_ps,
   1.802 +                          pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
   1.803 +    test_selector_in_html(":only-of-type", interesting_doc,
   1.804 +                          idset(["p2", "s5"]),
   1.805 +                          idset(["p1", "s1", "s2", "s3", "s4", "p3"]));
   1.806 +
   1.807 +    // And a bunch of tests for the of-type aspect of :nth-of-type() and
   1.808 +    // :nth-last-of-type().  Note that the last div here contains two
   1.809 +    // children.
   1.810 +    var mixed_elements="<p></p><p></p><div></div><p></p><div><p></p><address></address></div><address></address>";
   1.811 +    function pdaset(ps, divs, addresses) { // takes an array of 1-based indices
   1.812 +        var l = { p: ps, div: divs, address: addresses };
   1.813 +        return function pdaset_filter(doc) {
   1.814 +            var result = [];
   1.815 +            for (var tag in l) {
   1.816 +                var a = doc.getElementsByTagName(tag);
   1.817 +                var indices = l[tag];
   1.818 +                for (var i in indices)
   1.819 +                    result.push(a[indices[i] - 1]);
   1.820 +            }
   1.821 +            return result;
   1.822 +        }
   1.823 +    }
   1.824 +    test_selector_in_html(":nth-of-type(odd)", mixed_elements,
   1.825 +                          pdaset([1, 3, 4], [1], [1, 2]),
   1.826 +                          pdaset([2], [2], []));
   1.827 +    test_selector_in_html(":nth-of-type(2n-0)", mixed_elements,
   1.828 +                          pdaset([2], [2], []),
   1.829 +                          pdaset([1, 3, 4], [1], [1, 2]));
   1.830 +    test_selector_in_html(":nth-last-of-type(even)", mixed_elements,
   1.831 +                          pdaset([2], [1], []),
   1.832 +                          pdaset([1, 3, 4], [2], [1, 2]));
   1.833 +
   1.834 +    // Test greediness of descendant combinators.
   1.835 +    var four_children="<div id='a'><div id='b'><div id='c'><div id='d'><\/div><\/div><\/div><\/div>";
   1.836 +    test_selector_in_html("#a > div div", four_children,
   1.837 +                          idset(["c", "d"]), idset(["a", "b"]));
   1.838 +    test_selector_in_html("#a > #b div", four_children,
   1.839 +                          idset(["c", "d"]), idset(["a", "b"]));
   1.840 +    test_selector_in_html("#a div > div", four_children,
   1.841 +                          idset(["c", "d"]), idset(["a", "b"]));
   1.842 +    test_selector_in_html("#a #b > div", four_children,
   1.843 +                          idset(["c"]), idset(["a", "b", "d"]));
   1.844 +    test_selector_in_html("#a > #b div", four_children,
   1.845 +                          idset(["c", "d"]), idset(["a", "b"]));
   1.846 +    test_selector_in_html("#a #c > div", four_children,
   1.847 +                          idset(["d"]), idset(["a", "b", "c"]));
   1.848 +    test_selector_in_html("#a > #c div", four_children,
   1.849 +                          idset([]), idset(["a", "b", "c", "d"]));
   1.850 +
   1.851 +    // More descendant combinator greediness (bug 511147)
   1.852 +    test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="b"></div><div class="match"></div></div>',
   1.853 +                         classset(["match"]), classset(["a", "b"]));
   1.854 +    test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="b"></div><div class="x"></div><div class="match"></div></div>',
   1.855 +                         classset(["match"]), classset(["a", "b", "x"]));
   1.856 +    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>',
   1.857 +                         classset(["match"]), classset(["a", "b", "x"]));
   1.858 +    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>',
   1.859 +                         classset(["match"]), classset(["a", "b", "x"]));
   1.860 +    test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="b"></div><div class="match"></div><div class="match"></div></div>',
   1.861 +                         classset(["match"]), classset(["a", "b"]));
   1.862 +
   1.863 +    test_selector_in_html(".a > .b ~ .nomatch", '<div class="a"><div><div class="b"></div><div class="nomatch"></div></div></div>',
   1.864 +                         emptyset, classset(["a", "b", "nomatch"]));
   1.865 +    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>',
   1.866 +                         emptyset, classset(["a", "b", "nomatch"]));
   1.867 +    test_selector_in_html(".a > .b ~ .nomatch", '<div class="a"><div class="b"></div><div><div class="nomatch"></div></div><div></div></div>',
   1.868 +                         emptyset, classset(["a", "b", "nomatch"]));
   1.869 +    test_selector_in_html(".a > .b ~ .nomatch", '<div class="a"><div class="b"></div></div><div class="nomatch"></div>',
   1.870 +                         emptyset, classset(["a", "b", "nomatch"]));
   1.871 +
   1.872 +    // Test serialization of pseudo-elements.
   1.873 +    should_serialize_to("p:first-letter", "p:first-letter");
   1.874 +    should_serialize_to("div>p:first-letter", "div > p:first-letter");
   1.875 +    should_serialize_to("span +div:first-line", "span + div:first-line");
   1.876 +
   1.877 +    // Test default namespaces, including inside :not().
   1.878 +    var html_default_ns = "@namespace url(http://www.w3.org/1999/xhtml);";
   1.879 +    var html_ns = "@namespace html url(http://www.w3.org/1999/xhtml);";
   1.880 +    var xul_default_ns = "@namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);";
   1.881 +    var single_a = "<a id='a' href='data:text/plain,this_better_be_unvisited'></a>";
   1.882 +    var set_single = idset(['a']);
   1.883 +    var empty_set = idset([]);
   1.884 +    test_selector_in_html("a", single_a, set_single, empty_set,
   1.885 +                          html_default_ns);
   1.886 +    test_selector_in_html("a", single_a, empty_set, set_single,
   1.887 +                          xul_default_ns);
   1.888 +    test_selector_in_html("*|a", single_a, set_single, empty_set,
   1.889 +                          xul_default_ns);
   1.890 +    test_selector_in_html("html|a", single_a, set_single, empty_set,
   1.891 +                          xul_default_ns + html_ns);
   1.892 +    // Type selectors inside :not() bring in default namespaces, but
   1.893 +    // non-type selectors don't.
   1.894 +    test_selector_in_html("*|a:not(*)", single_a, set_single, empty_set,
   1.895 +                          xul_default_ns);
   1.896 +    test_selector_in_html("*|a:not(a)", single_a, set_single, empty_set,
   1.897 +                          xul_default_ns);
   1.898 +    test_selector_in_html("*|a:not(*|*)", single_a, empty_set, set_single,
   1.899 +                          xul_default_ns);
   1.900 +    test_selector_in_html("*|a:not(*|a)", single_a, empty_set, set_single,
   1.901 +                          xul_default_ns);
   1.902 +    test_selector_in_html("*|a:not(:link)", single_a + "<a id='b'></a>",
   1.903 +                          idset(["b"]), set_single,
   1.904 +                          xul_default_ns);
   1.905 +    test_selector_in_html("*|a:not(:visited)", single_a + "<a id='b'></a>",
   1.906 +                          idset(["a", "b"]), empty_set,
   1.907 +                          xul_default_ns);
   1.908 +    test_selector_in_html("*|a:not(html|*)", single_a, empty_set, set_single,
   1.909 +                          xul_default_ns + html_ns);
   1.910 +    test_selector_in_html("*|a:not(html|a)", single_a, empty_set, set_single,
   1.911 +                          xul_default_ns + html_ns);
   1.912 +    test_selector_in_html("*|a:not(|*)", single_a, set_single, empty_set,
   1.913 +                          xul_default_ns + html_ns);
   1.914 +    test_selector_in_html("*|a:not(|a)", single_a, set_single, empty_set,
   1.915 +                          xul_default_ns + html_ns);
   1.916 +    test_selector_in_html("html|a:not(|*)", single_a, set_single, empty_set,
   1.917 +                          xul_default_ns + html_ns);
   1.918 +    test_selector_in_html("html|a:not(|a)", single_a, set_single, empty_set,
   1.919 +                          xul_default_ns + html_ns);
   1.920 +    test_selector_in_html("html|a:not(*|*)", single_a, empty_set, set_single,
   1.921 +                          xul_default_ns + html_ns);
   1.922 +    test_selector_in_html("html|a:not(*|a)", single_a, empty_set, set_single,
   1.923 +                          xul_default_ns + html_ns);
   1.924 +
   1.925 +    // Test -moz-locale-dir
   1.926 +    test_parseable(":-moz-locale-dir(ltr)");
   1.927 +    test_parseable(":-moz-locale-dir(rtl)");
   1.928 +    test_parseable(":-moz-locale-dir(rTl)");
   1.929 +    test_parseable(":-moz-locale-dir(LTR)");
   1.930 +    if (document.body.mozMatchesSelector(":-moz-locale-dir(ltr)")) {
   1.931 +        test_selector_in_html("a:-moz-locale-dir(LTr)", single_a,
   1.932 +                              set_single, empty_set);
   1.933 +        test_selector_in_html("a:-moz-locale-dir(ltR)", single_a,
   1.934 +                              set_single, empty_set);
   1.935 +        test_selector_in_html("a:-moz-locale-dir(LTR)", single_a,
   1.936 +                              set_single, empty_set);
   1.937 +        test_selector_in_html("a:-moz-locale-dir(RTl)", single_a,
   1.938 +                              empty_set, set_single);
   1.939 +    } else {
   1.940 +        test_selector_in_html("a:-moz-locale-dir(RTl)", single_a,
   1.941 +                              set_single, empty_set);
   1.942 +        test_selector_in_html("a:-moz-locale-dir(rtL)", single_a,
   1.943 +                              set_single, empty_set);
   1.944 +        test_selector_in_html("a:-moz-locale-dir(RTL)", single_a,
   1.945 +                              set_single, empty_set);
   1.946 +        test_selector_in_html("a:-moz-locale-dir(LTr)", single_a,
   1.947 +                              empty_set, set_single);
   1.948 +    }
   1.949 +
   1.950 +    test_balanced_unparseable(":-moz-locale-dir(other)");
   1.951 +    test_balanced_unparseable(":-moz-locale-dir()");
   1.952 +    test_balanced_unparseable(":-moz-locale-dir(())");
   1.953 +    test_balanced_unparseable(":-moz-locale-dir(3())");
   1.954 +    test_balanced_unparseable(":-moz-locale-dir(f{})");
   1.955 +    test_balanced_unparseable(":-moz-locale-dir('ltr')");
   1.956 +    test_balanced_unparseable(":-moz-locale-dir(ltr, other)");
   1.957 +    test_balanced_unparseable(":-moz-locale-dir");
   1.958 +
   1.959 +    // Test :-moz-dir()
   1.960 +    test_parseable(":-moz-dir(ltr)");
   1.961 +    test_parseable(":-moz-dir(rtl)");
   1.962 +    test_parseable(":-moz-dir(rTl)");
   1.963 +    test_parseable(":-moz-dir(LTR)");
   1.964 +    if (document.body.mozMatchesSelector(":-moz-dir(ltr)")) {
   1.965 +        test_selector_in_html("a:-moz-dir(LTr)", single_a,
   1.966 +                              set_single, empty_set);
   1.967 +        test_selector_in_html("a:-moz-dir(ltR)", single_a,
   1.968 +                              set_single, empty_set);
   1.969 +        test_selector_in_html("a:-moz-dir(LTR)", single_a,
   1.970 +                              set_single, empty_set);
   1.971 +        test_selector_in_html("a:-moz-dir(RTl)", single_a,
   1.972 +                              empty_set, set_single);
   1.973 +    } else {
   1.974 +        test_selector_in_html("a:-moz-dir(RTl)", single_a,
   1.975 +                              set_single, empty_set);
   1.976 +        test_selector_in_html("a:-moz-dir(rtL)", single_a,
   1.977 +                              set_single, empty_set);
   1.978 +        test_selector_in_html("a:-moz-dir(RTL)", single_a,
   1.979 +                              set_single, empty_set);
   1.980 +        test_selector_in_html("a:-moz-dir(LTr)", single_a,
   1.981 +                              empty_set, set_single);
   1.982 +    }
   1.983 +
   1.984 +    test_balanced_unparseable(":-moz-dir(other)");
   1.985 +    test_balanced_unparseable(":-moz-dir()");
   1.986 +    test_balanced_unparseable(":-moz-dir(())");
   1.987 +    test_balanced_unparseable(":-moz-dir(3())");
   1.988 +    test_balanced_unparseable(":-moz-dir(f{})");
   1.989 +    test_balanced_unparseable(":-moz-dir('ltr')");
   1.990 +    test_balanced_unparseable(":-moz-dir(ltr, other)");
   1.991 +    test_balanced_unparseable(":-moz-dir");
   1.992 +
   1.993 +    // Test -moz-lwtheme and -moz-lwtheme-[darktext|brighttext]
   1.994 +    test_parseable(":-moz-lwtheme");
   1.995 +    test_parseable(":-moz-lwtheme-brighttext");
   1.996 +    test_parseable(":-moz-lwtheme-darktext");
   1.997 +
   1.998 +    test_parseable(":-moz-tree-row(selected)");
   1.999 +    test_parseable("::-moz-tree-row(selected)");
  1.1000 +    test_parseable(":-moz-tree-row(selected focus)");
  1.1001 +    test_parseable(":-moz-tree-row(selected , focus)");
  1.1002 +    test_parseable("::-moz-tree-row(selected ,focus)");
  1.1003 +    test_parseable(":-moz-tree-row(selected, focus)");
  1.1004 +    test_parseable("::-moz-tree-row(selected,focus)");
  1.1005 +    test_parseable(":-moz-tree-row(selected     focus)");
  1.1006 +    test_parseable("::-moz-tree-row(selected    ,   focus)");
  1.1007 +    test_parseable("::-moz-tree-twisty(  hover open  )");
  1.1008 +    test_balanced_unparseable("::-moz-tree-row(selected {[]} )");
  1.1009 +    test_balanced_unparseable(":-moz-tree-twisty(open())");
  1.1010 +    test_balanced_unparseable("::-moz-tree-twisty(hover ())");
  1.1011 +
  1.1012 +    test_parseable(":-moz-window-inactive");
  1.1013 +    test_parseable("div p:-moz-window-inactive:hover span");
  1.1014 +
  1.1015 +    // Plugin pseudoclasses
  1.1016 +    test_parseable(":-moz-type-unsupported");
  1.1017 +    test_parseable(":-moz-handler-disabled");
  1.1018 +    test_parseable(":-moz-handler-blocked");
  1.1019 +    test_parseable(":-moz-handler-crashed");
  1.1020 +
  1.1021 +    // Case sensitivity of tag selectors
  1.1022 +    function setup_cased_spans(body) {
  1.1023 +      var data = [
  1.1024 +        { tag: "span" },
  1.1025 +        { tag: "sPaN" },
  1.1026 +        { tag: "Span" },
  1.1027 +        { tag: "SPAN" },
  1.1028 +        { ns: "http://www.w3.org/1999/xhtml", tag: "span" },
  1.1029 +        { ns: "http://www.w3.org/1999/xhtml", tag: "sPaN" },
  1.1030 +        { ns: "http://www.w3.org/1999/xhtml", tag: "Span" },
  1.1031 +        { ns: "http://www.w3.org/1999/xhtml", tag: "SPAN" },
  1.1032 +        { ns: "http://example.com/useless", tag: "span" },
  1.1033 +        { ns: "http://example.com/useless", tag: "sPaN" },
  1.1034 +        { ns: "http://example.com/useless", tag: "Span" },
  1.1035 +        { ns: "http://example.com/useless", tag: "SPAN" },
  1.1036 +      ]
  1.1037 +      for (var i in data) {
  1.1038 +        var ent = data[i];
  1.1039 +        var elem;
  1.1040 +        if ("ns" in ent) {
  1.1041 +          elem = body.ownerDocument.createElementNS(ent.ns, ent.tag);
  1.1042 +        } else {
  1.1043 +          elem = body.ownerDocument.createElement(ent.tag);
  1.1044 +        }
  1.1045 +        body.appendChild(elem);
  1.1046 +      }
  1.1047 +    }
  1.1048 +    function bodychildset(indices) {
  1.1049 +      return function bodychildset_filter(doc) {
  1.1050 +        var body = doc.body;
  1.1051 +        var result = [];
  1.1052 +        for (var i in indices) {
  1.1053 +          result.push(body.childNodes[indices[i]]);
  1.1054 +        }
  1.1055 +        return result;
  1.1056 +      }
  1.1057 +    }
  1.1058 +    test_selector_in_html("span", setup_cased_spans,
  1.1059 +                          bodychildset([0, 1, 2, 3, 4, 8]),
  1.1060 +                          bodychildset([5, 6, 7, 9, 10, 11]));
  1.1061 +    test_selector_in_html("sPaN", setup_cased_spans,
  1.1062 +                          bodychildset([0, 1, 2, 3, 4, 9]),
  1.1063 +                          bodychildset([5, 6, 7, 8, 10, 11]));
  1.1064 +    test_selector_in_html("Span", setup_cased_spans,
  1.1065 +                          bodychildset([0, 1, 2, 3, 4, 10]),
  1.1066 +                          bodychildset([5, 6, 7, 8, 9, 11]));
  1.1067 +    test_selector_in_html("SPAN", setup_cased_spans,
  1.1068 +                          bodychildset([0, 1, 2, 3, 4, 11]),
  1.1069 +                          bodychildset([5, 6, 7, 8, 9, 10]));
  1.1070 +
  1.1071 +    // bug 528096 (tree pseudos)
  1.1072 +    test_unbalanced_unparseable(":-moz-tree-column((){} a");
  1.1073 +    test_unbalanced_unparseable(":-moz-tree-column(x(){} a");
  1.1074 +    test_unbalanced_unparseable(":-moz-tree-column(a b (){} a");
  1.1075 +    test_unbalanced_unparseable(":-moz-tree-column(a, b (){} a");
  1.1076 +
  1.1077 +    // Bug 543428 (escaping)
  1.1078 +    test_selector_in_html("\\32|a", single_a, set_single, empty_set,
  1.1079 +                          "@namespace \\32  url(http://www.w3.org/1999/xhtml);");
  1.1080 +    test_selector_in_html("-\\32|a", single_a, set_single, empty_set,
  1.1081 +                          "@namespace -\\32  url(http://www.w3.org/1999/xhtml);");
  1.1082 +    test_selector_in_html("\\2|a", single_a, set_single, empty_set,
  1.1083 +                          "@namespace \\0002  url(http://www.w3.org/1999/xhtml);");
  1.1084 +    test_selector_in_html("-\\2|a", single_a, set_single, empty_set,
  1.1085 +                          "@namespace -\\000002  url(http://www.w3.org/1999/xhtml);");
  1.1086 +    var spans = "<span class='2'></span><span class='&#x2;'></span>" +
  1.1087 +                "<span id='2'></span><span id='&#x2;'></span>"
  1.1088 +    test_selector_in_html(".\\32", spans,
  1.1089 +                          bodychildset([0]), bodychildset([1, 2, 3]));
  1.1090 +    test_selector_in_html("[class=\\32]", spans,
  1.1091 +                          bodychildset([0]), bodychildset([1, 2, 3]));
  1.1092 +    test_selector_in_html(".\\2", spans,
  1.1093 +                          bodychildset([1]), bodychildset([0, 2, 3]));
  1.1094 +    test_selector_in_html("[class=\\2]", spans,
  1.1095 +                          bodychildset([1]), bodychildset([0, 2, 3]));
  1.1096 +    test_selector_in_html("#\\32", spans,
  1.1097 +                          bodychildset([2]), bodychildset([0, 1, 3]));
  1.1098 +    test_selector_in_html("[id=\\32]", spans,
  1.1099 +                          bodychildset([2]), bodychildset([0, 1, 3]));
  1.1100 +    test_selector_in_html("#\\2", spans,
  1.1101 +                          bodychildset([3]), bodychildset([0, 1, 2]));
  1.1102 +    test_selector_in_html("[id=\\2]", spans,
  1.1103 +                          bodychildset([3]), bodychildset([0, 1, 2]));
  1.1104 +    test_balanced_unparseable("#2");
  1.1105 +
  1.1106 +    // Bug 553805:  :not() containing nothing is forbidden
  1.1107 +    test_balanced_unparseable(":not()");
  1.1108 +    test_balanced_unparseable(":not( )");
  1.1109 +    test_balanced_unparseable(":not( \t\n )");
  1.1110 +    test_balanced_unparseable(":not(/*comment*/)");
  1.1111 +    test_balanced_unparseable(":not( /*comment*/  /* comment */  )");
  1.1112 +    test_balanced_unparseable("p :not()");
  1.1113 +    test_balanced_unparseable("p :not( )");
  1.1114 +    test_balanced_unparseable("p :not( \t\n )");
  1.1115 +    test_balanced_unparseable("p :not(/*comment*/)");
  1.1116 +    test_balanced_unparseable("p :not( /*comment*/  /* comment */  )");
  1.1117 +    test_balanced_unparseable("p:not()");
  1.1118 +    test_balanced_unparseable("p:not( )");
  1.1119 +    test_balanced_unparseable("p:not( \t\n )");
  1.1120 +    test_balanced_unparseable("p:not(/*comment*/)");
  1.1121 +    test_balanced_unparseable("p:not( /*comment*/  /* comment */  )");
  1.1122 +
  1.1123 +    test_balanced_unparseable(":not(:nth-child(2k))");
  1.1124 +    test_balanced_unparseable(":not(:nth-child(()))");
  1.1125 +
  1.1126 +    // :-moz-any()
  1.1127 +    test_balanced_unparseable(":-moz-any()");
  1.1128 +    test_balanced_unparseable(":-moz-any(div p)");
  1.1129 +    test_balanced_unparseable(":-moz-any(div ~ p)");
  1.1130 +    test_balanced_unparseable(":-moz-any(div~p)");
  1.1131 +    test_balanced_unparseable(":-moz-any(div + p)");
  1.1132 +    test_balanced_unparseable(":-moz-any(div+p)");
  1.1133 +    test_balanced_unparseable(":-moz-any(div > p)");
  1.1134 +    test_balanced_unparseable(":-moz-any(div>p)");
  1.1135 +    test_parseable(":-moz-any(div, p)");
  1.1136 +    test_parseable(":-moz-any( div , p  )");
  1.1137 +    test_parseable(":-moz-any(div,p)");
  1.1138 +    test_parseable(":-moz-any(div)");
  1.1139 +    test_parseable(":-moz-any(div,p,:link,span:focus)");
  1.1140 +    test_parseable(":-moz-any(:active,:focus)");
  1.1141 +    test_parseable(":-moz-any(:active,:link:focus)");
  1.1142 +    test_balanced_unparseable(":-moz-any(div,:nonexistentpseudo)");
  1.1143 +    var any_elts = "<input type='text'><a href='http://www.example.com/'></a><div></div><a name='foo'>";
  1.1144 +    test_selector_in_html(":-moz-any(a,input)", any_elts,
  1.1145 +                          bodychildset([0, 1, 3]), bodychildset([2]));
  1.1146 +    test_selector_in_html(":-moz-any(:link,:not(a))", any_elts,
  1.1147 +                          bodychildset([0, 1, 2]), bodychildset([3]));
  1.1148 +    test_selector_in_html(":-moz-any([href],input[type],input[name])", any_elts,
  1.1149 +                          bodychildset([0, 1]), bodychildset([2, 3]));
  1.1150 +    test_selector_in_html(":-moz-any(div,a):-moz-any([type],[href],[name])",
  1.1151 +                          any_elts,
  1.1152 +                          bodychildset([1, 3]), bodychildset([0, 2]));
  1.1153 +
  1.1154 +    test_selector_in_html(":-moz-table-border-nonzero",
  1.1155 +                          "<p></p>" +
  1.1156 +                          "<p border='2'></p>" +
  1.1157 +                          "<table border='2'></table>" +
  1.1158 +                          "<table border></table>" +
  1.1159 +                          "<table></table>" +
  1.1160 +                          "<table frame='border'></table>" +
  1.1161 +                          "<table border='0'></table>" +
  1.1162 +                          "<table border='0pt'></table>" +
  1.1163 +                          "<table border='3pt'></table>",
  1.1164 +                          bodychildset([2, 3, 8]),
  1.1165 +                          bodychildset([0, 1, 4, 5, 6, 7]));
  1.1166 +
  1.1167 +    // Test that we don't tokenize an empty HASH.
  1.1168 +    test_balanced_unparseable("#");
  1.1169 +    test_balanced_unparseable("# ");
  1.1170 +    test_balanced_unparseable("#, p");
  1.1171 +    test_balanced_unparseable("# , p");
  1.1172 +    test_balanced_unparseable("p #");
  1.1173 +    test_balanced_unparseable("p # ");
  1.1174 +    test_balanced_unparseable("p #, p");
  1.1175 +    test_balanced_unparseable("p # , p");
  1.1176 +
  1.1177 +    // Test that a backslash alone at EOF outside of a string is treated
  1.1178 +    // as U+FFFD.
  1.1179 +    test_parseable_via_api("#a\\");
  1.1180 +    test_parseable_via_api("#\\");
  1.1181 +    test_parseable_via_api("\\");
  1.1182 +
  1.1183 +    // Test that newline escapes are only supported in strings.
  1.1184 +    test_balanced_unparseable("di\\\nv");
  1.1185 +    test_balanced_unparseable("div \\\n p");
  1.1186 +    test_balanced_unparseable("div\\\n p");
  1.1187 +    test_balanced_unparseable("div \\\np");
  1.1188 +    test_balanced_unparseable("div\\\np");
  1.1189 +
  1.1190 +    // Test that :-moz-placeholder is parsable.
  1.1191 +    test_parseable(":-moz-placeholder");
  1.1192 +
  1.1193 +    run_deferred_tests();
  1.1194 +}
  1.1195 +
  1.1196 +var deferred_tests = [];
  1.1197 +
  1.1198 +function defer_clonedoc_tests(docurl, onloadfunc)
  1.1199 +{
  1.1200 +    deferred_tests.push( { docurl: docurl, onloadfunc: onloadfunc } );
  1.1201 +}
  1.1202 +
  1.1203 +function run_deferred_tests()
  1.1204 +{
  1.1205 +    if (deferred_tests.length == 0) {
  1.1206 +        SimpleTest.finish();
  1.1207 +        return;
  1.1208 +    }
  1.1209 +
  1.1210 +    cloneiframe.onload = deferred_tests_onload;
  1.1211 +    cloneiframe.src = deferred_tests[0].docurl;
  1.1212 +}
  1.1213 +
  1.1214 +function deferred_tests_onload(event)
  1.1215 +{
  1.1216 +    if (event.target != cloneiframe)
  1.1217 +        return;
  1.1218 +
  1.1219 +    deferred_tests[0].onloadfunc();
  1.1220 +    deferred_tests.shift();
  1.1221 +
  1.1222 +    run_deferred_tests();
  1.1223 +}
  1.1224 +
  1.1225 +</script>
  1.1226 +</pre>
  1.1227 +</body>
  1.1228 +</html>

mercurial