UNPKG

org.eclipse.n4js.mangelhaft

Version:

An xUnit Testing Framework for N4JS.

322 lines (319 loc) 9.23 kB
// Generated by N4JS transpiler; for copyright see original N4JS source file. import 'n4js-runtime' import {AssertionError} from 'org.eclipse.n4js.mangelhaft.assert/src-gen/org/eclipse/n4js/mangelhaft/assert/AssertionError.js' import {PreconditionNotMet} from 'org.eclipse.n4js.mangelhaft.assert/src-gen/org/eclipse/n4js/mangelhaft/precondition/PreconditionNotMet.js' import {ResultGroup} from './types/ResultGroup.js' import {ResultGroups} from './types/ResultGroups.js' import {TestResult} from './types/TestResult.js' import {TestSpy} from './types/TestSpy.js' export class TestExecutor extends N4Object { constructor(spy) { super(); this.spy = undefined; this.constext = undefined; this.spy = spy; } static getStringFromAbiguous(thing) { let str; if (thing === null) { str = "null"; } else if (typeof thing === "object") { str = Object.prototype.hasOwnProperty.call(thing, "toString") ? "" + thing : "prototypeless object"; } else { str = "" + thing; } return str; } static generateFailureTestResult(ex, description) { const status = this.getStatus(ex); const error = this.getError(ex, description); const reason = this.getReason(error, description); const trace = this.getTrace(error); const expected = this.getStringifiedOwnProperty(error, "expected"); const actual = this.getStringifiedOwnProperty(error, "actual"); let tr = new TestResult({ testStatus: status, message: reason, trace: trace, description: description, expected: expected, actual: actual }); return tr; } static getReason(error, description) { if (error.message) { return String(error); } let reason = error.toString(); if (reason.charAt(0) === "[") { reason = error.name ? `${error.name} : ${description}` : description; } return reason; } static getStringifiedOwnProperty(object, name) { if (!object.hasOwnProperty(name)) { return undefined; } const prop = object[name]; const res = this.getStringFromAbiguous(prop); return res; } static getError(ex, description) { if (!ex) { return new Error("Unknown error: " + description); } if (typeof ex === "string") { return new Error(ex); } if (ex instanceof AssertionError) { return ex; } return ex; } static getStatus(ex) { if (ex instanceof AssertionError) { return 'FAILED'; } if (ex instanceof PreconditionNotMet) { return 'SKIPPED_PRECONDITION'; } if (ex instanceof N4ApiNotImplementedError) { return 'SKIPPED_NOT_IMPLEMENTED'; } return 'ERROR'; } static getTrace(e) { let trace; if (e['stack']) { const stack = e['stack']; if (typeof stack === "string") { trace = (stack).split("\n"); } else if (Array.isArray(stack)) { trace = stack; } else { trace = [ (stack).toString() ]; } trace = trace.map((line)=>line.trim()); } return trace; } handleFixme(testObject, scope, testRes) { if (testObject.fixme && (!testObject.fixmeScopes || testObject.fixmeScopes.has(scope))) { if (testRes.testStatus === 'PASSED') { testRes.testStatus = 'FAILED'; testRes.message = "Test marked with @Fixme annotation but was successful. Issue blocking test has probably been fixed. Try removing annotation."; if (testObject.fixmeReason != null) { testRes.message += " (reason was '" + testObject.fixmeReason + "')"; } testRes.trace = [ String(testRes) ]; } else if (testRes.testStatus === 'FAILED' || testRes.testStatus === 'ERROR') { testRes.testStatus = 'SKIPPED_FIXME'; testRes.message = testObject.fixmeReason; testRes.actual = testRes.expected = testRes.trace = null; } } return testRes; } async callAllGrouped(instrumentedTest, testMethodDescriptors) { for(const batch of testMethodDescriptors) { await this.callAll(instrumentedTest, batch); } } async callAll(instrumentedTest, testMethodDescriptors) { if (testMethodDescriptors) { const runTestMethod = getExecutingFunction(instrumentedTest); await Promise.all(testMethodDescriptors.map(runTestMethod)); } } getAncestorTestMethods(iTest, testMethodName) { let testMethods = []; let node = iTest; while(node.parent) { node = node.parent; } do { let nodeObj = node; const nodeTestMethods = nodeObj[testMethodName]; if (nodeTestMethods && nodeTestMethods.length) { testMethods.push(nodeTestMethods); } } while(node = node.child); return testMethods; } async runTestAsync(instrumentedTest) { return await this.runTestsAsync([ instrumentedTest ]); } async runGroup(iTest, scope) { let testResults = []; await this.spy.groupStarted.dispatch([ iTest ]); if (!iTest.error) { try { const beforeAlls = this.getAncestorTestMethods(iTest, "beforeAlls"); await this.callAllGrouped(iTest, beforeAlls); await this.runBeforesTestsAfters(testResults, iTest, scope); const afterAlls = this.getAncestorTestMethods(iTest, "afterAlls").reverse(); await this.callAllGrouped(iTest, afterAlls); } catch(error) { let results = await this.errorTests(iTest, error); testResults = testResults.concat(results); } } else { testResults = await this.errorTests(iTest, iTest.error); } const result = new ResultGroup(testResults, `${iTest.name}`); await this.spy.groupFinished.dispatch([ iTest, result ]); return result; } async runBeforesTestsAfters(testResults, iTest, scope) { const numTests = iTest.tests.length; for(let ii = 0;ii < numTests;++ii) { let testMethod = iTest.tests[ii]; let start, end; let testRes; try { await this.spy.testStarted.dispatch([ iTest, testMethod ]); start = new Date().getTime(); if (!testMethod.ignore) { try { const befores = this.getAncestorTestMethods(iTest, "befores"); await this.callAllGrouped(iTest, befores); await this.callAll(iTest, [ testMethod ]); testRes = new TestResult({ testStatus: 'PASSED', description: testMethod.name }); } finally { const afters = this.getAncestorTestMethods(iTest, "afters").reverse(); await this.callAllGrouped(iTest, afters); } } else { testRes = new TestResult({ testStatus: 'SKIPPED_IGNORE', message: testMethod.ignoreReason, description: testMethod.name }); } end = new Date().getTime(); } catch(er) { end = new Date().getTime(); testRes = TestExecutor.generateFailureTestResult(er, testMethod.name); } testRes.elapsedTime = end - start; testRes = this.handleFixme(testMethod, scope, testRes); await this.spy.testFinished.dispatch([ iTest, testMethod, testRes, async()=>{ let allTests = iTest.tests; iTest.tests = [ testMethod ]; try { await this.runTestsAsync([ iTest ]); } finally { iTest.tests = allTests; } } ]); testResults.push(testRes); } } async runTestsAsync(instrumentedTests, scope) { let results = []; for(let test of instrumentedTests) { if (test) { if (test.hasParameterizedTests) { let pResults = []; await this.spy.parameterizedGroupsStarted.dispatch([ test ]); for(let ptest of test.parameterizedTests) { let testRes = await this.runGroup(ptest, scope); pResults.push(testRes); results.push(testRes); } await this.spy.parameterizedGroupsFinished.dispatch([ new ResultGroups(pResults) ]); } else { let testRes = await this.runGroup(test, scope); results.push(testRes); } } } let resultGroups = new ResultGroups(results); return resultGroups; } async errorTests(instrumentedTest, error) { const testResults = []; const len = instrumentedTest.tests.length; for(let ii = 0;ii < len;++ii) { const test = instrumentedTest.tests[ii]; await this.spy.testStarted.dispatch([ instrumentedTest, test ]); const testResult = TestExecutor.generateFailureTestResult(error, test.name); testResult.elapsedTime = 0; await this.spy.testFinished.dispatch([ instrumentedTest, test, testResult ]); testResults.push(testResult); } return testResults; } static get n4type() { return $getReflectionForClass(this, '["TestExecutor","org/eclipse/n4js/mangelhaft/TestExecutor","org.eclipse.n4js.mangelhaft",["f.spy","f.constext"],{"f.spy":["Inject"]}]'); } } Object.defineProperty(TestExecutor, Symbol.for('org.eclipse.n4js/diInfo'), { value: { fieldsInjectedTypes: [ { name: 'spy', get type() { return TestSpy; } } ] } }); function getExecutingFunction(instrumentedTest) { return (testMethodDescriptor)=>(new Promise((resolve, reject)=>{ const pr = Promise.resolve(testMethodDescriptor.value.call(instrumentedTest.testObject)); let timeoutId; if (!process.env.N4JS_RT_mangelhaft_timeout_disabled) { timeoutId = setTimeout(()=>reject(new Error(`Test object ${testMethodDescriptor.name} timed out after ${testMethodDescriptor.timeout} milliseconds`)), testMethodDescriptor.timeout); } pr.then((res)=>{ clearTimeout(timeoutId); resolve(); }, (err)=>{ clearTimeout(timeoutId); reject(err); }); })); } //# sourceMappingURL=TestExecutor.map