UNPKG

stryker

Version:
201 lines 9.62 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _ = require("lodash"); var TestableMutant_1 = require("../TestableMutant"); var objectUtils_1 = require("../utils/objectUtils"); var SourceFile_1 = require("../SourceFile"); var LocationHelper_1 = require("../utils/LocationHelper"); var plugin_1 = require("stryker-api/plugin"); var di_1 = require("../di"); var StatementIndexKind; (function (StatementIndexKind) { StatementIndexKind[StatementIndexKind["function"] = 0] = "function"; StatementIndexKind[StatementIndexKind["statement"] = 1] = "statement"; })(StatementIndexKind || (StatementIndexKind = {})); var MutantTestMatcher = /** @class */ (function () { function MutantTestMatcher(log, options, reporter, input, initialRunResult) { this.log = log; this.options = options; this.reporter = reporter; this.input = input; this.initialRunResult = initialRunResult; } Object.defineProperty(MutantTestMatcher.prototype, "baseline", { get: function () { if (this.isCoveragePerTestResult(this.initialRunResult.runResult.coverage)) { return this.initialRunResult.runResult.coverage.baseline; } else { return null; } }, enumerable: true, configurable: true }); MutantTestMatcher.prototype.matchWithMutants = function (mutants) { var _this = this; var testableMutants = this.createTestableMutants(mutants); if (this.options.coverageAnalysis === 'off') { testableMutants.forEach(function (mutant) { return mutant.selectAllTests(_this.initialRunResult.runResult, TestableMutant_1.TestSelectionResult.Success); }); } else if (!this.initialRunResult.runResult.coverage) { this.log.warn('No coverage result found, even though coverageAnalysis is "%s". Assuming that all tests cover each mutant. This might have a big impact on the performance.', this.options.coverageAnalysis); testableMutants.forEach(function (mutant) { return mutant.selectAllTests(_this.initialRunResult.runResult, TestableMutant_1.TestSelectionResult.FailedButAlreadyReported); }); } else { testableMutants.forEach(function (testableMutant) { return _this.enrichWithCoveredTests(testableMutant); }); } this.reporter.onAllMutantsMatchedWithTests(Object.freeze(testableMutants.map(this.mapMutantOnMatchedMutant))); return testableMutants; }; MutantTestMatcher.prototype.enrichWithCoveredTests = function (testableMutant) { var _this = this; var transpiledLocation = this.initialRunResult.sourceMapper.transpiledLocationFor({ fileName: testableMutant.mutant.fileName, location: testableMutant.location }); var fileCoverage = this.initialRunResult.coverageMaps[transpiledLocation.fileName]; var statementIndex = this.findMatchingStatement(new LocationHelper_1.default(transpiledLocation.location), fileCoverage); if (statementIndex) { if (this.isCoveredByBaseline(transpiledLocation.fileName, statementIndex)) { testableMutant.selectAllTests(this.initialRunResult.runResult, TestableMutant_1.TestSelectionResult.Success); } else { this.initialRunResult.runResult.tests.forEach(function (testResult, id) { if (_this.isCoveredByTest(id, transpiledLocation.fileName, statementIndex)) { testableMutant.selectTest(testResult, id); } }); } } else { // Could not find a statement corresponding to this mutant // This can happen when for example mutating a TypeScript interface // It should result in an early result during mutation testing // Lets delay error reporting for now testableMutant.selectAllTests(this.initialRunResult.runResult, TestableMutant_1.TestSelectionResult.Failed); } }; MutantTestMatcher.prototype.isCoveredByBaseline = function (fileName, statementIndex) { if (this.baseline) { var coverageResult = this.baseline[fileName]; return this.isCoveredByCoverageCollection(coverageResult, statementIndex); } else { return false; } }; MutantTestMatcher.prototype.isCoveredByTest = function (testId, fileName, statementIndex) { var coverageCollection = this.findCoverageCollectionForTest(testId); var coveredFile = coverageCollection && coverageCollection[fileName]; return this.isCoveredByCoverageCollection(coveredFile, statementIndex); }; MutantTestMatcher.prototype.isCoveredByCoverageCollection = function (coveredFile, statementIndex) { if (coveredFile) { if (statementIndex.kind === StatementIndexKind.statement) { return coveredFile.s[statementIndex.index] > 0; } else { return coveredFile.f[statementIndex.index] > 0; } } else { return false; } }; MutantTestMatcher.prototype.createTestableMutants = function (mutants) { var _this = this; var sourceFiles = this.input.filesToMutate.map(function (file) { return new SourceFile_1.default(file); }); return objectUtils_1.filterEmpty(mutants.map(function (mutant, index) { var sourceFile = sourceFiles.find(function (file) { return file.name === mutant.fileName; }); if (sourceFile) { return new TestableMutant_1.default(index.toString(), mutant, sourceFile); } else { _this.log.error("Mutant \"" + mutant.mutatorName + mutant.replacement + "\" is corrupt, because cannot find a text file with name " + mutant.fileName + ". List of source files: \n\t" + sourceFiles.map(function (s) { return s.name; }).join('\n\t')); return null; } })); }; /** * Map the Mutant object on the MatchMutant Object. * @param testableMutant The mutant. * @returns The MatchedMutant */ MutantTestMatcher.prototype.mapMutantOnMatchedMutant = function (testableMutant) { var matchedMutant = _.cloneDeep({ fileName: testableMutant.mutant.fileName, id: testableMutant.id, mutatorName: testableMutant.mutant.mutatorName, replacement: testableMutant.mutant.replacement, scopedTestIds: testableMutant.selectedTests.map(function (testSelection) { return testSelection.id; }), timeSpentScopedTests: testableMutant.timeSpentScopedTests, }); return Object.freeze(matchedMutant); }; MutantTestMatcher.prototype.findMatchingStatement = function (location, fileCoverage) { var statementIndex = this.findMatchingStatementInMap(location, fileCoverage.statementMap); if (statementIndex) { return { index: statementIndex, kind: StatementIndexKind.statement }; } else { var functionIndex = this.findMatchingStatementInMap(location, fileCoverage.fnMap); if (functionIndex) { return { index: functionIndex, kind: StatementIndexKind.function }; } else { return null; } } }; /** * Finds the smallest statement that covers a location * @param needle The location to find. * @param haystack the statement map or function map to search in. * @returns The index of the smallest statement surrounding the location, or null if not found. */ MutantTestMatcher.prototype.findMatchingStatementInMap = function (needle, haystack) { var smallestStatement = { index: null, location: LocationHelper_1.default.MAX_VALUE }; if (haystack) { Object.keys(haystack).forEach(function (statementId) { var statementLocation = haystack[statementId]; if (needle.isCoveredBy(statementLocation) && smallestStatement.location.isSmallerArea(statementLocation)) { smallestStatement = { index: statementId, location: new LocationHelper_1.default(statementLocation) }; } }); } return smallestStatement.index; }; MutantTestMatcher.prototype.findCoverageCollectionForTest = function (testId) { if (this.initialRunResult.runResult.coverage) { if (this.isCoveragePerTestResult(this.initialRunResult.runResult.coverage)) { return this.initialRunResult.runResult.coverage.deviations[testId]; } else { return this.initialRunResult.runResult.coverage; } } else { return null; } }; MutantTestMatcher.prototype.isCoveragePerTestResult = function (_coverage) { return this.options.coverageAnalysis === 'perTest'; }; MutantTestMatcher.inject = plugin_1.tokens(plugin_1.commonTokens.logger, plugin_1.commonTokens.options, di_1.coreTokens.reporter, di_1.coreTokens.inputFiles, di_1.coreTokens.initialRunResult); return MutantTestMatcher; }()); exports.MutantTestMatcher = MutantTestMatcher; //# sourceMappingURL=MutantTestMatcher.js.map