Files
openlayers/tasks/test-coverage.js
2016-03-31 10:30:58 +02:00

155 lines
4.6 KiB
JavaScript

/**
* This task instruments our source code with istanbul, runs the test suite
* on the instrumented source and collects the coverage data. It then creates
* test coverage reports.
*
* TODO This can be improved in style. We should possibly rewrite it and use
* async.waterfall.
*/
var fs = require('fs-extra');
var istanbul = require('istanbul');
var path = require('path');
var glob = require('glob');
var runTestsuite = require('./test').runTests;
// setup some pathes
var dir = path.join(__dirname, '../src');
var backupDir = path.join(__dirname, '../src-backup');
var instrumentedDir = path.join(__dirname, '../src-instrumented');
var coverageDir = path.join(__dirname, '../coverage');
// The main players in the coverage generation via istanbul
var instrumenter = new istanbul.Instrumenter();
var reporter = new istanbul.Reporter(false, coverageDir);
var collector = new istanbul.Collector();
// General options used for the resource shuffling / directory copying
var copyOpts = {
// Overwrite existing file or directory
clobber: true,
// Preserve the mtime and atime when copying files
preserveTimestamps: true
};
/**
* A small utility method printing out log messages.
* @param {string} msg The message.
*/
var log = function(msg) {
process.stdout.write(msg + '\n');
};
/**
* Creates folders for backup and instrumentation and copies the contents of the
* current src folder into them.
*/
var setupBackupAndInstrumentationDir = function() {
if (!fs.existsSync(backupDir)) {
log('• create directory for backup of src: ' + backupDir);
fs.mkdirSync(backupDir);
}
if (!fs.existsSync(instrumentedDir)) {
log('• create directory for instrumented src: ' + instrumentedDir);
fs.mkdirSync(instrumentedDir);
}
log('• copy src files to backup folder');
fs.copySync(dir, backupDir, copyOpts);
log('• copy src files to instrumentation folder');
fs.copySync(dir, instrumentedDir, copyOpts);
};
/**
* Reverts the changes done in setupBackupAndInstrumentationDir, copies the
* backup over the src directory and removes the instrumentation and backup
* directory.
*/
var revertBackupAndInstrumentationDir = function() {
log('• copy original src back to src folder');
fs.copySync(backupDir, dir, copyOpts);
log('• delete backup directory');
fs.removeSync(backupDir);
log('• delete instrumentation directory');
fs.removeSync(instrumentedDir);
};
/**
* Callback for when runTestsuite() has finished.
*/
var collectAndWriteCoverageData = function() {
log('• collect data from coverage.json');
var coverageFile = path.join(__dirname,'../coverage/coverage.json');
var coverageJson = JSON.parse(fs.readFileSync(coverageFile, 'utf8'));
collector.add(coverageJson);
reporter.addAll(['lcovonly','html']);
revertBackupAndInstrumentationDir();
log('• write report from collected data');
reporter.write(collector, true, function() {
process.exit(0);
});
};
/**
* Will instrument all JavaScript files that are passed as second parameter.
* This is the callback to the glob call.
* @param {Error} err Any error.
* @param {Array.<string>} files List of file paths.
*/
var foundAllJavaScriptSourceFiles = function(err, files) {
if (err) {
process.stderr.write(err.message + '\n');
process.exit(1);
}
log('• instrumenting every src file');
var cnt = 0;
files.forEach(function(file) {
cnt++;
var content = fs.readFileSync(file, 'utf-8');
// derive output file name from input file name, by replacing the *last*
// occurence of /src/ by /src-instrumented/
var re = new RegExp('/src/', 'g');
var m, match;
while ((m = re.exec(file)) !== null) {
match = m;
}
var outfile = file.substr(0, match.index) + '/src-instrumented/' +
file.substr(match.index + '/src/'.length);
var instrumented = instrumenter.instrumentSync(content, file);
fs.writeFileSync(outfile, instrumented);
if (cnt % 10 === 0) {
log(' • instrumented ' + cnt + ' files');
}
});
log(' • done. ' + cnt + ' files instrumented');
log('• copy instrumented src back to src folder');
fs.copySync(instrumentedDir, dir, copyOpts);
log('• run test suite on instrumented code');
runTestsuite({coverage: true, reporter: 'dot'}, collectAndWriteCoverageData);
};
/**
* Our main method, first it sets up certain directory, and then it starts the
* coverage process by gathering all JavaScript files and then instrumenting
* them.
*/
var main = function() {
setupBackupAndInstrumentationDir();
glob(dir + '/**/*.js', {}, foundAllJavaScriptSourceFiles);
};
if (require.main === module) {
main();
}
module.exports = main;