Comparing version 0.5.9 to 0.6.0-0
{ | ||
"name": "stryker", | ||
"version": "0.5.9", | ||
"version": "0.6.0-0", | ||
"description": "The extendable JavaScript mutation testing framework", | ||
@@ -115,3 +115,3 @@ "main": "src/Stryker.js", | ||
"sinon-chai": "^2.8.0", | ||
"stryker-api": "^0.4.2", | ||
"stryker-api": "^0.5.0-0", | ||
"tslint": "^4.4.2", | ||
@@ -121,4 +121,4 @@ "typescript": "~2.2.1" | ||
"peerDependencies": { | ||
"stryker-api": "^0.4.2" | ||
"stryker-api": "^0.5.0-0" | ||
} | ||
} |
@@ -6,3 +6,3 @@ [![Build Status](https://travis-ci.org/stryker-mutator/stryker.svg?branch=master)](https://travis-ci.org/stryker-mutator/stryker) | ||
![Stryker](stryker-80x80.png) | ||
![Stryker](https://github.com/stryker-mutator/stryker/raw/master/stryker-80x80.png) | ||
@@ -9,0 +9,0 @@ # Stryker |
@@ -44,3 +44,3 @@ "use strict"; | ||
log.debug("Adding test hooks file for coverageAnalysis \"perTest\""); | ||
return objectUtils_1.wrapInClosure("\n var id = 0, coverageStateAtStart;\n window.__coverage__ = globalCoverage = {};\n " + this.testFramework.beforeEach(beforeEachFragmentPerTest) + "\n " + this.testFramework.afterEach(afterEachFragmentPerTest) + "\n " + cloneFunctionFragment + ";\n "); | ||
return objectUtils_1.wrapInClosure("\n var id = 0;\n window.__coverage__ = globalCoverage = { deviations: {} };\n " + this.testFramework.beforeEach(beforeEachFragmentPerTest) + "\n " + this.testFramework.afterEach(afterEachFragmentPerTest) + "\n " + cloneFunctionFragment + ";\n "); | ||
} | ||
@@ -66,5 +66,5 @@ else { | ||
exports.default = CoverageInstrumenter; | ||
var cloneFunctionFragment = " \n function clone(source) {\n var result = source;\n if (Array.isArray(source)) {\n result = [];\n source.forEach(function (child, index) {\n result[index] = clone(child);\n });\n } else if (typeof source == \"object\") {\n // it is an object literal\n result = {};\n for (var i in source) {\n result[i] = clone(source[i]);\n }\n }\n return result;\n }"; | ||
var beforeEachFragmentPerTest = "\nif (!coverageStateAtStart && window." + COVERAGE_CURRENT_TEST_VARIABLE_NAME + ") {\n coverageStateAtStart = clone(window." + COVERAGE_CURRENT_TEST_VARIABLE_NAME + ");\n}"; | ||
var afterEachFragmentPerTest = "\n globalCoverage[id] = coverageResult = {};\n id++;\n var coveragePerTest = window." + COVERAGE_CURRENT_TEST_VARIABLE_NAME + ";\n if(window." + COVERAGE_CURRENT_TEST_VARIABLE_NAME + ") {\n Object.keys(coveragePerTest).forEach(function (file) {\n var coverage = coveragePerTest[file];\n coverageResult[file] = { s: coverage.s };\n coverage.s = clone(coverageStateAtStart[file].s);\n });\n }"; | ||
var cloneFunctionFragment = " \n function clone(source) {\n var result = source;\n if (Array.isArray(source)) {\n result = [];\n source.forEach(function (child, index) {\n result[index] = clone(child);\n });\n } else if (typeof source == \"object\") {\n result = {};\n for (var i in source) {\n result[i] = clone(source[i]);\n }\n }\n return result;\n }"; | ||
var beforeEachFragmentPerTest = "\nif (!globalCoverage.baseline && window." + COVERAGE_CURRENT_TEST_VARIABLE_NAME + ") {\n globalCoverage.baseline = clone(window." + COVERAGE_CURRENT_TEST_VARIABLE_NAME + ");\n}"; | ||
var afterEachFragmentPerTest = "\n globalCoverage.deviations[id] = coverageResult = {};\n id++;\n var coveragePerFile = window." + COVERAGE_CURRENT_TEST_VARIABLE_NAME + ";\n if(coveragePerFile) {\n Object.keys(coveragePerFile).forEach(function (file) {\n var coverage = coveragePerFile[file];\n var baseline = globalCoverage.baseline[file];\n var fileResult = { s: {} };\n var touchedFile = false;\n for(var i in coverage.s){\n if(coverage.s[i] !== baseline.s[i]){\n fileResult.s[i] = coverage.s[i];\n touchedFile = true;\n }\n }\n if(touchedFile){\n coverageResult[file] = fileResult;\n }\n });\n }"; | ||
//# sourceMappingURL=CoverageInstrumenter.js.map |
/// <reference types="node" /> | ||
import { StatementMap } from 'stryker-api/test_runner'; | ||
import { Transform, TransformOptions } from 'stream'; | ||
import 'stryker-api/estree'; | ||
/** | ||
@@ -6,0 +5,0 @@ * Represents a stream responsible to add code coverage instrumentation and reporting back on the statement map |
@@ -7,3 +7,2 @@ "use strict"; | ||
var log4js = require("log4js"); | ||
require("stryker-api/estree"); | ||
var coverageObjRegex = /\{.*"path".*"fnMap".*"statementMap".*"branchMap".*\}/g; | ||
@@ -10,0 +9,0 @@ var log = log4js.getLogger('CoverageInstrumenterStream'); |
import { Location, Range } from 'stryker-api/core'; | ||
import { TestResult } from 'stryker-api/test_runner'; | ||
import { TestResult, RunResult } from 'stryker-api/test_runner'; | ||
/** | ||
@@ -18,2 +18,3 @@ * Represents a mutation which has been applied to a file. | ||
readonly timeSpentScopedTests: number; | ||
addAllTestResults(runResult: RunResult): void; | ||
addTestResult(index: number, testResult: TestResult): void; | ||
@@ -44,2 +45,3 @@ /** | ||
reset(filename: string): Promise<void>; | ||
toString(): string; | ||
} |
@@ -41,2 +41,6 @@ "use strict"; | ||
}); | ||
Mutant.prototype.addAllTestResults = function (runResult) { | ||
var _this = this; | ||
runResult.tests.forEach(function (testResult, id) { return _this.addTestResult(id, testResult); }); | ||
}; | ||
Mutant.prototype.addTestResult = function (index, testResult) { | ||
@@ -99,2 +103,5 @@ this._scopedTestIds.push(index); | ||
; | ||
Mutant.prototype.toString = function () { | ||
return this.mutatorName + " (" + this.filename + "@" + this.location.start.line + ":" + this.location.start.column + ")"; | ||
}; | ||
return Mutant; | ||
@@ -101,0 +108,0 @@ }()); |
@@ -13,3 +13,6 @@ import Mutant from './Mutant'; | ||
constructor(mutants: Mutant[], initialRunResult: RunResult, statementMaps: StatementMapDictionary, options: StrykerOptions, reporter: StrictReporter); | ||
private readonly baseline; | ||
matchWithMutants(): void; | ||
private isCoveredByBaseline(filename, statementId); | ||
private isCoveredByTest(testId, filename, statementId); | ||
/** | ||
@@ -43,3 +46,3 @@ * Map the Mutant object on the MatchMutant Object. | ||
private findCoverageCollectionForTest(testId); | ||
private isCoverageCollectionPerTest(coverage); | ||
private isCoveragePerTestResult(coverage); | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var log4js = require("log4js"); | ||
var _ = require("lodash"); | ||
var log = log4js.getLogger('MutantTestMatcher'); | ||
var MutantTestMatcher = (function () { | ||
@@ -12,27 +14,60 @@ function MutantTestMatcher(mutants, initialRunResult, statementMaps, options, reporter) { | ||
} | ||
Object.defineProperty(MutantTestMatcher.prototype, "baseline", { | ||
get: function () { | ||
if (this.isCoveragePerTestResult(this.initialRunResult.coverage)) { | ||
return this.initialRunResult.coverage.baseline; | ||
} | ||
else { | ||
return null; | ||
} | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
MutantTestMatcher.prototype.matchWithMutants = function () { | ||
var _this = this; | ||
this.mutants.forEach(function (mutant) { | ||
var statementMap = _this.statementMaps[mutant.filename]; | ||
var smallestStatement = _this.findSmallestCoveringStatement(mutant, statementMap); | ||
_this.initialRunResult.tests.forEach(function (testResult, id) { | ||
var covered = false; | ||
var coverageCollection = _this.findCoverageCollectionForTest(id); | ||
if (coverageCollection && smallestStatement) { | ||
var coveredFile = coverageCollection[mutant.filename]; | ||
if (coveredFile) { | ||
covered = coveredFile.s[smallestStatement] > 0; | ||
if (this.options.coverageAnalysis === 'off') { | ||
this.mutants.forEach(function (mutant) { return mutant.addAllTestResults(_this.initialRunResult); }); | ||
} | ||
else if (!this.initialRunResult.coverage) { | ||
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); | ||
this.mutants.forEach(function (mutant) { return mutant.addAllTestResults(_this.initialRunResult); }); | ||
} | ||
else | ||
this.mutants.forEach(function (mutant) { | ||
var statementMap = _this.statementMaps[mutant.filename]; | ||
var smallestStatement = _this.findSmallestCoveringStatement(mutant, statementMap); | ||
if (smallestStatement) { | ||
if (_this.isCoveredByBaseline(mutant.filename, smallestStatement)) { | ||
mutant.addAllTestResults(_this.initialRunResult); | ||
} | ||
else { | ||
_this.initialRunResult.tests.forEach(function (testResult, id) { | ||
if (_this.isCoveredByTest(id, mutant.filename, smallestStatement)) { | ||
mutant.addTestResult(id, testResult); | ||
} | ||
}); | ||
} | ||
} | ||
else { | ||
// If there is no coverage data we have to assume that the test covers the mutant | ||
covered = true; | ||
log.warn('Cannot find statement for mutant %s in statement map for file. Assuming that all tests cover this mutant. This might have a big impact on the performance.', mutant.toString()); | ||
mutant.addAllTestResults(_this.initialRunResult); | ||
} | ||
if (covered) { | ||
mutant.addTestResult(id, testResult); | ||
} | ||
}); | ||
}); | ||
this.reporter.onAllMutantsMatchedWithTests(Object.freeze(this.mutants.map(this.mapMutantOnMatchedMutant))); | ||
}; | ||
MutantTestMatcher.prototype.isCoveredByBaseline = function (filename, statementId) { | ||
if (this.baseline) { | ||
var coverageCollection = this.baseline[filename]; | ||
return coverageCollection && coverageCollection.s[statementId] > 0; | ||
} | ||
else { | ||
return false; | ||
} | ||
}; | ||
MutantTestMatcher.prototype.isCoveredByTest = function (testId, filename, statementId) { | ||
var coverageCollection = this.findCoverageCollectionForTest(testId); | ||
var coveredFile = coverageCollection && coverageCollection[filename]; | ||
return coveredFile && coveredFile.s[statementId] > 0; | ||
}; | ||
/** | ||
@@ -108,4 +143,4 @@ * Map the Mutant object on the MatchMutant Object. | ||
if (this.initialRunResult.coverage) { | ||
if (this.isCoverageCollectionPerTest(this.initialRunResult.coverage)) { | ||
return this.initialRunResult.coverage[testId]; | ||
if (this.isCoveragePerTestResult(this.initialRunResult.coverage)) { | ||
return this.initialRunResult.coverage.deviations[testId]; | ||
} | ||
@@ -120,3 +155,3 @@ else { | ||
}; | ||
MutantTestMatcher.prototype.isCoverageCollectionPerTest = function (coverage) { | ||
MutantTestMatcher.prototype.isCoveragePerTestResult = function (coverage) { | ||
return this.options.coverageAnalysis === 'perTest'; | ||
@@ -123,0 +158,0 @@ }; |
@@ -47,3 +47,3 @@ "use strict"; | ||
var abstractSyntaxTree = parserUtils.parse(fileContent); | ||
var nodes = parserUtils.collectFrozenNodes(abstractSyntaxTree); | ||
var nodes = new parserUtils.NodeIdentifier().identifyAndFreeze(abstractSyntaxTree); | ||
var newMutants = _this.findMutants(sourceFile, fileContent, abstractSyntaxTree, nodes); | ||
@@ -50,0 +50,0 @@ mutants = mutants.concat(newMutants); |
@@ -1,3 +0,2 @@ | ||
import { Mutator } from 'stryker-api/mutant'; | ||
import * as estree from 'estree'; | ||
import { Mutator, IdentifiedNode } from 'stryker-api/mutant'; | ||
/** | ||
@@ -9,3 +8,3 @@ * Represents a mutator which can remove the content of an array's elements. | ||
constructor(); | ||
applyMutations(node: estree.Node, copy: <T>(obj: T, deep?: boolean) => T): void | estree.Node | estree.Node[]; | ||
applyMutations(node: IdentifiedNode, copy: <T>(obj: T, deep?: boolean) => T): void | IdentifiedNode; | ||
} |
@@ -1,3 +0,2 @@ | ||
import { Mutator } from 'stryker-api/mutant'; | ||
import * as estree from 'estree'; | ||
import { Mutator, IdentifiedNode } from 'stryker-api/mutant'; | ||
export default class BinaryOperatorMutator implements Mutator { | ||
@@ -7,3 +6,3 @@ name: string; | ||
private operators; | ||
applyMutations(node: estree.Node, copy: <T>(obj: T, deep?: boolean) => T): estree.Node[]; | ||
applyMutations(node: IdentifiedNode, copy: <T>(obj: T, deep?: boolean) => T): IdentifiedNode[]; | ||
} |
@@ -1,3 +0,2 @@ | ||
import { Mutator } from 'stryker-api/mutant'; | ||
import * as estree from 'estree'; | ||
import { Mutator, IdentifiedNode } from 'stryker-api/mutant'; | ||
/** | ||
@@ -10,3 +9,3 @@ * Represents a mutator which can remove the content of a BlockStatement. | ||
constructor(); | ||
applyMutations(node: estree.Node, copy: <T>(obj: T, deep?: boolean) => T): void | estree.Node | estree.Node[]; | ||
applyMutations(node: IdentifiedNode, copy: <T>(obj: T, deep?: boolean) => T): void | IdentifiedNode; | ||
} |
@@ -1,3 +0,2 @@ | ||
import { Mutator } from 'stryker-api/mutant'; | ||
import * as estree from 'estree'; | ||
import { Mutator, IdentifiedNode } from 'stryker-api/mutant'; | ||
export default class LogicalOperatorMutator implements Mutator { | ||
@@ -7,3 +6,3 @@ name: string; | ||
private operators; | ||
applyMutations(node: estree.Node, copy: <T>(obj: T, deep?: boolean) => T): estree.Node[]; | ||
applyMutations(node: IdentifiedNode, copy: <T>(obj: T, deep?: boolean) => T): IdentifiedNode[]; | ||
} |
@@ -1,3 +0,2 @@ | ||
import { Mutator } from 'stryker-api/mutant'; | ||
import * as estree from 'estree'; | ||
import { Mutator, IdentifiedNode } from 'stryker-api/mutant'; | ||
/** | ||
@@ -10,5 +9,5 @@ * Represents a mutator which can remove the conditional clause from statements. | ||
constructor(); | ||
applyMutations(node: estree.Node, copy: <T>(obj: T, deep?: boolean) => T): estree.Node[] | void; | ||
applyMutations(node: IdentifiedNode, copy: <T>(obj: T, deep?: boolean) => T): IdentifiedNode[] | void; | ||
private booleanLiteralNode(nodeID, value); | ||
private canMutate(node); | ||
} |
@@ -1,3 +0,2 @@ | ||
import { Mutator } from 'stryker-api/mutant'; | ||
import * as estree from 'estree'; | ||
import { Mutator, IdentifiedNode } from 'stryker-api/mutant'; | ||
export default class UnaryOperatorMutator implements Mutator { | ||
@@ -7,3 +6,3 @@ name: string; | ||
private operators; | ||
applyMutations(node: estree.Node, copy: <T>(obj: T, deep?: boolean) => T): estree.Node[]; | ||
applyMutations(node: IdentifiedNode, copy: <T>(obj: T, deep?: boolean) => T): IdentifiedNode[]; | ||
} |
@@ -1,3 +0,2 @@ | ||
import { Mutator } from 'stryker-api/mutant'; | ||
import * as estree from 'estree'; | ||
import { Mutator, IdentifiedNode } from 'stryker-api/mutant'; | ||
export default class UpdateOperatorMutator implements Mutator { | ||
@@ -7,3 +6,3 @@ name: string; | ||
private operators; | ||
applyMutations(node: estree.Node, copy: <T>(obj: T, deep?: boolean) => T): void | estree.Node | estree.Node[]; | ||
applyMutations(node: IdentifiedNode, copy: <T>(obj: T, deep?: boolean) => T): void | IdentifiedNode; | ||
} |
@@ -204,3 +204,3 @@ 'use strict'; | ||
Stryker.prototype.logTimeoutInitialRun = function (runResult) { | ||
var message = 'Initial run timed out! Ran following tests before timeout:'; | ||
var message = 'Initial test run timed out! Ran following tests before timeout:'; | ||
runResult.tests.forEach(function (test) { return "\n\t" + test.name + " " + humanReadableTestState(test.status); }); | ||
@@ -207,0 +207,0 @@ log.error(message); |
import * as estree from 'estree'; | ||
import { IdentifiedNode, Identified } from 'stryker-api/mutant'; | ||
/** | ||
@@ -10,9 +11,2 @@ * Parses code to generate an Abstract Syntax Tree. | ||
/** | ||
* Finds all nodes which have a 'type' property and freezes them. | ||
* @function | ||
* @param abstractSyntaxTree - The current part of the abstract syntax tree which will be investigated. | ||
* @returns All nodes with a type. | ||
*/ | ||
export declare function collectFrozenNodes(abstractSyntaxTree: estree.Node, nodes?: estree.Node[]): estree.Node[]; | ||
/** | ||
* Parses a Node to generate code. | ||
@@ -23,1 +17,18 @@ * @param The Node which has to be transformed into code. | ||
export declare function generate(node: estree.Node): string; | ||
/** | ||
* Returns n as T & Identified, purely syntactic. | ||
* @param n The estree node which is identified | ||
*/ | ||
export declare function identified<T extends estree.Node>(n: T): T & Identified; | ||
/** | ||
* Represents an object responsible to identify estree nodes (estree.Node). | ||
* Labels all nodes with a `nodeID` recursively. | ||
*/ | ||
export declare class NodeIdentifier { | ||
private identifiedNodes; | ||
identifyAndFreeze(program: estree.Program): Readonly<IdentifiedNode>[]; | ||
private identifyAndFreezeRecursively(maybeNode); | ||
private isNode(maybeNode); | ||
private isIdentified(node); | ||
private identify(node); | ||
} |
@@ -32,31 +32,2 @@ "use strict"; | ||
/** | ||
* Finds all nodes which have a 'type' property and freezes them. | ||
* @function | ||
* @param abstractSyntaxTree - The current part of the abstract syntax tree which will be investigated. | ||
* @returns All nodes with a type. | ||
*/ | ||
function collectFrozenNodes(abstractSyntaxTree, nodes) { | ||
nodes = nodes || []; | ||
if (!_.isArray(abstractSyntaxTree) && _.isObject(abstractSyntaxTree) && abstractSyntaxTree.type && _.isUndefined(abstractSyntaxTree.nodeID)) { | ||
abstractSyntaxTree.nodeID = nodes.length; | ||
nodes.push(abstractSyntaxTree); | ||
} | ||
Object.freeze(abstractSyntaxTree); | ||
_.forOwn(abstractSyntaxTree, function (childNode, i) { | ||
if (childNode instanceof Object && !(childNode instanceof Array)) { | ||
collectFrozenNodes(childNode, nodes); | ||
} | ||
else if (childNode instanceof Array) { | ||
_.forEach(childNode, function (arrayChild) { | ||
if (arrayChild instanceof Object && !(arrayChild instanceof Array)) { | ||
collectFrozenNodes(arrayChild, nodes); | ||
} | ||
}); | ||
} | ||
}); | ||
return nodes; | ||
} | ||
exports.collectFrozenNodes = collectFrozenNodes; | ||
; | ||
/** | ||
* Parses a Node to generate code. | ||
@@ -71,2 +42,55 @@ * @param The Node which has to be transformed into code. | ||
; | ||
/** | ||
* Returns n as T & Identified, purely syntactic. | ||
* @param n The estree node which is identified | ||
*/ | ||
function identified(n) { | ||
return n; | ||
} | ||
exports.identified = identified; | ||
/** | ||
* Represents an object responsible to identify estree nodes (estree.Node). | ||
* Labels all nodes with a `nodeID` recursively. | ||
*/ | ||
var NodeIdentifier = (function () { | ||
function NodeIdentifier() { | ||
this.identifiedNodes = []; | ||
} | ||
NodeIdentifier.prototype.identifyAndFreeze = function (program) { | ||
this.identifiedNodes = []; | ||
this.identifyAndFreezeRecursively(program); | ||
return this.identifiedNodes; | ||
}; | ||
NodeIdentifier.prototype.identifyAndFreezeRecursively = function (maybeNode) { | ||
var _this = this; | ||
if (this.isNode(maybeNode)) { | ||
if (!this.isIdentified(maybeNode)) { | ||
this.identify(maybeNode); | ||
} | ||
Object.freeze(maybeNode); | ||
_.forOwn(maybeNode, function (childNode) { | ||
_this.identifyAndFreezeRecursively(childNode); | ||
}); | ||
} | ||
else if (Array.isArray(maybeNode)) { | ||
maybeNode.forEach(function (grandChild) { | ||
_this.identifyAndFreezeRecursively(grandChild); | ||
}); | ||
} | ||
}; | ||
NodeIdentifier.prototype.isNode = function (maybeNode) { | ||
return !_.isArray(maybeNode) && _.isObject(maybeNode) && maybeNode.type; | ||
}; | ||
NodeIdentifier.prototype.isIdentified = function (node) { | ||
var n = node; | ||
return _.isNumber(n.nodeID); | ||
}; | ||
NodeIdentifier.prototype.identify = function (node) { | ||
var n = node; | ||
n.nodeID = this.identifiedNodes.length; | ||
this.identifiedNodes.push(n); | ||
}; | ||
return NodeIdentifier; | ||
}()); | ||
exports.NodeIdentifier = NodeIdentifier; | ||
//# sourceMappingURL=parserUtils.js.map |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
3988
0
316969
147