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.freeze and Object.isFrozen methods - ES 15.2.3.9 and
     29 // ES 15.2.3.12
     30 
     31 // Flags: --allow-natives-syntax
     32 
     33 // Test that we throw an error if an object is not passed as argument.
     34 var non_objects = new Array(undefined, null, 1, -1, 0, 42.43);
     35 for (var key in non_objects) {
     36   var exception = false;
     37   try {
     38     Object.freeze(non_objects[key]);
     39   } catch(e) {
     40     exception = true;
     41     assertTrue(/Object.freeze called on non-object/.test(e));
     42   }
     43   assertTrue(exception);
     44 }
     45 
     46 for (var key in non_objects) {
     47   exception = false;
     48   try {
     49     Object.isFrozen(non_objects[key]);
     50   } catch(e) {
     51     exception = true;
     52     assertTrue(/Object.isFrozen called on non-object/.test(e));
     53   }
     54   assertTrue(exception);
     55 }
     56 
     57 // Test normal data properties.
     58 var obj = { x: 42, z: 'foobar' };
     59 var desc = Object.getOwnPropertyDescriptor(obj, 'x');
     60 assertTrue(desc.writable);
     61 assertTrue(desc.configurable);
     62 assertEquals(42, desc.value);
     63 
     64 desc = Object.getOwnPropertyDescriptor(obj, 'z');
     65 assertTrue(desc.writable);
     66 assertTrue(desc.configurable);
     67 assertEquals('foobar', desc.value);
     68 
     69 assertTrue(Object.isExtensible(obj));
     70 assertFalse(Object.isFrozen(obj));
     71 
     72 Object.freeze(obj);
     73 
     74 // Make sure we are no longer extensible.
     75 assertFalse(Object.isExtensible(obj));
     76 assertTrue(Object.isFrozen(obj));
     77 
     78 obj.foo = 42;
     79 assertEquals(obj.foo, undefined);
     80 
     81 desc = Object.getOwnPropertyDescriptor(obj, 'x');
     82 assertFalse(desc.writable);
     83 assertFalse(desc.configurable);
     84 assertEquals(42, desc.value);
     85 
     86 desc = Object.getOwnPropertyDescriptor(obj, 'z');
     87 assertFalse(desc.writable);
     88 assertFalse(desc.configurable);
     89 assertEquals("foobar", desc.value);
     90 
     91 // Make sure that even if we try overwrite a value that is not writable, it is
     92 // not changed.
     93 obj.x = "tete";
     94 assertEquals(42, obj.x);
     95 obj.x = { get: function() {return 43}, set: function() {} };
     96 assertEquals(42, obj.x);
     97 
     98 // Test on accessors.
     99 var obj2 = {};
    100 function get() { return 43; };
    101 function set() {};
    102 Object.defineProperty(obj2, 'x', { get: get, set: set, configurable: true });
    103 
    104 desc = Object.getOwnPropertyDescriptor(obj2, 'x');
    105 assertTrue(desc.configurable);
    106 assertEquals(undefined, desc.value);
    107 assertEquals(set, desc.set);
    108 assertEquals(get, desc.get);
    109 
    110 assertTrue(Object.isExtensible(obj2));
    111 assertFalse(Object.isFrozen(obj2));
    112 Object.freeze(obj2);
    113 assertTrue(Object.isFrozen(obj2));
    114 assertFalse(Object.isExtensible(obj2));
    115 
    116 desc = Object.getOwnPropertyDescriptor(obj2, 'x');
    117 assertFalse(desc.configurable);
    118 assertEquals(undefined, desc.value);
    119 assertEquals(set, desc.set);
    120 assertEquals(get, desc.get);
    121 
    122 obj2.foo = 42;
    123 assertEquals(obj2.foo, undefined);
    124 
    125 
    126 // Test freeze on arrays.
    127 var arr = new Array(42,43);
    128 
    129 desc = Object.getOwnPropertyDescriptor(arr, '0');
    130 assertTrue(desc.configurable);
    131 assertTrue(desc.writable);
    132 assertEquals(42, desc.value);
    133 
    134 desc = Object.getOwnPropertyDescriptor(arr, '1');
    135 assertTrue(desc.configurable);
    136 assertTrue(desc.writable);
    137 assertEquals(43, desc.value);
    138 
    139 assertTrue(Object.isExtensible(arr));
    140 assertFalse(Object.isFrozen(arr));
    141 Object.freeze(arr);
    142 assertTrue(Object.isFrozen(arr));
    143 assertFalse(Object.isExtensible(arr));
    144 
    145 desc = Object.getOwnPropertyDescriptor(arr, '0');
    146 assertFalse(desc.configurable);
    147 assertFalse(desc.writable);
    148 assertEquals(42, desc.value);
    149 
    150 desc = Object.getOwnPropertyDescriptor(arr, '1');
    151 assertFalse(desc.configurable);
    152 assertFalse(desc.writable);
    153 assertEquals(43, desc.value);
    154 
    155 arr[0] = 'foo';
    156 
    157 assertEquals(arr[0], 42);
    158 
    159 
    160 // Test that isFrozen return the correct value even if configurable has been set
    161 // to false on all properties manually and the extensible flag has also been set
    162 // to false manually.
    163 var obj3 = { x: 42, y: 'foo' };
    164 
    165 assertFalse(Object.isFrozen(obj3));
    166 
    167 Object.defineProperty(obj3, 'x', {configurable: false, writable: false});
    168 Object.defineProperty(obj3, 'y', {configurable: false, writable: false});
    169 Object.preventExtensions(obj3);
    170 
    171 assertTrue(Object.isFrozen(obj3));
    172 
    173 
    174 // Make sure that an object that has only non-configurable, but one
    175 // writable property, is not classified as frozen.
    176 var obj4 = {};
    177 Object.defineProperty(obj4, 'x', {configurable: false, writable: true});
    178 Object.defineProperty(obj4, 'y', {configurable: false, writable: false});
    179 Object.preventExtensions(obj4);
    180 
    181 assertFalse(Object.isFrozen(obj4));
    182 
    183 // Make sure that an object that has only non-writable, but one
    184 // configurable property, is not classified as frozen.
    185 var obj5 = {};
    186 Object.defineProperty(obj5, 'x', {configurable: true, writable: false});
    187 Object.defineProperty(obj5, 'y', {configurable: false, writable: false});
    188 Object.preventExtensions(obj5);
    189 
    190 assertFalse(Object.isFrozen(obj5));
    191 
    192 // Make sure that Object.freeze returns the frozen object.
    193 var obj6 = {}
    194 assertTrue(obj6 === Object.freeze(obj6))
    195 
    196 // Test that the enumerable attribute is unperturbed by freezing.
    197 obj = { x: 42, y: 'foo' };
    198 Object.defineProperty(obj, 'y', {enumerable: false});
    199 Object.freeze(obj);
    200 assertTrue(Object.isFrozen(obj));
    201 desc = Object.getOwnPropertyDescriptor(obj, 'x');
    202 assertTrue(desc.enumerable);
    203 desc = Object.getOwnPropertyDescriptor(obj, 'y');
    204 assertFalse(desc.enumerable);
    205 
    206 // Fast properties should remain fast
    207 obj = { x: 42, y: 'foo' };
    208 assertTrue(%HasFastProperties(obj));
    209 Object.freeze(obj);
    210 assertTrue(Object.isFrozen(obj));
    211 assertTrue(%HasFastProperties(obj));
    212 
    213 // Frozen objects should share maps where possible
    214 obj = { prop1: 1, prop2: 2 };
    215 obj2 = { prop1: 3, prop2: 4 };
    216 assertTrue(%HaveSameMap(obj, obj2));
    217 Object.freeze(obj);
    218 Object.freeze(obj2);
    219 assertTrue(Object.isFrozen(obj));
    220 assertTrue(Object.isFrozen(obj2));
    221 assertTrue(%HaveSameMap(obj, obj2));
    222 
    223 // Frozen objects should share maps even when they have elements
    224 obj = { prop1: 1, prop2: 2, 75: 'foo' };
    225 obj2 = { prop1: 3, prop2: 4, 150: 'bar' };
    226 assertTrue(%HaveSameMap(obj, obj2));
    227 Object.freeze(obj);
    228 Object.freeze(obj2);
    229 assertTrue(Object.isFrozen(obj));
    230 assertTrue(Object.isFrozen(obj2));
    231 assertTrue(%HaveSameMap(obj, obj2));
    232 
    233 // Setting elements after freezing should not be allowed
    234 obj = { prop: 'thing' };
    235 Object.freeze(obj);
    236 assertTrue(Object.isFrozen(obj));
    237 obj[0] = 'hello';
    238 assertFalse(obj.hasOwnProperty(0));
    239 
    240 // Freezing an object in dictionary mode should work
    241 // Also testing that getter/setter properties work after freezing
    242 obj = { };
    243 for (var i = 0; i < 100; ++i) {
    244   obj['x' + i] = i;
    245 }
    246 var accessorDidRun = false;
    247 Object.defineProperty(obj, 'accessor', {
    248   get: function() { return 42 },
    249   set: function() { accessorDidRun = true },
    250   configurable: true,
    251   enumerable: true
    252 });
    253 
    254 assertFalse(%HasFastProperties(obj));
    255 Object.freeze(obj);
    256 assertFalse(%HasFastProperties(obj));
    257 assertTrue(Object.isFrozen(obj));
    258 assertFalse(Object.isExtensible(obj));
    259 for (var i = 0; i < 100; ++i) {
    260   desc = Object.getOwnPropertyDescriptor(obj, 'x' + i);
    261   assertFalse(desc.writable);
    262   assertFalse(desc.configurable);
    263 }
    264 assertEquals(42, obj.accessor);
    265 assertFalse(accessorDidRun);
    266 obj.accessor = 'ignored value';
    267 assertTrue(accessorDidRun);
    268 
    269 // Freezing arguments should work
    270 var func = function(arg) {
    271   Object.freeze(arguments);
    272   assertTrue(Object.isFrozen(arguments));
    273 };
    274 func('hello', 'world');
    275 func('goodbye', 'world');
    276 
    277 // Freezing sparse arrays
    278 var sparseArr = [0, 1];
    279 sparseArr[10000] = 10000;
    280 Object.freeze(sparseArr);
    281 assertTrue(Object.isFrozen(sparseArr));
    282 
    283 // Accessors on fast object should behavior properly after freezing
    284 obj = {};
    285 Object.defineProperty(obj, 'accessor', {
    286   get: function() { return 42 },
    287   set: function() { accessorDidRun = true },
    288   configurable: true,
    289   enumerable: true
    290 });
    291 assertTrue(%HasFastProperties(obj));
    292 Object.freeze(obj);
    293 assertTrue(Object.isFrozen(obj));
    294 assertTrue(%HasFastProperties(obj));
    295 assertEquals(42, obj.accessor);
    296 accessorDidRun = false;
    297 obj.accessor = 'ignored value';
    298 assertTrue(accessorDidRun);
    299 
    300 // Test for regression in mixed accessor/data property objects.
    301 // The strict function is one such object.
    302 assertTrue(Object.isFrozen(Object.freeze(function(){"use strict";})));
    303 
    304 // Also test a simpler case
    305 obj = {};
    306 Object.defineProperty(obj, 'accessor', {
    307   get: function() { return 42 },
    308   set: function() { accessorDidRun = true },
    309   configurable: true,
    310   enumerable: true
    311 });
    312 obj.data = 'foo';
    313 assertTrue(%HasFastProperties(obj));
    314 Object.freeze(obj);
    315 assertTrue(%HasFastProperties(obj));
    316 assertTrue(Object.isFrozen(obj));
    317 
    318 // Test array built-in functions with freeze.
    319 obj = [1,2,3];
    320 Object.freeze(obj);
    321 // if frozen implies sealed, then the tests in object-seal.js are mostly
    322 // sufficient.
    323 assertTrue(Object.isSealed(obj));
    324 
    325 assertDoesNotThrow(function() { obj.push(); });
    326 assertDoesNotThrow(function() { obj.unshift(); });
    327 assertDoesNotThrow(function() { obj.splice(0,0); });
    328 assertTrue(Object.isFrozen(obj));
    329 
    330 // Verify that an item can't be changed with splice.
    331 assertThrows(function() { obj.splice(0,1,1); }, TypeError);
    332 
    333 // Verify that unshift() with no arguments will fail if it reifies from
    334 // the prototype into the object.
    335 obj = [1,,3];
    336 obj.__proto__[1] = 1;
    337 assertEquals(1, obj[1]);
    338 Object.freeze(obj);
    339 assertThrows(function() { obj.unshift(); }, TypeError);
    340