summaryrefslogtreecommitdiff
path: root/mocha_test
diff options
context:
space:
mode:
authorAlexander Early <alexander.early@gmail.com>2018-04-14 20:10:29 -0700
committerAlexander Early <alexander.early@gmail.com>2018-04-14 20:10:29 -0700
commit45e2938cfa536fe27898c60a4e0fe37080c880bb (patch)
treec0cb0776b596908d1a79f77c1a30a138dcba6a00 /mocha_test
parent2030f5f1bd01a141ac4c85d3deab927f49e255fc (diff)
parent3235c8f5f67ff38b85ce6f9664053d0b1897ff3b (diff)
downloadasync-45e2938cfa536fe27898c60a4e0fe37080c880bb.tar.gz
Merge branch 'master' into DELETE_THIS_BRANCHDELETE_THIS_BRANCH
Diffstat (limited to 'mocha_test')
-rw-r--r--mocha_test/applyEach.js6
-rw-r--r--mocha_test/asyncFunctions.js13
-rw-r--r--mocha_test/asyncify.js38
-rw-r--r--mocha_test/cargo.js55
-rw-r--r--mocha_test/concat.js442
-rw-r--r--mocha_test/eachOf.js60
-rw-r--r--mocha_test/es2017/asyncFunctions.js20
-rw-r--r--mocha_test/groupBy.js2
-rw-r--r--mocha_test/linked_list.js83
-rw-r--r--mocha_test/queue.js237
-rw-r--r--mocha_test/retry.js23
-rw-r--r--mocha_test/slice.js32
-rw-r--r--mocha_test/timeout.js36
-rw-r--r--mocha_test/tryEach.js86
-rw-r--r--mocha_test/waterfall.js32
15 files changed, 1003 insertions, 162 deletions
diff --git a/mocha_test/applyEach.js b/mocha_test/applyEach.js
index 6138d3f..ca5ada3 100644
--- a/mocha_test/applyEach.js
+++ b/mocha_test/applyEach.js
@@ -11,21 +11,21 @@ describe('applyEach', function () {
setTimeout(function () {
call_order.push('one');
cb(null, 1);
- }, 10);
+ }, 12);
};
var two = function (val, cb) {
expect(val).to.equal(5);
setTimeout(function () {
call_order.push('two');
cb(null, 2);
- }, 5);
+ }, 2);
};
var three = function (val, cb) {
expect(val).to.equal(5);
setTimeout(function () {
call_order.push('three');
cb(null, 3);
- }, 15);
+ }, 18);
};
async.applyEach([one, two, three], 5, function (err, results) {
assert(err === null, err + " passed instead of 'null'");
diff --git a/mocha_test/asyncFunctions.js b/mocha_test/asyncFunctions.js
index b756a90..3b759e1 100644
--- a/mocha_test/asyncFunctions.js
+++ b/mocha_test/asyncFunctions.js
@@ -1,4 +1,15 @@
-var supportsAsync = require('../lib/internal/wrapAsync').supportsAsync;
+var isAsync = require('../lib/internal/wrapAsync').isAsync;
+
+function supportsAsync() {
+ var supported;
+ try {
+ /* eslint no-eval: 0 */
+ supported = isAsync(eval('(async function () {})'));
+ } catch (e) {
+ supported = false;
+ }
+ return supported;
+}
describe('async function support', function () {
this.timeout(100);
diff --git a/mocha_test/asyncify.js b/mocha_test/asyncify.js
index a98826c..112b8ad 100644
--- a/mocha_test/asyncify.js
+++ b/mocha_test/asyncify.js
@@ -92,7 +92,9 @@ describe('asyncify', function(){
});
});
- it('callback error', function(done) {
+ it('callback error @nodeonly', function(done) {
+ expectUncaughtException();
+
var promisified = function(argument) {
return new Promise(function (resolve) {
resolve(argument + " resolved");
@@ -105,11 +107,30 @@ describe('asyncify', function(){
throw new Error("error in callback");
}
});
+
setTimeout(function () {
expect(call_count).to.equal(1);
done();
}, 15);
});
+
+ it('dont catch errors in the callback @nodeonly', function(done) {
+ expectUncaughtException(checkErr);
+ var callbackError = new Error('thrown from callback');
+
+ function checkErr(err) {
+ expect(err).to.equal(callbackError);
+ done();
+ }
+
+ function callback() {
+ throw callbackError;
+ }
+
+ async.asyncify(function () {
+ return Promise.reject(new Error('rejection'));
+ })(callback);
+ });
}
describe('native-promise-only', function() {
@@ -134,5 +155,20 @@ describe('asyncify', function(){
var Promise = require('rsvp').Promise;
promisifiedTests.call(this, Promise);
});
+
+ function expectUncaughtException(onError) {
+ // do a weird dance to catch the async thrown error before mocha
+ var listeners = process.listeners('uncaughtException');
+ process.removeAllListeners('uncaughtException');
+ process.once('uncaughtException', function onErr(err) {
+ listeners.forEach(function(listener) {
+ process.on('uncaughtException', listener);
+ });
+ // can't throw errors in a uncaughtException handler, defer
+ if (onError) {
+ setTimeout(onError, 0, err);
+ }
+ });
+ }
});
});
diff --git a/mocha_test/cargo.js b/mocha_test/cargo.js
index 235b9a2..55e6e96 100644
--- a/mocha_test/cargo.js
+++ b/mocha_test/cargo.js
@@ -236,7 +236,7 @@ describe('cargo', function () {
it('expose payload', function (done) {
var called_once = false;
- var cargo= async.cargo(function(tasks, cb) {
+ var cargo = async.cargo(function(tasks, cb) {
if (!called_once) {
expect(cargo.payload).to.equal(1);
assert(tasks.length === 1, 'should start with payload = 1');
@@ -261,4 +261,57 @@ describe('cargo', function () {
}, 15);
});
+ it('workersList', function(done) {
+ var called_once = false;
+
+ function getWorkersListData(cargo) {
+ return cargo.workersList().map(function(v) {
+ return v.data;
+ });
+ }
+
+ var cargo = async.cargo(function(tasks, cb) {
+ if (!called_once) {
+ expect(tasks).to.eql(['foo', 'bar']);
+ } else {
+ expect(tasks).to.eql(['baz']);
+ }
+ expect(getWorkersListData(cargo)).to.eql(tasks);
+ async.setImmediate(function() {
+ // ensure nothing has changed
+ expect(getWorkersListData(cargo)).to.eql(tasks);
+ called_once = true;
+ cb();
+ });
+ }, 2);
+
+ cargo.drain = function() {
+ expect(cargo.workersList()).to.eql([]);
+ expect(cargo.running()).to.equal(0);
+ done();
+ };
+
+ cargo.push('foo');
+ cargo.push('bar');
+ cargo.push('baz');
+ });
+
+ it('running', function(done) {
+ var cargo = async.cargo(function(tasks, cb) {
+ expect(cargo.running()).to.equal(1);
+ async.setImmediate(function() {
+ expect(cargo.running()).to.equal(1);
+ cb();
+ });
+ }, 2);
+
+ cargo.drain = function() {
+ expect(cargo.running()).to.equal(0);
+ done();
+ };
+
+ cargo.push('foo');
+ cargo.push('bar');
+ cargo.push('baz');
+ })
});
diff --git a/mocha_test/concat.js b/mocha_test/concat.js
index 389b2de..f6b73b3 100644
--- a/mocha_test/concat.js
+++ b/mocha_test/concat.js
@@ -3,55 +3,415 @@ var expect = require('chai').expect;
var assert = require('assert');
describe('concat', function() {
- it('concat', function(done) {
- var call_order = [];
- var iteratee = function (x, cb) {
- setTimeout(function(){
- call_order.push(x);
- var r = [];
- while (x > 0) {
- r.push(x);
- x--;
+ this.timeout(250);
+
+ function concatIteratee(callOrder, val, next) {
+ setTimeout(function() {
+ callOrder.push(val);
+ next(null, [val, val+1]);
+ }, val * 25);
+ }
+
+ context('concat', function() {
+ it('basics', function(done) {
+ var callOrder = [];
+ async.concat([1, 3, 2], concatIteratee.bind(this, callOrder), function(err, result) {
+ expect(err).to.eql(null);
+ expect(callOrder).to.eql([1, 2, 3]);
+ expect(result).to.eql([1, 2, 3, 4, 2, 3]);
+ done();
+ });
+ });
+
+ it('error', function(done) {
+ async.concat([1, 3, 2], function(val, next) {
+ if (val === 3) {
+ return next(new Error('fail'));
}
- cb(null, r);
- }, x*25);
- };
- async.concat([1,3,2], iteratee, function(err, results){
- expect(results).to.eql([1,2,1,3,2,1]);
- expect(call_order).to.eql([1,2,3]);
- assert(err === null, err + " passed instead of 'null'");
- done();
+ next(null, [val, val+1]);
+ }, function(err, result) {
+ expect(err).to.not.eql(null);
+ expect(result).to.eql([1, 2]);
+ done();
+ });
+ });
+
+ it('original untouched', function(done) {
+ var arr = ['foo', 'bar', 'baz'];
+ async.concat(arr, function(val, next) {
+ next(null, [val, val]);
+ }, function(err, result) {
+ expect(arr).to.eql(['foo', 'bar', 'baz']);
+ expect(result).to.eql(['foo', 'foo', 'bar', 'bar', 'baz', 'baz']);
+ done();
+ });
+ });
+
+ it('empty results', function(done) {
+ var arr = ['foo', 'bar', 'baz'];
+ async.concat(arr, function(val, next) {
+ next(null);
+ }, function(err, result) {
+ expect(err).to.eql(null);
+ expect(result).to.be.an('array').that.is.empty;
+ done();
+ });
+ });
+
+ it('empty arrays', function(done) {
+ var arr = ['foo', 'bar', 'baz'];
+ async.concat(arr, function(val, next) {
+ next(null, []);
+ }, function(err, result) {
+ expect(err).to.eql(null);
+ expect(result).to.be.an('array').that.is.empty;
+ done();
+ });
+ });
+
+ it('handles empty object', function(done) {
+ async.concat({}, function(val, next) {
+ assert(false, 'iteratee should not be called');
+ next();
+ }, function(err, result) {
+ expect(err).to.eql(null);
+ expect(result).to.be.an('array').that.is.empty;
+ done();
+ });
+ });
+
+ it('variadic', function(done) {
+ var arr = ['foo', 'bar', 'baz'];
+ async.concat(arr, function(val, next) {
+ next(null, val, val);
+ }, function(err, result) {
+ expect(err).to.eql(null);
+ expect(result).to.eql(['foo', 'foo', 'bar', 'bar', 'baz', 'baz']);
+ done();
+ });
+ });
+
+ it('flattens arrays', function(done) {
+ var arr = ['foo', 'bar'];
+ async.concat(arr, function(val, next) {
+ next(null, [val, [val]]);
+ }, function(err, result) {
+ expect(err).to.eql(null);
+ expect(result).to.eql(['foo', ['foo'], 'bar', ['bar']]);
+ done();
+ });
+ });
+
+ it('handles fasly values', function(done) {
+ var falsy = [null, undefined, 0, ''];
+ async.concat(falsy, function(val, next) {
+ next(null, val);
+ }, function(err, result) {
+ expect(err).to.eql(null);
+ expect(result).to.eql(falsy);
+ done();
+ });
+ });
+
+ it('handles objects', function(done) {
+ var obj = {a: 'foo', b: 'bar', c: 'baz'};
+ async.concat(obj, function(val, next) {
+ next(null, val);
+ }, function(err, result) {
+ expect(err).to.eql(null);
+ expect(result).to.eql(['foo', 'bar', 'baz']);
+ done();
+ });
+ });
+
+ it('main callback optional', function(done) {
+ var arr = [1, 2, 3];
+ var runs = [];
+ async.concat(arr, function(val, next) {
+ runs.push(val);
+ var _done = (runs.length === arr.length);
+ async.setImmediate(function() {
+ next(null);
+ if (_done) {
+ expect(runs).to.eql(arr);
+ done();
+ }
+ });
+ });
+ });
+
+ it('iteratee callback is only called once', function(done) {
+ async.concat([1, 2], function(val, next) {
+ try {
+ next(val);
+ } catch (exception) {
+ expect(function() {
+ next(exception);
+ }).to.throw(/already called/);
+ done();
+ }
+ }, function() {
+ throw new Error();
+ });
+ });
+
+ it('preserves order', function(done) {
+ var arr = [30, 15];
+ async.concat(arr, function(x, cb) {
+ setTimeout(function() {
+ cb(null, x);
+ }, x);
+ }, function(err, result) {
+ expect(err).to.eql(null);
+ expect(result).to.eql(arr);
+ done();
+ });
+ });
+
+ it('handles Map', function(done) {
+ if (typeof Map !== 'function') {
+ return done();
+ }
+
+ var map = new Map([
+ ['a', 'b'],
+ ['b', 'c'],
+ ['c', 'd']
+ ]);
+
+ async.concat(map, function(val, next) {
+ next(null, val);
+ }, function(err, result) {
+ expect(err).to.eql(null);
+ expect(result).to.eql(['a', 'b', 'b', 'c', 'c', 'd']);
+ done();
+ });
+ });
+
+ it('handles sparse results', function(done) {
+ var arr = [1, 2, 3, 4];
+ async.concat(arr, function(val, next) {
+ if (val === 1 || val === 3) {
+ return next(null, val+1);
+ } else if (val === 2) {
+ async.setImmediate(function() {
+ return next(null, val+1);
+ });
+ } else {
+ return next('error');
+ }
+ }, function(err, result) {
+ expect(err).to.not.eql(null);
+ expect(result).to.eql([2, 4]);
+ async.setImmediate(done);
+ });
});
});
- it('concat error', function(done) {
- var iteratee = function (x, cb) {
- cb(new Error('test error'));
- };
- async.concat([1,2,3], iteratee, function(err){
- assert(err);
- done();
+ context('concatLimit', function() {
+ var arr = ['foo', 'bar', 'baz'];
+ it('basics', function(done) {
+ var running = 0;
+ var concurrency = {'foo': 2, 'bar': 2, 'baz': 1};
+ async.concatLimit(arr, 2, function(val, next) {
+ running++;
+ async.setImmediate(function() {
+ expect(running).to.equal(concurrency[val]);
+ running--;
+ next(null, val, val);
+ })
+ }, function(err, result) {
+ expect(running).to.equal(0);
+ expect(err).to.eql(null);
+ expect(result).to.eql(['foo', 'foo', 'bar', 'bar', 'baz', 'baz']);
+ done();
+ });
+ });
+
+ it('error', function(done) {
+ async.concatLimit(arr, 1, function(val, next) {
+ if (val === 'bar') {
+ return next(new Error('fail'));
+ }
+ next(null, val);
+ }, function(err, result) {
+ expect(err).to.not.eql(null);
+ expect(result).to.eql(['foo']);
+ done();
+ });
+ });
+
+ it('handles objects', function(done) {
+ async.concatLimit({'foo': 1, 'bar': 2, 'baz': 3}, 2, function(val, next) {
+ next(null, val+1);
+ }, function(err, result) {
+ expect(err).to.eql(null);
+ expect(result).to.eql([2, 3, 4]);
+ done();
+ });
+ });
+
+ it('handles empty object', function(done) {
+ async.concatLimit({}, 2, function(val, next) {
+ assert(false, 'iteratee should not be called');
+ next();
+ }, function(err, result) {
+ expect(err).to.eql(null);
+ expect(result).to.be.an('array').that.is.empty;
+ done();
+ });
+ });
+
+ it('handles undefined', function(done) {
+ async.concatLimit(undefined, 2, function(val, next) {
+ assert(false, 'iteratee should not be called');
+ next();
+ }, function(err, result) {
+ expect(err).to.eql(null);
+ expect(result).to.be.an('array').that.is.empty;
+ done();
+ });
+ });
+
+ it('limit exceeds size', function(done) {
+ var callOrder = [];
+ async.concatLimit([3, 2, 2, 1], 10, concatIteratee.bind(this, callOrder), function(err, result) {
+ expect(err).to.eql(null);
+ expect(result).to.eql([3, 4, 2, 3, 2, 3, 1, 2]);
+ expect(callOrder).to.eql([1, 2, 2, 3]);
+ done();
+ });
+ });
+
+ it('limit equal size', function(done) {
+ var callOrder = [];
+ async.concatLimit([3, 2, 2, 1], 4, concatIteratee.bind(this, callOrder), function(err, result) {
+ expect(err).to.eql(null);
+ expect(result).to.eql([3, 4, 2, 3, 2, 3, 1, 2]);
+ expect(callOrder).to.eql([1, 2, 2, 3]);
+ done();
+ });
+ });
+
+ it('zero limit', function(done) {
+ async.concatLimit([3, 2, 2, 1], 0, function(val, next) {
+ assert(false, 'iteratee should not be called');
+ next();
+ }, function(err, result) {
+ expect(err).to.eql(null);
+ expect(result).to.be.an('array').that.is.empty;
+ done();
+ });
+ });
+
+ it('does not continue replenishing after error', function(done) {
+ var started = 0;
+ var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+ var limit = 3;
+ var step = 0;
+ var maxSteps = arr.length;
+
+ async.concatLimit(arr, limit, function(val, next) {
+ started++;
+ if (started === 3) {
+ return next(new Error('fail'));
+ }
+
+ async.setImmediate(function() {
+ next();
+ });
+ }, function(err, result) {
+ expect(err).to.not.eql(null);
+ expect(result).to.be.an('array').that.is.empty;
+ });
+
+ // wait `maxSteps` event loop cycles before calling done to ensure
+ // the iteratee is not called on more items in arr.
+ function waitCycle() {
+ step++;
+ if (step >= maxSteps) {
+ expect(started).to.equal(3);
+ done();
+ return;
+ } else {
+ async.setImmediate(waitCycle);
+ }
+ }
+
+ async.setImmediate(waitCycle);
});
});
- it('concatSeries', function(done) {
- var call_order = [];
- var iteratee = function (x, cb) {
- setTimeout(function(){
- call_order.push(x);
- var r = [];
- while (x > 0) {
- r.push(x);
- x--;
+ context('concatSeries', function() {
+ it('basics', function(done) {
+ var callOrder = [];
+ var running = 0;
+ var iteratee = function (x, cb) {
+ running++;
+ setTimeout(function() {
+ expect(running).to.equal(1);
+ running--;
+ callOrder.push(x);
+ var r = [];
+ while (x > 0) {
+ r.push(x);
+ x--;
+ }
+ cb(null, r);
+ }, x*25);
+ };
+ async.concatSeries([1,3,2], iteratee, function(err, results) {
+ expect(results).to.eql([1,3,2,1,2,1]);
+ expect(running).to.equal(0);
+ expect(callOrder).to.eql([1,3,2]);
+ assert(err === null, err + " passed instead of 'null'");
+ done();
+ });
+ });
+
+ it('error', function(done) {
+ async.concatSeries(['foo', 'bar', 'baz'], function(val, next) {
+ if (val === 'bar') {
+ return next(new Error('fail'));
}
- cb(null, r);
- }, x*25);
- };
- async.concatSeries([1,3,2], iteratee, function(err, results){
- expect(results).to.eql([1,3,2,1,2,1]);
- expect(call_order).to.eql([1,3,2]);
- assert(err === null, err + " passed instead of 'null'");
- done();
+ next(null, [val, val]);
+ }, function(err, result) {
+ expect(err).to.not.eql(null);
+ expect(result).to.eql(['foo', 'foo']);
+ done();
+ });
+ });
+
+ it('handles objects', function(done) {
+ async.concatSeries({'foo': 1, 'bar': 2, 'baz': 3}, function(val, next) {
+ return next(null, [val, val+1]);
+ }, function(err, result) {
+ expect(err).to.eql(null);
+ expect(result).to.eql([1, 2, 2, 3, 3, 4]);
+ done();
+ });
+ });
+
+ it('handles empty object', function(done) {
+ async.concatSeries({}, function(val, next) {
+ assert(false, 'iteratee should not be called');
+ next();
+ }, function(err, result) {
+ expect(err).to.eql(null);
+ expect(result).to.be.an('array').that.is.empty;
+ done();
+ });
+ });
+
+ it('handles undefined', function(done) {
+ async.concatSeries(undefined, function(val, next) {
+ assert(false, 'iteratee should not be called');
+ next();
+ }, function(err, result) {
+ expect(err).to.eql(null);
+ expect(result).to.be.an('array').that.is.empty;
+ done();
+ });
});
});
});
diff --git a/mocha_test/eachOf.js b/mocha_test/eachOf.js
index 925f995..dd73c22 100644
--- a/mocha_test/eachOf.js
+++ b/mocha_test/eachOf.js
@@ -43,6 +43,30 @@ describe("eachOf", function() {
});
});
+ it('forEachOf no call stack size exceed error', function(done) {
+ var obj = {};
+ var len = 3000;
+ var args = new Array(len * 2);
+ var expected = new Array(len * 2);
+
+ for (var i = 0; i < len; i++) {
+ obj["a" + i] = i;
+ expected[2 * i] = "a" + i;
+ expected[2 * i + 1] = i;
+ }
+
+ async.forEachOf(obj, function(value, key, callback) {
+ var index = parseInt(key.slice(1), 10);
+ args[2 * index] = key;
+ args[2 * index + 1] = value;
+ callback();
+ }, function(err) {
+ assert(err === null, err + " passed instead of 'null'");
+ expect(args).to.eql(expected);
+ done();
+ });
+ });
+
it('forEachOf - instant resolver', function(done) {
var args = [];
async.forEachOf({ a: 1, b: 2 }, function(x, k, cb) {
@@ -139,6 +163,30 @@ describe("eachOf", function() {
});
});
+ it('forEachOfSeries no call stack size exceed error', function(done) {
+ var obj = {};
+ var len = 3000;
+ var args = new Array(len * 2);
+ var expected = new Array(len * 2);
+
+ for (var i = 0; i < len; i++) {
+ obj["a" + i] = i;
+ expected[2 * i] = "a" + i;
+ expected[2 * i + 1] = i;
+ }
+
+ async.forEachOfSeries(obj, function(value, key, callback) {
+ var index = parseInt(key.slice(1), 10);
+ args[2 * index] = key;
+ args[2 * index + 1] = value;
+ callback();
+ }, function(err) {
+ assert(err === null, err + " passed instead of 'null'");
+ expect(args).to.eql(expected);
+ done();
+ });
+ });
+
it('forEachOfSeries empty object', function(done) {
async.forEachOfSeries({}, function(x, callback){
assert(false, 'iteratee should not be called');
@@ -274,6 +322,18 @@ describe("eachOf", function() {
setTimeout(done, 25);
});
+ it('forEachOfLimit no call stack size exceed error', function(done) {
+ var count = 0;
+ async.forEachOfLimit(_.range(1024 * 1024), Infinity, function(x, i, callback){
+ count++;
+ callback();
+ }, function(err){
+ if (err) throw err;
+ expect(count).to.equal(1024 * 1024);
+ done();
+ });
+ });
+
it('forEachOfLimit error', function(done) {
var obj = { a: 1, b: 2, c: 3, d: 4, e: 5 };
var call_order = [];
diff --git a/mocha_test/es2017/asyncFunctions.js b/mocha_test/es2017/asyncFunctions.js
index 8f77bdc..5616307 100644
--- a/mocha_test/es2017/asyncFunctions.js
+++ b/mocha_test/es2017/asyncFunctions.js
@@ -219,6 +219,14 @@ module.exports = function () {
});
});
+ it('should handle async functions in concatLimit', (done) => {
+ async.concatLimit(input, 2, asyncIdentity, (err, result) => {
+ expect(err).to.eql(null);
+ expect(result).to.eql(input);
+ done(err);
+ });
+ });
+
it('should handle async functions in concatSeries', (done) => {
async.concatSeries(input, asyncIdentity, (err, result) => {
expect(result).to.eql(input);
@@ -622,6 +630,18 @@ module.exports = function () {
})
});
+ it('should handle async functons in tryEach', (done) => {
+ async.tryEach([
+ async () => { throw new Error('fail1'); },
+ async () => { throw new Error('fail2'); },
+ async () => 5,
+ async () => { throw new Error('shoult not get here'); }
+ ], (err, result) => {
+ expect(result).to.eql(5);
+ done();
+ })
+ });
+
/**
* Utils
*/
diff --git a/mocha_test/groupBy.js b/mocha_test/groupBy.js
index afb612b..d20f385 100644
--- a/mocha_test/groupBy.js
+++ b/mocha_test/groupBy.js
@@ -330,7 +330,7 @@ describe('groupBy', function() {
});
it('handles empty object', function(done) {
- async.groupByLimit({}, 2, function(val, next) {
+ async.groupBySeries({}, function(val, next) {
assert(false, 'iteratee should not be called');
next();
}, function(err, result) {
diff --git a/mocha_test/linked_list.js b/mocha_test/linked_list.js
new file mode 100644
index 0000000..ab4b223
--- /dev/null
+++ b/mocha_test/linked_list.js
@@ -0,0 +1,83 @@
+var DLL = require('../lib/internal/DoublyLinkedList').default;
+var expect = require('chai').expect;
+
+describe('DoublyLinkedList', function () {
+ it('toArray', function() {
+ var list = new DLL();
+ expect(list.toArray()).to.eql([]);
+
+ for (var i = 0; i < 5; i++) {
+ list.push({data: i});
+ }
+ expect(list.toArray()).to.eql([0, 1, 2, 3, 4]);
+ });
+
+ it('remove', function() {
+ var list = new DLL();
+
+ for (var i = 0; i < 5; i++) {
+ list.push({data: i});
+ }
+
+ list.remove(function (node) {
+ return node.data === 3;
+ })
+
+ expect(list.toArray()).to.eql([0, 1, 2, 4]);
+ });
+
+ it('remove (head)', function() {
+ var list = new DLL();
+
+ for (var i = 0; i < 5; i++) {
+ list.push({data: i});
+ }
+
+ list.remove(function (node) {
+ return node.data === 0;
+ })
+
+ expect(list.toArray()).to.eql([1, 2, 3, 4]);
+ });
+
+ it('remove (tail)', function() {
+ var list = new DLL();
+
+ for (var i = 0; i < 5; i++) {
+ list.push({data: i});
+ }
+
+ list.remove(function (node) {
+ return node.data === 4;
+ })
+
+ expect(list.toArray()).to.eql([0, 1, 2, 3]);
+ });
+
+ it('remove (all)', function() {
+ var list = new DLL();
+
+ for (var i = 0; i < 5; i++) {
+ list.push({data: i});
+ }
+
+ list.remove(function (node) {
+ return node.data < 5;
+ })
+
+ expect(list.toArray()).to.eql([]);
+ });
+
+ it('empty', function() {
+ var list = new DLL();
+
+ for (var i = 0; i < 5; i++) {
+ list.push({data: i});
+ }
+
+ var empty = list.empty();
+
+ expect(list).to.equal(empty);
+ expect(list.toArray()).to.eql([]);
+ });
+});
diff --git a/mocha_test/queue.js b/mocha_test/queue.js
index cc72c52..4539c14 100644
--- a/mocha_test/queue.js
+++ b/mocha_test/queue.js
@@ -10,7 +10,7 @@ describe('queue', function(){
it('basics', function(done) {
var call_order = [];
- var delays = [40,20,60,20];
+ var delays = [40,10,60,10];
// worker1: --1-4
@@ -66,7 +66,7 @@ describe('queue', function(){
it('default concurrency', function(done) {
var call_order = [],
- delays = [40,20,60,20];
+ delays = [40,10,60,10];
// order of completion: 1,2,3,4
@@ -222,16 +222,21 @@ describe('queue', function(){
it('push without callback', function(done) {
this.retries(3); // test can be flakey
- var call_order = [],
- delays = [40,20,60,20];
+ var call_order = [];
+ var delays = [40,10,60,10];
+ var concurrencyList = [];
+ var running = 0;
// worker1: --1-4
// worker2: -2---3
// order of completion: 2,1,4,3
var q = async.queue(function (task, callback) {
+ running++;
+ concurrencyList.push(running);
setTimeout(function () {
call_order.push('process ' + task);
+ running--;
callback('error', 'arg');
}, delays.shift());
}, 2);
@@ -242,6 +247,8 @@ describe('queue', function(){
q.push(4);
q.drain = function () {
+ expect(running).to.eql(0);
+ expect(concurrencyList).to.eql([1, 2, 2, 2]);
expect(call_order).to.eql([
'process 2',
'process 1',
@@ -293,7 +300,7 @@ describe('queue', function(){
it('bulk task', function(done) {
var call_order = [],
- delays = [40,20,60,20];
+ delays = [40,10,60,10];
// worker1: --1-4
// worker2: -2---3
@@ -353,58 +360,58 @@ describe('queue', function(){
});
it('pause', function(done) {
- this.retries(3); // sometimes can be flakey to timing issues
-
- var call_order = [],
- task_timeout = 80,
- pause_timeout = task_timeout * 2.5,
- resume_timeout = task_timeout * 4.5,
- tasks = [ 1, 2, 3, 4, 5, 6 ],
-
- elapsed = (function () {
- var start = Date.now();
- return function () {
- return Math.round((Date.now() - start) / task_timeout) * task_timeout;
- };
- })();
+ var call_order = [];
+ var running = 0;
+ var concurrencyList = [];
+ var pauseCalls = ['process 1', 'process 2', 'process 3'];
var q = async.queue(function (task, callback) {
+ running++;
call_order.push('process ' + task);
- call_order.push('timeout ' + elapsed());
- callback();
- });
-
- function pushTask () {
- var task = tasks.shift();
- if (!task) { return; }
+ concurrencyList.push(running);
setTimeout(function () {
- q.push(task);
- pushTask();
- }, task_timeout);
- }
- pushTask();
+ running--;
+ callback();
+ }, 10)
+ }, 2);
- setTimeout(function () {
+ q.push(1);
+ q.push(2, after2);
+ q.push(3);
+
+ function after2() {
q.pause();
- expect(q.paused).to.equal(true);
- }, pause_timeout);
+ expect(concurrencyList).to.eql([1, 2, 2]);
+ expect(call_order).to.eql(pauseCalls);
- setTimeout(function () {
- q.resume();
- expect(q.paused).to.equal(false);
- }, resume_timeout);
+ setTimeout(whilePaused, 5);
+ setTimeout(afterPause, 10);
+ }
- setTimeout(function () {
+ function whilePaused() {
+ q.push(4);
+ }
+
+ function afterPause() {
+ expect(concurrencyList).to.eql([1, 2, 2]);
+ expect(call_order).to.eql(pauseCalls);
+ q.resume();
+ q.push(5);
+ q.push(6);
+ q.drain = drain;
+ }
+ function drain () {
+ expect(concurrencyList).to.eql([1, 2, 2, 1, 2, 2]);
expect(call_order).to.eql([
- 'process 1', 'timeout ' + task_timeout,
- 'process 2', 'timeout ' + task_timeout * 2,
- 'process 3', 'timeout ' + task_timeout * 5,
- 'process 4', 'timeout ' + task_timeout * 5,
- 'process 5', 'timeout ' + task_timeout * 5,
- 'process 6', 'timeout ' + task_timeout * 6
+ 'process 1',
+ 'process 2',
+ 'process 3',
+ 'process 4',
+ 'process 5',
+ 'process 6'
]);
done();
- }, (task_timeout * tasks.length) + pause_timeout + resume_timeout);
+ }
});
it('pause in worker with concurrency', function(done) {
@@ -436,57 +443,6 @@ describe('queue', function(){
};
});
- it('pause with concurrency', function(done) {
- var call_order = [],
- task_timeout = 40,
- pause_timeout = task_timeout / 2,
- resume_timeout = task_timeout * 2.75,
- tasks = [ 1, 2, 3, 4, 5, 6 ],
-
- elapsed = (function () {
- var start = Date.now();
- return function () {
- return Math.round((Date.now() - start) / task_timeout) * task_timeout;
- };
- })();
-
- var q = async.queue(function (task, callback) {
- setTimeout(function () {
- call_order.push('process ' + task);
- call_order.push('timeout ' + elapsed());
- callback();
- }, task_timeout);
- }, 2);
-
- q.push(tasks);
-
- setTimeout(function () {
- q.pause();
- expect(q.paused).to.equal(true);
- }, pause_timeout);
-
- setTimeout(function () {
- q.resume();
- expect(q.paused).to.equal(false);
- }, resume_timeout);
-
- setTimeout(function () {
- expect(q.running()).to.equal(2);
- }, resume_timeout + 10);
-
- setTimeout(function () {
- expect(call_order).to.eql([
- 'process 1', 'timeout ' + task_timeout,
- 'process 2', 'timeout ' + task_timeout,
- 'process 3', 'timeout ' + task_timeout * 4,
- 'process 4', 'timeout ' + task_timeout * 4,
- 'process 5', 'timeout ' + task_timeout * 5,
- 'process 6', 'timeout ' + task_timeout * 5
- ]);
- done();
- }, (task_timeout * tasks.length) + pause_timeout + resume_timeout);
- });
-
it('start paused', function(done) {
var q = async.queue(function (task, callback) {
setTimeout(function () {
@@ -498,11 +454,12 @@ describe('queue', function(){
q.push([1, 2, 3]);
setTimeout(function () {
+ expect(q.running()).to.equal(0);
q.resume();
}, 5);
setTimeout(function () {
- expect(q._tasks.length).to.equal(1);
+ expect(q.length()).to.equal(1);
expect(q.running()).to.equal(2);
q.resume();
}, 15);
@@ -699,7 +656,7 @@ describe('queue', function(){
});
});
- context('q.unsaturated(): ',function() {
+ context('q.unsaturated(): ', function() {
it('should have a default buffer property that equals 25% of the concurrenct rate', function(done){
var calls = [];
var q = async.queue(function(task, cb) {
@@ -761,5 +718,85 @@ describe('queue', function(){
q.push('foo4', function () {calls.push('foo4 cb');});
});
});
-});
+ context('workersList', function() {
+ it('should be the same length as running()', function(done) {
+ var q = async.queue(function(task, cb) {
+ async.setImmediate(function() {
+ expect(q.workersList().length).to.equal(q.running());
+ cb();
+ });
+ }, 2);
+
+ q.drain = function() {
+ expect(q.workersList().length).to.equal(0);
+ expect(q.running()).to.equal(0);
+ done();
+ };
+
+ q.push('foo');
+ q.push('bar');
+ q.push('baz');
+ });
+
+ it('should contain the items being processed', function(done) {
+ var itemsBeingProcessed = {
+ 'foo': ['foo'],
+ 'foo_cb': ['foo', 'bar'],
+ 'bar': ['foo', 'bar'],
+ 'bar_cb': ['bar', 'baz'],
+ 'baz': ['bar', 'baz'],
+ 'baz_cb': ['baz']
+ };
+
+ function getWorkersListData(q) {
+ return q.workersList().map(function(v) {
+ return v.data;
+ });
+ }
+
+ var q = async.queue(function(task, cb) {
+ expect(
+ getWorkersListData(q)
+ ).to.eql(itemsBeingProcessed[task]);
+ expect(q.workersList().length).to.equal(q.running());
+ async.setImmediate(function() {
+ expect(
+ getWorkersListData(q)
+ ).to.eql(itemsBeingProcessed[task+'_cb']);
+ expect(q.workersList().length).to.equal(q.running());
+ cb();
+ });
+ }, 2);
+
+ q.drain = function() {
+ expect(q.workersList()).to.eql([]);
+ expect(q.workersList().length).to.equal(q.running());
+ done();
+ };
+
+ q.push('foo');
+ q.push('bar');
+ q.push('baz');
+ });
+ })
+
+ it('remove', function(done) {
+ var result = [];
+ var q = async.queue(function(data, cb) {
+ result.push(data);
+ async.setImmediate(cb);
+ });
+
+ q.push([1, 2, 3, 4, 5]);
+
+ q.remove(function (node) {
+ return node.data === 3;
+ });
+
+ q.drain = function () {
+ expect(result).to.eql([1, 2, 4, 5]);
+ done();
+ }
+ });
+});
diff --git a/mocha_test/retry.js b/mocha_test/retry.js
index d3a5d22..8a9f4da 100644
--- a/mocha_test/retry.js
+++ b/mocha_test/retry.js
@@ -66,11 +66,10 @@ describe("retry", function () {
callCount++;
callback(error + callCount, erroredResult + callCount); // respond with indexed values
}
- var start = new Date().getTime();
+ var start = Date.now();
async.retry({ times: times, interval: interval}, fn, function(err, result){
- var now = new Date().getTime();
- var duration = now - start;
- assert(duration >= (interval * (times -1)), 'did not include interval');
+ var duration = Date.now() - start;
+ expect(duration).to.be.above(interval * (times - 1) - times);
assert.equal(callCount, 3, "did not retry the correct number of times");
assert.equal(err, error + times, "Incorrect error was returned");
assert.equal(result, erroredResult + times, "Incorrect result was returned");
@@ -88,11 +87,10 @@ describe("retry", function () {
callCount++;
callback(error + callCount, erroredResult + callCount); // respond with indexed values
}
- var start = new Date().getTime();
+ var start = Date.now();
async.retry({ times: times, interval: intervalFunc}, fn, function(err, result){
- var now = new Date().getTime();
- var duration = now - start;
- assert(duration >= 300, 'did not include custom interval');
+ var duration = Date.now() - start;
+ expect(duration).to.be.above(300 - times);
assert.equal(callCount, 3, "did not retry the correct number of times");
assert.equal(err, error + times, "Incorrect error was returned");
assert.equal(result, erroredResult + times, "Incorrect result was returned");
@@ -127,7 +125,7 @@ describe("retry", function () {
it('retry does not precompute the intervals (#1226)', function(done) {
var callTimes = [];
function intervalFunc() {
- callTimes.push(new Date().getTime());
+ callTimes.push(Date.now());
return 100;
};
function fn(callback) {
@@ -226,11 +224,10 @@ describe("retry", function () {
function errorTest(err) {
return err && err !== special;
}
- var start = new Date().getTime();
+ var start = Date.now();
async.retry({ interval: interval, errorFilter: errorTest }, fn, function(err, result){
- var now = new Date().getTime();
- var duration = now - start;
- assert(duration >= (interval * (specialCount - 1)), 'did not include interval');
+ var duration = Date.now() - start;
+ expect(duration).to.be.above(interval * (specialCount - 1) - specialCount);
assert.equal(callCount, specialCount, "did not retry the correct number of times");
assert.equal(err, special, "Incorrect error was returned");
assert.equal(result, erroredResult + specialCount, "Incorrect result was returned");
diff --git a/mocha_test/slice.js b/mocha_test/slice.js
new file mode 100644
index 0000000..7020526
--- /dev/null
+++ b/mocha_test/slice.js
@@ -0,0 +1,32 @@
+var slice = require('../lib/internal/slice').default;
+var expect = require('chai').expect;
+
+describe('slice', function() {
+ it('should slice arrays', function() {
+ var arr = ['foo', 'bar', 'baz'];
+ var result = slice(arr, 2);
+ expect(arr).to.eql(['foo', 'bar', 'baz']);
+ expect(result).to.eql(['baz']);
+ });
+
+ it('should handle ArrayLike objects', function() {
+ var args = {0: 'foo', 1: 'bar', 2: 'baz', length: 3};
+ var result = slice(args, 1);
+ expect(result).to.be.an('array');
+ expect(result).to.eql(['bar', 'baz']);
+ });
+
+ it('should handle arguments', function() {
+ var foo = function() {
+ return slice(arguments, 1);
+ };
+ var result = foo.apply(null, ['foo', 'bar', 'baz']);
+ expect(result).to.be.an('array');
+ expect(result).to.eql(['bar', 'baz']);
+ });
+
+ it('should return an empty array on an invalid start', function() {
+ var result = slice(['foo', 'bar', 'baz'], 10);
+ expect(result).to.be.an('array').that.is.empty;
+ });
+});
diff --git a/mocha_test/timeout.js b/mocha_test/timeout.js
index be41283..cd4a751 100644
--- a/mocha_test/timeout.js
+++ b/mocha_test/timeout.js
@@ -69,4 +69,40 @@ describe('timeout', function () {
done();
});
});
+
+ it('timeout with multiple calls (#1418)', function(done) {
+ var timeout = async.timeout(function asyncFn(n, callback) {
+ if (n < 1) {
+ setTimeout(function() {
+ callback(null, 'I will time out');
+ }, 75);
+ } else {
+ async.setImmediate(function() {
+ callback(null, 'I didn\'t time out');
+ })
+ }
+ }, 50);
+
+ async.series([
+ function(cb) {
+ timeout(0, function(err, result) {
+ expect(err.message).to.equal('Callback function "asyncFn" timed out.');
+ expect(err.code).to.equal('ETIMEDOUT');
+ expect(err.info).to.equal(undefined);
+ expect(result).to.equal(undefined);
+ cb();
+ });
+ },
+ function(cb) {
+ timeout(1, function(err, result) {
+ expect(err).to.equal(null);
+ expect(result).to.equal('I didn\'t time out');
+ cb();
+ });
+ }
+ ], function(err) {
+ expect(err).to.equal(null);
+ done();
+ });
+ })
});
diff --git a/mocha_test/tryEach.js b/mocha_test/tryEach.js
new file mode 100644
index 0000000..db884a5
--- /dev/null
+++ b/mocha_test/tryEach.js
@@ -0,0 +1,86 @@
+var async = require('../lib');
+var expect = require('chai').expect;
+var assert = require('assert');
+
+describe('tryEach', function () {
+ it('no callback', function () {
+ async.tryEach([]);
+ });
+ it('empty', function (done) {
+ async.tryEach([], function (err, results) {
+ expect(err).to.equal(null);
+ expect(results).to.eql(undefined);
+ done();
+ });
+ });
+ it('one task, multiple results', function (done) {
+ var RESULTS = ['something', 'something2'];
+ async.tryEach([
+ function (callback) {
+ callback(null, RESULTS[0], RESULTS[1]);
+ }
+ ], function (err, results) {
+ expect(err).to.equal(null);
+ expect(results).to.eql(RESULTS);
+ done();
+ });
+ });
+ it('one task', function (done) {
+ var RESULT = 'something';
+ async.tryEach([
+ function (callback) {
+ callback(null, RESULT);
+ }
+ ], function (err, results) {
+ expect(err).to.equal(null);
+ expect(results).to.eql(RESULT);
+ done();
+ });
+ });
+ it('two tasks, one failing', function (done) {
+ var RESULT = 'something';
+ async.tryEach([
+ function (callback) {
+ callback(new Error('Failure'), {});
+ },
+ function (callback) {
+ callback(null, RESULT);
+ }
+ ], function (err, results) {
+ expect(err).to.equal(null);
+ expect(results).to.eql(RESULT);
+ done();
+ });
+ });
+ it('two tasks, both failing', function (done) {
+ var ERROR_RESULT = new Error('Failure2');
+ async.tryEach([
+ function (callback) {
+ callback(new Error('Should not stop here'));
+ },
+ function (callback) {
+ callback(ERROR_RESULT);
+ }
+ ], function (err, results) {
+ expect(err).to.equal(ERROR_RESULT);
+ expect(results).to.eql(undefined);
+ done();
+ });
+ });
+ it('two tasks, non failing', function (done) {
+ var RESULT = 'something';
+ async.tryEach([
+ function (callback) {
+ callback(null, RESULT);
+ },
+ function () {
+ assert.fail('Should not been called');
+ },
+ ], function (err, results) {
+ expect(err).to.equal(null);
+ expect(results).to.eql(RESULT);
+ done();
+ });
+ });
+});
+
diff --git a/mocha_test/waterfall.js b/mocha_test/waterfall.js
index 0c21c80..54ca9f9 100644
--- a/mocha_test/waterfall.js
+++ b/mocha_test/waterfall.js
@@ -93,7 +93,6 @@ describe("waterfall", function () {
it('multiple callback calls', function(){
var arr = [
function(callback){
- // call the callback twice. this should call function 2 twice
callback(null, 'one', 'two');
callback(null, 'one', 'two');
},
@@ -106,6 +105,37 @@ describe("waterfall", function () {
}).to.throw(/already called/);
});
+ it('multiple callback calls (trickier) @nodeonly', function(done){
+
+ // do a weird dance to catch the async thrown error before mocha
+ var listeners = process.listeners('uncaughtException');
+ process.removeAllListeners('uncaughtException');
+ process.once('uncaughtException', function onErr(err) {
+ listeners.forEach(function(listener) {
+ process.on('uncaughtException', listener);
+ });
+ // can't throw errors in a uncaughtException handler, defer
+ setTimeout(checkErr, 0, err)
+ })
+
+ function checkErr(err) {
+ expect(err.message).to.match(/already called/);
+ done();
+ }
+
+ async.waterfall([
+ function(callback){
+ setTimeout(callback, 0, null, 'one', 'two');
+ setTimeout(callback, 10, null, 'one', 'two');
+ },
+ function(arg1, arg2, callback){
+ setTimeout(callback, 15, null, arg1, arg2, 'three');
+ }
+ ], function () {
+ throw new Error('should not get here')
+ });
+ });
+
it('call in another context @nycinvalid @nodeonly', function(done) {
var vm = require('vm');
var sandbox = {