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 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 DefineAccessorPropertyUnchecked - make sure we don't 445// crash. 446try { 447 %DefineAccessorPropertyUnchecked(0, 0, 0, 0, 0); 448} catch (e) { 449 assertTrue(/illegal access/.test(e)); 450} 451 452try { 453 %DefineAccessorPropertyUnchecked(null, null, null, null, null); 454} catch (e) { 455 assertTrue(/illegal access/.test(e)); 456} 457 458// Defining properties null should fail even when we have 459// other allowed values 460try { 461 %DefineAccessorPropertyUnchecked(null, 'foo', func, null, 0); 462} catch (e) { 463 assertTrue(/illegal access/.test(e)); 464} 465 466// Test that all possible differences in step 6 in DefineOwnProperty are 467// exercised, i.e., any difference in the given property descriptor and the 468// existing properties should not return true, but throw an error if the 469// existing configurable property is false. 470 471var obj5 = {}; 472// Enumerable will default to false. 473assertTrue(Reflect.defineProperty(obj5, 'foo', accessorNoConfigurable)); 474desc = Object.getOwnPropertyDescriptor(obj5, 'foo'); 475// First, test that we are actually allowed to set the accessor if all 476// values are of the descriptor are the same as the existing one. 477assertTrue(Reflect.defineProperty(obj5, 'foo', accessorNoConfigurable)); 478 479// Different setter. 480var descDifferent = { 481 configurable:false, 482 enumerable:false, 483 set: setter1, 484 get: getter2 485}; 486 487assertFalse(Reflect.defineProperty(obj5, 'foo', descDifferent)); 488 489// Different getter. 490descDifferent = { 491 configurable:false, 492 enumerable:false, 493 set: setter2, 494 get: getter1 495}; 496 497assertFalse(Reflect.defineProperty(obj5, 'foo', descDifferent)); 498 499// Different enumerable. 500descDifferent = { 501 configurable:false, 502 enumerable:true, 503 set: setter2, 504 get: getter2 505}; 506 507assertFalse(Reflect.defineProperty(obj5, 'foo', descDifferent)); 508 509// Different configurable. 510descDifferent = { 511 configurable:false, 512 enumerable:true, 513 set: setter2, 514 get: getter2 515}; 516 517assertFalse(Reflect.defineProperty(obj5, 'foo', descDifferent)); 518 519// No difference. 520descDifferent = { 521 configurable:false, 522 enumerable:false, 523 set: setter2, 524 get: getter2 525}; 526// Make sure we can still redefine if all properties are the same. 527assertTrue(Reflect.defineProperty(obj5, 'foo', descDifferent)); 528 529// Make sure that obj5 still holds the original values. 530desc = Object.getOwnPropertyDescriptor(obj5, 'foo'); 531assertEquals(desc.get, getter2); 532assertEquals(desc.set, setter2); 533assertFalse(desc.enumerable); 534assertFalse(desc.configurable); 535 536 537// Also exercise step 6 on data property, writable and enumerable 538// defaults to false. 539assertTrue(Reflect.defineProperty(obj5, 'bar', dataNoConfigurable)); 540 541// Test that redefinition with the same property descriptor is possible 542assertTrue(Reflect.defineProperty(obj5, 'bar', dataNoConfigurable)); 543 544// Different value. 545descDifferent = { 546 configurable:false, 547 enumerable:false, 548 writable: false, 549 value: 1999 550}; 551 552assertFalse(Reflect.defineProperty(obj5, 'bar', descDifferent)); 553 554// Different writable. 555descDifferent = { 556 configurable:false, 557 enumerable:false, 558 writable: true, 559 value: 2000 560}; 561 562assertFalse(Reflect.defineProperty(obj5, 'bar', descDifferent)); 563 564 565// Different enumerable. 566descDifferent = { 567 configurable:false, 568 enumerable:true , 569 writable:false, 570 value: 2000 571}; 572 573assertFalse(Reflect.defineProperty(obj5, 'bar', descDifferent)); 574 575 576// Different configurable. 577descDifferent = { 578 configurable:true, 579 enumerable:false, 580 writable:false, 581 value: 2000 582}; 583 584assertFalse(Reflect.defineProperty(obj5, 'bar', descDifferent)); 585 586// No difference. 587descDifferent = { 588 configurable:false, 589 enumerable:false, 590 writable:false, 591 value:2000 592}; 593// Make sure we can still redefine if all properties are the same. 594assertTrue(Reflect.defineProperty(obj5, 'bar', descDifferent)); 595 596// Make sure that obj5 still holds the original values. 597desc = Object.getOwnPropertyDescriptor(obj5, 'bar'); 598assertEquals(desc.value, 2000); 599assertFalse(desc.writable); 600assertFalse(desc.enumerable); 601assertFalse(desc.configurable); 602 603 604// Make sure that we can't overwrite +0 with -0 and vice versa. 605var descMinusZero = {value: -0, configurable: false}; 606var descPlusZero = {value: +0, configurable: false}; 607 608assertTrue(Reflect.defineProperty(obj5, 'minuszero', descMinusZero)); 609 610// Make sure we can redefine with -0. 611assertTrue(Reflect.defineProperty(obj5, 'minuszero', descMinusZero)); 612 613assertFalse(Reflect.defineProperty(obj5, 'minuszero', descPlusZero)); 614 615 616assertTrue(Reflect.defineProperty(obj5, 'pluszero', descPlusZero)); 617 618// Make sure we can redefine with +0. 619assertTrue(Reflect.defineProperty(obj5, 'pluszero', descPlusZero)); 620 621assertFalse(Reflect.defineProperty(obj5, 'pluszero', descMinusZero)); 622 623 624var obj6 = {}; 625obj6[1] = 'foo'; 626obj6[2] = 'bar'; 627obj6[3] = '42'; 628obj6[4] = '43'; 629obj6[5] = '44'; 630 631var descElement = { value: 'foobar' }; 632var descElementNonConfigurable = { value: 'barfoo', configurable: false }; 633var descElementNonWritable = { value: 'foofoo', writable: false }; 634var descElementNonEnumerable = { value: 'barbar', enumerable: false }; 635var descElementAllFalse = { value: 'foofalse', 636 configurable: false, 637 writable: false, 638 enumerable: false }; 639 640 641// Redefine existing property. 642assertTrue(Reflect.defineProperty(obj6, '1', descElement)); 643desc = Object.getOwnPropertyDescriptor(obj6, '1'); 644assertEquals(desc.value, 'foobar'); 645assertTrue(desc.writable); 646assertTrue(desc.enumerable); 647assertTrue(desc.configurable); 648 649// Redefine existing property with configurable: false. 650assertTrue(Reflect.defineProperty(obj6, '2', descElementNonConfigurable)); 651desc = Object.getOwnPropertyDescriptor(obj6, '2'); 652assertEquals(desc.value, 'barfoo'); 653assertTrue(desc.writable); 654assertTrue(desc.enumerable); 655assertFalse(desc.configurable); 656 657// Can use defineProperty to change the value of a non 658// configurable property. 659try { 660 assertTrue(Reflect.defineProperty(obj6, '2', descElement)); 661 desc = Object.getOwnPropertyDescriptor(obj6, '2'); 662 assertEquals(desc.value, 'foobar'); 663} catch (e) { 664 assertUnreachable(); 665} 666 667// Ensure that we can't change the descriptor of a 668// non configurable property. 669var descAccessor = { get: function() { return 0; } }; 670assertFalse(Reflect.defineProperty(obj6, '2', descAccessor)); 671 672assertTrue(Reflect.defineProperty(obj6, '2', descElementNonWritable)); 673desc = Object.getOwnPropertyDescriptor(obj6, '2'); 674assertEquals(desc.value, 'foofoo'); 675assertFalse(desc.writable); 676assertTrue(desc.enumerable); 677assertFalse(desc.configurable); 678 679assertTrue(Reflect.defineProperty(obj6, '3', descElementNonWritable)); 680desc = Object.getOwnPropertyDescriptor(obj6, '3'); 681assertEquals(desc.value, 'foofoo'); 682assertFalse(desc.writable); 683assertTrue(desc.enumerable); 684assertTrue(desc.configurable); 685 686// Redefine existing property with configurable: false. 687assertTrue(Reflect.defineProperty(obj6, '4', descElementNonEnumerable)); 688desc = Object.getOwnPropertyDescriptor(obj6, '4'); 689assertEquals(desc.value, 'barbar'); 690assertTrue(desc.writable); 691assertFalse(desc.enumerable); 692assertTrue(desc.configurable); 693 694// Redefine existing property with configurable: false. 695assertTrue(Reflect.defineProperty(obj6, '5', descElementAllFalse)); 696desc = Object.getOwnPropertyDescriptor(obj6, '5'); 697assertEquals(desc.value, 'foofalse'); 698assertFalse(desc.writable); 699assertFalse(desc.enumerable); 700assertFalse(desc.configurable); 701 702// Define non existing property - all attributes should default to false. 703assertTrue(Reflect.defineProperty(obj6, '15', descElement)); 704desc = Object.getOwnPropertyDescriptor(obj6, '15'); 705assertEquals(desc.value, 'foobar'); 706assertFalse(desc.writable); 707assertFalse(desc.enumerable); 708assertFalse(desc.configurable); 709 710// Make sure that we can't redefine using direct access. 711obj6[15] ='overwrite'; 712assertEquals(obj6[15],'foobar'); 713 714 715// Repeat the above tests on an array. 716var arr = new Array(); 717arr[1] = 'foo'; 718arr[2] = 'bar'; 719arr[3] = '42'; 720arr[4] = '43'; 721arr[5] = '44'; 722 723var descElement = { value: 'foobar' }; 724var descElementNonConfigurable = { value: 'barfoo', configurable: false }; 725var descElementNonWritable = { value: 'foofoo', writable: false }; 726var descElementNonEnumerable = { value: 'barbar', enumerable: false }; 727var descElementAllFalse = { value: 'foofalse', 728 configurable: false, 729 writable: false, 730 enumerable: false }; 731 732 733// Redefine existing property. 734assertTrue(Reflect.defineProperty(arr, '1', descElement)); 735desc = Object.getOwnPropertyDescriptor(arr, '1'); 736assertEquals(desc.value, 'foobar'); 737assertTrue(desc.writable); 738assertTrue(desc.enumerable); 739assertTrue(desc.configurable); 740 741// Redefine existing property with configurable: false. 742assertTrue(Reflect.defineProperty(arr, '2', descElementNonConfigurable)); 743desc = Object.getOwnPropertyDescriptor(arr, '2'); 744assertEquals(desc.value, 'barfoo'); 745assertTrue(desc.writable); 746assertTrue(desc.enumerable); 747assertFalse(desc.configurable); 748 749// Can use defineProperty to change the value of a non 750// configurable property of an array. 751try { 752 assertTrue(Reflect.defineProperty(arr, '2', descElement)); 753 desc = Object.getOwnPropertyDescriptor(arr, '2'); 754 assertEquals(desc.value, 'foobar'); 755} catch (e) { 756 assertUnreachable(); 757} 758 759// Ensure that we can't change the descriptor of a 760// non configurable property. 761var descAccessor = { get: function() { return 0; } }; 762assertFalse(Reflect.defineProperty(arr, '2', descAccessor)); 763 764assertTrue(Reflect.defineProperty(arr, '2', descElementNonWritable)); 765desc = Object.getOwnPropertyDescriptor(arr, '2'); 766assertEquals(desc.value, 'foofoo'); 767assertFalse(desc.writable); 768assertTrue(desc.enumerable); 769assertFalse(desc.configurable); 770 771assertTrue(Reflect.defineProperty(arr, '3', descElementNonWritable)); 772desc = Object.getOwnPropertyDescriptor(arr, '3'); 773assertEquals(desc.value, 'foofoo'); 774assertFalse(desc.writable); 775assertTrue(desc.enumerable); 776assertTrue(desc.configurable); 777 778// Redefine existing property with configurable: false. 779assertTrue(Reflect.defineProperty(arr, '4', descElementNonEnumerable)); 780desc = Object.getOwnPropertyDescriptor(arr, '4'); 781assertEquals(desc.value, 'barbar'); 782assertTrue(desc.writable); 783assertFalse(desc.enumerable); 784assertTrue(desc.configurable); 785 786// Redefine existing property with configurable: false. 787assertTrue(Reflect.defineProperty(arr, '5', descElementAllFalse)); 788desc = Object.getOwnPropertyDescriptor(arr, '5'); 789assertEquals(desc.value, 'foofalse'); 790assertFalse(desc.writable); 791assertFalse(desc.enumerable); 792assertFalse(desc.configurable); 793 794// Define non existing property - all attributes should default to false. 795assertTrue(Reflect.defineProperty(arr, '15', descElement)); 796desc = Object.getOwnPropertyDescriptor(arr, '15'); 797assertEquals(desc.value, 'foobar'); 798assertFalse(desc.writable); 799assertFalse(desc.enumerable); 800assertFalse(desc.configurable); 801 802// Define non-array property, check that .length is unaffected. 803assertEquals(16, arr.length); 804assertTrue(Reflect.defineProperty(arr, '0x20', descElement)); 805assertEquals(16, arr.length); 806 807// See issue 968: http://code.google.com/p/v8/issues/detail?id=968 808var o = { x : 42 }; 809assertTrue(Reflect.defineProperty(o, "x", { writable: false })); 810assertEquals(42, o.x); 811o.x = 37; 812assertEquals(42, o.x); 813 814o = { x : 42 }; 815assertTrue(Reflect.defineProperty(o, "x", {})); 816assertEquals(42, o.x); 817o.x = 37; 818// Writability is preserved. 819assertEquals(37, o.x); 820 821var o = { }; 822assertTrue(Reflect.defineProperty(o, "x", { writable: false })); 823assertEquals(undefined, o.x); 824o.x = 37; 825assertEquals(undefined, o.x); 826 827o = { get x() { return 87; } }; 828assertTrue(Reflect.defineProperty(o, "x", { writable: false })); 829assertEquals(undefined, o.x); 830o.x = 37; 831assertEquals(undefined, o.x); 832 833// Ignore inherited properties. 834o = { __proto__ : { x : 87 } }; 835assertTrue(Reflect.defineProperty(o, "x", { writable: false })); 836assertEquals(undefined, o.x); 837o.x = 37; 838assertEquals(undefined, o.x); 839 840function testDefineProperty(obj, propertyName, desc, resultDesc) { 841 assertTrue(Reflect.defineProperty(obj, propertyName, desc)); 842 var actualDesc = Object.getOwnPropertyDescriptor(obj, propertyName); 843 assertEquals(resultDesc.enumerable, actualDesc.enumerable); 844 assertEquals(resultDesc.configurable, actualDesc.configurable); 845 if (resultDesc.hasOwnProperty('value')) { 846 assertEquals(resultDesc.value, actualDesc.value); 847 assertEquals(resultDesc.writable, actualDesc.writable); 848 assertFalse(resultDesc.hasOwnProperty('get')); 849 assertFalse(resultDesc.hasOwnProperty('set')); 850 } else { 851 assertEquals(resultDesc.get, actualDesc.get); 852 assertEquals(resultDesc.set, actualDesc.set); 853 assertFalse(resultDesc.hasOwnProperty('value')); 854 assertFalse(resultDesc.hasOwnProperty('writable')); 855 } 856} 857 858// tests redefining existing property with a generic descriptor 859o = { p : 42 }; 860testDefineProperty(o, 'p', 861 { }, 862 { value : 42, writable : true, enumerable : true, configurable : true }); 863 864o = { p : 42 }; 865testDefineProperty(o, 'p', 866 { enumerable : true }, 867 { value : 42, writable : true, enumerable : true, configurable : true }); 868 869o = { p : 42 }; 870testDefineProperty(o, 'p', 871 { configurable : true }, 872 { value : 42, writable : true, enumerable : true, configurable : true }); 873 874o = { p : 42 }; 875testDefineProperty(o, 'p', 876 { enumerable : false }, 877 { value : 42, writable : true, enumerable : false, configurable : true }); 878 879o = { p : 42 }; 880testDefineProperty(o, 'p', 881 { configurable : false }, 882 { value : 42, writable : true, enumerable : true, configurable : false }); 883 884o = { p : 42 }; 885testDefineProperty(o, 'p', 886 { enumerable : true, configurable : true }, 887 { value : 42, writable : true, enumerable : true, configurable : true }); 888 889o = { p : 42 }; 890testDefineProperty(o, 'p', 891 { enumerable : false, configurable : true }, 892 { value : 42, writable : true, enumerable : false, configurable : true }); 893 894o = { p : 42 }; 895testDefineProperty(o, 'p', 896 { enumerable : true, configurable : false }, 897 { value : 42, writable : true, enumerable : true, configurable : false }); 898 899o = { p : 42 }; 900testDefineProperty(o, 'p', 901 { enumerable : false, configurable : false }, 902 { value : 42, writable : true, enumerable : false, configurable : false }); 903 904// can make a writable, non-configurable field non-writable 905o = { p : 42 }; 906assertTrue(Reflect.defineProperty(o, 'p', { configurable: false })); 907testDefineProperty(o, 'p', 908 { writable: false }, 909 { value : 42, writable : false, enumerable : true, configurable : false }); 910 911// redefine of get only property with generic descriptor 912o = {}; 913assertTrue(Reflect.defineProperty(o, 'p', 914 { get : getter1, enumerable: true, configurable: true })); 915testDefineProperty(o, 'p', 916 { enumerable : false, configurable : false }, 917 { get: getter1, set: undefined, enumerable : false, configurable : false }); 918 919// redefine of get/set only property with generic descriptor 920o = {}; 921assertTrue(Reflect.defineProperty(o, 'p', 922 { get: getter1, set: setter1, enumerable: true, configurable: true })); 923testDefineProperty(o, 'p', 924 { enumerable : false, configurable : false }, 925 { get: getter1, set: setter1, enumerable : false, configurable : false }); 926 927// redefine of set only property with generic descriptor 928o = {}; 929assertTrue(Reflect.defineProperty(o, 'p', 930 { set : setter1, enumerable: true, configurable: true })); 931testDefineProperty(o, 'p', 932 { enumerable : false, configurable : false }, 933 { get: undefined, set: setter1, enumerable : false, configurable : false }); 934 935 936// Regression test: Ensure that growing dictionaries are not ignored. 937o = {}; 938for (var i = 0; i < 1000; i++) { 939 // Non-enumerable property forces dictionary mode. 940 assertTrue(Reflect.defineProperty(o, i, {value: i, enumerable: false})); 941} 942assertEquals(999, o[999]); 943 944 945// Regression test: Bizzare behavior on non-strict arguments object. 946// TODO(yangguo): Tests disabled, needs investigation! 947/* 948(function test(arg0) { 949 // Here arguments[0] is a fast alias on arg0. 950 Reflect.defineProperty(arguments, "0", { 951 value:1, 952 enumerable:false 953 }); 954 // Here arguments[0] is a slow alias on arg0. 955 Reflect.defineProperty(arguments, "0", { 956 value:2, 957 writable:false 958 }); 959 // Here arguments[0] is no alias at all. 960 Reflect.defineProperty(arguments, "0", { 961 value:3 962 }); 963 assertEquals(2, arg0); 964 assertEquals(3, arguments[0]); 965})(0); 966*/ 967 968// Regression test: We should never observe the hole value. 969var objectWithGetter = {}; 970objectWithGetter.__defineGetter__('foo', function() {}); 971assertEquals(undefined, objectWithGetter.__lookupSetter__('foo')); 972 973var objectWithSetter = {}; 974objectWithSetter.__defineSetter__('foo', function(x) {}); 975assertEquals(undefined, objectWithSetter.__lookupGetter__('foo')); 976 977// An object with a getter on the prototype chain. 978function getter() { return 111; } 979function anotherGetter() { return 222; } 980 981function testGetterOnProto(expected, o) { 982 assertEquals(expected, o.quebec); 983} 984 985obj1 = {}; 986assertTrue( 987 Reflect.defineProperty(obj1, "quebec", { get: getter, configurable: true })); 988obj2 = Object.create(obj1); 989obj3 = Object.create(obj2); 990 991testGetterOnProto(111, obj3); 992testGetterOnProto(111, obj3); 993%OptimizeFunctionOnNextCall(testGetterOnProto); 994testGetterOnProto(111, obj3); 995testGetterOnProto(111, obj3); 996 997assertTrue(Reflect.defineProperty(obj1, "quebec", { get: anotherGetter })); 998 999testGetterOnProto(222, obj3); 1000testGetterOnProto(222, obj3); 1001%OptimizeFunctionOnNextCall(testGetterOnProto); 1002testGetterOnProto(222, obj3); 1003testGetterOnProto(222, obj3); 1004 1005// An object with a setter on the prototype chain. 1006var modifyMe; 1007function setter(x) { modifyMe = x+1; } 1008function anotherSetter(x) { modifyMe = x+2; } 1009 1010function testSetterOnProto(expected, o) { 1011 modifyMe = 333; 1012 o.romeo = 444; 1013 assertEquals(expected, modifyMe); 1014} 1015 1016obj1 = {}; 1017assertTrue( 1018 Reflect.defineProperty(obj1, "romeo", { set: setter, configurable: true })); 1019obj2 = Object.create(obj1); 1020obj3 = Object.create(obj2); 1021 1022testSetterOnProto(445, obj3); 1023testSetterOnProto(445, obj3); 1024%OptimizeFunctionOnNextCall(testSetterOnProto); 1025testSetterOnProto(445, obj3); 1026testSetterOnProto(445, obj3); 1027 1028assertTrue(Reflect.defineProperty(obj1, "romeo", { set: anotherSetter })); 1029 1030testSetterOnProto(446, obj3); 1031testSetterOnProto(446, obj3); 1032%OptimizeFunctionOnNextCall(testSetterOnProto); 1033testSetterOnProto(446, obj3); 1034testSetterOnProto(446, obj3); 1035 1036// Removing a setter on the prototype chain. 1037function testSetterOnProtoStrict(o) { 1038 "use strict"; 1039 o.sierra = 12345; 1040} 1041 1042obj1 = {}; 1043assertTrue(Reflect.defineProperty(obj1, "sierra", 1044 { get: getter, set: setter, configurable: true })); 1045obj2 = Object.create(obj1); 1046obj3 = Object.create(obj2); 1047 1048testSetterOnProtoStrict(obj3); 1049testSetterOnProtoStrict(obj3); 1050%OptimizeFunctionOnNextCall(testSetterOnProtoStrict); 1051testSetterOnProtoStrict(obj3); 1052testSetterOnProtoStrict(obj3); 1053 1054assertTrue(Reflect.defineProperty(obj1, "sierra", 1055 { get: getter, set: undefined, configurable: true })); 1056 1057exception = false; 1058try { 1059 testSetterOnProtoStrict(obj3); 1060} catch (e) { 1061 exception = true; 1062 assertTrue(/which has only a getter/.test(e)); 1063} 1064assertTrue(exception); 1065 1066// Test assignment to a getter-only property on the prototype chain. This makes 1067// sure that crankshaft re-checks its assumptions and doesn't rely only on type 1068// feedback (which would be monomorphic here). 1069 1070function Assign(o) { 1071 o.blubb = 123; 1072} 1073 1074function C() {} 1075 1076Assign(new C); 1077Assign(new C); 1078%OptimizeFunctionOnNextCall(Assign); 1079assertTrue( 1080 Reflect.defineProperty(C.prototype, "blubb", {get: function() {return -42}})); 1081Assign(new C); 1082 1083// Test that changes to the prototype of a simple constructor are not ignored, 1084// even after creating initial instances. 1085function C() { 1086 this.x = 23; 1087} 1088assertEquals(23, new C().x); 1089C.prototype.__defineSetter__('x', function(value) { this.y = 23; }); 1090assertEquals(void 0, new C().x); 1091