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. 33try { 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. 41try { 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. 49try { 50 Object.defineProperty(0, "foo", undefined); 51 assertTrue(false); 52} catch (e) { 53 assertTrue(/called on non-object/.test(e)); 54} 55 56// Object. 57var obj1 = {}; 58 59// Values. 60var val1 = 0; 61var val2 = 0; 62var val3 = 0; 63 64function setter1() {val1++; } 65function getter1() {return val1; } 66 67function setter2() {val2++; } 68function getter2() {return val2; } 69 70function setter3() {val3++; } 71function getter3() {return val3; } 72 73 74// Descriptors. 75var emptyDesc = {}; 76 77var accessorConfigurable = { 78 set: setter1, 79 get: getter1, 80 configurable: true 81}; 82 83var accessorNoConfigurable = { 84 set: setter2, 85 get: getter2, 86 configurable: false 87}; 88 89var accessorOnlySet = { 90 set: setter3, 91 configurable: true 92}; 93 94var accessorOnlyGet = { 95 get: getter3, 96 configurable: true 97}; 98 99var accessorDefault = {set: function(){} }; 100 101var dataConfigurable = { value: 1000, configurable: true }; 102 103var dataNoConfigurable = { value: 2000, configurable: false }; 104 105var dataWritable = { value: 3000, writable: true}; 106 107 108// Check that we can't add property with undefined attributes. 109try { 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. 118Object.defineProperty(obj1, "foo", emptyDesc); 119 120// foo should be undefined as it has no get, set or value 121assertEquals(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). 125var desc = Object.getOwnPropertyDescriptor(obj1, "foo"); 126assertFalse(desc.configurable); 127assertFalse(desc.enumerable); 128assertFalse(desc.writable); 129assertEquals(desc.get, undefined); 130assertEquals(desc.set, undefined); 131assertEquals(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). 136desc = Object.getOwnPropertyDescriptor(obj1, "bar"); 137assertEquals(desc, undefined); 138 139// Make sure that foo can't be reset (as configurable is false). 140try { 141 Object.defineProperty(obj1, "foo", accessorConfigurable); 142} catch (e) { 143 assertTrue(/Cannot redefine property/.test(e)); 144} 145 146 147// Accessor properties 148 149Object.defineProperty(obj1, "bar", accessorConfigurable); 150desc = Object.getOwnPropertyDescriptor(obj1, "bar"); 151assertTrue(desc.configurable); 152assertFalse(desc.enumerable); 153assertEquals(desc.writable, undefined); 154assertEquals(desc.get, accessorConfigurable.get); 155assertEquals(desc.set, accessorConfigurable.set); 156assertEquals(desc.value, undefined); 157assertEquals(1, obj1.bar = 1); 158assertEquals(1, val1); 159assertEquals(1, obj1.bar = 1); 160assertEquals(2, val1); 161assertEquals(2, obj1.bar); 162 163// Redefine bar with non configurable test 164Object.defineProperty(obj1, "bar", accessorNoConfigurable); 165desc = Object.getOwnPropertyDescriptor(obj1, "bar"); 166assertFalse(desc.configurable); 167assertFalse(desc.enumerable); 168assertEquals(desc.writable, undefined); 169assertEquals(desc.get, accessorNoConfigurable.get); 170assertEquals(desc.set, accessorNoConfigurable.set); 171assertEquals(desc.value, undefined); 172assertEquals(1, obj1.bar = 1); 173assertEquals(2, val1); 174assertEquals(1, val2); 175assertEquals(1, obj1.bar = 1) 176assertEquals(2, val1); 177assertEquals(2, val2); 178assertEquals(2, obj1.bar); 179 180// Try to redefine bar again - should fail as configurable is false. 181try { 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. 189try { 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. 197Object.defineProperty(obj1, "bar", accessorNoConfigurable); 198desc = Object.getOwnPropertyDescriptor(obj1, "bar"); 199assertFalse(desc.configurable); 200assertFalse(desc.enumerable); 201assertEquals(desc.writable, undefined); 202assertEquals(desc.get, accessorNoConfigurable.get); 203assertEquals(desc.set, accessorNoConfigurable.set); 204assertEquals(desc.value, undefined); 205assertEquals(1, obj1.bar = 1); 206assertEquals(2, val1); 207assertEquals(3, val2); 208assertEquals(1, obj1.bar = 1) 209assertEquals(2, val1); 210assertEquals(4, val2); 211assertEquals(4, obj1.bar); 212 213// Define an accessor that has only a setter. 214Object.defineProperty(obj1, "setOnly", accessorOnlySet); 215desc = Object.getOwnPropertyDescriptor(obj1, "setOnly"); 216assertTrue(desc.configurable); 217assertFalse(desc.enumerable); 218assertEquals(desc.set, accessorOnlySet.set); 219assertEquals(desc.writable, undefined); 220assertEquals(desc.value, undefined); 221assertEquals(desc.get, undefined); 222assertEquals(1, obj1.setOnly = 1); 223assertEquals(1, val3); 224 225// Add a getter - should not touch the setter. 226Object.defineProperty(obj1, "setOnly", accessorOnlyGet); 227desc = Object.getOwnPropertyDescriptor(obj1, "setOnly"); 228assertTrue(desc.configurable); 229assertFalse(desc.enumerable); 230assertEquals(desc.get, accessorOnlyGet.get); 231assertEquals(desc.set, accessorOnlySet.set); 232assertEquals(desc.writable, undefined); 233assertEquals(desc.value, undefined); 234assertEquals(1, obj1.setOnly = 1); 235assertEquals(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. 239Object.defineProperty(obj1, "both", accessorConfigurable); 240 241Object.defineProperty(obj1, "both", accessorOnlySet); 242desc = Object.getOwnPropertyDescriptor(obj1, "both"); 243assertTrue(desc.configurable); 244assertFalse(desc.enumerable); 245assertEquals(desc.set, accessorOnlySet.set); 246assertEquals(desc.get, accessorConfigurable.get); 247assertEquals(desc.writable, undefined); 248assertEquals(desc.value, undefined); 249assertEquals(1, obj1.both = 1); 250assertEquals(3, val3); 251 252 253// Data properties 254 255Object.defineProperty(obj1, "foobar", dataConfigurable); 256desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); 257assertEquals(obj1.foobar, 1000); 258assertEquals(desc.value, 1000); 259assertTrue(desc.configurable); 260assertFalse(desc.writable); 261assertFalse(desc.enumerable); 262assertEquals(desc.get, undefined); 263assertEquals(desc.set, undefined); 264//Try writing to non writable attribute - should remain 1000 265obj1.foobar = 1001; 266assertEquals(obj1.foobar, 1000); 267 268 269// Redefine to writable descriptor - now writing to foobar should be allowed. 270Object.defineProperty(obj1, "foobar", dataWritable); 271desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); 272assertEquals(obj1.foobar, 3000); 273assertEquals(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. 276assertTrue(desc.configurable); 277assertTrue(desc.writable); 278assertFalse(desc.enumerable); 279assertEquals(desc.get, undefined); 280assertEquals(desc.set, undefined); 281// Writing to the property should now be allowed 282obj1.foobar = 1001; 283assertEquals(obj1.foobar, 1001); 284 285 286// Redefine with non configurable data property. 287Object.defineProperty(obj1, "foobar", dataNoConfigurable); 288desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); 289assertEquals(obj1.foobar, 2000); 290assertEquals(desc.value, 2000); 291assertFalse(desc.configurable); 292assertTrue(desc.writable); 293assertFalse(desc.enumerable); 294assertEquals(desc.get, undefined); 295assertEquals(desc.set, undefined); 296 297// Try redefine again - shold fail because configurable is now false. 298try { 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. 306try { 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). 315Object.defineProperty(obj1, "foobar", dataNoConfigurable); 316desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); 317assertEquals(obj1.foobar, 2000); 318assertEquals(desc.value, 2000); 319assertFalse(desc.configurable); 320assertTrue(desc.writable); 321assertFalse(desc.enumerable); 322assertEquals(desc.get, undefined); 323assertEquals(desc.set, undefined); 324 325 326// New object 327var obj2 = {}; 328 329// Make accessor - redefine to data 330Object.defineProperty(obj2, "foo", accessorConfigurable); 331 332// Redefine to data property 333Object.defineProperty(obj2, "foo", dataConfigurable); 334desc = Object.getOwnPropertyDescriptor(obj2, "foo"); 335assertEquals(obj2.foo, 1000); 336assertEquals(desc.value, 1000); 337assertTrue(desc.configurable); 338assertFalse(desc.writable); 339assertFalse(desc.enumerable); 340assertEquals(desc.get, undefined); 341assertEquals(desc.set, undefined); 342 343 344// Redefine back to accessor 345Object.defineProperty(obj2, "foo", accessorConfigurable); 346desc = Object.getOwnPropertyDescriptor(obj2, "foo"); 347assertTrue(desc.configurable); 348assertFalse(desc.enumerable); 349assertEquals(desc.writable, undefined); 350assertEquals(desc.get, accessorConfigurable.get); 351assertEquals(desc.set, accessorConfigurable.set); 352assertEquals(desc.value, undefined); 353assertEquals(1, obj2.foo = 1); 354assertEquals(3, val1); 355assertEquals(4, val2); 356assertEquals(3, obj2.foo); 357 358// Make data - redefine to accessor 359Object.defineProperty(obj2, "bar", dataConfigurable) 360 361// Redefine to accessor property 362Object.defineProperty(obj2, "bar", accessorConfigurable); 363desc = Object.getOwnPropertyDescriptor(obj2, "bar"); 364assertTrue(desc.configurable); 365assertFalse(desc.enumerable); 366assertEquals(desc.writable, undefined); 367assertEquals(desc.get, accessorConfigurable.get); 368assertEquals(desc.set, accessorConfigurable.set); 369assertEquals(desc.value, undefined); 370assertEquals(1, obj2.bar = 1); 371assertEquals(4, val1); 372assertEquals(4, val2); 373assertEquals(4, obj2.foo); 374 375// Redefine back to data property 376Object.defineProperty(obj2, "bar", dataConfigurable); 377desc = Object.getOwnPropertyDescriptor(obj2, "bar"); 378assertEquals(obj2.bar, 1000); 379assertEquals(desc.value, 1000); 380assertTrue(desc.configurable); 381assertFalse(desc.writable); 382assertFalse(desc.enumerable); 383assertEquals(desc.get, undefined); 384assertEquals(desc.set, undefined); 385 386 387// Redefinition of an accessor defined using __defineGetter__ and 388// __defineSetter__. 389function get(){return this.x} 390function set(x){this.x=x}; 391 392var obj3 = {x:1000}; 393obj3.__defineGetter__("foo", get); 394obj3.__defineSetter__("foo", set); 395 396desc = Object.getOwnPropertyDescriptor(obj3, "foo"); 397assertTrue(desc.configurable); 398assertTrue(desc.enumerable); 399assertEquals(desc.writable, undefined); 400assertEquals(desc.get, get); 401assertEquals(desc.set, set); 402assertEquals(desc.value, undefined); 403assertEquals(1, obj3.foo = 1); 404assertEquals(1, obj3.x); 405assertEquals(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). 409Object.defineProperty(obj3, "foo", accessorNoConfigurable); 410desc = Object.getOwnPropertyDescriptor(obj3, "foo"); 411assertFalse(desc.configurable); 412assertTrue(desc.enumerable); 413assertEquals(desc.writable, undefined); 414assertEquals(desc.get, accessorNoConfigurable.get); 415assertEquals(desc.set, accessorNoConfigurable.set); 416assertEquals(desc.value, undefined); 417assertEquals(1, obj3.foo = 1); 418assertEquals(5, val2); 419assertEquals(5, obj3.foo); 420 421 422obj3.__defineGetter__("bar", get); 423obj3.__defineSetter__("bar", set); 424 425 426// Redefine back to data property 427Object.defineProperty(obj3, "bar", dataConfigurable); 428desc = Object.getOwnPropertyDescriptor(obj3, "bar"); 429assertEquals(obj3.bar, 1000); 430assertEquals(desc.value, 1000); 431assertTrue(desc.configurable); 432assertFalse(desc.writable); 433assertTrue(desc.enumerable); 434assertEquals(desc.get, undefined); 435assertEquals(desc.set, undefined); 436 437 438var obj4 = {}; 439var func = function (){return 42;}; 440obj4.bar = func; 441assertEquals(42, obj4.bar()); 442 443Object.defineProperty(obj4, "bar", accessorConfigurable); 444desc = Object.getOwnPropertyDescriptor(obj4, "bar"); 445assertTrue(desc.configurable); 446assertTrue(desc.enumerable); 447assertEquals(desc.writable, undefined); 448assertEquals(desc.get, accessorConfigurable.get); 449assertEquals(desc.set, accessorConfigurable.set); 450assertEquals(desc.value, undefined); 451assertEquals(1, obj4.bar = 1); 452assertEquals(5, val1); 453assertEquals(5, obj4.bar); 454 455// Make sure an error is thrown when trying to access to redefined function. 456try { 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. 467try { 468 %DefineOrRedefineAccessorProperty(0, 0, 0, 0, 0); 469} catch (e) { 470 assertTrue(/illegal access/.test(e)); 471} 472 473try { 474 %DefineOrRedefineDataProperty(0, 0, 0, 0); 475} catch (e) { 476 assertTrue(/illegal access/.test(e)); 477} 478 479try { 480 %DefineOrRedefineDataProperty(null, null, null, null); 481} catch (e) { 482 assertTrue(/illegal access/.test(e)); 483} 484 485try { 486 %DefineOrRedefineAccessorProperty(null, null, null, null, null); 487} catch (e) { 488 assertTrue(/illegal access/.test(e)); 489} 490 491try { 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 499try { 500 %DefineOrRedefineAccessorProperty(null, 'foo', 0, func, 0); 501} catch (e) { 502 assertTrue(/illegal access/.test(e)); 503} 504 505try { 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 516var obj5 = {}; 517// Enumerable will default to false. 518Object.defineProperty(obj5, 'foo', accessorNoConfigurable); 519desc = 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. 522Object.defineProperty(obj5, 'foo', accessorNoConfigurable); 523 524// Different setter. 525var descDifferent = { 526 configurable:false, 527 enumerable:false, 528 set: setter1, 529 get: getter2 530}; 531 532try { 533 Object.defineProperty(obj5, 'foo', descDifferent); 534 assertTrue(false); 535} catch (e) { 536 assertTrue(/Cannot redefine property/.test(e)); 537} 538 539// Different getter. 540descDifferent = { 541 configurable:false, 542 enumerable:false, 543 set: setter2, 544 get: getter1 545}; 546 547try { 548 Object.defineProperty(obj5, 'foo', descDifferent); 549 assertTrue(false); 550} catch (e) { 551 assertTrue(/Cannot redefine property/.test(e)); 552} 553 554// Different enumerable. 555descDifferent = { 556 configurable:false, 557 enumerable:true, 558 set: setter2, 559 get: getter2 560}; 561 562try { 563 Object.defineProperty(obj5, 'foo', descDifferent); 564 assertTrue(false); 565} catch (e) { 566 assertTrue(/Cannot redefine property/.test(e)); 567} 568 569// Different configurable. 570descDifferent = { 571 configurable:false, 572 enumerable:true, 573 set: setter2, 574 get: getter2 575}; 576 577try { 578 Object.defineProperty(obj5, 'foo', descDifferent); 579 assertTrue(false); 580} catch (e) { 581 assertTrue(/Cannot redefine property/.test(e)); 582} 583 584// No difference. 585descDifferent = { 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. 592Object.defineProperty(obj5, 'foo', descDifferent); 593 594// Make sure that obj5 still holds the original values. 595desc = Object.getOwnPropertyDescriptor(obj5, 'foo'); 596assertEquals(desc.get, getter2); 597assertEquals(desc.set, setter2); 598assertFalse(desc.enumerable); 599assertFalse(desc.configurable); 600 601 602// Also exercise step 6 on data property, writable and enumerable 603// defaults to false. 604Object.defineProperty(obj5, 'bar', dataNoConfigurable); 605 606// Test that redefinition with the same property descriptor is possible 607Object.defineProperty(obj5, 'bar', dataNoConfigurable); 608 609// Different value. 610descDifferent = { 611 configurable:false, 612 enumerable:false, 613 writable: false, 614 value: 1999 615}; 616 617try { 618 Object.defineProperty(obj5, 'bar', descDifferent); 619 assertTrue(false); 620} catch (e) { 621 assertTrue(/Cannot redefine property/.test(e)); 622} 623 624// Different writable. 625descDifferent = { 626 configurable:false, 627 enumerable:false, 628 writable: true, 629 value: 2000 630}; 631 632try { 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. 641descDifferent = { 642 configurable:false, 643 enumerable:true , 644 writable:false, 645 value: 2000 646}; 647 648try { 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. 657descDifferent = { 658 configurable:true, 659 enumerable:false, 660 writable:false, 661 value: 2000 662}; 663 664try { 665 Object.defineProperty(obj5, 'bar', descDifferent); 666 assertTrue(false); 667} catch (e) { 668 assertTrue(/Cannot redefine property/.test(e)); 669} 670 671// No difference. 672descDifferent = { 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. 679Object.defineProperty(obj5, 'bar', descDifferent); 680 681// Make sure that obj5 still holds the original values. 682desc = Object.getOwnPropertyDescriptor(obj5, 'bar'); 683assertEquals(desc.value, 2000); 684assertFalse(desc.writable); 685assertFalse(desc.enumerable); 686assertFalse(desc.configurable); 687 688 689// Make sure that we can't overwrite +0 with -0 and vice versa. 690var descMinusZero = {value: -0, configurable: false}; 691var descPlusZero = {value: +0, configurable: false}; 692 693Object.defineProperty(obj5, 'minuszero', descMinusZero); 694 695// Make sure we can redefine with -0. 696Object.defineProperty(obj5, 'minuszero', descMinusZero); 697 698try { 699 Object.defineProperty(obj5, 'minuszero', descPlusZero); 700 assertUnreachable(); 701} catch (e) { 702 assertTrue(/Cannot redefine property/.test(e)); 703} 704 705 706Object.defineProperty(obj5, 'pluszero', descPlusZero); 707 708// Make sure we can redefine with +0. 709Object.defineProperty(obj5, 'pluszero', descPlusZero); 710 711try { 712 Object.defineProperty(obj5, 'pluszero', descMinusZero); 713 assertUnreachable(); 714} catch (e) { 715 assertTrue(/Cannot redefine property/.test(e)); 716} 717 718 719var obj6 = {}; 720obj6[1] = 'foo'; 721obj6[2] = 'bar'; 722obj6[3] = '42'; 723obj6[4] = '43'; 724obj6[5] = '44'; 725 726var descElement = { value: 'foobar' }; 727var descElementNonConfigurable = { value: 'barfoo', configurable: false }; 728var descElementNonWritable = { value: 'foofoo', writable: false }; 729var descElementNonEnumerable = { value: 'barbar', enumerable: false }; 730var descElementAllFalse = { value: 'foofalse', 731 configurable: false, 732 writable: false, 733 enumerable: false }; 734 735 736// Redefine existing property. 737Object.defineProperty(obj6, '1', descElement); 738desc = Object.getOwnPropertyDescriptor(obj6, '1'); 739assertEquals(desc.value, 'foobar'); 740assertTrue(desc.writable); 741assertTrue(desc.enumerable); 742assertTrue(desc.configurable); 743 744// Redefine existing property with configurable: false. 745Object.defineProperty(obj6, '2', descElementNonConfigurable); 746desc = Object.getOwnPropertyDescriptor(obj6, '2'); 747assertEquals(desc.value, 'barfoo'); 748assertTrue(desc.writable); 749assertTrue(desc.enumerable); 750assertFalse(desc.configurable); 751 752// Can use defineProperty to change the value of a non 753// configurable property. 754try { 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. 764try { 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 772Object.defineProperty(obj6, '2', descElementNonWritable); 773desc = Object.getOwnPropertyDescriptor(obj6, '2'); 774assertEquals(desc.value, 'foofoo'); 775assertFalse(desc.writable); 776assertTrue(desc.enumerable); 777assertFalse(desc.configurable); 778 779Object.defineProperty(obj6, '3', descElementNonWritable); 780desc = Object.getOwnPropertyDescriptor(obj6, '3'); 781assertEquals(desc.value, 'foofoo'); 782assertFalse(desc.writable); 783assertTrue(desc.enumerable); 784assertTrue(desc.configurable); 785 786// Redefine existing property with configurable: false. 787Object.defineProperty(obj6, '4', descElementNonEnumerable); 788desc = Object.getOwnPropertyDescriptor(obj6, '4'); 789assertEquals(desc.value, 'barbar'); 790assertTrue(desc.writable); 791assertFalse(desc.enumerable); 792assertTrue(desc.configurable); 793 794// Redefine existing property with configurable: false. 795Object.defineProperty(obj6, '5', descElementAllFalse); 796desc = Object.getOwnPropertyDescriptor(obj6, '5'); 797assertEquals(desc.value, 'foofalse'); 798assertFalse(desc.writable); 799assertFalse(desc.enumerable); 800assertFalse(desc.configurable); 801 802// Define non existing property - all attributes should default to false. 803Object.defineProperty(obj6, '15', descElement); 804desc = Object.getOwnPropertyDescriptor(obj6, '15'); 805assertEquals(desc.value, 'foobar'); 806assertFalse(desc.writable); 807assertFalse(desc.enumerable); 808assertFalse(desc.configurable); 809 810// Make sure that we can't redefine using direct access. 811obj6[15] ='overwrite'; 812assertEquals(obj6[15],'foobar'); 813 814 815// Repeat the above tests on an array. 816var arr = new Array(); 817arr[1] = 'foo'; 818arr[2] = 'bar'; 819arr[3] = '42'; 820arr[4] = '43'; 821arr[5] = '44'; 822 823var descElement = { value: 'foobar' }; 824var descElementNonConfigurable = { value: 'barfoo', configurable: false }; 825var descElementNonWritable = { value: 'foofoo', writable: false }; 826var descElementNonEnumerable = { value: 'barbar', enumerable: false }; 827var descElementAllFalse = { value: 'foofalse', 828 configurable: false, 829 writable: false, 830 enumerable: false }; 831 832 833// Redefine existing property. 834Object.defineProperty(arr, '1', descElement); 835desc = Object.getOwnPropertyDescriptor(arr, '1'); 836assertEquals(desc.value, 'foobar'); 837assertTrue(desc.writable); 838assertTrue(desc.enumerable); 839assertTrue(desc.configurable); 840 841// Redefine existing property with configurable: false. 842Object.defineProperty(arr, '2', descElementNonConfigurable); 843desc = Object.getOwnPropertyDescriptor(arr, '2'); 844assertEquals(desc.value, 'barfoo'); 845assertTrue(desc.writable); 846assertTrue(desc.enumerable); 847assertFalse(desc.configurable); 848 849// Can use defineProperty to change the value of a non 850// configurable property of an array. 851try { 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. 861try { 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 869Object.defineProperty(arr, '2', descElementNonWritable); 870desc = Object.getOwnPropertyDescriptor(arr, '2'); 871assertEquals(desc.value, 'foofoo'); 872assertFalse(desc.writable); 873assertTrue(desc.enumerable); 874assertFalse(desc.configurable); 875 876Object.defineProperty(arr, '3', descElementNonWritable); 877desc = Object.getOwnPropertyDescriptor(arr, '3'); 878assertEquals(desc.value, 'foofoo'); 879assertFalse(desc.writable); 880assertTrue(desc.enumerable); 881assertTrue(desc.configurable); 882 883// Redefine existing property with configurable: false. 884Object.defineProperty(arr, '4', descElementNonEnumerable); 885desc = Object.getOwnPropertyDescriptor(arr, '4'); 886assertEquals(desc.value, 'barbar'); 887assertTrue(desc.writable); 888assertFalse(desc.enumerable); 889assertTrue(desc.configurable); 890 891// Redefine existing property with configurable: false. 892Object.defineProperty(arr, '5', descElementAllFalse); 893desc = Object.getOwnPropertyDescriptor(arr, '5'); 894assertEquals(desc.value, 'foofalse'); 895assertFalse(desc.writable); 896assertFalse(desc.enumerable); 897assertFalse(desc.configurable); 898 899// Define non existing property - all attributes should default to false. 900Object.defineProperty(arr, '15', descElement); 901desc = Object.getOwnPropertyDescriptor(arr, '15'); 902assertEquals(desc.value, 'foobar'); 903assertFalse(desc.writable); 904assertFalse(desc.enumerable); 905assertFalse(desc.configurable); 906 907// See issue 968: http://code.google.com/p/v8/issues/detail?id=968 908var o = { x : 42 }; 909Object.defineProperty(o, "x", { writable: false }); 910assertEquals(42, o.x); 911o.x = 37; 912assertEquals(42, o.x); 913 914o = { x : 42 }; 915Object.defineProperty(o, "x", {}); 916assertEquals(42, o.x); 917o.x = 37; 918// Writability is preserved. 919assertEquals(37, o.x); 920 921var o = { }; 922Object.defineProperty(o, "x", { writable: false }); 923assertEquals(undefined, o.x); 924o.x = 37; 925assertEquals(undefined, o.x); 926 927o = { get x() { return 87; } }; 928Object.defineProperty(o, "x", { writable: false }); 929assertEquals(undefined, o.x); 930o.x = 37; 931assertEquals(undefined, o.x); 932 933// Ignore inherited properties. 934o = { __proto__ : { x : 87 } }; 935Object.defineProperty(o, "x", { writable: false }); 936assertEquals(undefined, o.x); 937o.x = 37; 938assertEquals(undefined, o.x); 939 940function 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 959o = { p : 42 }; 960testDefineProperty(o, 'p', 961 { }, 962 { value : 42, writable : true, enumerable : true, configurable : true }); 963 964o = { p : 42 }; 965testDefineProperty(o, 'p', 966 { enumerable : true }, 967 { value : 42, writable : true, enumerable : true, configurable : true }); 968 969o = { p : 42 }; 970testDefineProperty(o, 'p', 971 { configurable : true }, 972 { value : 42, writable : true, enumerable : true, configurable : true }); 973 974o = { p : 42 }; 975testDefineProperty(o, 'p', 976 { enumerable : false }, 977 { value : 42, writable : true, enumerable : false, configurable : true }); 978 979o = { p : 42 }; 980testDefineProperty(o, 'p', 981 { configurable : false }, 982 { value : 42, writable : true, enumerable : true, configurable : false }); 983 984o = { p : 42 }; 985testDefineProperty(o, 'p', 986 { enumerable : true, configurable : true }, 987 { value : 42, writable : true, enumerable : true, configurable : true }); 988 989o = { p : 42 }; 990testDefineProperty(o, 'p', 991 { enumerable : false, configurable : true }, 992 { value : 42, writable : true, enumerable : false, configurable : true }); 993 994o = { p : 42 }; 995testDefineProperty(o, 'p', 996 { enumerable : true, configurable : false }, 997 { value : 42, writable : true, enumerable : true, configurable : false }); 998 999o = { p : 42 }; 1000testDefineProperty(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 1005o = { p : 42 }; 1006Object.defineProperty(o, 'p', { configurable: false }); 1007testDefineProperty(o, 'p', 1008 { writable: false }, 1009 { value : 42, writable : false, enumerable : true, configurable : false }); 1010 1011// redefine of get only property with generic descriptor 1012o = {}; 1013Object.defineProperty(o, 'p', 1014 { get : getter1, enumerable: true, configurable: true }); 1015testDefineProperty(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 1020o = {}; 1021Object.defineProperty(o, 'p', 1022 { get: getter1, set: setter1, enumerable: true, configurable: true }); 1023testDefineProperty(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 1028o = {}; 1029Object.defineProperty(o, 'p', 1030 { set : setter1, enumerable: true, configurable: true }); 1031testDefineProperty(o, 'p', 1032 { enumerable : false, configurable : false }, 1033 { get: undefined, set: setter1, enumerable : false, configurable : false }); 1034