Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / LayoutTests / resources / js-test.js
1 // svg/dynamic-updates tests set enablePixelTesting=true, as we want to dump text + pixel results
2 if (self.testRunner) {
3     if (self.enablePixelTesting)
4         testRunner.dumpAsTextWithPixelResults();
5     else
6         testRunner.dumpAsText();
7 }
8
9 var isJsTest = true;
10
11 var description, debug, successfullyParsed;
12
13 var expectingError; // set by shouldHaveError()
14 var expectedErrorMessage; // set by onerror when expectingError is true
15 var unexpectedErrorMessage; // set by onerror when expectingError is not true
16
17 (function() {
18
19     function getOrCreate(id, tagName)
20     {
21         var element = document.getElementById(id);
22         if (element)
23             return element;
24
25         element = document.createElement(tagName);
26         element.id = id;
27         var refNode;
28         var parent = document.body || document.documentElement;
29         if (id == "description")
30             refNode = getOrCreate("console", "div");
31         else
32             refNode = parent.firstChild;
33
34         parent.insertBefore(element, refNode);
35         return element;
36     }
37
38     description = function description(msg, quiet)
39     {
40         // For MSIE 6 compatibility
41         var span = document.createElement("span");
42         if (quiet)
43             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>';
44         else
45             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>';
46
47         var description = getOrCreate("description", "p");
48         if (description.firstChild)
49             description.replaceChild(span, description.firstChild);
50         else
51             description.appendChild(span);
52     };
53
54     debug = function debug(msg)
55     {
56         var span = document.createElement("span");
57         getOrCreate("console", "div").appendChild(span); // insert it first so XHTML knows the namespace
58         span.innerHTML = msg + '<br />';
59     };
60
61     var css =
62         ".pass {" +
63             "font-weight: bold;" +
64             "color: green;" +
65         "}" +
66         ".fail {" +
67             "font-weight: bold;" +
68             "color: red;" +
69         "}" +
70         "#console {" +
71             "white-space: pre-wrap;" +
72             "font-family: monospace;" +
73         "}";
74
75     function insertStyleSheet()
76     {
77         var styleElement = document.createElement("style");
78         styleElement.textContent = css;
79         (document.head || document.documentElement).appendChild(styleElement);
80     }
81
82     function handleTestFinished()
83     {
84         // FIXME: Get rid of this boolean.
85         wasPostTestScriptParsed = true;
86         if (window.jsTestIsAsync) {
87             if (window.testRunner)
88                 testRunner.waitUntilDone();
89             if (window.wasFinishJSTestCalled)
90                 finishJSTest();
91         } else
92             finishJSTest();
93     }
94
95     if (!isWorker()) {
96         window.addEventListener('DOMContentLoaded', handleTestFinished, false);
97         insertStyleSheet();
98     }
99
100     if (!self.isOnErrorTest) {
101         self.onerror = function(message)
102         {
103             if (self.expectingError) {
104                 self.expectedErrorMessage = message;
105                 self.expectingError = false;
106                 return;
107             }
108             self.unexpectedErrorMessage = message;
109             if (self.jsTestIsAsync) {
110                 self.testFailed("Unexpected error: " + message);
111                 finishJSTest();
112             }
113         };
114     }
115 })();
116
117 function isWorker()
118 {
119     // It's conceivable that someone would stub out 'document' in a worker so
120     // also check for childNodes, an arbitrary DOM-related object that is
121     // meaningless in a WorkerContext.
122     return (typeof document === 'undefined' || typeof document.childNodes === 'undefined') && !!self.importScripts;
123 }
124
125 function descriptionQuiet(msg) { description(msg, true); }
126
127 function escapeHTML(text)
128 {
129     return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/\0/g, "\\0");
130 }
131
132 function testPassed(msg)
133 {
134     debug('<span><span class="pass">PASS</span> ' + escapeHTML(msg) + '</span>');
135 }
136
137 function testFailed(msg)
138 {
139     debug('<span><span class="fail">FAIL</span> ' + escapeHTML(msg) + '</span>');
140 }
141
142 function areArraysEqual(a, b)
143 {
144     try {
145         if (a.length !== b.length)
146             return false;
147         for (var i = 0; i < a.length; i++)
148             if (a[i] !== b[i])
149                 return false;
150     } catch (ex) {
151         return false;
152     }
153     return true;
154 }
155
156 function isMinusZero(n)
157 {
158     // the only way to tell 0 from -0 in JS is the fact that 1/-0 is
159     // -Infinity instead of Infinity
160     return n === 0 && 1/n < 0;
161 }
162
163 function isNewSVGTearOffType(v)
164 {
165     return ['[object SVGLength]', '[object SVGLengthList]', '[object SVGPoint]', '[object SVGPointList]', '[object SVGNumber]', '[object SVGTransform]', '[object SVGTransformList]'].indexOf(""+v) != -1;
166 }
167
168 function isResultCorrect(actual, expected)
169 {
170     if (expected === 0)
171         return actual === expected && (1/actual) === (1/expected);
172     if (actual === expected)
173         return true;
174     // http://crbug.com/308818 : The new implementation of SVGListProperties do not necessary return the same wrapper object, so === operator would not work. We compare for their string representation instead.
175     if (isNewSVGTearOffType(expected) && typeof(expected) == typeof(actual) && actual.valueAsString == expected.valueAsString)
176         return true;
177     if (typeof(expected) == "number" && isNaN(expected))
178         return typeof(actual) == "number" && isNaN(actual);
179     if (expected && (Object.prototype.toString.call(expected) == Object.prototype.toString.call([])))
180         return areArraysEqual(actual, expected);
181     return false;
182 }
183
184 function stringify(v)
185 {
186     if (isNewSVGTearOffType(v))
187         return v.valueAsString;
188     if (v === 0 && 1/v < 0)
189         return "-0";
190     else 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, opt_tolerance)
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 " + _bv + ". Threw exception " + _exception);
226   else if (isResultCorrect(_av, _bv) || (typeof opt_tolerance == 'number' && typeof _av == 'number' && Math.abs(_av - _bv) <= opt_tolerance)) {
227     if (!quiet) {
228         testPassed(_a + " is " + _b);
229     }
230   } else if (typeof(_av) == typeof(_bv))
231     testFailed(_a + " should be " + _bv + ". Was " + stringify(_av) + ".");
232   else
233     testFailed(_a + " should be " + _bv + " (of type " + typeof _bv + "). Was " + _av + " (of type " + typeof _av + ").");
234 }
235
236 // Execute condition every 5 milliseconds until it succeed or failureTime is reached.
237 // completionHandler is executed on success, failureHandler is executed on timeout.
238 function _waitForCondition(condition, failureTime, completionHandler, failureHandler)
239 {
240   if (condition()) {
241     completionHandler();
242   } else if (Date.now() > failureTime) {
243     failureHandler();
244   } else {
245     setTimeout(_waitForCondition, 5, condition, failureTime, completionHandler, failureHandler);
246   }
247 }
248
249 function shouldBecomeEqual(_a, _b, _completionHandler, _timeout)
250 {
251   if (typeof _a != "string" || typeof _b != "string")
252     debug("WARN: shouldBecomeEqual() expects string arguments");
253
254   if (_timeout === undefined)
255     _timeout = 500;
256
257   var _bv;
258   var _condition = function() {
259     var _exception;
260     var _av;
261     try {
262       _av = eval(_a);
263     } catch (e) {
264         _exception = e;
265     }
266     _bv = eval(_b);
267     if (_exception)
268       testFailed(_a + " should become " + _bv + ". Threw exception " + _exception);
269     if (isResultCorrect(_av, _bv)) {
270       testPassed(_a + " became " + _b);
271       return true;
272     }
273     return false;
274   };
275   var _failureTime = Date.now() + _timeout;
276   var _failureHandler = function () {
277     testFailed(_a + " failed to change to " + _bv + " in " + (_timeout / 1000) + " seconds.");
278     _completionHandler();
279   };
280   _waitForCondition(_condition, _failureTime, _completionHandler, _failureHandler);
281 }
282
283 function shouldBecomeEqualToString(value, reference, completionHandler, timeout)
284 {
285   if (typeof value !== "string" || typeof reference !== "string")
286     debug("WARN: shouldBecomeEqualToString() expects string arguments");
287   var unevaledString = JSON.stringify(reference);
288   shouldBecomeEqual(value, unevaledString, completionHandler, timeout);
289 }
290
291 function shouldBeType(_a, _type) {
292   var _exception;
293   var _av;
294   try {
295     _av = eval(_a);
296   } catch (e) {
297     _exception = e;
298   }
299
300   var _typev = eval(_type);
301   if (_av instanceof _typev) {
302     testPassed(_a + " is an instance of " + _type);
303   } else {
304     testFailed(_a + " is not an instance of " + _type);
305   }
306 }
307
308 // Variant of shouldBe()--confirms that result of eval(_to_eval) is within
309 // numeric _tolerance of numeric _target.
310 function shouldBeCloseTo(_to_eval, _target, _tolerance, _quiet)
311 {
312   if (typeof _to_eval != "string") {
313     testFailed("shouldBeCloseTo() requires string argument _to_eval. was type " + typeof _to_eval);
314     return;
315   }
316   if (typeof _target != "number") {
317     testFailed("shouldBeCloseTo() requires numeric argument _target. was type " + typeof _target);
318     return;
319   }
320   if (typeof _tolerance != "number") {
321     testFailed("shouldBeCloseTo() requires numeric argument _tolerance. was type " + typeof _tolerance);
322     return;
323   }
324
325   var _result;
326   try {
327      _result = eval(_to_eval);
328   } catch (e) {
329     testFailed(_to_eval + " should be within " + _tolerance + " of "
330                + _target + ". Threw exception " + e);
331     return;
332   }
333
334   if (typeof(_result) != typeof(_target)) {
335     testFailed(_to_eval + " should be of type " + typeof _target
336                + " but was of type " + typeof _result);
337   } else if (Math.abs(_result - _target) <= _tolerance) {
338     if (!_quiet) {
339         testPassed(_to_eval + " is within " + _tolerance + " of " + _target);
340     }
341   } else {
342     testFailed(_to_eval + " should be within " + _tolerance + " of " + _target
343                + ". Was " + _result + ".");
344   }
345 }
346
347 function shouldNotBe(_a, _b, _quiet)
348 {
349   if (typeof _a != "string" || typeof _b != "string")
350     debug("WARN: shouldNotBe() expects string arguments");
351   var _exception;
352   var _av;
353   try {
354      _av = eval(_a);
355   } catch (e) {
356      _exception = e;
357   }
358   var _bv = eval(_b);
359
360   if (_exception)
361     testFailed(_a + " should not be " + _bv + ". Threw exception " + _exception);
362   else if (!isResultCorrect(_av, _bv)) {
363     if (!_quiet) {
364         testPassed(_a + " is not " + _b);
365     }
366   } else
367     testFailed(_a + " should not be " + _bv + ".");
368 }
369
370 function shouldBecomeDifferent(_a, _b, _completionHandler, _timeout)
371 {
372   if (typeof _a != "string" || typeof _b != "string")
373     debug("WARN: shouldBecomeDifferent() expects string arguments");
374   if (_timeout === undefined)
375     _timeout = 500;
376
377   var _bv;
378   var _condition = function() {
379     var _exception;
380     var _av;
381     try {
382       _av = eval(_a);
383     } catch (e) {
384       _exception = e;
385     }
386     _bv = eval(_b);
387     if (_exception)
388       testFailed(_a + " should became not equal to " + _bv + ". Threw exception " + _exception);
389     if (!isResultCorrect(_av, _bv)) {
390       testPassed(_a + " became different from " + _b);
391       return true;
392     }
393     return false;
394   };
395   var _failureTime = Date.now() + _timeout;
396   var _failureHandler = function () {
397     testFailed(_a + " did not become different from " + _bv + " in " + (_timeout / 1000) + " seconds.");
398     _completionHandler();
399   };
400   _waitForCondition(_condition, _failureTime, _completionHandler, _failureHandler);
401 }
402
403 function shouldBeTrue(a, quiet) { shouldBe(a, "true", quiet); }
404 function shouldBeTrueQuiet(a) { shouldBe(a, "true", true); }
405 function shouldBeFalse(a, quiet) { shouldBe(a, "false", quiet); }
406 function shouldBeNaN(a, quiet) { shouldBe(a, "NaN", quiet); }
407 function shouldBeNull(a, quiet) { shouldBe(a, "null", quiet); }
408 function shouldBeZero(a, quiet) { shouldBe(a, "0", quiet); }
409
410 function shouldBeEqualToString(a, b)
411 {
412   if (typeof a !== "string" || typeof b !== "string")
413     debug("WARN: shouldBeEqualToString() expects string arguments");
414   var unevaledString = JSON.stringify(b);
415   shouldBe(a, unevaledString);
416 }
417
418 function shouldBeEqualToNumber(a, b)
419 {
420   if (typeof a !== "string" || typeof b !== "number")
421     debug("WARN: shouldBeEqualToNumber() expects a string and a number arguments");
422   var unevaledString = JSON.stringify(b);
423   shouldBe(a, unevaledString);
424 }
425
426 function shouldBeEmptyString(a) { shouldBeEqualToString(a, ""); }
427
428 function shouldEvaluateTo(actual, expected, opt_tolerance) {
429   // A general-purpose comparator.  'actual' should be a string to be
430   // evaluated, as for shouldBe(). 'expected' may be any type and will be
431   // used without being eval'ed.
432   if (expected == null) {
433     // Do this before the object test, since null is of type 'object'.
434     shouldBeNull(actual);
435   } else if (typeof expected == "undefined") {
436     shouldBeUndefined(actual);
437   } else if (typeof expected == "function") {
438     // All this fuss is to avoid the string-arg warning from shouldBe().
439     try {
440       var actualValue = eval(actual);
441     } catch (e) {
442       testFailed("Evaluating " + actual + ": Threw exception " + e);
443       return;
444     }
445     shouldBe("'" + actualValue.toString().replace(/\n/g, "") + "'",
446              "'" + expected.toString().replace(/\n/g, "") + "'");
447   } else if (typeof expected == "object") {
448     shouldBeTrue(actual + " == '" + expected + "'");
449   } else if (typeof expected == "string") {
450     shouldBe(actual, expected, undefined, opt_tolerance);
451   } else if (typeof expected == "boolean") {
452     shouldBe("typeof " + actual, "'boolean'");
453     if (expected)
454       shouldBeTrue(actual);
455     else
456       shouldBeFalse(actual);
457   } else if (typeof expected == "number") {
458     if (opt_tolerance)
459         shouldBeCloseTo(actual, expected, opt_tolerance);
460     else
461         shouldBe(actual, stringify(expected));
462   } else {
463     debug(expected + " is unknown type " + typeof expected);
464     shouldBeTrue(actual, "'"  +expected.toString() + "'");
465   }
466 }
467
468 function shouldBeNonZero(_a)
469 {
470   var _exception;
471   var _av;
472   try {
473      _av = eval(_a);
474   } catch (e) {
475      _exception = e;
476   }
477
478   if (_exception)
479     testFailed(_a + " should be non-zero. Threw exception " + _exception);
480   else if (_av != 0)
481     testPassed(_a + " is non-zero.");
482   else
483     testFailed(_a + " should be non-zero. Was " + _av);
484 }
485
486 function shouldBeNonNull(_a)
487 {
488   var _exception;
489   var _av;
490   try {
491      _av = eval(_a);
492   } catch (e) {
493      _exception = e;
494   }
495
496   if (_exception)
497     testFailed(_a + " should be non-null. Threw exception " + _exception);
498   else if (_av != null)
499     testPassed(_a + " is non-null.");
500   else
501     testFailed(_a + " should be non-null. Was " + _av);
502 }
503
504 function shouldBeUndefined(_a)
505 {
506   var _exception;
507   var _av;
508   try {
509      _av = eval(_a);
510   } catch (e) {
511       _exception = e;
512   }
513
514   if (_exception)
515     testFailed(_a + " should be undefined. Threw exception " + _exception);
516   else if (typeof _av == "undefined")
517     testPassed(_a + " is undefined.");
518   else
519     testFailed(_a + " should be undefined. Was " + _av);
520 }
521
522 function shouldBeDefined(_a)
523 {
524   var _exception;
525   var _av;
526   try {
527      _av = eval(_a);
528   } catch (e) {
529      _exception = e;
530   }
531
532   if (_exception)
533     testFailed(_a + " should be defined. Threw exception " + _exception);
534   else if (_av !== undefined)
535     testPassed(_a + " is defined.");
536   else
537     testFailed(_a + " should be defined. Was " + _av);
538 }
539
540 function shouldBeGreaterThan(_a, _b) {
541     if (typeof _a != "string" || typeof _b != "string")
542         debug("WARN: shouldBeGreaterThan expects string arguments");
543
544     var _exception;
545     var _av;
546     try {
547         _av = eval(_a);
548     } catch (e) {
549         _exception = e;
550     }
551     var _bv = eval(_b);
552
553     if (_exception)
554         testFailed(_a + " should be > " + _b + ". Threw exception " + _exception);
555     else if (typeof _av == "undefined" || _av <= _bv)
556         testFailed(_a + " should be > " + _b + ". Was " + _av + " (of type " + typeof _av + ").");
557     else
558         testPassed(_a + " is > " + _b);
559 }
560
561 function shouldBeGreaterThanOrEqual(_a, _b) {
562     if (typeof _a != "string" || typeof _b != "string")
563         debug("WARN: shouldBeGreaterThanOrEqual expects string arguments");
564
565     var _exception;
566     var _av;
567     try {
568         _av = eval(_a);
569     } catch (e) {
570         _exception = e;
571     }
572     var _bv = eval(_b);
573
574     if (_exception)
575         testFailed(_a + " should be >= " + _b + ". Threw exception " + _exception);
576     else if (typeof _av == "undefined" || _av < _bv)
577         testFailed(_a + " should be >= " + _b + ". Was " + _av + " (of type " + typeof _av + ").");
578     else
579         testPassed(_a + " is >= " + _b);
580 }
581
582 function shouldNotThrow(_a) {
583     try {
584         eval(_a);
585         testPassed(_a + " did not throw exception.");
586     } catch (e) {
587         testFailed(_a + " should not throw exception. Threw exception " + e + ".");
588     }
589 }
590
591 function shouldThrow(_a, _e)
592 {
593   var _exception;
594   var _av;
595   try {
596      _av = eval(_a);
597   } catch (e) {
598      _exception = e;
599   }
600
601   var _ev;
602   if (_e)
603       _ev = eval(_e);
604
605   if (_exception) {
606     if (typeof _e == "undefined" || _exception == _ev)
607       testPassed(_a + " threw exception " + _exception + ".");
608     else
609       testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Threw exception " + _exception + ".");
610   } else if (typeof _av == "undefined")
611     testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was undefined.");
612   else
613     testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was " + _av + ".");
614 }
615
616 function shouldBeNow(a, delta)
617 {
618     // Right now, V8 and Chromium / Blink use two different clock
619     // implementations. On Windows, the implementations are non-trivial and can
620     // be slightly out of sync. The delta is intended to compensate for that.
621     //
622     // FIXME: reconsider this when the V8 and Blink clocks get unified, see http://crbug.com/324110
623     if (delta === undefined)
624         delta = 1000;
625
626     for (var i = 0; i < 1000; ++i) {
627         var startDate = Date.now();
628         var av = eval(a);
629         var date = av.valueOf();
630         var endDate = Date.now();
631
632         // On some occasions such as NTP updates, the current time can go
633         // backwards. This should only happen rarely, so we can get away with
634         // retrying the test a few times if we detect the time going backwards.
635         if (startDate > endDate)
636             continue;
637
638         if (typeof date !== "number") {
639             testFailed(a + " is not a number or a Date. Got " + av);
640             return;
641         }
642         if (date < startDate - delta) {
643             testFailed(a + " is not the curent time. Got " + av + " which is " + (startDate - date) / 1000 + " seconds in the past.");
644             return;
645         }
646         if (date > endDate + delta) {
647             testFailed(a + " is not the current time. Got " + av + " which is " + (date - endDate) / 1000 + " seconds in the future.");
648             return;
649         }
650
651         testPassed(a + " is equivalent to Date.now().");
652         return;
653     }
654     testFailed(a + " cannot be tested against the current time. The clock is going backwards too often.");
655 }
656
657 function expectError()
658 {
659     if (expectingError) {
660         testFailed("shouldHaveError() called twice before an error occurred!");
661     }
662     expectingError = true;
663 }
664
665 function shouldHaveHadError(message)
666 {
667     if (expectingError) {
668         testFailed("No error thrown between expectError() and shouldHaveHadError()");
669         return;
670     }
671
672     if (expectedErrorMessage) {
673         if (!message)
674             testPassed("Got expected error");
675         else if (expectedErrorMessage.indexOf(message) !== -1)
676             testPassed("Got expected error: '" + message + "'");
677         else
678             testFailed("Unexpected error '" + message + "'");
679         expectedErrorMessage = undefined;
680         return;
681     }
682
683     testFailed("expectError() not called before shouldHaveHadError()");
684 }
685
686 // With Oilpan tests that rely on garbage collection need to go through
687 // the event loop in order to get precise garbage collections. Oilpan
688 // uses conservative stack scanning when not at the event loop and that
689 // can artificially keep objects alive. Therefore, tests that need to check
690 // that something is dead need to use this asynchronous collectGarbage
691 // function.
692 function asyncGC(callback) {
693     GCController.collectAll();
694     setTimeout(callback, 0);
695 }
696
697 function gc() {
698     if (typeof GCController !== "undefined")
699         GCController.collectAll();
700     else {
701         var gcRec = function (n) {
702             if (n < 1)
703                 return {};
704             var temp = {i: "ab" + i + (i / 100000)};
705             temp += "foo";
706             gcRec(n-1);
707         };
708         for (var i = 0; i < 1000; i++)
709             gcRec(10);
710     }
711 }
712
713 function asyncMinorGC(callback) {
714     if (typeof GCController !== "undefined")
715         GCController.minorCollect();
716     else
717         testFailed("Minor GC is available only when you enable the --expose-gc option in V8.");
718     setTimeout(callback, 0);
719 }
720
721 function isSuccessfullyParsed()
722 {
723     // FIXME: Remove this and only report unexpected syntax errors.
724     successfullyParsed = !unexpectedErrorMessage;
725     shouldBeTrue("successfullyParsed");
726     debug('<br /><span class="pass">TEST COMPLETE</span>');
727 }
728
729 var wasPostTestScriptParsed, wasFinishJSTestCalled, jsTestIsAsync;
730
731 // It's possible for an async test to call finishJSTest() before js-test-post.js
732 // has been parsed.
733 function finishJSTest()
734 {
735     wasFinishJSTestCalled = true;
736     if (!self.wasPostTestScriptParsed)
737         return;
738     isSuccessfullyParsed();
739     if (self.jsTestIsAsync && self.testRunner)
740         testRunner.notifyDone();
741 }
742
743 function startWorker(testScriptURL, shared)
744 {
745     self.jsTestIsAsync = true;
746     debug('Starting worker: ' + testScriptURL);
747     var worker = shared ? new SharedWorker(testScriptURL, "Shared Worker") : new Worker(testScriptURL);
748     worker.onmessage = function(event)
749     {
750         var workerPrefix = "[Worker] ";
751         if (event.data.length < 5 || event.data.charAt(4) != ':') {
752           debug(workerPrefix + event.data);
753           return;
754         }
755         var code = event.data.substring(0, 4);
756         var payload = workerPrefix + event.data.substring(5);
757         if (code == "PASS")
758             testPassed(payload);
759         else if (code == "FAIL")
760             testFailed(payload);
761         else if (code == "DESC")
762             description(payload);
763         else if (code == "DONE")
764             finishJSTest();
765         else
766             debug(workerPrefix + event.data);
767     };
768
769     worker.onerror = function(event)
770     {
771         debug('Got error from worker: ' + event.message);
772         finishJSTest();
773     };
774
775     if (shared) {
776         worker.port.onmessage = function(event) { worker.onmessage(event); };
777         worker.port.start();
778     }
779     return worker;
780 }
781
782 if (isWorker()) {
783     var workerPort = self;
784     if (self.name == "Shared Worker") {
785         self.onconnect = function(e) {
786             workerPort = e.ports[0];
787             workerPort.onmessage = function(event)
788             {
789                 var colon = event.data.indexOf(":");
790                 if (colon == -1) {
791                     testFailed("Unrecognized message to shared worker: " + event.data);
792                     return;
793                 }
794                 var code = event.data.substring(0, colon);
795                 var payload = event.data.substring(colon + 1);
796                 try {
797                     if (code == "IMPORT")
798                         importScripts(payload);
799                     else
800                         testFailed("Unrecognized message to shared worker: " + event.data);
801                 } catch (ex) {
802                     testFailed("Caught exception in shared worker onmessage: " + ex);
803                 }
804             };
805         };
806     }
807     description = function(msg, quiet) {
808         workerPort.postMessage('DESC:' + msg);
809     };
810     testFailed = function(msg) {
811         workerPort.postMessage('FAIL:' + msg);
812     };
813     testPassed = function(msg) {
814         workerPort.postMessage('PASS:' + msg);
815     };
816     finishJSTest = function() {
817         workerPort.postMessage('DONE:');
818     };
819     debug = function(msg) {
820         workerPort.postMessage(msg);
821     };
822 }