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