showdown/test/performance/performance.js
2016-12-23 10:07:14 +00:00

238 lines
5.9 KiB
JavaScript

/**
* Created by Tivie on 21/12/2016.
*/
'use strict';
var now = require('performance-now'),
fs = require('fs'),
semverSort = require('semver-sort'),
performance = {
version: '',
libraryName: '',
MDFile: 'performance.log.md',
logFile: 'performance.json',
testSuites: [],
silent: false,
githubLink: ''
};
performance.setVersion = function (version) {
performance.version = version;
};
performance.setLibraryName = function (name) {
performance.libraryName = name;
};
performance.setGithubLink = function (url) {
performance.githubLink = url;
};
performance.generateLog = function (filename, MDFilename, asTable) {
filename = filename || performance.logFile;
MDFilename = MDFilename || performance.MDFile;
asTable = !!asTable;
fs.closeSync(fs.openSync(filename, 'a'));
var json = fs.readFileSync(filename),
jsonParsed;
try {
jsonParsed = JSON.parse(json);
}
catch (err) {
jsonParsed = {};
}
var jData = [];
for (var i = 0; i < performance.testSuites.length; ++i) {
// Suite
var suiteName = performance.testSuites[i].getSuiteName(),
cycles = performance.testSuites[i].getOption('cycles'),
subJData = {
suiteName: suiteName,
cycles: cycles,
tests: []
},
testSuite = performance.testSuites[i].getTests();
//make sure tests have ran first
if (!performance.testSuites[i].hasRun()) {
performance.testSuites[i].run();
}
// loop through tests
for (var ii = 0; ii < testSuite.length; ++ii) {
// Test
var test = testSuite[ii];
subJData.tests.push({
name: test.name,
time: test.time,
maxTime: test.maxTime,
minTime: test.minTime
});
}
jData.push(subJData);
}
jsonParsed[performance.version] = jData;
//Sort jsonParsed
var versions = [];
for (var version in jsonParsed) {
if (jsonParsed.hasOwnProperty(version)) {
versions.push(version);
}
}
semverSort.desc(versions);
var finalJsonObj = {};
for (i = 0; i < versions.length; ++i) {
if (jsonParsed.hasOwnProperty(versions[i])) {
finalJsonObj[versions[i]] = jsonParsed[versions[i]];
}
}
fs.writeFileSync(filename, JSON.stringify(finalJsonObj));
generateMD(MDFilename, finalJsonObj, asTable);
};
function generateMD(filename, obj, asTable) {
fs.closeSync(fs.openSync(filename, 'w'));
asTable = !!asTable;
// generate MD
var otp = '# Performance Tests for ' + performance.libraryName + '\n\n\n';
for (var version in obj) {
if (obj.hasOwnProperty(version)) {
otp += '## [version ' + version + '](' + performance.githubLink + ')\n\n';
var testSuite = obj[version];
for (var i = 0; i < testSuite.length; ++i) {
otp += '### Test Suite: ' + testSuite[i].suiteName + ' (' + testSuite[i].cycles + ' cycles)\n';
var tests = testSuite[i].tests;
if (asTable) {
otp += '| test | avgTime | max | min |\n';
otp += '|:-----|--------:|----:|----:|\n';
}
for (var ii = 0; ii < tests.length; ++ii) {
var time = parseFloat(tests[ii].time).toFixed(3),
maxTime = parseFloat(tests[ii].maxTime).toFixed(3),
minTime = parseFloat(tests[ii].minTime).toFixed(3);
if (asTable) {
otp += '|' + tests[ii].name + '|' + time + '|' + maxTime + '|' + minTime + '|\n';
} else {
otp += ' - **' + tests[ii].name + ':** took ' + time + 'ms (*max: ' + maxTime + 'ms; min: ' + minTime + 'ms*)\n';
}
}
otp += '\n';
}
otp += '\n';
}
}
fs.writeFileSync(filename, otp);
}
performance.Suite = function (name) {
var suiteName = name || '',
tests = [],
hasRunFlag = false,
options = {
cycles: 20
};
this.setOption = function (key, val) {
options[key] = val;
return this;
};
this.getOption = function (key) {
return options[key];
};
this.add = function (name, obj) {
if (typeof obj === 'function') {
obj = {
prepare: function () {},
test: obj,
teardown: function () {}
};
}
if (!obj.hasOwnProperty('test')) {
throw 'obj must have a property called test';
}
if (typeof obj.test !== 'function') {
throw 'obj test property must be a function';
}
if (!obj.hasOwnProperty('prepare')) {
obj.prepare = function () {};
}
if (!obj.hasOwnProperty('teardown')) {
obj.teardown = function () {};
}
if (typeof obj.prepare !== 'function') {
throw 'obj prepare property must be a function';
}
if (typeof obj.teardown !== 'function') {
throw 'obj teardown property must be a function';
}
tests.push({
name: name,
obj: obj,
time: 0,
maxTime: 0,
minTime: 0
});
return this;
};
this.run = function run () {
var nn = options.cycles;
console.log('running tests: ' + nn + ' cycles each.');
for (var i = 0; i < tests.length; ++i) {
var times = [],
passVar = tests[i].obj.prepare();
for (var ii = 0; ii < nn; ++ii) {
var before = now();
tests[i].obj.test(passVar);
var after = now();
times.push(after - before);
}
var total = times.reduce(function (a, b) {return a + b;}, 0);
tests[i].time = total / options.cycles;
tests[i].minTime = Math.min.apply(null, times);
tests[i].maxTime = Math.max.apply(null, times);
if (!options.silent) {
console.log(tests[i].name + ' took an average of ' + tests[i].time + 'ms (min: ' + tests[i].minTime + 'ms; max: ' + tests[i].maxTime + 'ms');
}
}
hasRunFlag = true;
return this;
};
this.hasRun = function () {
return hasRunFlag;
};
this.getSuiteName = function () {
return suiteName;
};
this.getTests = function () {
return tests;
};
performance.testSuites.push(this);
};
module.exports = performance;