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