microvium
Version:
A compact, embeddable scripting engine for microcontrollers for executing small scripts written in a subset of JavaScript.
126 lines • 5.96 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.anyGrepSelector = void 0;
const code_coverage_utils_1 = require("../lib/code-coverage-utils");
const native_vm_1 = require("../lib/native-vm");
const utils_1 = require("../lib/utils");
const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const os_1 = __importDefault(require("os"));
const colors_1 = __importDefault(require("colors"));
const microviumCFilename = './native-vm/microvium.c';
const coverageHits = {};
let anyFailures = false;
const rootArtifactDir = './test/end-to-end/artifacts';
const coveragePoints = (0, code_coverage_utils_1.getCoveragePoints)(fs_1.default.readFileSync(microviumCFilename, 'utf8').split(/\r?\n/g), microviumCFilename);
exports.anyGrepSelector = process.argv.some(x => x === '-g' || x === '--grep');
const allTestsFilename = path_1.default.join(rootArtifactDir, 'all-tests.json');
const allTests = fs_1.default.existsSync(allTestsFilename)
? new Set(JSON.parse(fs_1.default.readFileSync(allTestsFilename, 'utf8')))
: new Set();
const remainingTests = new Set([...allTests]);
let isFirstSetup = true;
// Note: I couldn't figure out a builtin way of doing a global setup and
// teardown across all tests, so I'm just keeping a list of tests and running
// the global teardown when we've done all of them. This will have issues if we
// delete or rename tests. If that happens, delete the `all-tests.json` output
// file and it will recreate it on the next run.
setup(function () {
if (isFirstSetup) {
globalSetup();
isFirstSetup = false;
}
});
teardown(function () {
if (this.currentTest && this.currentTest.isFailed()) {
anyFailures = true;
}
if (this.currentTest) {
const titlePath = this.currentTest.titlePath().join(' ');
allTests.add(titlePath);
if (remainingTests.has(titlePath)) {
remainingTests.delete(titlePath);
if (remainingTests.size === 0) {
globalTeardown();
}
}
else {
// Otherwise, there's a change to the set of test cases
(0, utils_1.writeTextFile)(allTestsFilename, JSON.stringify([...allTests], null, 4));
}
}
});
process.on('beforeExit', () => {
// If there are remaining tests when the process is exiting, it means we haven't run the teardown
if (remainingTests.size > 0) {
globalTeardown();
}
});
function globalSetup() {
native_vm_1.NativeVM.setCoverageCallback((id, mode, indexInTable, tableSize, line) => {
let hitInfo = coverageHits[id];
if (!hitInfo) {
hitInfo = { lineHitCount: 0 };
if (mode === native_vm_1.CoverageCaseMode.TABLE) {
hitInfo.hitCountByTableEntry = {};
hitInfo.tableSize = tableSize;
}
coverageHits[id] = hitInfo;
}
hitInfo.lineHitCount++;
if (mode === native_vm_1.CoverageCaseMode.TABLE) {
const tableHitCount = (0, utils_1.notUndefined)(hitInfo.hitCountByTableEntry);
tableHitCount[indexInTable] = (tableHitCount[indexInTable] || 0) + 1;
}
});
}
function globalTeardown() {
native_vm_1.NativeVM.setCoverageCallback(undefined);
const anySkips = remainingTests.size > 0;
const summaryPath = path_1.default.resolve(rootArtifactDir, 'code-coverage-summary.txt');
let coverageHitLocations = 0;
let coveragePossibleHitLocations = 0;
for (const c of coveragePoints) {
const hitInfo = coverageHits[c.id];
if (!hitInfo) {
coveragePossibleHitLocations++;
}
else {
if (hitInfo.tableSize !== undefined) {
coveragePossibleHitLocations += hitInfo.tableSize;
}
else {
coveragePossibleHitLocations++;
}
if (hitInfo.hitCountByTableEntry !== undefined) {
const numberOfItemsInTableThatWereHit = Object.keys(hitInfo.hitCountByTableEntry).length;
coverageHitLocations += numberOfItemsInTableThatWereHit;
}
else {
// Else we just say that the line was hit
coverageHitLocations++;
}
}
}
if (!exports.anyGrepSelector && !anySkips && !anyFailures) {
const coverageOneLiner = `${coverageHitLocations} of ${coveragePossibleHitLocations} (${(coverageHitLocations / coveragePossibleHitLocations * 100).toFixed(1)}%)`;
const microviumCFilenameRelative = path_1.default.relative(process.cwd(), microviumCFilename);
(0, utils_1.writeTextFile)(path_1.default.resolve(rootArtifactDir, 'code-coverage-details.json'), JSON.stringify(coverageHits));
const summaryLines = [`microvium.c code coverage: ${coverageOneLiner}`];
(0, utils_1.writeTextFile)(summaryPath, summaryLines.join(os_1.default.EOL));
const expectedButNotHit = coveragePoints
.filter(p => (p.type === 'normal') && !coverageHits[p.id]);
(0, code_coverage_utils_1.updateCoverageMarkers)(true, !anySkips && !anyFailures && !exports.anyGrepSelector);
if (expectedButNotHit.length) {
throw new Error('The following coverage points were expected but not hit in the tests\n' +
expectedButNotHit
.map(p => ` at ${microviumCFilenameRelative}:${p.lineI + 1} ID(${p.id})`)
.join('\n '));
}
console.log(`\n ${colors_1.default.green('√')} ${colors_1.default.gray('microvium.c code coverage: ')}${coverageOneLiner}`);
}
}
//# sourceMappingURL=code-coverage.test.js.map