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. 33var exception = false; 34try { 35 Object.defineProperty(null, null, null); 36} catch (e) { 37 exception = true; 38 assertTrue(/called on non-object/.test(e)); 39} 40assertTrue(exception); 41 42// Check that an exception is thrown when undefined is passed as object. 43exception = false; 44try { 45 Object.defineProperty(undefined, undefined, undefined); 46} catch (e) { 47 exception = true; 48 assertTrue(/called on non-object/.test(e)); 49} 50assertTrue(exception); 51 52// Check that an exception is thrown when non-object is passed as object. 53exception = false; 54try { 55 Object.defineProperty(0, "foo", undefined); 56} catch (e) { 57 exception = true; 58 assertTrue(/called on non-object/.test(e)); 59} 60assertTrue(exception); 61 62// Object. 63var obj1 = {}; 64 65// Values. 66var val1 = 0; 67var val2 = 0; 68var val3 = 0; 69 70function setter1() {val1++; } 71function getter1() {return val1; } 72 73function setter2() {val2++; } 74function getter2() {return val2; } 75 76function setter3() {val3++; } 77function getter3() {return val3; } 78 79 80// Descriptors. 81var emptyDesc = {}; 82 83var accessorConfigurable = { 84 set: setter1, 85 get: getter1, 86 configurable: true 87}; 88 89var accessorNoConfigurable = { 90 set: setter2, 91 get: getter2, 92 configurable: false 93}; 94 95var accessorOnlySet = { 96 set: setter3, 97 configurable: true 98}; 99 100var accessorOnlyGet = { 101 get: getter3, 102 configurable: true 103}; 104 105var accessorDefault = {set: function(){} }; 106 107var dataConfigurable = { value: 1000, configurable: true }; 108 109var dataNoConfigurable = { value: 2000, configurable: false }; 110 111var dataWritable = { value: 3000, writable: true}; 112 113 114// Check that we can't add property with undefined attributes. 115try { 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. 124Object.defineProperty(obj1, "foo", emptyDesc); 125 126// foo should be undefined as it has no get, set or value 127assertEquals(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). 131var desc = Object.getOwnPropertyDescriptor(obj1, "foo"); 132assertFalse(desc.configurable); 133assertFalse(desc.enumerable); 134assertFalse(desc.writable); 135assertEquals(desc.get, undefined); 136assertEquals(desc.set, undefined); 137assertEquals(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). 142desc = Object.getOwnPropertyDescriptor(obj1, "bar"); 143assertEquals(desc, undefined); 144 145// Make sure that foo can't be reset (as configurable is false). 146try { 147 Object.defineProperty(obj1, "foo", accessorConfigurable); 148} catch (e) { 149 assertTrue(/Cannot redefine property/.test(e)); 150} 151 152 153// Accessor properties 154 155Object.defineProperty(obj1, "bar", accessorConfigurable); 156desc = Object.getOwnPropertyDescriptor(obj1, "bar"); 157assertTrue(desc.configurable); 158assertFalse(desc.enumerable); 159assertEquals(desc.writable, undefined); 160assertEquals(desc.get, accessorConfigurable.get); 161assertEquals(desc.set, accessorConfigurable.set); 162assertEquals(desc.value, undefined); 163assertEquals(1, obj1.bar = 1); 164assertEquals(1, val1); 165assertEquals(1, obj1.bar = 1); 166assertEquals(2, val1); 167assertEquals(2, obj1.bar); 168 169// Redefine bar with non configurable test 170Object.defineProperty(obj1, "bar", accessorNoConfigurable); 171desc = Object.getOwnPropertyDescriptor(obj1, "bar"); 172assertFalse(desc.configurable); 173assertFalse(desc.enumerable); 174assertEquals(desc.writable, undefined); 175assertEquals(desc.get, accessorNoConfigurable.get); 176assertEquals(desc.set, accessorNoConfigurable.set); 177assertEquals(desc.value, undefined); 178assertEquals(1, obj1.bar = 1); 179assertEquals(2, val1); 180assertEquals(1, val2); 181assertEquals(1, obj1.bar = 1) 182assertEquals(2, val1); 183assertEquals(2, val2); 184assertEquals(2, obj1.bar); 185 186// Try to redefine bar again - should fail as configurable is false. 187try { 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. 195try { 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. 203Object.defineProperty(obj1, "bar", accessorNoConfigurable); 204desc = Object.getOwnPropertyDescriptor(obj1, "bar"); 205assertFalse(desc.configurable); 206assertFalse(desc.enumerable); 207assertEquals(desc.writable, undefined); 208assertEquals(desc.get, accessorNoConfigurable.get); 209assertEquals(desc.set, accessorNoConfigurable.set); 210assertEquals(desc.value, undefined); 211assertEquals(1, obj1.bar = 1); 212assertEquals(2, val1); 213assertEquals(3, val2); 214assertEquals(1, obj1.bar = 1) 215assertEquals(2, val1); 216assertEquals(4, val2); 217assertEquals(4, obj1.bar); 218 219// Define an accessor that has only a setter. 220Object.defineProperty(obj1, "setOnly", accessorOnlySet); 221desc = Object.getOwnPropertyDescriptor(obj1, "setOnly"); 222assertTrue(desc.configurable); 223assertFalse(desc.enumerable); 224assertEquals(desc.set, accessorOnlySet.set); 225assertEquals(desc.writable, undefined); 226assertEquals(desc.value, undefined); 227assertEquals(desc.get, undefined); 228assertEquals(1, obj1.setOnly = 1); 229assertEquals(1, val3); 230 231// Add a getter - should not touch the setter. 232Object.defineProperty(obj1, "setOnly", accessorOnlyGet); 233desc = Object.getOwnPropertyDescriptor(obj1, "setOnly"); 234assertTrue(desc.configurable); 235assertFalse(desc.enumerable); 236assertEquals(desc.get, accessorOnlyGet.get); 237assertEquals(desc.set, accessorOnlySet.set); 238assertEquals(desc.writable, undefined); 239assertEquals(desc.value, undefined); 240assertEquals(1, obj1.setOnly = 1); 241assertEquals(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. 245Object.defineProperty(obj1, "both", accessorConfigurable); 246 247Object.defineProperty(obj1, "both", accessorOnlySet); 248desc = Object.getOwnPropertyDescriptor(obj1, "both"); 249assertTrue(desc.configurable); 250assertFalse(desc.enumerable); 251assertEquals(desc.set, accessorOnlySet.set); 252assertEquals(desc.get, accessorConfigurable.get); 253assertEquals(desc.writable, undefined); 254assertEquals(desc.value, undefined); 255assertEquals(1, obj1.both = 1); 256assertEquals(3, val3); 257 258 259// Data properties 260 261Object.defineProperty(obj1, "foobar", dataConfigurable); 262desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); 263assertEquals(obj1.foobar, 1000); 264assertEquals(desc.value, 1000); 265assertTrue(desc.configurable); 266assertFalse(desc.writable); 267assertFalse(desc.enumerable); 268assertEquals(desc.get, undefined); 269assertEquals(desc.set, undefined); 270//Try writing to non writable attribute - should remain 1000 271obj1.foobar = 1001; 272assertEquals(obj1.foobar, 1000); 273 274 275// Redefine to writable descriptor - now writing to foobar should be allowed. 276Object.defineProperty(obj1, "foobar", dataWritable); 277desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); 278assertEquals(obj1.foobar, 3000); 279assertEquals(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. 282assertTrue(desc.configurable); 283assertTrue(desc.writable); 284assertFalse(desc.enumerable); 285assertEquals(desc.get, undefined); 286assertEquals(desc.set, undefined); 287// Writing to the property should now be allowed 288obj1.foobar = 1001; 289assertEquals(obj1.foobar, 1001); 290 291 292// Redefine with non configurable data property. 293Object.defineProperty(obj1, "foobar", dataNoConfigurable); 294desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); 295assertEquals(obj1.foobar, 2000); 296assertEquals(desc.value, 2000); 297assertFalse(desc.configurable); 298assertTrue(desc.writable); 299assertFalse(desc.enumerable); 300assertEquals(desc.get, undefined); 301assertEquals(desc.set, undefined); 302 303// Try redefine again - shold fail because configurable is now false. 304try { 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. 312try { 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). 321Object.defineProperty(obj1, "foobar", dataNoConfigurable); 322desc = Object.getOwnPropertyDescriptor(obj1, "foobar"); 323assertEquals(obj1.foobar, 2000); 324assertEquals(desc.value, 2000); 325assertFalse(desc.configurable); 326assertTrue(desc.writable); 327assertFalse(desc.enumerable); 328assertEquals(desc.get, undefined); 329assertEquals(desc.set, undefined); 330 331 332// New object 333var obj2 = {}; 334 335// Make accessor - redefine to data 336Object.defineProperty(obj2, "foo", accessorConfigurable); 337 338// Redefine to data property 339Object.defineProperty(obj2, "foo", dataConfigurable); 340desc = Object.getOwnPropertyDescriptor(obj2, "foo"); 341assertEquals(obj2.foo, 1000); 342assertEquals(desc.value, 1000); 343assertTrue(desc.configurable); 344assertFalse(desc.writable); 345assertFalse(desc.enumerable); 346assertEquals(desc.get, undefined); 347assertEquals(desc.set, undefined); 348 349 350// Redefine back to accessor 351Object.defineProperty(obj2, "foo", accessorConfigurable); 352desc = Object.getOwnPropertyDescriptor(obj2, "foo"); 353assertTrue(desc.configurable); 354assertFalse(desc.enumerable); 355assertEquals(desc.writable, undefined); 356assertEquals(desc.get, accessorConfigurable.get); 357assertEquals(desc.set, accessorConfigurable.set); 358assertEquals(desc.value, undefined); 359assertEquals(1, obj2.foo = 1); 360assertEquals(3, val1); 361assertEquals(4, val2); 362assertEquals(3, obj2.foo); 363 364// Make data - redefine to accessor 365Object.defineProperty(obj2, "bar", dataConfigurable) 366 367// Redefine to accessor property 368Object.defineProperty(obj2, "bar", accessorConfigurable); 369desc = Object.getOwnPropertyDescriptor(obj2, "bar"); 370assertTrue(desc.configurable); 371assertFalse(desc.enumerable); 372assertEquals(desc.writable, undefined); 373assertEquals(desc.get, accessorConfigurable.get); 374assertEquals(desc.set, accessorConfigurable.set); 375assertEquals(desc.value, undefined); 376assertEquals(1, obj2.bar = 1); 377assertEquals(4, val1); 378assertEquals(4, val2); 379assertEquals(4, obj2.foo); 380 381// Redefine back to data property 382Object.defineProperty(obj2, "bar", dataConfigurable); 383desc = Object.getOwnPropertyDescriptor(obj2, "bar"); 384assertEquals(obj2.bar, 1000); 385assertEquals(desc.value, 1000); 386assertTrue(desc.configurable); 387assertFalse(desc.writable); 388assertFalse(desc.enumerable); 389assertEquals(desc.get, undefined); 390assertEquals(desc.set, undefined); 391 392 393// Redefinition of an accessor defined using __defineGetter__ and 394// __defineSetter__. 395function get(){return this.x} 396function set(x){this.x=x}; 397 398var obj3 = {x:1000}; 399obj3.__defineGetter__("foo", get); 400obj3.__defineSetter__("foo", set); 401 402desc = Object.getOwnPropertyDescriptor(obj3, "foo"); 403assertTrue(desc.configurable); 404assertTrue(desc.enumerable); 405assertEquals(desc.writable, undefined); 406assertEquals(desc.get, get); 407assertEquals(desc.set, set); 408assertEquals(desc.value, undefined); 409assertEquals(1, obj3.foo = 1); 410assertEquals(1, obj3.x); 411assertEquals(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). 415Object.defineProperty(obj3, "foo", accessorNoConfigurable); 416desc = Object.getOwnPropertyDescriptor(obj3, "foo"); 417assertFalse(desc.configurable); 418assertTrue(desc.enumerable); 419assertEquals(desc.writable, undefined); 420assertEquals(desc.get, accessorNoConfigurable.get); 421assertEquals(desc.set, accessorNoConfigurable.set); 422assertEquals(desc.value, undefined); 423assertEquals(1, obj3.foo = 1); 424assertEquals(5, val2); 425assertEquals(5, obj3.foo); 426 427 428obj3.__defineGetter__("bar", get); 429obj3.__defineSetter__("bar", set); 430 431 432// Redefine back to data property 433Object.defineProperty(obj3, "bar", dataConfigurable); 434desc = Object.getOwnPropertyDescriptor(obj3, "bar"); 435assertEquals(obj3.bar, 1000); 436assertEquals(desc.value, 1000); 437assertTrue(desc.configurable); 438assertFalse(desc.writable); 439assertTrue(desc.enumerable); 440assertEquals(desc.get, undefined); 441assertEquals(desc.set, undefined); 442 443 444var obj4 = {}; 445var func = function (){return 42;}; 446obj4.bar = func; 447assertEquals(42, obj4.bar()); 448 449Object.defineProperty(obj4, "bar", accessorConfigurable); 450desc = Object.getOwnPropertyDescriptor(obj4, "bar"); 451assertTrue(desc.configurable); 452assertTrue(desc.enumerable); 453assertEquals(desc.writable, undefined); 454assertEquals(desc.get, accessorConfigurable.get); 455assertEquals(desc.set, accessorConfigurable.set); 456assertEquals(desc.value, undefined); 457assertEquals(1, obj4.bar = 1); 458assertEquals(5, val1); 459assertEquals(5, obj4.bar); 460 461// Make sure an error is thrown when trying to access to redefined function. 462try { 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. 473try { 474 %DefineOrRedefineAccessorProperty(0, 0, 0, 0, 0); 475} catch (e) { 476 assertTrue(/illegal access/.test(e)); 477} 478 479try { 480 %DefineOrRedefineDataProperty(0, 0, 0, 0); 481} catch (e) { 482 assertTrue(/illegal access/.test(e)); 483} 484 485try { 486 %DefineOrRedefineDataProperty(null, null, null, null); 487} catch (e) { 488 assertTrue(/illegal access/.test(e)); 489} 490 491try { 492 %DefineOrRedefineAccessorProperty(null, null, null, null, null); 493} catch (e) { 494 assertTrue(/illegal access/.test(e)); 495} 496 497try { 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 505try { 506 %DefineOrRedefineAccessorProperty(null, 'foo', func, null, 0); 507} catch (e) { 508 assertTrue(/illegal access/.test(e)); 509} 510 511try { 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 522var obj5 = {}; 523// Enumerable will default to false. 524Object.defineProperty(obj5, 'foo', accessorNoConfigurable); 525desc = 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. 528Object.defineProperty(obj5, 'foo', accessorNoConfigurable); 529 530// Different setter. 531var descDifferent = { 532 configurable:false, 533 enumerable:false, 534 set: setter1, 535 get: getter2 536}; 537 538try { 539 Object.defineProperty(obj5, 'foo', descDifferent); 540 assertTrue(false); 541} catch (e) { 542 assertTrue(/Cannot redefine property/.test(e)); 543} 544 545// Different getter. 546descDifferent = { 547 configurable:false, 548 enumerable:false, 549 set: setter2, 550 get: getter1 551}; 552 553try { 554 Object.defineProperty(obj5, 'foo', descDifferent); 555 assertTrue(false); 556} catch (e) { 557 assertTrue(/Cannot redefine property/.test(e)); 558} 559 560// Different enumerable. 561descDifferent = { 562 configurable:false, 563 enumerable:true, 564 set: setter2, 565 get: getter2 566}; 567 568try { 569 Object.defineProperty(obj5, 'foo', descDifferent); 570 assertTrue(false); 571} catch (e) { 572 assertTrue(/Cannot redefine property/.test(e)); 573} 574 575// Different configurable. 576descDifferent = { 577 configurable:false, 578 enumerable:true, 579 set: setter2, 580 get: getter2 581}; 582 583try { 584 Object.defineProperty(obj5, 'foo', descDifferent); 585 assertTrue(false); 586} catch (e) { 587 assertTrue(/Cannot redefine property/.test(e)); 588} 589 590// No difference. 591descDifferent = { 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. 598Object.defineProperty(obj5, 'foo', descDifferent); 599 600// Make sure that obj5 still holds the original values. 601desc = Object.getOwnPropertyDescriptor(obj5, 'foo'); 602assertEquals(desc.get, getter2); 603assertEquals(desc.set, setter2); 604assertFalse(desc.enumerable); 605assertFalse(desc.configurable); 606 607 608// Also exercise step 6 on data property, writable and enumerable 609// defaults to false. 610Object.defineProperty(obj5, 'bar', dataNoConfigurable); 611 612// Test that redefinition with the same property descriptor is possible 613Object.defineProperty(obj5, 'bar', dataNoConfigurable); 614 615// Different value. 616descDifferent = { 617 configurable:false, 618 enumerable:false, 619 writable: false, 620 value: 1999 621}; 622 623try { 624 Object.defineProperty(obj5, 'bar', descDifferent); 625 assertTrue(false); 626} catch (e) { 627 assertTrue(/Cannot redefine property/.test(e)); 628} 629 630// Different writable. 631descDifferent = { 632 configurable:false, 633 enumerable:false, 634 writable: true, 635 value: 2000 636}; 637 638try { 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. 647descDifferent = { 648 configurable:false, 649 enumerable:true , 650 writable:false, 651 value: 2000 652}; 653 654try { 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. 663descDifferent = { 664 configurable:true, 665 enumerable:false, 666 writable:false, 667 value: 2000 668}; 669 670try { 671 Object.defineProperty(obj5, 'bar', descDifferent); 672 assertTrue(false); 673} catch (e) { 674 assertTrue(/Cannot redefine property/.test(e)); 675} 676 677// No difference. 678descDifferent = { 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. 685Object.defineProperty(obj5, 'bar', descDifferent); 686 687// Make sure that obj5 still holds the original values. 688desc = Object.getOwnPropertyDescriptor(obj5, 'bar'); 689assertEquals(desc.value, 2000); 690assertFalse(desc.writable); 691assertFalse(desc.enumerable); 692assertFalse(desc.configurable); 693 694 695// Make sure that we can't overwrite +0 with -0 and vice versa. 696var descMinusZero = {value: -0, configurable: false}; 697var descPlusZero = {value: +0, configurable: false}; 698 699Object.defineProperty(obj5, 'minuszero', descMinusZero); 700 701// Make sure we can redefine with -0. 702Object.defineProperty(obj5, 'minuszero', descMinusZero); 703 704exception = false; 705try { 706 Object.defineProperty(obj5, 'minuszero', descPlusZero); 707} catch (e) { 708 exception = true; 709 assertTrue(/Cannot redefine property/.test(e)); 710} 711assertTrue(exception); 712 713 714Object.defineProperty(obj5, 'pluszero', descPlusZero); 715 716// Make sure we can redefine with +0. 717Object.defineProperty(obj5, 'pluszero', descPlusZero); 718 719exception = false; 720try { 721 Object.defineProperty(obj5, 'pluszero', descMinusZero); 722} catch (e) { 723 exception = true; 724 assertTrue(/Cannot redefine property/.test(e)); 725} 726assertTrue(exception); 727 728 729var obj6 = {}; 730obj6[1] = 'foo'; 731obj6[2] = 'bar'; 732obj6[3] = '42'; 733obj6[4] = '43'; 734obj6[5] = '44'; 735 736var descElement = { value: 'foobar' }; 737var descElementNonConfigurable = { value: 'barfoo', configurable: false }; 738var descElementNonWritable = { value: 'foofoo', writable: false }; 739var descElementNonEnumerable = { value: 'barbar', enumerable: false }; 740var descElementAllFalse = { value: 'foofalse', 741 configurable: false, 742 writable: false, 743 enumerable: false }; 744 745 746// Redefine existing property. 747Object.defineProperty(obj6, '1', descElement); 748desc = Object.getOwnPropertyDescriptor(obj6, '1'); 749assertEquals(desc.value, 'foobar'); 750assertTrue(desc.writable); 751assertTrue(desc.enumerable); 752assertTrue(desc.configurable); 753 754// Redefine existing property with configurable: false. 755Object.defineProperty(obj6, '2', descElementNonConfigurable); 756desc = Object.getOwnPropertyDescriptor(obj6, '2'); 757assertEquals(desc.value, 'barfoo'); 758assertTrue(desc.writable); 759assertTrue(desc.enumerable); 760assertFalse(desc.configurable); 761 762// Can use defineProperty to change the value of a non 763// configurable property. 764try { 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. 774exception = false; 775try { 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} 782assertTrue(exception); 783 784Object.defineProperty(obj6, '2', descElementNonWritable); 785desc = Object.getOwnPropertyDescriptor(obj6, '2'); 786assertEquals(desc.value, 'foofoo'); 787assertFalse(desc.writable); 788assertTrue(desc.enumerable); 789assertFalse(desc.configurable); 790 791Object.defineProperty(obj6, '3', descElementNonWritable); 792desc = Object.getOwnPropertyDescriptor(obj6, '3'); 793assertEquals(desc.value, 'foofoo'); 794assertFalse(desc.writable); 795assertTrue(desc.enumerable); 796assertTrue(desc.configurable); 797 798// Redefine existing property with configurable: false. 799Object.defineProperty(obj6, '4', descElementNonEnumerable); 800desc = Object.getOwnPropertyDescriptor(obj6, '4'); 801assertEquals(desc.value, 'barbar'); 802assertTrue(desc.writable); 803assertFalse(desc.enumerable); 804assertTrue(desc.configurable); 805 806// Redefine existing property with configurable: false. 807Object.defineProperty(obj6, '5', descElementAllFalse); 808desc = Object.getOwnPropertyDescriptor(obj6, '5'); 809assertEquals(desc.value, 'foofalse'); 810assertFalse(desc.writable); 811assertFalse(desc.enumerable); 812assertFalse(desc.configurable); 813 814// Define non existing property - all attributes should default to false. 815Object.defineProperty(obj6, '15', descElement); 816desc = Object.getOwnPropertyDescriptor(obj6, '15'); 817assertEquals(desc.value, 'foobar'); 818assertFalse(desc.writable); 819assertFalse(desc.enumerable); 820assertFalse(desc.configurable); 821 822// Make sure that we can't redefine using direct access. 823obj6[15] ='overwrite'; 824assertEquals(obj6[15],'foobar'); 825 826 827// Repeat the above tests on an array. 828var arr = new Array(); 829arr[1] = 'foo'; 830arr[2] = 'bar'; 831arr[3] = '42'; 832arr[4] = '43'; 833arr[5] = '44'; 834 835var descElement = { value: 'foobar' }; 836var descElementNonConfigurable = { value: 'barfoo', configurable: false }; 837var descElementNonWritable = { value: 'foofoo', writable: false }; 838var descElementNonEnumerable = { value: 'barbar', enumerable: false }; 839var descElementAllFalse = { value: 'foofalse', 840 configurable: false, 841 writable: false, 842 enumerable: false }; 843 844 845// Redefine existing property. 846Object.defineProperty(arr, '1', descElement); 847desc = Object.getOwnPropertyDescriptor(arr, '1'); 848assertEquals(desc.value, 'foobar'); 849assertTrue(desc.writable); 850assertTrue(desc.enumerable); 851assertTrue(desc.configurable); 852 853// Redefine existing property with configurable: false. 854Object.defineProperty(arr, '2', descElementNonConfigurable); 855desc = Object.getOwnPropertyDescriptor(arr, '2'); 856assertEquals(desc.value, 'barfoo'); 857assertTrue(desc.writable); 858assertTrue(desc.enumerable); 859assertFalse(desc.configurable); 860 861// Can use defineProperty to change the value of a non 862// configurable property of an array. 863try { 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. 873exception = false; 874try { 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} 881assertTrue(exception); 882 883Object.defineProperty(arr, '2', descElementNonWritable); 884desc = Object.getOwnPropertyDescriptor(arr, '2'); 885assertEquals(desc.value, 'foofoo'); 886assertFalse(desc.writable); 887assertTrue(desc.enumerable); 888assertFalse(desc.configurable); 889 890Object.defineProperty(arr, '3', descElementNonWritable); 891desc = Object.getOwnPropertyDescriptor(arr, '3'); 892assertEquals(desc.value, 'foofoo'); 893assertFalse(desc.writable); 894assertTrue(desc.enumerable); 895assertTrue(desc.configurable); 896 897// Redefine existing property with configurable: false. 898Object.defineProperty(arr, '4', descElementNonEnumerable); 899desc = Object.getOwnPropertyDescriptor(arr, '4'); 900assertEquals(desc.value, 'barbar'); 901assertTrue(desc.writable); 902assertFalse(desc.enumerable); 903assertTrue(desc.configurable); 904 905// Redefine existing property with configurable: false. 906Object.defineProperty(arr, '5', descElementAllFalse); 907desc = Object.getOwnPropertyDescriptor(arr, '5'); 908assertEquals(desc.value, 'foofalse'); 909assertFalse(desc.writable); 910assertFalse(desc.enumerable); 911assertFalse(desc.configurable); 912 913// Define non existing property - all attributes should default to false. 914Object.defineProperty(arr, '15', descElement); 915desc = Object.getOwnPropertyDescriptor(arr, '15'); 916assertEquals(desc.value, 'foobar'); 917assertFalse(desc.writable); 918assertFalse(desc.enumerable); 919assertFalse(desc.configurable); 920 921// See issue 968: http://code.google.com/p/v8/issues/detail?id=968 922var o = { x : 42 }; 923Object.defineProperty(o, "x", { writable: false }); 924assertEquals(42, o.x); 925o.x = 37; 926assertEquals(42, o.x); 927 928o = { x : 42 }; 929Object.defineProperty(o, "x", {}); 930assertEquals(42, o.x); 931o.x = 37; 932// Writability is preserved. 933assertEquals(37, o.x); 934 935var o = { }; 936Object.defineProperty(o, "x", { writable: false }); 937assertEquals(undefined, o.x); 938o.x = 37; 939assertEquals(undefined, o.x); 940 941o = { get x() { return 87; } }; 942Object.defineProperty(o, "x", { writable: false }); 943assertEquals(undefined, o.x); 944o.x = 37; 945assertEquals(undefined, o.x); 946 947// Ignore inherited properties. 948o = { __proto__ : { x : 87 } }; 949Object.defineProperty(o, "x", { writable: false }); 950assertEquals(undefined, o.x); 951o.x = 37; 952assertEquals(undefined, o.x); 953 954function 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 973o = { p : 42 }; 974testDefineProperty(o, 'p', 975 { }, 976 { value : 42, writable : true, enumerable : true, configurable : true }); 977 978o = { p : 42 }; 979testDefineProperty(o, 'p', 980 { enumerable : true }, 981 { value : 42, writable : true, enumerable : true, configurable : true }); 982 983o = { p : 42 }; 984testDefineProperty(o, 'p', 985 { configurable : true }, 986 { value : 42, writable : true, enumerable : true, configurable : true }); 987 988o = { p : 42 }; 989testDefineProperty(o, 'p', 990 { enumerable : false }, 991 { value : 42, writable : true, enumerable : false, configurable : true }); 992 993o = { p : 42 }; 994testDefineProperty(o, 'p', 995 { configurable : false }, 996 { value : 42, writable : true, enumerable : true, configurable : false }); 997 998o = { p : 42 }; 999testDefineProperty(o, 'p', 1000 { enumerable : true, configurable : true }, 1001 { value : 42, writable : true, enumerable : true, configurable : true }); 1002 1003o = { p : 42 }; 1004testDefineProperty(o, 'p', 1005 { enumerable : false, configurable : true }, 1006 { value : 42, writable : true, enumerable : false, configurable : true }); 1007 1008o = { p : 42 }; 1009testDefineProperty(o, 'p', 1010 { enumerable : true, configurable : false }, 1011 { value : 42, writable : true, enumerable : true, configurable : false }); 1012 1013o = { p : 42 }; 1014testDefineProperty(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 1019o = { p : 42 }; 1020Object.defineProperty(o, 'p', { configurable: false }); 1021testDefineProperty(o, 'p', 1022 { writable: false }, 1023 { value : 42, writable : false, enumerable : true, configurable : false }); 1024 1025// redefine of get only property with generic descriptor 1026o = {}; 1027Object.defineProperty(o, 'p', 1028 { get : getter1, enumerable: true, configurable: true }); 1029testDefineProperty(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 1034o = {}; 1035Object.defineProperty(o, 'p', 1036 { get: getter1, set: setter1, enumerable: true, configurable: true }); 1037testDefineProperty(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 1042o = {}; 1043Object.defineProperty(o, 'p', 1044 { set : setter1, enumerable: true, configurable: true }); 1045testDefineProperty(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. 1051o = {}; 1052for (var i = 0; i < 1000; i++) { 1053 // Non-enumerable property forces dictionary mode. 1054 Object.defineProperty(o, i, {value: i, enumerable: false}); 1055} 1056assertEquals(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. 1081var objectWithGetter = {}; 1082objectWithGetter.__defineGetter__('foo', function() {}); 1083assertEquals(undefined, objectWithGetter.__lookupSetter__('foo')); 1084 1085var objectWithSetter = {}; 1086objectWithSetter.__defineSetter__('foo', function(x) {}); 1087assertEquals(undefined, objectWithSetter.__lookupGetter__('foo')); 1088