New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

stryker

Package Overview
Dependencies
Maintainers
2
Versions
107
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

stryker - npm Package Compare versions

Comparing version 0.1.0 to 0.2.0

dist/src/api/core/InputFile.d.ts

1

dist/src/api/core.d.ts
export { default as StrykerOptions } from './core/StrykerOptions';
export { default as Factory } from './core/Factory';
export { default as InputFile } from './core/InputFile';

60

dist/src/api/test_runner/Coverage.d.ts

@@ -1,12 +0,23 @@

export interface Position {
line: number;
column: number;
export interface CoverageCollection {
[fileName: string]: CoverageResult;
}
export interface Location {
start: Position;
end: Position;
export interface CoverageResult {
s: CoverageData;
b?: BrancheCoverageData;
f?: CoverageData;
l?: CoverageData;
fnMap?: FunctionMap;
branchMap?: BranchMap;
statementMap: StatementMap;
path?: string;
}
export interface StatementMap {
[ref: number]: Location;
export interface CoverageData {
[ref: string]: number;
}
export interface BrancheCoverageData {
[ref: string]: [number, number];
}
export interface FunctionMap {
[ref: string]: FunctionDescription;
}
export interface FunctionDescription {

@@ -17,2 +28,5 @@ name: string;

}
export interface BranchMap {
[ref: string]: BranchDescription;
}
export interface BranchDescription {

@@ -23,26 +37,12 @@ line: number;

}
export interface BranchMap {
[ref: string]: BranchDescription;
export interface StatementMap {
[ref: string]: Location;
}
export interface FunctionMap {
[ref: string]: FunctionDescription;
export interface Location {
start: Position;
end: Position;
}
export interface CoverageData {
[ref: string]: number;
export interface Position {
line: number;
column: number;
}
export interface BrancheCoverageData {
[ref: string]: [number, number];
}
export interface CoverageResult {
s: CoverageData;
b?: BrancheCoverageData;
f?: CoverageData;
l?: CoverageData;
fnMap?: FunctionMap;
branchMap?: BranchMap;
statementMap: StatementMap;
path?: string;
}
export interface CoverageCollection {
[fileName: string]: CoverageResult;
}

@@ -1,5 +0,4 @@

import { StrykerOptions } from '../core';
import { StrykerOptions, InputFile } from '../core';
interface RunnerOptions {
sourceFiles: string[];
additionalFiles: string[];
files: InputFile[];
port: number;

@@ -6,0 +5,0 @@ strykerOptions: StrykerOptions;

@@ -10,3 +10,4 @@ import { CoverageCollection } from './Coverage';

coverage?: CoverageCollection;
errorMessages?: string[];
}
export default RunResult;
declare var _default: {
createRandomFolder: (prefix: string) => string;
writeFile: (fileName: string, data: string) => Promise<void>;
copyFile: (fromFileName: string, toFileName: string) => Promise<void>;
writeFile: (filename: string, data: string) => Promise<void>;
copyFile: (fromFilename: string, toFilename: string) => Promise<void>;
};
export default _default;

@@ -21,5 +21,14 @@ "use strict";

}
function writeFile(fileName, data) {
function fileOrFolderExists(path) {
try {
var stats = fs.lstatSync(path);
return true;
}
catch (error) {
return false;
}
}
function writeFile(filename, data) {
return new Promise(function (resolve, reject) {
fs.writeFile(fileName, data, { encoding: 'utf8' }, function (error) {
fs.writeFile(filename, data, { encoding: 'utf8' }, function (error) {
if (error) {

@@ -34,6 +43,6 @@ reject(error);

}
function copyFile(fromFileName, toFileName) {
function copyFile(fromFilename, toFilename) {
return new Promise(function (resolve, reject) {
var readStream = fs.createReadStream(fromFileName, { encoding: 'utf8' });
var writeStream = fs.createWriteStream(toFileName, { encoding: 'utf8' });
var readStream = fs.createReadStream(fromFilename, { encoding: 'utf8' });
var writeStream = fs.createWriteStream(toFilename, { encoding: 'utf8' });
readStream.on('error', reject);

@@ -45,12 +54,2 @@ writeStream.on('error', reject);

}
function fileOrFolderExists(path) {
try {
var stats = fs.lstatSync(path);
return true;
}
catch (error) {
return false;
}
}
;
Object.defineProperty(exports, "__esModule", { value: true });

@@ -57,0 +56,0 @@ exports.default = {

@@ -7,3 +7,3 @@ import { TestRunner, RunResult, RunOptions, RunnerOptions } from '../api/test_runner';

private currentPromise;
private currentInteractionCount;
private currentTimeoutTimer;
private currentRunStartedTimestamp;

@@ -18,4 +18,5 @@ constructor(realTestRunnerName: string, runnerOptions: RunnerOptions);

private handleResultMessage(message);
private markNoResultTimeout(timeoutMs, forInteractionNumber);
private clearCurrentTimer();
private markNoResultTimeout(timeoutMs);
private handleTimeout();
}

@@ -16,3 +16,2 @@ "use strict";

this.realTestRunnerName = realTestRunnerName;
this.currentInteractionCount = 0;
this.startWorker();

@@ -29,4 +28,12 @@ }

var _this = this;
if (this.workerProcess.stdout) {
this.workerProcess.stdout.on('data', function (data) { });
}
if (this.workerProcess.stderr) {
this.workerProcess.stderr.on('data', function (data) {
console.log('ERROR: ' + data);
});
}
this.workerProcess.on('message', function (message) {
_this.currentInteractionCount++;
_this.clearCurrentTimer();
switch (message.type) {

@@ -44,5 +51,5 @@ case Message_1.MessageType.Result:

var _this = this;
this.currentInteractionCount++;
this.clearCurrentTimer();
if (options.timeout) {
this.markNoResultTimeout(options.timeout, this.currentInteractionCount);
this.markNoResultTimeout(options.timeout);
}

@@ -57,3 +64,3 @@ this.currentPromise = new Promise(function (resolve) {

TestRunnerChildProcessAdapter.prototype.dispose = function () {
this.currentInteractionCount++;
this.clearCurrentTimer();
this.workerProcess.kill();

@@ -84,9 +91,11 @@ };

};
TestRunnerChildProcessAdapter.prototype.markNoResultTimeout = function (timeoutMs, forInteractionNumber) {
TestRunnerChildProcessAdapter.prototype.clearCurrentTimer = function () {
if (this.currentTimeoutTimer) {
clearTimeout(this.currentTimeoutTimer);
}
};
TestRunnerChildProcessAdapter.prototype.markNoResultTimeout = function (timeoutMs) {
var _this = this;
setTimeout(function () {
if (_this.currentInteractionCount === forInteractionNumber && !_this.currentPromise.isFulfilled) {
console.log('TIMEOUT occurred, restarting test runner', _this.realTestRunnerName);
_this.handleTimeout();
}
this.currentTimeoutTimer = setTimeout(function () {
_this.handleTimeout();
}, timeoutMs);

@@ -93,0 +102,0 @@ };

@@ -7,2 +7,3 @@ import { TestRunner, RunResult, RunnerOptions } from '../api/test_runner';

private currentSpecNames;
private currentErrorMessages;
private currentCoverageReport;

@@ -23,3 +24,3 @@ constructor(runnerOptions: RunnerOptions);

private convertResult(testResults);
private static convertTestResult(testResults);
private convertTestResult(testResults);
}

@@ -36,2 +36,3 @@ "use strict";

this.listenToCoverage();
this.listenToBrowserError();
this.server.start();

@@ -65,4 +66,5 @@ }

KarmaTestRunner.prototype.listenToBrowserError = function () {
var _this = this;
this.server.on('browser_error', function (browser, error) {
console.log('ERROR: ', error);
_this.currentErrorMessages.push(error);
});

@@ -92,13 +94,15 @@ };

}
this.options.sourceFiles.forEach(function (sourceFile) {
var preprocessor = karmaConfig.preprocessors[sourceFile];
if (!preprocessor) {
karmaConfig.preprocessors[sourceFile] = 'coverage';
}
else {
if (Array.isArray(preprocessor)) {
preprocessor.push('coverage');
this.options.files.forEach(function (file) {
if (file.shouldMutate) {
var preprocessor = karmaConfig.preprocessors[file.path];
if (!preprocessor) {
karmaConfig.preprocessors[file.path] = 'coverage';
}
else {
karmaConfig.preprocessors[sourceFile] = ['coverage', preprocessor];
if (Array.isArray(preprocessor)) {
preprocessor.push('coverage');
}
else {
karmaConfig.preprocessors[file.path] = ['coverage', preprocessor];
}
}

@@ -111,4 +115,3 @@ }

karmaConfig.files = [];
this.options.sourceFiles.forEach(function (file) { return karmaConfig.files.push(file); });
this.options.additionalFiles.forEach(function (file) { return karmaConfig.files.push(file); });
this.options.files.forEach(function (file) { return karmaConfig.files.push(file.path); });
karmaConfig.port = this.options.port;

@@ -132,2 +135,3 @@ return karmaConfig;

_this.currentSpecNames = [];
_this.currentErrorMessages = [];
_this.currentCoverageReport = null;

@@ -142,11 +146,17 @@ _this.runServer().then(function () {

specNames: this.currentSpecNames,
result: KarmaTestRunner.convertTestResult(testResults),
result: this.convertTestResult(testResults),
succeeded: testResults.success,
failed: testResults.failed,
coverage: this.currentCoverageReport
coverage: this.currentCoverageReport,
errorMessages: this.currentErrorMessages
};
};
KarmaTestRunner.convertTestResult = function (testResults) {
if (testResults.error && testResults.failed === 0) {
return test_runner_1.TestResult.Error;
KarmaTestRunner.prototype.convertTestResult = function (testResults) {
if (testResults.error) {
if (this.currentErrorMessages.length > 0) {
return test_runner_1.TestResult.Error;
}
else {
return test_runner_1.TestResult.Complete;
}
}

@@ -153,0 +163,0 @@ else if (testResults.disconnected) {

import BaseMutation from './mutations/BaseMutation';
import TestFile from './TestFile';
import { RunResult } from './api/test_runner';

@@ -22,4 +21,2 @@ export interface MutantTestedCallback {

status: MutantStatus;
testsRan: TestFile[];
private fileUtils;
private _mutatedCode;

@@ -47,4 +44,4 @@ private _mutatedLine;

insertMutatedFile(sourceFiles: string[]): string[];
save(fileName?: string): Promise<void>;
save(fileName: string): Promise<void>;
reset(fileName: string): Promise<void>;
}
'use strict';
var _ = require('lodash');
var FileUtils_1 = require('./utils/FileUtils');
var util_1 = require('./api/util');

@@ -18,4 +17,2 @@ (function (MutantStatus) {

this.mutatedLocation = mutatedLocation;
this.testsRan = [];
this.fileUtils = new FileUtils_1.default();
this._originalLine = '';

@@ -28,3 +25,2 @@ this.scopedTestsById = [];

this.insertSubstitude(substitude);
this.save();
}

@@ -140,8 +136,3 @@ Object.defineProperty(Mutant.prototype, "scopedTestIds", {

Mutant.prototype.save = function (fileName) {
if (fileName) {
return util_1.StrykerTempFolder.writeFile(fileName, this.mutatedCode);
}
else {
this._mutatedFilename = this.fileUtils.createFileInTempFolder(this.filename, this.mutatedCode);
}
return util_1.StrykerTempFolder.writeFile(fileName, this.mutatedCode);
};

@@ -148,0 +139,0 @@ ;

@@ -35,4 +35,4 @@ "use strict";

Object.keys(coveredFile.statementMap).forEach(function (statementId) {
var location = coveredFile.statementMap[parseInt(statementId)];
if (_this.statementCoversMutant(mutant, location) && _this.isNewSmallestStatement(coveredFile.statementMap[parseInt(smallestStatement)], location)) {
var location = coveredFile.statementMap[statementId];
if (_this.statementCoversMutant(mutant, location) && _this.isNewSmallestStatement(coveredFile.statementMap[smallestStatement], location)) {
smallestStatement = statementId;

@@ -39,0 +39,0 @@ }

import Mutant from './Mutant';
export default class Mutator {
private mutationRegistry;
private fileUtils;
private mutations;

@@ -6,0 +5,0 @@ constructor();

'use strict';
var _ = require('lodash');
var FileUtils_1 = require('./utils/FileUtils');
var fileUtils = require('./utils/fileUtils');
var MutationRegistry_1 = require('./MutationRegistry');
var ParserUtils_1 = require('./utils/ParserUtils');
var parserUtils = require('./utils/parserUtils');
var Mutator = (function () {
function Mutator() {
this.mutationRegistry = new MutationRegistry_1.default();
this.fileUtils = new FileUtils_1.default();
this.mutations = this.mutationRegistry.getAllMutations();

@@ -15,3 +14,2 @@ }

var mutants = [];
var parserUtils = new ParserUtils_1.default();
var types = _.uniq(_.flatten(_.map(this.mutations, function (mutation) {

@@ -22,3 +20,3 @@ return mutation.types;

try {
var fileContent = _this.fileUtils.readFile(sourceFile);
var fileContent = fileUtils.readFile(sourceFile);
var abstractSyntaxTree = parserUtils.parse(fileContent);

@@ -46,6 +44,6 @@ var nodes = parserUtils.getNodesWithType(abstractSyntaxTree, types);

_.forEach(nodes, function (astnode, index) {
if (astnode.node.type) {
if (astnode.type) {
_.forEach(_this.mutations, function (mutation) {
if (mutation.canMutate(astnode.node)) {
mutants = mutants.concat(mutation.applyMutation(sourceFile, originalCode, astnode.node, ast));
if (mutation.canMutate(astnode)) {
mutants = mutants.concat(mutation.applyMutation(sourceFile, originalCode, astnode, ast));
}

@@ -52,0 +50,0 @@ });

@@ -68,3 +68,3 @@ 'use strict';

var mutationScoreCodebase = (((mutantsKilled + mutantsTimedOut) / mutants.length) * 100).toFixed(2);
var mutationScoreCodeCoverage = (((mutantsKilled + mutantsTimedOut) / (mutants.length - mutantsUntested)) * 100).toFixed(2);
var mutationScoreCodeCoverage = (((mutantsKilled + mutantsTimedOut) / ((mutants.length - mutantsUntested) || 1)) * 100).toFixed(2);
var codebaseColor = this.getColorForMutationScore(+mutationScoreCodebase);

@@ -71,0 +71,0 @@ var codecoverageColor = this.getColorForMutationScore(+mutationScoreCodeCoverage);

@@ -1,2 +0,1 @@

import FileUtils from './utils/FileUtils';
import BaseReporter from './reporters/BaseReporter';

@@ -7,10 +6,9 @@ import { StrykerOptions } from './api/core';

export default class Stryker {
private sourceFiles;
private otherFiles;
fileUtils: FileUtils;
private mutateFilePatterns;
private allFilePatterns;
reporter: BaseReporter;
private testRunnerOrchestrator;
constructor(sourceFiles: string[], otherFiles: string[], options?: StrykerOptions);
runMutationTest(cb: () => void): void;
options: StrykerOptions;
constructor(mutateFilePatterns: string[], allFilePatterns: string[], options?: StrykerOptions);
runMutationTest(): Promise<void>;
private logFailedTests(unsuccessfulTests);
}
'use strict';
var _ = require('lodash');
var program = require('commander');
var FileUtils_1 = require('./utils/FileUtils');
var Mutator_1 = require('./Mutator');

@@ -11,56 +11,67 @@ var ReporterFactory_1 = require('./ReporterFactory');

var MutantRunResultMatcher_1 = require('./MutantRunResultMatcher');
var InputFileResolver_1 = require('./InputFileResolver');
var Stryker = (function () {
function Stryker(sourceFiles, otherFiles, options) {
this.sourceFiles = sourceFiles;
this.otherFiles = otherFiles;
this.fileUtils = new FileUtils_1.default();
this.fileUtils.normalize(sourceFiles);
this.fileUtils.normalize(otherFiles);
this.fileUtils.createBaseTempFolder();
options = options || {};
options.testFramework = 'jasmine';
options.testRunner = 'karma';
options.port = 1234;
this.testRunnerOrchestrator = new TestRunnerOrchestrator_1.default(options, sourceFiles, otherFiles);
function Stryker(mutateFilePatterns, allFilePatterns, options) {
this.mutateFilePatterns = mutateFilePatterns;
this.allFilePatterns = allFilePatterns;
this.options = options || {};
this.options.testFramework = 'jasmine';
this.options.testRunner = 'karma';
this.options.port = 1234;
var reporterFactory = new ReporterFactory_1.default();
this.reporter = reporterFactory.getReporter('console');
}
Stryker.prototype.runMutationTest = function (cb) {
Stryker.prototype.runMutationTest = function () {
var _this = this;
console.log('INFO: Running initial test run');
this.testRunnerOrchestrator.recordCoverage().then(function (runResults) {
var unsuccessfulTests = runResults.filter(function (runResult) {
return !(runResult.failed === 0 && runResult.result === test_runner_1.TestResult.Complete);
return new Promise(function (resolve) {
new InputFileResolver_1.default(_this.mutateFilePatterns, _this.allFilePatterns)
.resolve().then(function (inputFiles) {
var testRunnerOrchestrator = new TestRunnerOrchestrator_1.default(_this.options, inputFiles);
testRunnerOrchestrator.recordCoverage().then(function (runResults) {
var unsuccessfulTests = runResults.filter(function (runResult) {
return !(runResult.failed === 0 && runResult.result === test_runner_1.TestResult.Complete);
});
if (unsuccessfulTests.length === 0) {
console.log("INFO: Initial test run succeeded. Ran " + runResults.length + " tests.");
var mutator = new Mutator_1.default();
var mutants_1 = mutator.mutate(inputFiles
.filter(function (inputFile) { return inputFile.shouldMutate; })
.map(function (file) { return file.path; }));
console.log('INFO: ' + mutants_1.length + ' Mutants generated');
var mutantRunResultMatcher = new MutantRunResultMatcher_1.default(mutants_1, runResults);
mutantRunResultMatcher.matchWithMutants();
testRunnerOrchestrator.runMutations(mutants_1, _this.reporter).then(function () {
_this.reporter.allMutantsTested(mutants_1);
console.log('Done!');
});
}
else {
_this.logFailedTests(unsuccessfulTests);
}
resolve();
});
}, function (errors) {
errors.forEach(function (error) { return console.log("ERROR: " + error); });
resolve();
});
if (unsuccessfulTests.length === 0) {
console.log('INFO: Initial test run succeeded');
var mutator = new Mutator_1.default();
var mutants_1 = mutator.mutate(_this.sourceFiles);
console.log('INFO: ' + mutants_1.length + ' Mutants generated');
var mutantRunResultMatcher = new MutantRunResultMatcher_1.default(mutants_1, runResults);
mutantRunResultMatcher.matchWithMutants();
_this.testRunnerOrchestrator.runMutations(mutants_1, _this.reporter).then(function () {
_this.reporter.allMutantsTested(mutants_1);
console.log('Done!');
cb();
});
}
else {
_this.logFailedTests(unsuccessfulTests);
}
console.log('INFO: Running initial test run');
});
};
Stryker.prototype.logFailedTests = function (unsuccessfulTests) {
var specNames = [];
unsuccessfulTests.forEach(function (runResult) {
runResult.specNames.forEach(function (specName) {
if (specNames.indexOf(specName) < 0) {
specNames.push(specName);
}
});
});
console.log('ERROR: One or more tests failed in the inial test run:');
specNames.forEach(function (filename) {
console.log('\t', filename);
});
var failedSpecNames = _.uniq(_.flatten(unsuccessfulTests
.filter(function (runResult) { return runResult.result === test_runner_1.TestResult.Complete; })
.map(function (runResult) { return runResult.specNames; })))
.sort();
if (failedSpecNames.length > 0) {
console.log('ERROR: One or more tests failed in the inial test run:');
failedSpecNames.forEach(function (filename) { return console.log('\t', filename); });
}
var errors = _.flatten(unsuccessfulTests
.filter(function (runResult) { return runResult.result === test_runner_1.TestResult.Error; })
.map(function (runResult) { return runResult.errorMessages; }))
.sort();
if (errors.length > 0) {
console.log('ERROR: One or more tests errored in the initial test run:');
errors.forEach(function (error) { return console.log('\t', error); });
}
};

@@ -76,11 +87,11 @@ return Stryker;

program
.usage('-s <items> -t <items> [other options]')
.option('-s, --src <items>', 'A list of source files. Example: a.js,b.js', list)
.option('-o, --other-files <items>', 'A list of other files, such as test files or library files. Example: a.js,b.js', list)
.usage('-f <files> -m <filesToMutate> [other options]')
.description('Starts the stryker mutation testing process. Required arguments are --mutate and --files. You can use globbing expressions to target multiple files. See https://github.com/isaacs/node-glob#glob-primer for more information about the globbing syntax.')
.option('-m, --mutate <filesToMutate>', "A comma seperated list of globbing expression used for selecting the files that should be mutated.\n Example: src/**/*.js,a.js", list)
.option('-f, --files <allFiles>', "A comma seperated list of globbing expression used for selecting all files needed to run the tests. These include library files, test files and files to mutate, but should NOT include test framework files (for example jasmine).\n Example: node_modules/a-lib/**/*.js,src/**/*.js,a.js,test/**/*.js", list)
.parse(process.argv);
if (program.src && program.otherFiles) {
var stryker = new Stryker(program.src, program.otherFiles);
stryker.runMutationTest(function () { });
if (program.mutate && program.files) {
new Stryker(program.mutate, program.files).runMutationTest();
}
})();
//# sourceMappingURL=Stryker.js.map

@@ -1,2 +0,2 @@

import { StrykerOptions } from './api/core';
import { StrykerOptions, InputFile } from './api/core';
import { RunResult } from './api/test_runner';

@@ -7,5 +7,4 @@ import Mutant from './Mutant';

private options;
private sourceFiles;
private otherFiles;
constructor(options: StrykerOptions, sourceFiles: string[], otherFiles: string[]);
private files;
constructor(options: StrykerOptions, files: InputFile[]);
recordCoverage(): Promise<RunResult[]>;

@@ -19,3 +18,3 @@ runMutations(mutants: Mutant[], reporter: BaseReporter): Promise<void>;

private copyAllSourceFilesToTempFolder();
private createTestRunSettings(sourceFiles, selector, port, coverageEnabled);
private createTestRunSettings(files, selector, port, coverageEnabled);
}

@@ -12,10 +12,9 @@ "use strict";

var TestRunnerOrchestrator = (function () {
function TestRunnerOrchestrator(options, sourceFiles, otherFiles) {
function TestRunnerOrchestrator(options, files) {
this.options = options;
this.sourceFiles = sourceFiles;
this.otherFiles = otherFiles;
this.files = files;
}
TestRunnerOrchestrator.prototype.recordCoverage = function () {
var testSelector = test_selector_1.TestSelectorFactory.instance().create(this.options.testFramework, { options: this.options });
var testRunner = IsolatedTestRunnerAdapterFactory_1.default.create(this.createTestRunSettings(this.sourceFiles, testSelector, this.options.port, true));
var testRunner = IsolatedTestRunnerAdapterFactory_1.default.create(this.createTestRunSettings(this.files, testSelector, this.options.port, true));
return this.runSingleTestsRecursive(testSelector, testRunner, [], 0).then(function (testResults) {

@@ -36,12 +35,17 @@ testRunner.dispose();

var mutant = mutants.pop();
var nextRunner_1 = testRunners.pop();
var sourceFileCopy_1 = nextRunner_1.sourceFileMap[mutant.filename];
return Promise.all([mutant.save(sourceFileCopy_1), nextRunner_1.selector.select(mutant.scopedTestIds)])
.then(function () { return nextRunner_1.runnerAdapter.run({ timeout: _this.calculateTimeout(mutant.timeSpentScopedTests) }); })
.then(function (runResult) {
_this.updateMutantStatus(mutant, runResult);
reporter.mutantTested(mutant);
return mutant.reset(sourceFileCopy_1);
})
.then(function () { return testRunners.push(nextRunner_1); });
if (mutant.scopedTestIds.length > 0) {
var nextRunner_1 = testRunners.pop();
var sourceFileCopy_1 = nextRunner_1.sourceFileMap[mutant.filename];
return Promise.all([mutant.save(sourceFileCopy_1), nextRunner_1.selector.select(mutant.scopedTestIds)])
.then(function () { return nextRunner_1.runnerAdapter.run({ timeout: _this.calculateTimeout(mutant.timeSpentScopedTests) }); })
.then(function (runResult) {
_this.updateMutantStatus(mutant, runResult);
reporter.mutantTested(mutant);
return mutant.reset(sourceFileCopy_1);
})
.then(function () { return testRunners.push(nextRunner_1); });
}
else {
return Promise.resolve(reporter.mutantTested(mutant));
}
}

@@ -79,3 +83,3 @@ };

.then(function (runResult) {
if (runResult.succeeded > 0 || runResult.failed > 0) {
if (runResult.result === test_runner_1.TestResult.Complete && runResult.succeeded > 0 || runResult.failed > 0) {
runResults[currentTestIndex] = runResult;

@@ -85,2 +89,5 @@ resolve(_this.runSingleTestsRecursive(testSelector, testRunner, runResults, currentTestIndex + 1));

else {
if (runResult.result !== test_runner_1.TestResult.Complete) {
runResults[currentTestIndex] = runResult;
}
testRunner.dispose();

@@ -109,9 +116,14 @@ resolve(runResults);

var selector = test_selector_1.TestSelectorFactory.instance().create(_this.options.testFramework, { options: _this.options });
var tempSourceFiles = [];
for (var i in sourceFileMap) {
tempSourceFiles.push(sourceFileMap[i]);
}
var runnerFiles = [];
_this.files.forEach(function (originalFile) {
if (Object.keys(sourceFileMap).indexOf(originalFile.path) >= 0) {
runnerFiles.push({ path: sourceFileMap[originalFile.path], shouldMutate: originalFile.shouldMutate });
}
else {
runnerFiles.push(originalFile);
}
});
return {
sourceFileMap: sourceFileMap,
runnerAdapter: IsolatedTestRunnerAdapterFactory_1.default.create(_this.createTestRunSettings(tempSourceFiles, selector, _this.options.port + portOffset, false)),
runnerAdapter: IsolatedTestRunnerAdapterFactory_1.default.create(_this.createTestRunSettings(runnerFiles, selector, _this.options.port + portOffset, false)),
selector: selector

@@ -126,6 +138,11 @@ };

var tempFolder = util_1.StrykerTempFolder.createRandomFolder('test-runner-source-files');
var copyPromises = _this.sourceFiles.map(function (sourceFile) {
var targetFile = tempFolder + path.sep + path.basename(sourceFile);
fileMap[sourceFile] = targetFile;
return util_1.StrykerTempFolder.copyFile(sourceFile, targetFile);
var copyPromises = _this.files.map(function (file) {
if (file.shouldMutate) {
var targetFile = tempFolder + path.sep + path.basename(file.path);
fileMap[file.path] = targetFile;
return util_1.StrykerTempFolder.copyFile(file.path, targetFile);
}
else {
return Promise.resolve();
}
});

@@ -135,7 +152,6 @@ Promise.all(copyPromises).then(function () { resolve(fileMap); }, reject);

};
TestRunnerOrchestrator.prototype.createTestRunSettings = function (sourceFiles, selector, port, coverageEnabled) {
TestRunnerOrchestrator.prototype.createTestRunSettings = function (files, selector, port, coverageEnabled) {
return {
coverageEnabled: coverageEnabled,
sourceFiles: sourceFiles,
additionalFiles: [].concat(selector.files()).concat(this.otherFiles),
files: selector.files().map(function (f) { return { path: f, shouldMutate: false }; }).concat(files),
strykerOptions: this.options,

@@ -142,0 +158,0 @@ port: port

@@ -18,4 +18,3 @@ "use strict";

},
additionalFiles: [],
sourceFiles: [],
files: [],
port: null,

@@ -22,0 +21,0 @@ };

@@ -15,4 +15,3 @@ 'use strict';

testRunnerOptions = {
sourceFiles: ['test/sampleProject/src/Add.js'],
additionalFiles: ['test/sampleProject/test/AddSpec.js'],
files: [{ path: 'test/sampleProject/src/Add.js', shouldMutate: true }, { path: 'test/sampleProject/test/AddSpec.js', shouldMutate: false }],
port: 9877,

@@ -47,4 +46,3 @@ coverageEnabled: true,

testRunnerOptions = {
sourceFiles: ['test/sampleProject/src/Add.js'],
additionalFiles: ['test/sampleProject/test/AddSpec.js'],
files: [{ path: 'test/sampleProject/src/Add.js', shouldMutate: true }, { path: 'test/sampleProject/test/AddSpec.js', shouldMutate: false }],
port: 9878,

@@ -70,3 +68,44 @@ coverageEnabled: false,

});
describe('when an error occures while running tests', function () {
before(function () {
var testRunnerOptions = {
files: [{ path: 'test/sampleProject/src/Error.js', shouldMutate: true }, { path: 'test/sampleProject/test/AddSpec.js', shouldMutate: false }],
port: 9879,
coverageEnabled: false,
strykerOptions: {}
};
sut = new KarmaTestRunner_1.default(testRunnerOptions);
});
it('should report Error with the error message', function () {
return expect(sut.run()).to.eventually.satisfy(function (testResult) {
expect(testResult.succeeded).to.be.eq(0);
expect(testResult.failed).to.be.eq(0);
expect(testResult.result).to.be.eq(test_runner_1.TestResult.Error);
expect(testResult.errorMessages.length).to.equal(1);
expect(testResult.errorMessages[0].indexOf('ReferenceError: Can\'t find variable: someGlobalVariableThatIsNotDeclared\nat')).to.eq(0);
return true;
});
});
});
describe('when no error occured and no test is performed', function () {
before(function () {
var testRunnerOptions = {
files: [{ path: 'test/sampleProject/src/Add.js', shouldMutate: true }, { path: 'test/sampleProject/test/EmptySpec.js', shouldMutate: true }],
port: 9880,
coverageEnabled: false,
strykerOptions: {}
};
sut = new KarmaTestRunner_1.default(testRunnerOptions);
});
it('should report Complete without errors', function () {
return expect(sut.run()).to.eventually.satisfy(function (testResult) {
expect(testResult.succeeded).to.be.eq(0);
expect(testResult.failed).to.be.eq(0);
expect(testResult.result).to.be.eq(test_runner_1.TestResult.Complete);
expect(testResult.errorMessages.length).to.equal(0);
return true;
});
});
});
});
//# sourceMappingURL=KarmaTestRunnerSpec.js.map

@@ -42,3 +42,3 @@ "use strict";

strykerOptions = { testFrameork: '', testRunner: '', port: 23, karma: { 'my-karma-options': {} } };
sut = new MyTestRunner({ sourceFiles: [], additionalFiles: [], strykerOptions: strykerOptions, port: 58 });
sut = new MyTestRunner({ files: [], strykerOptions: strykerOptions, port: 58 });
});

@@ -45,0 +45,0 @@ it('should supply options', function () {

@@ -11,2 +11,3 @@ "use strict";

var path = require('path');
var _ = require('lodash');
var expect = chai.expect;

@@ -24,4 +25,3 @@ chai.use(sinonChai);

port: 42,
sourceFiles: [],
additionalFiles: [],
files: [],
strykerOptions: null

@@ -44,3 +44,5 @@ };

var expectedWorkerProcessPath = path.resolve(__dirname + '/../../../src/isolated-runner/') + '/IsolatedTestRunnerAdapterWorker';
expect(child_process.fork).to.have.been.calledWith(expectedWorkerProcessPath, [], { execArgv: [], silent: true });
var expectedExecArgv = _.clone(process.execArgv);
_.remove(expectedExecArgv, function (arg) { return arg.substr(0, 11) === '--debug-brk'; });
expect(child_process.fork).to.have.been.calledWith(expectedWorkerProcessPath, [], { execArgv: expectedExecArgv, silent: true });
expect(fakeChildProcess.on).to.have.been.calledWith('message');

@@ -47,0 +49,0 @@ });

@@ -42,3 +42,3 @@ "use strict";

anOtherFile: {
1: {
'1': {
start: { line: 5, column: 0 },

@@ -48,3 +48,3 @@ end: { line: 5, column: 8 }

},
s: { 1: 1 }
s: { '1': 1 }
};

@@ -54,11 +54,11 @@ runResultTwo.coverage = {

statementMap: {
1: {
'1': {
start: { line: 3, column: 0 },
end: { line: 5, column: 10 }
},
2: {
'2': {
start: { line: 5, column: 0 },
end: { line: 5, column: 10 }
},
3: {
'3': {
start: { line: 5, column: 4 },

@@ -69,5 +69,5 @@ end: { line: 5, column: 8 }

s: {
1: 1,
2: 1,
3: 0
'1': 1,
'2': 1,
'3': 0
}

@@ -77,11 +77,11 @@ },

statementMap: {
1: {
'1': {
start: { line: 0, column: 1 },
end: { line: 10, column: 5 }
},
2: {
'2': {
start: { line: 9, column: 1 },
end: { line: 10, column: 5 }
},
3: {
'3': {
start: { line: 10, column: 1 },

@@ -92,5 +92,5 @@ end: { line: 10, column: 5 }

s: {
1: 1,
2: 0,
3: 1
'1': 1,
'2': 0,
'3': 1
}

@@ -111,15 +111,15 @@ }

statementMap: {
1: {
'1': {
start: { line: 4, column: 0 },
end: { line: 6, column: 0 }
}
}, s: { 1: 1 }
}, s: { '1': 1 }
},
5: {
statementMap: {
1: {
'1': {
start: { line: 10, column: 0 },
end: { line: 10, column: 0 }
}
}, s: { 1: 1 }
}, s: { '1': 1 }
}

@@ -130,7 +130,7 @@ };

statementMap: {
1: {
'1': {
start: { line: 4, column: 0 },
end: { line: 5, column: 6 }
}
}, s: { 1: 1 }
}, s: { '1': 1 }
}

@@ -137,0 +137,0 @@ };

@@ -5,3 +5,3 @@ 'use strict';

var MathMutation_1 = require('../../src/mutations/MathMutation');
var ParserUtils_1 = require('../../src/utils/ParserUtils');
var parserUtils = require('../../src/utils/parserUtils');
require('mocha-sinon');

@@ -23,3 +23,2 @@ describe('Mutant', function () {

});
var parserUtils = new ParserUtils_1.default();
var baseCode = 'var i = 1 + 2;\n';

@@ -26,0 +25,0 @@ originalLine = 'var j = i * 2;';

@@ -10,3 +10,3 @@ 'use strict';

var Mutant_1 = require('../../../src/Mutant');
var ParserUtils_1 = require('../../../src/utils/ParserUtils');
var parserUtils = require('../../../src/utils/parserUtils');
require('mocha-sinon');

@@ -66,3 +66,2 @@ describe('BaseOperatorMutation', function () {

var mockMutation = new MockBaseOperatorMutation();
var parserUtils = new ParserUtils_1.default();
var ast = parserUtils.parse(code);

@@ -69,0 +68,0 @@ var node = ast.body[0].declarations[0].init;

@@ -5,3 +5,3 @@ 'use strict';

var RemoveConditionalsMutation_1 = require('../../../src/mutations/RemoveConditionalsMutation');
var ParserUtils_1 = require('../../../src/utils/ParserUtils');
var parserUtils = require('../../../src/utils/parserUtils');
require('mocha-sinon');

@@ -34,3 +34,2 @@ describe('RemoveConditionalsMutation', function () {

}';
var parserUtils = new ParserUtils_1.default();
ast = parserUtils.parse(code);

@@ -37,0 +36,0 @@ ifStatement = ast.body[1];

'use strict';
var expect = require('chai').expect;
var FileUtils_1 = require('../../src/utils/FileUtils');
var fileUtils = require('../../src/utils/fileUtils');
var Mutant_1 = require('../../src/Mutant');

@@ -17,3 +17,3 @@ var Mutator_1 = require('../../src/Mutator');

it('should return an empty array if nothing could be mutated', function () {
this.sinon.stub(FileUtils_1.default.prototype, 'readFile', function () {
this.sinon.stub(fileUtils, 'readFile', function () {
return '';

@@ -25,3 +25,3 @@ });

it('should return an array with a single mutant if only one mutant could be found in a file', function () {
this.sinon.stub(FileUtils_1.default.prototype, 'readFile', function () {
this.sinon.stub(fileUtils, 'readFile', function () {
return 'var i = 1 + 2;';

@@ -35,3 +35,3 @@ });

var mutatedCode = 'var i = 1 - 2;';
this.sinon.stub(FileUtils_1.default.prototype, 'readFile', function () {
this.sinon.stub(fileUtils, 'readFile', function () {
return originalCode;

@@ -45,3 +45,3 @@ });

var mutatedCode = '\n\nvar i = 1 - 2;';
this.sinon.stub(FileUtils_1.default.prototype, 'readFile', function () {
this.sinon.stub(fileUtils, 'readFile', function () {
return originalCode;

@@ -48,0 +48,0 @@ });

@@ -0,1 +1,52 @@

'use strict';
var Stryker_1 = require('../../src/Stryker');
var test_runner_1 = require('../../src/api/test_runner');
var chai_1 = require('chai');
var sinon = require('sinon');
var inputFileResolver = require('../../src/InputFileResolver');
var testRunnerOrchestrator = require('../../src/TestRunnerOrchestrator');
describe('Stryker runMutationTest()', function () {
var sut;
var sandbox;
var inputFileResolverStub;
var testRunnerOrchestratorStub;
var inputFiles;
var initialRunResults;
beforeEach(function () {
sandbox = sinon.sandbox.create();
sandbox.stub(console, 'log');
});
describe('with correct input file globbing', function () {
beforeEach(function () {
inputFiles = [{ path: 'someFile', shouldMutate: true }];
inputFileResolverStub = {
resolve: sandbox.stub().returns(Promise.resolve(inputFiles))
};
sandbox.stub(inputFileResolver, 'default').returns(inputFileResolverStub);
sut = new Stryker_1.default(['mutateFile'], ['allFiles']);
});
describe('when coverage can be collected', function () {
beforeEach(function () {
initialRunResults = [];
testRunnerOrchestratorStub = {
recordCoverage: sandbox.stub().returns(Promise.resolve(initialRunResults))
};
sandbox.stub(testRunnerOrchestrator, 'default').returns(testRunnerOrchestratorStub);
});
describe('but contains an error and failed tests', function () {
beforeEach(function () {
initialRunResults.push({ result: test_runner_1.TestResult.Error, errorMessages: ['An error!'] });
return sut.runMutationTest();
});
it('should have logged the errors', function () {
chai_1.expect(console.log).to.have.been.calledWith('ERROR: One or more tests errored in the initial test run:');
chai_1.expect(console.log).to.have.been.calledWith('\t', 'An error!');
});
});
});
});
afterEach(function () {
sandbox.restore();
});
});
//# sourceMappingURL=StrykerSpec.js.map

@@ -16,4 +16,3 @@ "use strict";

var sandbox;
var sourceFiles = ['a.js', 'b.js'];
var otherFiles = ['aSpec.js', 'bSpec.js'];
var files = [{ path: 'a.js', shouldMutate: true }, { path: 'b.js', shouldMutate: true }, { path: 'aSpec.js', shouldMutate: false }, { path: 'bSpec.js', shouldMutate: false }];
var strykerOptions = { testFramework: 'superFramework', testRunner: 'superRunner', port: 42 };

@@ -46,3 +45,3 @@ var firstTestRunner;

sandbox.stub(test_selector_1.TestSelectorFactory.instance(), 'create', function () { return selector; });
sut = new TestRunnerOrchestrator_1.default(strykerOptions, sourceFiles, otherFiles);
sut = new TestRunnerOrchestrator_1.default(strykerOptions, files);
});

@@ -55,5 +54,5 @@ describe('recordCoverage()', function () {

it('should have created an isolated test runner', function () {
var expectedOtherFiles = ['some', 'files'];
otherFiles.forEach(function (file) { return expectedOtherFiles.push(file); });
expect(IsolatedTestRunnerAdapterFactory_1.default.create).to.have.been.calledWith({ sourceFiles: sourceFiles, additionalFiles: expectedOtherFiles, port: 42, coverageEnabled: true, strykerOptions: strykerOptions });
var expectedFiles = [{ path: 'some', shouldMutate: false }, { path: 'files', shouldMutate: false }];
files.forEach(function (file) { return expectedFiles.push(file); });
expect(IsolatedTestRunnerAdapterFactory_1.default.create).to.have.been.calledWith({ files: expectedFiles, port: 42, coverageEnabled: true, strykerOptions: strykerOptions });
});

@@ -84,3 +83,3 @@ it('should have created the test selector', function () {

var mockMutant = function (id) {
return { filename: "mutant" + id, save: sinon.stub().returns(Promise.resolve()), scopedTestIds: [id], timeSpentScopedTests: id, reset: sinon.stub().returns(Promise.resolve()) };
return { filename: "mutant" + id, save: sinon.stub().returns(Promise.resolve()), scopedTestIds: [id], timeSpentScopedTests: id, reset: sinon.stub().returns(Promise.resolve()), status: Mutant_1.MutantStatus.UNTESTED };
};

@@ -94,8 +93,18 @@ beforeEach(function () {

};
mutants = [mockMutant(1), mockMutant(2), mockMutant(3)];
var untestedMutant = mockMutant(0);
untestedMutant.scopedTestIds = [];
mutants = [mockMutant(1), mockMutant(2), mockMutant(3), untestedMutant];
return sut.runMutations(mutants, reporter);
});
it('should have created 2 test runners', function () {
expect(IsolatedTestRunnerAdapterFactory_1.default.create).to.have.been.calledWithMatch({ additionalFiles: ["some", "files", "aSpec.js", "bSpec.js"], sourceFiles: [("a-folder" + path.sep + "a.js"), ("a-folder" + path.sep + "b.js")], port: 42, coverageEnabled: false, strykerOptions: strykerOptions });
expect(IsolatedTestRunnerAdapterFactory_1.default.create).to.have.been.calledWith({ additionalFiles: ["some", "files", "aSpec.js", "bSpec.js"], sourceFiles: [("a-folder" + path.sep + "a.js"), ("a-folder" + path.sep + "b.js")], port: 43, coverageEnabled: false, strykerOptions: strykerOptions });
var expectedFiles = [
{ path: 'some', shouldMutate: false },
{ path: 'files', shouldMutate: false },
{ path: "a-folder" + path.sep + "a.js", shouldMutate: true },
{ path: "a-folder" + path.sep + "b.js", shouldMutate: true },
{ path: 'aSpec.js', shouldMutate: false },
{ path: 'bSpec.js', shouldMutate: false }
];
expect(IsolatedTestRunnerAdapterFactory_1.default.create).to.have.been.calledWithMatch({ files: expectedFiles, port: 42, coverageEnabled: false, strykerOptions: strykerOptions });
expect(IsolatedTestRunnerAdapterFactory_1.default.create).to.have.been.calledWith({ files: expectedFiles, port: 43, coverageEnabled: false, strykerOptions: strykerOptions });
});

@@ -108,3 +117,3 @@ it('should have ran mutant 1 and 3 on the first test runner', function () {

});
it('should have reporterd mutant state correctly', function () {
it('should have reported the mutant state of tested mutants correctly', function () {
expect(mutants[0].status).to.be.eq(Mutant_1.MutantStatus.KILLED);

@@ -114,2 +123,5 @@ expect(mutants[1].status).to.be.eq(Mutant_1.MutantStatus.SURVIVED);

});
it('should have reported the mutant state of an untested mutant correctly', function () {
expect(mutants[3].status).to.be.eq(Mutant_1.MutantStatus.UNTESTED);
});
});

@@ -116,0 +128,0 @@ afterEach(function () {

{
"name": "stryker",
"version": "0.1.0",
"version": "0.2.0",
"description": "The extendable JavaScript mutation testing framework",

@@ -36,4 +36,4 @@ "main": "dist/src/Stryker.js",

"es6-promise-pool": "^2.4.1",
"escodegen": "^1.7.0",
"esprima": "^2.7.0",
"glob": "^7.0.3",
"jasmine-core": "^2.3.4",

@@ -45,2 +45,3 @@ "karma": "^0.13.15",

"lodash": "^3.10.1",
"node-glob": "^1.2.0",
"phantomjs": "^1.9.18"

@@ -60,2 +61,3 @@ },

"grunt-ts": "5.4.0",
"grunt-typings": "^0.1.4",
"istanbul": "^0.4.0",

@@ -66,4 +68,5 @@ "mocha": "^2.3.3",

"sinon-chai": "^2.8.0",
"typescript": "^1.8.9"
"typescript": "^1.8.9",
"typings": "^0.7.11"
}
}

@@ -5,2 +5,3 @@ [![Build Status](https://travis-ci.org/infosupport/stryker.svg?branch=master)](https://travis-ci.org/infosupport/stryker)

![Stryker](stryker-80x80.png)
# Stryker

@@ -11,2 +12,3 @@

## Work in progress

@@ -30,18 +32,20 @@ This repository is a work in progress. We only support Jasmine tests in the browser for now. Please create and vote on [issues](https://github.com/infosupport/stryker/issues) to help us determine the priority on features.

## Configuration
### Available options
#### Source files
**Short notation:** -s
**Full notation:** --src
### Required options
#### Files to mutate
**Short notation:** -m
**Full notation:** --mutate
**Optional:** **No**
**Description:**
The list of source files which should be mutated, separated by comma's.
**Example:** -s src/a.js,src/b.js
A comma seperated list of globbing expressions used for selecting the files that should be mutated.
**Example:** -m src/\*\*/\*.js,a.js`
#### Other files
**Short notation:** -o
**Full notation:** --other-files
#### All files
**Short notation:** -f
**Full notation:** --files
**Optional:** **No**
**Description:**
The list of other files which are needed, separated by comma's. These should be: test files, library files and any other file you need to run your project.
**Example:** -o test/a.js,test/b.js
A comma seperated list of globbing expressions used for selecting all files needed to run the tests.
These include: test files, library files, source files (the files selected with `--mutate`) and any other file you need to run your tests.
The order of the files specified here will be the order used to load the file in the test runner, for example: karma.
**Example:** -f node_modules/a-lib/\*\*/\*.js,src/\*\*/\*.js,a.js,test/\*\*/\*.js

@@ -54,3 +58,3 @@ ### Default config

```
node node_modules/stryker/src/Stryker.js –s src/myFirstFile.js,src/mySecondFile.js –o test/myFirstFileSpec.js,test/mySecondsFileSpec.js,libs/externalLibrary.js
node node_modules/stryker/src/Stryker.js –m src/myFirstFile.js,src/mySecondFile.js –f libs/externalLibrary.js,src/myFirstFile.js,src/mySecondFile.js,test/*.js,
```

@@ -57,0 +61,0 @@

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

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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc