REGRESSION (r179357-r179359): WebContent Crash using AOL Mail @ com.apple.JavascriptC...
[WebKit-https.git] / LayoutTests / resources / js-test-pre.js
1 // svg/dynamic-updates tests set enablePixelTesting=true, as we want to dump text + pixel results
2 if (self.testRunner)
3     testRunner.dumpAsText(self.enablePixelTesting);
4
5 var description, debug, successfullyParsed, errorMessage, silentTestPass, didPassSomeTestsSilently, didFailSomeTests;
6
7 silentTestPass = false;
8 didPassSomeTestsSilently = false;
9 didFailSomeTests = false;
10
11 (function() {
12
13     function createHTMLElement(tagName)
14     {
15         // FIXME: In an XML document, document.createElement() creates an element with a null namespace URI.
16         // So, we need use document.createElementNS() to explicitly create an element with the specified
17         // tag name in the HTML namespace. We can remove this function and use document.createElement()
18         // directly once we fix <https://bugs.webkit.org/show_bug.cgi?id=131074>.
19         if (document.createElementNS)
20             return document.createElementNS("http://www.w3.org/1999/xhtml", tagName);
21         return document.createElement(tagName);
22     }
23
24     function getOrCreate(id, tagName)
25     {
26         var element = document.getElementById(id);
27         if (element)
28             return element;
29
30         element = createHTMLElement(tagName);
31         element.id = id;
32         var refNode;
33         var parent = document.body || document.documentElement;
34         if (id == "description")
35             refNode = getOrCreate("console", "div");
36         else
37             refNode = parent.firstChild;
38
39         parent.insertBefore(element, refNode);
40         return element;
41     }
42
43     description = function description(msg, quiet)
44     {
45         // For MSIE 6 compatibility
46         var span = createHTMLElement("span");
47         if (quiet)
48             span.innerHTML = '<p>' + msg + '</p><p>On success, you will see no "<span class="fail">FAIL</span>" messages, followed by "<span class="pass">TEST COMPLETE</span>".</p>';
49         else
50             span.innerHTML = '<p>' + msg + '</p><p>On success, you will see a series of "<span class="pass">PASS</span>" messages, followed by "<span class="pass">TEST COMPLETE</span>".</p>';
51
52         var description = getOrCreate("description", "p");
53         if (description.firstChild)
54             description.replaceChild(span, description.firstChild);
55         else
56             description.appendChild(span);
57     };
58
59     debug = function debug(msg)
60     {
61         var span = createHTMLElement("span");
62         getOrCreate("console", "div").appendChild(span); // insert it first so XHTML knows the namespace
63         span.innerHTML = msg + '<br />';
64     };
65
66     var css =
67         ".pass {" +
68             "font-weight: bold;" +
69             "color: green;" +
70         "}" +
71         ".fail {" +
72             "font-weight: bold;" +
73             "color: red;" +
74         "}" +
75         "#console {" +
76             "white-space: pre-wrap;" +
77             "font-family: monospace;" +
78         "}";
79
80     function insertStyleSheet()
81     {
82         var styleElement = createHTMLElement("style");
83         styleElement.textContent = css;
84         (document.head || document.documentElement).appendChild(styleElement);
85     }
86
87     if (!isWorker())
88         insertStyleSheet();
89
90     self.onerror = function(message)
91     {
92         errorMessage = message;
93     };
94
95 })();
96
97 function isWorker()
98 {
99     // It's conceivable that someone would stub out 'document' in a worker so
100     // also check for childNodes, an arbitrary DOM-related object that is
101     // meaningless in a WorkerContext.
102     return (typeof document === 'undefined' || typeof document.childNodes === 'undefined') && !!self.importScripts;
103 }
104
105 function descriptionQuiet(msg) { description(msg, true); }
106
107 function escapeHTML(text)
108 {
109     return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/\0/g, "\\0");
110 }
111
112 function testPassed(msg)
113 {
114     if (silentTestPass)
115         didPassSomeTestsSilently = true;
116     else
117         debug('<span><span class="pass">PASS</span> ' + escapeHTML(msg) + '</span>');
118 }
119
120 function testFailed(msg)
121 {
122     didFailSomeTests = true;
123     debug('<span><span class="fail">FAIL</span> ' + escapeHTML(msg) + '</span>');
124 }
125
126 function areNumbersEqual(_actual, _expected)
127 {
128     if (_expected === 0)
129         return _actual === _expected && (1/_actual) === (1/_expected);
130     if (_actual === _expected)
131         return true;
132     if (typeof(_expected) == "number" && isNaN(_expected))
133         return typeof(_actual) == "number" && isNaN(_actual);
134     return false;
135 }
136
137 function areArraysEqual(_a, _b)
138 {
139     try {
140         if (_a.length !== _b.length)
141             return false;
142         for (var i = 0; i < _a.length; i++)
143             if (!areNumbersEqual(_a[i], _b[i]))
144                 return false;
145     } catch (ex) {
146         return false;
147     }
148     return true;
149 }
150
151 function isMinusZero(n)
152 {
153     // the only way to tell 0 from -0 in JS is the fact that 1/-0 is
154     // -Infinity instead of Infinity
155     return n === 0 && 1/n < 0;
156 }
157
158 function isTypedArray(array)
159 {
160     return array instanceof Int8Array
161         || array instanceof Int16Array
162         || array instanceof Int32Array
163         || array instanceof Uint8Array
164         || array instanceof Uint8ClampedArray
165         || array instanceof Uint16Array
166         || array instanceof Uint32Array
167         || array instanceof Float32Array
168         || array instanceof Float64Array;
169 }
170
171 function isResultCorrect(_actual, _expected)
172 {
173     if (areNumbersEqual(_actual, _expected))
174         return true;
175     if (_expected
176         && (Object.prototype.toString.call(_expected) ==
177             Object.prototype.toString.call([])
178             || isTypedArray(_expected)))
179         return areArraysEqual(_actual, _expected);
180     return false;
181 }
182
183 function stringify(v)
184 {
185     if (v === 0 && 1/v < 0)
186         return "-0";
187     else if (isTypedArray(v))
188         return v.__proto__.constructor.name + ":[" + Array.prototype.join.call(v, ",") + "]";
189     else
190         return "" + v;
191 }
192
193 function evalAndLog(_a, _quiet)
194 {
195   if (typeof _a != "string")
196     debug("WARN: tryAndLog() expects a string argument");
197
198   // Log first in case things go horribly wrong or this causes a sync event.
199   if (!_quiet)
200     debug(_a);
201
202   var _av;
203   try {
204      _av = eval(_a);
205   } catch (e) {
206     testFailed(_a + " threw exception " + e);
207   }
208   return _av;
209 }
210
211 function shouldBe(_a, _b, quiet)
212 {
213   if (typeof _a != "string" || typeof _b != "string")
214     debug("WARN: shouldBe() expects string arguments");
215   var exception;
216   var _av;
217   try {
218      _av = eval(_a);
219   } catch (e) {
220      exception = e;
221   }
222   var _bv = eval(_b);
223
224   if (exception)
225     testFailed(_a + " should be " + stringify(_bv) + ". Threw exception " + exception);
226   else if (isResultCorrect(_av, _bv)) {
227     if (!quiet) {
228         testPassed(_a + " is " + _b);
229     }
230   } else if (typeof(_av) == typeof(_bv))
231     testFailed(_a + " should be " + stringify(_bv) + ". Was " + stringify(_av) + ".");
232   else
233     testFailed(_a + " should be " + stringify(_bv) + " (of type " + typeof _bv + "). Was " + _av + " (of type " + typeof _av + ").");
234 }
235
236 function dfgShouldBe(theFunction, _a, _b)
237 {
238   if (typeof theFunction != "function" || typeof _a != "string" || typeof _b != "string")
239     debug("WARN: dfgShouldBe() expects a function and two strings");
240   noInline(theFunction);
241   var exception;
242   var values = [];
243
244   // Defend against tests that muck with numeric properties on array.prototype.
245   values.__proto__ = null;
246   values.push = Array.prototype.push;
247   
248   try {
249     while (!dfgCompiled({f:theFunction}))
250       values.push(eval(_a));
251     values.push(eval(_a));
252   } catch (e) {
253     exception = e;
254   }
255
256   var _bv = eval(_b);
257   if (exception)
258     testFailed(_a + " should be " + stringify(_bv) + ". On iteration " + (values.length + 1) + ", threw exception " + exception);
259   else {
260     var allPassed = true;
261     for (var i = 0; i < values.length; ++i) {
262       var _av = values[i];
263       if (isResultCorrect(_av, _bv))
264         continue;
265       if (typeof(_av) == typeof(_bv))
266         testFailed(_a + " should be " + stringify(_bv) + ". On iteration " + (i + 1) + ", was " + stringify(_av) + ".");
267       else
268         testFailed(_a + " should be " + stringify(_bv) + " (of type " + typeof _bv + "). On iteration " + (i + 1) + ", was " + _av + " (of type " + typeof _av + ").");
269       allPassed = false;
270     }
271     if (allPassed)
272       testPassed(_a + " is " + _b + " on all iterations including after DFG tier-up.");
273   }
274   
275   return values.length;
276 }
277
278 // Execute condition every 5 milliseconds until it succeeds.
279 function _waitForCondition(condition, completionHandler)
280 {
281   if (condition())
282     completionHandler();
283   else
284     setTimeout(_waitForCondition, 5, condition, completionHandler);
285 }
286
287 function shouldBecomeEqual(_a, _b, completionHandler)
288 {
289   if (typeof _a != "string" || typeof _b != "string")
290     debug("WARN: shouldBecomeEqual() expects string arguments");
291
292   function condition() {
293     var exception;
294     var _av;
295     try {
296       _av = eval(_a);
297     } catch (e) {
298       exception = e;
299     }
300     var _bv = eval(_b);
301     if (exception)
302       testFailed(_a + " should become " + _bv + ". Threw exception " + exception);
303     if (isResultCorrect(_av, _bv)) {
304       testPassed(_a + " became " + _b);
305       return true;
306     }
307     return false;
308   }
309   setTimeout(_waitForCondition, 0, condition, completionHandler);
310 }
311
312 function shouldBecomeEqualToString(value, reference, completionHandler)
313 {
314   if (typeof value !== "string" || typeof reference !== "string")
315     debug("WARN: shouldBecomeEqualToString() expects string arguments");
316   var unevaledString = JSON.stringify(reference);
317   shouldBecomeEqual(value, unevaledString, completionHandler);
318 }
319
320 function shouldBeType(_a, _type) {
321   var exception;
322   var _av;
323   try {
324     _av = eval(_a);
325   } catch (e) {
326     exception = e;
327   }
328
329   var _typev = eval(_type);
330   if (_av instanceof _typev) {
331     testPassed(_a + " is an instance of " + _type);
332   } else {
333     testFailed(_a + " is not an instance of " + _type);
334   }
335 }
336
337 // Variant of shouldBe()--confirms that result of eval(_to_eval) is within
338 // numeric _tolerance of numeric _target.
339 function shouldBeCloseTo(_to_eval, _target, _tolerance, quiet)
340 {
341   if (typeof _to_eval != "string") {
342     testFailed("shouldBeCloseTo() requires string argument _to_eval. was type " + typeof _to_eval);
343     return;
344   }
345   if (typeof _target != "number") {
346     testFailed("shouldBeCloseTo() requires numeric argument _target. was type " + typeof _target);
347     return;
348   }
349   if (typeof _tolerance != "number") {
350     testFailed("shouldBeCloseTo() requires numeric argument _tolerance. was type " + typeof _tolerance);
351     return;
352   }
353
354   var _result;
355   try {
356      _result = eval(_to_eval);
357   } catch (e) {
358     testFailed(_to_eval + " should be within " + _tolerance + " of "
359                + _target + ". Threw exception " + e);
360     return;
361   }
362
363   if (typeof(_result) != typeof(_target)) {
364     testFailed(_to_eval + " should be of type " + typeof _target
365                + " but was of type " + typeof _result);
366   } else if (Math.abs(_result - _target) <= _tolerance) {
367     if (!quiet) {
368         testPassed(_to_eval + " is within " + _tolerance + " of " + _target);
369     }
370   } else {
371     testFailed(_to_eval + " should be within " + _tolerance + " of " + _target
372                + ". Was " + _result + ".");
373   }
374 }
375
376 function shouldNotBe(_a, _b, quiet)
377 {
378   if (typeof _a != "string" || typeof _b != "string")
379     debug("WARN: shouldNotBe() expects string arguments");
380   var exception;
381   var _av;
382   try {
383      _av = eval(_a);
384   } catch (e) {
385      exception = e;
386   }
387   var _bv = eval(_b);
388
389   if (exception)
390     testFailed(_a + " should not be " + _bv + ". Threw exception " + exception);
391   else if (!isResultCorrect(_av, _bv)) {
392     if (!quiet) {
393         testPassed(_a + " is not " + _b);
394     }
395   } else
396     testFailed(_a + " should not be " + _bv + ".");
397 }
398
399 function shouldBecomeDifferent(_a, _b, completionHandler)
400 {
401   if (typeof _a != "string" || typeof _b != "string")
402     debug("WARN: shouldBecomeDifferent() expects string arguments");
403
404   function condition() {
405     var exception;
406     var _av;
407     try {
408       _av = eval(_a);
409     } catch (e) {
410       exception = e;
411     }
412     var _bv = eval(_b);
413     if (exception)
414       testFailed(_a + " should became not equal to " + _bv + ". Threw exception " + exception);
415     if (!isResultCorrect(_av, _bv)) {
416       testPassed(_a + " became different from " + _b);
417       return true;
418     }
419     return false;
420   }
421   setTimeout(_waitForCondition, 0, condition, completionHandler);
422 }
423
424 function shouldBeTrue(_a) { shouldBe(_a, "true"); }
425 function shouldBeTrueQuiet(_a) { shouldBe(_a, "true", true); }
426 function shouldBeFalse(_a) { shouldBe(_a, "false"); }
427 function shouldBeNaN(_a) { shouldBe(_a, "NaN"); }
428 function shouldBeNull(_a) { shouldBe(_a, "null"); }
429 function shouldBeZero(_a) { shouldBe(_a, "0"); }
430
431 function shouldBeEqualToString(a, b)
432 {
433   if (typeof a !== "string" || typeof b !== "string")
434     debug("WARN: shouldBeEqualToString() expects string arguments");
435   var unevaledString = JSON.stringify(b);
436   shouldBe(a, unevaledString);
437 }
438
439 function shouldNotBeEqualToString(a, b)
440 {
441   if (typeof a !== "string" || typeof b !== "string")
442     debug("WARN: shouldBeEqualToString() expects string arguments");
443   var unevaledString = JSON.stringify(b);
444   shouldNotBe(a, unevaledString);
445 }
446 function shouldBeEmptyString(_a) { shouldBeEqualToString(_a, ""); }
447
448 function shouldEvaluateTo(actual, expected) {
449   // A general-purpose comparator.  'actual' should be a string to be
450   // evaluated, as for shouldBe(). 'expected' may be any type and will be
451   // used without being eval'ed.
452   if (expected == null) {
453     // Do this before the object test, since null is of type 'object'.
454     shouldBeNull(actual);
455   } else if (typeof expected == "undefined") {
456     shouldBeUndefined(actual);
457   } else if (typeof expected == "function") {
458     // All this fuss is to avoid the string-arg warning from shouldBe().
459     try {
460       actualValue = eval(actual);
461     } catch (e) {
462       testFailed("Evaluating " + actual + ": Threw exception " + e);
463       return;
464     }
465     shouldBe("'" + actualValue.toString().replace(/\n/g, "") + "'",
466              "'" + expected.toString().replace(/\n/g, "") + "'");
467   } else if (typeof expected == "object") {
468     shouldBeTrue(actual + " == '" + expected + "'");
469   } else if (typeof expected == "string") {
470     shouldBe(actual, expected);
471   } else if (typeof expected == "boolean") {
472     shouldBe("typeof " + actual, "'boolean'");
473     if (expected)
474       shouldBeTrue(actual);
475     else
476       shouldBeFalse(actual);
477   } else if (typeof expected == "number") {
478     shouldBe(actual, stringify(expected));
479   } else {
480     debug(expected + " is unknown type " + typeof expected);
481     shouldBeTrue(actual, "'"  +expected.toString() + "'");
482   }
483 }
484
485 function shouldBeNonZero(_a)
486 {
487   var exception;
488   var _av;
489   try {
490      _av = eval(_a);
491   } catch (e) {
492      exception = e;
493   }
494
495   if (exception)
496     testFailed(_a + " should be non-zero. Threw exception " + exception);
497   else if (_av != 0)
498     testPassed(_a + " is non-zero.");
499   else
500     testFailed(_a + " should be non-zero. Was " + _av);
501 }
502
503 function shouldBeNonNull(_a)
504 {
505   var exception;
506   var _av;
507   try {
508      _av = eval(_a);
509   } catch (e) {
510      exception = e;
511   }
512
513   if (exception)
514     testFailed(_a + " should be non-null. Threw exception " + exception);
515   else if (_av != null)
516     testPassed(_a + " is non-null.");
517   else
518     testFailed(_a + " should be non-null. Was " + _av);
519 }
520
521 function shouldBeUndefined(_a)
522 {
523   var exception;
524   var _av;
525   try {
526      _av = eval(_a);
527   } catch (e) {
528      exception = e;
529   }
530
531   if (exception)
532     testFailed(_a + " should be undefined. Threw exception " + exception);
533   else if (typeof _av == "undefined")
534     testPassed(_a + " is undefined.");
535   else
536     testFailed(_a + " should be undefined. Was " + _av);
537 }
538
539 function shouldBeDefined(_a)
540 {
541   var exception;
542   var _av;
543   try {
544      _av = eval(_a);
545   } catch (e) {
546      exception = e;
547   }
548
549   if (exception)
550     testFailed(_a + " should be defined. Threw exception " + exception);
551   else if (_av !== undefined)
552     testPassed(_a + " is defined.");
553   else
554     testFailed(_a + " should be defined. Was " + _av);
555 }
556
557 function shouldBeGreaterThanOrEqual(_a, _b) {
558     if (typeof _a != "string" || typeof _b != "string")
559         debug("WARN: shouldBeGreaterThanOrEqual expects string arguments");
560
561     var exception;
562     var _av;
563     try {
564         _av = eval(_a);
565     } catch (e) {
566         exception = e;
567     }
568     var _bv = eval(_b);
569
570     if (exception)
571         testFailed(_a + " should be >= " + _b + ". Threw exception " + exception);
572     else if (typeof _av == "undefined" || _av < _bv)
573         testFailed(_a + " should be >= " + _b + ". Was " + _av + " (of type " + typeof _av + ").");
574     else
575         testPassed(_a + " is >= " + _b);
576 }
577
578 function expectTrue(v, msg) {
579   if (v) {
580     testPassed(msg);
581   } else {
582     testFailed(msg);
583   }
584 }
585
586 function shouldNotThrow(_a) {
587     try {
588         eval(_a);
589         testPassed(_a + " did not throw exception.");
590     } catch (e) {
591         testFailed(_a + " should not throw exception. Threw exception " + e + ".");
592     }
593 }
594
595 function shouldThrow(_a, _e)
596 {
597   var exception;
598   var _av;
599   try {
600      _av = eval(_a);
601   } catch (e) {
602      exception = e;
603   }
604
605   var _ev;
606   if (_e)
607       _ev =  eval(_e);
608
609   if (exception) {
610     if (typeof _e == "undefined" || exception == _ev)
611       testPassed(_a + " threw exception " + exception + ".");
612     else
613       testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Threw exception " + exception + ".");
614   } else if (typeof _av == "undefined")
615     testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was undefined.");
616   else
617     testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was " + _av + ".");
618 }
619
620 function shouldHaveHadError(message)
621 {
622     if (errorMessage) {
623         if (!message)
624             testPassed("Got expected error");
625         else if (errorMessage.indexOf(message) !== -1)
626             testPassed("Got expected error: '" + message + "'");
627         else
628             testFailed("Unexpexted error '" + message + "'");
629     } else
630         testFailed("Missing expexted error");
631     errorMessage = undefined;
632 }
633
634 function gc() {
635     if (typeof GCController !== "undefined")
636         GCController.collect();
637     else {
638         var gcRec = function (n) {
639             if (n < 1)
640                 return {};
641             var temp = {i: "ab" + i + (i / 100000)};
642             temp += "foo";
643             gcRec(n-1);
644         };
645         for (var i = 0; i < 1000; i++)
646             gcRec(10)
647     }
648 }
649
650 function dfgCompiled(argument)
651 {
652     var numberOfCompiles = "compiles" in argument ? argument.compiles : 1;
653     
654     if (!("f" in argument))
655         throw new Error("dfgCompiled called with invalid argument.");
656     
657     if (argument.f instanceof Array) {
658         for (var i = 0; i < argument.f.length; ++i) {
659             if (testRunner.numberOfDFGCompiles(argument.f[i]) < numberOfCompiles)
660                 return false;
661         }
662     } else {
663         if (testRunner.numberOfDFGCompiles(argument.f) < numberOfCompiles)
664             return false;
665     }
666     
667     return true;
668 }
669
670 function dfgIncrement(argument)
671 {
672     if (!self.testRunner)
673         return argument.i;
674     
675     if (argument.i < argument.n)
676         return argument.i;
677     
678     if (didFailSomeTests)
679         return argument.i;
680     
681     if (!dfgCompiled(argument))
682         return "start" in argument ? argument.start : 0;
683     
684     return argument.i;
685 }
686
687 function noInline(theFunction)
688 {
689     if (!self.testRunner)
690         return;
691     
692     testRunner.neverInlineFunction(theFunction);
693 }
694
695 function isSuccessfullyParsed()
696 {
697     // FIXME: Remove this and only report unexpected syntax errors.
698     if (!errorMessage)
699         successfullyParsed = true;
700     shouldBeTrue("successfullyParsed");
701     if (silentTestPass && didPassSomeTestsSilently)
702         debug("Passed some tests silently.");
703     if (silentTestPass && didFailSomeTests)
704         debug("Some tests failed.");
705     debug('<br /><span class="pass">TEST COMPLETE</span>');
706 }
707
708 // It's possible for an async test to call finishJSTest() before js-test-post.js
709 // has been parsed.
710 function finishJSTest()
711 {
712     wasFinishJSTestCalled = true;
713     if (!self.wasPostTestScriptParsed)
714         return;
715     isSuccessfullyParsed();
716     if (self.jsTestIsAsync && self.testRunner)
717         testRunner.notifyDone();
718 }
719
720 function startWorker(testScriptURL)
721 {
722     self.jsTestIsAsync = true;
723     debug('Starting worker: ' + testScriptURL);
724     var worker = new Worker(testScriptURL);
725     worker.onmessage = function(event)
726     {
727         var workerPrefix = "[Worker] ";
728         if (event.data.length < 5 || event.data.charAt(4) != ':') {
729           debug(workerPrefix + event.data);
730           return;
731         }
732         var code = event.data.substring(0, 4);
733         var payload = workerPrefix + event.data.substring(5);
734         if (code == "PASS")
735             testPassed(payload);
736         else if (code == "FAIL")
737             testFailed(payload);
738         else if (code == "DESC")
739             description(payload);
740         else if (code == "DONE")
741             finishJSTest();
742         else
743             debug(workerPrefix + event.data);
744     };
745
746     worker.onerror = function(event)
747     {
748         debug('Got error from worker: ' + event.message);
749         finishJSTest();
750     }
751
752     return worker;
753 }
754
755 if (isWorker()) {
756     var workerPort = self;
757     description = function(msg, quiet) {
758         workerPort.postMessage('DESC:' + msg);
759     }
760     testFailed = function(msg) {
761         workerPort.postMessage('FAIL:' + msg);
762     }
763     testPassed = function(msg) {
764         workerPort.postMessage('PASS:' + msg);
765     }
766     finishJSTest = function() {
767         workerPort.postMessage('DONE:');
768     }
769     debug = function(msg) {
770         workerPort.postMessage(msg);
771     }
772 }