1 // Copyright 2010 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 // Tests the object.defineProperty method - ES 15.2.3.6 29 30 // Flags: --allow-natives-syntax 31 32 // Check that an exception is thrown when null is passed as object. 33 try { 34 Object.defineProperty(null, null, null); 35 assertTrue(false); 36 } catch (e) { 37 assertTrue(/called on non-object/.test(e)); 38 } 39 40 // Check that an exception is thrown when undefined is passed as object. 41 try { 42 Object.defineProperty(undefined, undefined, undefined); 43 assertTrue(false); 44 } catch (e) { 45 assertTrue(/called on non-object/.test(e)); 46 } 47 48 // Check that an exception is thrown when non-object is passed as object. 49 try { 50 Object.defineProperty(0, "foo", undefined); 51 assertTrue(false); 52 } catch (e) { 53 assertTrue(/called on non-object/.test(e)); 54 } 55 56 // Object. 57 var obj1 = {}; 58 59 // Values. 60 var val1 = 0; 61 var val2 = 0; 62 var val3 = 0; 63 64 function setter1() {val1++; } 65 function getter1() {return val1; } 66 67 function setter2() {val2++; } 68 function getter2() {return val2; } 69 70 function setter3() {val3++; } 71 function getter3() {return val3; } 72 73 74 // Descriptors. 75 var emptyDesc = {}; 76 77 var accessorConfigurable = { 78 set: setter1, 79 get: getter1, 80 configurable: true 81 }; 82 83 var accessorNoConfigurable = { 84 set: setter2, 85 get: getter2, 86 configurable: false 87 }; 88 89 var accessorOnlySet = { 90 set: setter3, 91 configurable: true 92 }; 93 94 var accessorOnlyGet = { 95 get: getter3, 96 configurable: true 97 }; 98 99 var accessorDefault = {set: function(){} }; 100 101 var dataConfigurable = { value: 1000, configurable: true }; 102 103 var dataNoConfigurable = { value: 2000, configurable: false }; 104 105 var dataWritable = { value: 3000, writable: true}; 106 107 108 // Check that we can't add property with undefined attributes. 109 try { 110 Object.defineProperty(obj1, "foo", undefined); 111 assertTrue(false); 112 } catch (e) { 113 assertTrue(/must be an object/.test(e)); 114 } 115 116 // Make sure that we can add a property with an empty descriptor and 117 // that it has the default descriptor values. 118 Object.defineProperty(obj1, "foo", emptyDesc); 119 120 // foo should be undefined as it has no get, set or value 121 assertEquals(undefined, obj1.foo); 122 123 // We should, however, be able to retrieve the propertydescriptor which should 124 // have all default values (according to 8.6.1). 125 var desc = Object.getOwnPropertyDescriptor(obj1, "foo"); 126 assertFalse(desc.configurable); 127 assertFalse(desc.enumerable); 128 assertFalse(desc.writable); 129 assertEquals(desc.get, undefined); 130 assertEquals(desc.set, undefined); 131 assertEquals(desc.value, undefined); 132 133 // Make sure that getOwnPropertyDescriptor does not return a descriptor 134 // with default values if called with non existing property (otherwise 135 // the test above is invalid). 136 desc = Object.getOwnPropertyDescriptor(obj1, "bar"); 137 assertEquals(desc, undefined); 138 139 // Make sure that foo can't be reset (as configurable is false). 140 try { 141 Object.defineProperty(obj1, "foo", accessorConfigurable); 142 } catch (e) { 143 assertTrue(/Cannot redefine property/.test(e)); 144 } 145 146 147 // Accessor properties 148 149 Object.defineProperty(obj1, "bar", accessorConfigurable); 150 desc = Object.getOwnPropertyDescriptor(obj1, "bar"); 151 assertTrue(desc.configurable); 152 assertFalse(desc.enumerable); 153 assertEquals(desc.writable, undefined); 154 assertEquals(desc.get, accessorConfigurable.get); 155 assertEquals(desc.set, accessorConfigurable.set); 156 assertEquals(desc.value, undefined); 157 assertEquals(1, obj1.bar = 1); 158 assertEquals(1, val1); 159 assertEquals(1, obj1.bar = 1); 160 assertEquals(2, val1); 161 assertEquals(2, obj1.bar); 162 163 // Redefine bar with non configurable test 164 Object.defineProperty(obj1, "bar", accessorNoConfigurable); 165 desc = Object.getOwnPropertyDescriptor(obj1, "bar"); 166 assertFalse(desc.configurable); 167 assertFalse(desc.enumerable); 168 assertEquals(desc.writable, undefined); 169 assertEquals(desc.get, accessorNoConfigurable.get); 170 assertEquals(desc.set, accessorNoConfigurable.set); 171 assertEquals(desc.value, undefined); 172 assertEquals(1, obj1.bar = 1); 173 assertEquals(2, val1); 174 assertEquals(1, val2); 175 assertEquals(1, obj1.bar = 1) 176 assertEquals(2, val1); 177 assertEquals(2, val2); 178 assertEquals(2, obj1.bar); 179 180 // Try to redefine bar again - should fail as configurable is false. 181 try { 182 Object.defineProperty(obj1, "bar", accessorConfigurable); 183 assertTrue(false); 184 } catch(e) { 185 assertTrue(/Cannot redefine property/.test(e)); 186 } 187 188 // Try to redefine bar again using the data descriptor - should fail. 189 try { 190 Object.defineProperty(obj1, "bar", dataConfigurable); 191 assertTrue(false); 192 } catch(e) { 193 assertTrue(/Cannot redefine property/.test(e)); 194 } 195 196 // Redefine using same descriptor - should succeed. 197 Object.defineProperty(obj1, "bar", accessorNoConfigurable); 198 desc = Object.getOwnPropertyDescriptor(obj1, "bar"); 199 assertFalse(desc.configurable); 200 assertFalse(desc.enumerable); 201 assertEquals(desc.writable, undefined); 202 assertEquals(desc.get, accessorNoConfigurable.get); 203 assertEquals(desc.set, accessorNoConfigurable.set); 204 assertEquals(desc.value, undefined); 205 assertEquals(1, obj1.bar = 1); 206 assertEquals(2, val1); 207 assertEquals(3, val2); 208 assertEquals(1, obj1.bar = 1) 209 assertEquals(2, val1); 210 assertEquals(4, val2); 211 assertEquals(4, obj1.bar); 212 213 // Define an accessor that has only a setter. 214 Object.defineProperty(obj1, "setOnly", accessorOnlySet); 215 desc = Object.getOwnPropertyDescriptor(obj1, "setOnly"); 216 assertTrue(desc.configurable); 217 assertFalse(desc.enumerable); 218 assertEquals(desc.set, accessorOnlySet.set); 219 assertEquals(desc.writable, undefined); 220 assertEquals(desc.value, undefined); 221 assertEquals(desc.get, undefined); 222 assertEquals(1, obj1.setOnly = 1); 223 assertEquals(1, val3); 224 225 // Add a getter - should not touch the setter. 226 Object.defineProperty(obj1, "setOnly", accessorOnlyGet); 227 desc = Object.getOwnPropertyDescriptor(obj1, "setOnly"); 228 assertTrue(desc.configurable); 229 assertFalse(desc.enumerable); 230 assertEquals(desc.get, accessorOnlyGet.get); 231 assertEquals(desc.set, accessorOnlySet.set); 232 assertEquals(desc.writable, undefined); 233 assertEquals(desc.value, undefined); 234 assertEquals(1, obj1.setOnly = 1); 235 assertEquals(2, val3); 236 237 // The above should also work if redefining just a getter or setter on 238 // an existing property with both a getter and a setter. 239 Object.defineProperty(obj1, "both", accessorConfigurable); 240 241 Object.defineProperty(obj1, "both", accessorOnlySet); 242 desc = Object.getOwnPropertyDescriptor(obj1, "both"); 243 assertTrue(desc.configurable); 244 assertFalse(desc.enumerable); 245 assertEquals(desc.set, accessorOnlySet.set); 246 assertEquals(desc.get, accessorConfigurable.get); 247 assertEquals(desc.writable, undefined); 248 assertEquals(desc.value, undefined); 249 assertEquals(1, obj1.both = 1); 250 assertEquals(3, val3); 251 252 253 // Data properties 254 255 Object.defineProperty(obj1, "foobar", dataConfigurable); 256 desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); 257 assertEquals(obj1.foobar, 1000); 258 assertEquals(desc.value, 1000); 259 assertTrue(desc.configurable); 260 assertFalse(desc.writable); 261 assertFalse(desc.enumerable); 262 assertEquals(desc.get, undefined); 263 assertEquals(desc.set, undefined); 264 //Try writing to non writable attribute - should remain 1000 265 obj1.foobar = 1001; 266 assertEquals(obj1.foobar, 1000); 267 268 269 // Redefine to writable descriptor - now writing to foobar should be allowed. 270 Object.defineProperty(obj1, "foobar", dataWritable); 271 desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); 272 assertEquals(obj1.foobar, 3000); 273 assertEquals(desc.value, 3000); 274 // Note that since dataWritable does not define configurable the configurable 275 // setting from the redefined property (in this case true) is used. 276 assertTrue(desc.configurable); 277 assertTrue(desc.writable); 278 assertFalse(desc.enumerable); 279 assertEquals(desc.get, undefined); 280 assertEquals(desc.set, undefined); 281 // Writing to the property should now be allowed 282 obj1.foobar = 1001; 283 assertEquals(obj1.foobar, 1001); 284 285 286 // Redefine with non configurable data property. 287 Object.defineProperty(obj1, "foobar", dataNoConfigurable); 288 desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); 289 assertEquals(obj1.foobar, 2000); 290 assertEquals(desc.value, 2000); 291 assertFalse(desc.configurable); 292 assertTrue(desc.writable); 293 assertFalse(desc.enumerable); 294 assertEquals(desc.get, undefined); 295 assertEquals(desc.set, undefined); 296 297 // Try redefine again - shold fail because configurable is now false. 298 try { 299 Object.defineProperty(obj1, "foobar", dataConfigurable); 300 assertTrue(false); 301 } catch (e) { 302 assertTrue(/Cannot redefine property/.test(e)); 303 } 304 305 // Try redefine again with accessor property - shold also fail. 306 try { 307 Object.defineProperty(obj1, "foobar", dataConfigurable); 308 assertTrue(false); 309 } catch (e) { 310 assertTrue(/Cannot redefine property/.test(e)); 311 } 312 313 314 // Redifine with the same descriptor - should succeed (step 6). 315 Object.defineProperty(obj1, "foobar", dataNoConfigurable); 316 desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); 317 assertEquals(obj1.foobar, 2000); 318 assertEquals(desc.value, 2000); 319 assertFalse(desc.configurable); 320 assertTrue(desc.writable); 321 assertFalse(desc.enumerable); 322 assertEquals(desc.get, undefined); 323 assertEquals(desc.set, undefined); 324 325 326 // New object 327 var obj2 = {}; 328 329 // Make accessor - redefine to data 330 Object.defineProperty(obj2, "foo", accessorConfigurable); 331 332 // Redefine to data property 333 Object.defineProperty(obj2, "foo", dataConfigurable); 334 desc = Object.getOwnPropertyDescriptor(obj2, "foo"); 335 assertEquals(obj2.foo, 1000); 336 assertEquals(desc.value, 1000); 337 assertTrue(desc.configurable); 338 assertFalse(desc.writable); 339 assertFalse(desc.enumerable); 340 assertEquals(desc.get, undefined); 341 assertEquals(desc.set, undefined); 342 343 344 // Redefine back to accessor 345 Object.defineProperty(obj2, "foo", accessorConfigurable); 346 desc = Object.getOwnPropertyDescriptor(obj2, "foo"); 347 assertTrue(desc.configurable); 348 assertFalse(desc.enumerable); 349 assertEquals(desc.writable, undefined); 350 assertEquals(desc.get, accessorConfigurable.get); 351 assertEquals(desc.set, accessorConfigurable.set); 352 assertEquals(desc.value, undefined); 353 assertEquals(1, obj2.foo = 1); 354 assertEquals(3, val1); 355 assertEquals(4, val2); 356 assertEquals(3, obj2.foo); 357 358 // Make data - redefine to accessor 359 Object.defineProperty(obj2, "bar", dataConfigurable) 360 361 // Redefine to accessor property 362 Object.defineProperty(obj2, "bar", accessorConfigurable); 363 desc = Object.getOwnPropertyDescriptor(obj2, "bar"); 364 assertTrue(desc.configurable); 365 assertFalse(desc.enumerable); 366 assertEquals(desc.writable, undefined); 367 assertEquals(desc.get, accessorConfigurable.get); 368 assertEquals(desc.set, accessorConfigurable.set); 369 assertEquals(desc.value, undefined); 370 assertEquals(1, obj2.bar = 1); 371 assertEquals(4, val1); 372 assertEquals(4, val2); 373 assertEquals(4, obj2.foo); 374 375 // Redefine back to data property 376 Object.defineProperty(obj2, "bar", dataConfigurable); 377 desc = Object.getOwnPropertyDescriptor(obj2, "bar"); 378 assertEquals(obj2.bar, 1000); 379 assertEquals(desc.value, 1000); 380 assertTrue(desc.configurable); 381 assertFalse(desc.writable); 382 assertFalse(desc.enumerable); 383 assertEquals(desc.get, undefined); 384 assertEquals(desc.set, undefined); 385 386 387 // Redefinition of an accessor defined using __defineGetter__ and 388 // __defineSetter__. 389 function get(){return this.x} 390 function set(x){this.x=x}; 391 392 var obj3 = {x:1000}; 393 obj3.__defineGetter__("foo", get); 394 obj3.__defineSetter__("foo", set); 395 396 desc = Object.getOwnPropertyDescriptor(obj3, "foo"); 397 assertTrue(desc.configurable); 398 assertTrue(desc.enumerable); 399 assertEquals(desc.writable, undefined); 400 assertEquals(desc.get, get); 401 assertEquals(desc.set, set); 402 assertEquals(desc.value, undefined); 403 assertEquals(1, obj3.foo = 1); 404 assertEquals(1, obj3.x); 405 assertEquals(1, obj3.foo); 406 407 // Redefine to accessor property (non configurable) - note that enumerable 408 // which we do not redefine should remain the same (true). 409 Object.defineProperty(obj3, "foo", accessorNoConfigurable); 410 desc = Object.getOwnPropertyDescriptor(obj3, "foo"); 411 assertFalse(desc.configurable); 412 assertTrue(desc.enumerable); 413 assertEquals(desc.writable, undefined); 414 assertEquals(desc.get, accessorNoConfigurable.get); 415 assertEquals(desc.set, accessorNoConfigurable.set); 416 assertEquals(desc.value, undefined); 417 assertEquals(1, obj3.foo = 1); 418 assertEquals(5, val2); 419 assertEquals(5, obj3.foo); 420 421 422 obj3.__defineGetter__("bar", get); 423 obj3.__defineSetter__("bar", set); 424 425 426 // Redefine back to data property 427 Object.defineProperty(obj3, "bar", dataConfigurable); 428 desc = Object.getOwnPropertyDescriptor(obj3, "bar"); 429 assertEquals(obj3.bar, 1000); 430 assertEquals(desc.value, 1000); 431 assertTrue(desc.configurable); 432 assertFalse(desc.writable); 433 assertTrue(desc.enumerable); 434 assertEquals(desc.get, undefined); 435 assertEquals(desc.set, undefined); 436 437 438 var obj4 = {}; 439 var func = function (){return 42;}; 440 obj4.bar = func; 441 assertEquals(42, obj4.bar()); 442 443 Object.defineProperty(obj4, "bar", accessorConfigurable); 444 desc = Object.getOwnPropertyDescriptor(obj4, "bar"); 445 assertTrue(desc.configurable); 446 assertTrue(desc.enumerable); 447 assertEquals(desc.writable, undefined); 448 assertEquals(desc.get, accessorConfigurable.get); 449 assertEquals(desc.set, accessorConfigurable.set); 450 assertEquals(desc.value, undefined); 451 assertEquals(1, obj4.bar = 1); 452 assertEquals(5, val1); 453 assertEquals(5, obj4.bar); 454 455 // Make sure an error is thrown when trying to access to redefined function. 456 try { 457 obj4.bar(); 458 assertTrue(false); 459 } catch (e) { 460 assertTrue(/is not a function/.test(e)); 461 } 462 463 464 // Test runtime calls to DefineOrRedefineDataProperty and 465 // DefineOrRedefineAccessorProperty - make sure we don't 466 // crash. 467 try { 468 %DefineOrRedefineAccessorProperty(0, 0, 0, 0, 0); 469 } catch (e) { 470 assertTrue(/illegal access/.test(e)); 471 } 472 473 try { 474 %DefineOrRedefineDataProperty(0, 0, 0, 0); 475 } catch (e) { 476 assertTrue(/illegal access/.test(e)); 477 } 478 479 try { 480 %DefineOrRedefineDataProperty(null, null, null, null); 481 } catch (e) { 482 assertTrue(/illegal access/.test(e)); 483 } 484 485 try { 486 %DefineOrRedefineAccessorProperty(null, null, null, null, null); 487 } catch (e) { 488 assertTrue(/illegal access/.test(e)); 489 } 490 491 try { 492 %DefineOrRedefineDataProperty({}, null, null, null); 493 } catch (e) { 494 assertTrue(/illegal access/.test(e)); 495 } 496 497 // Defining properties null should fail even when we have 498 // other allowed values 499 try { 500 %DefineOrRedefineAccessorProperty(null, 'foo', 0, func, 0); 501 } catch (e) { 502 assertTrue(/illegal access/.test(e)); 503 } 504 505 try { 506 %DefineOrRedefineDataProperty(null, 'foo', 0, 0); 507 } catch (e) { 508 assertTrue(/illegal access/.test(e)); 509 } 510 511 // Test that all possible differences in step 6 in DefineOwnProperty are 512 // exercised, i.e., any difference in the given property descriptor and the 513 // existing properties should not return true, but throw an error if the 514 // existing configurable property is false. 515 516 var obj5 = {}; 517 // Enumerable will default to false. 518 Object.defineProperty(obj5, 'foo', accessorNoConfigurable); 519 desc = Object.getOwnPropertyDescriptor(obj5, 'foo'); 520 // First, test that we are actually allowed to set the accessor if all 521 // values are of the descriptor are the same as the existing one. 522 Object.defineProperty(obj5, 'foo', accessorNoConfigurable); 523 524 // Different setter. 525 var descDifferent = { 526 configurable:false, 527 enumerable:false, 528 set: setter1, 529 get: getter2 530 }; 531 532 try { 533 Object.defineProperty(obj5, 'foo', descDifferent); 534 assertTrue(false); 535 } catch (e) { 536 assertTrue(/Cannot redefine property/.test(e)); 537 } 538 539 // Different getter. 540 descDifferent = { 541 configurable:false, 542 enumerable:false, 543 set: setter2, 544 get: getter1 545 }; 546 547 try { 548 Object.defineProperty(obj5, 'foo', descDifferent); 549 assertTrue(false); 550 } catch (e) { 551 assertTrue(/Cannot redefine property/.test(e)); 552 } 553 554 // Different enumerable. 555 descDifferent = { 556 configurable:false, 557 enumerable:true, 558 set: setter2, 559 get: getter2 560 }; 561 562 try { 563 Object.defineProperty(obj5, 'foo', descDifferent); 564 assertTrue(false); 565 } catch (e) { 566 assertTrue(/Cannot redefine property/.test(e)); 567 } 568 569 // Different configurable. 570 descDifferent = { 571 configurable:false, 572 enumerable:true, 573 set: setter2, 574 get: getter2 575 }; 576 577 try { 578 Object.defineProperty(obj5, 'foo', descDifferent); 579 assertTrue(false); 580 } catch (e) { 581 assertTrue(/Cannot redefine property/.test(e)); 582 } 583 584 // No difference. 585 descDifferent = { 586 configurable:false, 587 enumerable:false, 588 set: setter2, 589 get: getter2 590 }; 591 // Make sure we can still redefine if all properties are the same. 592 Object.defineProperty(obj5, 'foo', descDifferent); 593 594 // Make sure that obj5 still holds the original values. 595 desc = Object.getOwnPropertyDescriptor(obj5, 'foo'); 596 assertEquals(desc.get, getter2); 597 assertEquals(desc.set, setter2); 598 assertFalse(desc.enumerable); 599 assertFalse(desc.configurable); 600 601 602 // Also exercise step 6 on data property, writable and enumerable 603 // defaults to false. 604 Object.defineProperty(obj5, 'bar', dataNoConfigurable); 605 606 // Test that redefinition with the same property descriptor is possible 607 Object.defineProperty(obj5, 'bar', dataNoConfigurable); 608 609 // Different value. 610 descDifferent = { 611 configurable:false, 612 enumerable:false, 613 writable: false, 614 value: 1999 615 }; 616 617 try { 618 Object.defineProperty(obj5, 'bar', descDifferent); 619 assertTrue(false); 620 } catch (e) { 621 assertTrue(/Cannot redefine property/.test(e)); 622 } 623 624 // Different writable. 625 descDifferent = { 626 configurable:false, 627 enumerable:false, 628 writable: true, 629 value: 2000 630 }; 631 632 try { 633 Object.defineProperty(obj5, 'bar', descDifferent); 634 assertTrue(false); 635 } catch (e) { 636 assertTrue(/Cannot redefine property/.test(e)); 637 } 638 639 640 // Different enumerable. 641 descDifferent = { 642 configurable:false, 643 enumerable:true , 644 writable:false, 645 value: 2000 646 }; 647 648 try { 649 Object.defineProperty(obj5, 'bar', descDifferent); 650 assertTrue(false); 651 } catch (e) { 652 assertTrue(/Cannot redefine property/.test(e)); 653 } 654 655 656 // Different configurable. 657 descDifferent = { 658 configurable:true, 659 enumerable:false, 660 writable:false, 661 value: 2000 662 }; 663 664 try { 665 Object.defineProperty(obj5, 'bar', descDifferent); 666 assertTrue(false); 667 } catch (e) { 668 assertTrue(/Cannot redefine property/.test(e)); 669 } 670 671 // No difference. 672 descDifferent = { 673 configurable:false, 674 enumerable:false, 675 writable:false, 676 value:2000 677 }; 678 // Make sure we can still redefine if all properties are the same. 679 Object.defineProperty(obj5, 'bar', descDifferent); 680 681 // Make sure that obj5 still holds the original values. 682 desc = Object.getOwnPropertyDescriptor(obj5, 'bar'); 683 assertEquals(desc.value, 2000); 684 assertFalse(desc.writable); 685 assertFalse(desc.enumerable); 686 assertFalse(desc.configurable); 687 688 689 // Make sure that we can't overwrite +0 with -0 and vice versa. 690 var descMinusZero = {value: -0, configurable: false}; 691 var descPlusZero = {value: +0, configurable: false}; 692 693 Object.defineProperty(obj5, 'minuszero', descMinusZero); 694 695 // Make sure we can redefine with -0. 696 Object.defineProperty(obj5, 'minuszero', descMinusZero); 697 698 try { 699 Object.defineProperty(obj5, 'minuszero', descPlusZero); 700 assertUnreachable(); 701 } catch (e) { 702 assertTrue(/Cannot redefine property/.test(e)); 703 } 704 705 706 Object.defineProperty(obj5, 'pluszero', descPlusZero); 707 708 // Make sure we can redefine with +0. 709 Object.defineProperty(obj5, 'pluszero', descPlusZero); 710 711 try { 712 Object.defineProperty(obj5, 'pluszero', descMinusZero); 713 assertUnreachable(); 714 } catch (e) { 715 assertTrue(/Cannot redefine property/.test(e)); 716 } 717 718 719 var obj6 = {}; 720 obj6[1] = 'foo'; 721 obj6[2] = 'bar'; 722 obj6[3] = '42'; 723 obj6[4] = '43'; 724 obj6[5] = '44'; 725 726 var descElement = { value: 'foobar' }; 727 var descElementNonConfigurable = { value: 'barfoo', configurable: false }; 728 var descElementNonWritable = { value: 'foofoo', writable: false }; 729 var descElementNonEnumerable = { value: 'barbar', enumerable: false }; 730 var descElementAllFalse = { value: 'foofalse', 731 configurable: false, 732 writable: false, 733 enumerable: false }; 734 735 736 // Redefine existing property. 737 Object.defineProperty(obj6, '1', descElement); 738 desc = Object.getOwnPropertyDescriptor(obj6, '1'); 739 assertEquals(desc.value, 'foobar'); 740 assertTrue(desc.writable); 741 assertTrue(desc.enumerable); 742 assertTrue(desc.configurable); 743 744 // Redefine existing property with configurable: false. 745 Object.defineProperty(obj6, '2', descElementNonConfigurable); 746 desc = Object.getOwnPropertyDescriptor(obj6, '2'); 747 assertEquals(desc.value, 'barfoo'); 748 assertTrue(desc.writable); 749 assertTrue(desc.enumerable); 750 assertFalse(desc.configurable); 751 752 // Can use defineProperty to change the value of a non 753 // configurable property. 754 try { 755 Object.defineProperty(obj6, '2', descElement); 756 desc = Object.getOwnPropertyDescriptor(obj6, '2'); 757 assertEquals(desc.value, 'foobar'); 758 } catch (e) { 759 assertUnreachable(); 760 } 761 762 // Ensure that we can't change the descriptor of a 763 // non configurable property. 764 try { 765 var descAccessor = { get: function() { return 0; } }; 766 Object.defineProperty(obj6, '2', descAccessor); 767 assertUnreachable(); 768 } catch (e) { 769 assertTrue(/Cannot redefine property/.test(e)); 770 } 771 772 Object.defineProperty(obj6, '2', descElementNonWritable); 773 desc = Object.getOwnPropertyDescriptor(obj6, '2'); 774 assertEquals(desc.value, 'foofoo'); 775 assertFalse(desc.writable); 776 assertTrue(desc.enumerable); 777 assertFalse(desc.configurable); 778 779 Object.defineProperty(obj6, '3', descElementNonWritable); 780 desc = Object.getOwnPropertyDescriptor(obj6, '3'); 781 assertEquals(desc.value, 'foofoo'); 782 assertFalse(desc.writable); 783 assertTrue(desc.enumerable); 784 assertTrue(desc.configurable); 785 786 // Redefine existing property with configurable: false. 787 Object.defineProperty(obj6, '4', descElementNonEnumerable); 788 desc = Object.getOwnPropertyDescriptor(obj6, '4'); 789 assertEquals(desc.value, 'barbar'); 790 assertTrue(desc.writable); 791 assertFalse(desc.enumerable); 792 assertTrue(desc.configurable); 793 794 // Redefine existing property with configurable: false. 795 Object.defineProperty(obj6, '5', descElementAllFalse); 796 desc = Object.getOwnPropertyDescriptor(obj6, '5'); 797 assertEquals(desc.value, 'foofalse'); 798 assertFalse(desc.writable); 799 assertFalse(desc.enumerable); 800 assertFalse(desc.configurable); 801 802 // Define non existing property - all attributes should default to false. 803 Object.defineProperty(obj6, '15', descElement); 804 desc = Object.getOwnPropertyDescriptor(obj6, '15'); 805 assertEquals(desc.value, 'foobar'); 806 assertFalse(desc.writable); 807 assertFalse(desc.enumerable); 808 assertFalse(desc.configurable); 809 810 // Make sure that we can't redefine using direct access. 811 obj6[15] ='overwrite'; 812 assertEquals(obj6[15],'foobar'); 813 814 815 // Repeat the above tests on an array. 816 var arr = new Array(); 817 arr[1] = 'foo'; 818 arr[2] = 'bar'; 819 arr[3] = '42'; 820 arr[4] = '43'; 821 arr[5] = '44'; 822 823 var descElement = { value: 'foobar' }; 824 var descElementNonConfigurable = { value: 'barfoo', configurable: false }; 825 var descElementNonWritable = { value: 'foofoo', writable: false }; 826 var descElementNonEnumerable = { value: 'barbar', enumerable: false }; 827 var descElementAllFalse = { value: 'foofalse', 828 configurable: false, 829 writable: false, 830 enumerable: false }; 831 832 833 // Redefine existing property. 834 Object.defineProperty(arr, '1', descElement); 835 desc = Object.getOwnPropertyDescriptor(arr, '1'); 836 assertEquals(desc.value, 'foobar'); 837 assertTrue(desc.writable); 838 assertTrue(desc.enumerable); 839 assertTrue(desc.configurable); 840 841 // Redefine existing property with configurable: false. 842 Object.defineProperty(arr, '2', descElementNonConfigurable); 843 desc = Object.getOwnPropertyDescriptor(arr, '2'); 844 assertEquals(desc.value, 'barfoo'); 845 assertTrue(desc.writable); 846 assertTrue(desc.enumerable); 847 assertFalse(desc.configurable); 848 849 // Can use defineProperty to change the value of a non 850 // configurable property of an array. 851 try { 852 Object.defineProperty(arr, '2', descElement); 853 desc = Object.getOwnPropertyDescriptor(arr, '2'); 854 assertEquals(desc.value, 'foobar'); 855 } catch (e) { 856 assertUnreachable(); 857 } 858 859 // Ensure that we can't change the descriptor of a 860 // non configurable property. 861 try { 862 var descAccessor = { get: function() { return 0; } }; 863 Object.defineProperty(arr, '2', descAccessor); 864 assertUnreachable(); 865 } catch (e) { 866 assertTrue(/Cannot redefine property/.test(e)); 867 } 868 869 Object.defineProperty(arr, '2', descElementNonWritable); 870 desc = Object.getOwnPropertyDescriptor(arr, '2'); 871 assertEquals(desc.value, 'foofoo'); 872 assertFalse(desc.writable); 873 assertTrue(desc.enumerable); 874 assertFalse(desc.configurable); 875 876 Object.defineProperty(arr, '3', descElementNonWritable); 877 desc = Object.getOwnPropertyDescriptor(arr, '3'); 878 assertEquals(desc.value, 'foofoo'); 879 assertFalse(desc.writable); 880 assertTrue(desc.enumerable); 881 assertTrue(desc.configurable); 882 883 // Redefine existing property with configurable: false. 884 Object.defineProperty(arr, '4', descElementNonEnumerable); 885 desc = Object.getOwnPropertyDescriptor(arr, '4'); 886 assertEquals(desc.value, 'barbar'); 887 assertTrue(desc.writable); 888 assertFalse(desc.enumerable); 889 assertTrue(desc.configurable); 890 891 // Redefine existing property with configurable: false. 892 Object.defineProperty(arr, '5', descElementAllFalse); 893 desc = Object.getOwnPropertyDescriptor(arr, '5'); 894 assertEquals(desc.value, 'foofalse'); 895 assertFalse(desc.writable); 896 assertFalse(desc.enumerable); 897 assertFalse(desc.configurable); 898 899 // Define non existing property - all attributes should default to false. 900 Object.defineProperty(arr, '15', descElement); 901 desc = Object.getOwnPropertyDescriptor(arr, '15'); 902 assertEquals(desc.value, 'foobar'); 903 assertFalse(desc.writable); 904 assertFalse(desc.enumerable); 905 assertFalse(desc.configurable); 906 907 // See issue 968: http://code.google.com/p/v8/issues/detail?id=968 908 var o = { x : 42 }; 909 Object.defineProperty(o, "x", { writable: false }); 910 assertEquals(42, o.x); 911 o.x = 37; 912 assertEquals(42, o.x); 913 914 o = { x : 42 }; 915 Object.defineProperty(o, "x", {}); 916 assertEquals(42, o.x); 917 o.x = 37; 918 // Writability is preserved. 919 assertEquals(37, o.x); 920 921 var o = { }; 922 Object.defineProperty(o, "x", { writable: false }); 923 assertEquals(undefined, o.x); 924 o.x = 37; 925 assertEquals(undefined, o.x); 926 927 o = { get x() { return 87; } }; 928 Object.defineProperty(o, "x", { writable: false }); 929 assertEquals(undefined, o.x); 930 o.x = 37; 931 assertEquals(undefined, o.x); 932 933 // Ignore inherited properties. 934 o = { __proto__ : { x : 87 } }; 935 Object.defineProperty(o, "x", { writable: false }); 936 assertEquals(undefined, o.x); 937 o.x = 37; 938 assertEquals(undefined, o.x); 939 940 function testDefineProperty(obj, propertyName, desc, resultDesc) { 941 Object.defineProperty(obj, propertyName, desc); 942 var actualDesc = Object.getOwnPropertyDescriptor(obj, propertyName); 943 assertEquals(resultDesc.enumerable, actualDesc.enumerable); 944 assertEquals(resultDesc.configurable, actualDesc.configurable); 945 if (resultDesc.hasOwnProperty('value')) { 946 assertEquals(resultDesc.value, actualDesc.value); 947 assertEquals(resultDesc.writable, actualDesc.writable); 948 assertFalse(resultDesc.hasOwnProperty('get')); 949 assertFalse(resultDesc.hasOwnProperty('set')); 950 } else { 951 assertEquals(resultDesc.get, actualDesc.get); 952 assertEquals(resultDesc.set, actualDesc.set); 953 assertFalse(resultDesc.hasOwnProperty('value')); 954 assertFalse(resultDesc.hasOwnProperty('writable')); 955 } 956 } 957 958 // tests redefining existing property with a generic descriptor 959 o = { p : 42 }; 960 testDefineProperty(o, 'p', 961 { }, 962 { value : 42, writable : true, enumerable : true, configurable : true }); 963 964 o = { p : 42 }; 965 testDefineProperty(o, 'p', 966 { enumerable : true }, 967 { value : 42, writable : true, enumerable : true, configurable : true }); 968 969 o = { p : 42 }; 970 testDefineProperty(o, 'p', 971 { configurable : true }, 972 { value : 42, writable : true, enumerable : true, configurable : true }); 973 974 o = { p : 42 }; 975 testDefineProperty(o, 'p', 976 { enumerable : false }, 977 { value : 42, writable : true, enumerable : false, configurable : true }); 978 979 o = { p : 42 }; 980 testDefineProperty(o, 'p', 981 { configurable : false }, 982 { value : 42, writable : true, enumerable : true, configurable : false }); 983 984 o = { p : 42 }; 985 testDefineProperty(o, 'p', 986 { enumerable : true, configurable : true }, 987 { value : 42, writable : true, enumerable : true, configurable : true }); 988 989 o = { p : 42 }; 990 testDefineProperty(o, 'p', 991 { enumerable : false, configurable : true }, 992 { value : 42, writable : true, enumerable : false, configurable : true }); 993 994 o = { p : 42 }; 995 testDefineProperty(o, 'p', 996 { enumerable : true, configurable : false }, 997 { value : 42, writable : true, enumerable : true, configurable : false }); 998 999 o = { p : 42 }; 1000 testDefineProperty(o, 'p', 1001 { enumerable : false, configurable : false }, 1002 { value : 42, writable : true, enumerable : false, configurable : false }); 1003 1004 // can make a writable, non-configurable field non-writable 1005 o = { p : 42 }; 1006 Object.defineProperty(o, 'p', { configurable: false }); 1007 testDefineProperty(o, 'p', 1008 { writable: false }, 1009 { value : 42, writable : false, enumerable : true, configurable : false }); 1010 1011 // redefine of get only property with generic descriptor 1012 o = {}; 1013 Object.defineProperty(o, 'p', 1014 { get : getter1, enumerable: true, configurable: true }); 1015 testDefineProperty(o, 'p', 1016 { enumerable : false, configurable : false }, 1017 { get: getter1, set: undefined, enumerable : false, configurable : false }); 1018 1019 // redefine of get/set only property with generic descriptor 1020 o = {}; 1021 Object.defineProperty(o, 'p', 1022 { get: getter1, set: setter1, enumerable: true, configurable: true }); 1023 testDefineProperty(o, 'p', 1024 { enumerable : false, configurable : false }, 1025 { get: getter1, set: setter1, enumerable : false, configurable : false }); 1026 1027 // redefine of set only property with generic descriptor 1028 o = {}; 1029 Object.defineProperty(o, 'p', 1030 { set : setter1, enumerable: true, configurable: true }); 1031 testDefineProperty(o, 'p', 1032 { enumerable : false, configurable : false }, 1033 { get: undefined, set: setter1, enumerable : false, configurable : false }); 1034