• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2010 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28// Tests the object.defineProperty method - ES 15.2.3.6
29
30// Flags: --allow-natives-syntax
31
32// Check that an exception is thrown when null is passed as object.
33try {
34  Object.defineProperty(null, null, null);
35  assertTrue(false);
36} catch (e) {
37  assertTrue(/called on non-object/.test(e));
38}
39
40// Check that an exception is thrown when undefined is passed as object.
41try {
42  Object.defineProperty(undefined, undefined, undefined);
43  assertTrue(false);
44} catch (e) {
45  assertTrue(/called on non-object/.test(e));
46}
47
48// Check that an exception is thrown when non-object is passed as object.
49try {
50  Object.defineProperty(0, "foo", undefined);
51  assertTrue(false);
52} catch (e) {
53  assertTrue(/called on non-object/.test(e));
54}
55
56// Object.
57var obj1 = {};
58
59// Values.
60var val1 = 0;
61var val2 = 0;
62var val3 = 0;
63
64function setter1() {val1++; }
65function getter1() {return val1; }
66
67function setter2() {val2++; }
68function getter2() {return val2; }
69
70function setter3() {val3++; }
71function getter3() {return val3; }
72
73
74// Descriptors.
75var emptyDesc = {};
76
77var accessorConfigurable = {
78    set: setter1,
79    get: getter1,
80    configurable: true
81};
82
83var accessorNoConfigurable = {
84    set: setter2,
85    get: getter2,
86    configurable: false
87};
88
89var accessorOnlySet = {
90  set: setter3,
91  configurable: true
92};
93
94var accessorOnlyGet = {
95  get: getter3,
96  configurable: true
97};
98
99var accessorDefault = {set: function(){} };
100
101var dataConfigurable = { value: 1000, configurable: true };
102
103var dataNoConfigurable = { value: 2000, configurable: false };
104
105var dataWritable = { value: 3000, writable: true};
106
107
108// Check that we can't add property with undefined attributes.
109try {
110  Object.defineProperty(obj1, "foo", undefined);
111  assertTrue(false);
112} catch (e) {
113  assertTrue(/must be an object/.test(e));
114}
115
116// Make sure that we can add a property with an empty descriptor and
117// that it has the default descriptor values.
118Object.defineProperty(obj1, "foo", emptyDesc);
119
120// foo should be undefined as it has no get, set or value
121assertEquals(undefined, obj1.foo);
122
123// We should, however, be able to retrieve the propertydescriptor which should
124// have all default values (according to 8.6.1).
125var desc = Object.getOwnPropertyDescriptor(obj1, "foo");
126assertFalse(desc.configurable);
127assertFalse(desc.enumerable);
128assertFalse(desc.writable);
129assertEquals(desc.get, undefined);
130assertEquals(desc.set, undefined);
131assertEquals(desc.value, undefined);
132
133// Make sure that getOwnPropertyDescriptor does not return a descriptor
134// with default values if called with non existing property (otherwise
135// the test above is invalid).
136desc = Object.getOwnPropertyDescriptor(obj1, "bar");
137assertEquals(desc, undefined);
138
139// Make sure that foo can't be reset (as configurable is false).
140try {
141  Object.defineProperty(obj1, "foo", accessorConfigurable);
142} catch (e) {
143  assertTrue(/Cannot redefine property/.test(e));
144}
145
146
147// Accessor properties
148
149Object.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
164Object.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.
181try {
182  Object.defineProperty(obj1, "bar", accessorConfigurable);
183  assertTrue(false);
184} catch(e) {
185  assertTrue(/Cannot redefine property/.test(e));
186}
187
188// Try to redefine bar again using the data descriptor - should fail.
189try {
190  Object.defineProperty(obj1, "bar", dataConfigurable);
191  assertTrue(false);
192} catch(e) {
193  assertTrue(/Cannot redefine property/.test(e));
194}
195
196// Redefine using same descriptor - should succeed.
197Object.defineProperty(obj1, "bar", accessorNoConfigurable);
198desc = Object.getOwnPropertyDescriptor(obj1, "bar");
199assertFalse(desc.configurable);
200assertFalse(desc.enumerable);
201assertEquals(desc.writable, undefined);
202assertEquals(desc.get, accessorNoConfigurable.get);
203assertEquals(desc.set, accessorNoConfigurable.set);
204assertEquals(desc.value, undefined);
205assertEquals(1, obj1.bar = 1);
206assertEquals(2, val1);
207assertEquals(3, val2);
208assertEquals(1, obj1.bar = 1)
209assertEquals(2, val1);
210assertEquals(4, val2);
211assertEquals(4, obj1.bar);
212
213// Define an accessor that has only a setter.
214Object.defineProperty(obj1, "setOnly", accessorOnlySet);
215desc = Object.getOwnPropertyDescriptor(obj1, "setOnly");
216assertTrue(desc.configurable);
217assertFalse(desc.enumerable);
218assertEquals(desc.set, accessorOnlySet.set);
219assertEquals(desc.writable, undefined);
220assertEquals(desc.value, undefined);
221assertEquals(desc.get, undefined);
222assertEquals(1, obj1.setOnly = 1);
223assertEquals(1, val3);
224
225// Add a getter - should not touch the setter.
226Object.defineProperty(obj1, "setOnly", accessorOnlyGet);
227desc = Object.getOwnPropertyDescriptor(obj1, "setOnly");
228assertTrue(desc.configurable);
229assertFalse(desc.enumerable);
230assertEquals(desc.get, accessorOnlyGet.get);
231assertEquals(desc.set, accessorOnlySet.set);
232assertEquals(desc.writable, undefined);
233assertEquals(desc.value, undefined);
234assertEquals(1, obj1.setOnly = 1);
235assertEquals(2, val3);
236
237// The above should also work if redefining just a getter or setter on
238// an existing property with both a getter and a setter.
239Object.defineProperty(obj1, "both", accessorConfigurable);
240
241Object.defineProperty(obj1, "both", accessorOnlySet);
242desc = Object.getOwnPropertyDescriptor(obj1, "both");
243assertTrue(desc.configurable);
244assertFalse(desc.enumerable);
245assertEquals(desc.set, accessorOnlySet.set);
246assertEquals(desc.get, accessorConfigurable.get);
247assertEquals(desc.writable, undefined);
248assertEquals(desc.value, undefined);
249assertEquals(1, obj1.both = 1);
250assertEquals(3, val3);
251
252
253// Data properties
254
255Object.defineProperty(obj1, "foobar", dataConfigurable);
256desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
257assertEquals(obj1.foobar, 1000);
258assertEquals(desc.value, 1000);
259assertTrue(desc.configurable);
260assertFalse(desc.writable);
261assertFalse(desc.enumerable);
262assertEquals(desc.get, undefined);
263assertEquals(desc.set, undefined);
264//Try writing to non writable attribute - should remain 1000
265obj1.foobar = 1001;
266assertEquals(obj1.foobar, 1000);
267
268
269// Redefine to writable descriptor - now writing to foobar should be allowed.
270Object.defineProperty(obj1, "foobar", dataWritable);
271desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
272assertEquals(obj1.foobar, 3000);
273assertEquals(desc.value, 3000);
274// Note that since dataWritable does not define configurable the configurable
275// setting from the redefined property (in this case true) is used.
276assertTrue(desc.configurable);
277assertTrue(desc.writable);
278assertFalse(desc.enumerable);
279assertEquals(desc.get, undefined);
280assertEquals(desc.set, undefined);
281// Writing to the property should now be allowed
282obj1.foobar = 1001;
283assertEquals(obj1.foobar, 1001);
284
285
286// Redefine with non configurable data property.
287Object.defineProperty(obj1, "foobar", dataNoConfigurable);
288desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
289assertEquals(obj1.foobar, 2000);
290assertEquals(desc.value, 2000);
291assertFalse(desc.configurable);
292assertTrue(desc.writable);
293assertFalse(desc.enumerable);
294assertEquals(desc.get, undefined);
295assertEquals(desc.set, undefined);
296
297// Try redefine again - shold fail because configurable is now false.
298try {
299  Object.defineProperty(obj1, "foobar", dataConfigurable);
300  assertTrue(false);
301} catch (e) {
302  assertTrue(/Cannot redefine property/.test(e));
303}
304
305// Try redefine again with accessor property - shold also fail.
306try {
307  Object.defineProperty(obj1, "foobar", dataConfigurable);
308  assertTrue(false);
309} catch (e) {
310  assertTrue(/Cannot redefine property/.test(e));
311}
312
313
314// Redifine with the same descriptor - should succeed (step 6).
315Object.defineProperty(obj1, "foobar", dataNoConfigurable);
316desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
317assertEquals(obj1.foobar, 2000);
318assertEquals(desc.value, 2000);
319assertFalse(desc.configurable);
320assertTrue(desc.writable);
321assertFalse(desc.enumerable);
322assertEquals(desc.get, undefined);
323assertEquals(desc.set, undefined);
324
325
326// New object
327var obj2 = {};
328
329// Make accessor - redefine to data
330Object.defineProperty(obj2, "foo", accessorConfigurable);
331
332// Redefine to data property
333Object.defineProperty(obj2, "foo", dataConfigurable);
334desc = Object.getOwnPropertyDescriptor(obj2, "foo");
335assertEquals(obj2.foo, 1000);
336assertEquals(desc.value, 1000);
337assertTrue(desc.configurable);
338assertFalse(desc.writable);
339assertFalse(desc.enumerable);
340assertEquals(desc.get, undefined);
341assertEquals(desc.set, undefined);
342
343
344// Redefine back to accessor
345Object.defineProperty(obj2, "foo", accessorConfigurable);
346desc = Object.getOwnPropertyDescriptor(obj2, "foo");
347assertTrue(desc.configurable);
348assertFalse(desc.enumerable);
349assertEquals(desc.writable, undefined);
350assertEquals(desc.get, accessorConfigurable.get);
351assertEquals(desc.set, accessorConfigurable.set);
352assertEquals(desc.value, undefined);
353assertEquals(1, obj2.foo = 1);
354assertEquals(3, val1);
355assertEquals(4, val2);
356assertEquals(3, obj2.foo);
357
358// Make data - redefine to accessor
359Object.defineProperty(obj2, "bar", dataConfigurable)
360
361// Redefine to accessor property
362Object.defineProperty(obj2, "bar", accessorConfigurable);
363desc = Object.getOwnPropertyDescriptor(obj2, "bar");
364assertTrue(desc.configurable);
365assertFalse(desc.enumerable);
366assertEquals(desc.writable, undefined);
367assertEquals(desc.get, accessorConfigurable.get);
368assertEquals(desc.set, accessorConfigurable.set);
369assertEquals(desc.value, undefined);
370assertEquals(1, obj2.bar = 1);
371assertEquals(4, val1);
372assertEquals(4, val2);
373assertEquals(4, obj2.foo);
374
375// Redefine back to data property
376Object.defineProperty(obj2, "bar", dataConfigurable);
377desc = Object.getOwnPropertyDescriptor(obj2, "bar");
378assertEquals(obj2.bar, 1000);
379assertEquals(desc.value, 1000);
380assertTrue(desc.configurable);
381assertFalse(desc.writable);
382assertFalse(desc.enumerable);
383assertEquals(desc.get, undefined);
384assertEquals(desc.set, undefined);
385
386
387// Redefinition of an accessor defined using __defineGetter__ and
388// __defineSetter__.
389function get(){return this.x}
390function set(x){this.x=x};
391
392var obj3 = {x:1000};
393obj3.__defineGetter__("foo", get);
394obj3.__defineSetter__("foo", set);
395
396desc = Object.getOwnPropertyDescriptor(obj3, "foo");
397assertTrue(desc.configurable);
398assertTrue(desc.enumerable);
399assertEquals(desc.writable, undefined);
400assertEquals(desc.get, get);
401assertEquals(desc.set, set);
402assertEquals(desc.value, undefined);
403assertEquals(1, obj3.foo = 1);
404assertEquals(1, obj3.x);
405assertEquals(1, obj3.foo);
406
407// Redefine to accessor property (non configurable) - note that enumerable
408// which we do not redefine should remain the same (true).
409Object.defineProperty(obj3, "foo", accessorNoConfigurable);
410desc = Object.getOwnPropertyDescriptor(obj3, "foo");
411assertFalse(desc.configurable);
412assertTrue(desc.enumerable);
413assertEquals(desc.writable, undefined);
414assertEquals(desc.get, accessorNoConfigurable.get);
415assertEquals(desc.set, accessorNoConfigurable.set);
416assertEquals(desc.value, undefined);
417assertEquals(1, obj3.foo = 1);
418assertEquals(5, val2);
419assertEquals(5, obj3.foo);
420
421
422obj3.__defineGetter__("bar", get);
423obj3.__defineSetter__("bar", set);
424
425
426// Redefine back to data property
427Object.defineProperty(obj3, "bar", dataConfigurable);
428desc = Object.getOwnPropertyDescriptor(obj3, "bar");
429assertEquals(obj3.bar, 1000);
430assertEquals(desc.value, 1000);
431assertTrue(desc.configurable);
432assertFalse(desc.writable);
433assertTrue(desc.enumerable);
434assertEquals(desc.get, undefined);
435assertEquals(desc.set, undefined);
436
437
438var obj4 = {};
439var func = function (){return 42;};
440obj4.bar = func;
441assertEquals(42, obj4.bar());
442
443Object.defineProperty(obj4, "bar", accessorConfigurable);
444desc = Object.getOwnPropertyDescriptor(obj4, "bar");
445assertTrue(desc.configurable);
446assertTrue(desc.enumerable);
447assertEquals(desc.writable, undefined);
448assertEquals(desc.get, accessorConfigurable.get);
449assertEquals(desc.set, accessorConfigurable.set);
450assertEquals(desc.value, undefined);
451assertEquals(1, obj4.bar = 1);
452assertEquals(5, val1);
453assertEquals(5, obj4.bar);
454
455// Make sure an error is thrown when trying to access to redefined function.
456try {
457  obj4.bar();
458  assertTrue(false);
459} catch (e) {
460  assertTrue(/is not a function/.test(e));
461}
462
463
464// Test runtime calls to DefineOrRedefineDataProperty and
465// DefineOrRedefineAccessorProperty - make sure we don't
466// crash.
467try {
468  %DefineOrRedefineAccessorProperty(0, 0, 0, 0, 0);
469} catch (e) {
470  assertTrue(/illegal access/.test(e));
471}
472
473try {
474  %DefineOrRedefineDataProperty(0, 0, 0, 0);
475} catch (e) {
476  assertTrue(/illegal access/.test(e));
477}
478
479try {
480  %DefineOrRedefineDataProperty(null, null, null, null);
481} catch (e) {
482  assertTrue(/illegal access/.test(e));
483}
484
485try {
486  %DefineOrRedefineAccessorProperty(null, null, null, null, null);
487} catch (e) {
488  assertTrue(/illegal access/.test(e));
489}
490
491try {
492  %DefineOrRedefineDataProperty({}, null, null, null);
493} catch (e) {
494  assertTrue(/illegal access/.test(e));
495}
496
497// Defining properties null should fail even when we have
498// other allowed values
499try {
500  %DefineOrRedefineAccessorProperty(null, 'foo', 0, func, 0);
501} catch (e) {
502  assertTrue(/illegal access/.test(e));
503}
504
505try {
506  %DefineOrRedefineDataProperty(null, 'foo', 0, 0);
507} catch (e) {
508  assertTrue(/illegal access/.test(e));
509}
510
511// Test that all possible differences in step 6 in DefineOwnProperty are
512// exercised, i.e., any difference in the given property descriptor and the
513// existing properties should not return true, but throw an error if the
514// existing configurable property is false.
515
516var obj5 = {};
517// Enumerable will default to false.
518Object.defineProperty(obj5, 'foo', accessorNoConfigurable);
519desc = Object.getOwnPropertyDescriptor(obj5, 'foo');
520// First, test that we are actually allowed to set the accessor if all
521// values are of the descriptor are the same as the existing one.
522Object.defineProperty(obj5, 'foo', accessorNoConfigurable);
523
524// Different setter.
525var descDifferent = {
526  configurable:false,
527  enumerable:false,
528  set: setter1,
529  get: getter2
530};
531
532try {
533  Object.defineProperty(obj5, 'foo', descDifferent);
534  assertTrue(false);
535} catch (e) {
536  assertTrue(/Cannot redefine property/.test(e));
537}
538
539// Different getter.
540descDifferent = {
541  configurable:false,
542  enumerable:false,
543  set: setter2,
544  get: getter1
545};
546
547try {
548  Object.defineProperty(obj5, 'foo', descDifferent);
549  assertTrue(false);
550} catch (e) {
551  assertTrue(/Cannot redefine property/.test(e));
552}
553
554// Different enumerable.
555descDifferent = {
556  configurable:false,
557  enumerable:true,
558  set: setter2,
559  get: getter2
560};
561
562try {
563  Object.defineProperty(obj5, 'foo', descDifferent);
564  assertTrue(false);
565} catch (e) {
566  assertTrue(/Cannot redefine property/.test(e));
567}
568
569// Different configurable.
570descDifferent = {
571  configurable:false,
572  enumerable:true,
573  set: setter2,
574  get: getter2
575};
576
577try {
578  Object.defineProperty(obj5, 'foo', descDifferent);
579  assertTrue(false);
580} catch (e) {
581  assertTrue(/Cannot redefine property/.test(e));
582}
583
584// No difference.
585descDifferent = {
586  configurable:false,
587  enumerable:false,
588  set: setter2,
589  get: getter2
590};
591// Make sure we can still redefine if all properties are the same.
592Object.defineProperty(obj5, 'foo', descDifferent);
593
594// Make sure that obj5 still holds the original values.
595desc = Object.getOwnPropertyDescriptor(obj5, 'foo');
596assertEquals(desc.get, getter2);
597assertEquals(desc.set, setter2);
598assertFalse(desc.enumerable);
599assertFalse(desc.configurable);
600
601
602// Also exercise step 6 on data property, writable and enumerable
603// defaults to false.
604Object.defineProperty(obj5, 'bar', dataNoConfigurable);
605
606// Test that redefinition with the same property descriptor is possible
607Object.defineProperty(obj5, 'bar', dataNoConfigurable);
608
609// Different value.
610descDifferent = {
611  configurable:false,
612  enumerable:false,
613  writable: false,
614  value: 1999
615};
616
617try {
618  Object.defineProperty(obj5, 'bar', descDifferent);
619  assertTrue(false);
620} catch (e) {
621  assertTrue(/Cannot redefine property/.test(e));
622}
623
624// Different writable.
625descDifferent = {
626  configurable:false,
627  enumerable:false,
628  writable: true,
629  value: 2000
630};
631
632try {
633  Object.defineProperty(obj5, 'bar', descDifferent);
634  assertTrue(false);
635} catch (e) {
636  assertTrue(/Cannot redefine property/.test(e));
637}
638
639
640// Different enumerable.
641descDifferent = {
642  configurable:false,
643  enumerable:true ,
644  writable:false,
645  value: 2000
646};
647
648try {
649  Object.defineProperty(obj5, 'bar', descDifferent);
650  assertTrue(false);
651} catch (e) {
652  assertTrue(/Cannot redefine property/.test(e));
653}
654
655
656// Different configurable.
657descDifferent = {
658  configurable:true,
659  enumerable:false,
660  writable:false,
661  value: 2000
662};
663
664try {
665  Object.defineProperty(obj5, 'bar', descDifferent);
666  assertTrue(false);
667} catch (e) {
668  assertTrue(/Cannot redefine property/.test(e));
669}
670
671// No difference.
672descDifferent = {
673  configurable:false,
674  enumerable:false,
675  writable:false,
676  value:2000
677};
678// Make sure we can still redefine if all properties are the same.
679Object.defineProperty(obj5, 'bar', descDifferent);
680
681// Make sure that obj5 still holds the original values.
682desc = Object.getOwnPropertyDescriptor(obj5, 'bar');
683assertEquals(desc.value, 2000);
684assertFalse(desc.writable);
685assertFalse(desc.enumerable);
686assertFalse(desc.configurable);
687
688
689// Make sure that we can't overwrite +0 with -0 and vice versa.
690var descMinusZero = {value: -0, configurable: false};
691var descPlusZero = {value: +0, configurable: false};
692
693Object.defineProperty(obj5, 'minuszero', descMinusZero);
694
695// Make sure we can redefine with -0.
696Object.defineProperty(obj5, 'minuszero', descMinusZero);
697
698try {
699  Object.defineProperty(obj5, 'minuszero', descPlusZero);
700  assertUnreachable();
701} catch (e) {
702  assertTrue(/Cannot redefine property/.test(e));
703}
704
705
706Object.defineProperty(obj5, 'pluszero', descPlusZero);
707
708// Make sure we can redefine with +0.
709Object.defineProperty(obj5, 'pluszero', descPlusZero);
710
711try {
712  Object.defineProperty(obj5, 'pluszero', descMinusZero);
713  assertUnreachable();
714} catch (e) {
715  assertTrue(/Cannot redefine property/.test(e));
716}
717
718
719var obj6 = {};
720obj6[1] = 'foo';
721obj6[2] = 'bar';
722obj6[3] = '42';
723obj6[4] = '43';
724obj6[5] = '44';
725
726var descElement = { value: 'foobar' };
727var descElementNonConfigurable = { value: 'barfoo', configurable: false };
728var descElementNonWritable = { value: 'foofoo', writable: false };
729var descElementNonEnumerable = { value: 'barbar', enumerable: false };
730var descElementAllFalse = { value: 'foofalse',
731                            configurable: false,
732                            writable: false,
733                            enumerable: false };
734
735
736// Redefine existing property.
737Object.defineProperty(obj6, '1', descElement);
738desc = Object.getOwnPropertyDescriptor(obj6, '1');
739assertEquals(desc.value, 'foobar');
740assertTrue(desc.writable);
741assertTrue(desc.enumerable);
742assertTrue(desc.configurable);
743
744// Redefine existing property with configurable: false.
745Object.defineProperty(obj6, '2', descElementNonConfigurable);
746desc = Object.getOwnPropertyDescriptor(obj6, '2');
747assertEquals(desc.value, 'barfoo');
748assertTrue(desc.writable);
749assertTrue(desc.enumerable);
750assertFalse(desc.configurable);
751
752// Can use defineProperty to change the value of a non
753// configurable property.
754try {
755  Object.defineProperty(obj6, '2', descElement);
756  desc = Object.getOwnPropertyDescriptor(obj6, '2');
757  assertEquals(desc.value, 'foobar');
758} catch (e) {
759  assertUnreachable();
760}
761
762// Ensure that we can't change the descriptor of a
763// non configurable property.
764try {
765  var descAccessor = { get: function() { return 0; } };
766  Object.defineProperty(obj6, '2', descAccessor);
767  assertUnreachable();
768} catch (e) {
769  assertTrue(/Cannot redefine property/.test(e));
770}
771
772Object.defineProperty(obj6, '2', descElementNonWritable);
773desc = Object.getOwnPropertyDescriptor(obj6, '2');
774assertEquals(desc.value, 'foofoo');
775assertFalse(desc.writable);
776assertTrue(desc.enumerable);
777assertFalse(desc.configurable);
778
779Object.defineProperty(obj6, '3', descElementNonWritable);
780desc = Object.getOwnPropertyDescriptor(obj6, '3');
781assertEquals(desc.value, 'foofoo');
782assertFalse(desc.writable);
783assertTrue(desc.enumerable);
784assertTrue(desc.configurable);
785
786// Redefine existing property with configurable: false.
787Object.defineProperty(obj6, '4', descElementNonEnumerable);
788desc = Object.getOwnPropertyDescriptor(obj6, '4');
789assertEquals(desc.value, 'barbar');
790assertTrue(desc.writable);
791assertFalse(desc.enumerable);
792assertTrue(desc.configurable);
793
794// Redefine existing property with configurable: false.
795Object.defineProperty(obj6, '5', descElementAllFalse);
796desc = Object.getOwnPropertyDescriptor(obj6, '5');
797assertEquals(desc.value, 'foofalse');
798assertFalse(desc.writable);
799assertFalse(desc.enumerable);
800assertFalse(desc.configurable);
801
802// Define non existing property - all attributes should default to false.
803Object.defineProperty(obj6, '15', descElement);
804desc = Object.getOwnPropertyDescriptor(obj6, '15');
805assertEquals(desc.value, 'foobar');
806assertFalse(desc.writable);
807assertFalse(desc.enumerable);
808assertFalse(desc.configurable);
809
810// Make sure that we can't redefine using direct access.
811obj6[15] ='overwrite';
812assertEquals(obj6[15],'foobar');
813
814
815// Repeat the above tests on an array.
816var arr = new Array();
817arr[1] = 'foo';
818arr[2] = 'bar';
819arr[3] = '42';
820arr[4] = '43';
821arr[5] = '44';
822
823var descElement = { value: 'foobar' };
824var descElementNonConfigurable = { value: 'barfoo', configurable: false };
825var descElementNonWritable = { value: 'foofoo', writable: false };
826var descElementNonEnumerable = { value: 'barbar', enumerable: false };
827var descElementAllFalse = { value: 'foofalse',
828                            configurable: false,
829                            writable: false,
830                            enumerable: false };
831
832
833// Redefine existing property.
834Object.defineProperty(arr, '1', descElement);
835desc = Object.getOwnPropertyDescriptor(arr, '1');
836assertEquals(desc.value, 'foobar');
837assertTrue(desc.writable);
838assertTrue(desc.enumerable);
839assertTrue(desc.configurable);
840
841// Redefine existing property with configurable: false.
842Object.defineProperty(arr, '2', descElementNonConfigurable);
843desc = Object.getOwnPropertyDescriptor(arr, '2');
844assertEquals(desc.value, 'barfoo');
845assertTrue(desc.writable);
846assertTrue(desc.enumerable);
847assertFalse(desc.configurable);
848
849// Can use defineProperty to change the value of a non
850// configurable property of an array.
851try {
852  Object.defineProperty(arr, '2', descElement);
853  desc = Object.getOwnPropertyDescriptor(arr, '2');
854  assertEquals(desc.value, 'foobar');
855} catch (e) {
856  assertUnreachable();
857}
858
859// Ensure that we can't change the descriptor of a
860// non configurable property.
861try {
862  var descAccessor = { get: function() { return 0; } };
863  Object.defineProperty(arr, '2', descAccessor);
864  assertUnreachable();
865} catch (e) {
866  assertTrue(/Cannot redefine property/.test(e));
867}
868
869Object.defineProperty(arr, '2', descElementNonWritable);
870desc = Object.getOwnPropertyDescriptor(arr, '2');
871assertEquals(desc.value, 'foofoo');
872assertFalse(desc.writable);
873assertTrue(desc.enumerable);
874assertFalse(desc.configurable);
875
876Object.defineProperty(arr, '3', descElementNonWritable);
877desc = Object.getOwnPropertyDescriptor(arr, '3');
878assertEquals(desc.value, 'foofoo');
879assertFalse(desc.writable);
880assertTrue(desc.enumerable);
881assertTrue(desc.configurable);
882
883// Redefine existing property with configurable: false.
884Object.defineProperty(arr, '4', descElementNonEnumerable);
885desc = Object.getOwnPropertyDescriptor(arr, '4');
886assertEquals(desc.value, 'barbar');
887assertTrue(desc.writable);
888assertFalse(desc.enumerable);
889assertTrue(desc.configurable);
890
891// Redefine existing property with configurable: false.
892Object.defineProperty(arr, '5', descElementAllFalse);
893desc = Object.getOwnPropertyDescriptor(arr, '5');
894assertEquals(desc.value, 'foofalse');
895assertFalse(desc.writable);
896assertFalse(desc.enumerable);
897assertFalse(desc.configurable);
898
899// Define non existing property - all attributes should default to false.
900Object.defineProperty(arr, '15', descElement);
901desc = Object.getOwnPropertyDescriptor(arr, '15');
902assertEquals(desc.value, 'foobar');
903assertFalse(desc.writable);
904assertFalse(desc.enumerable);
905assertFalse(desc.configurable);
906
907// See issue 968: http://code.google.com/p/v8/issues/detail?id=968
908var o = { x : 42 };
909Object.defineProperty(o, "x", { writable: false });
910assertEquals(42, o.x);
911o.x = 37;
912assertEquals(42, o.x);
913
914o = { x : 42 };
915Object.defineProperty(o, "x", {});
916assertEquals(42, o.x);
917o.x = 37;
918// Writability is preserved.
919assertEquals(37, o.x);
920
921var o = { };
922Object.defineProperty(o, "x", { writable: false });
923assertEquals(undefined, o.x);
924o.x = 37;
925assertEquals(undefined, o.x);
926
927o = { get x() { return 87; } };
928Object.defineProperty(o, "x", { writable: false });
929assertEquals(undefined, o.x);
930o.x = 37;
931assertEquals(undefined, o.x);
932
933// Ignore inherited properties.
934o = { __proto__ : { x : 87 } };
935Object.defineProperty(o, "x", { writable: false });
936assertEquals(undefined, o.x);
937o.x = 37;
938assertEquals(undefined, o.x);
939
940function testDefineProperty(obj, propertyName, desc, resultDesc) {
941  Object.defineProperty(obj, propertyName, desc);
942  var actualDesc = Object.getOwnPropertyDescriptor(obj, propertyName);
943  assertEquals(resultDesc.enumerable, actualDesc.enumerable);
944  assertEquals(resultDesc.configurable, actualDesc.configurable);
945  if (resultDesc.hasOwnProperty('value')) {
946    assertEquals(resultDesc.value, actualDesc.value);
947    assertEquals(resultDesc.writable, actualDesc.writable);
948    assertFalse(resultDesc.hasOwnProperty('get'));
949    assertFalse(resultDesc.hasOwnProperty('set'));
950  } else {
951    assertEquals(resultDesc.get, actualDesc.get);
952    assertEquals(resultDesc.set, actualDesc.set);
953    assertFalse(resultDesc.hasOwnProperty('value'));
954    assertFalse(resultDesc.hasOwnProperty('writable'));
955  }
956}
957
958// tests redefining existing property with a generic descriptor
959o = { p : 42 };
960testDefineProperty(o, 'p',
961  { },
962  { value : 42, writable : true, enumerable : true, configurable : true });
963
964o = { p : 42 };
965testDefineProperty(o, 'p',
966  { enumerable : true },
967  { value : 42, writable : true, enumerable : true, configurable : true });
968
969o = { p : 42 };
970testDefineProperty(o, 'p',
971  { configurable : true },
972  { value : 42, writable : true, enumerable : true, configurable : true });
973
974o = { p : 42 };
975testDefineProperty(o, 'p',
976  { enumerable : false },
977  { value : 42, writable : true, enumerable : false, configurable : true });
978
979o = { p : 42 };
980testDefineProperty(o, 'p',
981  { configurable : false },
982  { value : 42, writable : true, enumerable : true, configurable : false });
983
984o = { p : 42 };
985testDefineProperty(o, 'p',
986  { enumerable : true, configurable : true },
987  { value : 42, writable : true, enumerable : true, configurable : true });
988
989o = { p : 42 };
990testDefineProperty(o, 'p',
991  { enumerable : false, configurable : true },
992  { value : 42, writable : true, enumerable : false, configurable : true });
993
994o = { p : 42 };
995testDefineProperty(o, 'p',
996  { enumerable : true, configurable : false },
997  { value : 42, writable : true, enumerable : true, configurable : false });
998
999o = { p : 42 };
1000testDefineProperty(o, 'p',
1001  { enumerable : false, configurable : false },
1002  { value : 42, writable : true, enumerable : false, configurable : false });
1003
1004// can make a writable, non-configurable field non-writable
1005o = { p : 42 };
1006Object.defineProperty(o, 'p', { configurable: false });
1007testDefineProperty(o, 'p',
1008  { writable: false },
1009  { value : 42, writable : false, enumerable : true, configurable : false });
1010
1011// redefine of get only property with generic descriptor
1012o = {};
1013Object.defineProperty(o, 'p',
1014  { get : getter1, enumerable: true, configurable: true });
1015testDefineProperty(o, 'p',
1016  { enumerable : false, configurable : false },
1017  { get: getter1, set: undefined, enumerable : false, configurable : false });
1018
1019// redefine of get/set only property with generic descriptor
1020o = {};
1021Object.defineProperty(o, 'p',
1022  { get: getter1, set: setter1, enumerable: true, configurable: true });
1023testDefineProperty(o, 'p',
1024  { enumerable : false, configurable : false },
1025  { get: getter1, set: setter1, enumerable : false, configurable : false });
1026
1027// redefine of set only property with generic descriptor
1028o = {};
1029Object.defineProperty(o, 'p',
1030  { set : setter1, enumerable: true, configurable: true });
1031testDefineProperty(o, 'p',
1032  { enumerable : false, configurable : false },
1033  { get: undefined, set: setter1, enumerable : false, configurable : false });
1034