arrange-act-assert
Version:
The lightweight "Act-Arrange-Assert" oriented testing framework
243 lines (242 loc) • 11.1 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.processCoverage = processCoverage;
const Url = __importStar(require("url"));
const Path = __importStar(require("path"));
const Module = __importStar(require("module"));
const Fs = __importStar(require("fs"));
const Line_1 = require("./Line");
const utils_1 = require("../utils/utils");
const getSourceMap_1 = __importDefault(require("./sourceMaps/getSourceMap"));
function getLineColumn(lines, position) {
let start = 0;
let end = lines.length - 1;
while (start <= end) {
const mid = Math.floor((start + end) / 2);
if (position >= lines[mid].start && position <= lines[mid].end) {
return {
line: mid,
column: position - lines[mid].start
};
}
if (position < lines[mid].start) {
end = mid - 1;
}
else {
start = mid + 1;
}
}
return null;
}
function findOrigin(sourceMap, line, column) {
const entry = sourceMap.findEntry(line, column);
if (entry.originalLine != null && entry.generatedLine != null) {
entry.originalLine += line - entry.generatedLine;
}
if (entry.originalColumn != null && entry.generatedColumn != null) {
entry.originalColumn += column - entry.generatedColumn;
}
return entry;
}
const ignoreRegex = /\/\* coverage ignore next (?<lines>\d+ )?\*\//;
const enableRegex = /\/\* coverage (?<state>enable|disable) \*\//;
const fileCache = new Map();
class FileManager {
constructor() {
this._files = new Map();
}
async getState(file, sourceMap) {
let data = this._files.get(file);
if (data) {
if (data.deleted) {
return null;
}
return data;
}
const cache = fileCache.get(file);
const code = cache ? cache.code : await Fs.promises.readFile(file, "utf8");
this._files.set(file, data = {
deleted: false,
error: null,
sourceMap: sourceMap ? ((cache && cache.sourceMap) || await (0, getSourceMap_1.default)(Path.dirname(file), code)) : null,
lines: []
});
if (!cache) {
fileCache.set(file, {
code: code,
sourceMap: data.sourceMap
});
}
else if (!cache.sourceMap && data.sourceMap) {
cache.sourceMap = data.sourceMap;
}
let pos = 0;
let ignoreLines = 0;
const lines = code.split(/(?<=\r?\n)/);
for (const line of lines) {
let lineEnd = pos + line.length;
if (line[line.length - 1] === "\n") {
lineEnd--;
}
if (line[line.length - 2] === "\r") {
lineEnd--;
}
data.lines.push(new Line_1.Line(pos, lineEnd, ignoreLines > 0 ? !!ignoreLines-- : false));
pos += line.length;
const ignoreMatch = ignoreRegex.exec(line);
if (ignoreMatch) {
const lines = ignoreMatch.groups && ignoreMatch.groups.lines;
ignoreLines = lines != null ? Number(lines) : 1;
}
const enableMatch = enableRegex.exec(line);
if (enableMatch) {
ignoreLines = (enableMatch.groups && enableMatch.groups.state === "disable") ? Infinity : 0;
}
}
return data;
}
deleteState(file) {
const data = this._files.get(file);
if (data) {
data.deleted = true;
}
else {
this._files.set(file, {
deleted: true,
error: null,
sourceMap: null,
lines: []
});
}
}
summary(branches) {
const result = [];
for (const [file, { deleted, lines, error }] of this._files) {
if (!deleted) {
result.push({
file: file,
error: error,
lines: lines.map(line => ({
length: line.length,
ranges: line.getRanges(branches)
}))
});
}
}
return result;
}
}
async function processCoverage(coverage, options) {
const fileManager = new FileManager();
for (const entry of coverage) {
try {
if (entry.url.startsWith("file:")) {
const file = Url.fileURLToPath(entry.url);
if (!options.excludeFiles.includes(file) && !(0, utils_1.testRegex)(file, options.exclude)) {
const fileState = await fileManager.getState(file, true);
if (fileState) {
for (const func of entry.functions) {
for (const range of func.ranges) {
try {
const start = getLineColumn(fileState.lines, range.startOffset);
const end = getLineColumn(fileState.lines, range.endOffset);
if (!start || !end) {
throw new Error("Error searching for line and column");
}
const maxLine = Math.min(end.line, fileState.lines.length - 1);
for (let i = start.line; i <= maxLine; i++) {
fileState.lines[i].count(i === start.line ? start.column : 0, i === end.line ? end.column : null, range.count);
}
if (fileState.sourceMap && !fileState.error) {
let sourceFile = null;
try {
const sourceMap = new Module.SourceMap(fileState.sourceMap);
const sourceStart = findOrigin(sourceMap, start.line, start.column);
const sourceEnd = findOrigin(sourceMap, end.line, end.column);
if (!sourceStart.originalSource && sourceEnd.originalSource && start.line === 0) {
const sourceFile = fileState.sourceMap.sources[0];
if (sourceFile) {
sourceStart.originalSource = sourceFile;
sourceStart.originalLine = 0;
sourceStart.originalColumn = 0;
}
}
if (sourceStart.originalSource && sourceStart.originalSource === sourceEnd.originalSource) {
sourceFile = sourceStart.originalSource;
if (!options.excludeFiles.includes(sourceFile) && !(0, utils_1.testRegex)(sourceFile, options.exclude)) {
if (options.sourceMaps) {
const sourceFileState = await fileManager.getState(sourceFile, false);
if (sourceFileState) {
const maxLine = Math.min(sourceEnd.originalLine, sourceFileState.lines.length - 1);
for (let i = sourceStart.originalLine; i <= maxLine; i++) {
sourceFileState.lines[i].count(i === sourceStart.originalLine ? sourceStart.originalColumn : 0, i === sourceEnd.originalLine ? sourceEnd.originalColumn : null, range.count);
}
}
fileManager.deleteState(file);
}
else {
fileManager.deleteState(sourceFile);
}
}
else {
fileManager.deleteState(file);
}
}
}
catch (e) {
fileState.error = String(e);
if (sourceFile) {
fileManager.deleteState(sourceFile);
}
}
}
}
catch (e) {
fileState.error = String(e);
}
}
}
}
}
}
}
catch (e) { }
}
return fileManager.summary(options.branches);
}