UNPKG

cbfl

Version:

library that can be used to automatically find points of failure in TypeScript Modules that are tested with Mocha

151 lines (150 loc) 6.51 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (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 (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.FaultLocalizations = void 0; const fs = __importStar(require("fs")); class FaultLocalizations { constructor() { this.faultyFiles = new Map(); this.failedTests = new Map(); } getOrCreateFaultyFile(coverage, changedLineCoveragePath) { return (this.faultyFiles.get(changedLineCoveragePath) || this.createFaultyFile(coverage, changedLineCoveragePath)); } createFaultyFile(coverage, changedLineCoveragePath) { const functionMap = this.createFunctionMap(coverage); const faultyFile = { path: coverage.path, lines: new Map(Object.keys(coverage.s).map((statementNumber) => [ parseInt(statementNumber) + 1, new Set(), ]) // the line numbers that are put out are just the statements ), statements: new Map(Object.keys(coverage.s).map((statementNumber) => [ parseInt(statementNumber), new Set(), ])), functions: new Map(Object.keys(coverage.f).map((functionID) => [ parseInt(functionID), new Set(), ])), functionMap, }; this.faultyFiles.set(changedLineCoveragePath, faultyFile); return faultyFile; } createFunctionMap(coverage) { return new Map(Object.keys(coverage.fnMap).map((functionID) => { const info = coverage.fnMap[functionID]; return [ parseInt(functionID), { start: info.decl.start, end: info.decl.end, name: info.name }, ]; })); } addFailedTest(path, name) { this.failedTests.set(path, { name }); } addFailedLine(coverage, changedLineCoveragePath, lineNumber, failedTestPath) { var _a, _b, _c; const faultyFile = this.getOrCreateFaultyFile(coverage, changedLineCoveragePath); (_a = faultyFile.lines.get(lineNumber)) === null || _a === void 0 ? void 0 : _a.add(failedTestPath); (_b = faultyFile.statements.get(lineNumber - 1)) === null || _b === void 0 ? void 0 : _b.add(failedTestPath); (_c = faultyFile.functions .get(this.getFunctionIDForLineNumber(lineNumber, faultyFile))) === null || _c === void 0 ? void 0 : _c.add(failedTestPath); } getFunctionIDForLineNumber(lineNumber, faultyFile) { let functionID = -1; faultyFile.functionMap.forEach((info, id) => (functionID = lineNumber >= info.start.line && lineNumber <= info.end.line ? id : functionID)); return functionID; } generateComment() { var _a; let comment = ""; for (const [faultyFilePath, faultyFile] of this.faultyFiles) { for (const [lineNumber, failedTests] of faultyFile.lines) { if (failedTests.size === 1) { const failedTestPath = failedTests.values().next().value; comment += `\nThe failed Test ${(_a = this.failedTests.get(failedTestPath)) === null || _a === void 0 ? void 0 : _a.name} from the file "${failedTestPath}" ran through the line ${lineNumber} of the file ${faultyFilePath} which was changed recently changed.`; } else if (failedTests.size > 1) { const failedTestsPaths = [...failedTests]; const failedTestsDescriptions = failedTestsPaths.map((failedTestPath) => { var _a; return `<li>**${((_a = this.failedTests.get(failedTestPath)) === null || _a === void 0 ? void 0 : _a.name) || ""}** (${failedTestPath})</li>`; }); const failedTestsBlock = failedTestsDescriptions.reduce((prev, curr) => prev + curr, ""); comment += `The failed Tests <ul> ${failedTestsBlock} </ul> ran through the **line ${lineNumber}** of the file ${faultyFilePath} which was recently changed.`; console.log(failedTestsPaths); } } } return comment; } async saveToFile(commitID) { const data = { faultyFiles: this.faultyFiles, failedTests: this.failedTests, }; const serialized = JSON.stringify(data, FaultLocalizations.replacer); const path = "./faultLocalizations"; const filePath = `${path}/${commitID}.json`; fs.mkdir(path, { recursive: true }, function (err) { if (err) return console.log(err); return fs.promises.writeFile(filePath, serialized, "utf8"); }); return Promise.resolve(); } static replacer(key, value) { if (value instanceof Map) { return { dataType: "Map", value: Array.from(value.entries()), // or with spread: value: [...value] }; } else if (value instanceof Set) { return { dataType: "Set", value: Array.from(value.values()), // or with spread: value: [...value] }; } else { return value; } } static reviver(key, value) { if (typeof value === "object" && value !== null) { if (value.dataType === "Map") { return new Map(value.value); } if (value.dataType === "Set") { return new Set(value.value); } } return value; } } exports.FaultLocalizations = FaultLocalizations;