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
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.
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.
28 // Tests the Object.freeze and Object.isFrozen methods - ES 15.2.3.9 and
31 // Flags: --allow-natives-syntax
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;
38 Object.freeze(non_objects[key]);
41 assertTrue(/Object.freeze called on non-object/.test(e));
43 assertTrue(exception);
46 for (var key in non_objects) {
49 Object.isFrozen(non_objects[key]);
52 assertTrue(/Object.isFrozen called on non-object/.test(e));
54 assertTrue(exception);
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);
64 desc = Object.getOwnPropertyDescriptor(obj, 'z');
65 assertTrue(desc.writable);
66 assertTrue(desc.configurable);
67 assertEquals('foobar', desc.value);
69 assertTrue(Object.isExtensible(obj));
70 assertFalse(Object.isFrozen(obj));
74 // Make sure we are no longer extensible.
75 assertFalse(Object.isExtensible(obj));
76 assertTrue(Object.isFrozen(obj));
79 assertEquals(obj.foo, undefined);
81 desc = Object.getOwnPropertyDescriptor(obj, 'x');
82 assertFalse(desc.writable);
83 assertFalse(desc.configurable);
84 assertEquals(42, desc.value);
86 desc = Object.getOwnPropertyDescriptor(obj, 'z');
87 assertFalse(desc.writable);
88 assertFalse(desc.configurable);
89 assertEquals("foobar", desc.value);
91 // Make sure that even if we try overwrite a value that is not writable, it is
94 assertEquals(42, obj.x);
95 obj.x = { get: function() {return 43}, set: function() {} };
96 assertEquals(42, obj.x);
100 function get() { return 43; };
102 Object.defineProperty(obj2, 'x', { get: get, set: set, configurable: true });
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);
110 assertTrue(Object.isExtensible(obj2));
111 assertFalse(Object.isFrozen(obj2));
113 assertTrue(Object.isFrozen(obj2));
114 assertFalse(Object.isExtensible(obj2));
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);
123 assertEquals(obj2.foo, undefined);
126 // Test freeze on arrays.
127 var arr = new Array(42,43);
129 desc = Object.getOwnPropertyDescriptor(arr, '0');
130 assertTrue(desc.configurable);
131 assertTrue(desc.writable);
132 assertEquals(42, desc.value);
134 desc = Object.getOwnPropertyDescriptor(arr, '1');
135 assertTrue(desc.configurable);
136 assertTrue(desc.writable);
137 assertEquals(43, desc.value);
139 assertTrue(Object.isExtensible(arr));
140 assertFalse(Object.isFrozen(arr));
142 assertTrue(Object.isFrozen(arr));
143 assertFalse(Object.isExtensible(arr));
145 desc = Object.getOwnPropertyDescriptor(arr, '0');
146 assertFalse(desc.configurable);
147 assertFalse(desc.writable);
148 assertEquals(42, desc.value);
150 desc = Object.getOwnPropertyDescriptor(arr, '1');
151 assertFalse(desc.configurable);
152 assertFalse(desc.writable);
153 assertEquals(43, desc.value);
157 assertEquals(arr[0], 42);
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' };
165 assertFalse(Object.isFrozen(obj3));
167 Object.defineProperty(obj3, 'x', {configurable: false, writable: false});
168 Object.defineProperty(obj3, 'y', {configurable: false, writable: false});
169 Object.preventExtensions(obj3);
171 assertTrue(Object.isFrozen(obj3));
174 // Make sure that an object that has only non-configurable, but one
175 // writable property, is not classified as frozen.
177 Object.defineProperty(obj4, 'x', {configurable: false, writable: true});
178 Object.defineProperty(obj4, 'y', {configurable: false, writable: false});
179 Object.preventExtensions(obj4);
181 assertFalse(Object.isFrozen(obj4));
183 // Make sure that an object that has only non-writable, but one
184 // configurable property, is not classified as frozen.
186 Object.defineProperty(obj5, 'x', {configurable: true, writable: false});
187 Object.defineProperty(obj5, 'y', {configurable: false, writable: false});
188 Object.preventExtensions(obj5);
190 assertFalse(Object.isFrozen(obj5));
192 // Make sure that Object.freeze returns the frozen object.
194 assertTrue(obj6 === Object.freeze(obj6))
196 // Test that the enumerable attribute is unperturbed by freezing.
197 obj = { x: 42, y: 'foo' };
198 Object.defineProperty(obj, 'y', {enumerable: false});
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);
206 // Fast properties should remain fast
207 obj = { x: 42, y: 'foo' };
208 assertTrue(%HasFastProperties(obj));
210 assertTrue(Object.isFrozen(obj));
211 assertTrue(%HasFastProperties(obj));
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));
219 assertTrue(Object.isFrozen(obj));
220 assertTrue(Object.isFrozen(obj2));
221 assertTrue(%HaveSameMap(obj, obj2));
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));
229 assertTrue(Object.isFrozen(obj));
230 assertTrue(Object.isFrozen(obj2));
231 assertTrue(%HaveSameMap(obj, obj2));
233 // Setting elements after freezing should not be allowed
234 obj = { prop: 'thing' };
236 assertTrue(Object.isFrozen(obj));
238 assertFalse(obj.hasOwnProperty(0));
240 // Freezing an object in dictionary mode should work
241 // Also testing that getter/setter properties work after freezing
243 for (var i = 0; i < 100; ++i) {
246 var accessorDidRun = false;
247 Object.defineProperty(obj, 'accessor', {
248 get: function() { return 42 },
249 set: function() { accessorDidRun = true },
254 assertFalse(%HasFastProperties(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);
264 assertEquals(42, obj.accessor);
265 assertFalse(accessorDidRun);
266 obj.accessor = 'ignored value';
267 assertTrue(accessorDidRun);
269 // Freezing arguments should work
270 var func = function(arg) {
271 Object.freeze(arguments);
272 assertTrue(Object.isFrozen(arguments));
274 func('hello', 'world');
275 func('goodbye', 'world');
277 // Freezing sparse arrays
278 var sparseArr = [0, 1];
279 sparseArr[10000] = 10000;
280 Object.freeze(sparseArr);
281 assertTrue(Object.isFrozen(sparseArr));
283 // Accessors on fast object should behavior properly after freezing
285 Object.defineProperty(obj, 'accessor', {
286 get: function() { return 42 },
287 set: function() { accessorDidRun = true },
291 assertTrue(%HasFastProperties(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);
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";})));
304 // Also test a simpler case
306 Object.defineProperty(obj, 'accessor', {
307 get: function() { return 42 },
308 set: function() { accessorDidRun = true },
313 assertTrue(%HasFastProperties(obj));
315 assertTrue(%HasFastProperties(obj));
316 assertTrue(Object.isFrozen(obj));
318 // Test array built-in functions with freeze.
321 // if frozen implies sealed, then the tests in object-seal.js are mostly
323 assertTrue(Object.isSealed(obj));
325 // Verify that the length can't be written by builtins.
326 assertThrows(function() { obj.push(); }, TypeError);
327 assertThrows(function() { obj.unshift(); }, TypeError);
328 assertThrows(function() { obj.splice(0,0); }, TypeError);
329 assertTrue(Object.isFrozen(obj));
331 // Verify that an item can't be changed with splice.
332 assertThrows(function() { obj.splice(0,1,1); }, TypeError);
333 assertTrue(Object.isFrozen(obj));
335 // Verify that unshift() with no arguments will fail if it reifies from
336 // the prototype into the object.
338 obj.__proto__[1] = 1;
339 assertEquals(1, obj[1]);
341 assertThrows(function() { obj.unshift(); }, TypeError);