/* * Tests the "filter", "filterSeries", and "filterLimit" functions */ var mod_util = require('util'); var mod_tap = require('tap'); var mod_vasync = require('..'); mod_tap.test('filterSeries', function (test) { var inputs = [0, 1, 2, 3, 4, 5]; var curTasks = 0; var maxTasks = 0; // filterSeries has an implicit limit of 1 concurrent operation var limit = 1; function filterFunc(input, cb) { curTasks++; if (curTasks > maxTasks) { maxTasks = curTasks; } test.ok(curTasks <= limit, mod_util.format( 'input %d: current tasks %d <= %d', input, curTasks, limit)); setTimeout(function () { curTasks--; cb(null, input < 2 || input === 4); }, 50); } mod_vasync.filterSeries(inputs, filterFunc, function filterDone(err, results) { test.ok(!err, 'error unset'); test.equal(maxTasks, limit, 'max tasks reached limit'); test.deepEqual(results, [0, 1, 4], 'results array correct'); test.end(); }); }); mod_tap.test('filterLimit', function (test) { var inputs = [0, 1, 2, 3, 4, 5]; var curTasks = 0; var maxTasks = 0; var limit = 2; function filterFunc(input, cb) { curTasks++; if (curTasks > maxTasks) { maxTasks = curTasks; } test.ok(curTasks <= limit, mod_util.format( 'input %d: current tasks %d <= %d', input, curTasks, limit)); setTimeout(function () { curTasks--; cb(null, input < 2 || input === 4); }, 50); } mod_vasync.filterLimit(inputs, limit, filterFunc, function filterDone(err, results) { test.ok(!err, 'error unset'); test.equal(maxTasks, limit, 'max tasks reached limit'); test.deepEqual(results, [0, 1, 4], 'results array correct'); test.end(); }); }); mod_tap.test('filter (maintain order)', function (test) { var inputs = [0, 1, 2, 3, 4, 5]; var limit = inputs.length; var storedValues = []; function filterFunc(input, cb) { /* * Hold every callback in an array to be called when all * filterFunc's have run. This way, we can ensure that all * tasks have started without waiting for any others to finish. */ storedValues.push({ input: input, cb: cb }); test.ok(storedValues.length <= limit, mod_util.format( 'input %d: current tasks %d <= %d', input, storedValues.length, limit)); /* * When this constraint is true, all filterFunc's have run for * each input. We now call all callbacks in a pre-determined * order (out of order of the original) to ensure the final * array is in the correct order. */ if (storedValues.length === inputs.length) { [5, 2, 0, 1, 4, 3].forEach(function (i) { var o = storedValues[i]; o.cb(null, o.input < 2 || o.input === 4); }); } } mod_vasync.filter(inputs, filterFunc, function filterDone(err, results) { test.ok(!err, 'error unset'); test.equal(storedValues.length, inputs.length, 'max tasks reached limit'); test.deepEqual(results, [0, 1, 4], 'results array correct'); test.end(); }); }); mod_tap.test('filterSeries error handling', function (test) { /* * We will error half way through the list of inputs to ensure that * first half are processed while the second half are ignored. */ var inputs = [0, 1, 2, 3, 4, 5]; function filterFunc(input, cb) { switch (input) { case 0: case 1: case 2: cb(null, true); break; case 3: cb(new Error('error on ' + input)); break; case 4: case 5: test.ok(false, 'processed too many inputs'); cb(new Error('processed too many inputs')); break; default: test.ok(false, 'unexpected input: ' + input); cb(new Error('unexpected input')); break; } } mod_vasync.filterSeries(inputs, filterFunc, function filterDone(err, results) { test.ok(err, 'error set'); test.ok(err.message === 'error on 3', 'error on input 3'); test.ok(results === undefined, 'results is unset'); test.end(); }); }); mod_tap.test('filterSeries double callback', function (test) { var inputs = [0, 1, 2, 3, 4, 5]; function filterFunc(input, cb) { switch (input) { case 0: case 1: case 2: cb(null, true); break; case 3: /* * The first call to cb() should "win" - meaning this * value will be filtered out of the final array of * results. */ cb(null, false); test.throws(function () { cb(null, true); }); break; case 4: /* * Like input 3, all subsequent calls to cb() will * throw an error and not affect the original call to * cb(). */ cb(null, true); test.throws(function () { cb(new Error('uh oh')); }); break; case 5: cb(null, true); break; default: test.ok(false, 'unexpected input: ' + input); cb(new Error('unexpected input')); break; } } mod_vasync.filterSeries(inputs, filterFunc, function filterDone(err, results) { test.ok(!err, 'error not set'); test.deepEqual(results, [0, 1, 2, 4, 5], 'results array correct'); test.end(); }); }); mod_tap.test('filter push to queue object error', function (test) { var inputs = [0, 1, 2, 3, 4, 5]; function filterFunc(input, cb) { cb(null, true); } var q = mod_vasync.filterSeries(inputs, filterFunc, function filterDone(err, results) { test.end(); }); test.equal(q.closed, true, 'queue is closed'); test.throws(function () { q.push(6); }); });