blob: afd3ff6595f7420a0063ef28192da4da4e4742cb [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2012-2015 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 Reflect.defineProperty method - ES6 26.1.3
29// This is adapted from mjsunit/object-define-property.js.
30
31// Flags: --allow-natives-syntax --harmony-reflect
32
33
34// Check that an exception is thrown when null is passed as object.
35var exception = false;
36try {
37 Reflect.defineProperty(null, null, null);
38} catch (e) {
39 exception = true;
40 assertTrue(/called on non-object/.test(e));
41}
42assertTrue(exception);
43
44// Check that an exception is thrown when undefined is passed as object.
45exception = false;
46try {
47 Reflect.defineProperty(undefined, undefined, undefined);
48} catch (e) {
49 exception = true;
50 assertTrue(/called on non-object/.test(e));
51}
52assertTrue(exception);
53
54// Check that an exception is thrown when non-object is passed as object.
55exception = false;
56try {
57 Reflect.defineProperty(0, "foo", undefined);
58} catch (e) {
59 exception = true;
60 assertTrue(/called on non-object/.test(e));
61}
62assertTrue(exception);
63
64// Object.
65var obj1 = {};
66
67// Values.
68var val1 = 0;
69var val2 = 0;
70var val3 = 0;
71
72function setter1() {val1++; }
73function getter1() {return val1; }
74
75function setter2() {val2++; }
76function getter2() {return val2; }
77
78function setter3() {val3++; }
79function getter3() {return val3; }
80
81
82// Descriptors.
83var emptyDesc = {};
84
85var accessorConfigurable = {
86 set: setter1,
87 get: getter1,
88 configurable: true
89};
90
91var accessorNoConfigurable = {
92 set: setter2,
93 get: getter2,
94 configurable: false
95};
96
97var accessorOnlySet = {
98 set: setter3,
99 configurable: true
100};
101
102var accessorOnlyGet = {
103 get: getter3,
104 configurable: true
105};
106
107var accessorDefault = {set: function(){} };
108
109var dataConfigurable = { value: 1000, configurable: true };
110
111var dataNoConfigurable = { value: 2000, configurable: false };
112
113var dataWritable = { value: 3000, writable: true};
114
115
116// Check that we can't add property with undefined attributes.
117assertThrows(function() { Reflect.defineProperty(obj1, "foo", undefined) },
118 TypeError);
119
120// Make sure that we can add a property with an empty descriptor and
121// that it has the default descriptor values.
122assertTrue(Reflect.defineProperty(obj1, "foo", emptyDesc));
123
124// foo should be undefined as it has no get, set or value
125assertEquals(undefined, obj1.foo);
126
127// We should, however, be able to retrieve the propertydescriptor which should
128// have all default values (according to 8.6.1).
129var desc = Object.getOwnPropertyDescriptor(obj1, "foo");
130assertFalse(desc.configurable);
131assertFalse(desc.enumerable);
132assertFalse(desc.writable);
133assertEquals(desc.get, undefined);
134assertEquals(desc.set, undefined);
135assertEquals(desc.value, undefined);
136
137// Make sure that getOwnPropertyDescriptor does not return a descriptor
138// with default values if called with non existing property (otherwise
139// the test above is invalid).
140desc = Object.getOwnPropertyDescriptor(obj1, "bar");
141assertEquals(desc, undefined);
142
143// Make sure that foo can't be reset (as configurable is false).
144assertFalse(Reflect.defineProperty(obj1, "foo", accessorConfigurable));
145
146
147// Accessor properties
148
149assertTrue(Reflect.defineProperty(obj1, "bar", accessorConfigurable));
150desc = Object.getOwnPropertyDescriptor(obj1, "bar");
151assertTrue(desc.configurable);
152assertFalse(desc.enumerable);
153assertEquals(desc.writable, undefined);
154assertEquals(desc.get, accessorConfigurable.get);
155assertEquals(desc.set, accessorConfigurable.set);
156assertEquals(desc.value, undefined);
157assertEquals(1, obj1.bar = 1);
158assertEquals(1, val1);
159assertEquals(1, obj1.bar = 1);
160assertEquals(2, val1);
161assertEquals(2, obj1.bar);
162
163// Redefine bar with non configurable test
164assertTrue(Reflect.defineProperty(obj1, "bar", accessorNoConfigurable));
165desc = Object.getOwnPropertyDescriptor(obj1, "bar");
166assertFalse(desc.configurable);
167assertFalse(desc.enumerable);
168assertEquals(desc.writable, undefined);
169assertEquals(desc.get, accessorNoConfigurable.get);
170assertEquals(desc.set, accessorNoConfigurable.set);
171assertEquals(desc.value, undefined);
172assertEquals(1, obj1.bar = 1);
173assertEquals(2, val1);
174assertEquals(1, val2);
175assertEquals(1, obj1.bar = 1)
176assertEquals(2, val1);
177assertEquals(2, val2);
178assertEquals(2, obj1.bar);
179
180// Try to redefine bar again - should fail as configurable is false.
181assertFalse(Reflect.defineProperty(obj1, "bar", accessorConfigurable));
182
183// Try to redefine bar again using the data descriptor - should fail.
184assertFalse(Reflect.defineProperty(obj1, "bar", dataConfigurable));
185
186// Redefine using same descriptor - should succeed.
187assertTrue(Reflect.defineProperty(obj1, "bar", accessorNoConfigurable));
188desc = Object.getOwnPropertyDescriptor(obj1, "bar");
189assertFalse(desc.configurable);
190assertFalse(desc.enumerable);
191assertEquals(desc.writable, undefined);
192assertEquals(desc.get, accessorNoConfigurable.get);
193assertEquals(desc.set, accessorNoConfigurable.set);
194assertEquals(desc.value, undefined);
195assertEquals(1, obj1.bar = 1);
196assertEquals(2, val1);
197assertEquals(3, val2);
198assertEquals(1, obj1.bar = 1)
199assertEquals(2, val1);
200assertEquals(4, val2);
201assertEquals(4, obj1.bar);
202
203// Define an accessor that has only a setter.
204assertTrue(Reflect.defineProperty(obj1, "setOnly", accessorOnlySet));
205desc = Object.getOwnPropertyDescriptor(obj1, "setOnly");
206assertTrue(desc.configurable);
207assertFalse(desc.enumerable);
208assertEquals(desc.set, accessorOnlySet.set);
209assertEquals(desc.writable, undefined);
210assertEquals(desc.value, undefined);
211assertEquals(desc.get, undefined);
212assertEquals(1, obj1.setOnly = 1);
213assertEquals(1, val3);
214
215// Add a getter - should not touch the setter.
216assertTrue(Reflect.defineProperty(obj1, "setOnly", accessorOnlyGet));
217desc = Object.getOwnPropertyDescriptor(obj1, "setOnly");
218assertTrue(desc.configurable);
219assertFalse(desc.enumerable);
220assertEquals(desc.get, accessorOnlyGet.get);
221assertEquals(desc.set, accessorOnlySet.set);
222assertEquals(desc.writable, undefined);
223assertEquals(desc.value, undefined);
224assertEquals(1, obj1.setOnly = 1);
225assertEquals(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.
229assertTrue(Reflect.defineProperty(obj1, "both", accessorConfigurable));
230
231assertTrue(Reflect.defineProperty(obj1, "both", accessorOnlySet));
232desc = Object.getOwnPropertyDescriptor(obj1, "both");
233assertTrue(desc.configurable);
234assertFalse(desc.enumerable);
235assertEquals(desc.set, accessorOnlySet.set);
236assertEquals(desc.get, accessorConfigurable.get);
237assertEquals(desc.writable, undefined);
238assertEquals(desc.value, undefined);
239assertEquals(1, obj1.both = 1);
240assertEquals(3, val3);
241
242
243// Data properties
244
245assertTrue(Reflect.defineProperty(obj1, "foobar", dataConfigurable));
246desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
247assertEquals(obj1.foobar, 1000);
248assertEquals(desc.value, 1000);
249assertTrue(desc.configurable);
250assertFalse(desc.writable);
251assertFalse(desc.enumerable);
252assertEquals(desc.get, undefined);
253assertEquals(desc.set, undefined);
254//Try writing to non writable attribute - should remain 1000
255obj1.foobar = 1001;
256assertEquals(obj1.foobar, 1000);
257
258
259// Redefine to writable descriptor - now writing to foobar should be allowed.
260assertTrue(Reflect.defineProperty(obj1, "foobar", dataWritable));
261desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
262assertEquals(obj1.foobar, 3000);
263assertEquals(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.
266assertTrue(desc.configurable);
267assertTrue(desc.writable);
268assertFalse(desc.enumerable);
269assertEquals(desc.get, undefined);
270assertEquals(desc.set, undefined);
271// Writing to the property should now be allowed
272obj1.foobar = 1001;
273assertEquals(obj1.foobar, 1001);
274
275
276// Redefine with non configurable data property.
277assertTrue(Reflect.defineProperty(obj1, "foobar", dataNoConfigurable));
278desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
279assertEquals(obj1.foobar, 2000);
280assertEquals(desc.value, 2000);
281assertFalse(desc.configurable);
282assertTrue(desc.writable);
283assertFalse(desc.enumerable);
284assertEquals(desc.get, undefined);
285assertEquals(desc.set, undefined);
286
287// Try redefine again - shold fail because configurable is now false.
288assertFalse(Reflect.defineProperty(obj1, "foobar", dataConfigurable));
289
290// Try redefine again with accessor property - shold also fail.
291assertFalse(Reflect.defineProperty(obj1, "foobar", dataConfigurable));
292
293
294// Redifine with the same descriptor - should succeed (step 6).
295assertTrue(Reflect.defineProperty(obj1, "foobar", dataNoConfigurable));
296desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
297assertEquals(obj1.foobar, 2000);
298assertEquals(desc.value, 2000);
299assertFalse(desc.configurable);
300assertTrue(desc.writable);
301assertFalse(desc.enumerable);
302assertEquals(desc.get, undefined);
303assertEquals(desc.set, undefined);
304
305
306// New object
307var obj2 = {};
308
309// Make accessor - redefine to data
310assertTrue(Reflect.defineProperty(obj2, "foo", accessorConfigurable));
311
312// Redefine to data property
313assertTrue(Reflect.defineProperty(obj2, "foo", dataConfigurable));
314desc = Object.getOwnPropertyDescriptor(obj2, "foo");
315assertEquals(obj2.foo, 1000);
316assertEquals(desc.value, 1000);
317assertTrue(desc.configurable);
318assertFalse(desc.writable);
319assertFalse(desc.enumerable);
320assertEquals(desc.get, undefined);
321assertEquals(desc.set, undefined);
322
323
324// Redefine back to accessor
325assertTrue(Reflect.defineProperty(obj2, "foo", accessorConfigurable));
326desc = Object.getOwnPropertyDescriptor(obj2, "foo");
327assertTrue(desc.configurable);
328assertFalse(desc.enumerable);
329assertEquals(desc.writable, undefined);
330assertEquals(desc.get, accessorConfigurable.get);
331assertEquals(desc.set, accessorConfigurable.set);
332assertEquals(desc.value, undefined);
333assertEquals(1, obj2.foo = 1);
334assertEquals(3, val1);
335assertEquals(4, val2);
336assertEquals(3, obj2.foo);
337
338// Make data - redefine to accessor
339assertTrue(Reflect.defineProperty(obj2, "bar", dataConfigurable))
340
341// Redefine to accessor property
342assertTrue(Reflect.defineProperty(obj2, "bar", accessorConfigurable));
343desc = Object.getOwnPropertyDescriptor(obj2, "bar");
344assertTrue(desc.configurable);
345assertFalse(desc.enumerable);
346assertEquals(desc.writable, undefined);
347assertEquals(desc.get, accessorConfigurable.get);
348assertEquals(desc.set, accessorConfigurable.set);
349assertEquals(desc.value, undefined);
350assertEquals(1, obj2.bar = 1);
351assertEquals(4, val1);
352assertEquals(4, val2);
353assertEquals(4, obj2.foo);
354
355// Redefine back to data property
356assertTrue(Reflect.defineProperty(obj2, "bar", dataConfigurable));
357desc = Object.getOwnPropertyDescriptor(obj2, "bar");
358assertEquals(obj2.bar, 1000);
359assertEquals(desc.value, 1000);
360assertTrue(desc.configurable);
361assertFalse(desc.writable);
362assertFalse(desc.enumerable);
363assertEquals(desc.get, undefined);
364assertEquals(desc.set, undefined);
365
366
367// Redefinition of an accessor defined using __defineGetter__ and
368// __defineSetter__.
369function get(){return this.x}
370function set(x){this.x=x};
371
372var obj3 = {x:1000};
373obj3.__defineGetter__("foo", get);
374obj3.__defineSetter__("foo", set);
375
376desc = Object.getOwnPropertyDescriptor(obj3, "foo");
377assertTrue(desc.configurable);
378assertTrue(desc.enumerable);
379assertEquals(desc.writable, undefined);
380assertEquals(desc.get, get);
381assertEquals(desc.set, set);
382assertEquals(desc.value, undefined);
383assertEquals(1, obj3.foo = 1);
384assertEquals(1, obj3.x);
385assertEquals(1, obj3.foo);
386
387// Redefine to accessor property (non configurable) - note that enumerable
388// which we do not redefine should remain the same (true).
389assertTrue(Reflect.defineProperty(obj3, "foo", accessorNoConfigurable));
390desc = Object.getOwnPropertyDescriptor(obj3, "foo");
391assertFalse(desc.configurable);
392assertTrue(desc.enumerable);
393assertEquals(desc.writable, undefined);
394assertEquals(desc.get, accessorNoConfigurable.get);
395assertEquals(desc.set, accessorNoConfigurable.set);
396assertEquals(desc.value, undefined);
397assertEquals(1, obj3.foo = 1);
398assertEquals(5, val2);
399assertEquals(5, obj3.foo);
400
401
402obj3.__defineGetter__("bar", get);
403obj3.__defineSetter__("bar", set);
404
405
406// Redefine back to data property
407assertTrue(Reflect.defineProperty(obj3, "bar", dataConfigurable));
408desc = Object.getOwnPropertyDescriptor(obj3, "bar");
409assertEquals(obj3.bar, 1000);
410assertEquals(desc.value, 1000);
411assertTrue(desc.configurable);
412assertFalse(desc.writable);
413assertTrue(desc.enumerable);
414assertEquals(desc.get, undefined);
415assertEquals(desc.set, undefined);
416
417
418var obj4 = {};
419var func = function (){return 42;};
420obj4.bar = func;
421assertEquals(42, obj4.bar());
422
423assertTrue(Reflect.defineProperty(obj4, "bar", accessorConfigurable));
424desc = Object.getOwnPropertyDescriptor(obj4, "bar");
425assertTrue(desc.configurable);
426assertTrue(desc.enumerable);
427assertEquals(desc.writable, undefined);
428assertEquals(desc.get, accessorConfigurable.get);
429assertEquals(desc.set, accessorConfigurable.set);
430assertEquals(desc.value, undefined);
431assertEquals(1, obj4.bar = 1);
432assertEquals(5, val1);
433assertEquals(5, obj4.bar);
434
435// Make sure an error is thrown when trying to access to redefined function.
436try {
437 obj4.bar();
438 assertTrue(false);
439} catch (e) {
440 assertTrue(/is not a function/.test(e));
441}
442
443
444// Test runtime calls to DefineDataPropertyUnchecked and
445// DefineAccessorPropertyUnchecked - make sure we don't
446// crash.
447try {
448 %DefineAccessorPropertyUnchecked(0, 0, 0, 0, 0);
449} catch (e) {
450 assertTrue(/illegal access/.test(e));
451}
452
453try {
454 %DefineDataPropertyUnchecked(0, 0, 0, 0);
455} catch (e) {
456 assertTrue(/illegal access/.test(e));
457}
458
459try {
460 %DefineDataPropertyUnchecked(null, null, null, null);
461} catch (e) {
462 assertTrue(/illegal access/.test(e));
463}
464
465try {
466 %DefineAccessorPropertyUnchecked(null, null, null, null, null);
467} catch (e) {
468 assertTrue(/illegal access/.test(e));
469}
470
471try {
472 %DefineDataPropertyUnchecked({}, null, null, null);
473} catch (e) {
474 assertTrue(/illegal access/.test(e));
475}
476
477// Defining properties null should fail even when we have
478// other allowed values
479try {
480 %DefineAccessorPropertyUnchecked(null, 'foo', func, null, 0);
481} catch (e) {
482 assertTrue(/illegal access/.test(e));
483}
484
485try {
486 %DefineDataPropertyUnchecked(null, 'foo', 0, 0);
487} catch (e) {
488 assertTrue(/illegal access/.test(e));
489}
490
491// Test that all possible differences in step 6 in DefineOwnProperty are
492// exercised, i.e., any difference in the given property descriptor and the
493// existing properties should not return true, but throw an error if the
494// existing configurable property is false.
495
496var obj5 = {};
497// Enumerable will default to false.
498assertTrue(Reflect.defineProperty(obj5, 'foo', accessorNoConfigurable));
499desc = Object.getOwnPropertyDescriptor(obj5, 'foo');
500// First, test that we are actually allowed to set the accessor if all
501// values are of the descriptor are the same as the existing one.
502assertTrue(Reflect.defineProperty(obj5, 'foo', accessorNoConfigurable));
503
504// Different setter.
505var descDifferent = {
506 configurable:false,
507 enumerable:false,
508 set: setter1,
509 get: getter2
510};
511
512assertFalse(Reflect.defineProperty(obj5, 'foo', descDifferent));
513
514// Different getter.
515descDifferent = {
516 configurable:false,
517 enumerable:false,
518 set: setter2,
519 get: getter1
520};
521
522assertFalse(Reflect.defineProperty(obj5, 'foo', descDifferent));
523
524// Different enumerable.
525descDifferent = {
526 configurable:false,
527 enumerable:true,
528 set: setter2,
529 get: getter2
530};
531
532assertFalse(Reflect.defineProperty(obj5, 'foo', descDifferent));
533
534// Different configurable.
535descDifferent = {
536 configurable:false,
537 enumerable:true,
538 set: setter2,
539 get: getter2
540};
541
542assertFalse(Reflect.defineProperty(obj5, 'foo', descDifferent));
543
544// No difference.
545descDifferent = {
546 configurable:false,
547 enumerable:false,
548 set: setter2,
549 get: getter2
550};
551// Make sure we can still redefine if all properties are the same.
552assertTrue(Reflect.defineProperty(obj5, 'foo', descDifferent));
553
554// Make sure that obj5 still holds the original values.
555desc = Object.getOwnPropertyDescriptor(obj5, 'foo');
556assertEquals(desc.get, getter2);
557assertEquals(desc.set, setter2);
558assertFalse(desc.enumerable);
559assertFalse(desc.configurable);
560
561
562// Also exercise step 6 on data property, writable and enumerable
563// defaults to false.
564assertTrue(Reflect.defineProperty(obj5, 'bar', dataNoConfigurable));
565
566// Test that redefinition with the same property descriptor is possible
567assertTrue(Reflect.defineProperty(obj5, 'bar', dataNoConfigurable));
568
569// Different value.
570descDifferent = {
571 configurable:false,
572 enumerable:false,
573 writable: false,
574 value: 1999
575};
576
577assertFalse(Reflect.defineProperty(obj5, 'bar', descDifferent));
578
579// Different writable.
580descDifferent = {
581 configurable:false,
582 enumerable:false,
583 writable: true,
584 value: 2000
585};
586
587assertFalse(Reflect.defineProperty(obj5, 'bar', descDifferent));
588
589
590// Different enumerable.
591descDifferent = {
592 configurable:false,
593 enumerable:true ,
594 writable:false,
595 value: 2000
596};
597
598assertFalse(Reflect.defineProperty(obj5, 'bar', descDifferent));
599
600
601// Different configurable.
602descDifferent = {
603 configurable:true,
604 enumerable:false,
605 writable:false,
606 value: 2000
607};
608
609assertFalse(Reflect.defineProperty(obj5, 'bar', descDifferent));
610
611// No difference.
612descDifferent = {
613 configurable:false,
614 enumerable:false,
615 writable:false,
616 value:2000
617};
618// Make sure we can still redefine if all properties are the same.
619assertTrue(Reflect.defineProperty(obj5, 'bar', descDifferent));
620
621// Make sure that obj5 still holds the original values.
622desc = Object.getOwnPropertyDescriptor(obj5, 'bar');
623assertEquals(desc.value, 2000);
624assertFalse(desc.writable);
625assertFalse(desc.enumerable);
626assertFalse(desc.configurable);
627
628
629// Make sure that we can't overwrite +0 with -0 and vice versa.
630var descMinusZero = {value: -0, configurable: false};
631var descPlusZero = {value: +0, configurable: false};
632
633assertTrue(Reflect.defineProperty(obj5, 'minuszero', descMinusZero));
634
635// Make sure we can redefine with -0.
636assertTrue(Reflect.defineProperty(obj5, 'minuszero', descMinusZero));
637
638assertFalse(Reflect.defineProperty(obj5, 'minuszero', descPlusZero));
639
640
641assertTrue(Reflect.defineProperty(obj5, 'pluszero', descPlusZero));
642
643// Make sure we can redefine with +0.
644assertTrue(Reflect.defineProperty(obj5, 'pluszero', descPlusZero));
645
646assertFalse(Reflect.defineProperty(obj5, 'pluszero', descMinusZero));
647
648
649var obj6 = {};
650obj6[1] = 'foo';
651obj6[2] = 'bar';
652obj6[3] = '42';
653obj6[4] = '43';
654obj6[5] = '44';
655
656var descElement = { value: 'foobar' };
657var descElementNonConfigurable = { value: 'barfoo', configurable: false };
658var descElementNonWritable = { value: 'foofoo', writable: false };
659var descElementNonEnumerable = { value: 'barbar', enumerable: false };
660var descElementAllFalse = { value: 'foofalse',
661 configurable: false,
662 writable: false,
663 enumerable: false };
664
665
666// Redefine existing property.
667assertTrue(Reflect.defineProperty(obj6, '1', descElement));
668desc = Object.getOwnPropertyDescriptor(obj6, '1');
669assertEquals(desc.value, 'foobar');
670assertTrue(desc.writable);
671assertTrue(desc.enumerable);
672assertTrue(desc.configurable);
673
674// Redefine existing property with configurable: false.
675assertTrue(Reflect.defineProperty(obj6, '2', descElementNonConfigurable));
676desc = Object.getOwnPropertyDescriptor(obj6, '2');
677assertEquals(desc.value, 'barfoo');
678assertTrue(desc.writable);
679assertTrue(desc.enumerable);
680assertFalse(desc.configurable);
681
682// Can use defineProperty to change the value of a non
683// configurable property.
684try {
685 assertTrue(Reflect.defineProperty(obj6, '2', descElement));
686 desc = Object.getOwnPropertyDescriptor(obj6, '2');
687 assertEquals(desc.value, 'foobar');
688} catch (e) {
689 assertUnreachable();
690}
691
692// Ensure that we can't change the descriptor of a
693// non configurable property.
694var descAccessor = { get: function() { return 0; } };
695assertFalse(Reflect.defineProperty(obj6, '2', descAccessor));
696
697assertTrue(Reflect.defineProperty(obj6, '2', descElementNonWritable));
698desc = Object.getOwnPropertyDescriptor(obj6, '2');
699assertEquals(desc.value, 'foofoo');
700assertFalse(desc.writable);
701assertTrue(desc.enumerable);
702assertFalse(desc.configurable);
703
704assertTrue(Reflect.defineProperty(obj6, '3', descElementNonWritable));
705desc = Object.getOwnPropertyDescriptor(obj6, '3');
706assertEquals(desc.value, 'foofoo');
707assertFalse(desc.writable);
708assertTrue(desc.enumerable);
709assertTrue(desc.configurable);
710
711// Redefine existing property with configurable: false.
712assertTrue(Reflect.defineProperty(obj6, '4', descElementNonEnumerable));
713desc = Object.getOwnPropertyDescriptor(obj6, '4');
714assertEquals(desc.value, 'barbar');
715assertTrue(desc.writable);
716assertFalse(desc.enumerable);
717assertTrue(desc.configurable);
718
719// Redefine existing property with configurable: false.
720assertTrue(Reflect.defineProperty(obj6, '5', descElementAllFalse));
721desc = Object.getOwnPropertyDescriptor(obj6, '5');
722assertEquals(desc.value, 'foofalse');
723assertFalse(desc.writable);
724assertFalse(desc.enumerable);
725assertFalse(desc.configurable);
726
727// Define non existing property - all attributes should default to false.
728assertTrue(Reflect.defineProperty(obj6, '15', descElement));
729desc = Object.getOwnPropertyDescriptor(obj6, '15');
730assertEquals(desc.value, 'foobar');
731assertFalse(desc.writable);
732assertFalse(desc.enumerable);
733assertFalse(desc.configurable);
734
735// Make sure that we can't redefine using direct access.
736obj6[15] ='overwrite';
737assertEquals(obj6[15],'foobar');
738
739
740// Repeat the above tests on an array.
741var arr = new Array();
742arr[1] = 'foo';
743arr[2] = 'bar';
744arr[3] = '42';
745arr[4] = '43';
746arr[5] = '44';
747
748var descElement = { value: 'foobar' };
749var descElementNonConfigurable = { value: 'barfoo', configurable: false };
750var descElementNonWritable = { value: 'foofoo', writable: false };
751var descElementNonEnumerable = { value: 'barbar', enumerable: false };
752var descElementAllFalse = { value: 'foofalse',
753 configurable: false,
754 writable: false,
755 enumerable: false };
756
757
758// Redefine existing property.
759assertTrue(Reflect.defineProperty(arr, '1', descElement));
760desc = Object.getOwnPropertyDescriptor(arr, '1');
761assertEquals(desc.value, 'foobar');
762assertTrue(desc.writable);
763assertTrue(desc.enumerable);
764assertTrue(desc.configurable);
765
766// Redefine existing property with configurable: false.
767assertTrue(Reflect.defineProperty(arr, '2', descElementNonConfigurable));
768desc = Object.getOwnPropertyDescriptor(arr, '2');
769assertEquals(desc.value, 'barfoo');
770assertTrue(desc.writable);
771assertTrue(desc.enumerable);
772assertFalse(desc.configurable);
773
774// Can use defineProperty to change the value of a non
775// configurable property of an array.
776try {
777 assertTrue(Reflect.defineProperty(arr, '2', descElement));
778 desc = Object.getOwnPropertyDescriptor(arr, '2');
779 assertEquals(desc.value, 'foobar');
780} catch (e) {
781 assertUnreachable();
782}
783
784// Ensure that we can't change the descriptor of a
785// non configurable property.
786var descAccessor = { get: function() { return 0; } };
787assertFalse(Reflect.defineProperty(arr, '2', descAccessor));
788
789assertTrue(Reflect.defineProperty(arr, '2', descElementNonWritable));
790desc = Object.getOwnPropertyDescriptor(arr, '2');
791assertEquals(desc.value, 'foofoo');
792assertFalse(desc.writable);
793assertTrue(desc.enumerable);
794assertFalse(desc.configurable);
795
796assertTrue(Reflect.defineProperty(arr, '3', descElementNonWritable));
797desc = Object.getOwnPropertyDescriptor(arr, '3');
798assertEquals(desc.value, 'foofoo');
799assertFalse(desc.writable);
800assertTrue(desc.enumerable);
801assertTrue(desc.configurable);
802
803// Redefine existing property with configurable: false.
804assertTrue(Reflect.defineProperty(arr, '4', descElementNonEnumerable));
805desc = Object.getOwnPropertyDescriptor(arr, '4');
806assertEquals(desc.value, 'barbar');
807assertTrue(desc.writable);
808assertFalse(desc.enumerable);
809assertTrue(desc.configurable);
810
811// Redefine existing property with configurable: false.
812assertTrue(Reflect.defineProperty(arr, '5', descElementAllFalse));
813desc = Object.getOwnPropertyDescriptor(arr, '5');
814assertEquals(desc.value, 'foofalse');
815assertFalse(desc.writable);
816assertFalse(desc.enumerable);
817assertFalse(desc.configurable);
818
819// Define non existing property - all attributes should default to false.
820assertTrue(Reflect.defineProperty(arr, '15', descElement));
821desc = Object.getOwnPropertyDescriptor(arr, '15');
822assertEquals(desc.value, 'foobar');
823assertFalse(desc.writable);
824assertFalse(desc.enumerable);
825assertFalse(desc.configurable);
826
827// Define non-array property, check that .length is unaffected.
828assertEquals(16, arr.length);
829assertTrue(Reflect.defineProperty(arr, '0x20', descElement));
830assertEquals(16, arr.length);
831
832// See issue 968: http://code.google.com/p/v8/issues/detail?id=968
833var o = { x : 42 };
834assertTrue(Reflect.defineProperty(o, "x", { writable: false }));
835assertEquals(42, o.x);
836o.x = 37;
837assertEquals(42, o.x);
838
839o = { x : 42 };
840assertTrue(Reflect.defineProperty(o, "x", {}));
841assertEquals(42, o.x);
842o.x = 37;
843// Writability is preserved.
844assertEquals(37, o.x);
845
846var o = { };
847assertTrue(Reflect.defineProperty(o, "x", { writable: false }));
848assertEquals(undefined, o.x);
849o.x = 37;
850assertEquals(undefined, o.x);
851
852o = { get x() { return 87; } };
853assertTrue(Reflect.defineProperty(o, "x", { writable: false }));
854assertEquals(undefined, o.x);
855o.x = 37;
856assertEquals(undefined, o.x);
857
858// Ignore inherited properties.
859o = { __proto__ : { x : 87 } };
860assertTrue(Reflect.defineProperty(o, "x", { writable: false }));
861assertEquals(undefined, o.x);
862o.x = 37;
863assertEquals(undefined, o.x);
864
865function testDefineProperty(obj, propertyName, desc, resultDesc) {
866 assertTrue(Reflect.defineProperty(obj, propertyName, desc));
867 var actualDesc = Object.getOwnPropertyDescriptor(obj, propertyName);
868 assertEquals(resultDesc.enumerable, actualDesc.enumerable);
869 assertEquals(resultDesc.configurable, actualDesc.configurable);
870 if (resultDesc.hasOwnProperty('value')) {
871 assertEquals(resultDesc.value, actualDesc.value);
872 assertEquals(resultDesc.writable, actualDesc.writable);
873 assertFalse(resultDesc.hasOwnProperty('get'));
874 assertFalse(resultDesc.hasOwnProperty('set'));
875 } else {
876 assertEquals(resultDesc.get, actualDesc.get);
877 assertEquals(resultDesc.set, actualDesc.set);
878 assertFalse(resultDesc.hasOwnProperty('value'));
879 assertFalse(resultDesc.hasOwnProperty('writable'));
880 }
881}
882
883// tests redefining existing property with a generic descriptor
884o = { p : 42 };
885testDefineProperty(o, 'p',
886 { },
887 { value : 42, writable : true, enumerable : true, configurable : true });
888
889o = { p : 42 };
890testDefineProperty(o, 'p',
891 { enumerable : true },
892 { value : 42, writable : true, enumerable : true, configurable : true });
893
894o = { p : 42 };
895testDefineProperty(o, 'p',
896 { configurable : true },
897 { value : 42, writable : true, enumerable : true, configurable : true });
898
899o = { p : 42 };
900testDefineProperty(o, 'p',
901 { enumerable : false },
902 { value : 42, writable : true, enumerable : false, configurable : true });
903
904o = { p : 42 };
905testDefineProperty(o, 'p',
906 { configurable : false },
907 { value : 42, writable : true, enumerable : true, configurable : false });
908
909o = { p : 42 };
910testDefineProperty(o, 'p',
911 { enumerable : true, configurable : true },
912 { value : 42, writable : true, enumerable : true, configurable : true });
913
914o = { p : 42 };
915testDefineProperty(o, 'p',
916 { enumerable : false, configurable : true },
917 { value : 42, writable : true, enumerable : false, configurable : true });
918
919o = { p : 42 };
920testDefineProperty(o, 'p',
921 { enumerable : true, configurable : false },
922 { value : 42, writable : true, enumerable : true, configurable : false });
923
924o = { p : 42 };
925testDefineProperty(o, 'p',
926 { enumerable : false, configurable : false },
927 { value : 42, writable : true, enumerable : false, configurable : false });
928
929// can make a writable, non-configurable field non-writable
930o = { p : 42 };
931assertTrue(Reflect.defineProperty(o, 'p', { configurable: false }));
932testDefineProperty(o, 'p',
933 { writable: false },
934 { value : 42, writable : false, enumerable : true, configurable : false });
935
936// redefine of get only property with generic descriptor
937o = {};
938assertTrue(Reflect.defineProperty(o, 'p',
939 { get : getter1, enumerable: true, configurable: true }));
940testDefineProperty(o, 'p',
941 { enumerable : false, configurable : false },
942 { get: getter1, set: undefined, enumerable : false, configurable : false });
943
944// redefine of get/set only property with generic descriptor
945o = {};
946assertTrue(Reflect.defineProperty(o, 'p',
947 { get: getter1, set: setter1, enumerable: true, configurable: true }));
948testDefineProperty(o, 'p',
949 { enumerable : false, configurable : false },
950 { get: getter1, set: setter1, enumerable : false, configurable : false });
951
952// redefine of set only property with generic descriptor
953o = {};
954assertTrue(Reflect.defineProperty(o, 'p',
955 { set : setter1, enumerable: true, configurable: true }));
956testDefineProperty(o, 'p',
957 { enumerable : false, configurable : false },
958 { get: undefined, set: setter1, enumerable : false, configurable : false });
959
960
961// Regression test: Ensure that growing dictionaries are not ignored.
962o = {};
963for (var i = 0; i < 1000; i++) {
964 // Non-enumerable property forces dictionary mode.
965 assertTrue(Reflect.defineProperty(o, i, {value: i, enumerable: false}));
966}
967assertEquals(999, o[999]);
968
969
970// Regression test: Bizzare behavior on non-strict arguments object.
971// TODO(yangguo): Tests disabled, needs investigation!
972/*
973(function test(arg0) {
974 // Here arguments[0] is a fast alias on arg0.
975 Reflect.defineProperty(arguments, "0", {
976 value:1,
977 enumerable:false
978 });
979 // Here arguments[0] is a slow alias on arg0.
980 Reflect.defineProperty(arguments, "0", {
981 value:2,
982 writable:false
983 });
984 // Here arguments[0] is no alias at all.
985 Reflect.defineProperty(arguments, "0", {
986 value:3
987 });
988 assertEquals(2, arg0);
989 assertEquals(3, arguments[0]);
990})(0);
991*/
992
993// Regression test: We should never observe the hole value.
994var objectWithGetter = {};
995objectWithGetter.__defineGetter__('foo', function() {});
996assertEquals(undefined, objectWithGetter.__lookupSetter__('foo'));
997
998var objectWithSetter = {};
999objectWithSetter.__defineSetter__('foo', function(x) {});
1000assertEquals(undefined, objectWithSetter.__lookupGetter__('foo'));
1001
1002// An object with a getter on the prototype chain.
1003function getter() { return 111; }
1004function anotherGetter() { return 222; }
1005
1006function testGetterOnProto(expected, o) {
1007 assertEquals(expected, o.quebec);
1008}
1009
1010obj1 = {};
1011assertTrue(
1012 Reflect.defineProperty(obj1, "quebec", { get: getter, configurable: true }));
1013obj2 = Object.create(obj1);
1014obj3 = Object.create(obj2);
1015
1016testGetterOnProto(111, obj3);
1017testGetterOnProto(111, obj3);
1018%OptimizeFunctionOnNextCall(testGetterOnProto);
1019testGetterOnProto(111, obj3);
1020testGetterOnProto(111, obj3);
1021
1022assertTrue(Reflect.defineProperty(obj1, "quebec", { get: anotherGetter }));
1023
1024testGetterOnProto(222, obj3);
1025testGetterOnProto(222, obj3);
1026%OptimizeFunctionOnNextCall(testGetterOnProto);
1027testGetterOnProto(222, obj3);
1028testGetterOnProto(222, obj3);
1029
1030// An object with a setter on the prototype chain.
1031var modifyMe;
1032function setter(x) { modifyMe = x+1; }
1033function anotherSetter(x) { modifyMe = x+2; }
1034
1035function testSetterOnProto(expected, o) {
1036 modifyMe = 333;
1037 o.romeo = 444;
1038 assertEquals(expected, modifyMe);
1039}
1040
1041obj1 = {};
1042assertTrue(
1043 Reflect.defineProperty(obj1, "romeo", { set: setter, configurable: true }));
1044obj2 = Object.create(obj1);
1045obj3 = Object.create(obj2);
1046
1047testSetterOnProto(445, obj3);
1048testSetterOnProto(445, obj3);
1049%OptimizeFunctionOnNextCall(testSetterOnProto);
1050testSetterOnProto(445, obj3);
1051testSetterOnProto(445, obj3);
1052
1053assertTrue(Reflect.defineProperty(obj1, "romeo", { set: anotherSetter }));
1054
1055testSetterOnProto(446, obj3);
1056testSetterOnProto(446, obj3);
1057%OptimizeFunctionOnNextCall(testSetterOnProto);
1058testSetterOnProto(446, obj3);
1059testSetterOnProto(446, obj3);
1060
1061// Removing a setter on the prototype chain.
1062function testSetterOnProtoStrict(o) {
1063 "use strict";
1064 o.sierra = 12345;
1065}
1066
1067obj1 = {};
1068assertTrue(Reflect.defineProperty(obj1, "sierra",
1069 { get: getter, set: setter, configurable: true }));
1070obj2 = Object.create(obj1);
1071obj3 = Object.create(obj2);
1072
1073testSetterOnProtoStrict(obj3);
1074testSetterOnProtoStrict(obj3);
1075%OptimizeFunctionOnNextCall(testSetterOnProtoStrict);
1076testSetterOnProtoStrict(obj3);
1077testSetterOnProtoStrict(obj3);
1078
1079assertTrue(Reflect.defineProperty(obj1, "sierra",
1080 { get: getter, set: undefined, configurable: true }));
1081
1082exception = false;
1083try {
1084 testSetterOnProtoStrict(obj3);
1085} catch (e) {
1086 exception = true;
1087 assertTrue(/which has only a getter/.test(e));
1088}
1089assertTrue(exception);
1090
1091// Test assignment to a getter-only property on the prototype chain. This makes
1092// sure that crankshaft re-checks its assumptions and doesn't rely only on type
1093// feedback (which would be monomorphic here).
1094
1095function Assign(o) {
1096 o.blubb = 123;
1097}
1098
1099function C() {}
1100
1101Assign(new C);
1102Assign(new C);
1103%OptimizeFunctionOnNextCall(Assign);
1104assertTrue(
1105 Reflect.defineProperty(C.prototype, "blubb", {get: function() {return -42}}));
1106Assign(new C);
1107
1108// Test that changes to the prototype of a simple constructor are not ignored,
1109// even after creating initial instances.
1110function C() {
1111 this.x = 23;
1112}
1113assertEquals(23, new C().x);
1114C.prototype.__defineSetter__('x', function(value) { this.y = 23; });
1115assertEquals(void 0, new C().x);