blob: 4d8a8eeabadf8d6f71e69b98d3af247ead2ea57a [file] [log] [blame]
var errorMessage;
var self = this;
self.testRunner = {
neverInlineFunction: neverInlineFunction,
numberOfDFGCompiles: numberOfDFGCompiles
};
var silentMode = true;
var throwOnFirstFail = true;
var silentTestPass, didPassSomeTestsSilently, didFailSomeTests, successfullyParsed;
silentTestPass = false;
didPassSomeTestsSilently = 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");
}