mo/run-spec.js

242 lines
6.5 KiB
JavaScript
Raw Permalink Normal View History

#!/usr/bin/env node
var async, exec, fs, summary;
function makeShellString(value) {
if (typeof value === 'string') {
// Newlines are tricky
return value.split(/\n/).map(function (chunk) {
return JSON.stringify(chunk);
}).join('"\n"');
}
if (typeof value === 'number') {
return value;
}
return 'ERR_CONVERTING';
}
function addToEnvironment(name, value) {
var result;
if (Array.isArray(value)) {
result = [
'('
];
value.forEach(function (subValue) {
result.push(makeShellString(subValue));
});
result.push(')');
return name + '=' + result.join(' ');
}
// Sometimes the __tag__ property of the code in the lambdas may
// be missing. :-(
if (typeof value === 'object') {
if (value.__tag__ === 'code' || (value.ruby && value.php && value.perl)) {
if (value.bash) {
return name + '() { ' + value.bash + '; }';
}
return name + '() { perl -e \'print ((' + value.perl + ')->("\'"$1"\'"))\'; }';
}
}
if (typeof value === 'object') {
return '# ' + name + ' is an object and will not work in bash';
}
if (typeof value === 'boolean') {
if (value) {
return name + '="true"';
}
return name + '=""';
}
return name + '=' + makeShellString(value);
}
function runTest(test, done) {
var output, partials, script;
script = [
'#!/bin/bash'
];
partials = test.partials || {};
Object.keys(test.data).forEach(function (name) {
script.push(addToEnvironment(name, test.data[name]));
});
script.push('. mo');
script.push('mo spec-runner/spec-template');
test.script = script.join('\n');
async.series([
function (taskDone) {
fs.mkdir("spec-runner/", function (err) {
if (err && err.code !== 'EEXIST') {
return taskDone(err);
}
taskDone();
});
},
function (taskDone) {
fs.writeFile('spec-runner/spec-script', test.script, taskDone);
},
function (taskDone) {
fs.writeFile('spec-runner/spec-template', test.template, taskDone);
},
function (taskDone) {
async.eachSeries(Object.keys(partials), function (partialName, partialDone) {
fs.writeFile('spec-runner/' + partialName, test.partials[partialName], partialDone);
}, taskDone);
},
function (taskDone) {
exec('bash spec-runner/spec-script', function (err, stdout) {
if (err) {
return taskDone(err);
}
output = stdout;
taskDone();
});
},
function (taskDone) {
async.eachSeries(Object.keys(partials), function (partialName, partialDone) {
fs.unlink('spec-runner/' + partialName, partialDone);
}, taskDone);
},
function (taskDone) {
fs.unlink('spec-runner/spec-script', taskDone);
},
function (taskDone) {
fs.unlink('spec-runner/spec-template', taskDone);
},
function (taskDone) {
fs.rmdir('spec-runner/', taskDone);
}
], function (err) {
if (err) {
return done(err);
}
done(null, output);
});
return '';
}
function prepareAndRunTest(test, done) {
async.waterfall([
function (taskDone) {
console.log('### ' + test.name);
console.log('');
console.log(test.desc);
console.log('');
runTest(test, taskDone);
},
function (actual, taskDone) {
test.actual = actual;
test.pass = (test.actual === test.expected);
if (test.pass) {
console.log('Passed.');
} else {
console.log('Failed.');
console.log('');
console.log(test);
}
console.log('');
taskDone();
}
], done);
}
function specFileToName(file) {
return file.replace(/.*\//, '').replace('.json', '').replace('~', '').replace(/(^|-)[a-z]/g, function (match) {
return match.toUpperCase();
});
}
function processSpecFile(specFile, done) {
fs.readFile(specFile, 'utf8', function (err, data) {
var name;
if (err) {
return done(err);
}
name = specFileToName(specFile);
data = JSON.parse(data);
console.log(name);
console.log('====================');
console.log('');
console.log(data.overview);
console.log('');
console.log('Tests');
console.log('-----');
console.log('');
async.series([
function (taskDone) {
async.eachSeries(data.tests, prepareAndRunTest, taskDone);
},
function (taskDone) {
summary[name] = {};
data.tests.forEach(function (test) {
summary[name][test.name] = test.pass;
});
taskDone();
}
], done);
});
}
// 0 = node, 1 = script, 2 = file
if (process.argv.length < 3) {
console.log('Specify one or more JSON spec files on the command line');
process.exit();
}
async = require('async');
fs = require('fs');
exec = require('child_process').exec;
summary = {};
async.eachSeries(process.argv.slice(2), processSpecFile, function () {
var fail, pass;
console.log('');
console.log('Summary');
console.log('=======');
console.log('');
pass = 0;
fail = 0;
Object.keys(summary).forEach(function (name) {
var groupPass, groupFail, testResults;
testResults = [];
groupPass = 0;
groupFail = 0;
Object.keys(summary[name]).forEach(function (testName) {
if (summary[name][testName]) {
testResults.push(' * pass - ' + testName);
groupPass += 1;
pass += 1;
} else {
testResults.push(' * FAIL - ' + testName);
groupFail += 1;
fail += 1;
}
});
testResults.unshift('* ' + name + ' (failed ' + groupFail + ' out of ' + (groupPass + groupFail) + ' tests)');
console.log(testResults.join('\n'));
});
console.log('');
console.log('Failed ' + fail + ' out of ' + (pass + fail) + ' tests');
});