UNPKG

org.eclipse.n4js.mangelhaft

Version:

An xUnit Testing Framework for N4JS.

233 lines (230 loc) 7.46 kB
// Generated by N4JS transpiler; for copyright see original N4JS source file. import 'n4js-runtime' import {N4Injector} from 'n4js-runtime/src-gen/n4js/lang/N4Injector.js' import {InstrumentedTest} from './InstrumentedTest.js' import {TestExecutor} from './TestExecutor.js' import {PreconditionNotMet} from 'org.eclipse.n4js.mangelhaft.assert/src-gen/org/eclipse/n4js/mangelhaft/precondition/PreconditionNotMet.js' import {ResultGroups} from './types/ResultGroups.js' import {TestFunctionType} from './types/TestFunctionType.js' import {TestMethodDescriptor} from './types/TestMethodDescriptor.js' import {TestSpy} from './types/TestSpy.js' import {readJsonFile} from './util/fs.js' import {findPackageJson} from './util/npm.js' import {Module} from 'node:module' import * as lib_path from 'path' const MAX_GROUPS_PER_TEST_BATCH = 10; const notNull = (thing)=>thing !== null; export class TestController extends N4Object { constructor() { super(); this.spy = undefined; this.executor = undefined; this.injector = undefined; this.reportersVal = []; } get reporters() { return this.reportersVal; } set reporters(reporters) { reporters.forEach(function(reporter) { let dummy = reporter.register(); dummy; }); this.reportersVal = reporters; } async runGroups(testCatalog, numTests, scope) { if (!testCatalog) { throw new Error("TestController::runGroups called with a null testCatalog"); } const testInfos = testCatalog.testDescriptors.sort((x, y)=>{ let xVal = x.fqn ? x.fqn : x.module; let yVal = y.fqn ? y.fqn : y.module; return xVal.localeCompare(yVal); }); if (numTests === undefined) { numTests = testInfos.reduce((acc, info)=>acc + info.testMethods.length, 0); } try { await this.spy.testingStarted.dispatch([ testInfos.length, testCatalog.sessionId, numTests ]); } catch(ex) { console.log("testingStarted.dispatch is bad", ex); } const res = await this.runInBatches(testCatalog, testInfos, scope); await this.spy.testingFinished.dispatch([ res ]); return res; } async runInBatches(testCatalog, testInfos, scope) { let res; const batchedTestInfos = []; for(let batchedCount = 0;batchedCount < testInfos.length;batchedCount += MAX_GROUPS_PER_TEST_BATCH) { const batch = testInfos.slice(batchedCount, batchedCount + MAX_GROUPS_PER_TEST_BATCH); batchedTestInfos.push(batch); } const resultGroups = []; for(let numOfBatches = 0;numOfBatches < batchedTestInfos.length;++numOfBatches) { try { const testInfosBatch = batchedTestInfos[numOfBatches]; const instrumentedTestsBatch = await this.instrumentBatch(testCatalog, testInfosBatch, resultGroups); res = await this.executor.runTestsAsync(instrumentedTestsBatch, scope); resultGroups.push(res); } catch(er) { console.error(er); throw er; } } res = ResultGroups.concatArray(resultGroups); return res; } async instrumentBatch(testCatalog, testInfosBatch, resultGroups) { let result = []; for(const testInfo of testInfosBatch) { const instrumentedTest = await this.instrument(testCatalog, testInfo, resultGroups); result = result.concat(instrumentedTest); } return result; } async instrument(testCatalog, info, resultGroups) { let testClasses; const originOrPackageName = info.origin || testCatalog.packageName; const parts = info.fqn.split("/"); const ctorName = parts.pop(); const moduleName = parts.join("/"); try { let groupModule; try { const mod = `${testCatalog.location}/${moduleName}.js`; groupModule = await import(mod); info.filePath = Module.createRequire(import.meta.url).resolve(mod); } catch(exc) { const packageJsonPath = findPackageJson(process.cwd()); if (!packageJsonPath || readJsonFile(packageJsonPath).name !== originOrPackageName) { throw exc; } const parts = moduleName.split("/"); parts.unshift(lib_path.dirname(packageJsonPath)); info.filePath = `${parts.join(lib_path.sep)}.js`; groupModule = await import(info.filePath); } testClasses = [ groupModule[ctorName] ]; } catch(ex) { const errorTest = this.createErrorTest(info, originOrPackageName + "/" + moduleName, null, ex); return [ errorTest ]; } if (!testClasses) { const errorTest = this.createErrorTest(info, originOrPackageName + "/" + parts.join("/")); return [ errorTest ]; } let instrumentedTests = []; for(const testClass of testClasses) { if (!testClass) { const errorTest = this.createErrorTest(info, originOrPackageName + "/" + moduleName, null, new Error("Empty object loaded (is the test class exported?)")); instrumentedTests.push(errorTest); continue; } try { const testInjector = this.getTestInjector(testClass); let classITO = InstrumentedTest.getInstrumentedTest(testClass, info, testInjector, this); instrumentedTests.push(classITO); } catch(ex2) { const stubTestInstrumentationError = new InstrumentedTest(testClass, info).setTestObject(new N4Object()).setError(ex2); instrumentedTests.push(stubTestInstrumentationError); } } const result = instrumentedTests.filter(notNull); return result; } createErrorTest(info, loadPath, testObject, originalError) { if (!testObject) { testObject = this.getInstrumentedTestStub(info); } const error = originalError ? originalError : new Error("could not load test " + loadPath); testObject.setError(error); return testObject; } getInstrumentedTestStub(info) { const testObject = new InstrumentedTest(); info.module = info.module || ""; info.fqn = info.fqn || info.module.replace(/\//g, ".") + ".*"; testObject.load(N4Object, info).setTestObject(new N4Object()); if (info.testMethods) { testObject.tests = info.testMethods.map((methName)=>new TestMethodDescriptor({ name: methName, type: TestFunctionType.TEST, value: function() {} })); } else { testObject.tests = [ new TestMethodDescriptor({ name: "", type: TestFunctionType.TEST, value: function() {} }) ]; } return testObject; } getTestInjector(testClass) { let testInjector; let diClass = testClass; let testType = testClass.n4type; while(testType) { if (testType.hasAnnotation("GenerateInjector")) { if (testType.hasAnnotation("WithParentInjector")) { if (!this.injector.canBeParentOf(diClass)) { throw new PreconditionNotMet("Test called with incompatible parent injector"); } testInjector = N4Injector.of(diClass, this.injector); } else { testInjector = N4Injector.of(diClass); } break; } testType = testType.n4superType; diClass = Object.getPrototypeOf(diClass); } if (!testType) { testInjector = this.injector; } return testInjector; } static get n4type() { return $getReflectionForClass(this, '["TestController","org/eclipse/n4js/mangelhaft/TestController","org.eclipse.n4js.mangelhaft",["f.spy","f.executor","f.injector","f.reportersVal"],{"f.spy":["Inject"],"f.executor":["Inject"],"f.injector":["Inject"]}]'); } } Object.defineProperty(TestController, Symbol.for('org.eclipse.n4js/diInfo'), { value: { fieldsInjectedTypes: [ { name: 'spy', get type() { return TestSpy; } }, { name: 'executor', get type() { return TestExecutor; } }, { name: 'injector', get type() { return N4Injector; } } ] } }); //# sourceMappingURL=TestController.map