Enhance shouldBe()/shouldNotBe() to accept anonymous function arguments
[WebKit-https.git] / LayoutTests / http / tests / 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: evalAndLog() 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 evalAndLogResult(_a)
212 {
213   if (typeof _a != "string")
214     debug("WARN: evalAndLogResult() expects a string argument");
215
216   var _av;
217   try {
218      _av = eval(_a);
219   } catch (e) {
220     testFailed(_a + " threw exception " + e);
221   }
222
223   debug('<span>' + _a + " is " + escapeHTML(_av) + '</span>');
224 }
225
226 function shouldBe(_a, _b, quiet)
227 {
228   if ((typeof _a != "function" && typeof _a != "string") || (typeof _b != "function" && typeof _b != "string"))
229     debug("WARN: shouldBe() expects function or string arguments");
230   var exception;
231   var _av;
232   try {
233     _av = (typeof _a == "function" ? _a() : eval(_a));
234   } catch (e) {
235     exception = e;
236   }
237   var _bv = (typeof _b == "function" ? _b() : eval(_b));
238
239   if (exception)
240     testFailed(_a + " should be " + stringify(_bv) + ". Threw exception " + exception);
241   else if (isResultCorrect(_av, _bv)) {
242     if (!quiet) {
243       testPassed(_a + " is " + (typeof _b == "function" ? _bv : _b));
244     }
245   } else if (typeof(_av) == typeof(_bv))
246     testFailed(_a + " should be " + stringify(_bv) + ". Was " + stringify(_av) + ".");
247   else
248     testFailed(_a + " should be " + stringify(_bv) + " (of type " + typeof _bv + "). Was " + _av + " (of type " + typeof _av + ").");
249 }
250
251 function dfgShouldBe(theFunction, _a, _b)
252 {
253   if (typeof theFunction != "function" || typeof _a != "string" || typeof _b != "string")
254     debug("WARN: dfgShouldBe() expects a function and two strings");
255   noInline(theFunction);
256   var exception;
257   var values = [];
258
259   // Defend against tests that muck with numeric properties on array.prototype.
260   values.__proto__ = null;
261   values.push = Array.prototype.push;
262   
263   try {
264     while (!dfgCompiled({f:theFunction}))
265       values.push(eval(_a));
266     values.push(eval(_a));
267   } catch (e) {
268     exception = e;
269   }
270
271   var _bv = eval(_b);
272   if (exception)
273     testFailed(_a + " should be " + stringify(_bv) + ". On iteration " + (values.length + 1) + ", threw exception " + exception);
274   else {
275     var allPassed = true;
276     for (var i = 0; i < values.length; ++i) {
277       var _av = values[i];
278       if (isResultCorrect(_av, _bv))
279         continue;
280       if (typeof(_av) == typeof(_bv))
281         testFailed(_a + " should be " + stringify(_bv) + ". On iteration " + (i + 1) + ", was " + stringify(_av) + ".");
282       else
283         testFailed(_a + " should be " + stringify(_bv) + " (of type " + typeof _bv + "). On iteration " + (i + 1) + ", was " + _av + " (of type " + typeof _av + ").");
284       allPassed = false;
285     }
286     if (allPassed)
287       testPassed(_a + " is " + _b + " on all iterations including after DFG tier-up.");
288   }
289   
290   return values.length;
291 }
292
293 // Execute condition every 5 milliseconds until it succeeds.
294 function _waitForCondition(condition, completionHandler)
295 {
296   if (condition())
297     completionHandler();
298   else
299     setTimeout(_waitForCondition, 5, condition, completionHandler);
300 }
301
302 function shouldBecomeEqual(_a, _b, completionHandler)
303 {
304   if (typeof _a != "string" || typeof _b != "string")
305     debug("WARN: shouldBecomeEqual() expects string arguments");
306
307   function condition() {
308     var exception;
309     var _av;
310     try {
311       _av = eval(_a);
312     } catch (e) {
313       exception = e;
314     }
315     var _bv = eval(_b);
316     if (exception)
317       testFailed(_a + " should become " + _bv + ". Threw exception " + exception);
318     if (isResultCorrect(_av, _bv)) {
319       testPassed(_a + " became " + _b);
320       return true;
321     }
322     return false;
323   }
324   setTimeout(_waitForCondition, 0, condition, completionHandler);
325 }
326
327 function shouldBecomeEqualToString(value, reference, completionHandler)
328 {
329   if (typeof value !== "string" || typeof reference !== "string")
330     debug("WARN: shouldBecomeEqualToString() expects string arguments");
331   var unevaledString = JSON.stringify(reference);
332   shouldBecomeEqual(value, unevaledString, completionHandler);
333 }
334
335 function shouldBeType(_a, _type) {
336   var exception;
337   var _av;
338   try {
339     _av = eval(_a);
340   } catch (e) {
341     exception = e;
342   }
343
344   var _typev = eval(_type);
345   if (_av instanceof _typev) {
346     testPassed(_a + " is an instance of " + _type);
347   } else {
348     testFailed(_a + " is not an instance of " + _type);
349   }
350 }
351
352 // Variant of shouldBe()--confirms that result of eval(_to_eval) is within
353 // numeric _tolerance of numeric _target.
354 function shouldBeCloseTo(_to_eval, _target, _tolerance, quiet)
355 {
356   if (typeof _to_eval != "string") {
357     testFailed("shouldBeCloseTo() requires string argument _to_eval. was type " + typeof _to_eval);
358     return;
359   }
360   if (typeof _target != "number") {
361     testFailed("shouldBeCloseTo() requires numeric argument _target. was type " + typeof _target);
362     return;
363   }
364   if (typeof _tolerance != "number") {
365     testFailed("shouldBeCloseTo() requires numeric argument _tolerance. was type " + typeof _tolerance);
366     return;
367   }
368
369   var _result;
370   try {
371      _result = eval(_to_eval);
372   } catch (e) {
373     testFailed(_to_eval + " should be within " + _tolerance + " of "
374                + _target + ". Threw exception " + e);
375     return;
376   }
377
378   if (typeof(_result) != typeof(_target)) {
379     testFailed(_to_eval + " should be of type " + typeof _target
380                + " but was of type " + typeof _result);
381   } else if (Math.abs(_result - _target) <= _tolerance) {
382     if (!quiet) {
383         testPassed(_to_eval + " is within " + _tolerance + " of " + _target);
384     }
385   } else {
386     testFailed(_to_eval + " should be within " + _tolerance + " of " + _target
387                + ". Was " + _result + ".");
388   }
389 }
390
391 function shouldNotBe(_a, _b, quiet)
392 {
393   if ((typeof _a != "function" && typeof _a != "string") || (typeof _b != "function" && typeof _b != "string"))
394     debug("WARN: shouldNotBe() expects function or string arguments");
395   var exception;
396   var _av;
397   try {
398     _av = (typeof _a == "function" ? _a() : eval(_a));
399   } catch (e) {
400     exception = e;
401   }
402   var _bv = (typeof _b == "function" ? _b() : eval(_b));
403
404   if (exception)
405     testFailed(_a + " should not be " + _bv + ". Threw exception " + exception);
406   else if (!isResultCorrect(_av, _bv)) {
407     if (!quiet) {
408       testPassed(_a + " is not " + (typeof _b == "function" ? _bv : _b));
409     }
410   } else
411     testFailed(_a + " should not be " + _bv + ".");
412 }
413
414 function shouldBecomeDifferent(_a, _b, completionHandler)
415 {
416   if (typeof _a != "string" || typeof _b != "string")
417     debug("WARN: shouldBecomeDifferent() expects string arguments");
418
419   function condition() {
420     var exception;
421     var _av;
422     try {
423       _av = eval(_a);
424     } catch (e) {
425       exception = e;
426     }
427     var _bv = eval(_b);
428     if (exception)
429       testFailed(_a + " should became not equal to " + _bv + ". Threw exception " + exception);
430     if (!isResultCorrect(_av, _bv)) {
431       testPassed(_a + " became different from " + _b);
432       return true;
433     }
434     return false;
435   }
436   setTimeout(_waitForCondition, 0, condition, completionHandler);
437 }
438
439 function shouldBeTrue(_a) { shouldBe(_a, "true"); }
440 function shouldBeTrueQuiet(_a) { shouldBe(_a, "true", true); }
441 function shouldBeFalse(_a) { shouldBe(_a, "false"); }
442 function shouldBeNaN(_a) { shouldBe(_a, "NaN"); }
443 function shouldBeNull(_a) { shouldBe(_a, "null"); }
444 function shouldBeZero(_a) { shouldBe(_a, "0"); }
445
446 function shouldBeEqualToString(a, b)
447 {
448   if (typeof a !== "string" || typeof b !== "string")
449     debug("WARN: shouldBeEqualToString() expects string arguments");
450   var unevaledString = JSON.stringify(b);
451   shouldBe(a, unevaledString);
452 }
453
454 function shouldNotBeEqualToString(a, b)
455 {
456   if (typeof a !== "string" || typeof b !== "string")
457     debug("WARN: shouldBeEqualToString() expects string arguments");
458   var unevaledString = JSON.stringify(b);
459   shouldNotBe(a, unevaledString);
460 }
461 function shouldBeEmptyString(_a) { shouldBeEqualToString(_a, ""); }
462
463 function shouldEvaluateTo(actual, expected)
464 {
465   // A general-purpose comparator.  'actual' should be a string to be
466   // evaluated, as for shouldBe(). 'expected' may be any type and will be
467   // used without being eval'ed.
468   if (expected == null) {
469     // Do this before the object test, since null is of type 'object'.
470     shouldBeNull(actual);
471   } else if (typeof expected == "undefined") {
472     shouldBeUndefined(actual);
473   } else if (typeof expected == "function") {
474     // All this fuss is to avoid the string-arg warning from shouldBe().
475     try {
476       actualValue = eval(actual);
477     } catch (e) {
478       testFailed("Evaluating " + actual + ": Threw exception " + e);
479       return;
480     }
481     shouldBe("'" + actualValue.toString().replace(/\n/g, "") + "'",
482              "'" + expected.toString().replace(/\n/g, "") + "'");
483   } else if (typeof expected == "object") {
484     shouldBeTrue(actual + " == '" + expected + "'");
485   } else if (typeof expected == "string") {
486     shouldBe(actual, expected);
487   } else if (typeof expected == "boolean") {
488     shouldBe("typeof " + actual, "'boolean'");
489     if (expected)
490       shouldBeTrue(actual);
491     else
492       shouldBeFalse(actual);
493   } else if (typeof expected == "number") {
494     shouldBe(actual, stringify(expected));
495   } else {
496     debug(expected + " is unknown type " + typeof expected);
497     shouldBeTrue(actual, "'"  +expected.toString() + "'");
498   }
499 }
500
501 function shouldBeNonZero(_a)
502 {
503   var exception;
504   var _av;
505   try {
506      _av = eval(_a);
507   } catch (e) {
508      exception = e;
509   }
510
511   if (exception)
512     testFailed(_a + " should be non-zero. Threw exception " + exception);
513   else if (_av != 0)
514     testPassed(_a + " is non-zero.");
515   else
516     testFailed(_a + " should be non-zero. Was " + _av);
517 }
518
519 function shouldBeNonNull(_a)
520 {
521   var exception;
522   var _av;
523   try {
524      _av = eval(_a);
525   } catch (e) {
526      exception = e;
527   }
528
529   if (exception)
530     testFailed(_a + " should be non-null. Threw exception " + exception);
531   else if (_av != null)
532     testPassed(_a + " is non-null.");
533   else
534     testFailed(_a + " should be non-null. Was " + _av);
535 }
536
537 function shouldBeUndefined(_a)
538 {
539   var exception;
540   var _av;
541   try {
542      _av = eval(_a);
543   } catch (e) {
544      exception = e;
545   }
546
547   if (exception)
548     testFailed(_a + " should be undefined. Threw exception " + exception);
549   else if (typeof _av == "undefined")
550     testPassed(_a + " is undefined.");
551   else
552     testFailed(_a + " should be undefined. Was " + _av);
553 }
554
555 function shouldBeDefined(_a)
556 {
557   var exception;
558   var _av;
559   try {
560      _av = eval(_a);
561   } catch (e) {
562      exception = e;
563   }
564
565   if (exception)
566     testFailed(_a + " should be defined. Threw exception " + exception);
567   else if (_av !== undefined)
568     testPassed(_a + " is defined.");
569   else
570     testFailed(_a + " should be defined. Was " + _av);
571 }
572
573 function shouldBeGreaterThanOrEqual(_a, _b) {
574     if (typeof _a != "string" || typeof _b != "string")
575         debug("WARN: shouldBeGreaterThanOrEqual expects string arguments");
576
577     var exception;
578     var _av;
579     try {
580         _av = eval(_a);
581     } catch (e) {
582         exception = e;
583     }
584     var _bv = eval(_b);
585
586     if (exception)
587         testFailed(_a + " should be >= " + _b + ". Threw exception " + exception);
588     else if (typeof _av == "undefined" || _av < _bv)
589         testFailed(_a + " should be >= " + _b + ". Was " + _av + " (of type " + typeof _av + ").");
590     else
591         testPassed(_a + " is >= " + _b);
592 }
593
594 function expectTrue(v, msg) {
595   if (v) {
596     testPassed(msg);
597   } else {
598     testFailed(msg);
599   }
600 }
601
602 function shouldNotThrow(_a, _message) {
603     try {
604         typeof _a == "function" ? _a() : eval(_a);
605         testPassed((_message ? _message : _a) + " did not throw exception.");
606     } catch (e) {
607         testFailed((_message ? _message : _a) + " should not throw exception. Threw exception " + e + ".");
608     }
609 }
610
611 function shouldThrow(_a, _e, _message)
612 {
613     var _exception;
614     var _av;
615     try {
616         _av = typeof _a == "function" ? _a() : eval(_a);
617     } catch (e) {
618         _exception = e;
619     }
620
621     var _ev;
622     if (_e)
623         _ev = eval(_e);
624
625     if (_exception) {
626         if (typeof _e == "undefined" || _exception == _ev)
627             testPassed((_message ? _message : _a) + " threw exception " + _exception + ".");
628         else
629             testFailed((_message ? _message : _a) + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Threw exception " + _exception + ".");
630     } else if (typeof _av == "undefined")
631         testFailed((_message ? _message : _a) + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was undefined.");
632     else
633         testFailed((_message ? _message : _a) + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was " + _av + ".");
634 }
635
636 function shouldReject(_a, _message)
637 {
638     var _exception;
639     var _av;
640     try {
641         _av = typeof _a == "function" ? _a() : eval(_a);
642     } catch (e) {
643         testFailed((_message ? _message : _a) + " should not throw exception. Threw exception " + e + ".");
644         return Promise.resolve();
645     }
646
647      return _av.then(function(result) {
648         testFailed((_message ? _message : _a) + " should reject promise. Resolved with " + result + ".");
649     }, function(error) {
650         testPassed((_message ? _message : _a) + " rejected promise  with " + error + ".");
651     });
652 }
653
654 function shouldThrowErrorName(_a, _name)
655 {
656     var _exception;
657     try {
658         typeof _a == "function" ? _a() : eval(_a);
659     } catch (e) {
660         _exception = e;
661     }
662
663     if (_exception) {
664         if (_exception.name == _name)
665             testPassed(_a + " threw exception " + _exception + ".");
666         else
667             testFailed(_a + " should throw a " + _name + ". Threw a " + _exception.name + ".");
668     } else
669         testFailed(_a + " should throw a " + _name + ". Did not throw.");
670 }
671
672 function shouldHaveHadError(message)
673 {
674     if (errorMessage) {
675         if (!message)
676             testPassed("Got expected error");
677         else if (errorMessage.indexOf(message) !== -1)
678             testPassed("Got expected error: '" + message + "'");
679         else
680             testFailed("Unexpexted error '" + message + "'");
681     } else
682         testFailed("Missing expexted error");
683     errorMessage = undefined;
684 }
685
686 function gc() {
687     if (typeof GCController !== "undefined")
688         GCController.collect();
689     else {
690         var gcRec = function (n) {
691             if (n < 1)
692                 return {};
693             var temp = {i: "ab" + i + (i / 100000)};
694             temp += "foo";
695             gcRec(n-1);
696         };
697         for (var i = 0; i < 1000; i++)
698             gcRec(10)
699     }
700 }
701
702 function dfgCompiled(argument)
703 {
704     var numberOfCompiles = "compiles" in argument ? argument.compiles : 1;
705     
706     if (!("f" in argument))
707         throw new Error("dfgCompiled called with invalid argument.");
708     
709     if (argument.f instanceof Array) {
710         for (var i = 0; i < argument.f.length; ++i) {
711             if (testRunner.numberOfDFGCompiles(argument.f[i]) < numberOfCompiles)
712                 return false;
713         }
714     } else {
715         if (testRunner.numberOfDFGCompiles(argument.f) < numberOfCompiles)
716             return false;
717     }
718     
719     return true;
720 }
721
722 function dfgIncrement(argument)
723 {
724     if (!self.testRunner)
725         return argument.i;
726     
727     if (argument.i < argument.n)
728         return argument.i;
729     
730     if (didFailSomeTests)
731         return argument.i;
732     
733     if (!dfgCompiled(argument))
734         return "start" in argument ? argument.start : 0;
735     
736     return argument.i;
737 }
738
739 function noInline(theFunction)
740 {
741     if (!self.testRunner)
742         return;
743     
744     testRunner.neverInlineFunction(theFunction);
745 }
746
747 function isSuccessfullyParsed()
748 {
749     // FIXME: Remove this and only report unexpected syntax errors.
750     if (!errorMessage)
751         successfullyParsed = true;
752     shouldBeTrue("successfullyParsed");
753     if (silentTestPass && didPassSomeTestsSilently)
754         debug("Passed some tests silently.");
755     if (silentTestPass && didFailSomeTests)
756         debug("Some tests failed.");
757     debug('<br /><span class="pass">TEST COMPLETE</span>');
758 }
759
760 // It's possible for an async test to call finishJSTest() before js-test-post.js
761 // has been parsed.
762 function finishJSTest()
763 {
764     wasFinishJSTestCalled = true;
765     if (!self.wasPostTestScriptParsed)
766         return;
767     isSuccessfullyParsed();
768     if (self.jsTestIsAsync && self.testRunner)
769         testRunner.notifyDone();
770 }
771
772 function startWorker(testScriptURL)
773 {
774     self.jsTestIsAsync = true;
775     debug('Starting worker: ' + testScriptURL);
776     var worker = new Worker(testScriptURL);
777     worker.onmessage = function(event)
778     {
779         var workerPrefix = "[Worker] ";
780         if (event.data.length < 5 || event.data.charAt(4) != ':') {
781           debug(workerPrefix + event.data);
782           return;
783         }
784         var code = event.data.substring(0, 4);
785         var payload = workerPrefix + event.data.substring(5);
786         if (code == "PASS")
787             testPassed(payload);
788         else if (code == "FAIL")
789             testFailed(payload);
790         else if (code == "DESC")
791             description(payload);
792         else if (code == "DONE")
793             finishJSTest();
794         else
795             debug(workerPrefix + event.data);
796     };
797
798     worker.onerror = function(event)
799     {
800         debug('Got error from worker: ' + event.message);
801         finishJSTest();
802     }
803
804     return worker;
805 }
806
807 if (isWorker()) {
808     var workerPort = self;
809     description = function(msg, quiet) {
810         workerPort.postMessage('DESC:' + msg);
811     }
812     testFailed = function(msg) {
813         workerPort.postMessage('FAIL:' + msg);
814     }
815     testPassed = function(msg) {
816         workerPort.postMessage('PASS:' + msg);
817     }
818     finishJSTest = function() {
819         workerPort.postMessage('DONE:');
820     }
821     debug = function(msg) {
822         workerPort.postMessage(msg);
823     }
824 }