diff --git a/lib/array.js b/lib/array.js index 02279bde..a6ef9003 100644 --- a/lib/array.js +++ b/lib/array.js @@ -1,7 +1,11 @@ 'use strict'; +const common = require('@metarhia/common'); +const { asyncIter } = require('./async-iterator.js'); +const { promisify } = require('util'); + // Asynchronous map (iterate parallel) -// items - , incoming +// items - , incoming // fn - , to be executed for each value in the array // current - , current element being processed in the array // callback - @@ -9,38 +13,21 @@ // value - // done - , on done, optional // err - | -// result - -const map = (items, fn, done) => { - const len = items.length; - if (!len) { - done(null, []); +// result - +const map = (items, fn, done = common.emptyness) => { + if (!items[Symbol.iterator]) { + done(new TypeError('"items" argument is not iterable')); return; } - let errored = false; - let count = 0; - const result = new Array(len); - - const next = (index, err, value) => { - if (errored) return; - if (err) { - errored = true; - done(err); - return; - } - result[index] = value; - count++; - if (count === len) done(null, result); - }; - - for (let i = 0; i < len; i++) { - fn(items[i], next.bind(null, i)); - } + const isArray = Array.isArray(items); + asyncIter(items) + .parallel(item => promisify(fn)(item)) + .then(res => done(null, isArray ? res : new items.constructor(res))) + .catch(done); }; -const DEFAULT_OPTIONS = { min: 5, percent: 0.7 }; - // Non-blocking synchronous map -// items - , incoming dataset +// items - , incoming dataset // fn - // item - // index - @@ -49,59 +36,26 @@ const DEFAULT_OPTIONS = { min: 5, percent: 0.7 }; // percent - , ratio of map time to all time // done - , call on done // err - | -// result - -const asyncMap = (items, fn, options = {}, done) => { +// result - +const asyncMap = (items, fn, options = {}, done = common.emptyness) => { if (typeof options === 'function') { done = options; - options = DEFAULT_OPTIONS; + options = {}; } - - if (!items.length) { - if (done) done(null, []); + if (!items[Symbol.iterator]) { + done(new TypeError('"items" argument is not iterable')); return; } - - const min = options.min || DEFAULT_OPTIONS.min; - const percent = options.percent || DEFAULT_OPTIONS.percent; - - let begin; - let sum = 0; - let count = 0; - - const result = done ? new Array(items.length) : null; - const ratio = percent / (1 - percent); - - const countNumber = () => { - const loopTime = Date.now() - begin; - const itemTime = sum / count; - const necessaryNumber = (ratio * loopTime) / itemTime; - return Math.max(necessaryNumber, min); - }; - - const next = () => { - const itemsNumber = count ? countNumber() : min; - const iterMax = Math.min(items.length, itemsNumber + count); - - begin = Date.now(); - for (; count < iterMax; count++) { - const itemResult = fn(items[count], count); - if (done) result[count] = itemResult; - } - sum += Date.now() - begin; - - if (count < items.length) { - begin = Date.now(); - setTimeout(next, 0); - } else if (done) { - done(null, result); - } - }; - - next(); + const isArray = Array.isArray(items); + const iter = asyncIter(items) + .map(item => promisify(fn)(item)) + .throttle(options.percent, options.min); + const collect = isArray ? iter.toArray() : iter.collectTo(items.constructor); + collect.then(res => done(null, res)).catch(done); }; -// Asynchrous filter (iterate parallel) -// items - , incoming +// Asynchronous filter (iterate parallel) +// items - , incoming // fn - , to be executed for each value in the array // value - , item from items array // callback - @@ -109,49 +63,26 @@ const asyncMap = (items, fn, options = {}, done) => { // accepted - // done - , on done, optional // err - | -// result - -const filter = (items, fn, done) => { - const len = items.length; - - if (!len) { - done(null, []); +// result - +const filter = (items, fn, done = common.emptyness) => { + if (!items[Symbol.iterator]) { + done(new TypeError('"items" argument is not iterable')); return; } - - let count = 0; - let suitable = 0; - const data = new Array(len); - const rejected = Symbol('rejected'); - - const next = (index, err, accepted) => { - if (!accepted || err) { - data[index] = rejected; - } else { - data[index] = items[index]; - suitable++; - } - count++; - if (count === len) { - const result = new Array(suitable); - let pos = 0; - for (let i = 0; i < len; i++) { - const val = data[i]; - if (val !== rejected) result[pos++] = val; - } - done(null, result); - } - }; - - for (let i = 0; i < len; i++) { - fn(items[i], next.bind(null, i)); - } + const isArray = Array.isArray(items); + asyncIter(items) + .parallel(async item => [await promisify(fn)(item), item]) + .then(res => { + const filtered = res + .filter(([predicateResult]) => predicateResult) + .map(([, item]) => item); + done(null, isArray ? filtered : new items.constructor(filtered)); + }) + .catch(done); }; -const REDUCE_EMPTY_ARR = - 'Metasync: reduce of empty array with no initial value'; - // Asynchronous reduce -// items - , incoming +// items - , incoming // fn - , to be executed for each value in array // previous - , value previously returned in the last iteration // current - , current element being processed in the array @@ -161,54 +92,21 @@ const REDUCE_EMPTY_ARR = // data - , resulting value // counter - , index of the current element // being processed in array -// items - , the array reduce was called upon +// items - , the array reduce was called upon // done - , on done, optional // err - | -// result - +// result - // initial - , optional value to be used as first // argument in first iteration -const reduce = (items, fn, done, initial) => { - const len = items.length; - const hasInitial = typeof initial !== 'undefined'; - - if (len === 0 && !hasInitial) { - done(new TypeError(REDUCE_EMPTY_ARR), initial); - return; - } - - let previous = hasInitial ? initial : items[0]; - if ((len === 0 && hasInitial) || (len === 1 && !hasInitial)) { - done(null, previous); - return; - } - - let count = hasInitial ? 0 : 1; - let current = items[count]; - const last = len - 1; - - const next = (err, data) => { - if (err) { - done(err); - return; - } - if (count === last) { - done(null, data); - return; - } - count++; - previous = data; - current = items[count]; - fn(previous, current, next, count, items); - }; - - fn(previous, current, next, count, items); +const reduce = (items, fn, done = common.emptyness, initial) => { + asyncIter(items) + .reduce((prev, cur) => promisify(fn)(prev, cur), initial) + .then(res => done(null, res)) + .catch(done); }; -const REDUCE_RIGHT_EMPTY_ARR = - 'Metasync: reduceRight of empty array with no initial value'; - // Asynchronous reduceRight -// items - , incoming +// items - , incoming // fn - , to be executed for each value in array // previous - , value previously returned in the last iteration // current - , current element being processed in the array @@ -218,115 +116,53 @@ const REDUCE_RIGHT_EMPTY_ARR = // data - , resulting value // counter - , index of the current element // being processed in array -// items - , the array reduce was called upon +// items - , the array reduce was called upon // done - , on done, optional // err - | -// result - +// result - // initial - , optional value to be used as first // argument in first iteration -const reduceRight = (items, fn, done, initial) => { - const len = items.length; - const hasInitial = typeof initial !== 'undefined'; - - if (len === 0 && !hasInitial) { - done(new TypeError(REDUCE_RIGHT_EMPTY_ARR), initial); - return; - } - - let previous = hasInitial ? initial : items[len - 1]; - if ((len === 0 && hasInitial) || (len === 1 && !hasInitial)) { - done(null, previous); - return; - } - - let count = hasInitial ? len - 1 : len - 2; - let current = items[count]; - const last = 0; - - const next = (err, data) => { - if (err) { - done(err); - return; - } - if (count === last) { - done(null, data); - return; - } - count--; - previous = data; - current = items[count]; - fn(previous, current, next, count, items); - }; - - fn(previous, current, next, count, items); +const reduceRight = (items, fn, done = common.emptyness, initial) => { + asyncIter(items) + .reduceRight((prev, cur) => promisify(fn)(prev, cur), initial) + .then(res => done(null, res)) + .catch(done); }; // Asynchronous each (iterate in parallel) -// items - , incoming +// items - , incoming // fn - // value - , item from items array // callback - // err - | // done - , on done, optional // err - | -// items - -const each = (items, fn, done) => { - const len = items.length; - if (len === 0) { - done(null, items); - return; - } - let count = 0; - let errored = false; - - const next = err => { - if (errored) return; - if (err) { - errored = true; - done(err); - return; - } - count++; - if (count === len) done(null); - }; - - for (let i = 0; i < len; i++) { - fn(items[i], next); - } +// items - +const each = (items, fn, done = common.emptyness) => { + asyncIter(items) + .parallel(item => promisify(fn)(item)) + .then(res => done(null, res)) + .catch(done); }; // Asynchronous series -// items - , incoming +// items - , incoming // fn - // value - , item from items array // callback - // err - | // done - , on done, optional // err - | -// items - -const series = (items, fn, done) => { - const len = items.length; - let i = -1; - - const next = () => { - i++; - if (i === len) { - done(null, items); - return; - } - fn(items[i], err => { - if (err) { - done(err); - return; - } - setImmediate(next); - }); - }; - next(); +// items - +const series = (items, fn, done = common.emptyness) => { + asyncIter(items) + .each(item => promisify(fn)(item)) + .then(res => done(null, res)) + .catch(done); }; // Asynchronous find (iterate in series) -// items - , incoming +// items - , incoming // fn - , // value - , item from items array // callback - @@ -335,37 +171,15 @@ const series = (items, fn, done) => { // done - , on done, optional // err - | // result - -const find = (items, fn, done) => { - const len = items.length; - if (len === 0) { - done(); - return; - } - let finished = false; - const last = len - 1; - - const next = (index, err, accepted) => { - if (finished) return; - if (err) { - finished = true; - done(err); - return; - } - if (accepted) { - finished = true; - done(null, items[index]); - return; - } - if (index === last) done(null); - }; - - for (let i = 0; i < len; i++) { - fn(items[i], next.bind(null, i)); - } +const find = (items, fn, done = common.emptyness) => { + asyncIter(items) + .find(item => promisify(fn)(item)) + .then(res => done(null, res)) + .catch(done); }; // Asynchronous every -// items - , incoming +// items - , incoming // fn - , // value - , item from items array // callback - @@ -374,30 +188,18 @@ const find = (items, fn, done) => { // done - , on done, optional // err - | // result - -const every = (items, fn, done) => { - if (items.length === 0) { - done(null, true); - return; - } - let proceedItemsCount = 0; - const len = items.length; - - const finish = (err, accepted) => { - if (!done) return; - if (err || !accepted) { - done(err, false); - done = null; - return; - } - proceedItemsCount++; - if (proceedItemsCount === len) done(null, true); - }; - - for (const item of items) fn(item, finish); +const every = (items, fn, done = common.emptyness) => { + asyncIter(items) + .parallel(item => promisify(fn)(item)) + .then(res => { + const accepted = res.every(predicateResult => predicateResult); + done(null, accepted); + }) + .catch(done); }; // Asynchronous some (iterate in series) -// items - , incoming +// items - , incoming // fn - // value - , item from items array // callback - @@ -406,31 +208,11 @@ const every = (items, fn, done) => { // done - , on done // err - | // result - -const some = (items, fn, done) => { - const len = items.length; - let i = 0; - - const next = () => { - if (i === len) { - done(null, false); - return; - } - fn(items[i], (err, accepted) => { - if (err) { - done(err); - return; - } - if (accepted) { - done(null, true); - return; - } - i++; - next(); - }); - }; - - if (len > 0) next(); - else done(null, false); +const some = (items, fn, done = common.emptyness) => { + asyncIter(items) + .some(item => promisify(fn)(item)) + .then(res => done(null, res)) + .catch(done); }; module.exports = { diff --git a/lib/async-iterator.js b/lib/async-iterator.js index 5f2079aa..27229bbb 100644 --- a/lib/async-iterator.js +++ b/lib/async-iterator.js @@ -101,6 +101,10 @@ class AsyncIterator { return result; } + async reduceRight(reducer, initialValue) { + return this.reverse().reduce(reducer, initialValue); + } + async some(predicate, thisArg) { for await (const value of this) { if (await predicate.call(thisArg, value)) { @@ -195,6 +199,10 @@ class AsyncIterator { enumerate() { return new EnumerateIterator(this); } + + reverse() { + return new ReverseIterator(this.base); + } } class MapIterator extends AsyncIterator { @@ -213,6 +221,16 @@ class MapIterator extends AsyncIterator { } } +class ReverseIterator extends AsyncIterator { + constructor(base) { + const newBase = []; + for (const value of base) { + newBase.unshift(value); + } + super(newBase); + } +} + class FilterIterator extends AsyncIterator { constructor(base, predicate, thisArg) { super(base); @@ -403,19 +421,19 @@ class ThrottleIterator extends AsyncIterator { this.ratio = percent / (1 - percent); this.sum = 0; - this.count = 0; + this.iterCount = 0; this.begin = Date.now(); this.iterMax = this.min; } async next() { - if (this.iterMax > this.count) { - this.count++; - return this.base.next(); + if (this.iterMax > this.iterCount) { + this.iterCount++; + return await this.base.next(); } this.sum += Date.now() - this.begin; - const itemTime = this.sum / this.count; + const itemTime = this.sum / this.iterCount; this.begin = Date.now(); await timeout(); @@ -423,9 +441,9 @@ class ThrottleIterator extends AsyncIterator { const number = Math.max((this.ratio * loopTime) / itemTime, this.min); - this.iterMax = Math.round(number) + this.count; + this.iterMax = Math.round(number) + this.iterCount; - this.count++; + this.iterCount++; this.begin = Date.now(); return this.base.next(); } diff --git a/lib/control.js b/lib/control.js index 4877e755..789f8bff 100644 --- a/lib/control.js +++ b/lib/control.js @@ -1,8 +1,7 @@ 'use strict'; const common = require('@metarhia/common'); - -const { each } = require('./array'); +const { each } = require('./array.js'); // Executes all asynchronous functions and pass first result to callback // fns - , callback-last / err-first diff --git a/test/array.asyncMap.js b/test/array.asyncMap.js index a2deabc3..98ff5604 100644 --- a/test/array.asyncMap.js +++ b/test/array.asyncMap.js @@ -3,18 +3,62 @@ const metasync = require('..'); const metatests = require('metatests'); -metatests.test('succesfull map', test => { - test.plan(2); - +metatests.test('successful map / Array', test => { const arr = [1, 2, 3]; - const expectedArr = [2, 4, 6]; + const expected = [2, 4, 6]; metasync.asyncMap( arr, - item => item * 2, + (x, callback) => process.nextTick(() => callback(null, x * 2)), (err, newArr) => { test.error(err); - test.strictSame(newArr, expectedArr); + test.strictSame(newArr, expected); + test.end(); + } + ); +}); + +metatests.test('successful map / Set', test => { + const set = new Set([1, 2, 3]); + const expected = new Set([2, 4, 6]); + + metasync.asyncMap( + set, + (x, callback) => process.nextTick(() => callback(null, x * 2)), + (err, newSet) => { + test.error(err); + test.strictSame([...newSet], [...expected]); + test.end(); + } + ); +}); + +metatests.test('successful map / Map', test => { + const map = new Map([[1, 'a'], [2, 'b'], [3, 'c']]); + const expected = new Map([['a', 1], ['b', 2], ['c', 3]]); + + metasync.asyncMap( + map, + (x, callback) => process.nextTick(() => callback(null, x.reverse())), + (err, res) => { + test.error(err); + test.strictSame([...res], [...expected]); + test.end(); + } + ); +}); + +metatests.test('successful map / String', test => { + const str = 'abcdefgh'; + const expected = 'A,B,C,D,E,F,G,H'; + + metasync.asyncMap( + str, + (x, callback) => process.nextTick(() => callback(null, x.toUpperCase())), + (err, res) => { + test.error(err); + test.strictSame([...res], [...expected]); + test.end(); } ); }); @@ -24,7 +68,7 @@ const doSmth = time => { while (Date.now() - begin < time); }; -metatests.test('Non-blocking', test => { +metatests.test('asyncMap non-blocking', test => { const ITEM_TIME = 1; const TIMER_TIME = 9; const ARRAY_SIZE = 1000; @@ -32,17 +76,18 @@ metatests.test('Non-blocking', test => { const EXPECTED_DEVIATION = 0.2; const arr = new Array(ARRAY_SIZE).fill(1); - const timer = setInterval(() => doSmth(TIMER_TIME), 1); - const begin = Date.now(); + metasync.asyncMap( arr, - () => doSmth(ITEM_TIME), + (x, callback) => { + doSmth(ITEM_TIME); + callback(); + }, { percent: EXPECTED_PERCENT }, () => { clearInterval(timer); - const mapTime = ITEM_TIME * ARRAY_SIZE; const allTime = Date.now() - begin; const actualPercent = mapTime / allTime; @@ -52,3 +97,30 @@ metatests.test('Non-blocking', test => { } ); }); + +metatests.test('asyncMap with error', test => { + const arr = [1, 2, 3]; + const asyncMapError = new Error('asyncMap error'); + + metasync.asyncMap( + arr, + (x, callback) => + process.nextTick(() => callback(x === 2 ? asyncMapError : null, x * x)), + (err, res) => { + test.isError(err, asyncMapError); + test.assertNot(res); + test.end(); + } + ); +}); + +metatests.test('asyncMap with not iterable', test => { + const obj = { a: '1', b: '2', c: '3' }; + const expectedError = new TypeError('"items" argument is not iterable'); + + metasync.asyncMap(obj, test.mustNotCall(), (err, res) => { + test.isError(err, expectedError); + test.assertNot(res); + test.end(); + }); +}); diff --git a/test/array.each.js b/test/array.each.js index 22b2c4a2..927b4d3b 100644 --- a/test/array.each.js +++ b/test/array.each.js @@ -3,71 +3,128 @@ const metasync = require('..'); const metatests = require('metatests'); -metatests.test('successful each', test => { +metatests.test('successful each / Array', test => { const arr = [1, 2, 3, 4]; - - const elementsSet = new Set(); - const expectedElementsSet = new Set(arr); + const arrCopy = []; metasync.each( arr, - (el, callback) => + (item, callback) => process.nextTick(() => { - elementsSet.add(el); + arrCopy.push(item); callback(null); }), err => { test.error(err); - test.strictSame(elementsSet, expectedElementsSet); + test.strictSame(arrCopy, arr); test.end(); } ); }); -metatests.test('each with empty array', test => { - const arr = []; +metatests.test('successful each / Set', test => { + const set = new Set([1, 2, 3, 4, 5]); + const setCopy = new Set(); - const elementsSet = new Set(); - const expectedElementsSet = new Set(arr); + metasync.each( + set, + (item, callback) => + process.nextTick(() => { + setCopy.add(item); + callback(null); + }), + err => { + test.error(err); + test.strictSame([...setCopy], [...set]); + test.end(); + } + ); +}); + +metatests.test('successful each / Map', test => { + const map = new Map([[1, 'a'], [2, 'b'], [3, 'c']]); + const mapCopy = new Map(); metasync.each( - arr, - (el, callback) => + map, + (entry, callback) => + process.nextTick(() => { + mapCopy.set(...entry); + callback(null); + }), + err => { + test.error(err); + test.strictSame([...mapCopy], [...map]); + test.end(); + } + ); +}); + +metatests.test('successful each / String', test => { + const str = 'aaabcdeefff'; + let strCopy = ''; + + metasync.each( + str, + (item, callback) => process.nextTick(() => { - elementsSet.add(el); + strCopy += item; callback(null); }), err => { test.error(err); - test.strictSame(elementsSet, expectedElementsSet); + test.strictSame(strCopy, str); test.end(); } ); }); +metatests.test('each with empty / Array', test => { + const arr = []; + + metasync.each(arr, test.mustNotCall(), err => { + test.error(err); + test.end(); + }); +}); + +metatests.test('each with empty / Set', test => { + const set = new Set(); + + metasync.each(set, test.mustNotCall(), err => { + test.error(err); + test.end(); + }); +}); + +metatests.test('each with empty / Map', test => { + const map = new Map(); + + metasync.each(map, test.mustNotCall(), err => { + test.error(err); + test.end(); + }); +}); + +metatests.test('each with empty / String', test => { + const str = ''; + + metasync.each(str, test.mustNotCall(), err => { + test.error(err); + test.end(); + }); +}); + metatests.test('each with error', test => { const arr = [1, 2, 3, 4]; - let count = 0; - - const elementsSet = new Set(); - const expectedElementsCount = 2; - const eachError = new Error('Each error'); + const eachError = new Error('each error'); metasync.each( arr, - (el, callback) => - process.nextTick(() => { - elementsSet.add(el); - count++; - if (count === expectedElementsCount) { - callback(eachError); - } else { - callback(null); - } - }), + (x, callback) => + process.nextTick(() => callback(x === 3 ? eachError : null)), err => { - test.strictSame(err, eachError); - test.strictSame(elementsSet.size, expectedElementsCount); + test.isError(err, eachError); test.end(); } ); diff --git a/test/array.every.js b/test/array.every.js index fb36a173..f678782a 100644 --- a/test/array.every.js +++ b/test/array.every.js @@ -9,7 +9,6 @@ const strictSameResult = (input, expectedResult, test, done) => { metasync.every(input, identity, (err, result) => { test.error(err); test.strictSame(result, expectedResult); - done(); }); }; @@ -24,26 +23,6 @@ const fewStrictSameResult = (inOutPairs, test) => { } }; -metatests.test('every with error', test => { - const data = [1, 2, 3]; - const everyErr = new Error('Every error'); - - const predicate = (item, callback) => { - process.nextTick(() => - item % 2 === 0 ? callback(everyErr) : callback(null, true) - ); - }; - - metasync.every(data, predicate, err => { - test.strictSame(err, everyErr); - test.end(); - }); -}); - -metatests.test('every with empty array', test => - strictSameResult([], true, test, () => test.end()) -); - metatests.test('every with one-element arrays', test => fewStrictSameResult([[[false], false], [[true], true]], test) ); @@ -60,16 +39,122 @@ metatests.test('every with two-element arrays', test => ) ); -metatests.test('every', test => { - const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; +metatests.test('every / Array', test => { + const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + + metasync.every( + arr, + (x, callback) => { + process.nextTick(() => callback(null, x > 0)); + }, + (err, result) => { + test.error(err); + test.strictSame(result, true); + test.end(); + } + ); +}); + +metatests.test('every / Set', test => { + const set = new Set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); + + metasync.every( + set, + (x, callback) => { + process.nextTick(() => callback(null, x > 0)); + }, + (err, result) => { + test.error(err); + test.strictSame(result, true); + test.end(); + } + ); +}); + +metatests.test('every / Map', test => { + const map = new Map([[1, 'a'], [2, 'b'], [3, 'c']]); - const predicate = (item, callback) => { - process.nextTick(() => callback(null, item > 0)); - }; + metasync.every( + map, + (x, callback) => { + process.nextTick(() => callback(null, x[0] > 0)); + }, + (err, result) => { + test.error(err); + test.strictSame(result, true); + test.end(); + } + ); +}); - metasync.every(data, predicate, (err, result) => { +metatests.test('every / String', test => { + const str = 'aaaaaaaaaaaa'; + + metasync.every( + str, + (x, callback) => { + process.nextTick(() => callback(null, x === 'a')); + }, + (err, result) => { + test.error(err); + test.strictSame(result, true); + test.end(); + } + ); +}); + +metatests.test('every with empty / Array', test => { + const arr = []; + + metasync.every(arr, test.mustNotCall(), (err, res) => { test.error(err); - test.strictSame(result, true); + test.strictSame(res, true); test.end(); }); }); + +metatests.test('every with empty / Set', test => { + const set = new Set(); + + metasync.every(set, test.mustNotCall(), (err, res) => { + test.error(err); + test.strictSame(res, true); + test.end(); + }); +}); + +metatests.test('every with empty / Map', test => { + const map = new Map(); + + metasync.every(map, test.mustNotCall(), (err, res) => { + test.error(err); + test.strictSame(res, true); + test.end(); + }); +}); + +metatests.test('every with empty / String', test => { + const str = ''; + + metasync.every(str, test.mustNotCall(), (err, res) => { + test.error(err); + test.strictSame(res, true); + test.end(); + }); +}); + +metatests.test('every with error', test => { + const arr = [1, 2, 3]; + const everyError = new Error('every error'); + + metasync.every( + arr, + (x, callback) => { + process.nextTick(() => callback(x === 2 ? everyError : null, true)); + }, + err => { + test.isError(err, everyError); + test.end(); + } + ); +}); diff --git a/test/array.filter.js b/test/array.filter.js index 55528e85..d79539f3 100644 --- a/test/array.filter.js +++ b/test/array.filter.js @@ -3,116 +3,134 @@ const metasync = require('..'); const metatests = require('metatests'); -metatests.test('successful filter', test => { - const arr = [ - 'Lorem', - 'ipsum', - 'dolor', - 'sit', - 'amet', - 'consectetur', - 'adipiscing', - 'elit', - 'sed', - 'do', - 'eiusmod', - 'tempor', - 'incididunt', - 'ut', - 'labore', - 'et', - 'dolore', - 'magna', - 'aliqua', - ]; - const expectedArr = [ - 'Lorem', - 'ipsum', - 'dolor', - 'sit', - 'amet', - 'elit', - 'sed', - 'do', - 'ut', - 'et', - 'magna', - ]; +metatests.test('successful filter / Array', test => { + const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + const expected = [2, 4, 6, 8, 10]; metasync.filter( arr, - (str, callback) => process.nextTick(() => callback(null, str.length < 6)), + (x, callback) => process.nextTick(() => callback(null, x % 2 === 0)), (err, res) => { test.error(err); - test.same(res.join(), expectedArr.join()); + test.strictSame(res, expected); test.end(); } ); }); -metatests.test('filter with empty array', test => { - const arr = []; - const expectedArr = []; +metatests.test('successful filter / Set', test => { + const set = new Set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + const expected = new Set([2, 4, 6, 8, 10]); metasync.filter( - arr, - (str, callback) => process.nextTick(() => callback(null, str.length < 6)), + set, + (x, callback) => process.nextTick(() => callback(null, x % 2 === 0)), (err, res) => { test.error(err); - test.strictSame(res, expectedArr); + test.strictSame([...res], [...expected]); test.end(); } ); }); -metatests.test('successful filter', test => { - const arr = [ - 'Lorem', - 'ipsum', - 'dolor', - 'sit', - 'amet', - 'consectetur', - 'adipiscing', - 'elit', - 'sed', - 'do', - 'eiusmod', - 'tempor', - 'incididunt', - 'ut', - 'labore', - 'et', - 'dolore', - 'magna', - 'aliqua', - ]; - const filterError = new Error('Filter error'); - const expectedArr = [ - 'Lorem', - 'ipsum', - 'dolor', - 'sit', - 'amet', - 'elit', - 'sed', - 'magna', - ]; +metatests.test('successful filter / Map', test => { + const map = new Map([[1, 'a'], [2, 'b'], [3, 'c'], [4, 'd'], [5, 'e']]); + const expected = new Map([[4, 'd'], [5, 'e']]); metasync.filter( - arr, - (str, callback) => - process.nextTick(() => { - if (str.length === 2) { - callback(filterError); - return; - } - callback(null, str.length < 6); - }), + map, + (x, callback) => process.nextTick(() => callback(null, x[0] > 3)), (err, res) => { test.error(err); - test.same(res.join(), expectedArr.join()); + test.same([...res], [...expected]); test.end(); } ); }); + +metatests.test('successful filter / String', test => { + const str = 'aaabcfeeeeds'; + const expected = 'a,a,a,e,e,e,e'; + + metasync.filter( + str, + (x, callback) => + process.nextTick(() => callback(null, x === 'a' || x === 'e')), + (err, res) => { + test.error(err); + test.same([...res], [...expected]); + test.end(); + } + ); +}); + +metatests.test('filter with empty / Array', test => { + const arr = []; + const expected = []; + + metasync.filter(arr, test.mustNotCall(), (err, res) => { + test.error(err); + test.strictSame(res, expected); + test.end(); + }); +}); + +metatests.test('filter with empty / Set', test => { + const set = new Set(); + const expected = new Set(); + + metasync.filter(set, test.mustNotCall(), (err, res) => { + test.error(err); + test.strictSame([...res], [...expected]); + test.end(); + }); +}); + +metatests.test('filter with empty / Map', test => { + const map = new Map(); + const expected = new Map(); + + metasync.filter(map, test.mustNotCall(), (err, res) => { + test.error(err); + test.strictSame([...res], [...expected]); + test.end(); + }); +}); + +metatests.test('filter with empty / String', test => { + const str = ''; + const expected = ''; + + metasync.filter(str, test.mustNotCall(), (err, res) => { + test.error(err); + test.strictSame([...res], [...expected]); + test.end(); + }); +}); + +metatests.test('filter with error', test => { + const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + const filterError = new Error('filter error'); + + metasync.filter( + arr, + (x, callback) => + process.nextTick(() => callback(x === 5 ? filterError : null, x % 2)), + (err, res) => { + test.isError(err, filterError); + test.assertNot(res); + test.end(); + } + ); +}); + +metatests.test('filter with not iterable', test => { + const obj = { a: '1', b: '2', c: '3' }; + const expectedError = new TypeError('"items" argument is not iterable'); + + metasync.filter(obj, test.mustNotCall(), (err, res) => { + test.isError(err, expectedError); + test.assertNot(res); + test.end(); + }); +}); diff --git a/test/array.find.js b/test/array.find.js index fa26a458..1ec76874 100644 --- a/test/array.find.js +++ b/test/array.find.js @@ -3,58 +3,131 @@ const metasync = require('..'); const metatests = require('metatests'); -metatests.test('find with error', test => { - const data = [1, 2, 3]; - const expectedErrorMessage = 'Intentional error'; - const predicate = (item, callback) => - process.nextTick(() => { - if (item % 2 === 0) { - callback(new Error(expectedErrorMessage)); - } else { - callback(null, false); - } - }); - - metasync.find(data, predicate, err => { - test.type(err, 'Error', 'err must be an instance of Error'); - test.strictSame(err.message, expectedErrorMessage); +const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + +metatests.test('find / Array', test => { + const expected = 6; + + metasync.find( + arr, + (x, callback) => process.nextTick(() => callback(null, x > 5)), + (err, res) => { + test.error(err); + test.strictSame(res, expected); + test.end(); + } + ); +}); + +metatests.test('find / Set', test => { + const set = new Set(arr); + const expected = 6; + + metasync.find( + set, + (x, callback) => process.nextTick(() => callback(null, x > 5)), + (err, res) => { + test.error(err); + test.strictSame(res, expected); + test.end(); + } + ); +}); + +metatests.test('find / Map', test => { + const map = new Map([[1, 'a'], [2, 'b'], [3, 'c']]); + const expected = [3, 'c']; + + metasync.find( + map, + (x, callback) => process.nextTick(() => callback(null, x[1] === 'c')), + (err, res) => { + test.error(err); + test.strictSame(res, expected); + test.end(); + } + ); +}); + +metatests.test('find / String', test => { + const str = 'abcdefgh'; + const cCharCode = 'c'.charCodeAt(0); + const expected = 'd'; + + metasync.find( + str, + (x, callback) => + process.nextTick(() => callback(null, x.charCodeAt(0) > cCharCode)), + (err, res) => { + test.error(err); + test.strictSame(res, expected); + test.end(); + } + ); +}); + +metatests.test('find with empty / Array', test => { + const arr = []; + + metasync.find(arr, test.mustNotCall(), (err, res) => { + test.error(err); + test.assertNot(res); test.end(); }); }); -metatests.test('find', test => { - const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; - const expected = 15; - const predicate = (item, callback) => - process.nextTick(() => callback(null, item % 3 === 0 && item % 5 === 0)); +metatests.test('find with empty / Set', test => { + const set = new Set(); - metasync.find(data, predicate, (err, result) => { - test.error(err, 'must not return an error'); - test.strictSame(result, expected, `result should be: ${expected}`); + metasync.find(set, test.mustNotCall(), (err, res) => { + test.error(err); + test.assertNot(res); test.end(); }); }); -metatests.test('with empty array', test => { +metatests.test('find with empty / Map', test => { + const map = new Map(); + + metasync.find(map, test.mustNotCall(), (err, res) => { + test.error(err); + test.assertNot(res); + test.end(); + }); +}); + +metatests.test('find with empty / String', test => { + const str = ''; + + metasync.find(str, test.mustNotCall(), (err, res) => { + test.error(err); + test.assertNot(res); + test.end(); + }); +}); + +metatests.test('find without element which is searching', test => { metasync.find( - [], - (el, callback) => process.nextTick(() => callback(null, true)), - (err, result) => { + arr, + (el, callback) => process.nextTick(() => callback(null, el === 20)), + (err, res) => { test.error(err); - test.strictSame(result, undefined); + test.strictSame(res, undefined); test.end(); } ); }); -metatests.test('with array without element which is searching', test => { - const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; +metatests.test('find with error', test => { + const findError = new Error('find error'); + metasync.find( - data, - (el, callback) => process.nextTick(() => callback(null, el === 20)), - (err, result) => { - test.error(err); - test.strictSame(result, undefined); + arr, + (x, callback) => + process.nextTick(() => callback(x === 5 ? findError : null, false)), + (err, res) => { + test.isError(err, findError); + test.assertNot(res); test.end(); } ); diff --git a/test/array.map.js b/test/array.map.js index f059774a..d3c577d1 100644 --- a/test/array.map.js +++ b/test/array.map.js @@ -3,56 +3,133 @@ const metasync = require('..'); const metatests = require('metatests'); -metatests.test('succesfull map', test => { +metatests.test('successful map / Array', test => { const arr = [1, 2, 3]; - const expectedArr = [1, 4, 9]; + const expected = [1, 4, 9]; metasync.map( arr, (x, callback) => process.nextTick(() => callback(null, x * x)), (err, res) => { test.error(err); - test.strictSame(res, expectedArr); + test.strictSame(res, expected); test.end(); } ); }); -metatests.test('map with empty array', test => { - const arr = []; - const expectedArr = []; +metatests.test('successful map / Set', test => { + const set = new Set([1, 2, 3]); + const expected = new Set([1, 4, 9]); metasync.map( - arr, + set, (x, callback) => process.nextTick(() => callback(null, x * x)), (err, res) => { test.error(err); - test.strictSame(res, expectedArr); + test.strictSame([...res], [...expected]); + test.end(); + } + ); +}); + +metatests.test('successful map / Map', test => { + const map = new Map([[1, 'a'], [2, 'b'], [3, 'c']]); + const expected = new Map([['a', 1], ['b', 2], ['c', 3]]); + + metasync.map( + map, + (x, callback) => process.nextTick(() => callback(null, x.reverse())), + (err, res) => { + test.error(err); + test.strictSame([...res], [...expected]); + test.end(); + } + ); +}); + +metatests.test('successful map / String', test => { + const string = 'abcdefgh'; + const expected = 'A,B,C,D,E,F,G,H'; + + metasync.map( + string, + (x, callback) => process.nextTick(() => callback(null, x.toUpperCase())), + (err, res) => { + test.error(err); + test.strictSame([...res], [...expected]); test.end(); } ); }); +metatests.test('map with empty / Array', test => { + const arr = []; + const expected = []; + + metasync.map(arr, test.mustNotCall(), (err, res) => { + test.error(err); + test.strictSame(res, expected); + test.end(); + }); +}); + +metatests.test('map with empty / Set', test => { + const set = new Set(); + const expected = new Set(); + + metasync.map(set, test.mustNotCall(), (err, res) => { + test.error(err); + test.strictSame([...res], [...expected]); + test.end(); + }); +}); + +metatests.test('map with empty / Map', test => { + const map = new Map(); + const expected = new Map(); + + metasync.map(map, test.mustNotCall(), (err, res) => { + test.error(err); + test.strictSame([...res], [...expected]); + test.end(); + }); +}); + +metatests.test('map with empty / String', test => { + const str = ''; + const expected = ''; + + metasync.map(str, test.mustNotCall(), (err, res) => { + test.error(err); + test.strictSame([...res], [...expected]); + test.end(); + }); +}); + metatests.test('map with error', test => { const arr = [1, 2, 3]; - const mapError = new Error('Map error'); - let count = 0; + const mapError = new Error('map error'); metasync.map( arr, (x, callback) => - process.nextTick(() => { - count++; - if (count === 2) { - callback(mapError); - return; - } - callback(null, x * x); - }), + process.nextTick(() => callback(x === 2 ? mapError : null, x * x)), (err, res) => { - test.strictSame(err, mapError); - test.strictSame(res, undefined); + test.isError(err, mapError); + test.assertNot(res); test.end(); } ); }); + +metatests.test('map with not iterable', test => { + const obj = { a: '1', b: '2', c: '3' }; + const expectedError = new TypeError('"items" argument is not iterable'); + + metasync.map(obj, test.mustNotCall(), (err, res) => { + test.isError(err, expectedError); + test.assertNot(res); + test.end(); + }); +}); diff --git a/test/array.reduce.js b/test/array.reduce.js index 21028eac..699a6f7f 100644 --- a/test/array.reduce.js +++ b/test/array.reduce.js @@ -3,66 +3,116 @@ const metasync = require('..'); const metatests = require('metatests'); -metatests.test('reduce with initial', test => { +metatests.test('reduce with initial / Array', test => { const arr = [1, 2, 3, 4, 5]; const initial = 10; - const expectedRes = 25; + const expected = 25; metasync.reduce( arr, (prev, cur, callback) => process.nextTick(() => callback(null, prev + cur)), (err, res) => { test.error(err); - test.strictSame(res, expectedRes); + test.strictSame(res, expected); test.end(); }, initial ); }); -metatests.test('reduce with initial and empty array', test => { - const arr = []; +metatests.test('reduce with initial / Set', test => { + const set = new Set([1, 2, 3, 4, 5]); const initial = 10; - const expectedRes = 10; + const expected = 25; metasync.reduce( - arr, + set, (prev, cur, callback) => process.nextTick(() => callback(null, prev + cur)), (err, res) => { test.error(err); - test.strictSame(res, expectedRes); + test.strictSame(res, expected); test.end(); }, initial ); }); -metatests.test('reduce without initial and with empty array', test => { - const arr = []; - const expectedError = new TypeError( - 'Reduce of empty array with no initial value' +metatests.test('reduce with initial / Map', test => { + const map = new Map([['a', 1], ['b', 2], ['c', 3]]); + const initial = 10; + const expected = 16; + + metasync.reduce( + map, + (prev, cur, callback) => + process.nextTick(() => callback(null, prev + cur[1])), + (err, res) => { + test.error(err); + test.strictSame(res, expected); + test.end(); + }, + initial + ); +}); + +metatests.test('reduce with initial / String', test => { + const str = '12345'; + const initial = 10; + const expected = 25; + + metasync.reduce( + str, + (prev, cur, callback) => + process.nextTick(() => callback(null, prev + +cur)), + (err, res) => { + test.error(err); + test.strictSame(res, expected); + test.end(); + }, + initial ); +}); + +metatests.test('reduce empty items with initial', test => { + const arr = []; + const initial = 10; + const expected = 10; metasync.reduce( arr, - (prev, cur, callback) => process.nextTick(() => callback(null, prev + cur)), + test.mustNotCall(), (err, res) => { - test.strictSame(err, expectedError); - test.strictSame(res, undefined); + test.error(err); + test.strictSame(res, expected); test.end(); - } + }, + initial + ); +}); + +metatests.test('reduce empty items without initial', test => { + const arr = []; + const expectedError = new TypeError( + 'Reduce of consumed async iterator with no initial value' ); + + metasync.reduce(arr, test.mustNotCall(), (err, res) => { + test.isError(err, expectedError); + test.assertNot(res); + test.end(); + }); }); -metatests.test('reduce without initial and with single-element array', test => { +metatests.test('reduce single-element array without initial', test => { const arr = [2]; + const expected = 2; metasync.reduce( arr, (prev, cur, callback) => process.nextTick(() => callback(null, prev + cur)), (err, res) => { - test.strictSame(err, null); - test.strictSame(res, 2); + test.error(err); + test.strictSame(res, expected); test.end(); } ); @@ -70,53 +120,48 @@ metatests.test('reduce without initial and with single-element array', test => { metatests.test('reduce without initial', test => { const arr = [1, 2, 3, 4, 5]; - const expectedRes = 15; + const expected = 15; metasync.reduce( arr, (prev, cur, callback) => process.nextTick(() => callback(null, prev + cur)), (err, res) => { test.error(err); - test.strictSame(res, expectedRes); + test.strictSame(res, expected); test.end(); } ); }); -metatests.test('reduce with asymetric function', test => { - const arr = '10110011'; - const expectedRes = 179; +metatests.test('reduce with asymmetric function', test => { + const str = '10110011'; + const expected = 179; metasync.reduce( - arr, + str, (prev, cur, callback) => process.nextTick(() => callback(null, prev * 2 + +cur)), (err, res) => { test.error(err); - test.strictSame(res, expectedRes); + test.strictSame(res, expected); test.end(); } ); }); metatests.test('reduce with error', test => { - const arr = '10120011'; - const reduceError = new Error('Reduce error'); + const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + const reduceError = new Error('reduce error'); metasync.reduce( arr, (prev, cur, callback) => - process.nextTick(() => { - const digit = +cur; - if (digit > 1) { - callback(reduceError); - return; - } - callback(null, prev * 2 + digit); - }), + process.nextTick(() => + callback(cur === 5 ? reduceError : null, prev + cur) + ), (err, res) => { - test.strictSame(err, reduceError); - test.strictSame(res, undefined); + test.isError(err, reduceError); + test.assertNot(res); test.end(); } ); diff --git a/test/array.reduceRight.js b/test/array.reduceRight.js index a3fe9da9..2cc9be16 100644 --- a/test/array.reduceRight.js +++ b/test/array.reduceRight.js @@ -3,124 +3,152 @@ const metasync = require('..'); const metatests = require('metatests'); -metatests.test('reduceRight with initial', test => { - const arr = [1, 2, 3, 4, 5]; - const initial = 10; - const expectedRes = 25; +metatests.test('reduceRight with initial / Array', test => { + const arr = [1, 2, 3]; + const initial = 5; + const expected = 57; metasync.reduceRight( arr, - (prev, cur, callback) => process.nextTick(() => callback(null, prev + cur)), + (prev, cur, callback) => + process.nextTick(() => callback(null, prev * 2 + cur)), (err, res) => { test.error(err); - test.strictSame(res, expectedRes); + test.strictSame(res, expected); test.end(); }, initial ); }); -metatests.test('reduceRight with initial and empty array', test => { - const arr = []; - const initial = 10; - const expectedRes = 10; +metatests.test('reduceRight with initial / Set', test => { + const set = new Set([1, 2, 3]); + const initial = 5; + const expected = 57; metasync.reduceRight( - arr, - (prev, cur, callback) => process.nextTick(() => callback(null, prev + cur)), + set, + (prev, cur, callback) => + process.nextTick(() => callback(null, prev * 2 + cur)), (err, res) => { test.error(err); - test.strictSame(res, expectedRes); + test.strictSame(res, expected); test.end(); }, initial ); }); -metatests.test('reduceRight without initial and with empty array', test => { - const arr = []; - const expectedError = new TypeError( - 'Reduce of empty array with no initial value' +metatests.test('reduceRight with initial / Map', test => { + const map = new Map([['a', 1], ['b', 2], ['c', 3]]); + const initial = 5; + const expected = 57; + + metasync.reduceRight( + map, + (prev, cur, callback) => + process.nextTick(() => callback(null, prev * 2 + cur[1])), + (err, res) => { + test.error(err); + test.strictSame(res, expected); + test.end(); + }, + initial + ); +}); + +metatests.test('reduceRight with initial / string', test => { + const str = '123'; + const initial = 5; + const expected = 57; + + metasync.reduceRight( + str, + (prev, cur, callback) => + process.nextTick(() => callback(null, prev * 2 + +cur)), + (err, res) => { + test.error(err); + test.strictSame(res, expected); + test.end(); + }, + initial ); +}); + +metatests.test('reduceRight empty items with initial', test => { + const arr = []; + const initial = 10; + const expected = 10; metasync.reduceRight( arr, - (prev, cur, callback) => process.nextTick(() => callback(null, prev + cur)), + test.mustNotCall(), (err, res) => { - test.strictSame(err, expectedError); - test.strictSame(res, undefined); + test.error(err); + test.strictSame(res, expected); test.end(); - } + }, + initial ); }); -metatests.test( - 'reduceRight without initial and with single-element array', - test => { - const arr = [2]; - - metasync.reduceRight( - arr, - (prev, cur, callback) => - process.nextTick(() => callback(null, prev + cur)), - (err, res) => { - test.strictSame(err, null); - test.strictSame(res, 2); - test.end(); - } - ); - } -); +metatests.test('reduceRight empty items without initial', test => { + const arr = []; + const expectedError = new TypeError( + 'Reduce of consumed async iterator with no initial value' + ); + + metasync.reduceRight(arr, test.mustNotCall(), (err, res) => { + test.isError(err, expectedError); + test.assertNot(res); + test.end(); + }); +}); -metatests.test('reduceRight without initial', test => { - const arr = [1, 2, 3, 4, 5]; - const expectedRes = 15; +metatests.test('reduceRight single-element array without initial', test => { + const arr = [2]; + const expected = 2; metasync.reduceRight( arr, (prev, cur, callback) => process.nextTick(() => callback(null, prev + cur)), (err, res) => { test.error(err); - test.strictSame(res, expectedRes); + test.strictSame(res, expected); test.end(); } ); }); -metatests.test('reduceRight with asymetric function', test => { - const arr = '10110011'; - const expectedRes = 205; +metatests.test('reduceRight without initial', test => { + const arr = [1, 1, 0, 1, 0]; + const expected = 11; metasync.reduceRight( arr, (prev, cur, callback) => - process.nextTick(() => callback(null, prev * 2 + +cur)), + process.nextTick(() => callback(null, prev * 2 + cur)), (err, res) => { test.error(err); - test.strictSame(res, expectedRes); + test.strictSame(res, expected); test.end(); } ); }); metatests.test('reduceRight with error', test => { - const arr = '10120011'; - const reduceError = new Error('Reduce error'); + const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + const reduceRightError = new Error('reduceRight error'); - metasync.reduce( + metasync.reduceRight( arr, (prev, cur, callback) => - process.nextTick(() => { - const digit = +cur; - if (digit > 1) { - callback(reduceError); - return; - } - callback(null, prev * 2 + digit); - }), + process.nextTick(() => + callback(cur === 5 ? reduceRightError : null, prev + cur) + ), (err, res) => { - test.strictSame(err, reduceError); - test.strictSame(res, undefined); + test.isError(err, reduceRightError); + test.assertNot(res); test.end(); } ); diff --git a/test/array.series.js b/test/array.series.js index 5171d893..11625c24 100644 --- a/test/array.series.js +++ b/test/array.series.js @@ -3,19 +3,81 @@ const metasync = require('..'); const metatests = require('metatests'); -metatests.test('successful series', test => { - const arr = [1, 2, 3, 4]; - const expectedElements = arr; +metatests.test('successful series / Array', test => { + const arr = [4, 3, 2, 1]; const elements = []; + metasync.series( arr, - (el, callback) => { - elements.push(el); - callback(null); + (x, callback) => { + setTimeout(() => { + elements.push(x); + callback(null); + }, x); }, err => { test.error(err); - test.strictSame(elements, expectedElements); + test.strictSame(elements, arr); + test.end(); + } + ); +}); + +metatests.test('successful series / Set', test => { + const set = new Set([4, 3, 2, 1]); + const elements = []; + + metasync.series( + set, + (x, callback) => { + setTimeout(() => { + elements.push(x); + callback(null); + }, x); + }, + err => { + test.error(err); + test.strictSame(elements, [...set]); + test.end(); + } + ); +}); + +metatests.test('successful series / Map', test => { + const map = new Map([[1, 'a'], [2, 'b'], [3, 'c']]); + const elements = []; + + metasync.series( + map, + (x, callback) => { + setTimeout(() => { + elements.push(x); + callback(null); + }, x); + }, + err => { + test.error(err); + test.strictSame(elements, [...map]); + test.end(); + } + ); +}); + +metatests.test('successful series / String', test => { + const str = '54321'; + const elements = []; + + metasync.series( + str, + (x, callback) => { + setTimeout(() => { + elements.push(x); + callback(null); + }, +x); + }, + err => { + test.error(err); + test.strictSame(elements.join(''), str); test.end(); } ); @@ -28,22 +90,19 @@ metatests.test('series with error', test => { const elements = []; let count = 0; - const seriesError = new Error('seriesError'); + const seriesError = new Error('series error'); metasync.series( arr, - (el, callback) => { - elements.push(el); + (x, callback) => { + elements.push(x); count++; - if (count === expectedElementsCount) { - callback(seriesError); - } else { - callback(null); - } + callback(x === 2 ? seriesError : null); }, err => { - test.strictSame(err, seriesError); + test.isError(err, seriesError); test.strictSame(elements, expectedElements); + test.strictSame(count, expectedElementsCount); test.end(); } ); diff --git a/test/array.some.js b/test/array.some.js index bb12bcea..f2351721 100644 --- a/test/array.some.js +++ b/test/array.some.js @@ -3,48 +3,127 @@ const metasync = require('..'); const metatests = require('metatests'); -metatests.test('successful some', test => { +metatests.test('successful some / Array', test => { const arr = [1, 2, 3]; - const predicate = (x, callback) => callback(null, x % 2 === 0); - metasync.some(arr, predicate, (err, accepted) => { + metasync.some( + arr, + (x, callback) => callback(null, x === 2), + (err, res) => { + test.error(err); + test.strictSame(res, true); + test.end(); + } + ); +}); + +metatests.test('successful some / Set', test => { + const set = new Set([1, 2, 3]); + + metasync.some( + set, + (x, callback) => callback(null, x === 2), + (err, res) => { + test.error(err); + test.strictSame(res, true); + test.end(); + } + ); +}); + +metatests.test('successful some / Map', test => { + const map = new Map([[1, 'a'], [2, 'b'], [3, 'c']]); + + metasync.some( + map, + (x, callback) => callback(null, x[0] === 2), + (err, res) => { + test.error(err); + test.strictSame(res, true); + test.end(); + } + ); +}); + +metatests.test('successful some / String', test => { + const string = 'abcdeeef12343'; + + metasync.some( + string, + (x, callback) => callback(null, x === 'e'), + (err, res) => { + test.error(err); + test.strictSame(res, true); + test.end(); + } + ); +}); + +metatests.test('some with empty / Array', test => { + const arr = []; + + metasync.some(arr, test.mustNotCall(), (err, res) => { test.error(err); - test.strictSame(accepted, true); + test.strictSame(res, false); test.end(); }); }); -metatests.test('failing some', test => { - const arr = [1, 2, 3]; +metatests.test('some with empty / Set', test => { + const set = new Set(); - const predicate = (x, callback) => callback(null, x > 3); - metasync.some(arr, predicate, (err, accepted) => { + metasync.some(set, test.mustNotCall(), (err, res) => { test.error(err); - test.strictSame(accepted, false); + test.strictSame(res, false); test.end(); }); }); -metatests.test('erroneous some', test => { - const arr = [1, 2, 3]; - const someError = new Error('Some error'); +metatests.test('some with empty / Map', test => { + const map = new Map(); - const predicate = (x, callback) => - x % 2 === 0 ? callback(someError) : callback(null, false); - metasync.some(arr, predicate, (err, accepted) => { - test.strictSame(err, someError); - test.strictSame(accepted, undefined); + metasync.some(map, test.mustNotCall(), (err, res) => { + test.error(err); + test.strictSame(res, false); test.end(); }); }); -metatests.test('some with empty array', test => { - const arr = []; +metatests.test('some with empty / String', test => { + const str = ''; - const predicate = (x, callback) => callback(null, x > 3); - metasync.some(arr, predicate, (err, accepted) => { + metasync.some(str, test.mustNotCall(), (err, res) => { test.error(err); - test.strictSame(accepted, false); + test.strictSame(res, false); test.end(); }); }); + +metatests.test('failing some', test => { + const arr = [1, 2, 3]; + + metasync.some( + arr, + (x, callback) => callback(null, x > 3), + (err, res) => { + test.error(err); + test.strictSame(res, false); + test.end(); + } + ); +}); + +metatests.test('some with error', test => { + const arr = [1, 2, 3]; + const someError = new Error('some error'); + + metasync.some( + arr, + (x, callback) => callback(x === 2 ? someError : null, false), + (err, res) => { + test.isError(err, someError); + test.strictSame(res, undefined); + test.end(); + } + ); +}); diff --git a/test/chain.js b/test/chain.js index f6f7a16c..d4d24762 100644 --- a/test/chain.js +++ b/test/chain.js @@ -111,4 +111,4 @@ metatests.test('for chain all methods', test => { test.strictSame(result, false); test.end(); }); -}); +}); \ No newline at end of file diff --git a/test/firstOf.js b/test/firstOf.js index 25fb3864..a4a99aeb 100644 --- a/test/firstOf.js +++ b/test/firstOf.js @@ -7,11 +7,11 @@ metatests.test('firstOf', test => { const returningFnIndex = 2; let dataReturned = false; - const execUnlessDataReturned = data => callback => { + const execUnlessDataReturned = (data, callback) => { if (dataReturned) { callback(null, data); } else { - process.nextTick(execUnlessDataReturned); + process.nextTick(() => execUnlessDataReturned(data, callback)); } }; const makeIFn = i => callback => @@ -21,7 +21,7 @@ metatests.test('firstOf', test => { dataReturned = true; callback(null, iData); } else { - execUnlessDataReturned(iData); + execUnlessDataReturned(iData, callback); } });