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