Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / tests / ecma_5 / Object / defineProperty-setup.js
1 // Any copyright is dedicated to the Public Domain.
2 // http://creativecommons.org/licenses/publicdomain/
3
4 assertEq("defineProperty" in Object, true);
5 assertEq(Object.defineProperty.length, 3);
6
7 if (!Object.prototype.toSource)
8 {
9   Object.defineProperty(Object.prototype, "toSource",
10   {
11     value: function toSource()
12     {
13       if (this instanceof RegExp)
14       {
15         var v = "new RegExp(" + uneval(this.source);
16         var f = (this.multiline ? "m" : "") +
17                 (this.global ? "g" : "") +
18                 (this.ignoreCase ? "i" : "");
19         return v + (f ? ", '" + f + "'" : "") + ")";
20       }
21       return JSON.stringify(this);
22     },
23     enumerable: false,
24     configurable: true,
25     writable: true
26   });
27 }
28 if (!("uneval" in this))
29 {
30   Object.defineProperty(this, "uneval",
31   {
32     value: function uneval(v)
33     {
34       if (v === null)
35         return "null";
36       if (typeof v === "object")
37         return v.toSource();
38       if (typeof v === "string")
39       {
40         v = JSON.stringify({v:v});
41         return v.substring(5, v.length - 1);
42       }
43       return "" + v;
44     },
45     enumerable: false,
46     configurable: true,
47     writable: true
48   });
49 }
50
51 // reimplemented for the benefit of engines which don't have this helper
52 function assertEq(v1, v2, m)
53 {
54   if (!SameValue(v1, v2))
55   {
56     throw "assertion failed: " +
57           "got " + uneval(v1) + ", expected " + uneval(v2) +
58           (m ? ": " + m : "");
59   }
60 }
61
62 function SameValue(v1, v2)
63 {
64   if (v1 === 0 && v2 === 0)
65     return 1 / v1 === 1 / v2;
66   if (v1 !== v1 && v2 !== v2)
67     return true;
68   return v1 === v2;
69 }
70
71 function PropertyDescriptor(pd)
72 {
73   if (pd)
74     this.update(pd);
75 }
76 PropertyDescriptor.prototype.update = function update(pd)
77 {
78   if ("get" in pd)
79     this.get = pd.get;
80   if ("set" in pd)
81     this.set = pd.set;
82   if ("configurable" in pd)
83     this.configurable = pd.configurable;
84   if ("writable" in pd)
85     this.writable = pd.writable;
86   if ("enumerable" in pd)
87     this.enumerable = pd.enumerable;
88   if ("value" in pd)
89     this.value = pd.value;
90 };
91 PropertyDescriptor.prototype.convertToDataDescriptor = function convertToDataDescriptor()
92 {
93   delete this.get;
94   delete this.set;
95   this.writable = false;
96   this.value = undefined;
97 };
98 PropertyDescriptor.prototype.convertToAccessorDescriptor = function convertToAccessorDescriptor()
99 {
100   delete this.writable;
101   delete this.value;
102   this.get = undefined;
103   this.set = undefined;
104 };
105
106 function compareDescriptors(d1, d2)
107 {
108   if (d1 === undefined)
109   {
110     assertEq(d2, undefined, "non-descriptors");
111     return;
112   }
113   if (d2 === undefined)
114   {
115     assertEq(true, false, "descriptor-equality mismatch: " + uneval(d1) + ", " + uneval(d2));
116     return;
117   }
118
119   var props = ["value", "get", "set", "enumerable", "configurable", "writable"];
120   for (var i = 0, sz = props.length; i < sz; i++)
121   {
122     var p = props[i];
123     assertEq(p in d1, p in d2, p + " different in d1/d2");
124     if (p in d1)
125       assertEq(d1[p], d2[p], p);
126   }
127 }
128
129 function examine(desc, field, allowDefault)
130 {
131   if (field in desc)
132     return desc[field];
133   assertEq(allowDefault, true, "reimplementation error");
134   switch (field)
135   {
136     case "value":
137     case "get":
138     case "set":
139       return undefined;
140     case "writable":
141     case "enumerable":
142     case "configurable":
143       return false;
144     default:
145       assertEq(true, false, "bad field name: " + field);
146   }
147 }
148
149 function IsAccessorDescriptor(desc)
150 {
151   if (!desc)
152     return false;
153   if (!("get" in desc) && !("set" in desc))
154     return false;
155   return true;
156 }
157
158 function IsDataDescriptor(desc)
159 {
160   if (!desc)
161     return false;
162   if (!("value" in desc) && !("writable" in desc))
163     return false;
164   return true;
165 }
166
167 function IsGenericDescriptor(desc)
168 {
169   if (!desc)
170     return false;
171   if (!IsAccessorDescriptor(desc) && !IsDataDescriptor(desc))
172     return true;
173   return false;
174 }
175
176
177
178 function CustomObject()
179 {
180   this.properties = {};
181   this.extensible = true;
182 }
183 CustomObject.prototype =
184 {
185   _reject: function _reject(throwing, msg)
186   {
187     if (throwing)
188       throw new TypeError(msg + "; rejected!");
189     return false;
190   },
191   defineOwnProperty: function defineOwnProperty(propname, desc, throwing)
192   {
193     assertEq(typeof propname, "string", "non-string propname");
194
195     // Step 1.
196     var current = this.properties[propname];
197
198     // Step 2.
199     var extensible = this.extensible;
200
201     // Step 3.
202     if (current === undefined && !extensible)
203       return this._reject(throwing, "object not extensible");
204
205     // Step 4.
206     if (current === undefined && extensible)
207     {
208       var p;
209       // Step 4(a).
210       if (IsGenericDescriptor(desc) || IsDataDescriptor(desc))
211       {
212         p = new PropertyDescriptor();
213         p.value = examine(desc, "value", true);
214         p.writable = examine(desc, "writable", true);
215         p.enumerable = examine(desc, "enumerable", true);
216         p.configurable = examine(desc, "configurable", true);
217       }
218       // Step 4(b).
219       else
220       {
221         p = new PropertyDescriptor();
222         p.get = examine(desc, "get", true);
223         p.set = examine(desc, "set", true);
224         p.enumerable = examine(desc, "enumerable", true);
225         p.configurable = examine(desc, "configurable", true);
226       }
227
228       this.properties[propname] = p;
229
230       // Step 4(c).
231       return true;
232     }
233
234     // Step 5.
235     if (!("value" in desc) && !("get" in desc) && !("set" in desc) &&
236         !("writable" in desc) && !("enumerable" in desc) &&
237         !("configurable" in desc))
238     {
239       return;
240     }
241
242     // Step 6.
243     do
244     {
245       if ("value" in desc)
246       {
247         if (!("value" in current) || !SameValue(desc.value, current.value))
248           break;
249       }
250       if ("get" in desc)
251       {
252         if (!("get" in current) || !SameValue(desc.get, current.get))
253           break;
254       }
255       if ("set" in desc)
256       {
257         if (!("set" in current) || !SameValue(desc.set, current.set))
258           break;
259       }
260       if ("writable" in desc)
261       {
262         if (!("writable" in current) ||
263             !SameValue(desc.writable, current.writable))
264         {
265           break;
266         }
267       }
268       if ("enumerable" in desc)
269       {
270         if (!("enumerable" in current) ||
271             !SameValue(desc.enumerable, current.enumerable))
272         {
273           break;
274         }
275       }
276       if ("configurable" in desc)
277       {
278         if (!("configurable" in current) ||
279             !SameValue(desc.configurable, current.configurable))
280         {
281           break;
282         }
283       }
284
285       // all fields in desc also in current, with the same values
286       return true;
287     }
288     while (false);
289
290     // Step 7.
291     if (!examine(current, "configurable"))
292     {
293       if ("configurable" in desc && examine(desc, "configurable"))
294         return this._reject(throwing, "can't make configurable again");
295       if ("enumerable" in desc &&
296           examine(current, "enumerable") !== examine(desc, "enumerable"))
297       {
298         return this._reject(throwing, "can't change enumerability");
299       }
300     }
301
302     // Step 8.
303     if (IsGenericDescriptor(desc))
304     {
305       // do nothing
306     }
307     // Step 9.
308     else if (IsDataDescriptor(current) !== IsDataDescriptor(desc))
309     {
310       // Step 9(a).
311       if (!examine(current, "configurable"))
312         return this._reject(throwing, "can't change unconfigurable descriptor's type");
313       // Step 9(b).
314       if (IsDataDescriptor(current))
315         current.convertToAccessorDescriptor();
316       // Step 9(c).
317       else
318         current.convertToDataDescriptor();
319     }
320     // Step 10.
321     else if (IsDataDescriptor(current) && IsDataDescriptor(desc))
322     {
323       // Step 10(a)
324       if (!examine(current, "configurable"))
325       {
326         // Step 10(a).i.
327         if (!examine(current, "writable") &&
328             "writable" in desc && examine(desc, "writable"))
329         {
330           return this._reject(throwing, "can't make data property writable again");
331         }
332         // Step 10(a).ii.
333         if (!examine(current, "writable"))
334         {
335           if ("value" in desc &&
336               !SameValue(examine(desc, "value"), examine(current, "value")))
337           {
338             return this._reject(throwing, "can't change value if not writable");
339           }
340         }
341       }
342       // Step 10(b).
343       else
344       {
345         assertEq(examine(current, "configurable"), true,
346                  "spec bug step 10(b)");
347       }
348     }
349     // Step 11.
350     else
351     {
352       assertEq(IsAccessorDescriptor(current) && IsAccessorDescriptor(desc),
353                true,
354                "spec bug");
355
356       // Step 11(a).
357       if (!examine(current, "configurable"))
358       {
359         // Step 11(a).i.
360         if ("set" in desc &&
361             !SameValue(examine(desc, "set"), examine(current, "set")))
362         {
363           return this._reject(throwing, "can't change setter if not configurable");
364         }
365         // Step 11(a).ii.
366         if ("get" in desc &&
367             !SameValue(examine(desc, "get"), examine(current, "get")))
368         {
369           return this._reject(throwing, "can't change getter if not configurable");
370         }
371       }
372     }
373
374     // Step 12.
375     current.update(desc);
376
377     // Step 13.
378     return true;
379   }
380 };
381
382 function IsCallable(v)
383 {
384   return typeof v === "undefined" || typeof v === "function";
385 }
386
387 var NativeTest =
388   {
389     newObject: function newObject()
390     {
391       return {};
392     },
393     defineProperty: function defineProperty(obj, propname, propdesc)
394     {
395       Object.defineProperty(obj, propname, propdesc);
396     },
397     getDescriptor: function getDescriptor(obj, propname)
398     {
399       return Object.getOwnPropertyDescriptor(obj, propname);
400     }
401   };
402
403 var ReimplTest =
404   {
405     newObject: function newObject()
406     {
407       return new CustomObject();
408     },
409     defineProperty: function defineProperty(obj, propname, propdesc)
410     {
411       assertEq(obj instanceof CustomObject, true, "obj not instanceof CustomObject");
412       if ("get" in propdesc || "set" in propdesc)
413       {
414         if ("value" in propdesc || "writable" in propdesc)
415           throw new TypeError("get/set and value/writable");
416         if (!IsCallable(propdesc.get))
417           throw new TypeError("get defined, uncallable");
418         if (!IsCallable(propdesc.set))
419           throw new TypeError("set defined, uncallable");
420       }
421       return obj.defineOwnProperty(propname, propdesc, true);
422     },
423     getDescriptor: function getDescriptor(obj, propname)
424     {
425       if (!(propname in obj.properties))
426         return undefined;
427
428       return new PropertyDescriptor(obj.properties[propname]);
429     }
430   };
431
432 var JSVAL_INT_MAX = Math.pow(2, 30) - 1;
433 var JSVAL_INT_MIN = -Math.pow(2, 30);
434
435
436 function isValidDescriptor(propdesc)
437 {
438   if ("get" in propdesc || "set" in propdesc)
439   {
440     if ("value" in propdesc || "writable" in propdesc)
441       return false;
442
443     // We permit null here simply because this test's author believes the
444     // implementation may sometime be susceptible to making mistakes in this
445     // regard and would prefer to be cautious.
446     if (propdesc.get !== null && propdesc.get !== undefined && !IsCallable(propdesc.get))
447       return false;
448     if (propdesc.set !== null && propdesc.set !== undefined && !IsCallable(propdesc.set))
449       return false;
450   }
451
452   return true;
453 }
454
455
456 var OMIT = {};
457 var VALUES =
458   [-Infinity, JSVAL_INT_MIN, -0, +0, 1.5, JSVAL_INT_MAX, Infinity,
459    NaN, "foo", "bar", null, undefined, true, false, {}, /a/, OMIT];
460 var GETS =
461   [undefined, function get1() { return 1; }, function get2() { return 2; },
462    null, 5, OMIT];
463 var SETS =
464   [undefined, function set1() { return 1; }, function set2() { return 2; },
465    null, 5, OMIT];
466 var ENUMERABLES = [true, false, OMIT];
467 var CONFIGURABLES = [true, false, OMIT];
468 var WRITABLES = [true, false, OMIT];
469
470 function mapTestDescriptors(filter)
471 {
472   var descs = [];
473   var desc = {};
474
475   function put(field, value)
476   {
477     if (value !== OMIT)
478       desc[field] = value;
479   }
480
481   VALUES.forEach(function(value)
482   {
483     GETS.forEach(function(get)
484     {
485       SETS.forEach(function(set)
486       {
487         ENUMERABLES.forEach(function(enumerable)
488         {
489           CONFIGURABLES.forEach(function(configurable)
490           {
491             WRITABLES.forEach(function(writable)
492             {
493               desc = {};
494               put("value", value);
495               put("get", get);
496               put("set", set);
497               put("enumerable", enumerable);
498               put("configurable", configurable);
499               put("writable", writable);
500               if (filter(desc))
501                 descs.push(desc);
502             });
503           });
504         });
505       });
506     });
507   });
508
509   return descs;
510 }
511
512 var ALL_DESCRIPTORS = mapTestDescriptors(function(d) { return true; });
513 var VALID_DESCRIPTORS = mapTestDescriptors(isValidDescriptor);
514
515 var SKIP_FULL_FUNCTION_LENGTH_TESTS = true;
516
517 function TestRunner()
518 {
519   this._logLines = [];
520 }
521 TestRunner.prototype =
522   {
523     // MAIN METHODS
524
525     runFunctionLengthTests: function runFunctionLengthTests()
526     {
527       var self = this;
528       function functionLengthTests()
529       {
530         if (SKIP_FULL_FUNCTION_LENGTH_TESTS)
531         {
532           print("Skipping full tests for redefining Function.length for now " +
533                 "because we don't support redefinition of properties with " +
534                 "native getter or setter...");
535           self._simpleFunctionLengthTests();
536         }
537         else
538         {
539           self._simpleFunctionLengthTests();
540           self._fullFunctionLengthTests(function() { }, 0);
541           self._fullFunctionLengthTests(function(one) { }, 1);
542           self._fullFunctionLengthTests(function(one, two) { }, 2);
543         }
544       }
545
546       this._runTestSet(functionLengthTests, "Function length tests completed!");
547     },
548
549     runNotPresentTests: function runNotPresentTests()
550     {
551       var self = this;
552       function notPresentTests()
553       {
554         print("Running not-present tests now...");
555
556         for (var i = 0, sz = ALL_DESCRIPTORS.length; i < sz; i++)
557           self._runSingleNotPresentTest(ALL_DESCRIPTORS[i]);
558       };
559
560       this._runTestSet(notPresentTests, "Not-present length tests completed!");
561     },
562
563     runPropertyPresentTestsFraction:
564     function runPropertyPresentTestsFraction(part, parts)
565     {
566       var self = this;
567       function propertyPresentTests()
568       {
569         print("Running already-present tests now...");
570
571         var total = VALID_DESCRIPTORS.length;
572         var start = Math.floor((part - 1) / parts * total);
573         var end = Math.floor(part / parts * total);
574
575         for (var i = start; i < end; i++)
576         {
577           var old = VALID_DESCRIPTORS[i];
578           print("Starting test with old descriptor " + old.toSource() + "...");
579
580           for (var j = 0, sz2 = VALID_DESCRIPTORS.length; j < sz2; j++)
581             self._runSinglePropertyPresentTest(old, VALID_DESCRIPTORS[j], []);
582         }
583       }
584
585       this._runTestSet(propertyPresentTests,
586                        "Property-present fraction " + part + " of " + parts +
587                        " completed!");
588     },
589
590     runNonTerminalPropertyPresentTestsFraction:
591     function runNonTerminalPropertyPresentTestsFraction(part, parts)
592     {
593       var self = this;
594
595       /*
596        * A plain old property to define on the object before redefining the
597        * originally-added property, to test redefinition of a property that's
598        * not also lastProperty.  NB: we could loop over every possible
599        * descriptor here if we wanted, even try adding more than one, but we'd
600        * hit cubic complexity and worse, and SpiderMonkey only distinguishes by
601        * the mere presence of the middle property, not its precise details.
602        */
603       var middleDefines =
604         [{
605            property: "middle",
606            descriptor:
607              { value: 17, writable: true, configurable: true, enumerable: true }
608          }];
609
610       function nonTerminalPropertyPresentTests()
611       {
612         print("Running non-terminal already-present tests now...");
613
614         var total = VALID_DESCRIPTORS.length;
615         var start = Math.floor((part - 1) / parts * total);
616         var end = Math.floor(part / parts * total);
617
618         for (var i = start; i < end; i++)
619         {
620           var old = VALID_DESCRIPTORS[i];
621           print("Starting test with old descriptor " + old.toSource() + "...");
622
623           for (var j = 0, sz2 = VALID_DESCRIPTORS.length; j < sz2; j++)
624           {
625             self._runSinglePropertyPresentTest(old, VALID_DESCRIPTORS[j],
626                                                middleDefines);
627           }
628         }
629       }
630
631       this._runTestSet(nonTerminalPropertyPresentTests,
632                        "Non-terminal property-present fraction " +
633                        part + " of " + parts + " completed!");
634     },
635
636     runDictionaryPropertyPresentTestsFraction:
637     function runDictionaryPropertyPresentTestsFraction(part, parts)
638     {
639       var self = this;
640
641       /*
642        * Add and readd properties such that the scope for the object is in
643        * dictionary mode.
644        */
645       var middleDefines =
646         [
647          {
648            property: "mid1",
649            descriptor:
650              { value: 17, writable: true, configurable: true, enumerable: true }
651          },
652          {
653            property: "mid2",
654            descriptor:
655              { value: 17, writable: true, configurable: true, enumerable: true }
656          },
657          {
658            property: "mid1",
659            descriptor:
660              { get: function g() { }, set: function s(v){}, configurable: false,
661                enumerable: true }
662          },
663          ];
664
665       function dictionaryPropertyPresentTests()
666       {
667         print("Running dictionary already-present tests now...");
668
669         var total = VALID_DESCRIPTORS.length;
670         var start = Math.floor((part - 1) / parts * total);
671         var end = Math.floor(part / parts * total);
672
673         for (var i = start; i < end; i++)
674         {
675           var old = VALID_DESCRIPTORS[i];
676           print("Starting test with old descriptor " + old.toSource() + "...");
677
678           for (var j = 0, sz2 = VALID_DESCRIPTORS.length; j < sz2; j++)
679           {
680             self._runSinglePropertyPresentTest(old, VALID_DESCRIPTORS[j],
681                                                middleDefines);
682           }
683         }
684       }
685
686       this._runTestSet(dictionaryPropertyPresentTests,
687                        "Dictionary property-present fraction " +
688                        part + " of " + parts + " completed!");
689     },
690
691
692     // HELPERS
693
694     runPropertyPresentTests: function runPropertyPresentTests()
695     {
696       print("Running already-present tests now...");
697
698       for (var i = 0, sz = VALID_DESCRIPTORS.length; i < sz; i++)
699       {
700         var old = VALID_DESCRIPTORS[i];
701         print("Starting test with old descriptor " + old.toSource() + "...");
702
703         for (var j = 0, sz2 = VALID_DESCRIPTORS.length; j < sz2; j++)
704           this._runSinglePropertyPresentTest(old, VALID_DESCRIPTORS[j], []);
705       }
706     },
707     _runTestSet: function _runTestSet(fun, completeMessage)
708     {
709       try
710       {
711         fun();
712
713         print(completeMessage);
714       }
715       catch (e)
716       {
717         print("ERROR, EXITING (line " + (e.lineNumber || -1) + "): " + e);
718         throw e;
719       }
720       finally
721       {
722         this._reportAllErrors();
723       }
724     },
725     _reportAllErrors: function _reportAllErrors()
726     {
727       var errorCount = this._logLines.length;
728       print("Full accumulated number of errors: " + errorCount);
729       if (errorCount > 0)
730         throw errorCount + " errors detected, FAIL";
731     },
732     _simpleFunctionLengthTests: function _simpleFunctionLengthTests(fun)
733     {
734       print("Running simple Function.length tests now..");
735
736       function expectThrowTypeError(o, p, desc)
737       {
738         var err = "<none>", passed = false;
739         try
740         {
741           Object.defineProperty(o, p, desc);
742         }
743         catch (e)
744         {
745           err = e;
746           passed = e instanceof TypeError;
747         }
748         assertEq(passed, true, fun + " didn't throw TypeError when called: " + err);
749       }
750
751       expectThrowTypeError(function a() { }, "length", { value: 1 });
752       expectThrowTypeError(function a() { }, "length", { enumerable: true });
753       expectThrowTypeError(function a() { }, "length", { configurable: true });
754       expectThrowTypeError(function a() { }, "length", { writable: true });
755     },
756     _fullFunctionLengthTests: function _fullFunctionLengthTests(fun)
757     {
758       var len = fun.length;
759       print("Running Function.length (" + len + ") tests now...");
760
761       var desc;
762       var gen = new DescriptorState();
763       while ((desc = gen.nextDescriptor()))
764         this._runSingleFunctionLengthTest(fun, len, desc);
765     },
766     _log: function _log(v)
767     {
768       var m = "" + v;
769       print(m);
770       this._logLines.push(m);
771     },
772     _runSingleNotPresentTest: function _runSingleNotPresentTest(desc)
773     {
774       var nativeObj = NativeTest.newObject();
775       var reimplObj = ReimplTest.newObject();
776
777       try
778       {
779         NativeTest.defineProperty(nativeObj, "foo", desc);
780       }
781       catch (e)
782       {
783         try
784         {
785           ReimplTest.defineProperty(reimplObj, "foo", desc);
786         }
787         catch (e2)
788         {
789           if (e.constructor !== e2.constructor)
790           {
791             this._log("Difference when comparing native/reimplementation " +
792                       "behavior for new descriptor " + desc.toSource() +
793                       ", native threw " + e + ", reimpl threw " + e2);
794           }
795           return;
796         }
797         this._log("Difference when comparing native/reimplementation " +
798                   "behavior for new descriptor " + desc.toSource() +
799                   ", error " + e);
800         return;
801       }
802
803       try
804       {
805         ReimplTest.defineProperty(reimplObj, "foo", desc);
806       }
807       catch (e)
808       {
809         this._log("Reimpl threw defining new descriptor " + desc.toSource() +
810                   ", error: " + e);
811         return;
812       }
813
814       var nativeDesc = NativeTest.getDescriptor(nativeObj, "foo");
815       var reimplDesc = ReimplTest.getDescriptor(reimplObj, "foo");
816       try
817       {
818         compareDescriptors(nativeDesc, reimplDesc);
819       }
820       catch (e)
821       {
822         this._log("Difference comparing returned descriptors for new " +
823                   "property defined with descriptor " + desc.toSource() +
824                   "; error: " + e);
825         return;
826       }
827     },
828     _runSinglePropertyPresentTest:
829     function _runSinglePropertyPresentTest(old, add, middleDefines)
830     {
831       var nativeObj = NativeTest.newObject();
832       var reimplObj = ReimplTest.newObject();
833
834       try
835       {
836         NativeTest.defineProperty(nativeObj, "foo", old);
837       }
838       catch (e)
839       {
840         if (!SameValue(NativeTest.getDescriptor(nativeObj, "foo"), undefined))
841         {
842           this._log("defining bad property descriptor: " + old.toSource());
843           return;
844         }
845
846         try
847         {
848           ReimplTest.defineProperty(reimplObj, "foo", old);
849         }
850         catch (e2)
851         {
852           if (!SameValue(ReimplTest.getDescriptor(reimplObj, "foo"),
853                          undefined))
854           {
855             this._log("defining bad property descriptor: " + old.toSource() +
856                       "; reimplObj: " + uneval(reimplObj));
857           }
858
859           if (e.constructor !== e2.constructor)
860           {
861             this._log("Different errors defining bad property descriptor: " +
862                       old.toSource() + "; native threw " + e + ", reimpl " +
863                       "threw " + e2);
864           }
865
866           return;
867         }
868
869         this._log("Difference defining a property with descriptor " +
870                   old.toSource() + ", error " + e);
871         return;
872       }
873
874       try
875       {
876         ReimplTest.defineProperty(reimplObj, "foo", old);
877       }
878       catch (e)
879       {
880         this._log("Difference when comparing native/reimplementation " +
881                   "behavior when adding descriptor " + add.toSource() +
882                   ", error: " + e);
883         return;
884       }
885
886       // Now add (or even readd) however many properties were specified between
887       // the original property to add and the new one, to test redefining
888       // non-last-properties and properties in scopes in dictionary mode.
889       for (var i = 0, sz = middleDefines.length; i < sz; i++)
890       {
891         var middle = middleDefines[i];
892         var prop = middle.property;
893         var desc = middle.descriptor;
894
895         try
896         {
897           NativeTest.defineProperty(nativeObj, prop, desc);
898           ReimplTest.defineProperty(reimplObj, prop, desc);
899         }
900         catch (e)
901         {
902           this._log("failure defining middle descriptor: " + desc.toSource() +
903                     ", error " + e);
904           return;
905         }
906
907         // Sanity check
908         var nativeDesc = NativeTest.getDescriptor(nativeObj, prop);
909         var reimplDesc = ReimplTest.getDescriptor(reimplObj, prop);
910
911         compareDescriptors(nativeDesc, reimplDesc);
912         compareDescriptors(nativeDesc, desc);
913       }
914
915       try
916       {
917         NativeTest.defineProperty(nativeObj, "foo", add);
918       }
919       catch (e)
920       {
921         try
922         {
923           ReimplTest.defineProperty(reimplObj, "foo", add);
924         }
925         catch (e2)
926         {
927           if (e.constructor !== e2.constructor)
928           {
929             this._log("Difference when comparing native/reimplementation " +
930                       "behavior for descriptor " + add.toSource() +
931                       " overwriting descriptor " + old.toSource() + "; " +
932                       "native threw " + e + ", reimpl threw " + e2);
933           }
934           return;
935         }
936         this._log("Difference when comparing native/reimplementation " +
937                   "behavior for added descriptor " + add.toSource() + ", " +
938                   "initial was " + old.toSource() + "; error: " + e);
939         return;
940       }
941
942       try
943       {
944         ReimplTest.defineProperty(reimplObj, "foo", add);
945       }
946       catch (e)
947       {
948         this._log("Difference when comparing native/reimplementation " +
949                   "behavior for readded descriptor " + add.toSource() + ", " +
950                   "initial was " + old.toSource() + "; native readd didn't " +
951                   "throw, reimpl add did, error: " + e);
952         return;
953       }
954
955       var nativeDesc = NativeTest.getDescriptor(nativeObj, "foo");
956       var reimplDesc = ReimplTest.getDescriptor(reimplObj, "foo");
957       try
958       {
959         compareDescriptors(nativeDesc, reimplDesc);
960       }
961       catch (e)
962       {
963         this._log("Difference comparing returned descriptors for readded " +
964                   "property defined with descriptor " + add.toSource() + "; " +
965                   "initial was " + old.toSource() + "; error: " + e);
966         return;
967       }
968     },
969     _runSingleFunctionLengthTest: function _runSingleFunctionLengthTest(fun, len, desc)
970     {
971       var nativeObj = fun;
972       var reimplObj = ReimplTest.newObject();
973       ReimplTest.defineProperty(reimplObj, "length",
974       {
975         value: len,
976         enumerable: false,
977         configurable: false,
978         writable: false
979       });
980
981       try
982       {
983         NativeTest.defineProperty(nativeObj, "length", desc);
984       }
985       catch (e)
986       {
987         try
988         {
989           ReimplTest.defineProperty(reimplObj, "length", desc);
990         }
991         catch (e2)
992         {
993           if (e.constructor !== e2.constructor)
994           {
995             this._log("Difference when comparing native/reimplementation " +
996                       "behavior defining fun.length with " + desc.toSource() +
997                       "; native threw " + e + ", reimpl threw " + e2);
998           }
999           return;
1000         }
1001         this._log("Difference when comparing Function.length native/reimpl " +
1002                   "behavior for descriptor " + desc.toSource() +
1003                   ", native impl threw error " + e);
1004         return;
1005       }
1006
1007       try
1008       {
1009         ReimplTest.defineProperty(reimplObj, "length", desc);
1010       }
1011       catch (e)
1012       {
1013         this._log("Difference defining new Function.length descriptor: impl " +
1014                   "succeeded, reimpl threw for descriptor " +
1015                   desc.toSource() + ", error: " + e);
1016         return;
1017       }
1018
1019       var nativeDesc = NativeTest.getDescriptor(nativeObj, "length");
1020       var reimplDesc = ReimplTest.getDescriptor(reimplObj, "length");
1021       try
1022       {
1023         compareDescriptors(nativeDesc, reimplDesc);
1024       }
1025       catch (e)
1026       {
1027         this._log("Difference comparing returned descriptors for " +
1028                   "Function.length with descriptor " + desc.toSource() +
1029                   "; error: " + e);
1030         return;
1031       }
1032     }
1033   };
1034
1035 function runDictionaryPropertyPresentTestsFraction(PART, PARTS)
1036 {
1037   var testfile =
1038     '15.2.3.6-dictionary-redefinition-' + PART + '-of-' + PARTS + '.js';
1039   var BUGNUMBER = 560566;
1040   var summary =
1041     'ES5 Object.defineProperty(O, P, Attributes): dictionary redefinition ' +
1042     PART + ' of ' + PARTS;
1043
1044   print(BUGNUMBER + ": " + summary);
1045
1046   try
1047   {
1048     new TestRunner().runDictionaryPropertyPresentTestsFraction(PART, PARTS);
1049   }
1050   catch (e)
1051   {
1052     throw "Error thrown during testing: " + e +
1053             " at line " + e.lineNumber + "\n" +
1054           (e.stack
1055             ? "Stack: " + e.stack.split("\n").slice(2).join("\n") + "\n"
1056             : "");
1057   }
1058
1059   if (typeof reportCompare === "function")
1060     reportCompare(true, true);
1061
1062   print("Tests complete!");
1063 }
1064
1065 function runNonTerminalPropertyPresentTestsFraction(PART, PARTS)
1066 {
1067   var BUGNUMBER = 560566;
1068   var summary =
1069     'ES5 Object.defineProperty(O, P, Attributes): middle redefinition ' +
1070     PART + ' of ' + PARTS;
1071
1072   print(BUGNUMBER + ": " + summary);
1073
1074
1075   /**************
1076    * BEGIN TEST *
1077    **************/
1078
1079   try
1080   {
1081     new TestRunner().runNonTerminalPropertyPresentTestsFraction(PART, PARTS);
1082   }
1083   catch (e)
1084   {
1085     throw "Error thrown during testing: " + e +
1086             " at line " + e.lineNumber + "\n" +
1087           (e.stack
1088             ? "Stack: " + e.stack.split("\n").slice(2).join("\n") + "\n"
1089             : "");
1090   }
1091
1092   /******************************************************************************/
1093
1094   if (typeof reportCompare === "function")
1095     reportCompare(true, true);
1096
1097   print("Tests complete!");
1098 }