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 // Descriptors
     65 var emptyDesc = {};
     66 
     67 var accessorConfigurable = { 
     68     set: function() { val1++; },
     69     get: function() { return val1; },
     70     configurable: true
     71 };
     72 
     73 var accessorNoConfigurable = {
     74     set: function() { val2++; },
     75     get: function() { return val2; },
     76     configurable: false 
     77 };
     78 
     79 var accessorOnlySet = {
     80   set: function() { val3++; },
     81   configurable: true
     82 };
     83 
     84 var accessorOnlyGet = {
     85   get: function() { return val3; },
     86   configurable: true
     87 };
     88 
     89 var accessorDefault = {set: function(){} };
     90 
     91 var dataConfigurable = { value: 1000, configurable: true };
     92 
     93 var dataNoConfigurable = { value: 2000, configurable: false };
     94 
     95 var dataWritable = { value: 3000, writable: true};
     96 
     97 
     98 // Check that we can't add property with undefined attributes.
     99 try {
    100   Object.defineProperty(obj1, "foo", undefined);
    101   assertTrue(false);
    102 } catch (e) {
    103   assertTrue(/must be an object/.test(e));
    104 }
    105 
    106 // Make sure that we can add a property with an empty descriptor and
    107 // that it has the default descriptor values.
    108 Object.defineProperty(obj1, "foo", emptyDesc);
    109 
    110 // foo should be undefined as it has no get, set or value
    111 assertEquals(undefined, obj1.foo);
    112 
    113 // We should, however, be able to retrieve the propertydescriptor which should
    114 // have all default values (according to 8.6.1).
    115 var desc = Object.getOwnPropertyDescriptor(obj1, "foo");
    116 assertFalse(desc.configurable);
    117 assertFalse(desc.enumerable);
    118 assertFalse(desc.writable);
    119 assertEquals(desc.get, undefined);
    120 assertEquals(desc.set, undefined);
    121 assertEquals(desc.value, undefined);
    122 
    123 // Make sure that getOwnPropertyDescriptor does not return a descriptor
    124 // with default values if called with non existing property (otherwise
    125 // the test above is invalid).
    126 desc = Object.getOwnPropertyDescriptor(obj1, "bar");
    127 assertEquals(desc, undefined);
    128 
    129 // Make sure that foo can't be reset (as configurable is false).
    130 try {
    131   Object.defineProperty(obj1, "foo", accessorConfigurable);
    132 } catch (e) {
    133   assertTrue(/Cannot redefine property/.test(e));
    134 }
    135 
    136 
    137 // Accessor properties
    138 
    139 Object.defineProperty(obj1, "bar", accessorConfigurable);
    140 desc = Object.getOwnPropertyDescriptor(obj1, "bar");
    141 assertTrue(desc.configurable);
    142 assertFalse(desc.enumerable);
    143 assertEquals(desc.writable, undefined);
    144 assertEquals(desc.get, accessorConfigurable.get);
    145 assertEquals(desc.set, accessorConfigurable.set);
    146 assertEquals(desc.value, undefined);
    147 assertEquals(1, obj1.bar = 1);
    148 assertEquals(1, val1);
    149 assertEquals(1, obj1.bar = 1);
    150 assertEquals(2, val1);
    151 assertEquals(2, obj1.bar);
    152 
    153 // Redefine bar with non configurable test
    154 Object.defineProperty(obj1, "bar", accessorNoConfigurable);
    155 desc = Object.getOwnPropertyDescriptor(obj1, "bar");
    156 assertFalse(desc.configurable);
    157 assertFalse(desc.enumerable);
    158 assertEquals(desc.writable, undefined);
    159 assertEquals(desc.get, accessorNoConfigurable.get);
    160 assertEquals(desc.set, accessorNoConfigurable.set);
    161 assertEquals(desc.value, undefined);
    162 assertEquals(1, obj1.bar = 1);
    163 assertEquals(2, val1);
    164 assertEquals(1, val2);
    165 assertEquals(1, obj1.bar = 1)
    166 assertEquals(2, val1);
    167 assertEquals(2, val2);
    168 assertEquals(2, obj1.bar);
    169 
    170 // Try to redefine bar again - should fail as configurable is false.
    171 try {
    172   Object.defineProperty(obj1, "bar", accessorConfigurable);
    173   assertTrue(false);
    174 } catch(e) {
    175   assertTrue(/Cannot redefine property/.test(e));
    176 }
    177 
    178 // Try to redefine bar again using the data descriptor - should fail.
    179 try {
    180   Object.defineProperty(obj1, "bar", dataConfigurable);
    181   assertTrue(false);
    182 } catch(e) {
    183   assertTrue(/Cannot redefine property/.test(e));
    184 }
    185 
    186 // Redefine using same descriptor - should succeed.
    187 Object.defineProperty(obj1, "bar", accessorNoConfigurable);
    188 desc = Object.getOwnPropertyDescriptor(obj1, "bar");
    189 assertFalse(desc.configurable);
    190 assertFalse(desc.enumerable);
    191 assertEquals(desc.writable, undefined);
    192 assertEquals(desc.get, accessorNoConfigurable.get);
    193 assertEquals(desc.set, accessorNoConfigurable.set);
    194 assertEquals(desc.value, undefined);
    195 assertEquals(1, obj1.bar = 1);
    196 assertEquals(2, val1);
    197 assertEquals(3, val2);
    198 assertEquals(1, obj1.bar = 1)
    199 assertEquals(2, val1);
    200 assertEquals(4, val2);
    201 assertEquals(4, obj1.bar);
    202 
    203 // Define an accessor that has only a setter
    204 Object.defineProperty(obj1, "setOnly", accessorOnlySet);
    205 desc = Object.getOwnPropertyDescriptor(obj1, "setOnly");
    206 assertTrue(desc.configurable);
    207 assertFalse(desc.enumerable);
    208 assertEquals(desc.set, accessorOnlySet.set);
    209 assertEquals(desc.writable, undefined);
    210 assertEquals(desc.value, undefined);
    211 assertEquals(desc.get, undefined);
    212 assertEquals(1, obj1.setOnly = 1);
    213 assertEquals(1, val3);
    214 
    215 // Add a getter - should not touch the setter
    216 Object.defineProperty(obj1, "setOnly", accessorOnlyGet);
    217 desc = Object.getOwnPropertyDescriptor(obj1, "setOnly");
    218 assertTrue(desc.configurable);
    219 assertFalse(desc.enumerable);
    220 assertEquals(desc.get, accessorOnlyGet.get);
    221 assertEquals(desc.set, accessorOnlySet.set);
    222 assertEquals(desc.writable, undefined);
    223 assertEquals(desc.value, undefined);
    224 assertEquals(1, obj1.setOnly = 1);
    225 assertEquals(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.
    229 Object.defineProperty(obj1, "both", accessorConfigurable);
    230 
    231 Object.defineProperty(obj1, "both", accessorOnlySet);
    232 desc = Object.getOwnPropertyDescriptor(obj1, "both");
    233 assertTrue(desc.configurable);
    234 assertFalse(desc.enumerable);
    235 assertEquals(desc.set, accessorOnlySet.set);
    236 assertEquals(desc.get, accessorConfigurable.get);
    237 assertEquals(desc.writable, undefined);
    238 assertEquals(desc.value, undefined);
    239 assertEquals(1, obj1.both = 1);
    240 assertEquals(3, val3);
    241 
    242 
    243 // Data properties
    244 
    245 Object.defineProperty(obj1, "foobar", dataConfigurable);
    246 desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
    247 assertEquals(obj1.foobar, 1000);
    248 assertEquals(desc.value, 1000);
    249 assertTrue(desc.configurable);
    250 assertFalse(desc.writable);
    251 assertFalse(desc.enumerable);
    252 assertEquals(desc.get, undefined);
    253 assertEquals(desc.set, undefined);
    254 //Try writing to non writable attribute - should remain 1000
    255 obj1.foobar = 1001;
    256 assertEquals(obj1.foobar, 1000);
    257 
    258 
    259 // Redefine to writable descriptor - now writing to foobar should be allowed
    260 Object.defineProperty(obj1, "foobar", dataWritable);
    261 desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
    262 assertEquals(obj1.foobar, 3000);
    263 assertEquals(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.
    266 assertTrue(desc.configurable);
    267 assertTrue(desc.writable);
    268 assertFalse(desc.enumerable);
    269 assertEquals(desc.get, undefined);
    270 assertEquals(desc.set, undefined);
    271 // Writing to the property should now be allowed
    272 obj1.foobar = 1001;
    273 assertEquals(obj1.foobar, 1001);
    274 
    275 
    276 // Redefine with non configurable data property.
    277 Object.defineProperty(obj1, "foobar", dataNoConfigurable);
    278 desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
    279 assertEquals(obj1.foobar, 2000);
    280 assertEquals(desc.value, 2000);
    281 assertFalse(desc.configurable);
    282 assertFalse(desc.writable);
    283 assertFalse(desc.enumerable);
    284 assertEquals(desc.get, undefined);
    285 assertEquals(desc.set, undefined);
    286 
    287 // Try redefine again - shold fail because configurable is now false.
    288 try {
    289   Object.defineProperty(obj1, "foobar", dataConfigurable);
    290   assertTrue(false);
    291 } catch (e) {
    292   assertTrue(/Cannot redefine property/.test(e));
    293 }
    294 
    295 // Try redefine again with accessor property - shold also fail.
    296 try {
    297   Object.defineProperty(obj1, "foobar", dataConfigurable);
    298   assertTrue(false);
    299 } catch (e) {
    300   assertTrue(/Cannot redefine property/.test(e));
    301 }
    302 
    303 
    304 // Redifine with the same descriptor - should succeed (step 6).
    305 Object.defineProperty(obj1, "foobar", dataNoConfigurable);
    306 desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
    307 assertEquals(obj1.foobar, 2000);
    308 assertEquals(desc.value, 2000);
    309 assertFalse(desc.configurable);
    310 assertFalse(desc.writable);
    311 assertFalse(desc.enumerable);
    312 assertEquals(desc.get, undefined);
    313 assertEquals(desc.set, undefined);
    314 
    315 
    316 // New object
    317 var obj2 = {};
    318 
    319 // Make accessor - redefine to data
    320 Object.defineProperty(obj2, "foo", accessorConfigurable);
    321 
    322 // Redefine to data property
    323 Object.defineProperty(obj2, "foo", dataConfigurable);
    324 desc = Object.getOwnPropertyDescriptor(obj2, "foo");
    325 assertEquals(obj2.foo, 1000);
    326 assertEquals(desc.value, 1000);
    327 assertTrue(desc.configurable);
    328 assertFalse(desc.writable);
    329 assertFalse(desc.enumerable);
    330 assertEquals(desc.get, undefined);
    331 assertEquals(desc.set, undefined);
    332 
    333 
    334 // Redefine back to accessor
    335 Object.defineProperty(obj2, "foo", accessorConfigurable);
    336 desc = Object.getOwnPropertyDescriptor(obj2, "foo");
    337 assertTrue(desc.configurable);
    338 assertFalse(desc.enumerable);
    339 assertEquals(desc.writable, undefined);
    340 assertEquals(desc.get, accessorConfigurable.get);
    341 assertEquals(desc.set, accessorConfigurable.set);
    342 assertEquals(desc.value, undefined);
    343 assertEquals(1, obj2.foo = 1);
    344 assertEquals(3, val1);
    345 assertEquals(4, val2);
    346 assertEquals(3, obj2.foo);
    347 
    348 // Make data - redefine to accessor
    349 Object.defineProperty(obj2, "bar", dataConfigurable)
    350 
    351 // Redefine to accessor property
    352 Object.defineProperty(obj2, "bar", accessorConfigurable);
    353 desc = Object.getOwnPropertyDescriptor(obj2, "bar");
    354 assertTrue(desc.configurable);
    355 assertFalse(desc.enumerable);
    356 assertEquals(desc.writable, undefined);
    357 assertEquals(desc.get, accessorConfigurable.get);
    358 assertEquals(desc.set, accessorConfigurable.set);
    359 assertEquals(desc.value, undefined);
    360 assertEquals(1, obj2.bar = 1);
    361 assertEquals(4, val1);
    362 assertEquals(4, val2);
    363 assertEquals(4, obj2.foo);
    364 
    365 // Redefine back to data property
    366 Object.defineProperty(obj2, "bar", dataConfigurable);
    367 desc = Object.getOwnPropertyDescriptor(obj2, "bar");
    368 assertEquals(obj2.bar, 1000);
    369 assertEquals(desc.value, 1000);
    370 assertTrue(desc.configurable);
    371 assertFalse(desc.writable);
    372 assertFalse(desc.enumerable);
    373 assertEquals(desc.get, undefined);
    374 assertEquals(desc.set, undefined);
    375 
    376 
    377 // Redefinition of an accessor defined using __defineGetter__ and 
    378 // __defineSetter__
    379 function get(){return this.x}
    380 function set(x){this.x=x};
    381 
    382 var obj3 = {x:1000};
    383 obj3.__defineGetter__("foo", get);
    384 obj3.__defineSetter__("foo", set);
    385 
    386 desc = Object.getOwnPropertyDescriptor(obj3, "foo");
    387 assertTrue(desc.configurable);
    388 assertTrue(desc.enumerable);
    389 assertEquals(desc.writable, undefined);
    390 assertEquals(desc.get, get);
    391 assertEquals(desc.set, set);
    392 assertEquals(desc.value, undefined);
    393 assertEquals(1, obj3.foo = 1);
    394 assertEquals(1, obj3.x);
    395 assertEquals(1, obj3.foo);
    396 
    397 // Redefine to accessor property (non configurable) - note that enumerable
    398 // which we do not redefine should remain the same (true).
    399 Object.defineProperty(obj3, "foo", accessorNoConfigurable);
    400 desc = Object.getOwnPropertyDescriptor(obj3, "foo");
    401 assertFalse(desc.configurable);
    402 assertTrue(desc.enumerable);
    403 assertEquals(desc.writable, undefined);
    404 assertEquals(desc.get, accessorNoConfigurable.get);
    405 assertEquals(desc.set, accessorNoConfigurable.set);
    406 assertEquals(desc.value, undefined);
    407 assertEquals(1, obj3.foo = 1);
    408 assertEquals(5, val2);
    409 assertEquals(5, obj3.foo);
    410 
    411 
    412 obj3.__defineGetter__("bar", get);
    413 obj3.__defineSetter__("bar", set);
    414 
    415 
    416 // Redefine back to data property
    417 Object.defineProperty(obj3, "bar", dataConfigurable);
    418 desc = Object.getOwnPropertyDescriptor(obj3, "bar");
    419 assertEquals(obj3.bar, 1000);
    420 assertEquals(desc.value, 1000);
    421 assertTrue(desc.configurable);
    422 assertFalse(desc.writable);
    423 assertTrue(desc.enumerable);
    424 assertEquals(desc.get, undefined);
    425 assertEquals(desc.set, undefined);
    426 
    427 
    428 var obj4 = {};
    429 var func = function (){return 42;};
    430 obj4.bar = func;
    431 assertEquals(42, obj4.bar());
    432 
    433 Object.defineProperty(obj4, "bar", accessorConfigurable);
    434 desc = Object.getOwnPropertyDescriptor(obj4, "bar");
    435 assertTrue(desc.configurable);
    436 assertTrue(desc.enumerable);
    437 assertEquals(desc.writable, undefined);
    438 assertEquals(desc.get, accessorConfigurable.get);
    439 assertEquals(desc.set, accessorConfigurable.set);
    440 assertEquals(desc.value, undefined);
    441 assertEquals(1, obj4.bar = 1);
    442 assertEquals(5, val1);
    443 assertEquals(5, obj4.bar);
    444 
    445 // Make sure an error is thrown when trying to access to redefined function
    446 try {
    447   obj4.bar();
    448   assertTrue(false);
    449 } catch (e) {
    450   assertTrue(/is not a function/.test(e));
    451 }
    452 
    453 
    454 // Test runtime calls to DefineOrRedefineDataProperty and
    455 // DefineOrRedefineAccessorProperty - make sure we don't 
    456 // crash
    457 try {
    458   %DefineOrRedefineAccessorProperty(0, 0, 0, 0, 0);
    459 } catch (e) {
    460   assertTrue(/illegal access/.test(e));
    461 }
    462 
    463 try {
    464   %DefineOrRedefineDataProperty(0, 0, 0, 0);
    465 } catch (e) {
    466   assertTrue(/illegal access/.test(e));
    467 }
    468 
    469 try {
    470   %DefineOrRedefineDataProperty(null, null, null, null);
    471 } catch (e) {
    472   assertTrue(/illegal access/.test(e));
    473 }
    474 
    475 try {
    476   %DefineOrRedefineAccessorProperty(null, null, null, null, null);
    477 } catch (e) {
    478   assertTrue(/illegal access/.test(e));
    479 }
    480 
    481 try {
    482   %DefineOrRedefineDataProperty({}, null, null, null);
    483 } catch (e) {
    484   assertTrue(/illegal access/.test(e));
    485 }
    486 
    487 // Defining properties null should fail even when we have
    488 // other allowed values
    489 try {
    490   %DefineOrRedefineAccessorProperty(null, 'foo', 0, func, 0);
    491 } catch (e) {
    492   assertTrue(/illegal access/.test(e));
    493 }
    494 
    495 try {
    496   %DefineOrRedefineDataProperty(null, 'foo', 0, 0);
    497 } catch (e) {
    498   assertTrue(/illegal access/.test(e));
    499 }
    500