safe
Version:
Starting from version 0.4.0 safejs implements almost all functions of [Async](https://github.com/caolan/async) and can transparently replace it. For asyncjs functions library adds its error trap capabilities and also contain some optimizations and speed i
2,178 lines (1,921 loc) • 54 kB
JavaScript
"use strict";
require('es6-symbol/implement');
require('es6-set/implement');
require('es6-map/implement');
require('es6-promise/auto');
var assert = require('assert');
var safe = require('../app.js');
var isAsyncSupported = require('is-async-supported');
var randomTime = function () {
return 4 + Math.round(3 * Math.random());
};
describe("safe", function () {
describe("sure", function () {
it("should rise up exceptions", function () {
safe.sure(function (err) {
assert(err != null);
}, function () {
throw new Error();
})(null);
});
it("should protect inner function from error", function () {
safe.sure(function (err) {
assert(err != null);
}, function () {
assert("Should not be executed");
})(new Error());
});
it("should return value on success instead of function execute", function () {
safe.sure(function (err, v) {
assert(err == null);
assert.equal(v, "value");
}, "value")(null);
});
it("should not return value if error happens", function () {
safe.sure(function (err, v) {
assert(err != null);
}, "value")(new Error());
});
});
describe("trap", function () {
it("should rise up exceptions to explicetly provided callback", function () {
safe.trap(function (err) {
assert(err != null);
}, function () {
throw new Error();
})(null);
});
it("should rise up exceptions to indirectly provided callback", function () {
safe.trap(function () {
throw new Error();
})(null, function (err) {
assert(err != null);
});
});
});
describe("result", function () {
it("should rise up exceptions", function () {
safe.result(function (err) {
assert(err != null);
}, function () {
throw new Error();
})(null);
});
it("should convert return to callback", function () {
safe.result(function (err, v) {
assert(err == null);
assert.equal(v, "value");
}, function () {
return "value";
})(null);
});
});
describe("sure_result", function () {
it("should rise up exceptions", function () {
safe.sure_result(function (err) {
assert(err != null);
}, function () {
throw new Error();
})(null);
});
it("should protect inner function from error", function () {
safe.sure_result(function (err) {
assert(err != null);
}, function () {
assert("Should not be executed");
})(new Error());
});
it("should convert return to callback", function () {
safe.sure_result(function (err, v) {
assert(err == null);
assert.equal(v, "value");
}, function () {
return "value";
})(null);
});
});
describe("wrap", function () {
it("should rise up exceptions", function () {
safe.wrap(function () {
throw new Error();
}, function (err) {
assert(err != null);
})(null);
});
it("should append callback to inner function", function () {
safe.wrap(function (cb) {
cb(new Error());
}, function (err) {
assert(err != null);
})(null);
});
});
describe("run", function () {
it("should rise up exceptions", function () {
safe.run(function () {
throw new Error();
}, function (err) {
assert(err != null);
});
});
(!isAsyncSupported() ? it.skip : it)("works with async functions (ES7)", function (done) {
var asfn = new Function("return async () => true;")();
safe.run(asfn, function (err, result) {
assert(result, true);
done(err);
});
});
});
describe("spread", function () {
it("should convert array to variadic arguments", function () {
var arr = ["apple", "samsung", "nokia"];
var result = safe.spread(function (a1, a2, a3) {
assert.equal(a1, "apple");
assert.equal(a2, "samsung");
assert.equal(a3, "nokia");
return arr.join(", ");
})(arr);
assert.equal(result, arr.join(", "));
});
});
describe("sure_spread", function () {
it("should rise up exceptions", function () {
safe.sure_spread(function (err) {
assert(err != null);
}, function () {
throw new Error();
})(null);
});
it("should protect inner function from error", function () {
safe.sure_spread(function (err) {
assert(err != null);
}, function () {
assert("Should not be executed");
})(new Error());
});
it("should convert array to variadic arguments", function (done) {
safe.sure_spread(done, function (a1, a2, a3) {
assert.equal(a1, "apple");
assert.equal(a2, "samsung");
assert.equal(a3, "nokia");
safe.back(done);
})(null, ["apple", "samsung", "nokia"]);
});
});
describe("async", function () {
var obj = {
doStuff: function (a, b, cb) {
cb(null, a + b);
},
doBad: function (a, b, cb) {
throw new Error();
}
};
it("should rise up exceptions", function () {
safe.async(obj, "doBad")(function (err, v) {
assert(err != null);
});
});
it("should bind to object function and rise up callback value", function () {
safe.async(obj, "doStuff", 2, 3)(function (err, v) {
assert(err == null);
assert.equal(v, 5);
});
});
});
describe("back", function () {
it("should return value in next iteration", function (done) {
var a = 0;
safe.back(function (err) {
done((err != null && a == 1) ? null : new Error("Wrong behavior"));
}, new Error(1));
a += 1;
});
});
describe("yield", function () {
it("should execute function in next iteration", function (done) {
var a = 0;
safe.yield(function () {
done(a == 1 ? null : new Error("Wrong behavior"));
});
a += 1;
});
});
describe("inherits", function () {
var parent = function () {};
parent.prototype.parent_function = function () {};
var child = function () {};
safe.inherits(child, parent);
child.prototype.child_function = function () {};
it("should make magic that gives child instance methods of parents", function () {
var obj = new child();
obj.child_function();
obj.parent_function();
});
});
describe("for each", function () {
it("should execute asynchronous each (array)", function (done) {
var a = 1000;
var arr = new Array(a);
for (var i = 0; i < arr.length; i += 1)
arr[i] = i;
safe.forEach(arr, function (i, cb) {
setTimeout(function () {
a--;
cb();
}, randomTime());
}, safe.sure(done, function (result) {
assert.equal(a, 0);
done();
}));
});
it("should execute asynchronous each (es6-set)", function (done) {
var a = 0,
set = new Set();
set.add(3);
set.add(2);
set.add(1);
safe.eachOf(set, function (i, k, cb) {
setTimeout(function () {
a += i;
cb();
}, randomTime());
}, safe.sure(done, function (result) {
assert.equal(a, 6);
done();
}));
});
it("should execute asynchronous each (empty array)", function (done) {
var a = 0,
arr = [];
safe.each(arr, function (i, cb) {
setTimeout(function () {
a++;
cb();
}, randomTime());
}, safe.sure(done, function (result) {
assert.equal(a, 0);
done();
}));
});
it("should execute asynchronous each (array, limit)", function (done) {
var a = 100;
var arr = new Array(a);
for (var i = 0; i < arr.length; i += 1)
arr[i] = i;
safe.eachLimit(arr, 20, function (i, cb) {
setTimeout(function () {
a--;
cb();
}, randomTime());
}, safe.sure(done, function (result) {
assert.equal(a, 0);
done();
}));
});
it("should execute asynchronous each (object)", function (done) {
var a = 1000;
var obj = {};
for (var i = 0; i < a; i += 1)
obj[i] = i;
safe.forEachOf(obj, function (i, key, cb) {
setTimeout(function () {
a--;
cb();
}, randomTime());
}, safe.sure(done, function (result) {
assert.equal(a, 0);
done();
}));
});
it("should execute asynchronous each (empty object)", function (done) {
var a = 0,
obj = {};
safe.forEachOf(obj, function (i, key, cb) {
setTimeout(function () {
a++;
cb();
}, randomTime());
}, safe.sure(done, function (result) {
assert.equal(a, 0);
done();
}));
});
it("should execute asynchronous each (es6-map)", function (done) {
var a = 0,
arr = [['a', 1], ['b', 2], ['c', 3]],
map = new Map();
map.set('a', 1);
map.set('b', 2);
map.set('c', 3);
safe.eachOf(map, function (i, k, cb) {
assert.deepEqual(arr[k], i);
setTimeout(function () {
a += i[1];
cb();
}, randomTime());
}, safe.sure(done, function (result) {
assert.equal(a, 6);
done();
}));
});
it("should execute asynchronous each (object, limit)", function (done) {
var a = 100;
var obj = {};
for (var i = 0; i < a; i += 1)
obj[i] = i;
safe.forEachOfLimit(obj, 20, function (i, k, cb) {
setTimeout(function () {
a--;
cb();
}, randomTime());
}, safe.sure(done, function (result) {
assert.equal(a, 0);
done();
}));
});
it("should execute asynchronous each series (array)", function (done) {
var a = 0,
execute;
safe.eachSeries([1, 2, 3, 4, 5], function (i, cb) {
if (execute)
return cb(new Error("Wrong behavior"));
execute = 1;
setTimeout(function () {
execute = 0;
assert.equal(i, a);
cb();
}, randomTime());
a += 1;
}, done);
});
it("should execute asynchronous each series (object)", function (done) {
var a = 0,
execute;
safe.forEachOfSeries({a: 1, b: 2, c: 3, d: 4, e: 5}, function (i, k, cb) {
if (execute)
return cb(new Error("Wrong behavior"));
execute = 1;
setTimeout(function () {
execute = 0;
assert.equal(i, a);
cb();
}, randomTime());
a += 1;
}, done);
});
it("Check error in each series", function (done) {
var a = 0;
safe.forEachOfSeries([1, 2, 3, 4, 5], function (i, key, cb) {
++a;
setTimeout(function () {
cb(new Error("Exit"));
}, randomTime());
}, function (err) {
assert.equal(a, 1);
assert.equal(err.message, "Exit");
done();
});
});
});
describe("control flow", function () {
it("should execute step by step asynchronous functions in waterfall", function (done) {
var a = 0;
safe.waterfall([
function (cb) {
setTimeout(function () {
cb(null, "test");
}, randomTime());
a += 1;
},
function (test, cb) {
assert.equal(test, 'test');
return new Promise(function (resolve, reject) {
setTimeout(function () {
assert.equal(a, 2);
resolve(a);
}, randomTime());
a += 1;
});
},
function (a, cb) {
setTimeout(function () {
assert.equal(a, 3);
cb(null, 'final');
}, randomTime());
a += 1;
}
], safe.sure(done, function (result) {
assert.equal(result, 'final');
done();
}));
});
it("should execute step by step asynchronous functions in waterfall (catch errors)", function (done) {
safe.waterfall([
function (cb) {
throw new Error(1);
},
function (cb) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
reject(new Error(2));
}, randomTime());
});
},
function (cb) {
setTimeout(function () {
cb(new Error(3));
}, randomTime());
}
], function (err, result) {
done(err ? null : new Error("Wrong behavior"));
});
});
it("should execute step by step asynchronous functions in series", function (done) {
var a = 0;
safe.series([
function (cb) {
setTimeout(function () {
cb(null, 'first');
}, randomTime());
a += 1;
},
function (cb) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
assert.equal(a, 2);
resolve("middle");
}, randomTime());
a += 1;
});
},
function (cb) {
setTimeout(function () {
assert.equal(a, 3);
cb(null, "last");
}, randomTime());
a += 1;
}
], safe.sure(done, function (result) {
assert.deepEqual(result, ["first", "middle", "last"]);
done();
}));
});
it("should execute step by step asynchronous functions in series (catch errors)", function (done) {
var already = 0;
safe.series([
function (cb) {
setTimeout(function () {
cb(1);
}, randomTime());
},
function (cb) {
already = 1;
return new Promise(function (resolve, reject) {
setTimeout(function () {
reject(new Error(3));
}, randomTime());
});
},
function (cb) {
already = 1;
setTimeout(function () {
cb(new Error(2));
}, randomTime());
}
], function (err, result) {
if (already)
throw new Error("Wrong behavior");
already = 1;
assert.equal(err, 1);
done();
});
});
it("should execute step by step asynchronous functions in series (catch errors, sync callback)", function (done) {
safe.series([
function (cb) {
cb(1);
},
function (cb) {
throw new Error("Wrong behavior");
}
], function (err, result) {
assert.equal(err, 1);
done();
});
});
it("should execute asynchronous functions in parallel", function (done) {
safe.parallel({
"3": function (cb) {
safe.back(cb);
},
"2": function (cb) {
setTimeout(function () {
cb(null, "last");
}, randomTime());
},
"1": function (cb) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("middle");
}, randomTime());
});
},
"0": function (cb) {
setTimeout(function () {
cb(null, 'first');
}, randomTime());
}
}, safe.sure(done, function (result) {
assert.deepEqual(result, {
'3': null,
'2': 'last',
'1': 'middle',
'0': 'first'
});
done();
}));
});
it("should execute asynchronous functions in parallel (limit)", function (done) {
safe.parallelLimit({
"4": function (cb) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(5);
}, randomTime());
});
},
"3": function (cb) {
setTimeout(function () {
cb(null, 4);
}, randomTime());
},
"2": function (cb) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(3);
}, randomTime());
});
},
"1": function (cb) {
setTimeout(function () {
cb(null, 2);
}, randomTime());
},
"0": function (cb) {
setTimeout(function () {
cb(null, 1);
}, randomTime());
}
}, 2, safe.sure(done, function (result) {
assert.deepEqual(result, {'0': 1, '1': 2, '2': 3, '3': 4, '4': 5});
done();
}));
});
it("should execute asynchronous functions in parallel (catch errors)", function (done) {
safe.parallel({
"2": function (cb) {
setTimeout(function () {
cb(new Error(1));
}, randomTime());
},
"1": function (cb) {
return new Promise(function (resolve, reject) {
throw new Error(2);
});
},
"0": function (cb) {
throw new Error(3);
}
}, function (err, result) {
done(err ? null : new Error("Wrong behavior"));
});
});
it("should automatically resolve dependencies execute asynchronous functions", function (done) {
safe.auto({
"4": ["0", "2", function (cb, result) {
if (result["0"] !== "Tinker" || result["2"] !== "Soldier")
return cb(new Error("Wrong behavior"));
setTimeout(function () {
cb(null, "Spy");
}, randomTime());
}],
"3": ["1", "2", "4", function (cb, result) {
if (result["1"] !== "Tailor" || result["2"] !== "Soldier" || result["4"] !== "Spy")
return cb(new Error("Wrong behavior"));
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("Done");
}, randomTime());
});
}],
"2": ["0", function (cb, result) {
if (result["0"] !== "Tinker")
return cb(new Error("Wrong behavior"));
setTimeout(function () {
cb(null, "Soldier");
}, randomTime());
}],
"1": ["0", "4", function (cb, result) {
if (result["0"] !== "Tinker" || result["4"] !== "Spy")
return cb(new Error("Wrong behavior"));
setTimeout(function () {
cb(null, "Tailor");
}, randomTime());
}],
"0": [function (cb) {
setTimeout(function () {
cb(null, "Tinker");
}, randomTime());
}]
}, function (err, result) {
if (result["0"] !== "Tinker" ||
result["1"] !== "Tailor" ||
result["2"] !== "Soldier" ||
result["3"] !== "Done" ||
result["4"] !== "Spy")
return done(new Error("Wrong behavior"));
done();
});
});
it("Test unresolve dependies in auto", function (done) {
safe.auto({
"2": function (cb, result) {
setTimeout(function () {
cb(null, null);
}, randomTime());
},
"1": function (cb, result) {
setTimeout(function () {
cb(null, null);
}, randomTime());
},
"0": ["1", "3", function (cb) {
setTimeout(function () {
cb(null, null);
}, randomTime());
}]
}, function (err, result) {
done(err ? null : new Error("Wrong behavior"));
});
});
it("Test cyclic dependies in auto", function (done) {
safe.auto({
"2": ["1", function (cb, result) {
setTimeout(function () {
cb(null, null);
}, randomTime());
}],
"1": ["0", "2", function (cb, result) {
setTimeout(function () {
cb(null, null);
}, randomTime());
}],
"0": function (cb) {
setTimeout(function () {
cb(null, null);
}, randomTime());
}
}, function (err, result) {
done(err ? null : new Error("Wrong behavior"));
});
});
it("Test errors in auto", function (done) {
safe.auto({
"2": ["1", function (cb, result) {
setTimeout(function () {
cb(null, 2);
}, randomTime());
}],
"1": ["0", function (cb, result) {
throw new Error('exit');
}],
"0": function (cb) {
setTimeout(function () {
cb(null, "done");
}, randomTime());
}
}, function (err, result) {
if (err && result[0] === "done")
done();
else
done(new Error("Wrong behavior"));
});
});
it("Test limit auto", function (done) {
var count = 0;
safe.auto({
"4": ["1", function (cb, result) {
++count;
setTimeout(function () {
--count;
if (count >= 2)
throw new Error("Limit is reach!");
cb(null, 2);
}, randomTime());
}],
"3": ["1", function (cb, result) {
++count;
setTimeout(function () {
--count;
if (count >= 2)
throw new Error("Limit is reach!");
cb(null, 2);
}, randomTime());
}],
"2": ["1", function (cb, result) {
++count;
setTimeout(function () {
--count;
if (count >= 2)
throw new Error("Limit is reach!");
cb(null, 2);
}, randomTime());
}],
"1": ["0", function (cb, result) {
++count;
setTimeout(function () {
--count;
if (count >= 2)
throw new Error("Limit is reach!");
cb(null, 1);
}, randomTime());
}],
"0": function (cb) {
++count;
setTimeout(function () {
--count;
if (count >= 2)
throw new Error("Limit is reach!");
cb(null, "done");
}, randomTime());
}
}, 2, safe.sure(done, function () {
done();
}));
});
it("Try each (first success)", function (done) {
safe.tryEach([
function (cb) {
setTimeout(function () {
cb(null, 1);
}, randomTime());
},
function (cb) {
setTimeout(function () {
cb(null, 2);
}, randomTime());
}
], safe.sure(done, function (res) {
assert.equal(res, 1);
done();
}));
});
it("Try each (second success)", function (done) {
safe.tryEach([
function (cb) {
setTimeout(function () {
cb(new Error('1'), 1);
}, randomTime());
},
function (cb) {
setTimeout(function () {
cb(null, 2);
}, randomTime());
}
], safe.sure(done, function (res) {
assert.equal(res, 2);
done();
}));
});
it("Try each (all fails)", function (done) {
safe.tryEach([
function (cb) {
setTimeout(function () {
cb(1);
}, randomTime());
},
function (cb) {
setTimeout(function () {
cb(2);
}, randomTime());
}
], function (err, res) {
assert.equal(err, 2);
assert.equal(res, undefined);
done();
});
});
});
describe("queue", function () {
it("queue", function (done) {
var error = new Error('for test'),
hasError = 0;
var queue = safe.queue(function (task, cb) {
return task.cmd(function (err, res) {
if (task.name != 45)
assert.equal(res, "test");
else
assert.equal(err, error);
cb(err);
});
}, 1);
var counter = 0;
queue.drain = function () {
assert.equal(counter, 200);
assert.equal(hasError, 2);
done();
};
queue.error = function(err, task) {
assert.equal(err, error);
hasError++;
};
var arr = [];
for (var i = 0; i < 1000; i++) {
arr.push({
name: i,
cmd: function (cb) {
safe.yield(function () {
counter++;
if (counter === 10)
cb(error);
else
cb(null, "test");
});
}
});
if (arr.length === 10) {
queue.push(arr, function(err, task) {
if (err) {
assert.equal(err, error);
hasError++;
}
});
arr.length = 0;
}
}
queue.remove(function (item) {
return item.name % 5;
});
assert.equal(queue.length(), 200);
});
it("priorityQueue", function (done) {
var hasError = 0;
var queue = safe.priorityQueue(function (task, cb) {
return task.cmd(function (err, res) {
assert.equal(res, "test");
cb(err);
});
}, 2);
queue.pause();
var arr = [],
sature = 0,
unsature = 0;
queue.saturated = function () {
if (sature)
return;
assert.equal(queue.length(), 2);
sature = 1;
};
queue.unsaturated = function () {
if (unsature)
return;
assert.equal(queue.__workers, 1);
unsature = 1;
};
queue.drain = function () {
assert.deepEqual(arr, [4, 2, 1, 3]);
if (!sature)
return done(new Error("Wrong behavior"));
assert.equal(hasError, 0);
done();
};
queue.error = function(err, task) {
hasError++;
};
queue.push({
cmd: function (cb) {
safe.yield(function () {
arr.push(1);
cb(null, "test");
});
}
}, 2, function (err) {
if (err) throw err;
});
queue.push({
cmd: function (cb) {
return new Promise(function (resolve, reject) {
safe.yield(function () {
arr.push(2);
resolve("test");
});
});
}
}, 3, function (err) {
if (err) throw err;
});
queue.push({
cmd: function (cb) {
safe.yield(function () {
arr.push(3);
cb(null, "test");
});
}
}, 1, function (err) {
if (err) throw err;
});
queue.push({
cmd: function (cb) {
return new Promise(function (resolve, reject) {
arr.push(4);
resolve("test");
});
}
}, 4, function (err) {
if (err) throw err;
});
assert.equal(queue.length(), 4);
queue.resume();
});
it("cargo", function (done) {
var iteations = 0,
length = 1000,
counter = 0;
var cargo = safe.cargo(function (tasks, cb) {
length -= 100;
assert.equal(cargo.length(), length);
iteations++;
safe.each(tasks, function (task, cb) {
task.cmd(function (err, res) {
assert.equal(res, "test");
cb(err);
});
}, cb);
}, 100);
cargo.drain = function () {
assert.equal(iteations, 10);
assert.equal(counter, 1000);
done();
};
var arr = [];
for (var i = 0; i < length; i++) {
arr.push({
cmd: function (cb) {
safe.yield(function () {
counter++;
cb(null, "test");
});
}
});
}
cargo.push(arr, function (err) {
if (err)
throw (err);
});
});
});
describe("map", function () {
it("should execute asynchronous map (object)", function (done) {
safe.map({a: 1, b: 2, c: 3, d: 4, e: 5}, function (i, cb) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(i * 2);
}, randomTime());
});
}, safe.sure(done, function (res) {
assert.deepEqual(res, [2, 4, 6, 8, 10]);
done();
}));
});
it("should execute asynchronous map (array, limit)", function (done) {
safe.mapLimit([1, 2, 3, 4, 5], 2, function (i, cb) {
setTimeout(function () {
cb(null, i * 2);
}, randomTime());
}, safe.sure(done, function (res) {
assert.deepEqual(res, [2, 4, 6, 8, 10]);
done();
}));
});
it("should execute asynchronous map series", function (done) {
var execute = 0;
safe.mapSeries({a: 1, b: 2, c: 3, d: 4, e: 5}, function (i, cb) {
if (execute)
return cb(new Error("Wrong behavior"));
execute = 1;
setTimeout(function () {
execute = 0;
cb(null, i * 2);
}, randomTime());
}, safe.sure(done, function (res) {
assert.deepEqual(res, [2, 4, 6, 8, 10]);
done();
}));
});
it("should execute asynchronous map values (object)", function (done) {
safe.mapValues({a: 1, b: 2, c: 3, d: 4, e: 5}, function (i, k, cb) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(i * 2);
}, randomTime());
});
}, safe.sure(done, function (res) {
assert.deepEqual(res, {a: 2, b: 4, c: 6, d: 8, e: 10});
done();
}));
});
it("should execute asynchronous map values (array, limit)", function (done) {
safe.mapValuesLimit([1, 2, 3, 4, 5], 2, function (i, k, cb) {
setTimeout(function () {
cb(null, i * 2);
}, randomTime());
}, safe.sure(done, function (res) {
assert.deepEqual(res, {0: 2, 1: 4, 2: 6, 3: 8, 4: 10});
done();
}));
});
it("should execute asynchronous map values series", function (done) {
var execute = 0;
safe.mapValuesSeries({a: 1, b: 2, c: 3, d: 4, e: 5}, function (i, k, cb) {
if (execute)
return cb(new Error("Wrong behavior"));
execute = 1;
setTimeout(function () {
execute = 0;
cb(null, i * 2);
}, randomTime());
}, safe.sure(done, function (res) {
assert.deepEqual(res, {a: 2, b: 4, c: 6, d: 8, e: 10});
done();
}));
});
});
describe("groupBy", function () {
it("should execute asynchronous groupBy (object)", function (done) {
safe.groupBy({a: 1, b: 2, c: 3, d: 4, e: 5}, function (i, cb) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(i % 2 ? 'a' : 'b');
}, randomTime());
});
}, safe.sure(done, function (res) {
assert.deepEqual(res, { a: [ 1, 3, 5 ], b: [ 2, 4 ] });
done();
}));
});
it("should execute asynchronous groupBy (array, limit)", function (done) {
safe.groupByLimit([1, 2, 3, 4, 5], 2, function (i, cb) {
setTimeout(function () {
cb(null, i % 2 ? 'b' : 'a');
}, randomTime());
}, safe.sure(done, function (res) {
assert.deepEqual(res, { b: [ 1, 3, 5 ], a: [ 2, 4 ] });
done();
}));
});
it("should execute asynchronous groupBy series", function (done) {
var execute = 0;
safe.groupBySeries({a: 1, b: 2, c: 3, d: 4, e: 5}, function (i, cb) {
if (execute)
return cb(new Error("Wrong behavior"));
execute = 1;
setTimeout(function () {
execute = 0;
cb(null, i % 2 ? 'b' : 'a');
}, randomTime());
}, safe.sure(done, function (res) {
assert.deepEqual(res, { b: [ 1, 3, 5 ], a: [ 2, 4 ] });
done();
}));
});
});
describe("concat", function () {
it("should execute asynchronous arrays concat", function (done) {
safe.concat([1, 2, 3, 4, 5], function (i, cb) {
setTimeout(function () {
cb(null, [i, i * 2]);
}, randomTime());
}, safe.sure(done, function (res) {
assert.deepEqual(res, [1, 2, 2, 4, 3, 6, 4, 8, 5, 10]);
done();
}));
});
it("should execute asynchronous arrays concat (limit)", function (done) {
safe.concatLimit([1, 2, 3, 4, 5], 2, function (i, cb) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve([i, i * 2]);
}, randomTime());
});
}, safe.sure(done, function (res) {
assert.deepEqual(res, [1, 2, 2, 4, 3, 6, 4, 8, 5, 10]);
done();
}));
});
it("should execute asynchronous arrays concat series", function (done) {
var execute = 0;
safe.concatSeries([1, 2, 3, 4, 5], function (i, cb) {
if (execute)
return cb(new Error("Wrong behavior"));
execute = 1;
setTimeout(function () {
execute = 0;
cb(null, [i, i * 2]);
}, randomTime());
}, safe.sure(done, function (res) {
assert.deepEqual(res, [1, 2, 2, 4, 3, 6, 4, 8, 5, 10]);
done();
}));
});
});
describe("sortBy", function () {
it("should execute asynchronous sort", function (done) {
safe.sortBy([3, 5, 1, 4, 2], function (i, cb) {
return new Promise(function (resolve, reject) {
resolve(i);
});
}, safe.sure(done, function (res) {
assert.deepEqual(res, [1, 2, 3, 4, 5]);
done();
}));
});
});
describe("times", function () {
it("should execute asynchronous times", function (done) {
safe.times(5, function (i, cb) {
setTimeout(function () {
cb(null, i += 1);
}, randomTime());
}, safe.sure(done, function (res) {
assert.deepEqual(res, [1, 2, 3, 4, 5]);
done();
}));
});
it("should execute asynchronous times (limit)", function (done) {
safe.timesLimit(10, 2, function (i, cb) {
setTimeout(function () {
cb(null, i += 1);
}, randomTime());
}, safe.sure(done, function (res) {
assert.deepEqual(res, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
done();
}));
});
it("should execute asynchronous times series", function (done) {
var execute = 0;
safe.timesSeries(5, function (i, cb) {
if (execute)
return cb(new Error("Wrong behavior"));
return new Promise(function (resolve, reject) {
execute = 1;
setTimeout(function () {
execute = 0;
resolve(i * 2);
}, randomTime());
});
}, safe.sure(done, function (res) {
assert.deepEqual(res, [0, 2, 4, 6, 8]);
done();
}));
});
});
describe("filter", function () {
it("should execute asynchronous filter (array)", function (done) {
safe.filter([1, 2, 3, 4, 5], function (i, cb) {
return new Promise(function (resolve, reject) {
resolve(i % 2);
});
}, safe.sure(done, function (res) {
assert.deepEqual(res, [1, 3, 5]);
done();
}));
});
it("should execute asynchronous filter (array, limit)", function (done) {
safe.filterLimit([1, 2, 3, 4, 5], 2, function (i, cb) {
setTimeout(function () {
cb(null, i % 2);
}, randomTime());
}, safe.sure(done, function (res) {
assert.deepEqual(res, [1, 3, 5]);
done();
}));
});
it("should execute asynchronous filter series (array)", function (done) {
var execute = 0;
safe.filterSeries([1, 2, 3, 4, 5], function (i, cb) {
if (execute)
return cb(new Error("Wrong behavior"));
execute = 1;
setTimeout(function () {
execute = 0;
cb(null, i % 2);
}, randomTime());
}, safe.sure(done, function (res) {
assert.deepEqual(res, [1, 3, 5]);
done();
}));
});
});
describe("reject", function () {
it("should execute asynchronous reject (array)", function (done) {
safe.reject([1, 2, 3, 4, 5], function (i, cb) {
setTimeout(function () {
cb(null, i % 2);
}, randomTime());
}, safe.sure(done, function (res) {
assert.deepEqual(res, [2, 4]);
done();
}));
});
it("should execute asynchronous reject (array, limit)", function (done) {
safe.rejectLimit([1, 2, 3, 4, 5], 2, function (i, cb) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(i % 2);
}, randomTime());
});
}, safe.sure(done, function (res) {
assert.deepEqual(res, [2, 4]);
done();
}));
});
it("should execute asynchronous reject series (array)", function (done) {
var execute = 0;
safe.rejectSeries([1, 2, 3, 4, 5], function (i, cb) {
if (execute)
return cb(new Error("Wrong behavior"));
execute = 1;
setTimeout(function () {
execute = 0;
cb(null, i % 2);
}, randomTime());
}, safe.sure(done, function (res) {
assert.deepEqual(res, [2, 4]);
done();
}));
});
});
describe("detect", function () {
it("should execute asynchronous detect (array)", function (done) {
safe.detect([1, 2, 3, 4, 5], function (i, cb) {
setTimeout(function () {
cb(i === 2);
}, randomTime());
}, function (res) {
assert.deepEqual(res, 2);
done();
});
});
it("should execute asynchronous detect (array, limit)", function (done) {
safe.detectLimit([1, 2, 3, 4, 5], 2, function (i, cb) {
setTimeout(function () {
cb(i === 6);
}, randomTime());
}, function (res) {
assert.deepEqual(res, undefined);
done();
});
});
it("should execute asynchronous detect series (array)", function (done) {
var execute = 0;
safe.detectSeries([1, 2, 3, 4, 5], function (i, cb) {
if (execute)
return cb(new Error("Wrong behavior"));
execute = 1;
setTimeout(function () {
execute = 0;
cb(i === 4);
}, randomTime());
}, function (res) {
assert.deepEqual(res, 4);
done();
});
});
});
describe("detect", function () {
it("should execute asynchronous detect (array)", function (done) {
safe.detect([1, 2, 3, 4, 5], function (i, cb) {
setTimeout(function () {
cb(i === 2);
}, randomTime());
}, function (res) {
assert.deepEqual(res, 2);
done();
});
});
it("should execute asynchronous detect (array, limit)", function (done) {
safe.detectLimit([1, 2, 3, 4, 5], 2, function (i, cb) {
setTimeout(function () {
cb(i === 6);
}, randomTime());
}, function (res) {
assert.deepEqual(res, undefined);
done();
});
});
it("should execute asynchronous detect series (array)", function (done) {
var execute = 0;
safe.detectSeries([1, 2, 3, 4, 5], function (i, cb) {
if (execute)
return cb(new Error("Wrong behavior"));
execute = 1;
setTimeout(function () {
execute = 0;
cb(i === 4);
}, randomTime());
}, function (res) {
assert.deepEqual(res, 4);
done();
});
});
});
describe("some", function () {
it("should execute asynchronous some (array)", function (done) {
safe.some([1, 2, 3, 4, 5], function (i, cb) {
setTimeout(function () {
cb(i === 2);
}, randomTime());
}, function (res) {
assert.deepEqual(res, true);
done();
});
});
it("should execute asynchronous some (array, limit)", function (done) {
safe.someLimit([1, 2, 3, 4, 5], 2, function (i, cb) {
setTimeout(function () {
cb(i === 6);
}, randomTime());
}, function (res) {
assert.deepEqual(res, false);
done();
});
});
it("should execute asynchronous some series (array)", function (done) {
var execute = 0;
safe.someSeries([1, 2, 3, 4, 5], function (i, cb) {
if (execute)
return cb(new Error("Wrong behavior"));
execute = 1;
setTimeout(function () {
execute = 0;
cb(i === 4);
}, randomTime());
}, function (res) {
assert.deepEqual(res, true);
done();
});
});
});
describe("every", function () {
it("should execute asynchronous every (array)", function (done) {
safe.every([1, 3, 5, 7, 9], function (i, cb) {
setTimeout(function () {
cb(i % 2);
}, randomTime());
}, function (res) {
assert.deepEqual(res, true);
done();
});
});
it("should execute asynchronous every (array, limit)", function (done) {
safe.everyLimit([1, 3, 4, 7, 9], 2, function (i, cb) {
setTimeout(function () {
cb(i % 2);
}, randomTime());
}, function (res) {
assert.deepEqual(res, false);
done();
});
});
it("should execute asynchronous every series (array)", function (done) {
var execute = 0;
safe.everySeries([1, 3, 4, 7, 9], function (i, cb) {
if (execute)
return cb(new Error("Wrong behavior"));
execute = 1;
setTimeout(function () {
execute = 0;
cb(i % 2);
}, randomTime());
}, function (res) {
assert.deepEqual(res, false);
done();
});
});
});
describe("retry", function () {
it("should few times retry to execute function", function (done) {
var i = 0;
safe.retry(5, function (cb, res) {
return new Promise(function (resolve, reject) {
if (i)
assert.equal(res.err, "need more retry " + i);
i += 1;
if (i !== 5)
reject("need more retry " + i);
else
resolve("done");
});
}, safe.sure(done, function (res) {
assert.equal(res.result, "done");
assert.equal(i, 5);
done();
}));
});
it("should few times retry to execute function with filter", function (done) {
var i = 0;
var filter = function (e) {
return e !== "need more retry 3";
};
safe.retry({times: 5, errorFilter: filter}, function (cb, res) {
return new Promise(function (resolve, reject) {
if (i)
assert.equal(res.err, "need more retry " + i);
i += 1;
if (i !== 5)
reject("need more retry " + i);
else
resolve("done");
});
}, function (err, res) {
assert.equal(err, "need more retry 3");
assert.equal(i, 3);
done();
});
});
it("should few times retry to execute function (early done)", function (done) {
var i = 0,
sync = false;
var retry = safe.retry({times: 10, interval: 5}, function (cb, res) {
if (sync) {
return done(new Error("Wrong behavior"));
}
if (i)
assert.equal(res.err, "need more retry " + i);
i += 1;
sync = true;
if (i !== 3)
cb("need more retry " + i);
else
cb(null, "done");
sync = false;
});
retry(safe.sure(done, function (res) {
assert.equal(res.result, "done");
assert.equal(i, 3);
done();
}), {err: "need more retry " + i} );
});
it("should few times retry to execute function (interval function)", function (done) {
var i = 0,
sync = false;
var retry = safe.retry({times: 10, interval: function (count) { return count*i; }}, function (cb, res) {
if (sync) {
return done(new Error("Wrong behavior"));
}
if (i)
assert.equal(res.err, "need more retry " + i);
i += 1;
sync = true;
if (i !== 3)
cb("need more retry " + i);
else
cb(null, "done");
sync = false;
});
retry(safe.sure(done, function (res) {
assert.equal(res.result, "done");
assert.equal(i, 3);
done();
}), {err: "need more retry " + i} );
});
});
describe("do-while", function () {
it("should execute while a condition is true (sync tester)", function (done) {
var a = 0;
var flag = false;
safe.whilst(
function () {
flag = false;
return a < 5;
},
function (cb) {
return new Promise(function (resolve, reject) {
if (flag)
reject(new Error("Wrong behavior"));
setTimeout(function () {
resolve('abc');
}, randomTime());
a += 1;
});
}, safe.sure(done, function (res) {
assert.equal(a, 5);
assert.equal(res, 'abc');
done();
})
);
});
it("should execute while a condition is true (post check, sync tester)", function (done) {
var a = 0;
var flag = true;
safe.doWhilst(
function (cb) {
flag = false;
setTimeout(function () {
cb(null, 'abc');
}, randomTime());
a += 1;
},
function () {
if (flag)
throw new Error("Wrong behavior");
return a < 5 ? 1 : 0;
}, safe.sure(done, function (res) {
assert.equal(a, 5);
assert.equal(res, 'abc');
done();
}));
});
});
describe("do-during", function () {
it("should execute while a condition is true", function (done) {
var a = 0;
var flag = true;
safe.during(
function (cb) {
flag = false;
setTimeout(function () {
cb(null, a < 5);
}, randomTime());
},
function (cb) {
return new Promise(function (resolve, reject) {
if (flag)
reject(new Error("Wrong behavior"));
setTimeout(function () {
resolve('abc');
}, randomTime());
a += 1;
});
}, safe.sure(done, function (res) {
assert.equal(a, 5);
assert.equal(res, 'abc');
done();
})
);
});
it("should execute while a condition is true (post check)", function (done) {
var a = 0;
var flag = true;
safe.doDuring(
function (cb) {
flag = false;
setTimeout(function () {
cb(null, 'abc');
}, randomTime());
a += 1;
},
function (cb) {
if (flag)
throw new Error("Wrong behavior");
setTimeout(function () {
cb(null, a < 5);
}, randomTime());
}, safe.sure(done, function (res) {
assert.equal(a, 5);
assert.equal(res, 'abc');
done();
}));
});
});
describe("do-until", function () {
it("should execute until a condition is false", function (done) {
var a = 0;
var flag = true;
safe.until(
function () {
flag = false;
return a === 5;
},
function (cb) {
return new Promise(function (resolve, reject) {
if (flag)
reject(new Error("Wrong behavior"));
setTimeout(function () {
resolve('abc');
}, randomTime());
a += 1;
});
}, safe.sure(done, function (res) {
assert.equal(a, 5);
assert.equal(res, 'abc');
done();
}));
});
it("should execute until a condition is false (post check)", function (done) {
var a = 0;
var flag = true;
safe.doUntil(
function (cb) {
flag = false;
setTimeout(function () {
cb(null, 'abc');
}, randomTime());
a += 1;
},
function () {
if (flag)
throw new Error("Wrong behavior");
return a === 5;
}, safe.sure(done, function (res) {
assert.equal(a, 5);
assert.equal(res, 'abc');
done();
}));
});
});
describe("forever", function () {
it("should execute forever until without errback (async)", function (done) {
var a = 0;
var flag = false;
safe.forever(function (next) {
if (flag)
return done(new Error("Wrong behavior"));
flag = true;
setTimeout(function () {
flag = false;
a++;
next(a === 7 ? "exit" : null);
}, randomTime());
}, function (err) {
assert.equal(err, "exit");
assert.equal(a, 7);
done();
});
});
it("should execute forever until without errback (ensure async)", function (done) {
var a = 0,
sync = false;
safe.forever(function (next) {
if (sync)
return done(new Error("Wrong behavior"));
sync = true;
++a;
next(a === 2000 ? "exit" : null);
sync = false;
}, function (err) {
assert.equal(err, "exit");
assert.equal(a, 2000);
done();
});
});
});
describe("reduce", function () {
it("should reduce array an asynchronous iterator", function (done) {
safe.reduce([1, 2, 3, 4, 5], 0, function (memo, item, cb) {
return new Promise(function (resolve, reject) {
resolve(memo + item);
});
}, safe.sure(done, function (result) {
assert.equal(result, 15);
done();
}));
});
it("should reduce array an asynchronous iterator in reverse order", function (done) {
safe.reduceRight([1, 2, 3, 4, 5], 15, function (memo, item, cb) {
setTimeout(function () {
cb(null, memo - item);
}, randomTime());
}, safe.sure(done, function (result) {
assert.equal(result, 0);
done();
}));
});
});
describe("apply", function () {
it("should execute function with some arguments applied", function (done) {
function foo(text, cb) {
setTimeout(function () {
assert.equal(text, "test");
cb();
}, randomTime());
}
safe.parallel([
safe.apply(foo, "test"),
safe.apply(foo, "test")
], done);
});
it("should execute array function with some arguments applied", function (done) {
var a = 2;
function foo(text, cb) {
setTimeout(function () {
a--;
assert.equal(text, "test");
cb();
}, randomTime());
}
function bar(text, cb) {
setTimeout(function () {
a--;
assert.equal(text, "test");
cb();
}, randomTime());
}
safe.applyEach([foo, bar], 'test', safe.sure(done, function () {
assert.equal(a, 0);
done();
}));
});
it("should execute array function with some arguments applied (series, closure)", function (done) {
var arr = [1, 2, 3],
a = -1;
function foo(item, cb) {
a++;
setTimeout(function () {
assert.equal(item, arr[a]);
cb();
}, randomTime());
}
function bar(item, cb) {
assert.equal(item, arr[a]);
setTimeout(function () {
assert.equal(item, arr[a]);
cb();
}, randomTime());
}
safe.eachSeries(
arr,
safe.applyEachSeries([foo, bar]),
done
);
});
});
describe("transform", function () {
it("transform without memo", function (done) {
safe.transform([1, 2, 3], function(memo, x, v, cb){
memo.push(x + 1);
cb();
}, safe.sure(done, function(result){
assert.deepEqual(result, [2, 3, 4]);
done();
}));
});
it("transform array", function (done) {
safe.transform([1, 3, 2], {}, function(memo, v, k, callback){
setTimeout(function() {
memo[k] = v;
callback();
}, randomTime());
}, safe.sure(done, function(result){
assert.deepEqual(result, {0: 1, 1: 3, 2: 2});
done();
}));
});
it("transform object", function (done) {
safe.transform({a: 1, b: 3, c: 2}, {}, function(memo, v, k, callback){
setTimeout(function() {
memo[k] = v + 1;
callback();
}, randomTime());
}, safe.sure(done, function(result){
assert.deepEqual(result, {a: 2, b: 4, c: 3});
done();
}));
});
it("transform error", function (done) {
safe.transform([1, 2, 3], function(memo, v, k, callback){
setTimeout(function() {
callback('stop');
}, randomTime());
}, function(err){
assert.equal(err, 'stop');
done();
});
});
});
describe("race", function () {
it("First result", function (done) {
var arr = [];
for (var i = 0; i < 3; i++)
arr.push(function (cb) {
setTimeout(function () { cb(null, i); }, 10 - i*2);
});
safe.race(arr, safe.sure_result(done, function(result){
assert.equal(result, 3);
}));
});
it("First error", function (done) {
var arr = [];
for (var i = 0; i < 3; i++)
arr.push(function (cb) {
setTimeout(function () { cb(i === 3, i); }, 10 - i*2);
});
safe.race(arr, safe.sure(function (err) {
if (!err)
return done(new Error("Wrong behavior"));
done();
}, done));
});
});
describe("utils", function () {
it("ensure to async", function (done) {
var a = 2000, sync = false;
var arr = new Array(a);
for (var i = 0; i < arr.length; i += 1)
arr[i] = i;
safe.map(arr, safe.ensureAsync(function (i, cb) {
if (sync)
return done(new Error("Wrong behavior"));
sync = true;
cb(null, i);
sync = false;
}), safe.sure(done, function (result) {
assert.deepEqual(result, arr);
done(null);
}));
});
it("constant", function (done) {
safe.waterfall([
safe.constant("test"),
function (value, cb) {
assert.equal(value, "test");
safe.back(cb, null);
}
], done);
});
it("asyncify sync fn", function (done) {
var parse = safe.asyncify(JSON.parse);
parse('{"a":1}', safe.sure(done, function (result) {
assert.deepEqual(result, {"a":1});
done(null);
}));
});
it("asyncify promise", function (done) {
var promise = function(str) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(str);
}, randomTime());
});
};
safe.asyncify(promise)("done", safe.sure(done, function (result) {
assert.equal(result, "done");
done();
}));
});
it("memoize", function (done) { // test from async lib
var call_order = [];
var fn = function (arg1, arg2, callback) {
call_order.push(['fn', arg1, arg2]);
safe.yield(function () {
call_order.push(['cb', arg1, arg2]);
callback(null, arg1 + arg2);
});
};
var fn2 = safe.memoize(fn);
fn2(1, 2, safe.sure(done, function (result) {
assert.equal(result, 3);
fn2(1, 2, safe.sure(done, function (result) {
assert.equal(result, 3);
safe.yield(memoize_done);
call_order.push('tick3');
}));
call_order.push('tick2');
}));
call_order.push('tick1');
function memoize_done() {
var async_call_order = [
['fn',1,2],
'tick1',
['cb',1,2],
'tick2',
'tick3'
];
assert.deepEqual(call_order, async_call_order);
done();
}
});
it("unmemoize", function (done) { // test from async lib
var call_order = [];
var fn = function (arg1, arg2, callback) {
call_order.push(['fn', arg1, arg2]);
safe.yield(function () {
callback(null, arg1 + arg2);
});
};
var fn2 = safe.memoize(fn);
var fn3 = safe.unmemoize(fn2);
fn3(1, 2, safe.sure(done, function (result) {
assert.equal(result, 3);
fn3(1, 2, safe.sure(done, function (result) {
assert.equal(result, 3);
fn3(2, 2, safe.sure(done, function (result) {
assert.equal(result, 4);
assert.deepEqual(call_order, [['fn',1,2], ['fn',1,2], ['fn',2,2]]);
done();
}));
}));
}));
});
it("reflect", function (done) { // test from