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