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