content/html/content/test/reflect.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* Any copyright is dedicated to the Public Domain.
michael@0 2 http://creativecommons.org/publicdomain/zero/1.0/ */
michael@0 3
michael@0 4 /**
michael@0 5 * reflect.js is a collection of methods to test HTML attribute reflection.
michael@0 6 * Each of attribute is reflected differently, depending on various parameters,
michael@0 7 * see:
michael@0 8 * http://www.whatwg.org/html/#reflecting-content-attributes-in-idl-attributes
michael@0 9 *
michael@0 10 * Do not forget to add these line at the beginning of each new reflect* method:
michael@0 11 * ok(attr in element, attr + " should be an IDL attribute of this element");
michael@0 12 * is(typeof element[attr], <type>, attr + " IDL attribute should be a <type>");
michael@0 13 */
michael@0 14
michael@0 15 /**
michael@0 16 * Checks that a given attribute is correctly reflected as a string.
michael@0 17 *
michael@0 18 * @param aParameters Object object containing the parameters, which are:
michael@0 19 * - element Element node to test
michael@0 20 * - attribute String name of the attribute
michael@0 21 * OR
michael@0 22 * attribute Object object containing two attributes, 'content' and 'idl'
michael@0 23 * - otherValues Array [optional] other values to test in addition of the default ones
michael@0 24 * - extendedAttributes Object object which can have 'TreatNullAs': "EmptyString"
michael@0 25 */
michael@0 26 function reflectString(aParameters)
michael@0 27 {
michael@0 28 var element = aParameters.element;
michael@0 29 var contentAttr = typeof aParameters.attribute === "string"
michael@0 30 ? aParameters.attribute : aParameters.attribute.content;
michael@0 31 var idlAttr = typeof aParameters.attribute === "string"
michael@0 32 ? aParameters.attribute : aParameters.attribute.idl;
michael@0 33 var otherValues = aParameters.otherValues !== undefined
michael@0 34 ? aParameters.otherValues : [];
michael@0 35 var treatNullAs = aParameters.extendedAttributes ?
michael@0 36 aParameters.extendedAttributes.TreatNullAs : null;
michael@0 37
michael@0 38 ok(idlAttr in element,
michael@0 39 idlAttr + " should be an IDL attribute of this element");
michael@0 40 is(typeof element[idlAttr], "string",
michael@0 41 "'" + idlAttr + "' IDL attribute should be a string");
michael@0 42
michael@0 43 // Tests when the attribute isn't set.
michael@0 44 is(element.getAttribute(contentAttr), null,
michael@0 45 "When not set, the content attribute should be null.");
michael@0 46 is(element[idlAttr], "",
michael@0 47 "When not set, the IDL attribute should return the empty string");
michael@0 48
michael@0 49 /**
michael@0 50 * TODO: as long as null stringification doesn't follow the WebIDL
michael@0 51 * specifications, don't add it to the loop below and keep it here.
michael@0 52 */
michael@0 53 element.setAttribute(contentAttr, null);
michael@0 54 is(element.getAttribute(contentAttr), "null",
michael@0 55 "null should have been stringified to 'null' for '" + contentAttr + "'");
michael@0 56 is(element[idlAttr], "null",
michael@0 57 "null should have been stringified to 'null' for '" + idlAttr + "'");
michael@0 58 element.removeAttribute(contentAttr);
michael@0 59
michael@0 60 element[idlAttr] = null;
michael@0 61 if (treatNullAs == "EmptyString") {
michael@0 62 is(element.getAttribute(contentAttr), "",
michael@0 63 "null should have been stringified to '' for '" + contentAttr + "'");
michael@0 64 is(element[idlAttr], "",
michael@0 65 "null should have been stringified to '' for '" + idlAttr + "'");
michael@0 66 } else {
michael@0 67 is(element.getAttribute(contentAttr), "null",
michael@0 68 "null should have been stringified to 'null' for '" + contentAttr + "'");
michael@0 69 is(element[idlAttr], "null",
michael@0 70 "null should have been stringified to 'null' for '" + contentAttr + "'");
michael@0 71 }
michael@0 72 element.removeAttribute(contentAttr);
michael@0 73
michael@0 74 // Tests various strings.
michael@0 75 var stringsToTest = [
michael@0 76 // [ test value, expected result ]
michael@0 77 [ "", "" ],
michael@0 78 [ "null", "null" ],
michael@0 79 [ "undefined", "undefined" ],
michael@0 80 [ "foo", "foo" ],
michael@0 81 [ contentAttr, contentAttr ],
michael@0 82 [ idlAttr, idlAttr ],
michael@0 83 // TODO: uncomment this when null stringification will follow the specs.
michael@0 84 // [ null, "null" ],
michael@0 85 [ undefined, "undefined" ],
michael@0 86 [ true, "true" ],
michael@0 87 [ false, "false" ],
michael@0 88 [ 42, "42" ],
michael@0 89 // ES5, verse 8.12.8.
michael@0 90 [ { toString: function() { return "foo" } },
michael@0 91 "foo" ],
michael@0 92 [ { valueOf: function() { return "foo" } },
michael@0 93 "[object Object]" ],
michael@0 94 [ { valueOf: function() { return "quux" },
michael@0 95 toString: undefined },
michael@0 96 "quux" ],
michael@0 97 [ { valueOf: function() { return "foo" },
michael@0 98 toString: function() { return "bar" } },
michael@0 99 "bar" ]
michael@0 100 ];
michael@0 101
michael@0 102 otherValues.forEach(function(v) { stringsToTest.push([v, v]) });
michael@0 103
michael@0 104 stringsToTest.forEach(function([v, r]) {
michael@0 105 element.setAttribute(contentAttr, v);
michael@0 106 is(element[idlAttr], r,
michael@0 107 "IDL attribute '" + idlAttr + "' should return the value it has been set to.");
michael@0 108 is(element.getAttribute(contentAttr), r,
michael@0 109 "Content attribute '" + contentAttr + "'should return the value it has been set to.");
michael@0 110 element.removeAttribute(contentAttr);
michael@0 111
michael@0 112 element[idlAttr] = v;
michael@0 113 is(element[idlAttr], r,
michael@0 114 "IDL attribute '" + idlAttr + "' should return the value it has been set to.");
michael@0 115 is(element.getAttribute(contentAttr), r,
michael@0 116 "Content attribute '" + contentAttr + "' should return the value it has been set to.");
michael@0 117 element.removeAttribute(contentAttr);
michael@0 118 });
michael@0 119
michael@0 120 // Tests after removeAttribute() is called. Should be equivalent with not set.
michael@0 121 is(element.getAttribute(contentAttr), null,
michael@0 122 "When not set, the content attribute should be null.");
michael@0 123 is(element[idlAttr], "",
michael@0 124 "When not set, the IDL attribute should return the empty string");
michael@0 125 }
michael@0 126
michael@0 127 /**
michael@0 128 * Checks that a given attribute name for a given element is correctly reflected
michael@0 129 * as an unsigned int.
michael@0 130 *
michael@0 131 * @param aParameters Object object containing the parameters, which are:
michael@0 132 * - element Element node to test on
michael@0 133 * - attribute String name of the attribute
michael@0 134 * - nonZero Boolean whether the attribute should be non-null
michael@0 135 * - defaultValue Integer [optional] default value, if different from the default one
michael@0 136 */
michael@0 137 function reflectUnsignedInt(aParameters)
michael@0 138 {
michael@0 139 var element = aParameters.element;
michael@0 140 var attr = aParameters.attribute;
michael@0 141 var nonZero = aParameters.nonZero;
michael@0 142 var defaultValue = aParameters.defaultValue;
michael@0 143
michael@0 144 if (defaultValue === undefined) {
michael@0 145 if (nonZero) {
michael@0 146 defaultValue = 1;
michael@0 147 } else {
michael@0 148 defaultValue = 0;
michael@0 149 }
michael@0 150 }
michael@0 151
michael@0 152 ok(attr in element, attr + " should be an IDL attribute of this element");
michael@0 153 is(typeof element[attr], "number", attr + " IDL attribute should be a number");
michael@0 154
michael@0 155 // Check default value.
michael@0 156 is(element[attr], defaultValue, "default value should be " + defaultValue);
michael@0 157 ok(!element.hasAttribute(attr), attr + " shouldn't be present");
michael@0 158
michael@0 159 var values = [ 1, 3, 42, 2147483647 ];
michael@0 160
michael@0 161 for (var value of values) {
michael@0 162 element[attr] = value;
michael@0 163 is(element[attr], value, "." + attr + " should be equals " + value);
michael@0 164 is(element.getAttribute(attr), String(value),
michael@0 165 "@" + attr + " should be equals " + value);
michael@0 166
michael@0 167 element.setAttribute(attr, value);
michael@0 168 is(element[attr], value, "." + attr + " should be equals " + value);
michael@0 169 is(element.getAttribute(attr), String(value),
michael@0 170 "@" + attr + " should be equals " + value);
michael@0 171 }
michael@0 172
michael@0 173 // -3000000000 is equivalent to 1294967296 when using the IDL attribute.
michael@0 174 element[attr] = -3000000000;
michael@0 175 is(element[attr], 1294967296, "." + attr + " should be equals to 1294967296");
michael@0 176 is(element.getAttribute(attr), "1294967296",
michael@0 177 "@" + attr + " should be equals to 1294967296");
michael@0 178
michael@0 179 // When setting the content atribute, it's a string so it will be unvalid.
michael@0 180 element.setAttribute(attr, -3000000000);
michael@0 181 is(element.getAttribute(attr), "-3000000000",
michael@0 182 "@" + attr + " should be equals to " + -3000000000);
michael@0 183 is(element[attr], defaultValue,
michael@0 184 "." + attr + " should be equals to " + defaultValue);
michael@0 185
michael@0 186 var nonValidValues = [
michael@0 187 /* invalid value, value in the unsigned int range */
michael@0 188 [ -2147483648, 2147483648 ],
michael@0 189 [ -1, 4294967295 ],
michael@0 190 [ 3147483647, 3147483647 ],
michael@0 191 ];
michael@0 192
michael@0 193 for (var values of nonValidValues) {
michael@0 194 element[attr] = values[0];
michael@0 195 is(element.getAttribute(attr), String(values[1]),
michael@0 196 "@" + attr + " should be equals to " + values[1]);
michael@0 197 is(element[attr], defaultValue,
michael@0 198 "." + attr + " should be equals to " + defaultValue);
michael@0 199 }
michael@0 200
michael@0 201 for (var values of nonValidValues) {
michael@0 202 element.setAttribute(attr, values[0]);
michael@0 203 is(element.getAttribute(attr), String(values[0]),
michael@0 204 "@" + attr + " should be equals to " + values[0]);
michael@0 205 is(element[attr], defaultValue,
michael@0 206 "." + attr + " should be equals to " + defaultValue);
michael@0 207 }
michael@0 208
michael@0 209 // Setting to 0 should throw an error if nonZero is true.
michael@0 210 var caught = false;
michael@0 211 try {
michael@0 212 element[attr] = 0;
michael@0 213 } catch(e) {
michael@0 214 caught = true;
michael@0 215 is(e.name, "IndexSizeError", "exception should be IndexSizeError");
michael@0 216 is(e.code, DOMException.INDEX_SIZE_ERR, "exception code should be INDEX_SIZE_ERR");
michael@0 217 }
michael@0 218
michael@0 219 if (nonZero) {
michael@0 220 ok(caught, "an exception should have been caught");
michael@0 221 } else {
michael@0 222 ok(!caught, "no exception should have been caught");
michael@0 223 }
michael@0 224
michael@0 225 // If 0 is set in @attr, it will be ignored when calling .attr.
michael@0 226 element.setAttribute(attr, "0");
michael@0 227 is(element.getAttribute(attr), "0", "@" + attr + " should be equals to 0");
michael@0 228 if (nonZero) {
michael@0 229 is(element[attr], defaultValue,
michael@0 230 "." + attr + " should be equals to " + defaultValue);
michael@0 231 } else {
michael@0 232 is(element[attr], 0, "." + attr + " should be equals to 0");
michael@0 233 }
michael@0 234 }
michael@0 235
michael@0 236 /**
michael@0 237 * Checks that a given attribute is correctly reflected as limited to known
michael@0 238 * values enumerated attribute.
michael@0 239 *
michael@0 240 * @param aParameters Object object containing the parameters, which are:
michael@0 241 * - element Element node to test on
michael@0 242 * - attribute String name of the attribute
michael@0 243 * OR
michael@0 244 * attribute Object object containing two attributes, 'content' and 'idl'
michael@0 245 * - validValues Array valid values we support
michael@0 246 * - invalidValues Array invalid values
michael@0 247 * - defaultValue String [optional] default value when no valid value is set
michael@0 248 * OR
michael@0 249 * defaultValue Object [optional] object containing two attributes, 'invalid' and 'missing'
michael@0 250 * - unsupportedValues Array [optional] valid values we do not support
michael@0 251 */
michael@0 252 function reflectLimitedEnumerated(aParameters)
michael@0 253 {
michael@0 254 var element = aParameters.element;
michael@0 255 var contentAttr = typeof aParameters.attribute === "string"
michael@0 256 ? aParameters.attribute : aParameters.attribute.content;
michael@0 257 var idlAttr = typeof aParameters.attribute === "string"
michael@0 258 ? aParameters.attribute : aParameters.attribute.idl;
michael@0 259 var validValues = aParameters.validValues;
michael@0 260 var invalidValues = aParameters.invalidValues;
michael@0 261 var defaultValueInvalid = aParameters.defaultValue === undefined
michael@0 262 ? "" : typeof aParameters.defaultValue === "string"
michael@0 263 ? aParameters.defaultValue : aParameters.defaultValue.invalid
michael@0 264 var defaultValueMissing = aParameters.defaultValue === undefined
michael@0 265 ? "" : typeof aParameters.defaultValue === "string"
michael@0 266 ? aParameters.defaultValue : aParameters.defaultValue.missing
michael@0 267 var unsupportedValues = aParameters.unsupportedValues !== undefined
michael@0 268 ? aParameters.unsupportedValues : [];
michael@0 269
michael@0 270 ok(idlAttr in element, idlAttr + " should be an IDL attribute of this element");
michael@0 271 is(typeof element[idlAttr], "string", "'" + idlAttr + "' IDL attribute should be a string");
michael@0 272
michael@0 273 // Explicitly check the default value.
michael@0 274 element.removeAttribute(contentAttr);
michael@0 275 is(element[idlAttr], defaultValueMissing,
michael@0 276 "When no attribute is set, the value should be the default value.");
michael@0 277
michael@0 278 // Check valid values.
michael@0 279 validValues.forEach(function (v) {
michael@0 280 element.setAttribute(contentAttr, v);
michael@0 281 is(element[idlAttr], v,
michael@0 282 v + " should be accepted as a valid value for " + idlAttr);
michael@0 283 is(element.getAttribute(contentAttr), v,
michael@0 284 "Content attribute should return the value it has been set to.");
michael@0 285 element.removeAttribute(contentAttr);
michael@0 286
michael@0 287 element.setAttribute(contentAttr, v.toUpperCase());
michael@0 288 is(element[idlAttr], v,
michael@0 289 "Enumerated attributes should be case-insensitive.");
michael@0 290 is(element.getAttribute(contentAttr), v.toUpperCase(),
michael@0 291 "Content attribute should not be lower-cased.");
michael@0 292 element.removeAttribute(contentAttr);
michael@0 293
michael@0 294 element[idlAttr] = v;
michael@0 295 is(element[idlAttr], v,
michael@0 296 v + " should be accepted as a valid value for " + idlAttr);
michael@0 297 is(element.getAttribute(contentAttr), v,
michael@0 298 "Content attribute should return the value it has been set to.");
michael@0 299 element.removeAttribute(contentAttr);
michael@0 300
michael@0 301 element[idlAttr] = v.toUpperCase();
michael@0 302 is(element[idlAttr], v,
michael@0 303 "Enumerated attributes should be case-insensitive.");
michael@0 304 is(element.getAttribute(contentAttr), v.toUpperCase(),
michael@0 305 "Content attribute should not be lower-cased.");
michael@0 306 element.removeAttribute(contentAttr);
michael@0 307 });
michael@0 308
michael@0 309 // Check invalid values.
michael@0 310 invalidValues.forEach(function (v) {
michael@0 311 element.setAttribute(contentAttr, v);
michael@0 312 is(element[idlAttr], defaultValueInvalid,
michael@0 313 "When the content attribute is set to an invalid value, the default value should be returned.");
michael@0 314 is(element.getAttribute(contentAttr), v,
michael@0 315 "Content attribute should not have been changed.");
michael@0 316 element.removeAttribute(contentAttr);
michael@0 317
michael@0 318 element[idlAttr] = v;
michael@0 319 is(element[idlAttr], defaultValueInvalid,
michael@0 320 "When the value is set to an invalid value, the default value should be returned.");
michael@0 321 is(element.getAttribute(contentAttr), v,
michael@0 322 "Content attribute should not have been changed.");
michael@0 323 element.removeAttribute(contentAttr);
michael@0 324 });
michael@0 325
michael@0 326 // Check valid values we currently do not support.
michael@0 327 // Basically, it's like the checks for the valid values but with some todo's.
michael@0 328 unsupportedValues.forEach(function (v) {
michael@0 329 element.setAttribute(contentAttr, v);
michael@0 330 todo_is(element[idlAttr], v,
michael@0 331 v + " should be accepted as a valid value for " + idlAttr);
michael@0 332 is(element.getAttribute(contentAttr), v,
michael@0 333 "Content attribute should return the value it has been set to.");
michael@0 334 element.removeAttribute(contentAttr);
michael@0 335
michael@0 336 element.setAttribute(contentAttr, v.toUpperCase());
michael@0 337 todo_is(element[idlAttr], v,
michael@0 338 "Enumerated attributes should be case-insensitive.");
michael@0 339 is(element.getAttribute(contentAttr), v.toUpperCase(),
michael@0 340 "Content attribute should not be lower-cased.");
michael@0 341 element.removeAttribute(contentAttr);
michael@0 342
michael@0 343 element[idlAttr] = v;
michael@0 344 todo_is(element[idlAttr], v,
michael@0 345 v + " should be accepted as a valid value for " + idlAttr);
michael@0 346 is(element.getAttribute(contentAttr), v,
michael@0 347 "Content attribute should return the value it has been set to.");
michael@0 348 element.removeAttribute(contentAttr);
michael@0 349
michael@0 350 element[idlAttr] = v.toUpperCase();
michael@0 351 todo_is(element[idlAttr], v,
michael@0 352 "Enumerated attributes should be case-insensitive.");
michael@0 353 is(element.getAttribute(contentAttr), v.toUpperCase(),
michael@0 354 "Content attribute should not be lower-cased.");
michael@0 355 element.removeAttribute(contentAttr);
michael@0 356 });
michael@0 357 }
michael@0 358
michael@0 359 /**
michael@0 360 * Checks that a given attribute is correctly reflected as a boolean.
michael@0 361 *
michael@0 362 * @param aParameters Object object containing the parameters, which are:
michael@0 363 * - element Element node to test on
michael@0 364 * - attribute String name of the attribute
michael@0 365 * OR
michael@0 366 * attribute Object object containing two attributes, 'content' and 'idl'
michael@0 367 */
michael@0 368 function reflectBoolean(aParameters)
michael@0 369 {
michael@0 370 var element = aParameters.element;
michael@0 371 var contentAttr = typeof aParameters.attribute === "string"
michael@0 372 ? aParameters.attribute : aParameters.attribute.content;
michael@0 373 var idlAttr = typeof aParameters.attribute === "string"
michael@0 374 ? aParameters.attribute : aParameters.attribute.idl;
michael@0 375
michael@0 376 ok(idlAttr in element,
michael@0 377 idlAttr + " should be an IDL attribute of this element");
michael@0 378 is(typeof element[idlAttr], "boolean",
michael@0 379 idlAttr + " IDL attribute should be a boolean");
michael@0 380
michael@0 381 // Tests when the attribute isn't set.
michael@0 382 is(element.getAttribute(contentAttr), null,
michael@0 383 "When not set, the content attribute should be null.");
michael@0 384 is(element[idlAttr], false,
michael@0 385 "When not set, the IDL attribute should return false");
michael@0 386
michael@0 387 /**
michael@0 388 * Test various values.
michael@0 389 * Each value to test is actually an object containing a 'value' property
michael@0 390 * containing the value to actually test, a 'stringified' property containing
michael@0 391 * the stringified value and a 'result' property containing the expected
michael@0 392 * result when the value is set to the IDL attribute.
michael@0 393 */
michael@0 394 var valuesToTest = [
michael@0 395 { value: true, stringified: "true", result: true },
michael@0 396 { value: false, stringified: "false", result: false },
michael@0 397 { value: "true", stringified: "true", result: true },
michael@0 398 { value: "false", stringified: "false", result: true },
michael@0 399 { value: "foo", stringified: "foo", result: true },
michael@0 400 { value: idlAttr, stringified: idlAttr, result: true },
michael@0 401 { value: contentAttr, stringified: contentAttr, result: true },
michael@0 402 { value: "null", stringified: "null", result: true },
michael@0 403 { value: "undefined", stringified: "undefined", result: true },
michael@0 404 { value: "", stringified: "", result: false },
michael@0 405 { value: undefined, stringified: "undefined", result: false },
michael@0 406 { value: null, stringified: "null", result: false },
michael@0 407 { value: +0, stringified: "0", result: false },
michael@0 408 { value: -0, stringified: "0", result: false },
michael@0 409 { value: NaN, stringified: "NaN", result: false },
michael@0 410 { value: 42, stringified: "42", result: true },
michael@0 411 { value: Infinity, stringified: "Infinity", result: true },
michael@0 412 { value: -Infinity, stringified: "-Infinity", result: true },
michael@0 413 // ES5, verse 9.2.
michael@0 414 { value: { toString: function() { return "foo" } }, stringified: "foo",
michael@0 415 result: true },
michael@0 416 { value: { valueOf: function() { return "foo" } },
michael@0 417 stringified: "[object Object]", result: true },
michael@0 418 { value: { valueOf: function() { return "quux" }, toString: undefined },
michael@0 419 stringified: "quux", result: true },
michael@0 420 { value: { valueOf: function() { return "foo" },
michael@0 421 toString: function() { return "bar" } }, stringified: "bar",
michael@0 422 result: true },
michael@0 423 { value: { valueOf: function() { return false } },
michael@0 424 stringified: "[object Object]", result: true },
michael@0 425 { value: { foo: false, bar: false }, stringified: "[object Object]",
michael@0 426 result: true },
michael@0 427 { value: { }, stringified: "[object Object]", result: true },
michael@0 428 ];
michael@0 429
michael@0 430 valuesToTest.forEach(function(v) {
michael@0 431 element.setAttribute(contentAttr, v.value);
michael@0 432 is(element[idlAttr], true,
michael@0 433 "IDL attribute should return always return 'true' if the content attribute has been set");
michael@0 434 is(element.getAttribute(contentAttr), v.stringified,
michael@0 435 "Content attribute should return the stringified value it has been set to.");
michael@0 436 element.removeAttribute(contentAttr);
michael@0 437
michael@0 438 element[idlAttr] = v.value;
michael@0 439 is(element[idlAttr], v.result, "IDL attribute should return " + v.result);
michael@0 440 is(element.getAttribute(contentAttr), v.result ? "" : null,
michael@0 441 v.result ? "Content attribute should return the empty string."
michael@0 442 : "Content attribute should return null.");
michael@0 443 is(element.hasAttribute(contentAttr), v.result,
michael@0 444 v.result ? contentAttr + " should not be present"
michael@0 445 : contentAttr + " should be present");
michael@0 446 element.removeAttribute(contentAttr);
michael@0 447 });
michael@0 448
michael@0 449 // Tests after removeAttribute() is called. Should be equivalent with not set.
michael@0 450 is(element.getAttribute(contentAttr), null,
michael@0 451 "When not set, the content attribute should be null.");
michael@0 452 is(element[contentAttr], false,
michael@0 453 "When not set, the IDL attribute should return false");
michael@0 454 }
michael@0 455
michael@0 456 /**
michael@0 457 * Checks that a given attribute name for a given element is correctly reflected
michael@0 458 * as an signed integer.
michael@0 459 *
michael@0 460 * @param aParameters Object object containing the parameters, which are:
michael@0 461 * - element Element node to test on
michael@0 462 * - attribute String name of the attribute
michael@0 463 * - nonNegative Boolean true if the attribute is limited to 'non-negative numbers', false otherwise
michael@0 464 * - defaultValue Integer [optional] default value, if one exists
michael@0 465 */
michael@0 466 function reflectInt(aParameters)
michael@0 467 {
michael@0 468 // Expected value returned by .getAttribute() when |value| has been previously passed to .setAttribute().
michael@0 469 function expectedGetAttributeResult(value) {
michael@0 470 return String(value);
michael@0 471 }
michael@0 472
michael@0 473 function stringToInteger(value, nonNegative, defaultValue) {
michael@0 474 // Parse: Ignore leading whitespace, find [+/-][numbers]
michael@0 475 var result = /^[ \t\n\f\r]*([\+\-]?[0-9]+)/.exec(value);
michael@0 476 if (result) {
michael@0 477 var resultInt = parseInt(result[1], 10);
michael@0 478 if ((nonNegative ? 0 : -0x80000000) <= resultInt && resultInt <= 0x7FFFFFFF) {
michael@0 479 // If the value is within allowed value range for signed/unsigned integer, return value
michael@0 480 return resultInt;
michael@0 481 }
michael@0 482 }
michael@0 483 return defaultValue;
michael@0 484 }
michael@0 485
michael@0 486 // Expected value returned by .getAttribute(attr) or .attr if |value| has been set via the IDL attribute.
michael@0 487 function expectedIdlAttributeResult(value) {
michael@0 488 // This returns the result of calling the ES ToInt32 algorithm on value.
michael@0 489 return value << 0;
michael@0 490 }
michael@0 491
michael@0 492 var element = aParameters.element;
michael@0 493 var attr = aParameters.attribute;
michael@0 494 var nonNegative = aParameters.nonNegative;
michael@0 495
michael@0 496 var defaultValue = aParameters.defaultValue !== undefined
michael@0 497 ? aParameters.defaultValue
michael@0 498 : nonNegative ? -1 : 0;
michael@0 499
michael@0 500 ok(attr in element, attr + " should be an IDL attribute of this element");
michael@0 501 is(typeof element[attr], "number", attr + " IDL attribute should be a number");
michael@0 502
michael@0 503 // Check default value.
michael@0 504 is(element[attr], defaultValue, "default value should be " + defaultValue);
michael@0 505 ok(!element.hasAttribute(attr), attr + " shouldn't be present");
michael@0 506
michael@0 507 /**
michael@0 508 * Test various values.
michael@0 509 * value: The test value that will be set using both setAttribute(value) and
michael@0 510 * element[attr] = value
michael@0 511 */
michael@0 512 var valuesToTest = [
michael@0 513 // Test numeric inputs up to max signed integer
michael@0 514 0, 1, 55555, 2147483647, +42,
michael@0 515 // Test string inputs up to max signed integer
michael@0 516 "0", "1", "777777", "2147483647", "+42",
michael@0 517 // Test negative numeric inputs up to min signed integer
michael@0 518 -0, -1, -3333, -2147483648,
michael@0 519 // Test negative string inputs up to min signed integer
michael@0 520 "-0", "-1", "-222", "-2147483647", "-2147483648",
michael@0 521 // Test numeric inputs that are outside legal 32 bit signed values
michael@0 522 -2147483649, -3000000000, -4294967296, 2147483649, 4000000000, -4294967297,
michael@0 523 // Test string inputs with extra padding
michael@0 524 " 1111111", " 23456 ",
michael@0 525 // Test non-numeric string inputs
michael@0 526 "", " ", "+", "-", "foo", "+foo", "-foo", "+ foo", "- foo", "+-2", "-+2", "++2", "--2", "hello1234", "1234hello",
michael@0 527 "444 world 555", "why 567 what", "-3 nots", "2e5", "300e2", "42+-$", "+42foo", "-514not", "\vblah", "0x10FFFF", "-0xABCDEF",
michael@0 528 // Test decimal numbers
michael@0 529 1.2345, 42.0, 3456789.1, -2.3456, -6789.12345, -2147483649.1234,
michael@0 530 // Test decimal strings
michael@0 531 "1.2345", "42.0", "3456789.1", "-2.3456", "-6789.12345", "-2147483649.1234",
michael@0 532 // Test special values
michael@0 533 undefined, null, NaN, Infinity, -Infinity,
michael@0 534 ];
michael@0 535
michael@0 536 valuesToTest.forEach(function(v) {
michael@0 537 var intValue = stringToInteger(v, nonNegative, defaultValue);
michael@0 538
michael@0 539 element.setAttribute(attr, v);
michael@0 540
michael@0 541 is(element.getAttribute(attr), expectedGetAttributeResult(v), element.localName + ".setAttribute(" +
michael@0 542 attr + ", " + v + "), " + element.localName + ".getAttribute(" + attr + ") ");
michael@0 543
michael@0 544 if (intValue == -2147483648 && element[attr] == defaultValue) {
michael@0 545 //TBD: Bug 586761: .setAttribute(attr, -2147483648) --> element[attr] == defaultValue instead of -2147483648
michael@0 546 todo_is(element[attr], intValue, "Bug 586761: " + element.localName +
michael@0 547 ".setAttribute(value, " + v + "), " + element.localName + "[" + attr + "] ");
michael@0 548 } else {
michael@0 549 is(element[attr], intValue, element.localName +
michael@0 550 ".setAttribute(" + attr + ", " + v + "), " + element.localName + "[" + attr + "] ");
michael@0 551 }
michael@0 552 element.removeAttribute(attr);
michael@0 553
michael@0 554 if (nonNegative && expectedIdlAttributeResult(v) < 0) {
michael@0 555 try {
michael@0 556 element[attr] = v;
michael@0 557 ok(false, element.localName + "[" + attr + "] = " + v + " should throw IndexSizeError");
michael@0 558 } catch(e) {
michael@0 559 is(e.name, "IndexSizeError", element.localName + "[" + attr + "] = " + v +
michael@0 560 " should throw IndexSizeError");
michael@0 561 is(e.code, DOMException.INDEX_SIZE_ERR, element.localName + "[" + attr + "] = " + v +
michael@0 562 " should throw INDEX_SIZE_ERR");
michael@0 563 }
michael@0 564 } else {
michael@0 565 element[attr] = v;
michael@0 566 if (expectedIdlAttributeResult(v) == -2147483648 && element[attr] == defaultValue) {
michael@0 567 //TBD: Bug 586761: .setAttribute(attr, -2147483648) --> element[attr] == defaultValue instead of -2147483648
michael@0 568 todo_is(element[attr], expectedIdlAttributeResult(v), "Bug 586761: " + element.localName + "[" +
michael@0 569 attr + "] = " + v + ", " + element.localName + "[" + attr + "] ");
michael@0 570 } else {
michael@0 571 is(element[attr], expectedIdlAttributeResult(v), element.localName + "[" + attr + "] = " + v +
michael@0 572 ", " + element.localName + "[" + attr + "] ");
michael@0 573 is(element.getAttribute(attr), String(expectedIdlAttributeResult(v)),
michael@0 574 element.localName + "[" + attr + "] = " + v + ", " +
michael@0 575 element.localName + ".getAttribute(" + attr + ") ");
michael@0 576 }
michael@0 577 }
michael@0 578 element.removeAttribute(attr);
michael@0 579 });
michael@0 580
michael@0 581 // Tests after removeAttribute() is called. Should be equivalent with not set.
michael@0 582 is(element.getAttribute(attr), null,
michael@0 583 "When not set, the content attribute should be null.");
michael@0 584 is(element[attr], defaultValue,
michael@0 585 "When not set, the IDL attribute should return default value.");
michael@0 586 }
michael@0 587
michael@0 588 /**
michael@0 589 * Checks that a given attribute is correctly reflected as a url.
michael@0 590 *
michael@0 591 * @param aParameters Object object containing the parameters, which are:
michael@0 592 * - element Element node to test
michael@0 593 * - attribute String name of the attribute
michael@0 594 * OR
michael@0 595 * attribute Object object containing two attributes, 'content' and 'idl'
michael@0 596 */
michael@0 597 function reflectURL(aParameters)
michael@0 598 {
michael@0 599 var element = aParameters.element;
michael@0 600 var contentAttr = typeof aParameters.attribute === "string"
michael@0 601 ? aParameters.attribute : aParameters.attribute.content;
michael@0 602 var idlAttr = typeof aParameters.attribute === "string"
michael@0 603 ? aParameters.attribute : aParameters.attribute.idl;
michael@0 604
michael@0 605 element[idlAttr] = "";
michael@0 606 is(element[idlAttr], document.URL, "Empty string should resolve to document URL");
michael@0 607 }

mercurial