blob: 56e67c3c23ae69758a3b0ac96e00ad1b0c84749c [file] [log] [blame]
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001// Copyright 2012 the V8 project authors. All rights reserved.
ager@chromium.org5c838252010-02-19 08:53:10 +00002// 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
svenpanne@chromium.org619781a2012-07-05 08:22:44 +000030// Flags: --allow-natives-syntax --es5-readonly
ager@chromium.org5c838252010-02-19 08:53:10 +000031
32// Check that an exception is thrown when null is passed as object.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000033var exception = false;
ager@chromium.org5c838252010-02-19 08:53:10 +000034try {
35 Object.defineProperty(null, null, null);
ager@chromium.org5c838252010-02-19 08:53:10 +000036} catch (e) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000037 exception = true;
ager@chromium.org5c838252010-02-19 08:53:10 +000038 assertTrue(/called on non-object/.test(e));
39}
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000040assertTrue(exception);
ager@chromium.org5c838252010-02-19 08:53:10 +000041
42// Check that an exception is thrown when undefined is passed as object.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000043exception = false;
ager@chromium.org5c838252010-02-19 08:53:10 +000044try {
45 Object.defineProperty(undefined, undefined, undefined);
ager@chromium.org5c838252010-02-19 08:53:10 +000046} catch (e) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000047 exception = true;
ager@chromium.org5c838252010-02-19 08:53:10 +000048 assertTrue(/called on non-object/.test(e));
49}
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000050assertTrue(exception);
ager@chromium.org5c838252010-02-19 08:53:10 +000051
52// Check that an exception is thrown when non-object is passed as object.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000053exception = false;
ager@chromium.org5c838252010-02-19 08:53:10 +000054try {
55 Object.defineProperty(0, "foo", undefined);
ager@chromium.org5c838252010-02-19 08:53:10 +000056} catch (e) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000057 exception = true;
ager@chromium.org5c838252010-02-19 08:53:10 +000058 assertTrue(/called on non-object/.test(e));
59}
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000060assertTrue(exception);
ager@chromium.org5c838252010-02-19 08:53:10 +000061
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000062// Object.
ager@chromium.org5c838252010-02-19 08:53:10 +000063var obj1 = {};
64
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000065// Values.
ager@chromium.org5c838252010-02-19 08:53:10 +000066var val1 = 0;
67var val2 = 0;
68var val3 = 0;
69
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000070function setter1() {val1++; }
71function getter1() {return val1; }
72
73function setter2() {val2++; }
74function getter2() {return val2; }
75
76function setter3() {val3++; }
77function getter3() {return val3; }
78
79
80// Descriptors.
ager@chromium.org5c838252010-02-19 08:53:10 +000081var emptyDesc = {};
82
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000083var accessorConfigurable = {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000084 set: setter1,
85 get: getter1,
ager@chromium.org5c838252010-02-19 08:53:10 +000086 configurable: true
87};
88
89var accessorNoConfigurable = {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000090 set: setter2,
91 get: getter2,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000092 configurable: false
ager@chromium.org5c838252010-02-19 08:53:10 +000093};
94
95var accessorOnlySet = {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000096 set: setter3,
ager@chromium.org5c838252010-02-19 08:53:10 +000097 configurable: true
98};
99
100var accessorOnlyGet = {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000101 get: getter3,
ager@chromium.org5c838252010-02-19 08:53:10 +0000102 configurable: true
103};
104
105var accessorDefault = {set: function(){} };
106
107var dataConfigurable = { value: 1000, configurable: true };
108
109var dataNoConfigurable = { value: 2000, configurable: false };
110
111var dataWritable = { value: 3000, writable: true};
112
113
114// Check that we can't add property with undefined attributes.
115try {
116 Object.defineProperty(obj1, "foo", undefined);
117 assertTrue(false);
118} catch (e) {
119 assertTrue(/must be an object/.test(e));
120}
121
122// Make sure that we can add a property with an empty descriptor and
123// that it has the default descriptor values.
124Object.defineProperty(obj1, "foo", emptyDesc);
125
126// foo should be undefined as it has no get, set or value
127assertEquals(undefined, obj1.foo);
128
129// We should, however, be able to retrieve the propertydescriptor which should
130// have all default values (according to 8.6.1).
131var desc = Object.getOwnPropertyDescriptor(obj1, "foo");
132assertFalse(desc.configurable);
133assertFalse(desc.enumerable);
134assertFalse(desc.writable);
135assertEquals(desc.get, undefined);
136assertEquals(desc.set, undefined);
137assertEquals(desc.value, undefined);
138
139// Make sure that getOwnPropertyDescriptor does not return a descriptor
140// with default values if called with non existing property (otherwise
141// the test above is invalid).
142desc = Object.getOwnPropertyDescriptor(obj1, "bar");
143assertEquals(desc, undefined);
144
145// Make sure that foo can't be reset (as configurable is false).
146try {
147 Object.defineProperty(obj1, "foo", accessorConfigurable);
148} catch (e) {
149 assertTrue(/Cannot redefine property/.test(e));
150}
151
152
153// Accessor properties
154
155Object.defineProperty(obj1, "bar", accessorConfigurable);
156desc = Object.getOwnPropertyDescriptor(obj1, "bar");
157assertTrue(desc.configurable);
158assertFalse(desc.enumerable);
159assertEquals(desc.writable, undefined);
160assertEquals(desc.get, accessorConfigurable.get);
161assertEquals(desc.set, accessorConfigurable.set);
162assertEquals(desc.value, undefined);
163assertEquals(1, obj1.bar = 1);
164assertEquals(1, val1);
165assertEquals(1, obj1.bar = 1);
166assertEquals(2, val1);
167assertEquals(2, obj1.bar);
168
169// Redefine bar with non configurable test
170Object.defineProperty(obj1, "bar", accessorNoConfigurable);
171desc = Object.getOwnPropertyDescriptor(obj1, "bar");
172assertFalse(desc.configurable);
173assertFalse(desc.enumerable);
174assertEquals(desc.writable, undefined);
175assertEquals(desc.get, accessorNoConfigurable.get);
176assertEquals(desc.set, accessorNoConfigurable.set);
177assertEquals(desc.value, undefined);
178assertEquals(1, obj1.bar = 1);
179assertEquals(2, val1);
180assertEquals(1, val2);
181assertEquals(1, obj1.bar = 1)
182assertEquals(2, val1);
183assertEquals(2, val2);
184assertEquals(2, obj1.bar);
185
186// Try to redefine bar again - should fail as configurable is false.
187try {
188 Object.defineProperty(obj1, "bar", accessorConfigurable);
189 assertTrue(false);
190} catch(e) {
191 assertTrue(/Cannot redefine property/.test(e));
192}
193
194// Try to redefine bar again using the data descriptor - should fail.
195try {
196 Object.defineProperty(obj1, "bar", dataConfigurable);
197 assertTrue(false);
198} catch(e) {
199 assertTrue(/Cannot redefine property/.test(e));
200}
201
202// Redefine using same descriptor - should succeed.
203Object.defineProperty(obj1, "bar", accessorNoConfigurable);
204desc = Object.getOwnPropertyDescriptor(obj1, "bar");
205assertFalse(desc.configurable);
206assertFalse(desc.enumerable);
207assertEquals(desc.writable, undefined);
208assertEquals(desc.get, accessorNoConfigurable.get);
209assertEquals(desc.set, accessorNoConfigurable.set);
210assertEquals(desc.value, undefined);
211assertEquals(1, obj1.bar = 1);
212assertEquals(2, val1);
213assertEquals(3, val2);
214assertEquals(1, obj1.bar = 1)
215assertEquals(2, val1);
216assertEquals(4, val2);
217assertEquals(4, obj1.bar);
218
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000219// Define an accessor that has only a setter.
ager@chromium.org5c838252010-02-19 08:53:10 +0000220Object.defineProperty(obj1, "setOnly", accessorOnlySet);
221desc = Object.getOwnPropertyDescriptor(obj1, "setOnly");
222assertTrue(desc.configurable);
223assertFalse(desc.enumerable);
224assertEquals(desc.set, accessorOnlySet.set);
225assertEquals(desc.writable, undefined);
226assertEquals(desc.value, undefined);
227assertEquals(desc.get, undefined);
228assertEquals(1, obj1.setOnly = 1);
229assertEquals(1, val3);
230
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000231// Add a getter - should not touch the setter.
ager@chromium.org5c838252010-02-19 08:53:10 +0000232Object.defineProperty(obj1, "setOnly", accessorOnlyGet);
233desc = Object.getOwnPropertyDescriptor(obj1, "setOnly");
234assertTrue(desc.configurable);
235assertFalse(desc.enumerable);
236assertEquals(desc.get, accessorOnlyGet.get);
237assertEquals(desc.set, accessorOnlySet.set);
238assertEquals(desc.writable, undefined);
239assertEquals(desc.value, undefined);
240assertEquals(1, obj1.setOnly = 1);
241assertEquals(2, val3);
242
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000243// The above should also work if redefining just a getter or setter on
ager@chromium.org5c838252010-02-19 08:53:10 +0000244// an existing property with both a getter and a setter.
245Object.defineProperty(obj1, "both", accessorConfigurable);
246
247Object.defineProperty(obj1, "both", accessorOnlySet);
248desc = Object.getOwnPropertyDescriptor(obj1, "both");
249assertTrue(desc.configurable);
250assertFalse(desc.enumerable);
251assertEquals(desc.set, accessorOnlySet.set);
252assertEquals(desc.get, accessorConfigurable.get);
253assertEquals(desc.writable, undefined);
254assertEquals(desc.value, undefined);
255assertEquals(1, obj1.both = 1);
256assertEquals(3, val3);
257
258
259// Data properties
260
261Object.defineProperty(obj1, "foobar", dataConfigurable);
262desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
263assertEquals(obj1.foobar, 1000);
264assertEquals(desc.value, 1000);
265assertTrue(desc.configurable);
266assertFalse(desc.writable);
267assertFalse(desc.enumerable);
268assertEquals(desc.get, undefined);
269assertEquals(desc.set, undefined);
270//Try writing to non writable attribute - should remain 1000
271obj1.foobar = 1001;
272assertEquals(obj1.foobar, 1000);
273
274
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000275// Redefine to writable descriptor - now writing to foobar should be allowed.
ager@chromium.org5c838252010-02-19 08:53:10 +0000276Object.defineProperty(obj1, "foobar", dataWritable);
277desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
278assertEquals(obj1.foobar, 3000);
279assertEquals(desc.value, 3000);
280// Note that since dataWritable does not define configurable the configurable
281// setting from the redefined property (in this case true) is used.
282assertTrue(desc.configurable);
283assertTrue(desc.writable);
284assertFalse(desc.enumerable);
285assertEquals(desc.get, undefined);
286assertEquals(desc.set, undefined);
287// Writing to the property should now be allowed
288obj1.foobar = 1001;
289assertEquals(obj1.foobar, 1001);
290
291
292// Redefine with non configurable data property.
293Object.defineProperty(obj1, "foobar", dataNoConfigurable);
294desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
295assertEquals(obj1.foobar, 2000);
296assertEquals(desc.value, 2000);
297assertFalse(desc.configurable);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000298assertTrue(desc.writable);
ager@chromium.org5c838252010-02-19 08:53:10 +0000299assertFalse(desc.enumerable);
300assertEquals(desc.get, undefined);
301assertEquals(desc.set, undefined);
302
303// Try redefine again - shold fail because configurable is now false.
304try {
305 Object.defineProperty(obj1, "foobar", dataConfigurable);
306 assertTrue(false);
307} catch (e) {
308 assertTrue(/Cannot redefine property/.test(e));
309}
310
311// Try redefine again with accessor property - shold also fail.
312try {
313 Object.defineProperty(obj1, "foobar", dataConfigurable);
314 assertTrue(false);
315} catch (e) {
316 assertTrue(/Cannot redefine property/.test(e));
317}
318
319
320// Redifine with the same descriptor - should succeed (step 6).
321Object.defineProperty(obj1, "foobar", dataNoConfigurable);
322desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
323assertEquals(obj1.foobar, 2000);
324assertEquals(desc.value, 2000);
325assertFalse(desc.configurable);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000326assertTrue(desc.writable);
ager@chromium.org5c838252010-02-19 08:53:10 +0000327assertFalse(desc.enumerable);
328assertEquals(desc.get, undefined);
329assertEquals(desc.set, undefined);
330
331
332// New object
333var obj2 = {};
334
335// Make accessor - redefine to data
336Object.defineProperty(obj2, "foo", accessorConfigurable);
337
338// Redefine to data property
339Object.defineProperty(obj2, "foo", dataConfigurable);
340desc = Object.getOwnPropertyDescriptor(obj2, "foo");
341assertEquals(obj2.foo, 1000);
342assertEquals(desc.value, 1000);
343assertTrue(desc.configurable);
344assertFalse(desc.writable);
345assertFalse(desc.enumerable);
346assertEquals(desc.get, undefined);
347assertEquals(desc.set, undefined);
348
349
350// Redefine back to accessor
351Object.defineProperty(obj2, "foo", accessorConfigurable);
352desc = Object.getOwnPropertyDescriptor(obj2, "foo");
353assertTrue(desc.configurable);
354assertFalse(desc.enumerable);
355assertEquals(desc.writable, undefined);
356assertEquals(desc.get, accessorConfigurable.get);
357assertEquals(desc.set, accessorConfigurable.set);
358assertEquals(desc.value, undefined);
359assertEquals(1, obj2.foo = 1);
360assertEquals(3, val1);
361assertEquals(4, val2);
362assertEquals(3, obj2.foo);
363
364// Make data - redefine to accessor
365Object.defineProperty(obj2, "bar", dataConfigurable)
366
367// Redefine to accessor property
368Object.defineProperty(obj2, "bar", accessorConfigurable);
369desc = Object.getOwnPropertyDescriptor(obj2, "bar");
370assertTrue(desc.configurable);
371assertFalse(desc.enumerable);
372assertEquals(desc.writable, undefined);
373assertEquals(desc.get, accessorConfigurable.get);
374assertEquals(desc.set, accessorConfigurable.set);
375assertEquals(desc.value, undefined);
376assertEquals(1, obj2.bar = 1);
377assertEquals(4, val1);
378assertEquals(4, val2);
379assertEquals(4, obj2.foo);
380
381// Redefine back to data property
382Object.defineProperty(obj2, "bar", dataConfigurable);
383desc = Object.getOwnPropertyDescriptor(obj2, "bar");
384assertEquals(obj2.bar, 1000);
385assertEquals(desc.value, 1000);
386assertTrue(desc.configurable);
387assertFalse(desc.writable);
388assertFalse(desc.enumerable);
389assertEquals(desc.get, undefined);
390assertEquals(desc.set, undefined);
391
392
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000393// Redefinition of an accessor defined using __defineGetter__ and
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000394// __defineSetter__.
ager@chromium.org5c838252010-02-19 08:53:10 +0000395function get(){return this.x}
396function set(x){this.x=x};
397
398var obj3 = {x:1000};
399obj3.__defineGetter__("foo", get);
400obj3.__defineSetter__("foo", set);
401
402desc = Object.getOwnPropertyDescriptor(obj3, "foo");
403assertTrue(desc.configurable);
404assertTrue(desc.enumerable);
405assertEquals(desc.writable, undefined);
406assertEquals(desc.get, get);
407assertEquals(desc.set, set);
408assertEquals(desc.value, undefined);
409assertEquals(1, obj3.foo = 1);
410assertEquals(1, obj3.x);
411assertEquals(1, obj3.foo);
412
413// Redefine to accessor property (non configurable) - note that enumerable
414// which we do not redefine should remain the same (true).
415Object.defineProperty(obj3, "foo", accessorNoConfigurable);
416desc = Object.getOwnPropertyDescriptor(obj3, "foo");
417assertFalse(desc.configurable);
418assertTrue(desc.enumerable);
419assertEquals(desc.writable, undefined);
420assertEquals(desc.get, accessorNoConfigurable.get);
421assertEquals(desc.set, accessorNoConfigurable.set);
422assertEquals(desc.value, undefined);
423assertEquals(1, obj3.foo = 1);
424assertEquals(5, val2);
425assertEquals(5, obj3.foo);
426
427
428obj3.__defineGetter__("bar", get);
429obj3.__defineSetter__("bar", set);
430
431
432// Redefine back to data property
433Object.defineProperty(obj3, "bar", dataConfigurable);
434desc = Object.getOwnPropertyDescriptor(obj3, "bar");
435assertEquals(obj3.bar, 1000);
436assertEquals(desc.value, 1000);
437assertTrue(desc.configurable);
438assertFalse(desc.writable);
439assertTrue(desc.enumerable);
440assertEquals(desc.get, undefined);
441assertEquals(desc.set, undefined);
442
443
444var obj4 = {};
445var func = function (){return 42;};
446obj4.bar = func;
447assertEquals(42, obj4.bar());
448
449Object.defineProperty(obj4, "bar", accessorConfigurable);
450desc = Object.getOwnPropertyDescriptor(obj4, "bar");
451assertTrue(desc.configurable);
452assertTrue(desc.enumerable);
453assertEquals(desc.writable, undefined);
454assertEquals(desc.get, accessorConfigurable.get);
455assertEquals(desc.set, accessorConfigurable.set);
456assertEquals(desc.value, undefined);
457assertEquals(1, obj4.bar = 1);
458assertEquals(5, val1);
459assertEquals(5, obj4.bar);
460
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000461// Make sure an error is thrown when trying to access to redefined function.
ager@chromium.org5c838252010-02-19 08:53:10 +0000462try {
463 obj4.bar();
464 assertTrue(false);
465} catch (e) {
466 assertTrue(/is not a function/.test(e));
467}
468
469
470// Test runtime calls to DefineOrRedefineDataProperty and
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000471// DefineOrRedefineAccessorProperty - make sure we don't
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000472// crash.
ager@chromium.org5c838252010-02-19 08:53:10 +0000473try {
474 %DefineOrRedefineAccessorProperty(0, 0, 0, 0, 0);
475} catch (e) {
476 assertTrue(/illegal access/.test(e));
477}
478
479try {
480 %DefineOrRedefineDataProperty(0, 0, 0, 0);
481} catch (e) {
482 assertTrue(/illegal access/.test(e));
483}
484
485try {
486 %DefineOrRedefineDataProperty(null, null, null, null);
487} catch (e) {
488 assertTrue(/illegal access/.test(e));
489}
490
491try {
492 %DefineOrRedefineAccessorProperty(null, null, null, null, null);
493} catch (e) {
494 assertTrue(/illegal access/.test(e));
495}
496
497try {
498 %DefineOrRedefineDataProperty({}, null, null, null);
499} catch (e) {
500 assertTrue(/illegal access/.test(e));
501}
502
503// Defining properties null should fail even when we have
504// other allowed values
505try {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000506 %DefineOrRedefineAccessorProperty(null, 'foo', func, null, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000507} catch (e) {
508 assertTrue(/illegal access/.test(e));
509}
510
511try {
512 %DefineOrRedefineDataProperty(null, 'foo', 0, 0);
513} catch (e) {
514 assertTrue(/illegal access/.test(e));
515}
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000516
517// Test that all possible differences in step 6 in DefineOwnProperty are
518// exercised, i.e., any difference in the given property descriptor and the
519// existing properties should not return true, but throw an error if the
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000520// existing configurable property is false.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000521
522var obj5 = {};
523// Enumerable will default to false.
524Object.defineProperty(obj5, 'foo', accessorNoConfigurable);
525desc = Object.getOwnPropertyDescriptor(obj5, 'foo');
526// First, test that we are actually allowed to set the accessor if all
527// values are of the descriptor are the same as the existing one.
528Object.defineProperty(obj5, 'foo', accessorNoConfigurable);
529
530// Different setter.
531var descDifferent = {
532 configurable:false,
533 enumerable:false,
534 set: setter1,
535 get: getter2
536};
537
538try {
539 Object.defineProperty(obj5, 'foo', descDifferent);
540 assertTrue(false);
541} catch (e) {
542 assertTrue(/Cannot redefine property/.test(e));
543}
544
545// Different getter.
546descDifferent = {
547 configurable:false,
548 enumerable:false,
549 set: setter2,
550 get: getter1
551};
552
553try {
554 Object.defineProperty(obj5, 'foo', descDifferent);
555 assertTrue(false);
556} catch (e) {
557 assertTrue(/Cannot redefine property/.test(e));
558}
559
560// Different enumerable.
561descDifferent = {
562 configurable:false,
563 enumerable:true,
564 set: setter2,
565 get: getter2
566};
567
568try {
569 Object.defineProperty(obj5, 'foo', descDifferent);
570 assertTrue(false);
571} catch (e) {
572 assertTrue(/Cannot redefine property/.test(e));
573}
574
575// Different configurable.
576descDifferent = {
577 configurable:false,
578 enumerable:true,
579 set: setter2,
580 get: getter2
581};
582
583try {
584 Object.defineProperty(obj5, 'foo', descDifferent);
585 assertTrue(false);
586} catch (e) {
587 assertTrue(/Cannot redefine property/.test(e));
588}
589
590// No difference.
591descDifferent = {
592 configurable:false,
593 enumerable:false,
594 set: setter2,
595 get: getter2
596};
597// Make sure we can still redefine if all properties are the same.
598Object.defineProperty(obj5, 'foo', descDifferent);
599
600// Make sure that obj5 still holds the original values.
601desc = Object.getOwnPropertyDescriptor(obj5, 'foo');
602assertEquals(desc.get, getter2);
603assertEquals(desc.set, setter2);
604assertFalse(desc.enumerable);
605assertFalse(desc.configurable);
606
607
608// Also exercise step 6 on data property, writable and enumerable
609// defaults to false.
610Object.defineProperty(obj5, 'bar', dataNoConfigurable);
611
612// Test that redefinition with the same property descriptor is possible
613Object.defineProperty(obj5, 'bar', dataNoConfigurable);
614
615// Different value.
616descDifferent = {
617 configurable:false,
618 enumerable:false,
619 writable: false,
620 value: 1999
621};
622
623try {
624 Object.defineProperty(obj5, 'bar', descDifferent);
625 assertTrue(false);
626} catch (e) {
627 assertTrue(/Cannot redefine property/.test(e));
628}
629
630// Different writable.
631descDifferent = {
632 configurable:false,
633 enumerable:false,
634 writable: true,
635 value: 2000
636};
637
638try {
639 Object.defineProperty(obj5, 'bar', descDifferent);
640 assertTrue(false);
641} catch (e) {
642 assertTrue(/Cannot redefine property/.test(e));
643}
644
645
646// Different enumerable.
647descDifferent = {
648 configurable:false,
649 enumerable:true ,
650 writable:false,
651 value: 2000
652};
653
654try {
655 Object.defineProperty(obj5, 'bar', descDifferent);
656 assertTrue(false);
657} catch (e) {
658 assertTrue(/Cannot redefine property/.test(e));
659}
660
661
662// Different configurable.
663descDifferent = {
664 configurable:true,
665 enumerable:false,
666 writable:false,
667 value: 2000
668};
669
670try {
671 Object.defineProperty(obj5, 'bar', descDifferent);
672 assertTrue(false);
673} catch (e) {
674 assertTrue(/Cannot redefine property/.test(e));
675}
676
677// No difference.
678descDifferent = {
679 configurable:false,
680 enumerable:false,
681 writable:false,
682 value:2000
683};
684// Make sure we can still redefine if all properties are the same.
685Object.defineProperty(obj5, 'bar', descDifferent);
686
687// Make sure that obj5 still holds the original values.
688desc = Object.getOwnPropertyDescriptor(obj5, 'bar');
689assertEquals(desc.value, 2000);
690assertFalse(desc.writable);
691assertFalse(desc.enumerable);
692assertFalse(desc.configurable);
693
694
695// Make sure that we can't overwrite +0 with -0 and vice versa.
696var descMinusZero = {value: -0, configurable: false};
697var descPlusZero = {value: +0, configurable: false};
698
699Object.defineProperty(obj5, 'minuszero', descMinusZero);
700
701// Make sure we can redefine with -0.
702Object.defineProperty(obj5, 'minuszero', descMinusZero);
703
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000704exception = false;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000705try {
706 Object.defineProperty(obj5, 'minuszero', descPlusZero);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000707} catch (e) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000708 exception = true;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000709 assertTrue(/Cannot redefine property/.test(e));
710}
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000711assertTrue(exception);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000712
713
714Object.defineProperty(obj5, 'pluszero', descPlusZero);
715
716// Make sure we can redefine with +0.
717Object.defineProperty(obj5, 'pluszero', descPlusZero);
718
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000719exception = false;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000720try {
721 Object.defineProperty(obj5, 'pluszero', descMinusZero);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000722} catch (e) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000723 exception = true;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000724 assertTrue(/Cannot redefine property/.test(e));
725}
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000726assertTrue(exception);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000727
728
729var obj6 = {};
730obj6[1] = 'foo';
731obj6[2] = 'bar';
732obj6[3] = '42';
733obj6[4] = '43';
734obj6[5] = '44';
735
736var descElement = { value: 'foobar' };
737var descElementNonConfigurable = { value: 'barfoo', configurable: false };
738var descElementNonWritable = { value: 'foofoo', writable: false };
739var descElementNonEnumerable = { value: 'barbar', enumerable: false };
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000740var descElementAllFalse = { value: 'foofalse',
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000741 configurable: false,
742 writable: false,
743 enumerable: false };
744
745
746// Redefine existing property.
747Object.defineProperty(obj6, '1', descElement);
748desc = Object.getOwnPropertyDescriptor(obj6, '1');
749assertEquals(desc.value, 'foobar');
750assertTrue(desc.writable);
751assertTrue(desc.enumerable);
752assertTrue(desc.configurable);
753
754// Redefine existing property with configurable: false.
755Object.defineProperty(obj6, '2', descElementNonConfigurable);
756desc = Object.getOwnPropertyDescriptor(obj6, '2');
757assertEquals(desc.value, 'barfoo');
758assertTrue(desc.writable);
759assertTrue(desc.enumerable);
760assertFalse(desc.configurable);
761
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000762// Can use defineProperty to change the value of a non
763// configurable property.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000764try {
765 Object.defineProperty(obj6, '2', descElement);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000766 desc = Object.getOwnPropertyDescriptor(obj6, '2');
767 assertEquals(desc.value, 'foobar');
768} catch (e) {
769 assertUnreachable();
770}
771
772// Ensure that we can't change the descriptor of a
773// non configurable property.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000774exception = false;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000775try {
776 var descAccessor = { get: function() { return 0; } };
777 Object.defineProperty(obj6, '2', descAccessor);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000778} catch (e) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000779 exception = true;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000780 assertTrue(/Cannot redefine property/.test(e));
781}
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000782assertTrue(exception);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000783
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000784Object.defineProperty(obj6, '2', descElementNonWritable);
785desc = Object.getOwnPropertyDescriptor(obj6, '2');
786assertEquals(desc.value, 'foofoo');
787assertFalse(desc.writable);
788assertTrue(desc.enumerable);
789assertFalse(desc.configurable);
790
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000791Object.defineProperty(obj6, '3', descElementNonWritable);
792desc = Object.getOwnPropertyDescriptor(obj6, '3');
793assertEquals(desc.value, 'foofoo');
794assertFalse(desc.writable);
795assertTrue(desc.enumerable);
796assertTrue(desc.configurable);
797
798// Redefine existing property with configurable: false.
799Object.defineProperty(obj6, '4', descElementNonEnumerable);
800desc = Object.getOwnPropertyDescriptor(obj6, '4');
801assertEquals(desc.value, 'barbar');
802assertTrue(desc.writable);
803assertFalse(desc.enumerable);
804assertTrue(desc.configurable);
805
806// Redefine existing property with configurable: false.
807Object.defineProperty(obj6, '5', descElementAllFalse);
808desc = Object.getOwnPropertyDescriptor(obj6, '5');
809assertEquals(desc.value, 'foofalse');
810assertFalse(desc.writable);
811assertFalse(desc.enumerable);
812assertFalse(desc.configurable);
813
814// Define non existing property - all attributes should default to false.
815Object.defineProperty(obj6, '15', descElement);
816desc = Object.getOwnPropertyDescriptor(obj6, '15');
817assertEquals(desc.value, 'foobar');
818assertFalse(desc.writable);
819assertFalse(desc.enumerable);
820assertFalse(desc.configurable);
821
822// Make sure that we can't redefine using direct access.
823obj6[15] ='overwrite';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000824assertEquals(obj6[15],'foobar');
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000825
826
827// Repeat the above tests on an array.
828var arr = new Array();
829arr[1] = 'foo';
830arr[2] = 'bar';
831arr[3] = '42';
832arr[4] = '43';
833arr[5] = '44';
834
835var descElement = { value: 'foobar' };
836var descElementNonConfigurable = { value: 'barfoo', configurable: false };
837var descElementNonWritable = { value: 'foofoo', writable: false };
838var descElementNonEnumerable = { value: 'barbar', enumerable: false };
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000839var descElementAllFalse = { value: 'foofalse',
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000840 configurable: false,
841 writable: false,
842 enumerable: false };
843
844
845// Redefine existing property.
846Object.defineProperty(arr, '1', descElement);
847desc = Object.getOwnPropertyDescriptor(arr, '1');
848assertEquals(desc.value, 'foobar');
849assertTrue(desc.writable);
850assertTrue(desc.enumerable);
851assertTrue(desc.configurable);
852
853// Redefine existing property with configurable: false.
854Object.defineProperty(arr, '2', descElementNonConfigurable);
855desc = Object.getOwnPropertyDescriptor(arr, '2');
856assertEquals(desc.value, 'barfoo');
857assertTrue(desc.writable);
858assertTrue(desc.enumerable);
859assertFalse(desc.configurable);
860
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000861// Can use defineProperty to change the value of a non
862// configurable property of an array.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000863try {
864 Object.defineProperty(arr, '2', descElement);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000865 desc = Object.getOwnPropertyDescriptor(arr, '2');
866 assertEquals(desc.value, 'foobar');
867} catch (e) {
868 assertUnreachable();
869}
870
871// Ensure that we can't change the descriptor of a
872// non configurable property.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000873exception = false;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000874try {
875 var descAccessor = { get: function() { return 0; } };
876 Object.defineProperty(arr, '2', descAccessor);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000877} catch (e) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000878 exception = true;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000879 assertTrue(/Cannot redefine property/.test(e));
880}
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000881assertTrue(exception);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000882
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000883Object.defineProperty(arr, '2', descElementNonWritable);
884desc = Object.getOwnPropertyDescriptor(arr, '2');
885assertEquals(desc.value, 'foofoo');
886assertFalse(desc.writable);
887assertTrue(desc.enumerable);
888assertFalse(desc.configurable);
889
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000890Object.defineProperty(arr, '3', descElementNonWritable);
891desc = Object.getOwnPropertyDescriptor(arr, '3');
892assertEquals(desc.value, 'foofoo');
893assertFalse(desc.writable);
894assertTrue(desc.enumerable);
895assertTrue(desc.configurable);
896
897// Redefine existing property with configurable: false.
898Object.defineProperty(arr, '4', descElementNonEnumerable);
899desc = Object.getOwnPropertyDescriptor(arr, '4');
900assertEquals(desc.value, 'barbar');
901assertTrue(desc.writable);
902assertFalse(desc.enumerable);
903assertTrue(desc.configurable);
904
905// Redefine existing property with configurable: false.
906Object.defineProperty(arr, '5', descElementAllFalse);
907desc = Object.getOwnPropertyDescriptor(arr, '5');
908assertEquals(desc.value, 'foofalse');
909assertFalse(desc.writable);
910assertFalse(desc.enumerable);
911assertFalse(desc.configurable);
912
913// Define non existing property - all attributes should default to false.
914Object.defineProperty(arr, '15', descElement);
915desc = Object.getOwnPropertyDescriptor(arr, '15');
916assertEquals(desc.value, 'foobar');
917assertFalse(desc.writable);
918assertFalse(desc.enumerable);
919assertFalse(desc.configurable);
920
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000921// See issue 968: http://code.google.com/p/v8/issues/detail?id=968
922var o = { x : 42 };
923Object.defineProperty(o, "x", { writable: false });
924assertEquals(42, o.x);
925o.x = 37;
926assertEquals(42, o.x);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000927
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000928o = { x : 42 };
929Object.defineProperty(o, "x", {});
930assertEquals(42, o.x);
931o.x = 37;
932// Writability is preserved.
933assertEquals(37, o.x);
934
935var o = { };
936Object.defineProperty(o, "x", { writable: false });
937assertEquals(undefined, o.x);
938o.x = 37;
939assertEquals(undefined, o.x);
940
941o = { get x() { return 87; } };
942Object.defineProperty(o, "x", { writable: false });
943assertEquals(undefined, o.x);
944o.x = 37;
945assertEquals(undefined, o.x);
946
947// Ignore inherited properties.
948o = { __proto__ : { x : 87 } };
949Object.defineProperty(o, "x", { writable: false });
950assertEquals(undefined, o.x);
951o.x = 37;
952assertEquals(undefined, o.x);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000953
954function testDefineProperty(obj, propertyName, desc, resultDesc) {
955 Object.defineProperty(obj, propertyName, desc);
956 var actualDesc = Object.getOwnPropertyDescriptor(obj, propertyName);
957 assertEquals(resultDesc.enumerable, actualDesc.enumerable);
958 assertEquals(resultDesc.configurable, actualDesc.configurable);
959 if (resultDesc.hasOwnProperty('value')) {
960 assertEquals(resultDesc.value, actualDesc.value);
961 assertEquals(resultDesc.writable, actualDesc.writable);
962 assertFalse(resultDesc.hasOwnProperty('get'));
963 assertFalse(resultDesc.hasOwnProperty('set'));
964 } else {
965 assertEquals(resultDesc.get, actualDesc.get);
966 assertEquals(resultDesc.set, actualDesc.set);
967 assertFalse(resultDesc.hasOwnProperty('value'));
968 assertFalse(resultDesc.hasOwnProperty('writable'));
969 }
970}
971
972// tests redefining existing property with a generic descriptor
973o = { p : 42 };
974testDefineProperty(o, 'p',
975 { },
976 { value : 42, writable : true, enumerable : true, configurable : true });
977
978o = { p : 42 };
979testDefineProperty(o, 'p',
980 { enumerable : true },
981 { value : 42, writable : true, enumerable : true, configurable : true });
982
983o = { p : 42 };
984testDefineProperty(o, 'p',
985 { configurable : true },
986 { value : 42, writable : true, enumerable : true, configurable : true });
987
988o = { p : 42 };
989testDefineProperty(o, 'p',
990 { enumerable : false },
991 { value : 42, writable : true, enumerable : false, configurable : true });
992
993o = { p : 42 };
994testDefineProperty(o, 'p',
995 { configurable : false },
996 { value : 42, writable : true, enumerable : true, configurable : false });
997
998o = { p : 42 };
999testDefineProperty(o, 'p',
1000 { enumerable : true, configurable : true },
1001 { value : 42, writable : true, enumerable : true, configurable : true });
1002
1003o = { p : 42 };
1004testDefineProperty(o, 'p',
1005 { enumerable : false, configurable : true },
1006 { value : 42, writable : true, enumerable : false, configurable : true });
1007
1008o = { p : 42 };
1009testDefineProperty(o, 'p',
1010 { enumerable : true, configurable : false },
1011 { value : 42, writable : true, enumerable : true, configurable : false });
1012
1013o = { p : 42 };
1014testDefineProperty(o, 'p',
1015 { enumerable : false, configurable : false },
1016 { value : 42, writable : true, enumerable : false, configurable : false });
1017
1018// can make a writable, non-configurable field non-writable
1019o = { p : 42 };
1020Object.defineProperty(o, 'p', { configurable: false });
1021testDefineProperty(o, 'p',
1022 { writable: false },
1023 { value : 42, writable : false, enumerable : true, configurable : false });
1024
1025// redefine of get only property with generic descriptor
1026o = {};
1027Object.defineProperty(o, 'p',
1028 { get : getter1, enumerable: true, configurable: true });
1029testDefineProperty(o, 'p',
1030 { enumerable : false, configurable : false },
1031 { get: getter1, set: undefined, enumerable : false, configurable : false });
1032
1033// redefine of get/set only property with generic descriptor
1034o = {};
1035Object.defineProperty(o, 'p',
1036 { get: getter1, set: setter1, enumerable: true, configurable: true });
1037testDefineProperty(o, 'p',
1038 { enumerable : false, configurable : false },
1039 { get: getter1, set: setter1, enumerable : false, configurable : false });
1040
1041// redefine of set only property with generic descriptor
1042o = {};
1043Object.defineProperty(o, 'p',
1044 { set : setter1, enumerable: true, configurable: true });
1045testDefineProperty(o, 'p',
1046 { enumerable : false, configurable : false },
1047 { get: undefined, set: setter1, enumerable : false, configurable : false });
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001048
1049
1050// Regression test: Ensure that growing dictionaries are not ignored.
1051o = {};
1052for (var i = 0; i < 1000; i++) {
1053 // Non-enumerable property forces dictionary mode.
1054 Object.defineProperty(o, i, {value: i, enumerable: false});
1055}
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001056assertEquals(999, o[999]);
1057
1058
1059// Regression test: Bizzare behavior on non-strict arguments object.
1060(function test(arg0) {
1061 // Here arguments[0] is a fast alias on arg0.
1062 Object.defineProperty(arguments, "0", {
1063 value:1,
1064 enumerable:false
1065 });
1066 // Here arguments[0] is a slow alias on arg0.
1067 Object.defineProperty(arguments, "0", {
1068 value:2,
1069 writable:false
1070 });
1071 // Here arguments[0] is no alias at all.
1072 Object.defineProperty(arguments, "0", {
1073 value:3
1074 });
1075 assertEquals(2, arg0);
1076 assertEquals(3, arguments[0]);
1077})(0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001078
1079
1080// Regression test: We should never observe the hole value.
1081var objectWithGetter = {};
1082objectWithGetter.__defineGetter__('foo', function() {});
1083assertEquals(undefined, objectWithGetter.__lookupSetter__('foo'));
1084
1085var objectWithSetter = {};
1086objectWithSetter.__defineSetter__('foo', function(x) {});
1087assertEquals(undefined, objectWithSetter.__lookupGetter__('foo'));
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00001088
1089// An object with a getter on the prototype chain.
1090function getter() { return 111; }
1091function anotherGetter() { return 222; }
1092
1093function testGetterOnProto(expected, o) {
1094 assertEquals(expected, o.quebec);
1095}
1096
1097obj1 = {};
1098Object.defineProperty(obj1, "quebec", { get: getter, configurable: true });
1099obj2 = Object.create(obj1);
1100obj3 = Object.create(obj2);
1101
1102testGetterOnProto(111, obj3);
1103testGetterOnProto(111, obj3);
1104%OptimizeFunctionOnNextCall(testGetterOnProto);
1105testGetterOnProto(111, obj3);
1106testGetterOnProto(111, obj3);
1107
1108Object.defineProperty(obj1, "quebec", { get: anotherGetter });
1109
1110testGetterOnProto(222, obj3);
1111testGetterOnProto(222, obj3);
1112%OptimizeFunctionOnNextCall(testGetterOnProto);
1113testGetterOnProto(222, obj3);
1114testGetterOnProto(222, obj3);
1115
1116// An object with a setter on the prototype chain.
1117var modifyMe;
1118function setter(x) { modifyMe = x+1; }
1119function anotherSetter(x) { modifyMe = x+2; }
1120
1121function testSetterOnProto(expected, o) {
1122 modifyMe = 333;
1123 o.romeo = 444;
1124 assertEquals(expected, modifyMe);
1125}
1126
1127obj1 = {};
1128Object.defineProperty(obj1, "romeo", { set: setter, configurable: true });
1129obj2 = Object.create(obj1);
1130obj3 = Object.create(obj2);
1131
1132testSetterOnProto(445, obj3);
1133testSetterOnProto(445, obj3);
1134%OptimizeFunctionOnNextCall(testSetterOnProto);
1135testSetterOnProto(445, obj3);
1136testSetterOnProto(445, obj3);
1137
1138Object.defineProperty(obj1, "romeo", { set: anotherSetter });
1139
1140testSetterOnProto(446, obj3);
1141testSetterOnProto(446, obj3);
1142%OptimizeFunctionOnNextCall(testSetterOnProto);
1143testSetterOnProto(446, obj3);
1144testSetterOnProto(446, obj3);
1145
1146// Removing a setter on the prototype chain.
1147function testSetterOnProtoStrict(o) {
1148 "use strict";
1149 o.sierra = 12345;
1150}
1151
1152obj1 = {};
1153Object.defineProperty(obj1, "sierra",
1154 { get: getter, set: setter, configurable: true });
1155obj2 = Object.create(obj1);
1156obj3 = Object.create(obj2);
1157
1158testSetterOnProtoStrict(obj3);
1159testSetterOnProtoStrict(obj3);
1160%OptimizeFunctionOnNextCall(testSetterOnProtoStrict);
1161testSetterOnProtoStrict(obj3);
1162testSetterOnProtoStrict(obj3);
1163
1164Object.defineProperty(obj1, "sierra",
1165 { get: getter, set: undefined, configurable: true });
1166
1167exception = false;
1168try {
1169 testSetterOnProtoStrict(obj3);
1170} catch (e) {
1171 exception = true;
1172 assertTrue(/which has only a getter/.test(e));
1173}
1174assertTrue(exception);