blob: 1df1b8b49e4fbfbc7984e5eaab195b18631749f8 [file] [log] [blame]
beidson@apple.comf321a852014-02-12 18:17:47 +00001if (self.testRunner) {
beidson@apple.com422df6a2016-01-19 06:02:30 +00002 // svg/dynamic-updates tests set enablePixelTesting=true, as we want to dump text + pixel results
beidson@apple.comf321a852014-02-12 18:17:47 +00003 if (self.enablePixelTesting)
4 testRunner.dumpAsTextWithPixelResults();
5 else
6 testRunner.dumpAsText();
beidson@apple.com422df6a2016-01-19 06:02:30 +00007
8 // If the test file URL ends in "-private.html", enable private browsing.
beidson@apple.com0faeb9f2016-02-04 19:46:47 +00009 if (window.location.href.endsWith("-private.html") || self.enablePrivateBrowsing)
beidson@apple.com422df6a2016-01-19 06:02:30 +000010 testRunner.setPrivateBrowsingEnabled(true);
beidson@apple.comf321a852014-02-12 18:17:47 +000011}
12
ddkilzer@apple.come44e4222016-06-29 04:17:36 +000013var description, debug, didFailSomeTests, successfullyParsed;
14
15didFailSomeTests = false;
beidson@apple.comf321a852014-02-12 18:17:47 +000016
17var expectingError; // set by shouldHaveError()
18var expectedErrorMessage; // set by onerror when expectingError is true
19var unexpectedErrorMessage; // set by onerror when expectingError is not true
20
21(function() {
22
dbates@webkit.org094dc6e2014-04-02 21:40:26 +000023 function createHTMLElement(tagName)
24 {
25 // FIXME: In an XML document, document.createElement() creates an element with a null namespace URI.
26 // So, we need use document.createElementNS() to explicitly create an element with the specified
27 // tag name in the HTML namespace. We can remove this function and use document.createElement()
28 // directly once we fix <https://bugs.webkit.org/show_bug.cgi?id=131074>.
29 if (document.createElementNS)
30 return document.createElementNS("http://www.w3.org/1999/xhtml", tagName);
31 return document.createElement(tagName);
32 }
33
beidson@apple.comf321a852014-02-12 18:17:47 +000034 function getOrCreate(id, tagName)
35 {
36 var element = document.getElementById(id);
37 if (element)
38 return element;
39
dbates@webkit.org094dc6e2014-04-02 21:40:26 +000040 element = createHTMLElement(tagName);
beidson@apple.comf321a852014-02-12 18:17:47 +000041 element.id = id;
42 var refNode;
43 var parent = document.body || document.documentElement;
44 if (id == "description")
45 refNode = getOrCreate("console", "div");
46 else
47 refNode = parent.firstChild;
48
49 parent.insertBefore(element, refNode);
50 return element;
51 }
52
53 description = function description(msg, quiet)
54 {
55 // For MSIE 6 compatibility
dbates@webkit.org094dc6e2014-04-02 21:40:26 +000056 var span = createHTMLElement("span");
beidson@apple.comf321a852014-02-12 18:17:47 +000057 if (quiet)
58 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>';
59 else
60 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>';
61
62 var description = getOrCreate("description", "p");
63 if (description.firstChild)
64 description.replaceChild(span, description.firstChild);
65 else
66 description.appendChild(span);
67 };
68
69 debug = function debug(msg)
70 {
dbates@webkit.org094dc6e2014-04-02 21:40:26 +000071 var span = createHTMLElement("span");
beidson@apple.comf321a852014-02-12 18:17:47 +000072 getOrCreate("console", "div").appendChild(span); // insert it first so XHTML knows the namespace
73 span.innerHTML = msg + '<br />';
74 };
75
76 var css =
77 ".pass {" +
78 "font-weight: bold;" +
79 "color: green;" +
80 "}" +
81 ".fail {" +
82 "font-weight: bold;" +
83 "color: red;" +
84 "}" +
85 "#console {" +
86 "white-space: pre-wrap;" +
87 "font-family: monospace;" +
88 "}";
89
90 function insertStyleSheet()
91 {
dbates@webkit.org094dc6e2014-04-02 21:40:26 +000092 var styleElement = createHTMLElement("style");
beidson@apple.comf321a852014-02-12 18:17:47 +000093 styleElement.textContent = css;
94 (document.head || document.documentElement).appendChild(styleElement);
95 }
96
97 function handleTestFinished()
98 {
99 // FIXME: Get rid of this boolean.
100 wasPostTestScriptParsed = true;
101 if (window.jsTestIsAsync) {
102 if (window.testRunner)
103 testRunner.waitUntilDone();
104 if (window.wasFinishJSTestCalled)
105 finishJSTest();
106 } else
107 finishJSTest();
108 }
109
110 if (!isWorker()) {
ap@apple.comfab549e2014-12-27 23:22:02 +0000111 window.addEventListener('DOMContentLoaded', function() {
112 // Some tests set jsTestIsAsync in load event handler. Adding the listener late
113 // makes handleTestFinished() run after the test handles load events.
114 window.addEventListener("load", handleTestFinished, false);
115 }, false);
beidson@apple.comf321a852014-02-12 18:17:47 +0000116 insertStyleSheet();
117 }
118
119 if (!self.isOnErrorTest) {
120 self.onerror = function(message)
121 {
122 if (self.expectingError) {
123 self.expectedErrorMessage = message;
124 self.expectingError = false;
125 return;
126 }
127 self.unexpectedErrorMessage = message;
128 if (self.jsTestIsAsync) {
129 self.testFailed("Unexpected error: " + message);
130 finishJSTest();
131 }
132 };
133 }
134})();
135
136function isWorker()
137{
138 // It's conceivable that someone would stub out 'document' in a worker so
139 // also check for childNodes, an arbitrary DOM-related object that is
140 // meaningless in a WorkerContext.
141 return (typeof document === 'undefined' || typeof document.childNodes === 'undefined') && !!self.importScripts;
142}
143
144function descriptionQuiet(msg) { description(msg, true); }
145
146function escapeHTML(text)
147{
148 return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/\0/g, "\\0");
149}
150
151function testPassed(msg)
152{
153 debug('<span><span class="pass">PASS</span> ' + escapeHTML(msg) + '</span>');
154}
155
156function testFailed(msg)
157{
ddkilzer@apple.come44e4222016-06-29 04:17:36 +0000158 didFailSomeTests = true;
beidson@apple.comf321a852014-02-12 18:17:47 +0000159 debug('<span><span class="fail">FAIL</span> ' + escapeHTML(msg) + '</span>');
160}
161
162function areArraysEqual(a, b)
163{
164 try {
165 if (a.length !== b.length)
166 return false;
167 for (var i = 0; i < a.length; i++)
168 if (a[i] !== b[i])
169 return false;
170 } catch (ex) {
171 return false;
172 }
173 return true;
174}
175
176function isMinusZero(n)
177{
178 // the only way to tell 0 from -0 in JS is the fact that 1/-0 is
179 // -Infinity instead of Infinity
180 return n === 0 && 1/n < 0;
181}
182
183function isNewSVGTearOffType(v)
184{
185 return ['[object SVGLength]', '[object SVGLengthList]', '[object SVGPoint]', '[object SVGPointList]', '[object SVGNumber]'].indexOf(""+v) != -1;
186}
187
188function isResultCorrect(actual, expected)
189{
190 if (expected === 0)
191 return actual === expected && (1/actual) === (1/expected);
192 if (actual === expected)
193 return true;
194 // 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.
195 if (isNewSVGTearOffType(expected) && typeof(expected) == typeof(actual) && actual.valueAsString == expected.valueAsString)
196 return true;
197 if (typeof(expected) == "number" && isNaN(expected))
198 return typeof(actual) == "number" && isNaN(actual);
199 if (expected && (Object.prototype.toString.call(expected) == Object.prototype.toString.call([])))
200 return areArraysEqual(actual, expected);
201 return false;
202}
203
204function stringify(v)
205{
206 if (isNewSVGTearOffType(v))
207 return v.valueAsString;
208 if (v === 0 && 1/v < 0)
209 return "-0";
210 else return "" + v;
211}
212
213function evalAndLog(_a, _quiet)
214{
215 if (typeof _a != "string")
216 debug("WARN: tryAndLog() expects a string argument");
217
218 // Log first in case things go horribly wrong or this causes a sync event.
219 if (!_quiet)
220 debug(_a);
221
222 var _av;
223 try {
224 _av = eval(_a);
225 } catch (e) {
226 testFailed(_a + " threw exception " + e);
227 }
228 return _av;
229}
230
ddkilzer@apple.com15acfc2c62017-05-02 20:10:12 +0000231function shouldBe(_a, _b, _quiet)
beidson@apple.comf321a852014-02-12 18:17:47 +0000232{
ddkilzer@apple.com15acfc2c62017-05-02 20:10:12 +0000233 if ((typeof _a != "function" && typeof _a != "string") || (typeof _b != "function" && typeof _b != "string"))
234 debug("WARN: shouldBe() expects function or string arguments");
235 var _exception;
236 var _av;
237 try {
238 _av = (typeof _a == "function" ? _a() : eval(_a));
239 } catch (e) {
240 _exception = e;
beidson@apple.comf321a852014-02-12 18:17:47 +0000241 }
ddkilzer@apple.com15acfc2c62017-05-02 20:10:12 +0000242 var _bv = (typeof _b == "function" ? _b() : eval(_b));
243
244 if (_exception)
245 testFailed(_a + " should be " + stringify(_bv) + ". Threw exception " + _exception);
246 else if (isResultCorrect(_av, _bv)) {
247 if (!_quiet) {
248 testPassed(_a + " is " + (typeof _b == "function" ? _bv : _b));
249 }
250 } else if (typeof(_av) == typeof(_bv))
251 testFailed(_a + " should be " + stringify(_bv) + ". Was " + stringify(_av) + ".");
252 else
253 testFailed(_a + " should be " + stringify(_bv) + " (of type " + typeof _bv + "). Was " + _av + " (of type " + typeof _av + ").");
beidson@apple.comf321a852014-02-12 18:17:47 +0000254}
255
g.czajkowski@samsung.com8deb0ce2014-12-18 17:44:18 +0000256// Execute condition every 5 milliseconds until it succeeds.
257function _waitForCondition(condition, completionHandler)
beidson@apple.comf321a852014-02-12 18:17:47 +0000258{
g.czajkowski@samsung.com8deb0ce2014-12-18 17:44:18 +0000259 if (condition())
beidson@apple.comf321a852014-02-12 18:17:47 +0000260 completionHandler();
g.czajkowski@samsung.com8deb0ce2014-12-18 17:44:18 +0000261 else
262 setTimeout(_waitForCondition, 5, condition, completionHandler);
beidson@apple.comf321a852014-02-12 18:17:47 +0000263}
264
g.czajkowski@samsung.com8deb0ce2014-12-18 17:44:18 +0000265function shouldBecomeEqual(_a, _b, completionHandler)
beidson@apple.comf321a852014-02-12 18:17:47 +0000266{
267 if (typeof _a != "string" || typeof _b != "string")
268 debug("WARN: shouldBecomeEqual() expects string arguments");
269
g.czajkowski@samsung.com701b7212014-12-23 08:26:49 +0000270 function condition() {
g.czajkowski@samsung.com8deb0ce2014-12-18 17:44:18 +0000271 var exception;
beidson@apple.comf321a852014-02-12 18:17:47 +0000272 var _av;
273 try {
274 _av = eval(_a);
275 } catch (e) {
g.czajkowski@samsung.com8deb0ce2014-12-18 17:44:18 +0000276 exception = e;
beidson@apple.comf321a852014-02-12 18:17:47 +0000277 }
g.czajkowski@samsung.com8deb0ce2014-12-18 17:44:18 +0000278 var _bv = eval(_b);
279 if (exception)
280 testFailed(_a + " should become " + _bv + ". Threw exception " + exception);
beidson@apple.comf321a852014-02-12 18:17:47 +0000281 if (isResultCorrect(_av, _bv)) {
282 testPassed(_a + " became " + _b);
283 return true;
284 }
285 return false;
g.czajkowski@samsung.com701b7212014-12-23 08:26:49 +0000286 }
287 setTimeout(_waitForCondition, 0, condition, completionHandler);
beidson@apple.comf321a852014-02-12 18:17:47 +0000288}
289
g.czajkowski@samsung.com8deb0ce2014-12-18 17:44:18 +0000290function shouldBecomeEqualToString(value, reference, completionHandler)
beidson@apple.comf321a852014-02-12 18:17:47 +0000291{
292 if (typeof value !== "string" || typeof reference !== "string")
293 debug("WARN: shouldBecomeEqualToString() expects string arguments");
294 var unevaledString = JSON.stringify(reference);
g.czajkowski@samsung.com8deb0ce2014-12-18 17:44:18 +0000295 shouldBecomeEqual(value, unevaledString, completionHandler);
beidson@apple.comf321a852014-02-12 18:17:47 +0000296}
297
298function shouldBeType(_a, _type) {
299 var _exception;
300 var _av;
301 try {
302 _av = eval(_a);
303 } catch (e) {
304 _exception = e;
305 }
306
307 var _typev = eval(_type);
308 if (_av instanceof _typev) {
309 testPassed(_a + " is an instance of " + _type);
310 } else {
311 testFailed(_a + " is not an instance of " + _type);
312 }
313}
314
315// Variant of shouldBe()--confirms that result of eval(_to_eval) is within
316// numeric _tolerance of numeric _target.
317function shouldBeCloseTo(_to_eval, _target, _tolerance, _quiet)
318{
319 if (typeof _to_eval != "string") {
320 testFailed("shouldBeCloseTo() requires string argument _to_eval. was type " + typeof _to_eval);
321 return;
322 }
323 if (typeof _target != "number") {
324 testFailed("shouldBeCloseTo() requires numeric argument _target. was type " + typeof _target);
325 return;
326 }
327 if (typeof _tolerance != "number") {
328 testFailed("shouldBeCloseTo() requires numeric argument _tolerance. was type " + typeof _tolerance);
329 return;
330 }
331
332 var _result;
333 try {
334 _result = eval(_to_eval);
335 } catch (e) {
336 testFailed(_to_eval + " should be within " + _tolerance + " of "
337 + _target + ". Threw exception " + e);
338 return;
339 }
340
341 if (typeof(_result) != typeof(_target)) {
342 testFailed(_to_eval + " should be of type " + typeof _target
343 + " but was of type " + typeof _result);
344 } else if (Math.abs(_result - _target) <= _tolerance) {
345 if (!_quiet) {
346 testPassed(_to_eval + " is within " + _tolerance + " of " + _target);
347 }
348 } else {
349 testFailed(_to_eval + " should be within " + _tolerance + " of " + _target
350 + ". Was " + _result + ".");
351 }
352}
353
354function shouldNotBe(_a, _b, _quiet)
355{
ddkilzer@apple.com15acfc2c62017-05-02 20:10:12 +0000356 if ((typeof _a != "function" && typeof _a != "string") || (typeof _b != "function" && typeof _b != "string"))
357 debug("WARN: shouldNotBe() expects function or string arguments");
358 var _exception;
359 var _av;
360 try {
361 _av = (typeof _a == "function" ? _a() : eval(_a));
362 } catch (e) {
363 _exception = e;
beidson@apple.comf321a852014-02-12 18:17:47 +0000364 }
ddkilzer@apple.com15acfc2c62017-05-02 20:10:12 +0000365 var _bv = (typeof _b == "function" ? _b() : eval(_b));
366
367 if (_exception)
368 testFailed(_a + " should not be " + _bv + ". Threw exception " + _exception);
369 else if (!isResultCorrect(_av, _bv)) {
370 if (!_quiet) {
371 testPassed(_a + " is not " + (typeof _b == "function" ? _bv : _b));
372 }
373 } else
374 testFailed(_a + " should not be " + _bv + ".");
beidson@apple.comf321a852014-02-12 18:17:47 +0000375}
376
g.czajkowski@samsung.com8deb0ce2014-12-18 17:44:18 +0000377function shouldBecomeDifferent(_a, _b, completionHandler)
beidson@apple.comf321a852014-02-12 18:17:47 +0000378{
379 if (typeof _a != "string" || typeof _b != "string")
380 debug("WARN: shouldBecomeDifferent() expects string arguments");
beidson@apple.comf321a852014-02-12 18:17:47 +0000381
g.czajkowski@samsung.com701b7212014-12-23 08:26:49 +0000382 function condition() {
g.czajkowski@samsung.com8deb0ce2014-12-18 17:44:18 +0000383 var exception;
beidson@apple.comf321a852014-02-12 18:17:47 +0000384 var _av;
385 try {
386 _av = eval(_a);
387 } catch (e) {
g.czajkowski@samsung.com8deb0ce2014-12-18 17:44:18 +0000388 exception = e;
beidson@apple.comf321a852014-02-12 18:17:47 +0000389 }
g.czajkowski@samsung.com8deb0ce2014-12-18 17:44:18 +0000390 var _bv = eval(_b);
391 if (exception)
392 testFailed(_a + " should became not equal to " + _bv + ". Threw exception " + exception);
beidson@apple.comf321a852014-02-12 18:17:47 +0000393 if (!isResultCorrect(_av, _bv)) {
394 testPassed(_a + " became different from " + _b);
395 return true;
396 }
397 return false;
g.czajkowski@samsung.com701b7212014-12-23 08:26:49 +0000398 }
399 setTimeout(_waitForCondition, 0, condition, completionHandler);
beidson@apple.comf321a852014-02-12 18:17:47 +0000400}
401
402function shouldBeTrue(a, quiet) { shouldBe(a, "true", quiet); }
403function shouldBeTrueQuiet(a) { shouldBe(a, "true", true); }
404function shouldBeFalse(a, quiet) { shouldBe(a, "false", quiet); }
405function shouldBeNaN(a, quiet) { shouldBe(a, "NaN", quiet); }
406function shouldBeNull(a, quiet) { shouldBe(a, "null", quiet); }
407function shouldBeZero(a, quiet) { shouldBe(a, "0", quiet); }
408
409function shouldBeEqualToString(a, b)
410{
411 if (typeof a !== "string" || typeof b !== "string")
412 debug("WARN: shouldBeEqualToString() expects string arguments");
413 var unevaledString = JSON.stringify(b);
414 shouldBe(a, unevaledString);
415}
416
commit-queue@webkit.org2f837982014-12-16 18:42:43 +0000417function shouldBeEqualToNumber(a, b)
418{
419 if (typeof a !== "string" || typeof b !== "number")
420 debug("WARN: shouldBeEqualToNumber() expects a string and a number arguments");
421 var unevaledString = JSON.stringify(b);
422 shouldBe(a, unevaledString);
423}
424
beidson@apple.comf321a852014-02-12 18:17:47 +0000425function shouldBeEmptyString(a) { shouldBeEqualToString(a, ""); }
426
427function shouldEvaluateTo(actual, expected) {
428 // A general-purpose comparator. 'actual' should be a string to be
429 // evaluated, as for shouldBe(). 'expected' may be any type and will be
430 // used without being eval'ed.
431 if (expected == null) {
432 // Do this before the object test, since null is of type 'object'.
433 shouldBeNull(actual);
434 } else if (typeof expected == "undefined") {
435 shouldBeUndefined(actual);
436 } else if (typeof expected == "function") {
437 // All this fuss is to avoid the string-arg warning from shouldBe().
438 try {
439 var actualValue = eval(actual);
440 } catch (e) {
441 testFailed("Evaluating " + actual + ": Threw exception " + e);
442 return;
443 }
444 shouldBe("'" + actualValue.toString().replace(/\n/g, "") + "'",
445 "'" + expected.toString().replace(/\n/g, "") + "'");
446 } else if (typeof expected == "object") {
447 shouldBeTrue(actual + " == '" + expected + "'");
448 } else if (typeof expected == "string") {
449 shouldBe(actual, expected);
450 } else if (typeof expected == "boolean") {
451 shouldBe("typeof " + actual, "'boolean'");
452 if (expected)
453 shouldBeTrue(actual);
454 else
455 shouldBeFalse(actual);
456 } else if (typeof expected == "number") {
457 shouldBe(actual, stringify(expected));
458 } else {
459 debug(expected + " is unknown type " + typeof expected);
460 shouldBeTrue(actual, "'" +expected.toString() + "'");
461 }
462}
463
464function shouldBeNonZero(_a)
465{
466 var _exception;
467 var _av;
468 try {
469 _av = eval(_a);
470 } catch (e) {
471 _exception = e;
472 }
473
474 if (_exception)
475 testFailed(_a + " should be non-zero. Threw exception " + _exception);
476 else if (_av != 0)
477 testPassed(_a + " is non-zero.");
478 else
479 testFailed(_a + " should be non-zero. Was " + _av);
480}
481
482function shouldBeNonNull(_a)
483{
484 var _exception;
485 var _av;
486 try {
487 _av = eval(_a);
488 } catch (e) {
489 _exception = e;
490 }
491
492 if (_exception)
493 testFailed(_a + " should be non-null. Threw exception " + _exception);
494 else if (_av != null)
495 testPassed(_a + " is non-null.");
496 else
497 testFailed(_a + " should be non-null. Was " + _av);
498}
499
500function shouldBeUndefined(_a)
501{
502 var _exception;
503 var _av;
504 try {
505 _av = eval(_a);
506 } catch (e) {
507 _exception = e;
508 }
509
510 if (_exception)
511 testFailed(_a + " should be undefined. Threw exception " + _exception);
512 else if (typeof _av == "undefined")
513 testPassed(_a + " is undefined.");
514 else
515 testFailed(_a + " should be undefined. Was " + _av);
516}
517
518function shouldBeDefined(_a)
519{
520 var _exception;
521 var _av;
522 try {
523 _av = eval(_a);
524 } catch (e) {
525 _exception = e;
526 }
527
528 if (_exception)
529 testFailed(_a + " should be defined. Threw exception " + _exception);
530 else if (_av !== undefined)
531 testPassed(_a + " is defined.");
532 else
533 testFailed(_a + " should be defined. Was " + _av);
534}
535
536function shouldBeGreaterThanOrEqual(_a, _b) {
537 if (typeof _a != "string" || typeof _b != "string")
538 debug("WARN: shouldBeGreaterThanOrEqual expects string arguments");
539
540 var _exception;
541 var _av;
542 try {
543 _av = eval(_a);
544 } catch (e) {
545 _exception = e;
546 }
547 var _bv = eval(_b);
548
549 if (_exception)
550 testFailed(_a + " should be >= " + _b + ". Threw exception " + _exception);
551 else if (typeof _av == "undefined" || _av < _bv)
552 testFailed(_a + " should be >= " + _b + ". Was " + _av + " (of type " + typeof _av + ").");
553 else
554 testPassed(_a + " is >= " + _b);
555}
556
ap@apple.comfab549e2014-12-27 23:22:02 +0000557function expectTrue(v, msg) {
558 if (v) {
559 testPassed(msg);
560 } else {
561 testFailed(msg);
562 }
563}
564
ddkilzer@apple.come44e4222016-06-29 04:17:36 +0000565function shouldNotThrow(_a, _message) {
beidson@apple.comf321a852014-02-12 18:17:47 +0000566 try {
ddkilzer@apple.com15acfc2c62017-05-02 20:10:12 +0000567 typeof _a == "function" ? _a() : eval(_a);
ddkilzer@apple.come44e4222016-06-29 04:17:36 +0000568 testPassed((_message ? _message : _a) + " did not throw exception.");
beidson@apple.comf321a852014-02-12 18:17:47 +0000569 } catch (e) {
ddkilzer@apple.come44e4222016-06-29 04:17:36 +0000570 testFailed((_message ? _message : _a) + " should not throw exception. Threw exception " + e + ".");
beidson@apple.comf321a852014-02-12 18:17:47 +0000571 }
572}
573
ddkilzer@apple.come44e4222016-06-29 04:17:36 +0000574function shouldThrow(_a, _e, _message)
beidson@apple.comf321a852014-02-12 18:17:47 +0000575{
ddkilzer@apple.come44e4222016-06-29 04:17:36 +0000576 var _exception;
577 var _av;
578 try {
579 _av = typeof _a == "function" ? _a() : eval(_a);
580 } catch (e) {
581 _exception = e;
582 }
beidson@apple.comf321a852014-02-12 18:17:47 +0000583
ddkilzer@apple.come44e4222016-06-29 04:17:36 +0000584 var _ev;
585 if (_e)
586 _ev = eval(_e);
beidson@apple.comf321a852014-02-12 18:17:47 +0000587
ddkilzer@apple.come44e4222016-06-29 04:17:36 +0000588 if (_exception) {
589 if (typeof _e == "undefined" || _exception == _ev)
590 testPassed((_message ? _message : _a) + " threw exception " + _exception + ".");
591 else
592 testFailed((_message ? _message : _a) + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Threw exception " + _exception + ".");
593 } else if (typeof _av == "undefined")
594 testFailed((_message ? _message : _a) + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was undefined.");
beidson@apple.comf321a852014-02-12 18:17:47 +0000595 else
ddkilzer@apple.come44e4222016-06-29 04:17:36 +0000596 testFailed((_message ? _message : _a) + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was " + _av + ".");
beidson@apple.comf321a852014-02-12 18:17:47 +0000597}
598
599function shouldBeNow(a, delta)
600{
601 // Right now, V8 and Chromium / Blink use two different clock
602 // implementations. On Windows, the implementations are non-trivial and can
603 // be slightly out of sync. The delta is intended to compensate for that.
604 //
605 // FIXME: reconsider this when the V8 and Blink clocks get unified, see http://crbug.com/324110
606 if (delta === undefined)
607 delta = 1000;
608
609 for (var i = 0; i < 1000; ++i) {
610 var startDate = Date.now();
611 var av = eval(a);
612 var date = av.valueOf();
613 var endDate = Date.now();
614
615 // On some occasions such as NTP updates, the current time can go
616 // backwards. This should only happen rarely, so we can get away with
617 // retrying the test a few times if we detect the time going backwards.
618 if (startDate > endDate)
619 continue;
620
621 if (typeof date !== "number") {
622 testFailed(a + " is not a number or a Date. Got " + av);
623 return;
624 }
625 if (date < startDate - delta) {
626 testFailed(a + " is not the curent time. Got " + av + " which is " + (startDate - date) / 1000 + " seconds in the past.");
627 return;
628 }
629 if (date > endDate + delta) {
630 testFailed(a + " is not the current time. Got " + av + " which is " + (date - endDate) / 1000 + " seconds in the future.");
631 return;
632 }
633
634 testPassed(a + " is equivalent to Date.now().");
635 return;
636 }
637 testFailed(a + " cannot be tested against the current time. The clock is going backwards too often.");
638}
639
640function expectError()
641{
642 if (expectingError) {
643 testFailed("shouldHaveError() called twice before an error occurred!");
644 }
645 expectingError = true;
646}
647
648function shouldHaveHadError(message)
649{
650 if (expectingError) {
651 testFailed("No error thrown between expectError() and shouldHaveHadError()");
652 return;
653 }
654
655 if (expectedErrorMessage) {
656 if (!message)
657 testPassed("Got expected error");
658 else if (expectedErrorMessage.indexOf(message) !== -1)
659 testPassed("Got expected error: '" + message + "'");
660 else
661 testFailed("Unexpected error '" + message + "'");
662 expectedErrorMessage = undefined;
663 return;
664 }
665
666 testFailed("expectError() not called before shouldHaveHadError()");
667}
668
669function gc() {
670 if (typeof GCController !== "undefined")
671 GCController.collect();
672 else {
673 var gcRec = function (n) {
674 if (n < 1)
675 return {};
676 var temp = {i: "ab" + i + (i / 100000)};
677 temp += "foo";
678 gcRec(n-1);
679 };
680 for (var i = 0; i < 1000; i++)
681 gcRec(10);
682 }
683}
684
685function minorGC() {
686 if (typeof GCController !== "undefined")
687 GCController.minorCollect();
688 else
689 testFailed("Minor GC is available only when you enable the --expose-gc option in V8.");
690}
691
692function isSuccessfullyParsed()
693{
694 // FIXME: Remove this and only report unexpected syntax errors.
695 successfullyParsed = !unexpectedErrorMessage;
696 shouldBeTrue("successfullyParsed");
ddkilzer@apple.come44e4222016-06-29 04:17:36 +0000697 if (didFailSomeTests)
698 debug("Some tests failed.");
beidson@apple.comf321a852014-02-12 18:17:47 +0000699 debug('<br /><span class="pass">TEST COMPLETE</span>');
700}
701
702// It's possible for an async test to call finishJSTest() before js-test-post.js
703// has been parsed.
704function finishJSTest()
705{
706 wasFinishJSTestCalled = true;
707 if (!self.wasPostTestScriptParsed)
708 return;
709 isSuccessfullyParsed();
710 if (self.jsTestIsAsync && self.testRunner)
711 testRunner.notifyDone();
712}
713
beidson@apple.com0f23ce42016-11-01 23:51:54 +0000714function areObjectsEqual(a, b) {
715 for (var property in a) {
716 if (!b.hasOwnProperty(property))
717 return false;
718
719 switch (typeof (a[property])) {
720 case 'function':
721 if (typeof b[property] == 'undefined' || a[property].toString() != b[property].toString())
722 return false;
723 break;
724 case 'object':
725 if (!areObjectsEqual(a, b))
726 return false;
727 break;
728 default:
729 if (a[property] != b[property])
730 return false;
731 }
732 }
733
734 for (var property in b) {
735 if (!a.hasOwnProperty(property))
736 return false;
737 }
738
739 return true;
740};
741
weinig@apple.comf4eb1bb2015-01-13 00:40:49 +0000742function startWorker(testScriptURL)
beidson@apple.comf321a852014-02-12 18:17:47 +0000743{
744 self.jsTestIsAsync = true;
745 debug('Starting worker: ' + testScriptURL);
weinig@apple.comf4eb1bb2015-01-13 00:40:49 +0000746 var worker = new Worker(testScriptURL);
beidson@apple.comf321a852014-02-12 18:17:47 +0000747 worker.onmessage = function(event)
748 {
749 var workerPrefix = "[Worker] ";
750 if (event.data.length < 5 || event.data.charAt(4) != ':') {
751 debug(workerPrefix + event.data);
752 return;
753 }
754 var code = event.data.substring(0, 4);
755 var payload = workerPrefix + event.data.substring(5);
756 if (code == "PASS")
757 testPassed(payload);
758 else if (code == "FAIL")
759 testFailed(payload);
760 else if (code == "DESC")
761 description(payload);
762 else if (code == "DONE")
763 finishJSTest();
764 else
765 debug(workerPrefix + event.data);
766 };
767
768 worker.onerror = function(event)
769 {
770 debug('Got error from worker: ' + event.message);
771 finishJSTest();
772 };
773
beidson@apple.comf321a852014-02-12 18:17:47 +0000774 return worker;
775}
776
777if (isWorker()) {
778 var workerPort = self;
beidson@apple.comf321a852014-02-12 18:17:47 +0000779 description = function(msg, quiet) {
780 workerPort.postMessage('DESC:' + msg);
781 };
782 testFailed = function(msg) {
783 workerPort.postMessage('FAIL:' + msg);
784 };
785 testPassed = function(msg) {
786 workerPort.postMessage('PASS:' + msg);
787 };
788 finishJSTest = function() {
789 workerPort.postMessage('DONE:');
790 };
791 debug = function(msg) {
792 workerPort.postMessage(msg);
793 };
794}