Skip to content

Commit

Permalink
better reporter passing and enforcement of test command
Browse files Browse the repository at this point in the history
  • Loading branch information
bttmly committed Feb 11, 2015
1 parent 7022269 commit 99e89d0
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 46 deletions.
16 changes: 16 additions & 0 deletions lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,21 @@ var JS_TYPES = util.constObj({
obj: "object"
});

var BINARY_OPERATOR_SWAPS = util.constObj({
"+": "-",
"-": "+",
"*": "/",
"/": "*",
">": "<=",
"<=": ">",
"<": ">=",
">=": "<",
"==": "!=",
"!=": "==",
"===": "!==",
"!==": "==="
});

var NODE_TYPES = util.mapMirror([
"AssignmentExpression",
"ArrayExpression",
Expand Down Expand Up @@ -76,6 +91,7 @@ var ERRORS = util.constObj({
});

module.exports = {
BINARY_OPERATOR_SWAPS: BINARY_OPERATOR_SWAPS,
NODES_WITH_TEST: NODES_WITH_TEST,
NODE_TYPES: NODE_TYPES,
FUNC_NODES: FUNC_NODES,
Expand Down
10 changes: 4 additions & 6 deletions lib/handle-match.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,11 @@ var ENC_UTF8 = util.constObj({
encoding: "utf8"
});

function mutantReporter (mutant) {
console.log(util.prettyPrintMutant(mutant));
}


module.exports = handleMatch;
function handleMatch (match, done) {

var config = global.__perturb__;

async.parallel({
sourceCode: partial(fs.readFile, match.sourceFile, ENC_UTF8),
testCode: partial(fs.readFile, match.testFile, ENC_UTF8)
Expand Down Expand Up @@ -91,7 +89,7 @@ function handleMatch (match, done) {
}

async.mapSeries(mutations, function (mutant, next) {
runMutation(mutant, mutantReporter, next);
runMutation(mutant, config.mutantReporter, next);
}, finish);

});
Expand Down
25 changes: 15 additions & 10 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ process.setMaxListeners(0);

var EventEmitter = require("events").EventEmitter;
var path = require("path");
var exec = require("child_process").exec;

var npm = require("npm");
var async = require("async");
Expand All @@ -28,11 +29,16 @@ var DEFAULT_TEST = "test";
var PERTURB_DIR = ".perturb";
var DEFAULT_GLOB = "/**/*.js";

// module.exports = function (settings, cb) {
// npm.commands['run-script']("test", perturb.bind(null, settings, cb));
// };
module.exports = function (settings, cb) {
var cmd = settings.testCommand || "npm test";
console.log("executing `", cmd, "` ...");
exec(cmd, function (err) {
if (err) throw new Error("Test command failed. Tests must be passing for perturb to work properly.");
perturb(settings, cb);
});
};


module.exports = perturb;
function perturb (settings, cb) {

if (typeof settings === JS_TYPES.str) {
Expand Down Expand Up @@ -125,17 +131,12 @@ function perturb (settings, cb) {

function defaultConfig () {

return {
var config = {
rootDir: process.cwd(),
sourceDir: DEFAULT_SOURCE,
testDir: DEFAULT_TEST,
sourceGlob: DEFAULT_GLOB,
testGlob: DEFAULT_GLOB,
reporter: reporters.defaultReporter,

matchReporter: function (data) { console.log(data); },
mutantReporter: function (data) { console.log(data); },
summaryReporter: function (data) { console.log(data); },

matcher: function defaultMatcher (sourceFile, testFile) {
var sName = sourceFile
Expand All @@ -147,6 +148,10 @@ function defaultConfig () {
return sName.replace(".js", "-test.js") === tName;
},
};

assign(config, reporters);

return config;
}

function perturbMatch (sourceFiles, testFiles, matcher) {
Expand Down
17 changes: 7 additions & 10 deletions lib/reporters.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
"use strict";

module.exports = {
defaultReporter: function defaultReporter (err, matches) {
if (err) throw err;
console.log(matches);
}
};

var util = require("./util");

module.exports = {
defaultMatchReporter: function defaultMatchReporter (err, matches) {
configReporter: function defaultConfigReporter (config) {
console.log(config);
},

matchReporter: function defaultMatchReporter (err, matches) {
if (err) throw(err);
console.log(matches);
},

defaultMutantReporter: function defaultMutantReporter (mutant) {
mutantReporter: function defaultMutantReporter (mutant) {
console.log(util.prettyPrintMutant(mutant));
},

defaultSummaryReporter: function defaultSummaryReporter (summary) {
summaryReporter: function defaultSummaryReporter (summary) {
console.log(summary);
}
};
41 changes: 21 additions & 20 deletions lib/run-mutation.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,10 @@ var fs = require("fs-extra");
var Mocha = require("mocha");
var diff = require("diff");
var assign = require("object-assign");
var pick = require("lodash.pick");
var makeModule = require("make-module");
var intercept = require("intercept-require");

var util = require("./util");
var handlers = require("./mocha-handlers");

function clearCache (mutation) {
// if(!require.cache[mutation.sourceFile]) throw new Error();
delete require.cache[mutation.testFile];
delete require.cache[mutation.sourceFile];
}
Expand Down Expand Up @@ -51,41 +46,46 @@ function failFromError (err) {
};
}

// this will take a MutantReporter eventually
function runMutationWithIo (mutation, reporter, done) {

function mReporter (runner) {
function makeFailCollector (counters) {
return function failCollector (runner) {
runner
.on("pass", function (test) {
counters.passed.push(test.fullTitle());
})
.on("fail", function (test) {
counters.failed.push(test.fullTitle());
});
}
};
}

// this will take a MutantReporter eventually
function runMutationWithIo (mutation, mutantReporter, done) {

var counters = {
passed: [],
failed: []
};

var mochaReporter = makeFailCollector(counters);

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

// Wrap the mocha runner in a domain so that we can catch compile errors from mutated code
var d = domain.create();

d.on("error", function (err) {
d.exit();
process.nextTick(function () {
counters.failed.push(failFromError(err));
finish(formatMutation(mutation, counters), reporter, done);
finish(formatMutation(mutation, counters), mutantReporter, done);
});
});

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

Expand All @@ -96,18 +96,20 @@ function runMutationWithIo (mutation, reporter, done) {
// entirely by generating modules directly from mutated source code, and short circuiting
// the `require` mechanism of the module under test. In larger projects it may exhibit
// substantial speed gains, but it's performance and stability must first be examined.
function runMutationWithInterception (mutation, reporter, done) {
function runMutationWithInterception (mutation, mutantReporter, done) {

var counters = {
passed: [],
failed: []
};

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

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

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

intercept.attach({
Expand All @@ -125,15 +127,14 @@ function runMutationWithInterception (mutation, reporter, done) {
return result;
});

new Mocha({reporter: handlers.reporter(counters)})

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



module.exports = function (mutant, reporter, done) {
if (global.__perturb__.interception) {
return runMutationWithInterception(mutant, reporter, done);
Expand Down

0 comments on commit 99e89d0

Please sign in to comment.