Skip to content

Commit

Permalink
mocha style _perturb spawner; mutant API changes
Browse files Browse the repository at this point in the history
  • Loading branch information
bttmly committed Feb 14, 2015
1 parent 8ba2fc4 commit 038b187
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 77 deletions.
2 changes: 1 addition & 1 deletion .jshintrc
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

// Relaxing
"asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
"boss" : false, // true: Tolerate assignments where comparisons would be expected
"boss" : true, // true: Tolerate assignments where comparisons would be expected
"debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
"eqnull" : true, // true: Tolerate use of `== null`
"es5" : false, // true: Allow ES5 syntax (ex: getters and setters)
Expand Down
12 changes: 6 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
test:
NODE_ENV='testing' ./node_modules/.bin/_mocha ./test/**/*.js
./node_modules/.bin/_mocha ./test/**/*.js

test-example:
NODE_ENV='testing' ./node_modules/.bin/_mocha ./example/test/**/*-test.js
./node_modules/.bin/_mocha ./example/test/**/*-test.js

example:
NODE_ENV='testing' ./bin/perturb -r ./example
./bin/perturb -r ./example

example-i:
NODE_ENV='testing' ./bin/perturb -r ./example -i
./bin/perturb -r ./example -i

dogfood:
NODE_ENV='testing' ./bin/perturb -r ./
./bin/perturb -r ./

dogfood-i:
NODE_ENV='testing' ./bin/perturb -r ./ -i
./bin/perturb -r ./ -i

.PHONY: test example
53 changes: 53 additions & 0 deletions bin/_perturb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env node

"use strict";

console.log(process.argv);

var program = require("commander");

var path = require("path");

var perturb = require("../");
var util = require("../lib/util");
var pkg = require("../package.json");

function assignNoUndefined (target, source) {
Object.keys(source).forEach(function (key) {
if (source[key] === undefined) return;
target[key] = source[key];
});
return target;
}

program
.version(pkg.version)
.option("-r, --rootDir <rootDir>", "root directory of the project")
.option("-t, --testDir <testDir>", "test directory relative to root directory")
.option("-s, --sourceDir <sourceDir>", "source directory relative to root directory")
.option("-x, --testGlob <testGlob>", "glob for selecting files in test directory")
.option("-y, --sourceGlob <sourceGlob>", "glob for selecting files in source directory")
.option("-i, --interception", "use interception strategy (no disk I/O)")
.parse(process.argv);

if (program.rootDir && program.rootDir[0] !== "/") {
program.rootDir = path.join(process.cwd(), program.rootDir);
}

var config = assignNoUndefined({}, {
rootDir: program.rootDir,
testDir: program.testDir,
sourceDir: program.sourceDir,
testGlob: program.testGlob,
sourceGlob: program.sourceGlob,
interception: program.interception
});

// this will become the default reporter
function reporter (err, data) {
if (err) throw err;
var mutants = data.matches[0].mutations;
console.log(data.meta);
}

perturb(config, reporter);
91 changes: 51 additions & 40 deletions bin/perturb
Original file line number Diff line number Diff line change
@@ -1,50 +1,61 @@
#!/usr/bin/env node
#!/usr/bin/env node

"use strict";
// shamelessly appropriated from mocha

var program = require("commander");
"use strict";

var path = require("path");

var perturb = require("../");
var util = require("../lib/util");
var pkg = require("../package.json");
var spawn = require("child_process").spawn;
var perturb = path.join(__dirname, "_perturb");
var args = [perturb];

var bin = process.argv[0];

process.argv.slice(2).forEach(function (arg) {
var flag = arg.split("=")[0];

switch (flag) {

case "--iojs":
return bin = "iojs";

case "--harmony":
case "--harmony-proxies":
case "--harmony-collections":
case "--harmony-generators":
case "--harmony_shipping":
case "--harmony_arrow_functions":
case "--harmony_proxies":
return args.unshift(arg);

default:
return args.push(arg);

function assignNoUndefined (target, source) {
Object.keys(source).forEach(function (key) {
if (source[key] === undefined) return;
target[key] = source[key];
}

});

console.log([bin].concat(args).join(" "));

var proc = spawn(bin, args, {stdio: 'inherit'});


proc.on('exit', function (code, signal) {
process.on('exit', function(){
if (signal) {
process.kill(process.pid, signal);
} else {
process.exit(code);
}
});
return target;
}

program
.version(pkg.version)
.option("-r, --rootDir <rootDir>", "root directory of the project")
.option("-t, --testDir <testDir>", "test directory relative to root directory")
.option("-s, --sourceDir <sourceDir>", "source directory relative to root directory")
.option("-x, --testGlob <testGlob>", "glob for selecting files in test directory")
.option("-y, --sourceGlob <sourceGlob>", "glob for selecting files in source directory")
.option("-i, --interception", "use interception strategy (no disk I/O)")
.parse(process.argv);

if (program.rootDir && program.rootDir[0] !== "/") {
program.rootDir = path.join(process.cwd(), program.rootDir);
}

var config = assignNoUndefined({}, {
rootDir: program.rootDir,
testDir: program.testDir,
sourceDir: program.sourceDir,
testGlob: program.testGlob,
sourceGlob: program.sourceGlob,
interception: program.interception
});

// this will become the default reporter
function reporter (err, data) {
if (err) throw err;
console.log(data.meta);
}
proc.on('error', console.log);

perturb(config, reporter);
// terminate children.
process.on('SIGINT', function () {
proc.kill('SIGINT'); // calls runner.abort()
proc.kill('SIGTERM'); // if that didn't work, we're probably in an infinite loop, so make it die.
process.kill(process.pid, 'SIGINT');
});
7 changes: 4 additions & 3 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,7 @@ function perturb (settings, cb) {

meta.matchesProcessed = matches.length;

// swap this out for a reporter
config.configReporter(assign(config, {
assign(config, {
originalDir: oRoot,
originalSourceDir: oSource,
originalTestDir: oTest,
Expand All @@ -106,7 +105,9 @@ function perturb (settings, cb) {
perturbTestFiles: pTests,

matches: matches
}));
});

config.configReporter(config);

var start = process.hrtime();

Expand Down
49 changes: 29 additions & 20 deletions lib/run-mutation.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ function generateDiff (mutation) {
});
}

function formatMutation (mutation, counters) {
var result = assign({}, mutation, counters);
// var result = assign(pick(mutation, "loc", "name", "mutSourceCode"), counters);
function formatMutation (mutation) {
var result = assign({}, mutation);
result.loc = result.loc.start.line + "," + result.loc.start.column;
if (!result.failed.length) {
if (!result.failed) {
result.diff = generateDiff(mutation);
}
return result;
Expand Down Expand Up @@ -61,12 +60,17 @@ function makeFailCollector (counters) {
// this will take a MutantReporter eventually
function runMutationWithIo (mutation, mutantReporter, done) {

var counters = {
passed: [],
failed: []
};
mutation.passedCount = 0;

var mochaReporter = makeFailCollector(counters);
function mochaReporter (runner) {
runner
.on("pass", function () {
mutation.passedCount += 1;
})
.on("fail", function (test) {
mutation.failed = test.fullTitle();
});
}

fs.writeFileSync(mutation.sourceFile, mutation.mutSourceCode);

Expand All @@ -76,16 +80,16 @@ function runMutationWithIo (mutation, mutantReporter, done) {
d.on("error", function (err) {
d.exit();
process.nextTick(function () {
counters.failed.push(failFromError(err));
finish(formatMutation(mutation, counters), mutantReporter, done);
mutation.failed = err.toString();
finish(formatMutation(mutation), mutantReporter, done);
});
});

d.run(function () {
new Mocha({reporter: mochaReporter, bail: true})
.addFile(mutation.testFile)
.run(function () {
finish(formatMutation(mutation, counters), mutantReporter, done);
finish(formatMutation(mutation), mutantReporter, done);
});
});

Expand All @@ -98,18 +102,23 @@ function runMutationWithIo (mutation, mutantReporter, done) {
// substantial speed gains, but it's performance and stability must first be examined.
function runMutationWithInterception (mutation, mutantReporter, done) {

var counters = {
passed: [],
failed: []
};
mutation.passedCount = 0;

var mochaReporter = makeFailCollector(counters);
function mochaReporter (runner) {
runner
.on("pass", function () {
mutation.passedCount += 1;
})
.on("fail", function (test) {
mutation.failed = test.fullTitle();
});
}

var mutatedModule = makeModule(mutation.mutSourceCode, mutation.sourceFile);

if (mutatedModule.error) {
counters.failed.push(failFromError(mutatedModule.error));
return finish(formatMutation(mutation, counters), mutantReporter, done);
mutation.failed = mutatedModule.error.toString();
return finish(formatMutation(mutation), mutantReporter, done);
}

intercept.attach({
Expand All @@ -131,7 +140,7 @@ function runMutationWithInterception (mutation, mutantReporter, done) {
new Mocha({reporter: mochaReporter, bail: true})
.addFile(mutation.testFile)
.run(function () {
finish(formatMutation(mutation, counters), mutantReporter, done);
finish(formatMutation(mutation), mutantReporter, done);
});
}

Expand Down
6 changes: 3 additions & 3 deletions lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,15 @@ var util = module.exports = {
},

mutantIsDead: function (mutant) {
return !!mutant.failed.length;
return !!mutant.failed;
},

mutantIsZombie: function (mutant) {
return !mutant.passed.length && !mutant.failed.length;
return mutant.passedCount && !mutant.failed;
},

mutantIsAlive: function (mutant) {
return mutant.passed.length && !mutant.failed.length;
return mutant.passedCount && !mutant.failed;
},

countAllMutants: function (matches) {
Expand Down
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
"version": "0.1.0",
"description": "",
"main": "index.js",
"bin": "./bin/perturb",
"bin": {
"perturb": "./bin/perturb",
"_perturb": "./bin/_perturb"
},
"repository": "git@github.com:nickb1080/perturb.git",
"dependencies": {
"async": "^0.9.0",
Expand All @@ -16,7 +19,7 @@
"fs-extra": "^0.16.3",
"glob": "^4.3.2",
"immutable": "^3.5.0",
"intercept-require": "^1.0.0",
"intercept-require": "^0.6.1",
"lodash.find": "^3.0.0",
"lodash.last": "^3.0.0",
"lodash.partial": "^3.0.0",
Expand All @@ -34,7 +37,7 @@
"watch": "^0.13.0"
},
"scripts": {
"example": "NODE_ENV='testing' ./bin/perturb -r ./example",
"example": "./bin/perturb -r ./example",
"example-i": "NODE_ENV='testing' ./bin/perturb -r ./example -i",
"test-example": "mocha ./example/test/**/*-test.js",
"dogfood": "make dogfood",
Expand All @@ -43,4 +46,4 @@
},
"author": "Nick Bottomley (github.com/nickb1080)",
"license": "MIT"
}
}

0 comments on commit 038b187

Please sign in to comment.