• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// 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
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 DefineAccessorPropertyUnchecked - make sure we don't
445// crash.
446try {
447  %DefineAccessorPropertyUnchecked(0, 0, 0, 0, 0);
448} catch (e) {
449  assertTrue(/illegal access/.test(e));
450}
451
452try {
453  %DefineAccessorPropertyUnchecked(null, null, null, null, null);
454} catch (e) {
455  assertTrue(/illegal access/.test(e));
456}
457
458// Defining properties null should fail even when we have
459// other allowed values
460try {
461  %DefineAccessorPropertyUnchecked(null, 'foo', func, null, 0);
462} catch (e) {
463  assertTrue(/illegal access/.test(e));
464}
465
466// Test that all possible differences in step 6 in DefineOwnProperty are
467// exercised, i.e., any difference in the given property descriptor and the
468// existing properties should not return true, but throw an error if the
469// existing configurable property is false.
470
471var obj5 = {};
472// Enumerable will default to false.
473assertTrue(Reflect.defineProperty(obj5, 'foo', accessorNoConfigurable));
474desc = Object.getOwnPropertyDescriptor(obj5, 'foo');
475// First, test that we are actually allowed to set the accessor if all
476// values are of the descriptor are the same as the existing one.
477assertTrue(Reflect.defineProperty(obj5, 'foo', accessorNoConfigurable));
478
479// Different setter.
480var descDifferent = {
481  configurable:false,
482  enumerable:false,
483  set: setter1,
484  get: getter2
485};
486
487assertFalse(Reflect.defineProperty(obj5, 'foo', descDifferent));
488
489// Different getter.
490descDifferent = {
491  configurable:false,
492  enumerable:false,
493  set: setter2,
494  get: getter1
495};
496
497assertFalse(Reflect.defineProperty(obj5, 'foo', descDifferent));
498
499// Different enumerable.
500descDifferent = {
501  configurable:false,
502  enumerable:true,
503  set: setter2,
504  get: getter2
505};
506
507assertFalse(Reflect.defineProperty(obj5, 'foo', descDifferent));
508
509// Different configurable.
510descDifferent = {
511  configurable:false,
512  enumerable:true,
513  set: setter2,
514  get: getter2
515};
516
517assertFalse(Reflect.defineProperty(obj5, 'foo', descDifferent));
518
519// No difference.
520descDifferent = {
521  configurable:false,
522  enumerable:false,
523  set: setter2,
524  get: getter2
525};
526// Make sure we can still redefine if all properties are the same.
527assertTrue(Reflect.defineProperty(obj5, 'foo', descDifferent));
528
529// Make sure that obj5 still holds the original values.
530desc = Object.getOwnPropertyDescriptor(obj5, 'foo');
531assertEquals(desc.get, getter2);
532assertEquals(desc.set, setter2);
533assertFalse(desc.enumerable);
534assertFalse(desc.configurable);
535
536
537// Also exercise step 6 on data property, writable and enumerable
538// defaults to false.
539assertTrue(Reflect.defineProperty(obj5, 'bar', dataNoConfigurable));
540
541// Test that redefinition with the same property descriptor is possible
542assertTrue(Reflect.defineProperty(obj5, 'bar', dataNoConfigurable));
543
544// Different value.
545descDifferent = {
546  configurable:false,
547  enumerable:false,
548  writable: false,
549  value: 1999
550};
551
552assertFalse(Reflect.defineProperty(obj5, 'bar', descDifferent));
553
554// Different writable.
555descDifferent = {
556  configurable:false,
557  enumerable:false,
558  writable: true,
559  value: 2000
560};
561
562assertFalse(Reflect.defineProperty(obj5, 'bar', descDifferent));
563
564
565// Different enumerable.
566descDifferent = {
567  configurable:false,
568  enumerable:true ,
569  writable:false,
570  value: 2000
571};
572
573assertFalse(Reflect.defineProperty(obj5, 'bar', descDifferent));
574
575
576// Different configurable.
577descDifferent = {
578  configurable:true,
579  enumerable:false,
580  writable:false,
581  value: 2000
582};
583
584assertFalse(Reflect.defineProperty(obj5, 'bar', descDifferent));
585
586// No difference.
587descDifferent = {
588  configurable:false,
589  enumerable:false,
590  writable:false,
591  value:2000
592};
593// Make sure we can still redefine if all properties are the same.
594assertTrue(Reflect.defineProperty(obj5, 'bar', descDifferent));
595
596// Make sure that obj5 still holds the original values.
597desc = Object.getOwnPropertyDescriptor(obj5, 'bar');
598assertEquals(desc.value, 2000);
599assertFalse(desc.writable);
600assertFalse(desc.enumerable);
601assertFalse(desc.configurable);
602
603
604// Make sure that we can't overwrite +0 with -0 and vice versa.
605var descMinusZero = {value: -0, configurable: false};
606var descPlusZero = {value: +0, configurable: false};
607
608assertTrue(Reflect.defineProperty(obj5, 'minuszero', descMinusZero));
609
610// Make sure we can redefine with -0.
611assertTrue(Reflect.defineProperty(obj5, 'minuszero', descMinusZero));
612
613assertFalse(Reflect.defineProperty(obj5, 'minuszero', descPlusZero));
614
615
616assertTrue(Reflect.defineProperty(obj5, 'pluszero', descPlusZero));
617
618// Make sure we can redefine with +0.
619assertTrue(Reflect.defineProperty(obj5, 'pluszero', descPlusZero));
620
621assertFalse(Reflect.defineProperty(obj5, 'pluszero', descMinusZero));
622
623
624var obj6 = {};
625obj6[1] = 'foo';
626obj6[2] = 'bar';
627obj6[3] = '42';
628obj6[4] = '43';
629obj6[5] = '44';
630
631var descElement = { value: 'foobar' };
632var descElementNonConfigurable = { value: 'barfoo', configurable: false };
633var descElementNonWritable = { value: 'foofoo', writable: false };
634var descElementNonEnumerable = { value: 'barbar', enumerable: false };
635var descElementAllFalse = { value: 'foofalse',
636                            configurable: false,
637                            writable: false,
638                            enumerable: false };
639
640
641// Redefine existing property.
642assertTrue(Reflect.defineProperty(obj6, '1', descElement));
643desc = Object.getOwnPropertyDescriptor(obj6, '1');
644assertEquals(desc.value, 'foobar');
645assertTrue(desc.writable);
646assertTrue(desc.enumerable);
647assertTrue(desc.configurable);
648
649// Redefine existing property with configurable: false.
650assertTrue(Reflect.defineProperty(obj6, '2', descElementNonConfigurable));
651desc = Object.getOwnPropertyDescriptor(obj6, '2');
652assertEquals(desc.value, 'barfoo');
653assertTrue(desc.writable);
654assertTrue(desc.enumerable);
655assertFalse(desc.configurable);
656
657// Can use defineProperty to change the value of a non
658// configurable property.
659try {
660  assertTrue(Reflect.defineProperty(obj6, '2', descElement));
661  desc = Object.getOwnPropertyDescriptor(obj6, '2');
662  assertEquals(desc.value, 'foobar');
663} catch (e) {
664  assertUnreachable();
665}
666
667// Ensure that we can't change the descriptor of a
668// non configurable property.
669var descAccessor = { get: function() { return 0; } };
670assertFalse(Reflect.defineProperty(obj6, '2', descAccessor));
671
672assertTrue(Reflect.defineProperty(obj6, '2', descElementNonWritable));
673desc = Object.getOwnPropertyDescriptor(obj6, '2');
674assertEquals(desc.value, 'foofoo');
675assertFalse(desc.writable);
676assertTrue(desc.enumerable);
677assertFalse(desc.configurable);
678
679assertTrue(Reflect.defineProperty(obj6, '3', descElementNonWritable));
680desc = Object.getOwnPropertyDescriptor(obj6, '3');
681assertEquals(desc.value, 'foofoo');
682assertFalse(desc.writable);
683assertTrue(desc.enumerable);
684assertTrue(desc.configurable);
685
686// Redefine existing property with configurable: false.
687assertTrue(Reflect.defineProperty(obj6, '4', descElementNonEnumerable));
688desc = Object.getOwnPropertyDescriptor(obj6, '4');
689assertEquals(desc.value, 'barbar');
690assertTrue(desc.writable);
691assertFalse(desc.enumerable);
692assertTrue(desc.configurable);
693
694// Redefine existing property with configurable: false.
695assertTrue(Reflect.defineProperty(obj6, '5', descElementAllFalse));
696desc = Object.getOwnPropertyDescriptor(obj6, '5');
697assertEquals(desc.value, 'foofalse');
698assertFalse(desc.writable);
699assertFalse(desc.enumerable);
700assertFalse(desc.configurable);
701
702// Define non existing property - all attributes should default to false.
703assertTrue(Reflect.defineProperty(obj6, '15', descElement));
704desc = Object.getOwnPropertyDescriptor(obj6, '15');
705assertEquals(desc.value, 'foobar');
706assertFalse(desc.writable);
707assertFalse(desc.enumerable);
708assertFalse(desc.configurable);
709
710// Make sure that we can't redefine using direct access.
711obj6[15] ='overwrite';
712assertEquals(obj6[15],'foobar');
713
714
715// Repeat the above tests on an array.
716var arr = new Array();
717arr[1] = 'foo';
718arr[2] = 'bar';
719arr[3] = '42';
720arr[4] = '43';
721arr[5] = '44';
722
723var descElement = { value: 'foobar' };
724var descElementNonConfigurable = { value: 'barfoo', configurable: false };
725var descElementNonWritable = { value: 'foofoo', writable: false };
726var descElementNonEnumerable = { value: 'barbar', enumerable: false };
727var descElementAllFalse = { value: 'foofalse',
728                            configurable: false,
729                            writable: false,
730                            enumerable: false };
731
732
733// Redefine existing property.
734assertTrue(Reflect.defineProperty(arr, '1', descElement));
735desc = Object.getOwnPropertyDescriptor(arr, '1');
736assertEquals(desc.value, 'foobar');
737assertTrue(desc.writable);
738assertTrue(desc.enumerable);
739assertTrue(desc.configurable);
740
741// Redefine existing property with configurable: false.
742assertTrue(Reflect.defineProperty(arr, '2', descElementNonConfigurable));
743desc = Object.getOwnPropertyDescriptor(arr, '2');
744assertEquals(desc.value, 'barfoo');
745assertTrue(desc.writable);
746assertTrue(desc.enumerable);
747assertFalse(desc.configurable);
748
749// Can use defineProperty to change the value of a non
750// configurable property of an array.
751try {
752  assertTrue(Reflect.defineProperty(arr, '2', descElement));
753  desc = Object.getOwnPropertyDescriptor(arr, '2');
754  assertEquals(desc.value, 'foobar');
755} catch (e) {
756  assertUnreachable();
757}
758
759// Ensure that we can't change the descriptor of a
760// non configurable property.
761var descAccessor = { get: function() { return 0; } };
762assertFalse(Reflect.defineProperty(arr, '2', descAccessor));
763
764assertTrue(Reflect.defineProperty(arr, '2', descElementNonWritable));
765desc = Object.getOwnPropertyDescriptor(arr, '2');
766assertEquals(desc.value, 'foofoo');
767assertFalse(desc.writable);
768assertTrue(desc.enumerable);
769assertFalse(desc.configurable);
770
771assertTrue(Reflect.defineProperty(arr, '3', descElementNonWritable));
772desc = Object.getOwnPropertyDescriptor(arr, '3');
773assertEquals(desc.value, 'foofoo');
774assertFalse(desc.writable);
775assertTrue(desc.enumerable);
776assertTrue(desc.configurable);
777
778// Redefine existing property with configurable: false.
779assertTrue(Reflect.defineProperty(arr, '4', descElementNonEnumerable));
780desc = Object.getOwnPropertyDescriptor(arr, '4');
781assertEquals(desc.value, 'barbar');
782assertTrue(desc.writable);
783assertFalse(desc.enumerable);
784assertTrue(desc.configurable);
785
786// Redefine existing property with configurable: false.
787assertTrue(Reflect.defineProperty(arr, '5', descElementAllFalse));
788desc = Object.getOwnPropertyDescriptor(arr, '5');
789assertEquals(desc.value, 'foofalse');
790assertFalse(desc.writable);
791assertFalse(desc.enumerable);
792assertFalse(desc.configurable);
793
794// Define non existing property - all attributes should default to false.
795assertTrue(Reflect.defineProperty(arr, '15', descElement));
796desc = Object.getOwnPropertyDescriptor(arr, '15');
797assertEquals(desc.value, 'foobar');
798assertFalse(desc.writable);
799assertFalse(desc.enumerable);
800assertFalse(desc.configurable);
801
802// Define non-array property, check that .length is unaffected.
803assertEquals(16, arr.length);
804assertTrue(Reflect.defineProperty(arr, '0x20', descElement));
805assertEquals(16, arr.length);
806
807// See issue 968: http://code.google.com/p/v8/issues/detail?id=968
808var o = { x : 42 };
809assertTrue(Reflect.defineProperty(o, "x", { writable: false }));
810assertEquals(42, o.x);
811o.x = 37;
812assertEquals(42, o.x);
813
814o = { x : 42 };
815assertTrue(Reflect.defineProperty(o, "x", {}));
816assertEquals(42, o.x);
817o.x = 37;
818// Writability is preserved.
819assertEquals(37, o.x);
820
821var o = { };
822assertTrue(Reflect.defineProperty(o, "x", { writable: false }));
823assertEquals(undefined, o.x);
824o.x = 37;
825assertEquals(undefined, o.x);
826
827o = { get x() { return 87; } };
828assertTrue(Reflect.defineProperty(o, "x", { writable: false }));
829assertEquals(undefined, o.x);
830o.x = 37;
831assertEquals(undefined, o.x);
832
833// Ignore inherited properties.
834o = { __proto__ : { x : 87 } };
835assertTrue(Reflect.defineProperty(o, "x", { writable: false }));
836assertEquals(undefined, o.x);
837o.x = 37;
838assertEquals(undefined, o.x);
839
840function testDefineProperty(obj, propertyName, desc, resultDesc) {
841  assertTrue(Reflect.defineProperty(obj, propertyName, desc));
842  var actualDesc = Object.getOwnPropertyDescriptor(obj, propertyName);
843  assertEquals(resultDesc.enumerable, actualDesc.enumerable);
844  assertEquals(resultDesc.configurable, actualDesc.configurable);
845  if (resultDesc.hasOwnProperty('value')) {
846    assertEquals(resultDesc.value, actualDesc.value);
847    assertEquals(resultDesc.writable, actualDesc.writable);
848    assertFalse(resultDesc.hasOwnProperty('get'));
849    assertFalse(resultDesc.hasOwnProperty('set'));
850  } else {
851    assertEquals(resultDesc.get, actualDesc.get);
852    assertEquals(resultDesc.set, actualDesc.set);
853    assertFalse(resultDesc.hasOwnProperty('value'));
854    assertFalse(resultDesc.hasOwnProperty('writable'));
855  }
856}
857
858// tests redefining existing property with a generic descriptor
859o = { p : 42 };
860testDefineProperty(o, 'p',
861  { },
862  { value : 42, writable : true, enumerable : true, configurable : true });
863
864o = { p : 42 };
865testDefineProperty(o, 'p',
866  { enumerable : true },
867  { value : 42, writable : true, enumerable : true, configurable : true });
868
869o = { p : 42 };
870testDefineProperty(o, 'p',
871  { configurable : true },
872  { value : 42, writable : true, enumerable : true, configurable : true });
873
874o = { p : 42 };
875testDefineProperty(o, 'p',
876  { enumerable : false },
877  { value : 42, writable : true, enumerable : false, configurable : true });
878
879o = { p : 42 };
880testDefineProperty(o, 'p',
881  { configurable : false },
882  { value : 42, writable : true, enumerable : true, configurable : false });
883
884o = { p : 42 };
885testDefineProperty(o, 'p',
886  { enumerable : true, configurable : true },
887  { value : 42, writable : true, enumerable : true, configurable : true });
888
889o = { p : 42 };
890testDefineProperty(o, 'p',
891  { enumerable : false, configurable : true },
892  { value : 42, writable : true, enumerable : false, configurable : true });
893
894o = { p : 42 };
895testDefineProperty(o, 'p',
896  { enumerable : true, configurable : false },
897  { value : 42, writable : true, enumerable : true, configurable : false });
898
899o = { p : 42 };
900testDefineProperty(o, 'p',
901  { enumerable : false, configurable : false },
902  { value : 42, writable : true, enumerable : false, configurable : false });
903
904// can make a writable, non-configurable field non-writable
905o = { p : 42 };
906assertTrue(Reflect.defineProperty(o, 'p', { configurable: false }));
907testDefineProperty(o, 'p',
908  { writable: false },
909  { value : 42, writable : false, enumerable : true, configurable : false });
910
911// redefine of get only property with generic descriptor
912o = {};
913assertTrue(Reflect.defineProperty(o, 'p',
914  { get : getter1, enumerable: true, configurable: true }));
915testDefineProperty(o, 'p',
916  { enumerable : false, configurable : false },
917  { get: getter1, set: undefined, enumerable : false, configurable : false });
918
919// redefine of get/set only property with generic descriptor
920o = {};
921assertTrue(Reflect.defineProperty(o, 'p',
922  { get: getter1, set: setter1, enumerable: true, configurable: true }));
923testDefineProperty(o, 'p',
924  { enumerable : false, configurable : false },
925  { get: getter1, set: setter1, enumerable : false, configurable : false });
926
927// redefine of set only property with generic descriptor
928o = {};
929assertTrue(Reflect.defineProperty(o, 'p',
930  { set : setter1, enumerable: true, configurable: true }));
931testDefineProperty(o, 'p',
932  { enumerable : false, configurable : false },
933  { get: undefined, set: setter1, enumerable : false, configurable : false });
934
935
936// Regression test: Ensure that growing dictionaries are not ignored.
937o = {};
938for (var i = 0; i < 1000; i++) {
939  // Non-enumerable property forces dictionary mode.
940  assertTrue(Reflect.defineProperty(o, i, {value: i, enumerable: false}));
941}
942assertEquals(999, o[999]);
943
944
945// Regression test: Bizzare behavior on non-strict arguments object.
946// TODO(yangguo): Tests disabled, needs investigation!
947/*
948(function test(arg0) {
949  // Here arguments[0] is a fast alias on arg0.
950  Reflect.defineProperty(arguments, "0", {
951    value:1,
952    enumerable:false
953  });
954  // Here arguments[0] is a slow alias on arg0.
955  Reflect.defineProperty(arguments, "0", {
956    value:2,
957    writable:false
958  });
959  // Here arguments[0] is no alias at all.
960  Reflect.defineProperty(arguments, "0", {
961    value:3
962  });
963  assertEquals(2, arg0);
964  assertEquals(3, arguments[0]);
965})(0);
966*/
967
968// Regression test: We should never observe the hole value.
969var objectWithGetter = {};
970objectWithGetter.__defineGetter__('foo', function() {});
971assertEquals(undefined, objectWithGetter.__lookupSetter__('foo'));
972
973var objectWithSetter = {};
974objectWithSetter.__defineSetter__('foo', function(x) {});
975assertEquals(undefined, objectWithSetter.__lookupGetter__('foo'));
976
977// An object with a getter on the prototype chain.
978function getter() { return 111; }
979function anotherGetter() { return 222; }
980
981function testGetterOnProto(expected, o) {
982  assertEquals(expected, o.quebec);
983}
984
985obj1 = {};
986assertTrue(
987  Reflect.defineProperty(obj1, "quebec", { get: getter, configurable: true }));
988obj2 = Object.create(obj1);
989obj3 = Object.create(obj2);
990
991testGetterOnProto(111, obj3);
992testGetterOnProto(111, obj3);
993%OptimizeFunctionOnNextCall(testGetterOnProto);
994testGetterOnProto(111, obj3);
995testGetterOnProto(111, obj3);
996
997assertTrue(Reflect.defineProperty(obj1, "quebec", { get: anotherGetter }));
998
999testGetterOnProto(222, obj3);
1000testGetterOnProto(222, obj3);
1001%OptimizeFunctionOnNextCall(testGetterOnProto);
1002testGetterOnProto(222, obj3);
1003testGetterOnProto(222, obj3);
1004
1005// An object with a setter on the prototype chain.
1006var modifyMe;
1007function setter(x) { modifyMe = x+1; }
1008function anotherSetter(x) { modifyMe = x+2; }
1009
1010function testSetterOnProto(expected, o) {
1011  modifyMe = 333;
1012  o.romeo = 444;
1013  assertEquals(expected, modifyMe);
1014}
1015
1016obj1 = {};
1017assertTrue(
1018  Reflect.defineProperty(obj1, "romeo", { set: setter, configurable: true }));
1019obj2 = Object.create(obj1);
1020obj3 = Object.create(obj2);
1021
1022testSetterOnProto(445, obj3);
1023testSetterOnProto(445, obj3);
1024%OptimizeFunctionOnNextCall(testSetterOnProto);
1025testSetterOnProto(445, obj3);
1026testSetterOnProto(445, obj3);
1027
1028assertTrue(Reflect.defineProperty(obj1, "romeo", { set: anotherSetter }));
1029
1030testSetterOnProto(446, obj3);
1031testSetterOnProto(446, obj3);
1032%OptimizeFunctionOnNextCall(testSetterOnProto);
1033testSetterOnProto(446, obj3);
1034testSetterOnProto(446, obj3);
1035
1036// Removing a setter on the prototype chain.
1037function testSetterOnProtoStrict(o) {
1038  "use strict";
1039  o.sierra = 12345;
1040}
1041
1042obj1 = {};
1043assertTrue(Reflect.defineProperty(obj1, "sierra",
1044                      { get: getter, set: setter, configurable: true }));
1045obj2 = Object.create(obj1);
1046obj3 = Object.create(obj2);
1047
1048testSetterOnProtoStrict(obj3);
1049testSetterOnProtoStrict(obj3);
1050%OptimizeFunctionOnNextCall(testSetterOnProtoStrict);
1051testSetterOnProtoStrict(obj3);
1052testSetterOnProtoStrict(obj3);
1053
1054assertTrue(Reflect.defineProperty(obj1, "sierra",
1055                      { get: getter, set: undefined, configurable: true }));
1056
1057exception = false;
1058try {
1059  testSetterOnProtoStrict(obj3);
1060} catch (e) {
1061  exception = true;
1062  assertTrue(/which has only a getter/.test(e));
1063}
1064assertTrue(exception);
1065
1066// Test assignment to a getter-only property on the prototype chain. This makes
1067// sure that crankshaft re-checks its assumptions and doesn't rely only on type
1068// feedback (which would be monomorphic here).
1069
1070function Assign(o) {
1071  o.blubb = 123;
1072}
1073
1074function C() {}
1075
1076Assign(new C);
1077Assign(new C);
1078%OptimizeFunctionOnNextCall(Assign);
1079assertTrue(
1080  Reflect.defineProperty(C.prototype, "blubb", {get: function() {return -42}}));
1081Assign(new C);
1082
1083// Test that changes to the prototype of a simple constructor are not ignored,
1084// even after creating initial instances.
1085function C() {
1086  this.x = 23;
1087}
1088assertEquals(23, new C().x);
1089C.prototype.__defineSetter__('x', function(value) { this.y = 23; });
1090assertEquals(void 0, new C().x);
1091