microvium
Version:
A compact, embeddable scripting engine for microcontrollers for executing small scripts written in a subset of JavaScript.
155 lines • 6.37 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.updateCoverageMarkers = exports.reconstructCoverageLine = exports.getCoveragePoints = void 0;
const utils_1 = require("./utils");
const colors_1 = __importDefault(require("colors"));
const fs_1 = __importDefault(require("fs"));
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));
function getCoveragePoints(sourceLines, filename) {
const coveragePoints = [];
for (const [lineI, line] of sourceLines.entries()) {
let m = line.match(/^(\s*)CODE_COVERAGE(|_UNTESTED|_UNIMPLEMENTED|_ERROR_PATH)\((.*?)\);\s*(\/\/.*)?$/);
if (m) {
const info = {
lineI,
indent: m[1],
type: m[2] === '' ? 'normal' :
m[2] === '_UNTESTED' ? 'untested' :
m[2] === '_UNIMPLEMENTED' ? 'unimplemented' :
m[2] === '_ERROR_PATH' ? 'error-path' :
(0, utils_1.unexpected)(),
id: parseInt(m[3]),
comment: m[4],
};
coveragePoints.push(info);
}
else if (line.includes('CODE_COVERAGE') && !line.trim().startsWith('//')) {
throw new Error(`Invalid CODE_COVERAGE marker\n at ${filename}:${lineI + 1}`);
}
m = line.match(/^(\s*)TABLE_COVERAGE\((.*?),(.*?)(?:,(.*?))?\);\s*(\/\/.*)?$/);
if (m) {
const info = {
type: 'table',
lineI,
indent: m[1],
indexInTable: m[2].trim(),
tableSize: m[3].trim(),
id: parseInt(m[4]),
comment: m[5],
};
coveragePoints.push(info);
}
else if (line.includes('TABLE_COVERAGE') && !line.trim().startsWith('//')) {
throw new Error(`Invalid TABLE_COVERAGE marker\n at ${colors_1.default.red(`${filename}:${lineI + 1}`)}`);
}
}
return coveragePoints;
}
exports.getCoveragePoints = getCoveragePoints;
function reconstructCoverageLine(lineInfo, includeIndent) {
let macroMain;
switch (lineInfo.type) {
case 'normal':
macroMain = `CODE_COVERAGE(${lineInfo.id});`;
break;
case 'untested':
macroMain = `CODE_COVERAGE_UNTESTED(${lineInfo.id});`;
break;
case 'unimplemented':
macroMain = `CODE_COVERAGE_UNIMPLEMENTED(${lineInfo.id});`;
break;
case 'error-path':
macroMain = `CODE_COVERAGE_ERROR_PATH(${lineInfo.id});`;
break;
case 'table':
macroMain = `TABLE_COVERAGE(${lineInfo.indexInTable}, ${lineInfo.tableSize}, ${lineInfo.id});`;
break;
}
return `${includeIndent ? lineInfo.indent : ''}${macroMain}${lineInfo.comment
? ' ' + lineInfo.comment
: ''}`;
}
exports.reconstructCoverageLine = reconstructCoverageLine;
/**
* @param removeUntestedFlags Removes the `_UNTESTED` flag for paths that are hit.
*/
function updateCoverageMarkers(silent, removeUntestedFlags) {
const hitInfoFilename = path_1.default.resolve('./test/end-to-end/artifacts/code-coverage-details.json');
const microviumCFilename = './native-vm/microvium.c';
const ids = new Set();
const toAssign = new Array();
const lines = fs_1.default.readFileSync(microviumCFilename, 'utf8')
.split(/\r?\n/g);
const log = (s) => !silent && console.log(s);
const coveragePoints = getCoveragePoints(lines, microviumCFilename);
for (const c of coveragePoints) {
if (!isNaN(c.id)) {
if (ids.has(c.id)) {
console.error(` Warning: duplicate coverage ID ${c.id} at ` + colors_1.default.yellow(`${microviumCFilename}:${c.lineI + 1}`));
toAssign.push(c);
}
else {
ids.add(c.id);
}
}
else {
toAssign.push(c);
}
}
let changedCount = 0;
let nextID = 1;
for (const c of toAssign) {
while (ids.has(nextID)) {
nextID++;
}
const id = nextID++;
c.id = id;
}
// If we have hit count information, then we calculate all lines based on hit information
if (fs_1.default.existsSync(hitInfoFilename)) {
const coverageHits = JSON.parse(fs_1.default.readFileSync(hitInfoFilename, 'utf8'));
for (const c of coveragePoints) {
const hitInfo = coverageHits[c.id];
if (hitInfo) {
if (removeUntestedFlags && c.type === 'untested')
c.type = 'normal';
if (hitInfo.tableSize !== undefined && hitInfo.hitCountByTableEntry !== undefined) {
c.comment = `// Hit ${Object.keys(hitInfo.hitCountByTableEntry).length}/${hitInfo.tableSize}`;
}
else {
c.comment = '// Hit';
}
}
else {
c.comment = '// Not hit';
}
const s = reconstructCoverageLine(c, false);
const lineContent = `${c.indent}${s}`;
if (lines[c.lineI] !== lineContent) {
lines[c.lineI] = lineContent;
log(` ${microviumCFilename}:${c.lineI + 1} ${s}`);
changedCount++;
}
}
}
else {
for (const c of toAssign) {
const s = reconstructCoverageLine(c, false);
lines[c.lineI] = `${c.indent}${s}`;
log(`✓ ` + colors_1.default.green(`${microviumCFilename}:${c.lineI + 1} `) + s);
changedCount++;
}
}
if (!changedCount) {
log(colors_1.default.cyan(`✓ All ${coveragePoints.length} coverage markers are up to date`));
}
else {
(0, utils_1.writeTextFile)(microviumCFilename, lines.join(os_1.default.EOL));
}
}
exports.updateCoverageMarkers = updateCoverageMarkers;
//# sourceMappingURL=code-coverage-utils.js.map