[css-grid] Scroll reset position when updating inner html on content
[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: 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 }