interpreted
Version:
node-tap wrapper for testing input/output functionality
218 lines (174 loc) • 5.23 kB
JavaScript
var fs = require('fs');
var tap = require('tap');
var path = require('path');
var util = require('util');
var async = require('async');
var events = require('events');
var extend = require('util-extend');
function Intrepreted(settings) {
if (!(this instanceof Intrepreted)) return new Intrepreted(settings);
var self = this;
this._readSource = settings.hasOwnProperty('readSource') ? !!settings.readSource : true;
this.source = path.resolve(settings.source);
this.expected = path.resolve(settings.expected);
this.update = !!settings.update;
this.run = Array.isArray(settings.run) ? settings.run : null;
this.methods = {
start: settings.start,
close: settings.close,
test: settings.test
};
this.files = {
source: {},
expected: {},
total: []
};
this.types = extend({
'json': {
test: function (t, actual, expected) {
t.deepEqual(actual, JSON.parse(expected));
},
update: function (actual) {
return JSON.stringify(actual, null, '\t');
}
},
'default': {
test: function (t, actual, expected) {
t.strictEqual(actual, expected);
},
update: function (actual) {
return actual;
}
}
}, settings.types);
this.tapOptions = settings.tap || {};
this._readdir(function (err) {
if (err) return self.emit('error', err);
// if no run files was set use all files
if (self.run === null) {
self.run = self.files.total;
}
// validate run files
self._validateFiles();
self._assignStart();
self.run.forEach(self._assignTest, self);
self._assignClose();
});
}
module.exports = Intrepreted;
util.inherits(Intrepreted, events.EventEmitter);
Intrepreted.prototype._assignStart = function (callback) {
var self = this;
if (this.methods.start === undefined) return;
tap.test('start interpreted tester', this.tapOptions, function (t) {
process.nextTick(function () {
self.methods.start(function (err) {
if (err) throw err;
t.end();
});
});
});
};
Intrepreted.prototype._assignClose = function (callback) {
var self = this;
if (this.methods.close === undefined) return;
tap.test('close interperted tester', this.tapOptions, function (t) {
process.nextTick(function () {
self.methods.close(function (err) {
if (err) throw err;
t.end();
});
});
});
};
Intrepreted.prototype._assignTest = function (name) {
var self = this;
tap.test('test ' + name + ' interpreted', this.tapOptions, function (t) {
async.parallel({
source: function (done) {
if (self._readSource) {
fs.readFile(self.files.source[name], 'utf8', done);
} else {
done(null, null);
}
},
expected: function (done) {
fs.readFile(self.files.expected[name], 'utf8', done);
}
}, function (err, file) {
if (err) throw err;
if (self._readSource) {
self.methods.test(name, file.source, posttest);
} else {
self.methods.test(name, posttest);
}
function posttest(err, result) {
if (err) throw err;
var expectedPath = self.files.expected[name];
var extname = path.extname(expectedPath).slice(1);
var validater = self.types[extname] || self.types['default'];
if (self.update) {
fs.writeFile(expectedPath, validater.update(result), function (err) {
if (err) throw err;
t.end();
});
} else {
validater.test(t, result, file.expected);
t.end();
}
}
});
});
};
// validate run files
Intrepreted.prototype._validateFiles = function () {
for (var i = 0; i < this.run.length; i++) {
if (this.files.source.hasOwnProperty(this.run[i]) === false) {
return this.emit('error',
new Error(this.run[i] + ' source file is missing')
);
}
if (this.files.expected.hasOwnProperty(this.run[i]) === false) {
return this.emit('error',
new Error(this.run[i] + ' expected file is missing')
);
}
}
};
Intrepreted.prototype._readdir = function (callback) {
var self = this;
var files = this.files;
function readDir(name) {
return function (done) {
fs.readdir(self[name], function (err, content) {
if (err) return done(err);
// create a object map between name and full filepath
var map = {}, basename;
for (var i = 0; i < content.length; i++) {
if (content[i][0] === '.') continue;
basename = path.basename(content[i], path.extname(content[i]));
map[basename] = path.resolve(self[name], content[i]);
}
files[name] = map;
done(null);
});
};
}
async.parallel([
readDir('source'),
readDir('expected')
], function (err) {
if (err) return callback(err);
// create a unique total list
var unique = {};
Object.keys(files.source).forEach(function (name) {
unique[name] = true;
});
Object.keys(files.expected).forEach(function (name) {
unique[name] = true;
});
files.total = Object.keys(unique);
// done
callback(null);
});
};