Test code refactor #63

Use mocha for feature-specific unit tests

Add test coverage report via istanbul
This commit is contained in:
Lovell Fuller
2014-10-20 15:32:56 +01:00
parent f4cb577cb4
commit ca561daedf
37 changed files with 1341 additions and 1223 deletions

21
test/bench/package.json Executable file
View File

@@ -0,0 +1,21 @@
{
"name": "sharp-benchmark",
"version": "0.0.1",
"private": true,
"author": "Lovell Fuller <npm@lovell.info>",
"description": "Benchmark and performance tests for sharp",
"scripts": {
"test": "node perf && node random && node parallel"
},
"devDependencies": {
"imagemagick": "^0.1.3",
"imagemagick-native": "^1.4.0",
"gm": "^1.16.0",
"async": "^0.9.0",
"benchmark": "^1.0.0"
},
"license": "Apache 2.0",
"engines": {
"node": ">=0.10"
}
}

41
test/bench/parallel.js Executable file
View File

@@ -0,0 +1,41 @@
'use strict';
var assert = require('assert');
var async = require('async');
var sharp = require('../../index');
var fixtures = require('../fixtures');
var width = 720;
var height = 480;
sharp.concurrency(1);
var timer = setInterval(function() {
console.dir(sharp.counters());
}, 100);
async.mapSeries([1, 1, 2, 4, 8, 16, 32, 64, 128], function(parallelism, next) {
var start = new Date().getTime();
async.times(parallelism,
function(id, callback) {
/*jslint unused: false */
sharp(fixtures.inputJpg).resize(width, height).toBuffer(function(err, buffer) {
buffer = null;
callback(err, new Date().getTime() - start);
});
},
function(err, ids) {
assert(!err);
assert(ids.length === parallelism);
var mean = ids.reduce(function(a, b) {
return a + b;
}) / ids.length;
console.log(parallelism + ' parallel calls: fastest=' + ids[0] + 'ms slowest=' + ids[ids.length - 1] + 'ms mean=' + mean + 'ms');
next();
}
);
}, function() {
clearInterval(timer);
console.dir(sharp.counters());
});

493
test/bench/perf.js Executable file
View File

@@ -0,0 +1,493 @@
'use strict';
var fs = require('fs');
var async = require('async');
var assert = require('assert');
var Benchmark = require('benchmark');
var imagemagick = require('imagemagick');
var imagemagickNative = require('imagemagick-native');
var gm = require('gm');
var sharp = require('../../index');
var fixtures = require('../fixtures');
var width = 720;
var height = 480;
// Disable libvips cache to ensure tests are as fair as they can be
sharp.cache(0);
async.series({
jpeg: function(callback) {
var inputJpgBuffer = fs.readFileSync(fixtures.inputJpg);
(new Benchmark.Suite('jpeg')).add('imagemagick-file-file', {
defer: true,
fn: function(deferred) {
imagemagick.resize({
srcPath: fixtures.inputJpg,
dstPath: fixtures.outputJpg,
quality: 0.8,
width: width,
height: height
}, function(err) {
if (err) {
throw err;
} else {
deferred.resolve();
}
});
}
}).add('imagemagick-native-buffer-buffer', {
defer: true,
fn: function(deferred) {
imagemagickNative.convert({
srcData: inputJpgBuffer,
quality: 80,
width: width,
height: height,
format: 'JPEG'
});
deferred.resolve();
}
}).add('gm-buffer-file', {
defer: true,
fn: function(deferred) {
gm(inputJpgBuffer).resize(width, height).quality(80).write(fixtures.outputJpg, function (err) {
if (err) {
throw err;
} else {
deferred.resolve();
}
});
}
}).add('gm-buffer-buffer', {
defer: true,
fn: function(deferred) {
gm(inputJpgBuffer).resize(width, height).quality(80).toBuffer(function (err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('gm-file-file', {
defer: true,
fn: function(deferred) {
gm(fixtures.inputJpg).resize(width, height).quality(80).write(fixtures.outputJpg, function (err) {
if (err) {
throw err;
} else {
deferred.resolve();
}
});
}
}).add('gm-file-buffer', {
defer: true,
fn: function(deferred) {
gm(fixtures.inputJpg).resize(width, height).quality(80).toBuffer(function (err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-buffer-file', {
defer: true,
fn: function(deferred) {
sharp(inputJpgBuffer).resize(width, height).toFile(fixtures.outputJpg, function(err) {
if (err) {
throw err;
} else {
deferred.resolve();
}
});
}
}).add('sharp-buffer-buffer', {
defer: true,
fn: function(deferred) {
sharp(inputJpgBuffer).resize(width, height).toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-file-file', {
defer: true,
fn: function(deferred) {
sharp(fixtures.inputJpg).resize(width, height).toFile(fixtures.outputJpg, function(err) {
if (err) {
throw err;
} else {
deferred.resolve();
}
});
}
}).add('sharp-stream-stream', {
defer: true,
fn: function(deferred) {
var readable = fs.createReadStream(fixtures.inputJpg);
var writable = fs.createWriteStream(fixtures.outputJpg);
writable.on('finish', function() {
deferred.resolve();
});
var pipeline = sharp().resize(width, height);
readable.pipe(pipeline).pipe(writable);
}
}).add('sharp-file-buffer', {
defer: true,
fn: function(deferred) {
sharp(fixtures.inputJpg).resize(width, height).toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-promise', {
defer: true,
fn: function(deferred) {
sharp(inputJpgBuffer).resize(width, height).toBuffer().then(function(buffer) {
assert.notStrictEqual(null, buffer);
deferred.resolve();
});
}
}).add('sharp-sharpen', {
defer: true,
fn: function(deferred) {
sharp(inputJpgBuffer).resize(width, height).sharpen().toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-nearest-neighbour', {
defer: true,
fn: function(deferred) {
sharp(inputJpgBuffer).resize(width, height).interpolateWith(sharp.interpolator.nearest).toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-bicubic', {
defer: true,
fn: function(deferred) {
sharp(inputJpgBuffer).resize(width, height).interpolateWith(sharp.interpolator.bicubic).toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-nohalo', {
defer: true,
fn: function(deferred) {
sharp(inputJpgBuffer).resize(width, height).interpolateWith(sharp.interpolator.nohalo).toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-locallyBoundedBicubic', {
defer: true,
fn: function(deferred) {
sharp(inputJpgBuffer).resize(width, height).interpolateWith(sharp.interpolator.locallyBoundedBicubic).toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-vertexSplitQuadraticBasisSpline', {
defer: true,
fn: function(deferred) {
sharp(inputJpgBuffer).resize(width, height).interpolateWith(sharp.interpolator.vertexSplitQuadraticBasisSpline).toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-gamma', {
defer: true,
fn: function(deferred) {
sharp(inputJpgBuffer).resize(width, height).gamma().toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-greyscale', {
defer: true,
fn: function(deferred) {
sharp(inputJpgBuffer).resize(width, height).greyscale().toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-greyscale-gamma', {
defer: true,
fn: function(deferred) {
sharp(inputJpgBuffer).resize(width, height).gamma().greyscale().toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-progressive', {
defer: true,
fn: function(deferred) {
sharp(inputJpgBuffer).resize(width, height).progressive().toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-rotate', {
defer: true,
fn: function(deferred) {
sharp(inputJpgBuffer).rotate(90).resize(width, height).toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-sequentialRead', {
defer: true,
fn: function(deferred) {
sharp(inputJpgBuffer).resize(width, height).sequentialRead().toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).on('cycle', function(event) {
console.log('jpeg ' + String(event.target));
}).on('complete', function() {
callback(null, this.filter('fastest').pluck('name'));
}).run();
},
png: function(callback) {
var inputPngBuffer = fs.readFileSync(fixtures.inputPng);
(new Benchmark.Suite('png')).add('imagemagick-file-file', {
defer: true,
fn: function(deferred) {
imagemagick.resize({
srcPath: fixtures.inputPng,
dstPath: fixtures.outputPng,
width: width,
height: height
}, function(err) {
if (err) {
throw err;
} else {
deferred.resolve();
}
});
}
}).add('imagemagick-native-buffer-buffer', {
defer: true,
fn: function(deferred) {
imagemagickNative.convert({
srcData: inputPngBuffer,
width: width,
height: height,
format: 'PNG'
});
deferred.resolve();
}
}).add('gm-file-file', {
defer: true,
fn: function(deferred) {
gm(fixtures.inputPng).resize(width, height).write(fixtures.outputPng, function (err) {
if (err) {
throw err;
} else {
deferred.resolve();
}
});
}
}).add('gm-file-buffer', {
defer: true,
fn: function(deferred) {
gm(fixtures.inputPng).resize(width, height).quality(80).toBuffer(function (err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-buffer-file', {
defer: true,
fn: function(deferred) {
sharp(inputPngBuffer).resize(width, height).toFile(fixtures.outputPng, function(err) {
if (err) {
throw err;
} else {
deferred.resolve();
}
});
}
}).add('sharp-buffer-buffer', {
defer: true,
fn: function(deferred) {
sharp(inputPngBuffer).resize(width, height).toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-file-file', {
defer: true,
fn: function(deferred) {
sharp(fixtures.inputPng).resize(width, height).toFile(fixtures.outputPng, function(err) {
if (err) {
throw err;
} else {
deferred.resolve();
}
});
}
}).add('sharp-file-buffer', {
defer: true,
fn: function(deferred) {
sharp(fixtures.inputPng).resize(width, height).toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-progressive', {
defer: true,
fn: function(deferred) {
sharp(inputPngBuffer).resize(width, height).progressive().toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).on('cycle', function(event) {
console.log(' png ' + String(event.target));
}).on('complete', function() {
callback(null, this.filter('fastest').pluck('name'));
}).run();
},
webp: function(callback) {
var inputWebPBuffer = fs.readFileSync(fixtures.inputWebP);
(new Benchmark.Suite('webp')).add('sharp-buffer-file', {
defer: true,
fn: function(deferred) {
sharp(inputWebPBuffer).resize(width, height).toFile(fixtures.outputWebP, function(err) {
if (err) {
throw err;
} else {
deferred.resolve();
}
});
}
}).add('sharp-buffer-buffer', {
defer: true,
fn: function(deferred) {
sharp(inputWebPBuffer).resize(width, height).toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-file-file', {
defer: true,
fn: function(deferred) {
sharp(fixtures.inputWebP).resize(width, height).toFile(fixtures.outputWebP, function(err) {
if (err) {
throw err;
} else {
deferred.resolve();
}
});
}
}).add('sharp-file-buffer', {
defer: true,
fn: function(deferred) {
sharp(fixtures.inputWebp).resize(width, height).toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).on('cycle', function(event) {
console.log('webp ' + String(event.target));
}).on('complete', function() {
callback(null, this.filter('fastest').pluck('name'));
}).run();
}
}, function(err, results) {
assert(!err, err);
Object.keys(results).forEach(function(format) {
if (results[format].toString().substr(0, 5) !== 'sharp') {
console.log('sharp was slower than ' + results[format] + ' for ' + format);
}
});
console.dir(sharp.cache());
});

65
test/bench/random.js Executable file
View File

@@ -0,0 +1,65 @@
'use strict';
var imagemagick = require('imagemagick');
var gm = require('gm');
var assert = require('assert');
var Benchmark = require('benchmark');
var sharp = require('../../index');
var fixtures = require('../fixtures');
var min = 320;
var max = 960;
var randomDimension = function() {
return Math.random() * (max - min) + min;
};
new Benchmark.Suite('random').add('imagemagick', {
defer: true,
fn: function(deferred) {
imagemagick.resize({
srcPath: fixtures.inputJpg,
dstPath: fixtures.outputJpg,
quality: 0.8,
width: randomDimension(),
height: randomDimension()
}, function(err) {
if (err) {
throw err;
} else {
deferred.resolve();
}
});
}
}).add('gm', {
defer: true,
fn: function(deferred) {
gm(fixtures.inputJpg).resize(randomDimension(), randomDimension()).quality(80).toBuffer(function (err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp', {
defer: true,
fn: function(deferred) {
sharp(fixtures.inputJpg).resize(randomDimension(), randomDimension()).toBuffer(function(err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).on('cycle', function(event) {
console.log(String(event.target));
}).on('complete', function() {
var winner = this.filter('fastest').pluck('name');
assert.strictEqual('sharp', String(winner), 'sharp was slower than ' + winner);
console.dir(sharp.cache());
}).run();