| var errorMessage; |
| var self = this; |
| |
| self.testRunner = { |
| neverInlineFunction: neverInlineFunction, |
| numberOfDFGCompiles: numberOfDFGCompiles |
| }; |
| |
| var silentMode = true; |
| var throwOnFirstFail = true; |
| var silentTestPass, didPassSomeTestsSilently, didFailSomeTests, successfullyParsed; |
| silentTestPass = false; |
| didPassSomeTestsSilenty = false; |
| didFailSomeTests = false; |
| |
| function description(msg) |
| { |
| if (silentMode) |
| return; |
| print(msg); |
| print("\nOn success, you will see a series of \"PASS\" messages, followed by \"TEST COMPLETE\".\n"); |
| print(); |
| } |
| |
| function debug(msg) |
| { |
| if (silentMode) |
| return; |
| print(msg); |
| } |
| |
| function escapeString(text) |
| { |
| return text.replace(/\0/g, ""); |
| } |
| |
| function testPassed(msg) |
| { |
| if (silentTestPass) |
| didPassSomeTestsSilently = true; |
| else if (silentMode) |
| return; |
| else |
| print("PASS", escapeString(msg)); |
| } |
| |
| function testFailed(msg) |
| { |
| didFailSomeTests = true; |
| if (!silentMode) |
| print("FAIL", escapeString(msg)); |
| if (throwOnFirstFail) |
| throw new Error(escapeString(msg)); |
| } |
| |
| function areNumbersEqual(_actual, _expected) |
| { |
| if (_expected === 0) |
| return _actual === _expected && (1/_actual) === (1/_expected); |
| if (_actual === _expected) |
| return true; |
| if (typeof(_expected) == "number" && isNaN(_expected)) |
| return typeof(_actual) == "number" && isNaN(_actual); |
| return false; |
| } |
| |
| function areArraysEqual(_a, _b) |
| { |
| try { |
| if (_a.length !== _b.length) |
| return false; |
| for (var i = 0; i < _a.length; i++) |
| if (!areNumbersEqual(_a[i], _b[i])) |
| return false; |
| } catch (ex) { |
| return false; |
| } |
| return true; |
| } |
| |
| function isMinusZero(n) |
| { |
| // the only way to tell 0 from -0 in JS is the fact that 1/-0 is |
| // -Infinity instead of Infinity |
| return n === 0 && 1/n < 0; |
| } |
| |
| function isTypedArray(array) |
| { |
| return array instanceof Int8Array |
| || array instanceof Int16Array |
| || array instanceof Int32Array |
| || array instanceof Uint8Array |
| || array instanceof Uint8ClampedArray |
| || array instanceof Uint16Array |
| || array instanceof Uint32Array |
| || array instanceof Float32Array |
| || array instanceof Float64Array; |
| } |
| |
| function isResultCorrect(_actual, _expected) |
| { |
| if (areNumbersEqual(_actual, _expected)) |
| return true; |
| if (_expected |
| && (Object.prototype.toString.call(_expected) == |
| Object.prototype.toString.call([]) |
| || isTypedArray(_expected))) |
| return areArraysEqual(_actual, _expected); |
| return false; |
| } |
| |
| function stringify(v) |
| { |
| if (v === 0 && 1/v < 0) |
| return "-0"; |
| else if (isTypedArray(v)) |
| return v.__proto__.constructor.name + ":[" + Array.prototype.join.call(v, ",") + "]"; |
| else |
| return "" + v; |
| } |
| |
| function shouldBe(_a, _b, _quiet) |
| { |
| if ((typeof _a != "function" && typeof _a != "string") || (typeof _b != "function" && typeof _b != "string")) |
| debug("WARN: shouldBe() expects function or string arguments"); |
| var _exception; |
| var _av; |
| try { |
| _av = (typeof _a == "function" ? _a() : eval(_a)); |
| } catch (e) { |
| _exception = e; |
| } |
| var _bv = (typeof _b == "function" ? _b() : eval(_b)); |
| |
| if (_exception) |
| testFailed(_a + " should be " + stringify(_bv) + ". Threw exception " + _exception); |
| else if (isResultCorrect(_av, _bv)) { |
| if (!_quiet) { |
| testPassed(_a + " is " + (typeof _b == "function" ? _bv : _b)); |
| } |
| } else if (typeof(_av) == typeof(_bv)) |
| testFailed(_a + " should be " + stringify(_bv) + ". Was " + stringify(_av) + "."); |
| else |
| testFailed(_a + " should be " + stringify(_bv) + " (of type " + typeof _bv + "). Was " + _av + " (of type " + typeof _av + ")."); |
| } |
| |
| function dfgShouldBe(theFunction, _a, _b) |
| { |
| if (typeof theFunction != "function" || typeof _a != "string" || typeof _b != "string") |
| debug("WARN: dfgShouldBe() expects a function and two strings"); |
| noInline(theFunction); |
| var exception; |
| var values = []; |
| |
| // Defend against tests that muck with numeric properties on array.prototype. |
| values.__proto__ = null; |
| values.push = Array.prototype.push; |
| |
| try { |
| while (!dfgCompiled({f:theFunction})) |
| values.push(eval(_a)); |
| values.push(eval(_a)); |
| } catch (e) { |
| exception = e; |
| } |
| |
| var _bv = eval(_b); |
| if (exception) |
| testFailed(_a + " should be " + stringify(_bv) + ". On iteration " + (values.length + 1) + ", threw exception " + exception); |
| else { |
| var allPassed = true; |
| for (var i = 0; i < values.length; ++i) { |
| var _av = values[i]; |
| if (isResultCorrect(_av, _bv)) |
| continue; |
| if (typeof(_av) == typeof(_bv)) |
| testFailed(_a + " should be " + stringify(_bv) + ". On iteration " + (i + 1) + ", was " + stringify(_av) + "."); |
| else |
| testFailed(_a + " should be " + stringify(_bv) + " (of type " + typeof _bv + "). On iteration " + (i + 1) + ", was " + _av + " (of type " + typeof _av + ")."); |
| allPassed = false; |
| } |
| if (allPassed) |
| testPassed(_a + " is " + _b + " on all iterations including after DFG tier-up."); |
| } |
| |
| return values.length; |
| } |
| |
| function shouldBeType(_a, _type) { |
| var exception; |
| var _av; |
| try { |
| _av = eval(_a); |
| } catch (e) { |
| exception = e; |
| } |
| |
| var _typev = eval(_type); |
| if (_av instanceof _typev) { |
| testPassed(_a + " is an instance of " + _type); |
| } else { |
| testFailed(_a + " is not an instance of " + _type); |
| } |
| } |
| |
| function shouldBeTrue(_a) { shouldBe(_a, "true"); } |
| function shouldBeFalse(_a) { shouldBe(_a, "false"); } |
| function shouldBeNaN(_a) { shouldBe(_a, "NaN"); } |
| function shouldBeNull(_a) { shouldBe(_a, "null"); } |
| |
| function shouldBeEqualToString(a, b) |
| { |
| if (typeof a !== "string" || typeof b !== "string") |
| debug("WARN: shouldBeEqualToString() expects string arguments"); |
| var unevaledString = JSON.stringify(b); |
| shouldBe(a, unevaledString); |
| } |
| |
| function shouldBeUndefined(_a) |
| { |
| var exception; |
| var _av; |
| try { |
| _av = eval(_a); |
| } catch (e) { |
| exception = e; |
| } |
| |
| if (exception) |
| testFailed(_a + " should be undefined. Threw exception " + exception); |
| else if (typeof _av == "undefined") |
| testPassed(_a + " is undefined."); |
| else |
| testFailed(_a + " should be undefined. Was " + _av); |
| } |
| |
| function shouldNotThrow(_a, _message) { |
| try { |
| typeof _a == "function" ? _a() : eval(_a); |
| testPassed((_message ? _message : _a) + " did not throw exception."); |
| } catch (e) { |
| testFailed((_message ? _message : _a) + " should not throw exception. Threw exception " + e + "."); |
| } |
| } |
| |
| function shouldThrow(_a, _e, _message) |
| { |
| var _exception; |
| var _av; |
| try { |
| _av = typeof _a == "function" ? _a() : eval(_a); |
| } catch (e) { |
| _exception = e; |
| } |
| |
| var _ev; |
| if (_e) |
| _ev = eval(_e); |
| |
| if (_exception) { |
| if (typeof _e == "undefined" || _exception == _ev) |
| testPassed((_message ? _message : _a) + " threw exception " + _exception + "."); |
| else |
| testFailed((_message ? _message : _a) + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Threw exception " + _exception + "."); |
| } else if (typeof _av == "undefined") |
| testFailed((_message ? _message : _a) + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was undefined."); |
| else |
| testFailed((_message ? _message : _a) + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was " + _av + "."); |
| } |
| |
| function isSuccessfullyParsed() |
| { |
| // FIXME: Remove this and only report unexpected syntax errors. |
| if (!errorMessage) |
| successfullyParsed = true; |
| shouldBeTrue("successfullyParsed"); |
| if (silentTestPass && didPassSomeTestsSilently) |
| debug("Passed some tests silently."); |
| if (silentTestPass && didFailSomeTests) |
| debug("Some tests failed."); |
| debug("\nTEST COMPLETE\n"); |
| } |
| |
| |
| function dfgCompiled(argument) |
| { |
| var numberOfCompiles = "compiles" in argument ? argument.compiles : 1; |
| |
| if (!("f" in argument)) |
| throw new Error("dfgCompiled called with invalid argument."); |
| |
| if (argument.f instanceof Array) { |
| for (var i = 0; i < argument.f.length; ++i) { |
| if (testRunner.numberOfDFGCompiles(argument.f[i]) < numberOfCompiles) |
| return false; |
| } |
| } else { |
| if (testRunner.numberOfDFGCompiles(argument.f) < numberOfCompiles) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| function dfgIncrement(argument) |
| { |
| if (!self.testRunner) |
| return argument.i; |
| |
| if (argument.i < argument.n) |
| return argument.i; |
| |
| if (didFailSomeTests) |
| return argument.i; |
| |
| if (!dfgCompiled(argument)) |
| return "start" in argument ? argument.start : 0; |
| |
| return argument.i; |
| } |
| |
| function noInline(theFunction) |
| { |
| if (!self.testRunner) |
| return; |
| |
| testRunner.neverInlineFunction(theFunction); |
| } |
| |
| function finishJSTest() |
| { |
| isSuccessfullyParsed(); |
| if (didFailSomeTests) |
| throw new Error("Some Tests Failed"); |
| } |