123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- <!DOCTYPE HTML>
- <html>
- <!--
- -->
- <head>
- <title>Test for parsing, storage, and serialization of CSS values</title>
- <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- <script type="text/javascript" src="property_database.js"></script>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
- <style type="text/css" id="prereqsheet">
- #testnode {}
- </style>
- </head>
- <body>
- <p id="display"></p>
- <div id="content" style="display: none">
- <div id="testnode"></div>
- </div>
- <pre id="test">
- <script class="testbody" type="text/javascript">
- /** Test for parsing, storage, and serialization of CSS values **/
- /*
- * The idempotence tests here deserve a little bit of explanation. What
- * we're testing here are the following operations:
- * parse: string -> CSS rule
- * serialize: CSS rule -> string (normalization 1)
- * (this actually has two variants that go through partly different
- * codepaths, which we exercise with getPropertyValue and cssText)
- * compute: CSS rule -> computed style
- * cserialize: computed style -> string (normalization 2)
- *
- * Both serialize and cserialize do some normalization, so we can't test
- * for pure round-tripping, and we also can't compare their output since
- * they could normalize differently. (We might at some point in the
- * future want to guarantee that any output of cserialize is
- * untouched by going through parse+serialize, though.)
- *
- * So we test idempotence of parse + serialize by running the whole
- * operation twice. Likewise for parse + compute + cserialize.
- *
- * Slightly more interestingly, we test that serialize + parse is the
- * identity transform by comparing the output of parse + compute +
- * cserialize to the output of parse + serialize + parse + compute +
- * cserialize.
- */
- var gSystemFont = {
- "caption": true,
- "icon": true,
- "menu": true,
- "message-box": true,
- "small-caption": true,
- "status-bar": true,
- "-moz-window": true,
- "-moz-document": true,
- "-moz-desktop": true,
- "-moz-info": true,
- "-moz-dialog": true,
- "-moz-button": true,
- "-moz-pull-down-menu": true,
- "-moz-list": true,
- "-moz-field": true,
- "-moz-workspace": true,
- };
- var gBadCompute = {
- // output wrapped around to positive, in exponential notation
- "-moz-box-ordinal-group": [ "-1", "-1000" ],
- };
- function xfail_compute(property, value)
- {
- if (property in gBadCompute &&
- gBadCompute[property].indexOf(value) != -1)
- return true;
- return false;
- }
- // constructed to map longhands ==> list of containing shorthands
- var gPropertyShorthands = {};
- var gElement = document.getElementById("testnode");
- var gDeclaration = gElement.style;
- var gComputedStyle = window.getComputedStyle(gElement, "");
- var gPrereqDeclaration =
- document.getElementById("prereqsheet").sheet.cssRules[0].style;
- // Returns true if propA and propB are equivalent, considering aliasing.
- // (i.e. if one is an alias of the other, or if they're both aliases of
- // the same 3rd property)
- function are_properties_aliased(propA, propB)
- {
- // If either property is an alias, replace it with the property it aliases.
- if ("alias_for" in gCSSProperties[propA]) {
- propA = gCSSProperties[propA].alias_for;
- }
- if ("alias_for" in gCSSProperties[propB]) {
- propB = gCSSProperties[propB].alias_for;
- }
- return propA == propB;
- }
- function test_property(property)
- {
- var info = gCSSProperties[property];
- // can all properties be removed from the style?
- function test_remove_all_properties(property, value) {
- var i, p = [];
- for (i = 0; i < gDeclaration.length; i++) p.push(gDeclaration[i]);
- for (i = 0; i < p.length; i++) gDeclaration.removeProperty(p[i]);
- var errstr = "when setting property " + property + " to " + value;
- is(gDeclaration.length, 0, "unremovable properties " + errstr);
- is(gDeclaration.cssText, "", "non-empty serialization after removing all properties " + errstr);
- }
- function test_other_shorthands_empty(value, subprop) {
- if (!(subprop in gPropertyShorthands)) return;
- var shorthands = gPropertyShorthands[subprop];
- for (idx in shorthands) {
- var sh = shorthands[idx];
- if (are_properties_aliased(sh, property)) {
- continue;
- }
- is(gDeclaration.getPropertyValue(sh), "",
- "setting '" + value + "' on '" + property + "' (for shorthand '" + sh + "')");
- }
- }
- function test_value(value, resolved_value) {
- var value_has_variable_reference = resolved_value != null;
- gDeclaration.setProperty(property, value, "");
- var idx;
- var step1val = gDeclaration.getPropertyValue(property);
- var step1vals = [];
- var step1ser = gDeclaration.cssText;
- if ("subproperties" in info)
- for (idx in info.subproperties)
- step1vals.push(gDeclaration.getPropertyValue(info.subproperties[idx]));
- var step1comp;
- var step1comps = [];
- if (info.type != CSS_TYPE_TRUE_SHORTHAND)
- step1comp = gComputedStyle.getPropertyValue(property);
- if ("subproperties" in info)
- for (idx in info.subproperties)
- step1comps.push(gComputedStyle.getPropertyValue(info.subproperties[idx]));
- SimpleTest.isnot(step1val, "", "setting '" + value + "' on '" + property + "'");
- if ("subproperties" in info)
- for (idx in info.subproperties) {
- var subprop = info.subproperties[idx];
- if (value_has_variable_reference &&
- (!info.alias_for || info.type == CSS_TYPE_TRUE_SHORTHAND)) {
- is(gDeclaration.getPropertyValue(subprop), "",
- "setting '" + value + "' on '" + property + "' (for '" + subprop + "')");
- test_other_shorthands_empty(value, subprop);
- } else {
- isnot(gDeclaration.getPropertyValue(subprop), "",
- "setting '" + value + "' on '" + property + "' (for '" + subprop + "')");
- }
- }
- // We don't care particularly about the whitespace or the placement of
- // semicolons, but for simplicity we'll test the current behavior.
- var expected_serialization = "";
- if (step1val != "") {
- if ("alias_for" in info) {
- expected_serialization = info.alias_for + ": " + step1val + ";";
- } else {
- expected_serialization = property + ": " + step1val + ";";
- }
- }
- is(step1ser, expected_serialization,
- "serialization should match property value");
- gDeclaration.removeProperty(property);
- gDeclaration.setProperty(property, step1val, "");
- is(gDeclaration.getPropertyValue(property), step1val,
- "parse+serialize should be idempotent for '" +
- property + ": " + value + "'");
- if (info.type != CSS_TYPE_TRUE_SHORTHAND) {
- is(gComputedStyle.getPropertyValue(property), step1comp,
- "serialize+parse should be identity transform for '" +
- property + ": " + value + "'");
- }
- if ("subproperties" in info &&
- // Using setProperty over subproperties is not sufficient for
- // system fonts, since the shorthand does more than its parts.
- (property != "font" || !(value in gSystemFont)) &&
- // Likewise for special compatibility values of transform
- (property != "-moz-transform" || !value.match(/^matrix.*(px|em|%)/)) &&
- !value_has_variable_reference) {
- gDeclaration.removeProperty(property);
- for (idx in info.subproperties) {
- var subprop = info.subproperties[idx];
- gDeclaration.setProperty(subprop, step1vals[idx], "");
- }
- // Now that all the subprops are set, check their values. Note that we
- // need this in a separate loop, in case parts of the shorthand affect
- // the computed values of other parts.
- for (idx in info.subproperties) {
- var subprop = info.subproperties[idx];
- is(gComputedStyle.getPropertyValue(subprop), step1comps[idx],
- "serialize(" + subprop + ")+parse should be the identity " +
- "transform for '" + property + ": " + value + "'");
- }
- is(gDeclaration.getPropertyValue(property), step1val,
- "parse+split+serialize should be idempotent for '" +
- property + ": " + value + "'");
- }
- if (info.type != CSS_TYPE_TRUE_SHORTHAND &&
- property != "mask") {
- gDeclaration.removeProperty(property);
- gDeclaration.setProperty(property, step1comp, "");
- var func = xfail_compute(property, value) ? todo_is : is;
- func(gComputedStyle.getPropertyValue(property), step1comp,
- "parse+compute+serialize should be idempotent for '" +
- property + ": " + value + "'");
- }
- if ("subproperties" in info) {
- gDeclaration.removeProperty(property);
- for (idx in info.subproperties) {
- var subprop = info.subproperties[idx];
- gDeclaration.setProperty(subprop, step1comps[idx], "");
- }
- // Now that all the subprops are set, check their values. Note that we
- // need this in a separate loop, in case parts of the shorthand affect
- // the computed values of other parts.
- for (idx in info.subproperties) {
- var subprop = info.subproperties[idx];
- is(gComputedStyle.getPropertyValue(subprop), step1comps[idx],
- "parse+compute+serialize(" + subprop + ") should be idempotent for '" +
- property + ": " + value + "'");
- }
- }
- // sanity check shorthands to make sure disabled props aren't exposed
- if (info.type != CSS_TYPE_LONGHAND) {
- gDeclaration.setProperty(property, value, "");
- test_remove_all_properties(property, value);
- }
- gDeclaration.removeProperty(property);
- }
- function test_value_without_variable(value) {
- test_value(value, null);
- }
- function test_value_with_variable(value) {
- gPrereqDeclaration.setProperty("--a", value, "");
- test_value("var(--a)", value);
- gPrereqDeclaration.removeProperty("--a");
- }
- if ("prerequisites" in info) {
- var prereqs = info.prerequisites;
- for (var prereq in prereqs) {
- gPrereqDeclaration.setProperty(prereq, prereqs[prereq], "");
- }
- }
- var idx;
- for (idx in info.initial_values) {
- test_value_without_variable(info.initial_values[idx]);
- test_value_with_variable(info.initial_values[idx]);
- }
- for (idx in info.other_values) {
- test_value_without_variable(info.other_values[idx]);
- test_value_with_variable(info.other_values[idx]);
- }
- if ("prerequisites" in info) {
- for (var prereq in info.prerequisites) {
- gPrereqDeclaration.removeProperty(prereq);
- }
- }
- }
- function runTest() {
- // To avoid triggering the slow script dialog, we have to test one
- // property at a time.
- ok(SpecialPowers.getBoolPref("layout.css.variables.enabled"), "pref not set #1");
- var props = [];
- for (var prop in gCSSProperties) {
- var info = gCSSProperties[prop];
- if ("subproperties" in info) {
- for (var idx in info.subproperties) {
- var subprop = info.subproperties[idx];
- if (!(subprop in gPropertyShorthands)) {
- gPropertyShorthands[subprop] = [];
- }
- gPropertyShorthands[subprop].push(prop);
- }
- }
- props.push(prop);
- }
- props = props.reverse();
- function do_one() {
- if (props.length == 0) {
- SimpleTest.finish();
- return;
- }
- test_property(props.pop());
- SimpleTest.executeSoon(do_one);
- }
- SimpleTest.executeSoon(do_one);
- }
- SimpleTest.waitForExplicitFinish();
- SimpleTest.requestLongerTimeout(7);
- SpecialPowers.pushPrefEnv({ set: [["layout.css.variables.enabled", true]] },
- runTest);
- </script>
- </pre>
- </body>
- </html>
|