put_by_val_direct need to check the property is index or not for using putDirect...
[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 dfgShouldThrow(theFunction, _a, _e)
621 {
622   if (typeof theFunction != "function" || typeof _a != "string" || typeof _e != "string")
623     debug("WARN: dfgShouldBe() expects a function and two strings");
624   noInline(theFunction);
625   var values = [], _av = undefined, notThrow = false;
626
627   // Defend against tests that muck with numeric properties on array.prototype.
628   values.__proto__ = null;
629   values.push = Array.prototype.push;
630
631   while (!dfgCompiled({f:theFunction})) {
632     try {
633         _av = eval(_a);
634         notThrow = true;
635     } catch (exception) {
636         values.push(exception);
637     }
638   }
639   try {
640     _av = eval(_a);
641     notThrow = true;
642   } catch (exception) {
643     values.push(exception);
644   }
645
646   var _ev = eval(_e);
647   if (notThrow) {
648     if (typeof _av == "undefined")
649       testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was undefined.");
650     else
651       testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was " + _av + ".");
652   } else {
653     var allPassed = true;
654     for (var i = 0; i < values.length; ++i) {
655       var _av = values[i];
656       if (typeof _e == "undefined" || _av == _ev)
657         continue;
658       testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Threw exception " + _av + ".");
659       allPassed = false;
660     }
661     if (allPassed)
662       testPassed(_a + " threw exception " + _e + " on all iterations including after DFG tier-up.");
663   }
664
665   return values.length;
666 }
667
668 function shouldHaveHadError(message)
669 {
670     if (errorMessage) {
671         if (!message)
672             testPassed("Got expected error");
673         else if (errorMessage.indexOf(message) !== -1)
674             testPassed("Got expected error: '" + message + "'");
675         else
676             testFailed("Unexpexted error '" + message + "'");
677     } else
678         testFailed("Missing expexted error");
679     errorMessage = undefined;
680 }
681
682 function gc() {
683     if (typeof GCController !== "undefined")
684         GCController.collect();
685     else {
686         var gcRec = function (n) {
687             if (n < 1)
688                 return {};
689             var temp = {i: "ab" + i + (i / 100000)};
690             temp += "foo";
691             gcRec(n-1);
692         };
693         for (var i = 0; i < 1000; i++)
694             gcRec(10)
695     }
696 }
697
698 function dfgCompiled(argument)
699 {
700     var numberOfCompiles = "compiles" in argument ? argument.compiles : 1;
701     
702     if (!("f" in argument))
703         throw new Error("dfgCompiled called with invalid argument.");
704     
705     if (argument.f instanceof Array) {
706         for (var i = 0; i < argument.f.length; ++i) {
707             if (testRunner.numberOfDFGCompiles(argument.f[i]) < numberOfCompiles)
708                 return false;
709         }
710     } else {
711         if (testRunner.numberOfDFGCompiles(argument.f) < numberOfCompiles)
712             return false;
713     }
714     
715     return true;
716 }
717
718 function dfgIncrement(argument)
719 {
720     if (!self.testRunner)
721         return argument.i;
722     
723     if (argument.i < argument.n)
724         return argument.i;
725     
726     if (didFailSomeTests)
727         return argument.i;
728     
729     if (!dfgCompiled(argument))
730         return "start" in argument ? argument.start : 0;
731     
732     return argument.i;
733 }
734
735 function noInline(theFunction)
736 {
737     if (!self.testRunner)
738         return;
739     
740     testRunner.neverInlineFunction(theFunction);
741 }
742
743 function isSuccessfullyParsed()
744 {
745     // FIXME: Remove this and only report unexpected syntax errors.
746     if (!errorMessage)
747         successfullyParsed = true;
748     shouldBeTrue("successfullyParsed");
749     if (silentTestPass && didPassSomeTestsSilently)
750         debug("Passed some tests silently.");
751     if (silentTestPass && didFailSomeTests)
752         debug("Some tests failed.");
753     debug('<br /><span class="pass">TEST COMPLETE</span>');
754 }
755
756 // It's possible for an async test to call finishJSTest() before js-test-post.js
757 // has been parsed.
758 function finishJSTest()
759 {
760     wasFinishJSTestCalled = true;
761     if (!self.wasPostTestScriptParsed)
762         return;
763     isSuccessfullyParsed();
764     if (self.jsTestIsAsync && self.testRunner)
765         testRunner.notifyDone();
766 }
767
768 function startWorker(testScriptURL)
769 {
770     self.jsTestIsAsync = true;
771     debug('Starting worker: ' + testScriptURL);
772     var worker = new Worker(testScriptURL);
773     worker.onmessage = function(event)
774     {
775         var workerPrefix = "[Worker] ";
776         if (event.data.length < 5 || event.data.charAt(4) != ':') {
777           debug(workerPrefix + event.data);
778           return;
779         }
780         var code = event.data.substring(0, 4);
781         var payload = workerPrefix + event.data.substring(5);
782         if (code == "PASS")
783             testPassed(payload);
784         else if (code == "FAIL")
785             testFailed(payload);
786         else if (code == "DESC")
787             description(payload);
788         else if (code == "DONE")
789             finishJSTest();
790         else
791             debug(workerPrefix + event.data);
792     };
793
794     worker.onerror = function(event)
795     {
796         debug('Got error from worker: ' + event.message);
797         finishJSTest();
798     }
799
800     return worker;
801 }
802
803 if (isWorker()) {
804     var workerPort = self;
805     description = function(msg, quiet) {
806         workerPort.postMessage('DESC:' + msg);
807     }
808     testFailed = function(msg) {
809         workerPort.postMessage('FAIL:' + msg);
810     }
811     testPassed = function(msg) {
812         workerPort.postMessage('PASS:' + msg);
813     }
814     finishJSTest = function() {
815         workerPort.postMessage('DONE:');
816     }
817     debug = function(msg) {
818         workerPort.postMessage(msg);
819     }
820 }