reflect.js (28750B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 /** 5 * reflect.js is a collection of methods to test HTML attribute reflection. 6 * Each of attribute is reflected differently, depending on various parameters, 7 * see: 8 * http://www.whatwg.org/html/#reflecting-content-attributes-in-idl-attributes 9 * 10 * Do not forget to add these line at the beginning of each new reflect* method: 11 * ok(attr in element, attr + " should be an IDL attribute of this element"); 12 * is(typeof element[attr], <type>, attr + " IDL attribute should be a <type>"); 13 */ 14 15 /** 16 * Checks that a given attribute is correctly reflected as a string. 17 * 18 * @param aParameters Object object containing the parameters, which are: 19 * - element Element node to test 20 * - attribute String name of the attribute 21 * OR 22 * attribute Object object containing two attributes, 'content' and 'idl' 23 * - otherValues Array [optional] other values to test in addition of the default ones 24 * - extendedAttributes Object object which can have 'TreatNullAs': "EmptyString" 25 */ 26 function reflectString(aParameters) { 27 var element = aParameters.element; 28 var contentAttr = 29 typeof aParameters.attribute === "string" 30 ? aParameters.attribute 31 : aParameters.attribute.content; 32 var idlAttr = 33 typeof aParameters.attribute === "string" 34 ? aParameters.attribute 35 : aParameters.attribute.idl; 36 var otherValues = 37 aParameters.otherValues !== undefined ? aParameters.otherValues : []; 38 var treatNullAs = aParameters.extendedAttributes 39 ? aParameters.extendedAttributes.TreatNullAs 40 : null; 41 42 ok( 43 idlAttr in element, 44 idlAttr + " should be an IDL attribute of this element" 45 ); 46 is( 47 typeof element[idlAttr], 48 "string", 49 "'" + idlAttr + "' IDL attribute should be a string" 50 ); 51 52 // Tests when the attribute isn't set. 53 is( 54 element.getAttribute(contentAttr), 55 null, 56 "When not set, the content attribute should be null." 57 ); 58 is( 59 element[idlAttr], 60 "", 61 "When not set, the IDL attribute should return the empty string" 62 ); 63 64 /** 65 * TODO: as long as null stringification doesn't follow the WebIDL 66 * specifications, don't add it to the loop below and keep it here. 67 */ 68 element.setAttribute(contentAttr, null); 69 is( 70 element.getAttribute(contentAttr), 71 "null", 72 "null should have been stringified to 'null' for '" + contentAttr + "'" 73 ); 74 is( 75 element[idlAttr], 76 "null", 77 "null should have been stringified to 'null' for '" + idlAttr + "'" 78 ); 79 element.removeAttribute(contentAttr); 80 81 element[idlAttr] = null; 82 if (treatNullAs == "EmptyString") { 83 is( 84 element.getAttribute(contentAttr), 85 "", 86 "null should have been stringified to '' for '" + contentAttr + "'" 87 ); 88 is( 89 element[idlAttr], 90 "", 91 "null should have been stringified to '' for '" + idlAttr + "'" 92 ); 93 } else { 94 is( 95 element.getAttribute(contentAttr), 96 "null", 97 "null should have been stringified to 'null' for '" + contentAttr + "'" 98 ); 99 is( 100 element[idlAttr], 101 "null", 102 "null should have been stringified to 'null' for '" + contentAttr + "'" 103 ); 104 } 105 element.removeAttribute(contentAttr); 106 107 // Tests various strings. 108 var stringsToTest = [ 109 // [ test value, expected result ] 110 ["", ""], 111 ["null", "null"], 112 ["undefined", "undefined"], 113 ["foo", "foo"], 114 [contentAttr, contentAttr], 115 [idlAttr, idlAttr], 116 // TODO: uncomment this when null stringification will follow the specs. 117 // [ null, "null" ], 118 [undefined, "undefined"], 119 [true, "true"], 120 [false, "false"], 121 [42, "42"], 122 // ES5, verse 8.12.8. 123 [ 124 { 125 toString() { 126 return "foo"; 127 }, 128 }, 129 "foo", 130 ], 131 [ 132 { 133 valueOf() { 134 return "foo"; 135 }, 136 }, 137 "[object Object]", 138 ], 139 [ 140 { 141 valueOf() { 142 return "quux"; 143 }, 144 toString: undefined, 145 }, 146 "quux", 147 ], 148 [ 149 { 150 valueOf() { 151 return "foo"; 152 }, 153 toString() { 154 return "bar"; 155 }, 156 }, 157 "bar", 158 ], 159 ]; 160 161 otherValues.forEach(function (v) { 162 stringsToTest.push([v, v]); 163 }); 164 165 stringsToTest.forEach(function ([v, r]) { 166 element.setAttribute(contentAttr, v); 167 is( 168 element[idlAttr], 169 r, 170 "IDL attribute '" + 171 idlAttr + 172 "' should return the value it has been set to." 173 ); 174 is( 175 element.getAttribute(contentAttr), 176 r, 177 "Content attribute '" + 178 contentAttr + 179 "'should return the value it has been set to." 180 ); 181 element.removeAttribute(contentAttr); 182 183 element[idlAttr] = v; 184 is( 185 element[idlAttr], 186 r, 187 "IDL attribute '" + 188 idlAttr + 189 "' should return the value it has been set to." 190 ); 191 is( 192 element.getAttribute(contentAttr), 193 r, 194 "Content attribute '" + 195 contentAttr + 196 "' should return the value it has been set to." 197 ); 198 element.removeAttribute(contentAttr); 199 }); 200 201 // Tests after removeAttribute() is called. Should be equivalent with not set. 202 is( 203 element.getAttribute(contentAttr), 204 null, 205 "When not set, the content attribute should be null." 206 ); 207 is( 208 element[idlAttr], 209 "", 210 "When not set, the IDL attribute should return the empty string" 211 ); 212 } 213 214 /** 215 * Checks that a given attribute name for a given element is correctly reflected 216 * as an unsigned int. 217 * 218 * @param aParameters Object object containing the parameters, which are: 219 * - element Element node to test on 220 * - attribute String name of the attribute 221 * - nonZero Boolean whether the attribute should be non-null 222 * - defaultValue Integer [optional] default value, if different from the default one 223 */ 224 function reflectUnsignedInt(aParameters) { 225 var element = aParameters.element; 226 var attr = aParameters.attribute; 227 var nonZero = aParameters.nonZero; 228 var defaultValue = aParameters.defaultValue; 229 var fallback = aParameters.fallback; 230 231 if (defaultValue === undefined) { 232 if (nonZero) { 233 defaultValue = 1; 234 } else { 235 defaultValue = 0; 236 } 237 } 238 239 if (fallback === undefined) { 240 fallback = false; 241 } 242 243 ok(attr in element, attr + " should be an IDL attribute of this element"); 244 is( 245 typeof element[attr], 246 "number", 247 attr + " IDL attribute should be a number" 248 ); 249 250 // Check default value. 251 is(element[attr], defaultValue, "default value should be " + defaultValue); 252 ok(!element.hasAttribute(attr), attr + " shouldn't be present"); 253 254 var values = [1, 3, 42, 2147483647]; 255 256 for (var value of values) { 257 element[attr] = value; 258 is(element[attr], value, "." + attr + " should be equals " + value); 259 is( 260 element.getAttribute(attr), 261 String(value), 262 "@" + attr + " should be equals " + value 263 ); 264 265 element.setAttribute(attr, value); 266 is(element[attr], value, "." + attr + " should be equals " + value); 267 is( 268 element.getAttribute(attr), 269 String(value), 270 "@" + attr + " should be equals " + value 271 ); 272 } 273 274 // -3000000000 is equivalent to 1294967296 when using the IDL attribute. 275 element[attr] = -3000000000; 276 is(element[attr], 1294967296, "." + attr + " should be equals to 1294967296"); 277 is( 278 element.getAttribute(attr), 279 "1294967296", 280 "@" + attr + " should be equals to 1294967296" 281 ); 282 283 // When setting the content attribute, it's a string so it will be invalid. 284 element.setAttribute(attr, -3000000000); 285 is( 286 element.getAttribute(attr), 287 "-3000000000", 288 "@" + attr + " should be equals to " + -3000000000 289 ); 290 is( 291 element[attr], 292 defaultValue, 293 "." + attr + " should be equals to " + defaultValue 294 ); 295 296 // When interpreted as unsigned 32-bit integers, all of these fall between 297 // 2^31 and 2^32 - 1, so per spec they return the default value. 298 var nonValidValues = [-2147483648, -1, 3147483647]; 299 300 for (var value of nonValidValues) { 301 element[attr] = value; 302 is( 303 element.getAttribute(attr), 304 String(defaultValue), 305 "@" + attr + " should be equals to " + defaultValue 306 ); 307 is( 308 element[attr], 309 defaultValue, 310 "." + attr + " should be equals to " + defaultValue 311 ); 312 } 313 314 for (var values of nonValidValues) { 315 element.setAttribute(attr, values[0]); 316 is( 317 element.getAttribute(attr), 318 String(values[0]), 319 "@" + attr + " should be equals to " + values[0] 320 ); 321 is( 322 element[attr], 323 defaultValue, 324 "." + attr + " should be equals to " + defaultValue 325 ); 326 } 327 328 // Setting to 0 should throw an error if nonZero is true. 329 var caught = false; 330 try { 331 element[attr] = 0; 332 } catch (e) { 333 caught = true; 334 is(e.name, "IndexSizeError", "exception should be IndexSizeError"); 335 is( 336 e.code, 337 DOMException.INDEX_SIZE_ERR, 338 "exception code should be INDEX_SIZE_ERR" 339 ); 340 } 341 342 if (nonZero && !fallback) { 343 ok(caught, "an exception should have been caught"); 344 } else { 345 ok(!caught, "no exception should have been caught"); 346 } 347 348 // If 0 is set in @attr, it will be ignored when calling .attr. 349 element.setAttribute(attr, "0"); 350 is(element.getAttribute(attr), "0", "@" + attr + " should be equals to 0"); 351 if (nonZero) { 352 is( 353 element[attr], 354 defaultValue, 355 "." + attr + " should be equals to " + defaultValue 356 ); 357 } else { 358 is(element[attr], 0, "." + attr + " should be equals to 0"); 359 } 360 } 361 362 /** 363 * Checks that a given attribute is correctly reflected as limited to known 364 * values enumerated attribute. 365 * 366 * @param aParameters Object object containing the parameters, which are: 367 * - element Element node to test on 368 * - attribute String name of the attribute 369 * OR 370 * attribute Object object containing two attributes, 'content' and 'idl' 371 * - validValues Array valid values we support 372 * - invalidValues Array invalid values 373 * - defaultValue String [optional] default value when no valid value is set 374 * OR 375 * defaultValue Object [optional] object containing two attributes, 'invalid' and 'missing' 376 * - unsupportedValues Array [optional] valid values we do not support 377 * - nullable boolean [optional] whether the attribute is nullable 378 */ 379 function reflectLimitedEnumerated(aParameters) { 380 var element = aParameters.element; 381 var contentAttr = 382 typeof aParameters.attribute === "string" 383 ? aParameters.attribute 384 : aParameters.attribute.content; 385 var idlAttr = 386 typeof aParameters.attribute === "string" 387 ? aParameters.attribute 388 : aParameters.attribute.idl; 389 var validValues = aParameters.validValues; 390 var invalidValues = aParameters.invalidValues; 391 var defaultValueInvalid = 392 aParameters.defaultValue === undefined 393 ? "" 394 : typeof aParameters.defaultValue === "string" 395 ? aParameters.defaultValue 396 : aParameters.defaultValue.invalid; 397 var defaultValueMissing = 398 aParameters.defaultValue === undefined 399 ? "" 400 : typeof aParameters.defaultValue === "string" 401 ? aParameters.defaultValue 402 : aParameters.defaultValue.missing; 403 var unsupportedValues = 404 aParameters.unsupportedValues !== undefined 405 ? aParameters.unsupportedValues 406 : []; 407 var nullable = aParameters.nullable; 408 409 ok( 410 idlAttr in element, 411 idlAttr + " should be an IDL attribute of this element" 412 ); 413 if (nullable) { 414 // The missing value default is null, which is typeof == "object" 415 is( 416 typeof element[idlAttr], 417 "object", 418 "'" + 419 idlAttr + 420 "' IDL attribute should be null, which has typeof == object" 421 ); 422 is( 423 element[idlAttr], 424 null, 425 "'" + idlAttr + "' IDL attribute should be null" 426 ); 427 } else { 428 is( 429 typeof element[idlAttr], 430 "string", 431 "'" + idlAttr + "' IDL attribute should be a string" 432 ); 433 } 434 435 if (nullable) { 436 element.setAttribute(contentAttr, "something"); 437 // Now it will be a string 438 is( 439 typeof element[idlAttr], 440 "string", 441 "'" + idlAttr + "' IDL attribute should be a string" 442 ); 443 } 444 445 // Explicitly check the default value. 446 element.removeAttribute(contentAttr); 447 is( 448 element[idlAttr], 449 defaultValueMissing, 450 "When no attribute is set, the value should be the default value." 451 ); 452 453 // Check valid values. 454 validValues.forEach(function (v) { 455 element.setAttribute(contentAttr, v); 456 is( 457 element[idlAttr], 458 v, 459 "'" + v + "' should be accepted as a valid value for " + idlAttr 460 ); 461 is( 462 element.getAttribute(contentAttr), 463 v, 464 "Content attribute should return the value it has been set to." 465 ); 466 element.removeAttribute(contentAttr); 467 468 element.setAttribute(contentAttr, v.toUpperCase()); 469 is( 470 element[idlAttr], 471 v, 472 "Enumerated attributes should be case-insensitive." 473 ); 474 is( 475 element.getAttribute(contentAttr), 476 v.toUpperCase(), 477 "Content attribute should not be lower-cased." 478 ); 479 element.removeAttribute(contentAttr); 480 481 element[idlAttr] = v; 482 is( 483 element[idlAttr], 484 v, 485 "'" + v + "' should be accepted as a valid value for " + idlAttr 486 ); 487 is( 488 element.getAttribute(contentAttr), 489 v, 490 "Content attribute should return the value it has been set to." 491 ); 492 element.removeAttribute(contentAttr); 493 494 element[idlAttr] = v.toUpperCase(); 495 is( 496 element[idlAttr], 497 v, 498 "Enumerated attributes should be case-insensitive." 499 ); 500 is( 501 element.getAttribute(contentAttr), 502 v.toUpperCase(), 503 "Content attribute should not be lower-cased." 504 ); 505 element.removeAttribute(contentAttr); 506 }); 507 508 // Check invalid values. 509 invalidValues.forEach(function (v) { 510 element.setAttribute(contentAttr, v); 511 is( 512 element[idlAttr], 513 defaultValueInvalid, 514 "When the content attribute is set to an invalid value, the default value should be returned." 515 ); 516 is( 517 element.getAttribute(contentAttr), 518 v, 519 "Content attribute should not have been changed." 520 ); 521 element.removeAttribute(contentAttr); 522 523 element[idlAttr] = v; 524 is( 525 element[idlAttr], 526 defaultValueInvalid, 527 "When the value is set to an invalid value, the default value should be returned." 528 ); 529 is( 530 element.getAttribute(contentAttr), 531 v, 532 "Content attribute should not have been changed." 533 ); 534 element.removeAttribute(contentAttr); 535 }); 536 537 // Check valid values we currently do not support. 538 // Basically, it's like the checks for the valid values but with some todo's. 539 unsupportedValues.forEach(function (v) { 540 element.setAttribute(contentAttr, v); 541 todo_is( 542 element[idlAttr], 543 v, 544 "'" + v + "' should be accepted as a valid value for " + idlAttr 545 ); 546 is( 547 element.getAttribute(contentAttr), 548 v, 549 "Content attribute should return the value it has been set to." 550 ); 551 element.removeAttribute(contentAttr); 552 553 element.setAttribute(contentAttr, v.toUpperCase()); 554 todo_is( 555 element[idlAttr], 556 v, 557 "Enumerated attributes should be case-insensitive." 558 ); 559 is( 560 element.getAttribute(contentAttr), 561 v.toUpperCase(), 562 "Content attribute should not be lower-cased." 563 ); 564 element.removeAttribute(contentAttr); 565 566 element[idlAttr] = v; 567 todo_is( 568 element[idlAttr], 569 v, 570 "'" + v + "' should be accepted as a valid value for " + idlAttr 571 ); 572 is( 573 element.getAttribute(contentAttr), 574 v, 575 "Content attribute should return the value it has been set to." 576 ); 577 element.removeAttribute(contentAttr); 578 579 element[idlAttr] = v.toUpperCase(); 580 todo_is( 581 element[idlAttr], 582 v, 583 "Enumerated attributes should be case-insensitive." 584 ); 585 is( 586 element.getAttribute(contentAttr), 587 v.toUpperCase(), 588 "Content attribute should not be lower-cased." 589 ); 590 element.removeAttribute(contentAttr); 591 }); 592 593 if (nullable) { 594 is( 595 defaultValueMissing, 596 null, 597 "Missing default value should be null for nullable attributes" 598 ); 599 ok(validValues.length, "We better have at least one valid value"); 600 element.setAttribute(contentAttr, validValues[0]); 601 ok( 602 element.hasAttribute(contentAttr), 603 "Should have content attribute: we just set it" 604 ); 605 element[idlAttr] = null; 606 ok( 607 !element.hasAttribute(contentAttr), 608 "Should have removed content attribute" 609 ); 610 } 611 } 612 613 /** 614 * Checks that a given attribute is correctly reflected as a boolean. 615 * 616 * @param aParameters Object object containing the parameters, which are: 617 * - element Element node to test on 618 * - attribute String name of the attribute 619 * OR 620 * attribute Object object containing two attributes, 'content' and 'idl' 621 */ 622 function reflectBoolean(aParameters) { 623 var element = aParameters.element; 624 var contentAttr = 625 typeof aParameters.attribute === "string" 626 ? aParameters.attribute 627 : aParameters.attribute.content; 628 var idlAttr = 629 typeof aParameters.attribute === "string" 630 ? aParameters.attribute 631 : aParameters.attribute.idl; 632 633 ok( 634 idlAttr in element, 635 idlAttr + " should be an IDL attribute of this element" 636 ); 637 is( 638 typeof element[idlAttr], 639 "boolean", 640 idlAttr + " IDL attribute should be a boolean" 641 ); 642 643 // Tests when the attribute isn't set. 644 is( 645 element.getAttribute(contentAttr), 646 null, 647 "When not set, the content attribute should be null." 648 ); 649 is( 650 element[idlAttr], 651 false, 652 "When not set, the IDL attribute should return false" 653 ); 654 655 /** 656 * Test various values. 657 * Each value to test is actually an object containing a 'value' property 658 * containing the value to actually test, a 'stringified' property containing 659 * the stringified value and a 'result' property containing the expected 660 * result when the value is set to the IDL attribute. 661 */ 662 var valuesToTest = [ 663 { value: true, stringified: "true", result: true }, 664 { value: false, stringified: "false", result: false }, 665 { value: "true", stringified: "true", result: true }, 666 { value: "false", stringified: "false", result: true }, 667 { value: "foo", stringified: "foo", result: true }, 668 { value: idlAttr, stringified: idlAttr, result: true }, 669 { value: contentAttr, stringified: contentAttr, result: true }, 670 { value: "null", stringified: "null", result: true }, 671 { value: "undefined", stringified: "undefined", result: true }, 672 { value: "", stringified: "", result: false }, 673 { value: undefined, stringified: "undefined", result: false }, 674 { value: null, stringified: "null", result: false }, 675 { value: +0, stringified: "0", result: false }, 676 { value: -0, stringified: "0", result: false }, 677 { value: NaN, stringified: "NaN", result: false }, 678 { value: 42, stringified: "42", result: true }, 679 { value: Infinity, stringified: "Infinity", result: true }, 680 { value: -Infinity, stringified: "-Infinity", result: true }, 681 // ES5, verse 9.2. 682 { 683 value: { 684 toString() { 685 return "foo"; 686 }, 687 }, 688 stringified: "foo", 689 result: true, 690 }, 691 { 692 value: { 693 valueOf() { 694 return "foo"; 695 }, 696 }, 697 stringified: "[object Object]", 698 result: true, 699 }, 700 { 701 value: { 702 valueOf() { 703 return "quux"; 704 }, 705 toString: undefined, 706 }, 707 stringified: "quux", 708 result: true, 709 }, 710 { 711 value: { 712 valueOf() { 713 return "foo"; 714 }, 715 toString() { 716 return "bar"; 717 }, 718 }, 719 stringified: "bar", 720 result: true, 721 }, 722 { 723 value: { 724 valueOf() { 725 return false; 726 }, 727 }, 728 stringified: "[object Object]", 729 result: true, 730 }, 731 { 732 value: { foo: false, bar: false }, 733 stringified: "[object Object]", 734 result: true, 735 }, 736 { value: {}, stringified: "[object Object]", result: true }, 737 ]; 738 739 valuesToTest.forEach(function (v) { 740 element.setAttribute(contentAttr, v.value); 741 is( 742 element[idlAttr], 743 true, 744 "IDL attribute should return always return 'true' if the content attribute has been set" 745 ); 746 is( 747 element.getAttribute(contentAttr), 748 v.stringified, 749 "Content attribute should return the stringified value it has been set to." 750 ); 751 element.removeAttribute(contentAttr); 752 753 element[idlAttr] = v.value; 754 is(element[idlAttr], v.result, "IDL attribute should return " + v.result); 755 is( 756 element.getAttribute(contentAttr), 757 v.result ? "" : null, 758 v.result 759 ? "Content attribute should return the empty string." 760 : "Content attribute should return null." 761 ); 762 is( 763 element.hasAttribute(contentAttr), 764 v.result, 765 v.result 766 ? contentAttr + " should not be present" 767 : contentAttr + " should be present" 768 ); 769 element.removeAttribute(contentAttr); 770 }); 771 772 // Tests after removeAttribute() is called. Should be equivalent with not set. 773 is( 774 element.getAttribute(contentAttr), 775 null, 776 "When not set, the content attribute should be null." 777 ); 778 is( 779 element[contentAttr], 780 false, 781 "When not set, the IDL attribute should return false" 782 ); 783 } 784 785 /** 786 * Checks that a given attribute name for a given element is correctly reflected 787 * as an signed integer. 788 * 789 * @param aParameters Object object containing the parameters, which are: 790 * - element Element node to test on 791 * - attribute String name of the attribute 792 * - nonNegative Boolean true if the attribute is limited to 'non-negative numbers', false otherwise 793 * - defaultValue Integer [optional] default value, if one exists 794 */ 795 function reflectInt(aParameters) { 796 // Expected value returned by .getAttribute() when |value| has been previously passed to .setAttribute(). 797 function expectedGetAttributeResult(value) { 798 return String(value); 799 } 800 801 function stringToInteger(value, nonNegative, defaultValue) { 802 // Parse: Ignore leading whitespace, find [+/-][numbers] 803 var result = /^[ \t\n\f\r]*([\+\-]?[0-9]+)/.exec(value); 804 if (result) { 805 var resultInt = parseInt(result[1], 10); 806 if ( 807 (nonNegative ? 0 : -0x80000000) <= resultInt && 808 resultInt <= 0x7fffffff 809 ) { 810 // If the value is within allowed value range for signed/unsigned 811 // integer, return it -- but add 0 to it to convert a possible -0 into 812 // +0, the only zero present in the signed integer range. 813 return resultInt + 0; 814 } 815 } 816 return defaultValue; 817 } 818 819 // Expected value returned by .getAttribute(attr) or .attr if |value| has been set via the IDL attribute. 820 function expectedIdlAttributeResult(value) { 821 // This returns the result of calling the ES ToInt32 algorithm on value. 822 return value << 0; 823 } 824 825 var element = aParameters.element; 826 var attr = aParameters.attribute; 827 var nonNegative = aParameters.nonNegative; 828 829 var defaultValue = 830 aParameters.defaultValue !== undefined 831 ? aParameters.defaultValue 832 : nonNegative 833 ? -1 834 : 0; 835 836 ok(attr in element, attr + " should be an IDL attribute of this element"); 837 is( 838 typeof element[attr], 839 "number", 840 attr + " IDL attribute should be a number" 841 ); 842 843 // Check default value. 844 is(element[attr], defaultValue, "default value should be " + defaultValue); 845 ok(!element.hasAttribute(attr), attr + " shouldn't be present"); 846 847 /** 848 * Test various values. 849 * value: The test value that will be set using both setAttribute(value) and 850 * element[attr] = value 851 */ 852 var valuesToTest = [ 853 // Test numeric inputs up to max signed integer 854 0, 855 1, 856 55555, 857 2147483647, 858 +42, 859 // Test string inputs up to max signed integer 860 "0", 861 "1", 862 "777777", 863 "2147483647", 864 "+42", 865 // Test negative numeric inputs up to min signed integer 866 -0, 867 -1, 868 -3333, 869 -2147483648, 870 // Test negative string inputs up to min signed integer 871 "-0", 872 "-1", 873 "-222", 874 "-2147483647", 875 "-2147483648", 876 // Test numeric inputs that are outside legal 32 bit signed values 877 -2147483649, 878 -3000000000, 879 -4294967296, 880 2147483649, 881 4000000000, 882 -4294967297, 883 // Test string inputs with extra padding 884 " 1111111", 885 " 23456 ", 886 // Test non-numeric string inputs 887 "", 888 " ", 889 "+", 890 "-", 891 "foo", 892 "+foo", 893 "-foo", 894 "+ foo", 895 "- foo", 896 "+-2", 897 "-+2", 898 "++2", 899 "--2", 900 "hello1234", 901 "1234hello", 902 "444 world 555", 903 "why 567 what", 904 "-3 nots", 905 "2e5", 906 "300e2", 907 "42+-$", 908 "+42foo", 909 "-514not", 910 "\vblah", 911 "0x10FFFF", 912 "-0xABCDEF", 913 // Test decimal numbers 914 1.2345, 915 42.0, 916 3456789.1, 917 -2.3456, 918 -6789.12345, 919 -2147483649.1234, 920 // Test decimal strings 921 "1.2345", 922 "42.0", 923 "3456789.1", 924 "-2.3456", 925 "-6789.12345", 926 "-2147483649.1234", 927 // Test special values 928 undefined, 929 null, 930 NaN, 931 Infinity, 932 -Infinity, 933 ]; 934 935 valuesToTest.forEach(function (v) { 936 var intValue = stringToInteger(v, nonNegative, defaultValue); 937 938 element.setAttribute(attr, v); 939 940 is( 941 element.getAttribute(attr), 942 expectedGetAttributeResult(v), 943 element.localName + 944 ".setAttribute(" + 945 attr + 946 ", " + 947 v + 948 "), " + 949 element.localName + 950 ".getAttribute(" + 951 attr + 952 ") " 953 ); 954 955 is( 956 element[attr], 957 intValue, 958 element.localName + 959 ".setAttribute(" + 960 attr + 961 ", " + 962 v + 963 "), " + 964 element.localName + 965 "[" + 966 attr + 967 "] " 968 ); 969 element.removeAttribute(attr); 970 971 if (nonNegative && expectedIdlAttributeResult(v) < 0) { 972 try { 973 element[attr] = v; 974 ok( 975 false, 976 element.localName + 977 "[" + 978 attr + 979 "] = " + 980 v + 981 " should throw IndexSizeError" 982 ); 983 } catch (e) { 984 is( 985 e.name, 986 "IndexSizeError", 987 element.localName + 988 "[" + 989 attr + 990 "] = " + 991 v + 992 " should throw IndexSizeError" 993 ); 994 is( 995 e.code, 996 DOMException.INDEX_SIZE_ERR, 997 element.localName + 998 "[" + 999 attr + 1000 "] = " + 1001 v + 1002 " should throw INDEX_SIZE_ERR" 1003 ); 1004 } 1005 } else { 1006 element[attr] = v; 1007 is( 1008 element[attr], 1009 expectedIdlAttributeResult(v), 1010 element.localName + 1011 "[" + 1012 attr + 1013 "] = " + 1014 v + 1015 ", " + 1016 element.localName + 1017 "[" + 1018 attr + 1019 "] " 1020 ); 1021 is( 1022 element.getAttribute(attr), 1023 String(expectedIdlAttributeResult(v)), 1024 element.localName + 1025 "[" + 1026 attr + 1027 "] = " + 1028 v + 1029 ", " + 1030 element.localName + 1031 ".getAttribute(" + 1032 attr + 1033 ") " 1034 ); 1035 } 1036 element.removeAttribute(attr); 1037 }); 1038 1039 // Tests after removeAttribute() is called. Should be equivalent with not set. 1040 is( 1041 element.getAttribute(attr), 1042 null, 1043 "When not set, the content attribute should be null." 1044 ); 1045 is( 1046 element[attr], 1047 defaultValue, 1048 "When not set, the IDL attribute should return default value." 1049 ); 1050 } 1051 1052 /** 1053 * Checks that a given attribute is correctly reflected as a url. 1054 * 1055 * @param aParameters Object object containing the parameters, which are: 1056 * - element Element node to test 1057 * - attribute String name of the attribute 1058 * OR 1059 * attribute Object object containing two attributes, 'content' and 'idl' 1060 */ 1061 function reflectURL(aParameters) { 1062 var element = aParameters.element; 1063 var contentAttr = 1064 typeof aParameters.attribute === "string" 1065 ? aParameters.attribute 1066 : aParameters.attribute.content; 1067 var idlAttr = 1068 typeof aParameters.attribute === "string" 1069 ? aParameters.attribute 1070 : aParameters.attribute.idl; 1071 1072 element[idlAttr] = ""; 1073 is( 1074 element[idlAttr], 1075 document.URL, 1076 "Empty string should resolve to document URL" 1077 ); 1078 }