| // This test module provides infrastructure for generating and running tests on a unary |
| // operator. |
| // |
| // It works by generating test functions to exercise the specified operator on operand |
| // values in a provided set. For each test, it computes the expected result by exercising |
| // the test function once (using the LLINT) at test generation time. |
| // The test runner later compares the result produced by the function (as it tiers up) |
| // against the expected result. |
| // |
| // The generated tests will exercise the operator on a variable. |
| // |
| // If all goes well, this test module will terminate silently. If not, it will print |
| // errors. |
| |
| //============================================================================ |
| // Debugging options: |
| |
| var verbose = false; |
| var abortOnFirstFail = false; |
| var testFilterStr = undefined; // Define a filter string to filter tests to run. |
| |
| var verboseTestGeneration = false; |
| |
| //============================================================================ |
| // Test generation: |
| |
| function stringifyIfNeeded(x) { |
| if (typeof x == "string") |
| return '"' + x + '"'; |
| if (typeof x == "object") |
| return 'objWithVal:' + x; |
| return x; |
| } |
| |
| // operatorTypes can be "Prefix" or "Postfix". |
| // resultTypes can be "ImmediateResult" or "PostResult". PostResult is mainly for |
| // checking the value of a variable on subsequent inspection, so we can confirm that the |
| // postfix operator did do its job. |
| var funcIndex = 0; |
| function generateBinaryTests(tests, opName, operatorType, resultType, op, inValues) { |
| var funcNamePrefix = opName + resultType; |
| for (var i = 0; i < inValues.length; i++) { |
| var test = { }; |
| xStr = inValues[i]; |
| test.x = eval(xStr); |
| |
| var funcName = funcNamePrefix + funcIndex++; |
| if (operatorType == "Prefix") { |
| if (resultType == "ImmediateResult") |
| test.signature = funcName + "(x) { return " + op + "x }"; |
| else if (resultType == "PostResult") |
| test.signature = funcName + "(x) { " + op + "x; return x; }"; |
| } else if (operatorType == "Postfix") { |
| if (resultType == "ImmediateResult") |
| test.signature = funcName + "(x) { return x" + op + " }"; |
| else if (resultType == "PostResult") |
| test.signature = funcName + "(x) { x" + op + "; return x; }"; |
| } |
| |
| test.name = test.signature + " with x:" + xStr; |
| |
| test.func = eval("(function " + test.signature + ")"); |
| noInline(test.func); |
| |
| test.expectedResult = test.func(test.x); |
| test.name += ", expected:" + stringifyIfNeeded(test.expectedResult); |
| |
| tests.push(test); |
| if (verboseTestGeneration) |
| print("Generated " + test.name); |
| } |
| } |
| |
| //============================================================================ |
| // Test running and reporting: |
| |
| var errorReport = ""; |
| |
| function isIdentical(x, y) { |
| if (typeof x == "undefined" && typeof y == "undefined") |
| return true; |
| if (typeof x != typeof y) |
| return false; |
| if (x == y) { |
| if (x) |
| return true; |
| // Distinguish between 0 and negative 0. |
| if (1 / x == 1 / y) |
| return true; |
| } else if (Number.isNaN(x) && Number.isNaN(y)) |
| return true; |
| return false; |
| } |
| |
| function runTest(test) { |
| if (testFilterStr && !test.name.includes(testFilterStr)) |
| return; |
| |
| var firstFailed = -1; |
| try { |
| if (verbose) |
| print(test.name); |
| for (var i = 0; i < 10000; i++) { |
| var result = test.func(test.x); |
| if (isIdentical(result, test.expectedResult)) |
| continue; |
| if (firstFailed < 0) { |
| errorReport += "FAILED: " + test.name + " started failing on iteration " + i |
| + ": actual " + stringifyIfNeeded(result) + "\n"; |
| if (abortOnFirstFail) |
| throw errorReport; |
| firstFailed = i; |
| } |
| } |
| } catch(e) { |
| if (abortOnFirstFail) |
| throw e; // Negate the catch by re-throwing. |
| errorReport += "FAILED: Unexpected exception: " + e + "\n"; |
| } |
| } |
| |
| function run() { |
| if (verbose) |
| print("Start testing"); |
| |
| for (var test of tests) |
| runTest(test); |
| |
| if (errorReport !== "") |
| throw "Found failures:\n" + errorReport; |
| |
| if (verbose) |
| print("Done testing"); |
| } |