layout/style/test/test_value_storage.html

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

Ignore runtime configuration files generated during quality assurance.

michael@0 1 <!DOCTYPE HTML>
michael@0 2 <html>
michael@0 3 <!--
michael@0 4 -->
michael@0 5 <head>
michael@0 6 <title>Test for parsing, storage, and serialization of CSS values</title>
michael@0 7 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
michael@0 8 <script type="text/javascript" src="property_database.js"></script>
michael@0 9 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
michael@0 10 <style type="text/css" id="prereqsheet">
michael@0 11 #testnode {}
michael@0 12 </style>
michael@0 13 </head>
michael@0 14 <body>
michael@0 15 <p id="display"></p>
michael@0 16 <div id="content" style="display: none">
michael@0 17
michael@0 18 <div id="testnode"></div>
michael@0 19
michael@0 20 </div>
michael@0 21 <pre id="test">
michael@0 22 <script class="testbody" type="text/javascript">
michael@0 23
michael@0 24 /** Test for parsing, storage, and serialization of CSS values **/
michael@0 25
michael@0 26 /*
michael@0 27 * The idempotence tests here deserve a little bit of explanation. What
michael@0 28 * we're testing here are the following operations:
michael@0 29 * parse: string -> CSS rule
michael@0 30 * serialize: CSS rule -> string (normalization 1)
michael@0 31 * (this actually has two variants that go through partly different
michael@0 32 * codepaths, which we exercise with getPropertyValue and cssText)
michael@0 33 * compute: CSS rule -> computed style
michael@0 34 * cserialize: computed style -> string (normalization 2)
michael@0 35 *
michael@0 36 * Both serialize and cserialize do some normalization, so we can't test
michael@0 37 * for pure round-tripping, and we also can't compare their output since
michael@0 38 * they could normalize differently. (We might at some point in the
michael@0 39 * future want to guarantee that any output of cserialize is
michael@0 40 * untouched by going through parse+serialize, though.)
michael@0 41 *
michael@0 42 * So we test idempotence of parse + serialize by running the whole
michael@0 43 * operation twice. Likewise for parse + compute + cserialize.
michael@0 44 *
michael@0 45 * Slightly more interestingly, we test that serialize + parse is the
michael@0 46 * identity transform by comparing the output of parse + compute +
michael@0 47 * cserialize to the output of parse + serialize + parse + compute +
michael@0 48 * cserialize.
michael@0 49 */
michael@0 50
michael@0 51 var gSystemFont = {
michael@0 52 "caption": true,
michael@0 53 "icon": true,
michael@0 54 "menu": true,
michael@0 55 "message-box": true,
michael@0 56 "small-caption": true,
michael@0 57 "status-bar": true,
michael@0 58 "-moz-window": true,
michael@0 59 "-moz-document": true,
michael@0 60 "-moz-desktop": true,
michael@0 61 "-moz-info": true,
michael@0 62 "-moz-dialog": true,
michael@0 63 "-moz-button": true,
michael@0 64 "-moz-pull-down-menu": true,
michael@0 65 "-moz-list": true,
michael@0 66 "-moz-field": true,
michael@0 67 "-moz-workspace": true,
michael@0 68 };
michael@0 69
michael@0 70 var gBadCompute = {
michael@0 71 // output wrapped around to positive, in exponential notation
michael@0 72 "-moz-box-ordinal-group": [ "-1", "-1000" ],
michael@0 73 };
michael@0 74
michael@0 75 function xfail_compute(property, value)
michael@0 76 {
michael@0 77 if (property in gBadCompute &&
michael@0 78 gBadCompute[property].indexOf(value) != -1)
michael@0 79 return true;
michael@0 80
michael@0 81 return false;
michael@0 82 }
michael@0 83
michael@0 84 var gBadSerialize = {
michael@0 85 // Font-families which include quotes don't get those escaped when
michael@0 86 //serializing: see bug 660397
michael@0 87 "font-family": ["\\\"Times New Roman", "Times, \\\"Times New Roman"],
michael@0 88 };
michael@0 89
michael@0 90 function xfail_serialize(property, value)
michael@0 91 {
michael@0 92 if (property in gBadSerialize &&
michael@0 93 gBadSerialize[property].indexOf(value) != -1)
michael@0 94 return true;
michael@0 95
michael@0 96 return false;
michael@0 97 }
michael@0 98
michael@0 99 var gElement = document.getElementById("testnode");
michael@0 100 var gDeclaration = gElement.style;
michael@0 101 var gComputedStyle = window.getComputedStyle(gElement, "");
michael@0 102
michael@0 103 var gPrereqDeclaration =
michael@0 104 document.getElementById("prereqsheet").sheet.cssRules[0].style;
michael@0 105
michael@0 106 function test_property(property)
michael@0 107 {
michael@0 108 ok(SpecialPowers.getBoolPref("layout.css.variables.enabled"), "pref not set #2");
michael@0 109 var info = gCSSProperties[property];
michael@0 110
michael@0 111 var test_computed = !("backend_only" in info);
michael@0 112
michael@0 113 // can all properties be removed from the style?
michael@0 114 function test_remove_all_properties(property, value) {
michael@0 115 var i, p = [];
michael@0 116 for (i = 0; i < gDeclaration.length; i++) p.push(gDeclaration[i]);
michael@0 117 for (i = 0; i < p.length; i++) gDeclaration.removeProperty(p[i]);
michael@0 118 var errstr = "when setting property " + property + " to " + value;
michael@0 119 is(gDeclaration.length, 0, "unremovable properties " + errstr);
michael@0 120 is(gDeclaration.cssText, "", "non-empty serialization after removing all properties " + errstr);
michael@0 121 }
michael@0 122
michael@0 123 function test_value(value, resolved_value) {
michael@0 124 var value_has_variable_reference = resolved_value != null;
michael@0 125
michael@0 126 gDeclaration.setProperty(property, value, "");
michael@0 127
michael@0 128 var idx;
michael@0 129
michael@0 130 var step1val = gDeclaration.getPropertyValue(property);
michael@0 131 var step1vals = [];
michael@0 132 var step1ser = gDeclaration.cssText;
michael@0 133 if ("subproperties" in info)
michael@0 134 for (idx in info.subproperties)
michael@0 135 step1vals.push(gDeclaration.getPropertyValue(info.subproperties[idx]));
michael@0 136 var step1comp;
michael@0 137 var step1comps = [];
michael@0 138 if (test_computed && info.type != CSS_TYPE_TRUE_SHORTHAND)
michael@0 139 step1comp = gComputedStyle.getPropertyValue(property);
michael@0 140 if (test_computed && "subproperties" in info)
michael@0 141 for (idx in info.subproperties)
michael@0 142 step1comps.push(gComputedStyle.getPropertyValue(info.subproperties[idx]));
michael@0 143
michael@0 144 isnot(step1val, "", "setting '" + value + "' on '" + property + "'");
michael@0 145 if ("subproperties" in info)
michael@0 146 for (idx in info.subproperties) {
michael@0 147 var subprop = info.subproperties[idx];
michael@0 148 if (value_has_variable_reference &&
michael@0 149 (!info.alias_for || info.type == CSS_TYPE_TRUE_SHORTHAND)) {
michael@0 150 is(gDeclaration.getPropertyValue(subprop), "",
michael@0 151 "setting '" + value + "' on '" + property + "' (for '" + subprop + "')");
michael@0 152 } else {
michael@0 153 isnot(gDeclaration.getPropertyValue(subprop), "",
michael@0 154 "setting '" + value + "' on '" + property + "' (for '" + subprop + "')");
michael@0 155 }
michael@0 156 }
michael@0 157
michael@0 158 // We don't care particularly about the whitespace or the placement of
michael@0 159 // semicolons, but for simplicity we'll test the current behavior.
michael@0 160 var expected_serialization = "";
michael@0 161 if (step1val != "") {
michael@0 162 if ("alias_for" in info) {
michael@0 163 expected_serialization = info.alias_for + ": " + step1val + ";";
michael@0 164 } else {
michael@0 165 expected_serialization = property + ": " + step1val + ";";
michael@0 166 }
michael@0 167 }
michael@0 168 is(step1ser, expected_serialization,
michael@0 169 "serialization should match property value");
michael@0 170
michael@0 171 gDeclaration.removeProperty(property);
michael@0 172 gDeclaration.setProperty(property, step1val, "");
michael@0 173
michael@0 174 var serialize_func = xfail_serialize(property, value) &&
michael@0 175 !value_has_variable_reference ? todo_is : is;
michael@0 176
michael@0 177 serialize_func(gDeclaration.getPropertyValue(property), step1val,
michael@0 178 "parse+serialize should be idempotent for '" +
michael@0 179 property + ": " + value + "'");
michael@0 180 if (test_computed && info.type != CSS_TYPE_TRUE_SHORTHAND) {
michael@0 181 serialize_func(gComputedStyle.getPropertyValue(property), step1comp,
michael@0 182 "serialize+parse should be identity transform for '" +
michael@0 183 property + ": " + value + "'");
michael@0 184 }
michael@0 185
michael@0 186 if ("subproperties" in info &&
michael@0 187 // Using setProperty over subproperties is not sufficient for
michael@0 188 // system fonts, since the shorthand does more than its parts.
michael@0 189 (property != "font" || !(value in gSystemFont)) &&
michael@0 190 // Likewise for special compatibility values of transform
michael@0 191 (property != "-moz-transform" || !value.match(/^matrix.*(px|em|%)/)) &&
michael@0 192 !value_has_variable_reference) {
michael@0 193 gDeclaration.removeProperty(property);
michael@0 194 for (idx in info.subproperties) {
michael@0 195 var subprop = info.subproperties[idx];
michael@0 196 gDeclaration.setProperty(subprop, step1vals[idx], "");
michael@0 197 }
michael@0 198
michael@0 199 // Now that all the subprops are set, check their values. Note that we
michael@0 200 // need this in a separate loop, in case parts of the shorthand affect
michael@0 201 // the computed values of other parts.
michael@0 202 for (idx in info.subproperties) {
michael@0 203 var subprop = info.subproperties[idx];
michael@0 204 if (test_computed && !("backend_only" in gCSSProperties[subprop])) {
michael@0 205 is(gComputedStyle.getPropertyValue(subprop), step1comps[idx],
michael@0 206 "serialize(" + subprop + ")+parse should be the identity " +
michael@0 207 "transform for '" + property + ": " + value + "'");
michael@0 208 }
michael@0 209 }
michael@0 210 is(gDeclaration.getPropertyValue(property), step1val,
michael@0 211 "parse+split+serialize should be idempotent for '" +
michael@0 212 property + ": " + value + "'");
michael@0 213 }
michael@0 214
michael@0 215 if (test_computed && info.type != CSS_TYPE_TRUE_SHORTHAND) {
michael@0 216 gDeclaration.removeProperty(property);
michael@0 217 gDeclaration.setProperty(property, step1comp, "");
michael@0 218 var func = (xfail_compute(property, value) ||
michael@0 219 xfail_serialize(property, resolved_value || value)) ? todo_is : is;
michael@0 220 func(gComputedStyle.getPropertyValue(property), step1comp,
michael@0 221 "parse+compute+serialize should be idempotent for '" +
michael@0 222 property + ": " + value + "'");
michael@0 223 }
michael@0 224 if (test_computed && "subproperties" in info) {
michael@0 225 gDeclaration.removeProperty(property);
michael@0 226 for (idx in info.subproperties) {
michael@0 227 var subprop = info.subproperties[idx];
michael@0 228 if ("backend_only" in gCSSProperties[subprop])
michael@0 229 continue;
michael@0 230 gDeclaration.setProperty(subprop, step1comps[idx], "");
michael@0 231 }
michael@0 232
michael@0 233 // Now that all the subprops are set, check their values. Note that we
michael@0 234 // need this in a separate loop, in case parts of the shorthand affect
michael@0 235 // the computed values of other parts.
michael@0 236 for (idx in info.subproperties) {
michael@0 237 var subprop = info.subproperties[idx];
michael@0 238 if ("backend_only" in gCSSProperties[subprop])
michael@0 239 continue;
michael@0 240 is(gComputedStyle.getPropertyValue(subprop), step1comps[idx],
michael@0 241 "parse+compute+serialize(" + subprop + ") should be idempotent for '" +
michael@0 242 property + ": " + value + "'");
michael@0 243 }
michael@0 244 }
michael@0 245
michael@0 246 // sanity check shorthands to make sure disabled props aren't exposed
michael@0 247 if (info.type != CSS_TYPE_LONGHAND) {
michael@0 248 gDeclaration.setProperty(property, value, "");
michael@0 249 test_remove_all_properties(property, value);
michael@0 250 }
michael@0 251
michael@0 252 gDeclaration.removeProperty(property);
michael@0 253 }
michael@0 254
michael@0 255 function test_value_without_variable(value) {
michael@0 256 test_value(value, null);
michael@0 257 }
michael@0 258
michael@0 259 function test_value_with_variable(value) {
michael@0 260 gPrereqDeclaration.setProperty("--a", value, "");
michael@0 261 test_value("var(--a)", value);
michael@0 262 gPrereqDeclaration.removeProperty("--a");
michael@0 263 }
michael@0 264
michael@0 265 if ("prerequisites" in info) {
michael@0 266 var prereqs = info.prerequisites;
michael@0 267 for (var prereq in prereqs) {
michael@0 268 gPrereqDeclaration.setProperty(prereq, prereqs[prereq], "");
michael@0 269 }
michael@0 270 }
michael@0 271
michael@0 272 var idx;
michael@0 273 for (idx in info.initial_values) {
michael@0 274 test_value_without_variable(info.initial_values[idx]);
michael@0 275 test_value_with_variable(info.initial_values[idx]);
michael@0 276 }
michael@0 277 for (idx in info.other_values) {
michael@0 278 test_value_without_variable(info.other_values[idx]);
michael@0 279 test_value_with_variable(info.other_values[idx]);
michael@0 280 }
michael@0 281
michael@0 282 if ("prerequisites" in info) {
michael@0 283 for (var prereq in info.prerequisites) {
michael@0 284 gPrereqDeclaration.removeProperty(prereq);
michael@0 285 }
michael@0 286 }
michael@0 287
michael@0 288 }
michael@0 289
michael@0 290 function runTest() {
michael@0 291 // To avoid triggering the slow script dialog, we have to test one
michael@0 292 // property at a time.
michael@0 293 ok(SpecialPowers.getBoolPref("layout.css.variables.enabled"), "pref not set #1");
michael@0 294 var props = [];
michael@0 295 for (var prop in gCSSProperties)
michael@0 296 props.push(prop);
michael@0 297 props = props.reverse();
michael@0 298 function do_one() {
michael@0 299 if (props.length == 0) {
michael@0 300 SimpleTest.finish();
michael@0 301 return;
michael@0 302 }
michael@0 303 test_property(props.pop());
michael@0 304 SimpleTest.executeSoon(do_one);
michael@0 305 }
michael@0 306 SimpleTest.executeSoon(do_one);
michael@0 307 }
michael@0 308
michael@0 309 SimpleTest.waitForExplicitFinish();
michael@0 310 SimpleTest.requestLongerTimeout(2);
michael@0 311
michael@0 312 SpecialPowers.pushPrefEnv({ set: [["layout.css.variables.enabled", true]] },
michael@0 313 runTest);
michael@0 314 </script>
michael@0 315 </pre>
michael@0 316 </body>
michael@0 317 </html>

mercurial