tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_media_queries.html (32439B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <head>
      4  <title>Media Queries Self-Contained Test Suite</title>
      5  <link rel="author" title="L. David Baron" href="https://dbaron.org/">
      6  <link rel="author" title="Anne van Kesteren" href="http://annevankesteren.nl/">
      7  <link rel="author" title="Ms2ger" href="mailto:Ms2ger@gmail.com">
      8  <link rel="help" href="https://www.w3.org/TR/css3-mediaqueries/#media0">
      9  <script type="text/javascript" src="/resources/testharness.js"></script>
     10  <script type="text/javascript" src="/resources/testharnessreport.js"></script>
     11 </head>
     12 <body onload="run()">
     13 <div id=log></div>
     14 <iframe id="subdoc" src="support/media_queries_iframe.html"></iframe>
     15 <div id="content" style="display: none"></div>
     16 
     17 <script type="text/javascript">
     18 setup({ "explicit_done": true });
     19 
     20  function run() {
     21    var subdoc = document.getElementById("subdoc").contentDocument;
     22    var subwin = document.getElementById("subdoc").contentWindow;
     23    var style = subdoc.getElementById("style");
     24    var iframe_style = document.getElementById("subdoc").style;
     25    var body_cs = subdoc.defaultView.getComputedStyle(subdoc.body, "");
     26    var testGroup = "";
     27 
     28    function query_applies(q) {
     29      style.setAttribute("media", q);
     30      return body_cs.getPropertyValue("text-decoration-line") == "underline";
     31    }
     32 
     33    function not(predicate) {
     34      return (...args) => !predicate(...args);
     35    }
     36 
     37    function test_predicate(input, predicate, name) {
     38      test(() => {
     39        // lazily evaluate template string to avoid including device-specific data in test name
     40        var escaped = JSON.stringify(input);
     41        var evaled = eval("`" + escaped.substring(1, escaped.length - 1) + "`");
     42        // Also avoid an assert message for the same reason. (Relevant for
     43        // failing tests).
     44        assert_true(predicate(evaled))
     45      }, `${testGroup ? testGroup + ": " : ""}${name}: ${input}`);
     46    }
     47 
     48    function should_apply(q) {
     49      test_predicate(q, query_applies, "should_apply");
     50    }
     51 
     52    function should_not_apply(q) {
     53      test_predicate(q, not(query_applies), "should_not_apply");
     54    }
     55 
     56    /*
     57     * Functions to test whether a query is parseable at all.  (Should not
     58     * be used for parse errors within expressions.)
     59     */
     60    var parse_test_style_element = document.createElement("style");
     61    parse_test_style_element.type = "text/css";
     62    parse_test_style_element.disabled = true; // for performance, hopefully
     63    var parse_test_style_text = document.createTextNode("");
     64    parse_test_style_element.appendChild(parse_test_style_text);
     65    document.getElementsByTagName("head")[0]
     66      .appendChild(parse_test_style_element);
     67 
     68    function query_is_parseable(q) {
     69      parse_test_style_text.data = "@media screen, " + q + " {}";
     70      var sheet = parse_test_style_element.sheet; // XXX yikes, not live!
     71      if (sheet.cssRules.length == 1 &&
     72          sheet.cssRules[0].type == CSSRule.MEDIA_RULE)
     73        return sheet.cssRules[0].media.mediaText != "screen, not all";
     74 
     75      assert_unreached(
     76        "unexpected result testing whether query " + q + " is parseable");
     77    }
     78 
     79    function query_should_be_parseable(q) {
     80      test_predicate(q, query_is_parseable, "query_should_be_parseable");
     81    }
     82 
     83    function query_should_not_be_parseable(q) {
     84      test_predicate(q, not(query_is_parseable), "query_should_not_be_parseable");
     85    }
     86 
     87    /*
     88     * Functions to test whether a single media expression is "unknown" or not.
     89     *
     90     * https://drafts.csswg.org/mediaqueries-4/#evaluating
     91     */
     92 
     93    function expression_is_parseable(e) {
     94      return query_is_parseable(`(${e})`);
     95    }
     96 
     97    function expression_is_known(e) {
     98      return query_applies(`(${e}), not all and (${e})`);
     99    }
    100 
    101    function expression_should_be_known(e) {
    102      // We don't bother with expression_is_parseable here, because it must be parseable to be known
    103      test_predicate(e, expression_is_known, "expression_should_be_known");
    104    }
    105 
    106    function expression_should_be_unknown(e) {
    107      test_predicate(e, expression_is_parseable, "expression_should_be_parseable");
    108      test_predicate(e, not(expression_is_known), "expression_should_be_unknown");
    109    }
    110 
    111    // The no-type syntax doesn't mix with the not and only keywords.
    112    query_should_be_parseable("(orientation)");
    113    query_should_be_parseable("not (orientation)");
    114    expression_should_be_known("(orientation)");
    115    expression_should_be_known("not (orientation)");
    116    query_should_not_be_parseable("only (orientation)");
    117    query_should_be_parseable("all and (orientation)");
    118    query_should_be_parseable("not all and (orientation)");
    119    query_should_be_parseable("only all and (orientation)");
    120 
    121    query_should_not_be_parseable("not not (orientation)");
    122    query_should_be_parseable("(orientation) and (orientation)");
    123    query_should_be_parseable("(orientation) or (orientation)");
    124    query_should_be_parseable("(orientation) or ((orientation) and ((orientation) or (orientation) or (not (orientation))))");
    125    expression_should_be_known("(orientation) and (orientation)");
    126    expression_should_be_known("(orientation) or (orientation)");
    127    expression_should_be_known("(orientation) or ((orientation) and ((orientation) or (orientation) or (not (orientation))))");
    128 
    129    query_should_not_be_parseable("all and (orientation) or (orientation)");
    130    query_should_be_parseable("all and (orientation) and (orientation)");
    131 
    132    query_should_not_be_parseable("(orientation) and (orientation) or (orientation)");
    133    query_should_not_be_parseable("(orientation) and not (orientation)");
    134 
    135    var features = [ "width", "height", "device-width", "device-height" ];
    136    var separators = [ ":", ">", ">=", "=", "<=", "<" ];
    137    var feature;
    138    var i;
    139    for (i in features) {
    140      feature = features[i];
    141      expression_should_be_known(feature);
    142      expression_should_be_unknown("min-" + feature);
    143      expression_should_be_unknown("max-" + feature);
    144      for (let separator of separators) {
    145        expression_should_be_known(feature + " " + separator + " 0");
    146        expression_should_be_known(feature + " " + separator + " 0px");
    147        expression_should_be_known(feature + " " + separator + " 0em");
    148        expression_should_be_known(feature + " " + separator + " -0");
    149        expression_should_be_known(feature + " " + separator + " -0cm");
    150        expression_should_be_known(feature + " " + separator + " 1px");
    151        expression_should_be_known(feature + " " + separator + " 0.001mm");
    152        expression_should_be_known(feature + " " + separator + " 100000px");
    153        if (separator == ":") {
    154          expression_should_be_known("min-" + feature + " " + separator + " -0");
    155          expression_should_be_known("max-" + feature + " " + separator + " -0");
    156        } else {
    157          expression_should_be_unknown("min-" + feature + " " + separator + " -0");
    158          expression_should_be_unknown("max-" + feature + " " + separator + " -0");
    159          let multi_range = "0px " + separator + " " + feature + " " + separator + " 100000px"
    160          if (separator == "=") {
    161            expression_should_be_unknown(multi_range);
    162          } else {
    163            expression_should_be_known(multi_range);
    164          }
    165        }
    166        if (separator == ">=") {
    167          expression_should_be_unknown(feature + " > = 0px");
    168        } else if (separator == "<=") {
    169          expression_should_be_unknown(feature + " < = 0px");
    170        }
    171 
    172        expression_should_be_known(feature + " " + separator + " -1px");
    173        if (separator == ":") {
    174          expression_should_be_known("min-" + feature + " " + separator + " -1px");
    175          expression_should_be_known("max-" + feature + " " + separator + " -1px");
    176        } else {
    177          expression_should_be_unknown("min-" + feature + " " + separator + " -1px");
    178          expression_should_be_unknown("max-" + feature + " " + separator + " -1px");
    179        }
    180        expression_should_be_known(feature + " " + separator + " -0.00001mm");
    181        expression_should_be_known(feature + " " + separator + " -100000em");
    182 
    183        for (let separator2 of separators) {
    184          // https://drafts.csswg.org/mediaqueries-4/#typedef-mf-range
    185          if (separator[0] == separator2[0] && (separator[0] == '<' || separator[0] == '>')) {
    186            expression_should_be_known(`0px ${separator} ${feature} ${separator2} 0px`);
    187          } else {
    188            expression_should_be_unknown(`0px ${separator} ${feature} ${separator2} 0px`);
    189          }
    190        }
    191      }
    192    }
    193 
    194    var content_div = document.getElementById("content");
    195    content_div.style.font = "medium sans-serif";
    196    var em_size =
    197      getComputedStyle(content_div, "").fontSize.match(/^(\d+)px$/)[1];
    198 
    199    // in this test, assume the common underlying implementation is correct
    200    var width_val = 117; // pick two not-too-round numbers
    201    var height_val = 76;
    202    iframe_style.width = width_val + "px";
    203    iframe_style.height = height_val + "px";
    204    var device_width = window.screen.width;
    205    var device_height = window.screen.height;
    206    features = {
    207      "width": width_val,
    208      "height": height_val,
    209      "device-width": device_width,
    210      "device-height": device_height
    211    };
    212    for (feature in features) {
    213      var value = features[feature];
    214      should_apply("all and (" + feature + ": ${value}px)");
    215      should_apply("all and (" + feature + " = ${value}px)");
    216      should_not_apply("all and (" + feature + ": ${value + 1}px)");
    217      should_not_apply("all and (" + feature + ": ${value - 1}px)");
    218      should_not_apply("all and (" + feature + " = ${value + 1}px)");
    219      should_not_apply("all and (" + feature + " = ${value - 1}px)");
    220 
    221      should_apply("all and (min-" + feature + ": ${value}px)");
    222      should_not_apply("all and (min-" + feature + ": ${value + 1}px)");
    223      should_apply("all and (min-" + feature + ": ${value - 1}px)");
    224      should_apply("all and (max-" + feature + ": ${value}px)");
    225      should_apply("all and (max-" + feature + ": ${value + 1}px)");
    226      should_not_apply("all and (max-" + feature + ": ${value - 1}px)");
    227      should_not_apply("all and (min-" + feature + ": ${Math.ceil(value/em_size) + 1}em)");
    228      should_apply("all and (min-" + feature + ": ${Math.floor(value/em_size) - 1}em)");
    229      should_apply("all and (max-" + feature + ": ${Math.ceil(value/em_size) + 1}em)");
    230      should_not_apply("all and (max-" + feature + ": ${Math.floor(value/em_size) - 1}em)");
    231 
    232      should_apply("(" + feature + " <= ${value}px)");
    233      should_apply("(" + feature + " >= ${value}px)");
    234 
    235      should_apply("(0px < " + feature + " <= ${value}px)");
    236      should_apply("(${value}px >= " + feature + " > 0px)");
    237 
    238      should_not_apply("(0px < " + feature + " < ${value}px)");
    239      should_not_apply("(${value}px > " + feature + " > 0px)");
    240 
    241      should_not_apply("(" + feature + " < ${value}px)");
    242      should_not_apply("(" + feature + " > ${value}px)");
    243 
    244      should_apply("(" + feature + " < ${value + 1}px)");
    245      should_apply("(" + feature + " <= ${value + 1}px)");
    246      should_not_apply("(" + feature + " > ${value + 1}px)");
    247      should_not_apply("(" + feature + " >= ${value + 1}px)");
    248 
    249      should_apply("(" + feature + " > ${value - 1}px)");
    250      should_apply("(" + feature + " >= ${value - 1}px)");
    251      should_not_apply("(" + feature + " < ${value - 1}px)");
    252      should_not_apply("(" + feature + " <= ${value - 1}px)");
    253 
    254      should_apply("(${value - 1}px < " + feature + ")");
    255      should_apply("(${value - 1}px <= " + feature + ")");
    256      should_not_apply("(${value - 1}px > " + feature + ")");
    257      should_not_apply("(${value - 1}px >= " + feature + ")");
    258 
    259      should_apply("(${value - 1}px < " + feature + " < ${value + 1}px)");
    260      should_apply("(${value - 1}px < " + feature + " <= ${value}px)");
    261      should_apply("(${value}px <= " + feature + " < ${value + 1}px)");
    262      should_apply("(${value + 1}px > " + feature + " > ${value - 1}px)");
    263      should_apply("(${value + 1}px > " + feature + " >= ${value}px)");
    264      should_apply("(${value}px >= " + feature + " > ${value - 1}px)");
    265      should_not_apply("(${value}px > " + feature + " > ${value - 1}px)");
    266      should_not_apply("(${value + 1}px > " + feature + " > ${value}px)");
    267    }
    268 
    269    iframe_style.width = "0";
    270    testGroup = "width = 0, height != 0";
    271    should_apply("all and (height)");
    272    should_not_apply("all and (width)");
    273    iframe_style.height = "0";
    274    testGroup = "width = 0, height = 0"
    275    should_not_apply("all and (height)");
    276    should_not_apply("all and (width)");
    277    should_apply("all and (device-height)");
    278    should_apply("all and (device-width)");
    279    iframe_style.width = width_val + "px";
    280    testGroup = "width != 0, height = 0";
    281    should_not_apply("all and (height)");
    282    should_apply("all and (width)");
    283    iframe_style.height = height_val + "px";
    284    testGroup = "width != 0, height != 0";
    285    should_apply("all and (height)");
    286    should_apply("all and (width)");
    287    testGroup = "";
    288 
    289    testGroup = "ratio that reduces to 59/40";
    290    iframe_style.width = "236px";
    291    iframe_style.height = "160px";
    292    expression_should_be_known("orientation");
    293    expression_should_be_known("orientation: portrait");
    294    expression_should_be_known("orientation: landscape");
    295    expression_should_be_unknown("min-orientation");
    296    expression_should_be_unknown("min-orientation: portrait");
    297    expression_should_be_unknown("min-orientation: landscape");
    298    expression_should_be_unknown("max-orientation");
    299    expression_should_be_unknown("max-orientation: portrait");
    300    expression_should_be_unknown("max-orientation: landscape");
    301    should_apply("(orientation)");
    302    should_apply("(orientation: landscape)");
    303    should_not_apply("(orientation: portrait)");
    304    should_apply("not all and (orientation: portrait)");
    305 
    306    testGroup = "ratio that reduces to 59/80";
    307    iframe_style.height = "320px";
    308    should_apply("(orientation)");
    309    should_not_apply("(orientation: landscape)");
    310    should_apply("not all and (orientation: landscape)");
    311    should_apply("(orientation: portrait)");
    312    testGroup = "";
    313 
    314    should_apply("(aspect-ratio: 59/80)");
    315    should_not_apply("(aspect-ratio: 58/80)");
    316    should_not_apply("(aspect-ratio: 59/81)");
    317    should_not_apply("(aspect-ratio: 60/80)");
    318    should_not_apply("(aspect-ratio: 59/79)");
    319    should_apply("(aspect-ratio: 177/240)");
    320    should_apply("(aspect-ratio: 413/560)");
    321    should_apply("(aspect-ratio: 5900/8000)");
    322    should_not_apply("(aspect-ratio: 5901/8000)");
    323    should_not_apply("(aspect-ratio: 5899/8000)");
    324    should_not_apply("(aspect-ratio: 5900/8001)");
    325    should_not_apply("(aspect-ratio: 5900/7999)");
    326    should_apply("(aspect-ratio)");
    327 
    328    should_apply("(min-aspect-ratio: 59/80)");
    329    should_apply("(min-aspect-ratio: 58/80)");
    330    should_apply("(min-aspect-ratio: 59/81)");
    331    should_not_apply("(min-aspect-ratio: 60/80)");
    332    should_not_apply("(min-aspect-ratio: 59/79)");
    333    expression_should_be_unknown("min-aspect-ratio");
    334 
    335    should_apply("(max-aspect-ratio: 59/80)");
    336    should_not_apply("(max-aspect-ratio: 58/80)");
    337    should_not_apply("(max-aspect-ratio: 59/81)");
    338    should_apply("(max-aspect-ratio: 60/80)");
    339    should_apply("(max-aspect-ratio: 59/79)");
    340    expression_should_be_unknown("max-aspect-ratio");
    341 
    342    var real_dar = device_width + "/" + device_height;
    343    var high_dar_1 = (device_width + 1) + "/" + device_height;
    344    var high_dar_2 = device_width + "/" + (device_height - 1);
    345    var low_dar_1 = (device_width - 1) + "/" + device_height;
    346    var low_dar_2 = device_width + "/" + (device_height + 1);
    347    should_apply("(device-aspect-ratio: ${real_dar})");
    348    should_apply("not all and (device-aspect-ratio: ${high_dar_1})");
    349    should_not_apply("all and (device-aspect-ratio: ${high_dar_2})");
    350    should_not_apply("all and (device-aspect-ratio: ${low_dar_1})");
    351    should_apply("not all and (device-aspect-ratio: ${low_dar_2})");
    352    should_apply("(device-aspect-ratio)");
    353 
    354    should_apply("(min-device-aspect-ratio: ${real_dar})");
    355    should_not_apply("all and (min-device-aspect-ratio: ${high_dar_1})");
    356    should_apply("not all and (min-device-aspect-ratio: ${high_dar_2})");
    357    should_not_apply("not all and (min-device-aspect-ratio: ${low_dar_1})");
    358    should_apply("all and (min-device-aspect-ratio: ${low_dar_2})");
    359    expression_should_be_unknown("min-device-aspect-ratio");
    360 
    361    should_apply("all and (max-device-aspect-ratio: ${real_dar})");
    362    should_apply("(max-device-aspect-ratio: ${high_dar_1})");
    363    should_apply("(max-device-aspect-ratio: ${high_dar_2})");
    364    should_not_apply("all and (max-device-aspect-ratio: ${low_dar_1})");
    365    should_apply("not all and (max-device-aspect-ratio: ${low_dar_2})");
    366    expression_should_be_unknown("max-device-aspect-ratio");
    367 
    368    features = [ "max-aspect-ratio", "device-aspect-ratio" ];
    369    for (i in features) {
    370      feature = features[i];
    371      expression_should_be_known(feature + ": 1/1");
    372      expression_should_be_known(feature + ": 1  /1");
    373      expression_should_be_known(feature + ": 1  / \t\n1");
    374      expression_should_be_known(feature + ": 1/\r1");
    375      expression_should_be_known(feature + ": 1");
    376      expression_should_be_known(feature + ": 0.5");
    377      expression_should_be_known(feature + ": 1.0/1");
    378      expression_should_be_known(feature + ": 1/1.0");
    379      expression_should_be_known(feature + ": 1.0/1.0");
    380      expression_should_be_known(feature + ": 0/1");
    381      expression_should_be_known(feature + ": 1/0");
    382      expression_should_be_known(feature + ": 0/0");
    383      expression_should_be_unknown(feature + ": -1/1");
    384      expression_should_be_unknown(feature + ": 1/-1");
    385      expression_should_be_unknown(feature + ": -1/-1");
    386      expression_should_be_unknown(feature + ": invalid");
    387      expression_should_be_unknown(feature + ": 1 / invalid");
    388      expression_should_be_unknown(feature + ": 1 invalid");
    389    }
    390 
    391    var is_monochrome = query_applies("all and (min-monochrome: 1)");
    392    var is_color = query_applies("all and (min-color: 1)");
    393    test(function() {
    394      assert_not_equals(is_monochrome, is_color, "should be either monochrome or color");
    395    }, "monochrome_and_color");
    396 
    397    function depth_query(prefix, depth) {
    398      return "all and (" + prefix + (is_color ? "color" : "monochrome") +
    399             ":" + depth + ")";
    400    }
    401 
    402    var depth = 0;
    403    do {
    404      if (depth > 50) {
    405        break;
    406      }
    407    } while (query_applies(depth_query("min-", ++depth)));
    408    test(function() {
    409      assert_false(50 < depth);
    410    }, "find_depth");
    411    --depth;
    412 
    413    should_apply(depth_query("", depth));
    414    should_not_apply(depth_query("", depth - 1));
    415    should_not_apply(depth_query("", depth + 1));
    416    should_apply(depth_query("max-", depth));
    417    should_not_apply(depth_query("max-", depth - 1));
    418    should_apply(depth_query("max-", depth + 1));
    419 
    420    (is_color ? should_apply : should_not_apply)("all and (color)");
    421    expression_should_be_unknown("max-color");
    422    expression_should_be_unknown("min-color");
    423    (is_color ? should_not_apply : should_apply)("all and (monochrome)");
    424    expression_should_be_unknown("max-monochrome");
    425    expression_should_be_unknown("min-monochrome");
    426    (is_color ? should_apply : should_not_apply)("not all and (monochrome)");
    427    (is_color ? should_not_apply : should_apply)("not all and (color)");
    428    (is_color ? should_apply : should_not_apply)("only all and (color)");
    429    (is_color ? should_not_apply : should_apply)("only all and (monochrome)");
    430 
    431    features = [ "color", "min-monochrome", "max-color-index" ];
    432    for (i in features) {
    433      feature = features[i];
    434      expression_should_be_known(feature + ": 1");
    435      expression_should_be_known(feature + ": 327");
    436      expression_should_be_known(feature + ": 0");
    437      expression_should_be_unknown(feature + ": 1.0");
    438      expression_should_be_known(feature + ": -1");
    439      expression_should_be_unknown(feature + ": 1/1");
    440    }
    441 
    442    // Presume that we never support indexed color (at least not usefully
    443    // enough to call it indexed color).
    444    should_apply("(color-index: 0)");
    445    should_not_apply("(color-index: 1)");
    446    should_apply("(min-color-index: 0)");
    447    should_not_apply("(min-color-index: 1)");
    448    should_apply("(max-color-index: 0)");
    449    should_apply("(max-color-index: 1)");
    450    should_apply("(max-color-index: 157)");
    451 
    452    features = [ "resolution", "min-resolution", "max-resolution" ];
    453    for (i in features) {
    454      feature = features[i];
    455      expression_should_be_known(feature + ": 3dpi");
    456      expression_should_be_known(feature + ":3dpi");
    457      expression_should_be_known(feature + ": 3.0dpi");
    458      expression_should_be_known(feature + ": 3.4dpi");
    459      expression_should_be_known(feature + "\t: 120dpcm");
    460      expression_should_be_known(feature + ": 1dppx");
    461      expression_should_be_known(feature + ": 1x");
    462      expression_should_be_known(feature + ": 1.5dppx");
    463      expression_should_be_known(feature + ": 1.5x");
    464      expression_should_be_known(feature + ": 2.0dppx");
    465      expression_should_be_known(feature + ": 0dpi");
    466      expression_should_be_known(feature + ": 0dppx");
    467      expression_should_be_known(feature + ": 0x");
    468      expression_should_be_known(feature + ": calc(6x / 2)");
    469      expression_should_be_unknown(feature + ": -3dpi");
    470    }
    471 
    472    // Find the resolution using max-resolution
    473    var resolution = 0;
    474    do {
    475      ++resolution;
    476      if (resolution > 10000) {
    477        break;
    478      }
    479    } while (!query_applies("(max-resolution: " + resolution + "dpi)"));
    480    test(function() {
    481      assert_false(10000 < resolution);
    482    }, "find_resolution");
    483 
    484    // resolution should now be Math.ceil() of the actual resolution.
    485    var dpi_high;
    486    var dpi_low = resolution - 1;
    487    if (query_applies(`(min-resolution: ${resolution}dpi)`)) { // query_applies, so template literal!
    488      // It's exact!
    489      testGroup = "resolution is exact";
    490      should_apply("(resolution: ${resolution}dpi)");
    491      should_apply("(resolution: ${Math.floor(resolution/96)}dppx)");
    492      should_apply("(resolution: ${Math.floor(resolution/96)}x)");
    493      should_not_apply("(resolution: ${resolution + 1}dpi)");
    494      should_not_apply("(resolution: ${resolution - 1}dpi)");
    495      dpi_high = resolution + 1;
    496    } else {
    497      // We have no way to test resolution applying since it need not be
    498      // an integer.
    499      testGroup = "resolution is inexact";
    500      should_not_apply("(resolution: ${resolution}dpi)");
    501      should_not_apply("(resolution: ${resolution - 1}dpi)");
    502      dpi_high = resolution;
    503    }
    504    testGroup = "";
    505 
    506    should_apply("(min-resolution: ${dpi_low}dpi)");
    507    should_not_apply("not all and (min-resolution: ${dpi_low}dpi)");
    508    should_apply("not all and (min-resolution: ${dpi_high}dpi)");
    509    should_not_apply("all and (min-resolution: ${dpi_high}dpi)");
    510 
    511    // Test dpcm units based on what we computed in dpi.
    512    var dpcm_high = Math.ceil(dpi_high / 2.54);
    513    var dpcm_low = Math.floor(dpi_low / 2.54);
    514    should_apply("(min-resolution: ${dpcm_low}dpcm)");
    515    should_apply("(max-resolution: ${dpcm_high}dpcm)");
    516    should_not_apply("(max-resolution: ${dpcm_low}dpcm)");
    517    should_apply("not all and (min-resolution: ${dpcm_high}dpcm)");
    518 
    519    expression_should_be_known("scan");
    520    expression_should_be_known("scan: progressive");
    521    expression_should_be_known("scan:interlace");
    522    expression_should_be_unknown("min-scan:interlace");
    523    expression_should_be_unknown("scan: 1");
    524    expression_should_be_unknown("max-scan");
    525    expression_should_be_unknown("max-scan: progressive");
    526    // Assume we don't support tv devices.
    527    should_not_apply("(scan)");
    528    should_not_apply("(scan: progressive)");
    529    should_not_apply("(scan: interlace)");
    530    should_apply("not all and (scan)");
    531    should_apply("not all and (scan: progressive)");
    532    should_apply("not all and (scan: interlace)");
    533 
    534    expression_should_be_known("grid");
    535    expression_should_be_known("grid: 0");
    536    expression_should_be_known("grid: 1");
    537    expression_should_be_unknown("min-grid");
    538    expression_should_be_unknown("min-grid:0");
    539    expression_should_be_unknown("max-grid: 1");
    540    expression_should_be_unknown("grid: 2");
    541    expression_should_be_unknown("grid: -1");
    542 
    543    // Assume we don't support grid devices
    544    should_not_apply("(grid)");
    545    should_apply("(grid: 0)");
    546    should_not_apply("(grid: 1)");
    547    should_not_apply("(grid: 2)");
    548    should_not_apply("(grid: -1)");
    549 
    550    // Parsing tests
    551    // bug 454227
    552    should_apply("(orientation");
    553    should_not_apply("not all and (orientation");
    554    should_not_apply("(orientation:");
    555    should_not_apply("(orientation:)");
    556    should_not_apply("(orientation:  )");
    557    should_apply("all,(orientation:");
    558    should_not_apply("(orientation:,all");
    559    should_apply("not all and (grid");
    560    should_not_apply("only all and (grid");
    561    should_not_apply("(grid");
    562    should_apply("all,(grid");
    563    should_not_apply("(grid,all");
    564    // bug 454226
    565    should_apply(",all");
    566    should_apply("all,");
    567    should_apply(",all,");
    568    should_apply("all,badmedium");
    569    should_apply("badmedium,all");
    570    should_not_apply(",badmedium,");
    571    should_apply("all,(badexpression)");
    572    should_apply("(badexpression),all");
    573    should_not_apply("(badexpression),badmedium");
    574    should_not_apply("badmedium,(badexpression)");
    575    should_apply("all,[badsyntax]");
    576    should_apply("[badsyntax],all");
    577    should_not_apply("badmedium,[badsyntax]");
    578    should_not_apply("[badsyntax],badmedium");
    579 
    580    // Parsing tests based on Acid3
    581    query_should_not_be_parseable("all and color :");
    582    query_should_not_be_parseable("all and color : 1");
    583    should_not_apply("all and min-color : 1");
    584    should_not_apply("(bogus)");
    585    should_not_apply("not all and (bogus)")
    586    should_not_apply("only all and (bogus)")
    587 
    588    // Parsing tests for overflow-block from mediaqueries-4
    589    expression_should_be_known("overflow-block")
    590    expression_should_be_known("overflow-block: none")
    591    expression_should_be_known("overflow-block: paged")
    592    expression_should_be_known("overflow-block: scroll")
    593    expression_should_be_unknown("overflow-block: optional-paged")
    594    expression_should_be_unknown("overflow-block: some-random-invalid-thing")
    595 
    596    // Sanity check for overflow-block
    597    test(function() {
    598      var any_overflow_block = query_applies("(overflow-block)");
    599      var overflow_block_none = query_applies("(overflow-block: none)");
    600      assert_not_equals(any_overflow_block, overflow_block_none, "overflow-block should be equivalent to not (overflow-block: none)");
    601    }, "Sanity check for overflow-block");
    602 
    603    // Parsing tests for overflow-inline from mediaqueries-4
    604    expression_should_be_known("overflow-inline")
    605    expression_should_be_known("overflow-inline: none")
    606    expression_should_be_known("overflow-inline: scroll")
    607    expression_should_be_unknown("overflow-inline: some-random-invalid-thing")
    608 
    609    // Sanity check for overflow-inline
    610    test(function() {
    611      var any_overflow_inline = query_applies("(overflow-inline)");
    612      var overflow_inline_none = query_applies("(overflow-inline: none)");
    613      assert_not_equals(any_overflow_inline, overflow_inline_none, "overflow-inline should be equivalent to not (overflow-inline: none)");
    614    }, "Sanity check for overflow-inline");
    615 
    616    // Parsing tests for update from mediaqueries-4
    617    expression_should_be_known("update")
    618    expression_should_be_known("update: none")
    619    expression_should_be_known("update: slow")
    620    expression_should_be_known("update: fast")
    621    expression_should_be_unknown("update: some-random-invalid-thing")
    622 
    623    // Sanity check for update
    624    test(function() {
    625      var any_update = query_applies("(update)");
    626      var update_none = query_applies("(update: none)");
    627      assert_not_equals(any_update, update_none, "update should be equivalent to not (update: none)");
    628    }, "Sanity check for update");
    629 
    630    // Parsing tests for interaction media features.
    631    expression_should_be_known("hover")
    632    expression_should_be_known("hover: hover")
    633    expression_should_be_known("hover: none")
    634    expression_should_be_known("any-hover")
    635    expression_should_be_known("any-hover: hover")
    636    expression_should_be_known("any-hover: none")
    637 
    638    test(function() {
    639      assert_equals(query_applies("(hover)"), query_applies("(hover: hover)"));
    640    } , "(hover) == (hover: hover)");
    641 
    642    test(function() {
    643      assert_not_equals(query_applies("(hover)"), query_applies("(hover: none)"));
    644    }, "(hover) == not (hover: none)");
    645 
    646    test(function() {
    647      assert_equals(query_applies("(any-hover)"), query_applies("(any-hover: hover)"));
    648    }, "(any-hover) == (any-hover: hover)");
    649 
    650    test(function() {
    651      assert_not_equals(query_applies("(any-hover)"), query_applies("(any-hover: none)"));
    652    }, "(any-hover) == not (any-hover: none)");
    653 
    654    expression_should_be_known("pointer")
    655    expression_should_be_known("pointer: coarse")
    656    expression_should_be_known("pointer: fine")
    657    expression_should_be_known("pointer: none")
    658    expression_should_be_known("any-pointer")
    659    expression_should_be_known("any-pointer: coarse")
    660    expression_should_be_known("any-pointer: fine")
    661    expression_should_be_known("any-pointer: none")
    662 
    663    test(function() {
    664      assert_equals(query_applies("(pointer)"),
    665                    query_applies("(pointer: coarse)") || query_applies("(pointer: fine)"));
    666    }, "(pointer) == (pointer: coarse) or (pointer: fine)");
    667 
    668    test(function() {
    669      assert_not_equals(query_applies("(pointer)"),
    670                        query_applies("(pointer: none)"));
    671    }, "(pointer) == not (pointer: none)");
    672 
    673    test(function() {
    674      assert_equals(query_applies("(any-pointer)"),
    675                    query_applies("(any-pointer: coarse)") || query_applies("(any-pointer: fine)"));
    676    }, "(any-pointer) == (any-pointer: coarse) or (any-pointer: fine)");
    677 
    678    test(function() {
    679      assert_not_equals(query_applies("(any-pointer)"),
    680                        query_applies("(any-pointer: none)"));
    681    }, "(any-pointer) == not (any-pointer: none)");
    682 
    683    iframe_style.width = '100px';
    684    iframe_style.height = '0px';
    685 
    686    testGroup = "'or' keyword"
    687    should_not_apply("(height) or (height)");
    688    should_apply("(width) or (height)");
    689    should_apply("(height) or (width)");
    690    should_apply("(height) or (width) or (height)");
    691    query_should_not_be_parseable("screen or (width)");
    692    query_should_not_be_parseable("screen and (width) or (height)");
    693 
    694    testGroup = "nesting"
    695    should_not_apply("((height))");
    696    should_apply("((width))");
    697    should_apply("(((((width)))))");
    698    should_apply("(((((width");
    699 
    700    testGroup = "'not' keyword"
    701    should_not_apply("not (width)");
    702    should_apply("not (height)");
    703    should_apply("not ((width) and (height))");
    704    should_not_apply("not ((width) or (height))");
    705    should_not_apply("not ((width) and (not (height)))");
    706    query_should_not_be_parseable("not (width) and not (height)");
    707    query_should_not_be_parseable("not not (width)");
    708    query_should_be_parseable("not unknown(width) ");
    709 
    710    testGroup = "three-valued logic"
    711    should_not_apply("(unknown)");
    712    should_not_apply("not (unknown)");
    713    should_not_apply("((unknown) and (width))");
    714    should_not_apply("not ((unknown) and (width))");
    715    should_not_apply("((unknown) and (height))");
    716    should_apply("not ((unknown) and (height))");
    717    should_apply("((unknown) or (width))");
    718    should_not_apply("not ((unknown) or (width))");
    719    should_not_apply("((unknown) or (height))");
    720    should_not_apply("not ((unknown) or (height))");
    721    should_apply("(width) or (not ((unknown) and (width)))");
    722    should_not_apply("(width) and (not ((unknown) and (width)))");
    723    should_apply("(width) or (not ((unknown) or (width)))");
    724    should_not_apply("(width) and (not ((unknown) or (width)))");
    725    should_apply("(width) or (not ((unknown) and (height)))");
    726    should_apply("(width) and (not ((unknown) and (height)))");
    727    should_apply("(width) or (not ((unknown) or (height)))");
    728    should_not_apply("(width) and (not ((unknown) or (height)))");
    729    should_not_apply("unknown(width)");
    730    should_not_apply("not unknown(width)");
    731    should_apply("not (unknown(width) and (height))");
    732    should_not_apply("not (unknown(width) or (height))");
    733 
    734    testGroup = ""
    735    done();
    736 }
    737 
    738 </script>
    739 </body>
    740 </html>