Skip to content

Commit

Permalink
feat(ts2.0): Migrate to typescript 2.0 (#154)
Browse files Browse the repository at this point in the history
* feat(ts-2): Upgrade to typescript 2

* Using @types dev dependencies
* Update estree node structure in mutator module
* Remove dependency on typings

* Fix(mutators) Use new ESTree API

* feat(mutants): Make use of ts2 type narrowing

* Make use of ts2 type narrowing
* Rename module 'stryker-api/estree' back to 'estree'

* feat(ts2.0): Update mutators

* Update mutators by injecting the new signature of the copy function. This allows us to remove most of the type castings.

* refactor(Mutators) Use new estree API

* fix(lint): Fix linting issues

Mostely:
* Semicolon
* Whitespaces
* double quotes <> single quotes

* fix(deps): Stryker-api v0.3.0-0

* Removed unused other stryker dependencies

* fix(RemoveConditionalsMutator): Use correct nodeID

* Use the nodeID of the test expression wrather than the if-expression itself.
* Add Ternary operator `true` mutation

* fix(stryker-api): Make stryker backward compatible

* Make stryker backward compatible with stryker-api@0.2.0 by removing the import of the new `'stryker-api/estree'`
  • Loading branch information
nicojs authored and simondel committed Oct 3, 2016
1 parent 4be210c commit 1c5db5c
Show file tree
Hide file tree
Showing 59 changed files with 561 additions and 862 deletions.
11 changes: 8 additions & 3 deletions .bithoundrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
{
"critics": {
"lint": { "engine": "tslint" }
}
}
"lint": { "engine": "tslint" },
"wc": { "limit": 3000 }
},
"test": [
"test/**",
"testResources/**"
]
}
10 changes: 9 additions & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,21 @@ module.exports = function (grunt) {
commitMessage: 'chore: release v%VERSION%',
prereleaseName: 'rc'
}
},
tslint: {
src: {
src: ['*.ts', 'src/**/*.ts']
},
test: {
src: ['test/**/*.ts', 'testResources/module/*.ts']
}
}
});

grunt.registerTask('default', ['test']);
grunt.registerTask('watch-test', ['test', 'watch']);
grunt.registerTask('test', ['build', 'coverage']);
grunt.registerTask('build', ['clean', 'ts']);
grunt.registerTask('build', ['clean', 'tslint', 'ts']);
grunt.registerTask('integration', ['mochaTest:integration']);
grunt.registerTask('coverage', ['mocha_istanbul:coverage']);
grunt.registerTask('serve', ['watch']);
Expand Down
396 changes: 0 additions & 396 deletions customTyping/karma.d.ts

This file was deleted.

25 changes: 18 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"main": "src/Stryker.js",
"typings": "src/Stryker.d.ts",
"scripts": {
"pretest": "typings install",
"test": "grunt test",
"start": "concurrently \"npm run tsc:w\" \"grunt serve\"",
"tsc:w": "tsc -w",
Expand Down Expand Up @@ -51,6 +50,20 @@
"serialize-javascript": "^1.3.0"
},
"devDependencies": {
"@types/chai-as-promised": "0.0.28",
"@types/chalk": "^0.4.28",
"@types/es6-promise": "0.0.31",
"@types/escodegen": "0.0.5",
"@types/esprima": "^2.1.31",
"@types/estree": "0.0.32",
"@types/glob": "^5.0.29",
"@types/karma": "^0.13.32",
"@types/lodash": "^4.14.34",
"@types/log4js": "0.0.31",
"@types/mkdirp": "^0.3.28",
"@types/mocha": "^2.2.31",
"@types/sinon": "^1.16.29",
"@types/sinon-chai": "^2.7.26",
"chai": "^3.4.1",
"chai-as-promised": "^5.2.0",
"concurrently": "^2.0.0",
Expand All @@ -65,6 +78,7 @@
"grunt-mocha-test": "^0.12.7",
"grunt-npm": "0.0.2",
"grunt-ts": "^6.0.0-beta.3",
"grunt-tslint": "^3.2.1",
"istanbul": "^0.4.0",
"jasmine-core": "^2.4.1",
"karma": "1.0.0",
Expand All @@ -76,12 +90,9 @@
"mocha-sinon": "^1.1.4",
"sinon": "^1.17.2",
"sinon-chai": "^2.8.0",
"stryker-api": "^0.2.0",
"stryker-html-reporter": "^0.2.0",
"stryker-karma-runner": "^0.2.0",
"stryker-mocha-runner": "0.1.0",
"typescript": "^1.8.9",
"typings": "^0.7.11"
"stryker-api": "^0.2.1",
"tslint": "^3.15.1",
"typescript": "^2.0.2"
},
"peerDependencies": {
"stryker-api": "^0.2.0"
Expand Down
20 changes: 10 additions & 10 deletions src/ConfigReader.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Config} from 'stryker-api/config';
import {StrykerOptions} from 'stryker-api/core';
import { Config } from 'stryker-api/config';
import { StrykerOptions } from 'stryker-api/core';
import * as log4js from 'log4js';
import * as path from 'path';
import * as _ from 'lodash';
Expand All @@ -8,7 +8,7 @@ export var CONFIG_SYNTAX_HELP = ' module.exports = function(config) {\n' +
' config.set({\n' +
' // your config\n' +
' });\n' +
' };\n'
' };\n';

const log = log4js.getLogger('ConfigReader');

Expand All @@ -17,12 +17,12 @@ export default class ConfigReader {
constructor(private options: StrykerOptions) { }

readConfig() {
let configModule = this.loadConfigModule();
var config = new Config();
const configModule = this.loadConfigModule();
const config = new Config();
try {
configModule(config);
} catch (e) {
log.fatal('Error in config file!\n', e)
log.fatal('Error in config file!\n', e);
process.exit(1);
}

Expand All @@ -47,13 +47,13 @@ export default class ConfigReader {
process.exit(1);
}
if (!_.isFunction(configModule)) {
log.fatal('Config file must export a function!\n' + CONFIG_SYNTAX_HELP)
process.exit(1)
log.fatal('Config file must export a function!\n' + CONFIG_SYNTAX_HELP);
process.exit(1);
}
} else {
log.debug('No config file specified.')
log.debug('No config file specified.');
// if no config file path is passed, we define a dummy config module.
configModule = function () { }
configModule = function () { };
}
return configModule;
}
Expand Down
6 changes: 3 additions & 3 deletions src/InputFileResolver.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {InputFile, InputFileDescriptor} from 'stryker-api/core';
import {glob, normalize} from './utils/fileUtils';
import { InputFile, InputFileDescriptor } from 'stryker-api/core';
import { glob, normalize } from './utils/fileUtils';
import * as _ from 'lodash';
import * as log4js from 'log4js';

Expand Down Expand Up @@ -60,7 +60,7 @@ export default class InputFileResolver {
if (_.isObject(maybeInputFileDescriptor)) {
if (Object.keys(maybeInputFileDescriptor).indexOf('pattern') > -1) {
return true;
}else{
} else {
throw Error(`File descriptor ${JSON.stringify(maybeInputFileDescriptor)} is missing mandatory property 'pattern'.`);
}
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/MutantRunResultMatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export default class MutantRunResultMatcher {
// Statement map should change between test run results.
// We should be able to safely reuse the smallest statement found in first run.
if (!smallestStatement) {
smallestStatement = this.findSmallestCoveringStatement(mutant, coveredFile)
smallestStatement = this.findSmallestCoveringStatement(mutant, coveredFile);
}
covered = coveredFile.s[smallestStatement] > 0;
}
Expand Down
49 changes: 28 additions & 21 deletions src/MutatorOrchestrator.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import * as _ from 'lodash';
import BinaryOperatorMutator from './mutators/BinaryOperatorMutator';
import BlockStatementMutator from './mutators/BlockStatementMutator';
import ConditionalBoundaryMutator from './mutators/ConditionalBoundaryMutator';
import MathMutator from './mutators/MathMutator';
import LogicalOperatorMutator from './mutators/LogicalOperatorMutator';
import RemoveConditionalsMutator from './mutators/RemoveConditionalsMutator';
import ReverseConditionalMutator from './mutators/ReverseConditionalMutator';
import UnaryOperatorMutator from './mutators/UnaryOperatorMutator';
import {Mutator, StrykerNode, MutatorFactory} from 'stryker-api/mutant';
import {Reporter, SourceFile} from 'stryker-api/report';
import UpdateOperatorMutator from './mutators/UpdateOperatorMutator';
import { Mutator, MutatorFactory } from 'stryker-api/mutant';
import { Reporter, SourceFile } from 'stryker-api/report';
import * as fileUtils from './utils/fileUtils';
import Mutant from './Mutant';
import * as parserUtils from './utils/parserUtils';
import * as log4js from 'log4js';
import {freezeRecursively} from './utils/objectUtils';
import { freezeRecursively, copy } from './utils/objectUtils';
import * as estree from 'estree';
// import 'stryker-api/estree'; TODO: uncomment when doing next major release

const log = log4js.getLogger('Mutator');

Expand Down Expand Up @@ -78,12 +79,12 @@ export default class MutatorOrchestrator {

private registerDefaultMutators() {
let mutatorFactory = MutatorFactory.instance();
mutatorFactory.register('BinaryOperator', BinaryOperatorMutator);
mutatorFactory.register('BlockStatement', BlockStatementMutator);
mutatorFactory.register('ConditionalBoundary', ConditionalBoundaryMutator);
mutatorFactory.register('Math', MathMutator);
mutatorFactory.register('LogicalOperator', LogicalOperatorMutator);
mutatorFactory.register('RemoveConditionals', RemoveConditionalsMutator);
mutatorFactory.register('ReverseConditional', ReverseConditionalMutator);
mutatorFactory.register('UnaryOperator', UnaryOperatorMutator);
mutatorFactory.register('UpdateOperator', UpdateOperatorMutator);
}

/**
Expand All @@ -95,25 +96,31 @@ export default class MutatorOrchestrator {
* @param {AbstractSyntaxTreeNode[]} nodes - The nodes which could be used by mutations to generate mutants.
* @returns {Mutant[]} All possible Mutants for the given set of nodes.
*/
private findMutants(sourceFile: string, originalCode: string, ast: ESTree.Program, nodes: any[]) {
private findMutants(sourceFile: string, originalCode: string, ast: estree.Program, nodes: any[]) {
let mutants: Mutant[] = [];
nodes.forEach((astnode) => {
if (astnode.type) {
Object.freeze(astnode);
this.mutators.forEach((mutator: Mutator) => {
try {
let mutatedNodes = mutator.applyMutations(astnode, (node, deepClone) => {
return deepClone ? _.cloneDeep(node) : _.clone(node);
});
if (mutatedNodes.length > 0) {
log.debug(`The mutator '${mutator.name}' mutated ${mutatedNodes.length} node${mutatedNodes.length > 1 ? 's' : ''} between (Ln ${astnode.loc.start.line}, Col ${astnode.loc.start.column}) and (Ln ${astnode.loc.end.line}, Col ${astnode.loc.end.column}) in file ${sourceFile}`)
let mutatedNodes = mutator.applyMutations(astnode, copy);

if (mutatedNodes) {
if (!Array.isArray(mutatedNodes)) {
mutatedNodes = [mutatedNodes];
}

if (mutatedNodes.length > 0) {
log.debug(`The mutator '${mutator.name}' mutated ${mutatedNodes.length} node${mutatedNodes.length > 1 ? 's' : ''} between (Ln ${astnode.loc.start.line}, Col ${astnode.loc.start.column}) and (Ln ${astnode.loc.end.line}, Col ${astnode.loc.end.column}) in file ${sourceFile}`);
}

mutatedNodes.forEach((mutatedNode: estree.Node) => {
let mutatedCode = parserUtils.generate(mutatedNode);
let originalNode = nodes[(mutatedNode as any).nodeID];
mutants.push(new Mutant(mutator.name, sourceFile, originalCode, mutatedCode, originalNode.loc, originalNode.range));
});
}

mutatedNodes.forEach((mutatedNode: ESTree.Node) => {
let mutatedCode = parserUtils.generate(mutatedNode);
let originalNode = nodes[(<StrykerNode>mutatedNode).nodeID];
mutants.push(new Mutant(mutator.name, sourceFile, originalCode, mutatedCode, originalNode.loc, originalNode.range));
})
} catch (error) {
throw new Error(`The mutator named '${mutator.name}' caused an error: ${error}`);
}
Expand Down
16 changes: 8 additions & 8 deletions src/PluginLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import * as fs from 'fs';
import * as path from 'path';
import * as log4js from 'log4js';
import * as _ from 'lodash';
import {importModule} from './utils/fileUtils'
import { importModule } from './utils/fileUtils';

let log = log4js.getLogger('PluginLoader');

var IGNORED_PACKAGES = ['stryker-cli', 'stryker-api'];
const IGNORED_PACKAGES = ['stryker-cli', 'stryker-api'];

export default class PluginLoader {

Expand All @@ -24,8 +24,8 @@ export default class PluginLoader {

// Plugin directory is the node_modules folder of the module that installed stryker
// So if current __dirname is './stryker/src' than the plugin directory should be 2 directories above
var pluginDirectory = path.normalize(__dirname + '/../..');
var regexp = new RegExp('^' + pluginExpression.replace('*', '.*'));
const pluginDirectory = path.normalize(__dirname + '/../..');
const regexp = new RegExp('^' + pluginExpression.replace('*', '.*'));

log.debug('Loading %s from %s', pluginExpression, pluginDirectory);
let plugins = fs.readdirSync(pluginDirectory)
Expand All @@ -45,11 +45,11 @@ export default class PluginLoader {
modules.push(pluginExpression);
}
} else {
log.warn('Ignoring plugin %s, as its not a string type', pluginExpression)
log.warn('Ignoring plugin %s, as its not a string type', pluginExpression);
}
});

return modules
return modules;
}

private requirePlugin(name: string) {
Expand All @@ -59,9 +59,9 @@ export default class PluginLoader {
} catch (e) {
if (e.code === 'MODULE_NOT_FOUND' && e.message.indexOf(name) !== -1) {
log.warn('Cannot find plugin "%s".\n Did you forget to install it ?\n' +
' npm install %s --save-dev', name, name)
' npm install %s --save-dev', name, name);
} else {
log.warn('Error during loading "%s" plugin:\n %s', name, e.message)
log.warn('Error during loading "%s" plugin:\n %s', name, e.message);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Stryker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export default class Stryker {
return new InputFileResolver(this.config.mutate, this.config.files).resolve()
.then(inputFiles => {
let testRunnerOrchestrator = new TestRunnerOrchestrator(this.config, inputFiles, testSelector, reporter);
return testRunnerOrchestrator.initialRun().then(runResults => ({ runResults, inputFiles, testRunnerOrchestrator }))
return testRunnerOrchestrator.initialRun().then(runResults => ({ runResults, inputFiles, testRunnerOrchestrator }));
})
.then(tuple => {
let runResults = tuple.runResults;
Expand Down
17 changes: 8 additions & 9 deletions src/TestRunnerOrchestrator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import Mutant from './Mutant';
import {Reporter, MutantStatus, MutantResult} from 'stryker-api/report';
import * as log4js from 'log4js';
import {freezeRecursively} from './utils/objectUtils';
const PromisePool = require('es6-promise-pool')
const PromisePool = require('es6-promise-pool');

const log = log4js.getLogger('TestRunnerOrchestrator');

interface FileMap {
[sourceFile: string]: string
[sourceFile: string]: string;
}

interface TestRunnerSandbox {
Expand Down Expand Up @@ -68,7 +68,7 @@ export default class TestRunnerOrchestrator {
if (mutants.length === 0) {
return null; // we're done
} else {
var mutant = mutants.pop();
const mutant = mutants.pop();
if (mutant.scopedTestIds.length > 0) {
let sandbox = sandboxes.pop();
let sourceFileCopy = sandbox.fileMap[mutant.filename];
Expand All @@ -87,7 +87,7 @@ export default class TestRunnerOrchestrator {
return Promise.resolve(this.reporter.onMutantTested(result));
}
}
}
};
return new PromisePool(promiseProducer, sandboxes.length)
.start()
.then(() => this.reportAllMutantsTested(results))
Expand Down Expand Up @@ -146,8 +146,7 @@ export default class TestRunnerOrchestrator {
return result;
}

private runSingleTestsRecursive(sandbox: TestRunnerSandbox, runResults: RunResult[], currentTestIndex: number)
: Promise<RunResult[]> {
private runSingleTestsRecursive(sandbox: TestRunnerSandbox, runResults: RunResult[], currentTestIndex: number): Promise<RunResult[]> {

return new Promise<RunResult[]>(resolve => {
this.selectTestsIfPossible(sandbox, [currentTestIndex])
Expand All @@ -165,7 +164,7 @@ export default class TestRunnerOrchestrator {
resolve(runResults);
}
});
})
});
}

private createTestRunnerSandboxes(): Promise<TestRunnerSandbox[]> {
Expand All @@ -190,7 +189,7 @@ export default class TestRunnerOrchestrator {
}

private createInitializedSandbox(index: number): Promise<TestRunnerSandbox> {
var tempFolder = this.createTempFolder();
const tempFolder = this.createTempFolder();
return this.copyAllFilesToFolder(tempFolder).then(fileMap => {
let testSelectionFilePath: string = null;
if (this.testSelector) {
Expand All @@ -203,7 +202,7 @@ export default class TestRunnerOrchestrator {
}

private createTempFolder() {
var tempFolder = StrykerTempFolder.createRandomFolder('test-runner-files');
const tempFolder = StrykerTempFolder.createRandomFolder('test-runner-files');
log.debug('Creating a sandbox for files in %s', tempFolder);
return tempFolder;
}
Expand Down
Loading

0 comments on commit 1c5db5c

Please sign in to comment.