eventemitter-ex
Advanced tools
Comparing version 1.0.0 to 1.1.0
@@ -1,262 +0,273 @@ | ||
(function () { | ||
'use strict'; | ||
'use strict'; | ||
var EE = require('events').EventEmitter, | ||
util = require('util'), | ||
assert = require('assert'), | ||
slice = Function.prototype.call.bind(Array.prototype.slice), | ||
concat = Array.prototype.concat; | ||
var EE = require('events').EventEmitter, | ||
util = require('util'), | ||
assert = require('assert'), | ||
slice = Function.prototype.call.bind(Array.prototype.slice), | ||
concat = Array.prototype.concat; | ||
module.exports = EventEmitterEx; | ||
module.exports = EventEmitterEx; | ||
function EventEmitterEx () { | ||
EE.call(this); | ||
this._onAllListeners = []; | ||
} | ||
util.inherits(EventEmitterEx, EE); | ||
function EventEmitterEx () { | ||
EE.call(this); | ||
this._onAllListeners = []; | ||
} | ||
util.inherits(EventEmitterEx, EE); | ||
EventEmitterEx.prototype.onAllExcept = function onAllExcept (/* arguments */) { | ||
var f = arguments[arguments.length - 1]; | ||
assertIsFunction(f); | ||
EventEmitterEx.prototype.onAllExcept = function onAllExcept (/* arguments */) { | ||
var f = arguments[arguments.length - 1]; | ||
assertIsFunction(f); | ||
var except = slice(arguments, 0, -1); | ||
this._onAllListeners.push([f, except]); | ||
var except = slice(arguments, 0, -1); | ||
this._onAllListeners.push([f, except]); | ||
return this; | ||
}; | ||
return this; | ||
}; | ||
EventEmitterEx.prototype.emit = function emit (type /* arguments */) { | ||
var args = arguments, | ||
res = false, | ||
filtered = this.listenersOnAll(type); | ||
EventEmitterEx.prototype.emit = function emit (type /* arguments */) { | ||
var args = arguments, | ||
res = false, | ||
filtered = this.listenersOnAll(type); | ||
if (type !== 'error' || filtered.length === 0 || EE.listenerCount(this, type)) { | ||
res = EventEmitterEx.super_.prototype.emit.apply(this, args); | ||
} | ||
if (type !== 'error' || filtered.length === 0 || EE.listenerCount(this, type)) { | ||
res = EventEmitterEx.super_.prototype.emit.apply(this, args); | ||
} | ||
filtered.forEach(function (listener) { | ||
listener.apply(null, args); | ||
}); | ||
filtered.forEach(function (listener) { | ||
listener.apply(null, args); | ||
}); | ||
return res || filtered.length > 0; | ||
}; | ||
return res || filtered.length > 0; | ||
}; | ||
EventEmitterEx.prototype.emitAsync = function emitAsync (/* arguments */) { | ||
var args = arguments, | ||
self = this; | ||
EventEmitterEx.prototype.emitAsync = function emitAsync (/* arguments */) { | ||
var args = arguments, | ||
self = this; | ||
setImmediate(function () { | ||
self.emit.apply(self, args); | ||
}); | ||
setImmediate(function () { | ||
self.emit.apply(self, args); | ||
}); | ||
return this; | ||
}; | ||
return this; | ||
}; | ||
EventEmitterEx.prototype.startPipeline = function startPipeline (/* arguments */) { | ||
var args = slice(arguments); | ||
args.unshift('end'); | ||
EventEmitterEx.prototype.startPipeline = function startPipeline (/* arguments */) { | ||
var args = slice(arguments); | ||
args.unshift('end'); | ||
return this.emitAsync.apply(this, args); | ||
}; | ||
return this.emitAsync.apply(this, args); | ||
}; | ||
EventEmitterEx.prototype.pipeExcept = function pipeExcept (/* arguments */) { | ||
var ee = arguments[arguments.length - 1]; | ||
if (! (ee instanceof EE)) { | ||
throw new TypeError('Expecting EventEmitter or EventEmitterEx. Given: ' + typeof ee); | ||
} | ||
EventEmitterEx.prototype.pipeExcept = function pipeExcept (/* arguments */) { | ||
var ee = arguments[arguments.length - 1]; | ||
if (! (ee instanceof EE)) { | ||
throw new TypeError('Expecting EventEmitter or EventEmitterEx. Given: ' + typeof ee); | ||
} | ||
var self = this, | ||
except = slice(arguments, 0, -1); | ||
var self = this, | ||
except = slice(arguments, 0, -1); | ||
if (typeof ee.onAllExcept === 'function') { | ||
// This is an EventEmitterEx | ||
except.push(function (/* arguments */) { | ||
self.emit.apply(self, arguments); | ||
if (typeof ee.onAllExcept === 'function') { | ||
// This is an EventEmitterEx | ||
except.push(function (/* arguments */) { | ||
self.emit.apply(self, arguments); | ||
}); | ||
ee.onAllExcept.apply(ee, except); | ||
} else { | ||
// This is a usual EventEmitter | ||
var emit = ee.emit; | ||
if (except.indexOf('error') === -1) { | ||
ee.on('error', function (/* arguments */) { | ||
var args = slice(arguments); | ||
args.unshift('error'); | ||
self.emit.apply(self, args); | ||
}); | ||
ee.onAllExcept.apply(ee, except); | ||
} else { | ||
// This is a usual EventEmitter | ||
var emit = ee.emit; | ||
if (except.indexOf('error') === -1) { | ||
ee.on('error', function (/* arguments */) { | ||
var args = slice(arguments); | ||
args.unshift('error'); | ||
self.emit.apply(self, args); | ||
}); | ||
} | ||
ee.emit = function pipedEmit (type /* arguments */) { | ||
var args = arguments, | ||
res = emit.apply(ee, args); | ||
if (type !== 'error' && except.indexOf(type) === -1) { | ||
res = self.emit.apply(self, args) || res; | ||
} | ||
return res; | ||
}; | ||
} | ||
return this; | ||
}; | ||
ee.emit = function pipedEmit (type /* arguments */) { | ||
var args = arguments, | ||
res = emit.apply(ee, args); | ||
if (type !== 'error' && except.indexOf(type) === -1) { | ||
res = self.emit.apply(self, args) || res; | ||
} | ||
return res; | ||
}; | ||
EventEmitterEx.prototype.map = function map (/* arguments */) { | ||
var eex = new EventEmitterEx(), | ||
mapArgs = slice(arguments); | ||
mapArgs.forEach(assertIsFunction); | ||
eex.pipeExcept('end', this); | ||
this.on('end', function (/* arguments */) { | ||
var result; | ||
try { | ||
var endArgs = arguments; | ||
result = mapArgs.map(function (f) { | ||
var res = f.apply(eex, endArgs); | ||
return Array.isArray(res) ? res : [res]; | ||
}); | ||
// flatten the array | ||
result = concat.apply(['end'], result); | ||
} catch (err) { | ||
eex.emit('error', err); | ||
return; | ||
} | ||
return this; | ||
}; | ||
eex.emit.apply(eex, result); | ||
}); | ||
EventEmitterEx.prototype.map = function map (/* arguments */) { | ||
var eex = new EventEmitterEx(), | ||
mapArgs = slice(arguments); | ||
return eex; | ||
}; | ||
mapArgs.forEach(assertIsFunction); | ||
// Takes zero or more functions and runs them in the same way as #map() but | ||
// also providing a callback as an additional last parameter. After all functions | ||
// had called the callback, results are emitted. | ||
EventEmitterEx.prototype.mapAsync = function mapAsync (/* arguments */) { | ||
var eex = new EventEmitterEx(), | ||
funcs = slice(arguments); | ||
eex.pipeExcept('end', this); | ||
this.on('end', function (/* arguments */) { | ||
var result; | ||
try { | ||
var endArgs = arguments; | ||
result = mapArgs.map(function (f) { | ||
var res = f.apply(eex, endArgs); | ||
return Array.isArray(res) ? res : [res]; | ||
}); | ||
// flatten the array | ||
result = concat.apply(['end'], result); | ||
} catch (err) { | ||
eex.emit('error', err); | ||
return; | ||
} | ||
eex.emit.apply(eex, result); | ||
}); | ||
funcs.forEach(assertIsFunction); | ||
return eex; | ||
}; | ||
eex.pipeExcept('end', this); | ||
this.on('end', function (/* arguments */) { | ||
var result = [], firstError, len = funcs.length, lenLoop = len; | ||
var endArgs = slice(arguments), | ||
endArgsLen = endArgs.length; | ||
// Takes zero or more functions and runs them in the same way as #map() but | ||
// also providing a callback as an additional last parameter. After all functions | ||
// had called the callback, results are emitted. | ||
EventEmitterEx.prototype.mapAsync = function mapAsync (/* arguments */) { | ||
var eex = new EventEmitterEx(), | ||
funcs = slice(arguments); | ||
for (var i = 0; i < lenLoop; i++) { | ||
endArgs[endArgsLen] = callback.bind(null, i); | ||
funcs[i].apply(eex, endArgs); | ||
} | ||
funcs.forEach(assertIsFunction); | ||
function callback (position, err/* arguments */) { | ||
assert(! Array.isArray(result[position]), | ||
'Callback called more than once by function at position ' + position + ' (0-based)'); | ||
eex.pipeExcept('end', this); | ||
this.on('end', function (/* arguments */) { | ||
var result = [], firstError, len = funcs.length, lenLoop = len; | ||
var endArgs = slice(arguments), | ||
endArgsLen = endArgs.length; | ||
for (var i = 0; i < lenLoop; i++) { | ||
endArgs[endArgsLen] = callback.bind(null, i); | ||
funcs[i].apply(eex, endArgs); | ||
if (err === null) { | ||
result[position] = slice(arguments, 2); | ||
} else { | ||
if (! firstError) firstError = slice(arguments, 1); | ||
result[position] = []; | ||
} | ||
function callback (position, err/* arguments */) { | ||
assert(! Array.isArray(result[position]), | ||
'Callback called more than once by function at position ' + position + ' (0-based)'); | ||
if (err === null) { | ||
result[position] = slice(arguments, 2); | ||
len--; | ||
if (! len) { | ||
if (firstError) { | ||
firstError.unshift('error'); | ||
eex.emit.apply(eex, firstError); | ||
} else { | ||
if (! firstError) firstError = slice(arguments, 1); | ||
result[position] = []; | ||
// flatten the array | ||
eex.emit.apply(eex, concat.apply(['end'], result)); | ||
} | ||
len--; | ||
if (! len) { | ||
if (firstError) { | ||
firstError.unshift('error'); | ||
eex.emit.apply(eex, firstError); | ||
} else { | ||
// flatten the array | ||
eex.emit.apply(eex, concat.apply(['end'], result)); | ||
} | ||
} | ||
} | ||
}); | ||
} | ||
}); | ||
return eex; | ||
}; | ||
return eex; | ||
}; | ||
EventEmitterEx.prototype.flatMap = function flatMap (/* arguments */) { | ||
var eex = new EventEmitterEx(), | ||
funcs = slice(arguments); | ||
EventEmitterEx.prototype.flatMap = function flatMap (/* arguments */) { | ||
var eex = new EventEmitterEx(), | ||
funcs = slice(arguments); | ||
funcs.forEach(assertIsFunction); | ||
funcs.forEach(assertIsFunction); | ||
eex.pipeExcept('end', this); | ||
this.on('end', function (/* arguments */) { | ||
var result = [], firstError, len = funcs.length, lenLoop = len; | ||
eex.pipeExcept('end', this); | ||
this.on('end', function (/* arguments */) { | ||
var result = [], firstError, len = funcs.length, lenLoop = len; | ||
for (var i = 0; i < lenLoop; i++) { | ||
var e = funcs[i].apply(eex, arguments); | ||
eex.pipeExcept('end', 'error', e); | ||
e.on('end', endListener.bind(null, i)); | ||
e.on('error', errorListener.bind(null, i)); | ||
} | ||
for (var i = 0; i < lenLoop; i++) { | ||
var e = funcs[i].apply(eex, arguments); | ||
eex.pipeExcept('end', 'error', e); | ||
e.on('end', endListener.bind(null, i)); | ||
e.on('error', errorListener.bind(null, i)); | ||
} | ||
function checkUsage (position) { | ||
assert(! Array.isArray(result[position]), | ||
'end/error (or both) event emitted more than once by emitter at position ' + position + ' (0-based)'); | ||
} | ||
function checkUsage (position) { | ||
assert(! Array.isArray(result[position]), | ||
'end/error (or both) event emitted more than once by emitter at position ' + position + ' (0-based)'); | ||
} | ||
function endListener (position/* arguments */) { | ||
checkUsage(position); | ||
result[position] = slice(arguments, 1); | ||
maybeNext(); | ||
} | ||
function endListener (position/* arguments */) { | ||
checkUsage(position); | ||
result[position] = slice(arguments, 1); | ||
maybeNext(); | ||
} | ||
function errorListener (position, err) { | ||
checkUsage(position); | ||
firstError = firstError || err; | ||
result[position] = []; | ||
maybeNext(); | ||
} | ||
function errorListener (position, err) { | ||
checkUsage(position); | ||
firstError = firstError || err; | ||
result[position] = []; | ||
maybeNext(); | ||
} | ||
function maybeNext () { | ||
len--; | ||
if (! len) { | ||
if (firstError) { | ||
eex.emit('error', firstError); | ||
} else { | ||
// flatten the array | ||
eex.emit.apply(eex, concat.apply(['end'], result)); | ||
} | ||
function maybeNext () { | ||
len--; | ||
if (! len) { | ||
if (firstError) { | ||
eex.emit('error', firstError); | ||
} else { | ||
// flatten the array | ||
eex.emit.apply(eex, concat.apply(['end'], result)); | ||
} | ||
} | ||
} | ||
}); | ||
return eex; | ||
}; | ||
EventEmitterEx.prototype.listenersOnAll = function listenersOnAll (type) { | ||
return this._onAllListeners | ||
.filter(function (listener) { | ||
return listener[1].indexOf(type) === -1; | ||
}) | ||
.map(function (listener) { | ||
return listener[0]; | ||
}); | ||
}; | ||
return eex; | ||
}; | ||
EventEmitterEx.prototype.listenerCountOnAll = function listenerCountOnAll (type) { | ||
return this.listenersOnAll(type).length; | ||
}; | ||
EventEmitterEx.prototype.listenersOnAll = function listenersOnAll (type) { | ||
return this._onAllListeners | ||
.filter(function (listener) { | ||
return listener[1].indexOf(type) === -1; | ||
}) | ||
.map(function (listener) { | ||
return listener[0]; | ||
}); | ||
}; | ||
EventEmitterEx.prototype.asPromise = function asPromise () { | ||
return EventEmitterEx.asPromise(this); | ||
}; | ||
EventEmitterEx.prototype.listenerCountOnAll = function listenerCountOnAll (type) { | ||
return this.listenersOnAll(type).length; | ||
}; | ||
EventEmitterEx.listenerCount = function listenerCount (eex, type) { | ||
return (typeof eex.listenerCountOnAll === 'function' ? eex.listenerCountOnAll(type) : 0) + | ||
EE.listenerCount(eex, type); | ||
}; | ||
EventEmitterEx.listenerCount = function listenerCount (eex, type) { | ||
return (typeof eex.listenerCountOnAll === 'function' ? eex.listenerCountOnAll(type) : 0) + | ||
EE.listenerCount(eex, type); | ||
}; | ||
// Should NOT emit exceptions from function as errors. | ||
// Code should not catch exceptions, thrown by listeners for 'end' event because | ||
// emitting 'error' in that case is wrong - it is the callback that is failed, not the original | ||
// operation. Also calling more than one 'final' callback is wrong. | ||
EventEmitterEx.startAsync = function startAsync (f) { | ||
assertIsFunction(f); | ||
// Should NOT emit exceptions from function as errors. | ||
// Code should not catch exceptions, thrown by listeners for 'end' event because | ||
// emitting 'error' in that case is wrong - it is the callback that is failed, not the original | ||
// operation. Also calling more than one 'final' callback is wrong. | ||
EventEmitterEx.startAsync = function startAsync (f) { | ||
assertIsFunction(f); | ||
var r = new EventEmitterEx(); | ||
var r = new EventEmitterEx(); | ||
setImmediate(f.bind(null, r)); | ||
setImmediate(f.bind(null, r)); | ||
return r; | ||
}; | ||
return r; | ||
}; | ||
EventEmitterEx.asPromise = function asPromise (emitter) { | ||
return new Promise(function (resolve, reject) { | ||
emitter.on('error', reject); | ||
emitter.on('end', function (value) { | ||
// we only consume the first argument | ||
resolve(value); | ||
}); | ||
}); | ||
}; | ||
function assertIsFunction (f) { | ||
if (typeof f !== 'function') | ||
throw new TypeError('Argument must be a function. Got ' + typeof f); | ||
} | ||
})(); | ||
function assertIsFunction (f) { | ||
if (typeof f !== 'function') | ||
throw new TypeError('Argument must be a function. Got ' + typeof f); | ||
} |
{ | ||
"name": "eventemitter-ex", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"description": "EventEmitter extensions", | ||
@@ -9,3 +9,3 @@ "main": "EventEmitterEx.js", | ||
"test": "jshint --exclude-path=.gitignore . && mocha test", | ||
"coveralls": "istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | coveralls && rm -rf ./coverage" | ||
"coveralls": "istanbul cover _mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | coveralls && rm -rf ./coverage" | ||
}, | ||
@@ -12,0 +12,0 @@ "repository": { |
@@ -1,726 +0,716 @@ | ||
(function () { | ||
'use strict'; | ||
/*jshint expr: true*/ | ||
'use strict'; | ||
/*jshint expr: true*/ | ||
var EventEmitter = require('events').EventEmitter, | ||
EEX = require('../EventEmitterEx'), | ||
emitter; | ||
var EventEmitter = require('events').EventEmitter, | ||
EEX = require('../EventEmitterEx'), | ||
emitter; | ||
beforeEach(function () { | ||
emitter = new EEX(); | ||
}); | ||
beforeEach(function () { | ||
emitter = new EEX(); | ||
}); | ||
describe('EventEmitterEx', function () { | ||
describe('EventEmitterEx', function () { | ||
describe('#onAllExcept()', function () { | ||
describe('#startAsync()', function () { | ||
it('should return self', function () { | ||
emitter.onAllExcept('data', function () {}).should.be.equal(emitter); | ||
it('should throw exception on non-function arguments', function () { | ||
expect(function () { | ||
EEX.startAsync(42); | ||
}).to.throw(TypeError, /Argument must be a function/); | ||
}); | ||
it('should call function with a new emitter', function (done) { | ||
var eexResult = EEX.startAsync(function (eex) { | ||
eex.should.be.equal(eexResult); | ||
done(); | ||
}); | ||
eexResult.should.be.instanceOf(EEX); | ||
}); | ||
describe('#startAsync()', function () { | ||
}); | ||
it('should throw exception on non-function arguments', function () { | ||
expect(function () { | ||
EEX.startAsync(42); | ||
}).to.throw(TypeError, /Argument must be a function/); | ||
describe('#asPromise()', function () { | ||
var i = 0; | ||
[EventEmitter, EEX].forEach(function (SourceType) { | ||
i++; | ||
it('should return a Promise that is bound to end event #' + i, function (done) { | ||
var e = new SourceType(); | ||
var p = EEX.asPromise(e); | ||
var A = 42; | ||
p.then(function (value) { | ||
value.should.equals(A); | ||
done(); | ||
}, done); | ||
setImmediate(e.emit.bind(e, 'end', A)); | ||
}); | ||
it('should call function with a new emitter', function (done) { | ||
var eexResult = EEX.startAsync(function (eex) { | ||
eex.should.be.equal(eexResult); | ||
it('should return a Promise that is bound to error event #' + i, function (done) { | ||
var e = new SourceType(); | ||
var p = EEX.asPromise(e); | ||
var ERR = new Error('Something fishy just happened!'); | ||
p.then(function () { | ||
done(new Error('What?')); | ||
}, function (err) { | ||
err.should.equals(ERR); | ||
done(); | ||
}); | ||
eexResult.should.be.instanceOf(EEX); | ||
setImmediate(e.emit.bind(e, 'error', ERR)); | ||
}); | ||
}); | ||
}); | ||
describe('#emitAsync()', function () { | ||
}); | ||
it('should call emit() asynchronously', function (done) { | ||
var spyEnd = sinon.spy(); | ||
describe('instance', function () { | ||
emitter | ||
.on('error', done) | ||
.on('end1', spyEnd) | ||
.on('end', function () { | ||
spyEnd.calledWithExactly(1, 2, 3).should.be.true; | ||
done(); | ||
}) | ||
.emitAsync('end1', 1, 2, 3) | ||
.emitAsync('end') | ||
.should.be.equal(emitter); | ||
describe('#onAllExcept()', function () { | ||
spyEnd.callCount.should.be.equal(0); | ||
}); | ||
it('should return self', function () { | ||
emitter.onAllExcept('data', function () {}).should.be.equal(emitter); | ||
}); | ||
it('should return self', function (done) { | ||
emitter | ||
.on('error', done) | ||
.on('end', done) | ||
.emitAsync('end').should.be.equal(emitter); | ||
}); | ||
}); | ||
}); | ||
describe('#emitAsync()', function () { | ||
describe('#startPipeline()', function () { | ||
it('should call emit() asynchronously', function (done) { | ||
var spyEnd = sinon.spy(); | ||
it('should call emitAsync() with "end" event type', function () { | ||
var A = 42, B = 17, mockEmitter = sinon.mock(emitter); | ||
emitter | ||
.on('error', done) | ||
.on('end1', spyEnd) | ||
.on('end', function () { | ||
spyEnd.calledWithExactly(1, 2, 3).should.be.true; | ||
done(); | ||
}) | ||
.emitAsync('end1', 1, 2, 3) | ||
.emitAsync('end') | ||
.should.be.equal(emitter); | ||
mockEmitter | ||
.expects('emitAsync') | ||
.withExactArgs('end', A, B); | ||
spyEnd.callCount.should.be.equal(0); | ||
}); | ||
emitter.startPipeline(A, B); | ||
}); | ||
it('should return self', function (done) { | ||
emitter | ||
.on('error', done) | ||
.on('end', done) | ||
.emitAsync('end').should.be.equal(emitter); | ||
}); | ||
it('should return self', function () { | ||
var mockEmitter = sinon.mock(emitter); | ||
}); | ||
mockEmitter | ||
.expects('emitAsync') | ||
.withExactArgs('end') | ||
.returnsThis(); | ||
describe('#startPipeline()', function () { | ||
emitter.startPipeline().should.be.equal(emitter); | ||
}); | ||
it('should call emitAsync() with "end" event type', function () { | ||
var A = 42, B = 17, mockEmitter = sinon.mock(emitter); | ||
mockEmitter | ||
.expects('emitAsync') | ||
.withExactArgs('end', A, B); | ||
emitter.startPipeline(A, B); | ||
}); | ||
describe('#pipeExcept()', function () { | ||
it('should return self', function () { | ||
var mockEmitter = sinon.mock(emitter); | ||
it('should throw on invalid argument', function () { | ||
expect(function () { | ||
emitter.pipeExcept({}); | ||
}).to.throw(TypeError, /Expecting EventEmitter or EventEmitterEx/); | ||
}); | ||
mockEmitter | ||
.expects('emitAsync') | ||
.withExactArgs('end') | ||
.returnsThis(); | ||
var i = 0; | ||
[EventEmitter, EEX].forEach(function (SourceType) { | ||
i++; | ||
var source; | ||
emitter.startPipeline().should.be.equal(emitter); | ||
}); | ||
beforeEach(function () { | ||
source = new SourceType(); | ||
}); | ||
}); | ||
it('should return self #' + i, function () { | ||
emitter.pipeExcept(source).should.be.equal(emitter); | ||
}); | ||
describe('#pipeExcept()', function () { | ||
it('should call corresponding callbacks on original emitter #' + i, function () { | ||
var spyA = sinon.spy(), | ||
spyError1 = sinon.spy(), | ||
spyError2 = sinon.spy(), | ||
spyEnd = sinon.spy(), | ||
err = new Error('123'); | ||
it('should throw on invalid argument', function () { | ||
expect(function () { | ||
emitter.pipeExcept({}); | ||
}).to.throw(TypeError, /Expecting EventEmitter or EventEmitterEx/); | ||
}); | ||
source.on('a', spyA); | ||
source.on('end', spyEnd); | ||
source.on('error', spyError1); | ||
var i = 0; | ||
[EventEmitter, EEX].forEach(function (SourceType) { | ||
i++; | ||
var source; | ||
emitter.pipeExcept('end', source); | ||
beforeEach(function () { | ||
source = new SourceType(); | ||
}); | ||
emitter.on('error', spyError2); | ||
it('should return self #' + i, function () { | ||
emitter.pipeExcept(source).should.be.equal(emitter); | ||
}); | ||
source.emit('a', 'a1').should.be.true; | ||
source.emit('end', 1, 2, 3).should.be.true; | ||
source.emit('error', err).should.be.true; | ||
it('should call corresponding callbacks on original emitter #' + i, function () { | ||
var spyA = sinon.spy(), | ||
spyError1 = sinon.spy(), | ||
spyError2 = sinon.spy(), | ||
spyEnd = sinon.spy(), | ||
err = new Error('123'); | ||
spyA.calledWith('a1').should.be.true; | ||
spyEnd.calledWith(1, 2, 3).should.be.true; | ||
spyError1.calledWith(err).should.be.true; | ||
spyError2.calledWith(err).should.be.true; | ||
source.on('a', spyA); | ||
source.on('end', spyEnd); | ||
source.on('error', spyError1); | ||
spyEnd.calledAfter(spyA).should.be.true; | ||
spyError1.calledAfter(spyEnd).should.be.true; | ||
spyError2.calledAfter(spyError1).should.be.true; | ||
}); | ||
emitter.pipeExcept('end', source); | ||
it('should pipe all events except specified #' + i, function () { | ||
var spyA = sinon.spy(), | ||
spyError1 = sinon.spy(), | ||
spyError2 = sinon.spy(), | ||
spyEnd = sinon.spy(), | ||
err = new Error('123'); | ||
emitter.on('error', spyError2); | ||
source.on('error', spyError1); | ||
source.emit('a', 'a1').should.be.true; | ||
source.emit('end', 1, 2, 3).should.be.true; | ||
source.emit('error', err).should.be.true; | ||
emitter.pipeExcept('end', 'x', source); | ||
spyA.calledWith('a1').should.be.true; | ||
spyEnd.calledWith(1, 2, 3).should.be.true; | ||
spyError1.calledWith(err).should.be.true; | ||
spyError2.calledWith(err).should.be.true; | ||
emitter.on('a', spyA); | ||
emitter.on('end', spyEnd); | ||
emitter.on('error', spyError2); | ||
spyEnd.calledAfter(spyA).should.be.true; | ||
spyError1.calledAfter(spyEnd).should.be.true; | ||
spyError2.calledAfter(spyError1).should.be.true; | ||
}); | ||
source.emit('a', 'a1').should.be.true; | ||
source.emit('end', 1, 2, 3).should.be.false; | ||
source.emit('error', err).should.be.true; | ||
it('should pipe all events except specified #' + i, function () { | ||
var spyA = sinon.spy(), | ||
spyError1 = sinon.spy(), | ||
spyError2 = sinon.spy(), | ||
spyEnd = sinon.spy(), | ||
err = new Error('123'); | ||
spyA.calledWith('a1').should.be.true; | ||
spyEnd.calledWith(1, 2, 3).should.be.false; | ||
spyError1.calledWith(err).should.be.true; | ||
spyError2.calledWith(err).should.be.true; | ||
source.on('error', spyError1); | ||
spyError1.calledAfter(spyA).should.be.true; | ||
spyError2.calledAfter(spyError1).should.be.true; | ||
}); | ||
emitter.pipeExcept('end', 'x', source); | ||
it('should not throw on unhandled error on original emitter #' + i, function () { | ||
var spyError = sinon.spy(), | ||
err = new Error('123'); | ||
emitter.on('a', spyA); | ||
emitter.on('end', spyEnd); | ||
emitter.on('error', spyError2); | ||
emitter.pipeExcept(source); | ||
source.emit('a', 'a1').should.be.true; | ||
source.emit('end', 1, 2, 3).should.be.false; | ||
source.emit('error', err).should.be.true; | ||
emitter.on('error', spyError); | ||
spyA.calledWith('a1').should.be.true; | ||
spyEnd.calledWith(1, 2, 3).should.be.false; | ||
spyError1.calledWith(err).should.be.true; | ||
spyError2.calledWith(err).should.be.true; | ||
source.emit('error', err).should.be.true; | ||
spyError1.calledAfter(spyA).should.be.true; | ||
spyError2.calledAfter(spyError1).should.be.true; | ||
}); | ||
spyError.calledWith(err).should.be.true; | ||
}); | ||
it('should not throw on unhandled error on original emitter #' + i, function () { | ||
var spyError = sinon.spy(), | ||
err = new Error('123'); | ||
it('should throw on unhandled error on piped emitter #' + i, function () { | ||
var spyError = sinon.spy(), | ||
err = new Error('123'); | ||
emitter.pipeExcept(source); | ||
source.on('error', spyError); | ||
emitter.on('error', spyError); | ||
emitter.pipeExcept(source); | ||
source.emit('error', err).should.be.true; | ||
expect(function () { | ||
source.emit('error', err); | ||
}).to.throw(err); | ||
spyError.calledWith(err).should.be.true; | ||
}); | ||
spyError.calledWith(err).should.be.true; | ||
}); | ||
it('should throw on unhandled error on piped emitter #' + i, function () { | ||
var spyError = sinon.spy(), | ||
err = new Error('123'); | ||
it('should not emit error if it is excepted #' + i, function () { | ||
var spyError1 = sinon.spy(), | ||
spyError2 = sinon.spy(), | ||
err = new Error('123'); | ||
source.on('error', spyError); | ||
emitter.pipeExcept('error', source); | ||
emitter.pipeExcept(source); | ||
source.on('error', spyError1); | ||
emitter.on('error', spyError2); | ||
expect(function () { | ||
source.emit('error', err); | ||
}).to.throw(err); | ||
source.emit('error', err).should.be.true; | ||
spyError.calledWith(err).should.be.true; | ||
}); | ||
spyError1.calledWith(err).should.be.true; | ||
spyError2.callCount.should.be.equal(0); | ||
}); | ||
it('should not emit error if it is excepted #' + i, function () { | ||
var spyError1 = sinon.spy(), | ||
spyError2 = sinon.spy(), | ||
err = new Error('123'); | ||
it('should not throw error if it is excepted #' + i, function () { | ||
var spyError = sinon.spy(), | ||
err = new Error('123'); | ||
emitter.pipeExcept('error', source); | ||
emitter.pipeExcept('error', source); | ||
source.on('error', spyError1); | ||
emitter.on('error', spyError2); | ||
source.on('error', spyError); | ||
source.emit('error', err).should.be.true; | ||
source.emit('error', err).should.be.true; | ||
spyError1.calledWith(err).should.be.true; | ||
spyError2.callCount.should.be.equal(0); | ||
}); | ||
spyError.calledWith(err).should.be.true; | ||
}); | ||
it('should not throw error if it is excepted #' + i, function () { | ||
var spyError = sinon.spy(), | ||
err = new Error('123'); | ||
it('should throw on unhandled errors #' + i, function () { | ||
var err = new Error('123'); | ||
emitter.pipeExcept('error', source); | ||
emitter.pipeExcept(source); | ||
source.on('error', spyError); | ||
expect(function () { | ||
source.emit('error', err); | ||
}).to.throw(err); | ||
}); | ||
source.emit('error', err).should.be.true; | ||
var j = 0; | ||
[EventEmitter, EEX].forEach(function (SourceType2) { | ||
j++; | ||
it('should pipe events from multiple sources #' + i + ':' + j, function () { | ||
var spyError = sinon.spy(), | ||
spyEnd = sinon.spy(), | ||
err = new Error('123'), | ||
source2 = new SourceType2(); | ||
spyError.calledWith(err).should.be.true; | ||
}); | ||
emitter.pipeExcept(source); | ||
emitter.pipeExcept(source2); | ||
emitter.on('error', spyError); | ||
emitter.on('end', spyEnd); | ||
it('should throw on unhandled errors #' + i, function () { | ||
var err = new Error('123'); | ||
source.emit('error', err).should.be.true; | ||
source2.emit('end', 1, 2, 3).should.be.true; | ||
emitter.pipeExcept(source); | ||
spyError.calledWith(err).should.be.true; | ||
spyEnd.calledWith(1, 2, 3).should.be.true; | ||
expect(function () { | ||
source.emit('error', err); | ||
}).to.throw(err); | ||
}); | ||
spyEnd.calledAfter(spyError).should.be.true; | ||
}); | ||
}); | ||
it('should support multiple pipes from single source #' + i, function () { | ||
var j = 0; | ||
[EventEmitter, EEX].forEach(function (SourceType2) { | ||
j++; | ||
it('should pipe events from multiple sources #' + i + ':' + j, function () { | ||
var spyError = sinon.spy(), | ||
spyEnd = sinon.spy(), | ||
spyError2 = sinon.spy(), | ||
spyEnd2 = sinon.spy(), | ||
err = new Error('123'), | ||
emitter2 = new EEX(); | ||
source2 = new SourceType2(); | ||
emitter.pipeExcept(source); | ||
emitter2.pipeExcept(source); | ||
emitter.pipeExcept(source2); | ||
emitter.on('error', spyError); | ||
emitter.on('end', spyEnd); | ||
emitter2.on('error', spyError2); | ||
emitter2.on('end', spyEnd2); | ||
source.emit('error', err).should.be.true; | ||
source.emit('end', 1, 2, 3).should.be.true; | ||
source2.emit('end', 1, 2, 3).should.be.true; | ||
spyError.calledWith(err).should.be.true; | ||
spyEnd.calledWith(1, 2, 3).should.be.true; | ||
spyError2.calledWith(err).should.be.true; | ||
spyEnd2.calledWith(1, 2, 3).should.be.true; | ||
spyError2.calledAfter(spyError).should.be.true; | ||
spyEnd2.calledAfter(spyEnd).should.be.true; | ||
spyEnd.calledAfter(spyError).should.be.true; | ||
}); | ||
}); | ||
}); | ||
it('should support multiple pipes from single source #' + i, function () { | ||
var spyError = sinon.spy(), | ||
spyEnd = sinon.spy(), | ||
spyError2 = sinon.spy(), | ||
spyEnd2 = sinon.spy(), | ||
err = new Error('123'), | ||
emitter2 = new EEX(); | ||
describe('#map()', function () { | ||
emitter.pipeExcept(source); | ||
emitter2.pipeExcept(source); | ||
emitter.on('error', spyError); | ||
emitter.on('end', spyEnd); | ||
emitter2.on('error', spyError2); | ||
emitter2.on('end', spyEnd2); | ||
it('should set this to emitter', function (done) { | ||
var mapped = emitter.map(function () { return this; }); | ||
mapped | ||
.on('end', function (result) { | ||
result.should.be.equal(mapped); | ||
done(); | ||
}) | ||
.on('error', done); | ||
emitter.emit('end'); | ||
}); | ||
source.emit('error', err).should.be.true; | ||
source.emit('end', 1, 2, 3).should.be.true; | ||
it('should support returning multiple values as array', function (done) { | ||
var A = 1, B = 2; | ||
var mapped = emitter.map(function () { return [A, B]; }); | ||
mapped | ||
.on('end', function (a, b) { | ||
a.should.be.equal(A); | ||
b.should.be.equal(B); | ||
done(); | ||
}) | ||
.on('error', done); | ||
emitter.emit('end'); | ||
}); | ||
spyError.calledWith(err).should.be.true; | ||
spyEnd.calledWith(1, 2, 3).should.be.true; | ||
spyError2.calledWith(err).should.be.true; | ||
spyEnd2.calledWith(1, 2, 3).should.be.true; | ||
it('should emit exceptions as error', function (done) { | ||
var err = new Error('234'); | ||
emitter | ||
.map(function () { throw err; }) | ||
.on('end', function () { | ||
done(new Error('Expecting error')); | ||
}) | ||
.on('error', function (error) { | ||
error.should.be.equal(err); | ||
done(); | ||
}); | ||
emitter.emit('end'); | ||
spyError2.calledAfter(spyError).should.be.true; | ||
spyEnd2.calledAfter(spyEnd).should.be.true; | ||
}); | ||
}); | ||
it('should throw exception on non-function arguments', function () { | ||
expect(function () { | ||
emitter.map(function () {}, 2); | ||
}).to.throw(TypeError, /Argument must be a function/); | ||
}); | ||
}); | ||
it('should call each map function and return results in order', function (done) { | ||
var f1 = function (a1, a2) { | ||
return a1 + a2; | ||
}; | ||
var f2 = function (a1, a2) { | ||
return a1 * a2; | ||
}; | ||
describe('#map()', function () { | ||
var r = emitter.map(f1, f2); | ||
r.on('end', function (r1, r2) { | ||
r1.should.be.equal(6); | ||
r2.should.be.equal(8); | ||
it('should set this to emitter', function (done) { | ||
var mapped = emitter.map(function () { return this; }); | ||
mapped | ||
.on('end', function (result) { | ||
result.should.be.equal(mapped); | ||
done(); | ||
}); | ||
emitter.emit('end', 4, 2); | ||
}); | ||
}) | ||
.on('error', done); | ||
emitter.emit('end'); | ||
}); | ||
describe('#mapAsync()', function () { | ||
it('should emit error if no arguments passed to callback', function (done) { | ||
var mapped = emitter.mapAsync(function (cb) { | ||
cb(); | ||
}); | ||
mapped.on('error', function () { | ||
done(); | ||
}); | ||
mapped.on('end', function () { throw new Error('Should not emit end'); }); | ||
emitter.emit('end'); | ||
}); | ||
// this is to check type strictness of the err check | ||
it('should emit error on false as first argument to callback', function (done) { | ||
var A = 1, B = 40, C = 2; | ||
var mapped = emitter.mapAsync(function (cb) { | ||
cb(false, A, B, C); | ||
}); | ||
mapped.on('error', function (err, a, b, c) { | ||
err.should.be.false; | ||
it('should support returning multiple values as array', function (done) { | ||
var A = 1, B = 2; | ||
var mapped = emitter.map(function () { return [A, B]; }); | ||
mapped | ||
.on('end', function (a, b) { | ||
a.should.be.equal(A); | ||
b.should.be.equal(B); | ||
c.should.be.equal(C); | ||
done(); | ||
}); | ||
mapped.on('end', function () { throw new Error('Should not emit end'); }); | ||
emitter.emit('end'); | ||
}); | ||
}) | ||
.on('error', done); | ||
emitter.emit('end'); | ||
}); | ||
// this is to check type strictness of the err check | ||
it('should emit error on true as first argument to callback', function (done) { | ||
var A = 1, B = 40, C = 2; | ||
var mapped = emitter.mapAsync(function (cb) { | ||
cb(true, A, B, C); | ||
}); | ||
mapped.on('error', function (err, a, b, c) { | ||
err.should.be.true; | ||
a.should.be.equal(A); | ||
b.should.be.equal(B); | ||
c.should.be.equal(C); | ||
it('should emit exceptions as error', function (done) { | ||
var err = new Error('234'); | ||
emitter | ||
.map(function () { throw err; }) | ||
.on('end', function () { | ||
done(new Error('Expecting error')); | ||
}) | ||
.on('error', function (error) { | ||
error.should.be.equal(err); | ||
done(); | ||
}); | ||
mapped.on('end', function () { throw new Error('Should not emit end'); }); | ||
emitter.emit('end'); | ||
}); | ||
emitter.emit('end'); | ||
}); | ||
// this is to check type strictness of the err check | ||
it('should emit end on null as first argument to callback', function (done) { | ||
var A = 1, B = 40, C = 2; | ||
var mapped = emitter.mapAsync(function (cb) { | ||
cb(null, A, B, C); | ||
}); | ||
mapped.on('error', function () { throw new Error('Should not emit error'); }); | ||
mapped.on('end', function (a, b, c) { | ||
a.should.be.equal(A); | ||
b.should.be.equal(B); | ||
c.should.be.equal(C); | ||
done(); | ||
}); | ||
emitter.emit('end'); | ||
}); | ||
it('should throw exception on non-function arguments', function () { | ||
expect(function () { | ||
emitter.map(function () {}, 2); | ||
}).to.throw(TypeError, /Argument must be a function/); | ||
}); | ||
it('should throw if callback called too many times', function (done) { | ||
var mapped = emitter.mapAsync(function (cb) { | ||
cb(null); | ||
expect(function () { | ||
cb(null); | ||
}).to.throw(Error, 'Callback called more than once by function at position 0 (0-based)'); | ||
done(); | ||
}); | ||
mapped.on('error', done); | ||
emitter.emit('end'); | ||
}); | ||
it('should call each map function and return results in order', function (done) { | ||
var f1 = function (a1, a2) { | ||
return a1 + a2; | ||
}; | ||
var f2 = function (a1, a2) { | ||
return a1 * a2; | ||
}; | ||
it('should throw if callback called too many times (with misbehaving callback)', function (done) { | ||
var mapped = emitter.mapAsync(function () {/* bad function, does not call cb() */}, function (cb) { | ||
cb(null); | ||
expect(function () { | ||
cb(null); | ||
}).to.throw(Error, 'Callback called more than once by function at position 1 (0-based)'); | ||
done(); | ||
}); | ||
mapped.on('error', done); | ||
emitter.emit('end'); | ||
var r = emitter.map(f1, f2); | ||
r.on('end', function (r1, r2) { | ||
r1.should.be.equal(6); | ||
r2.should.be.equal(8); | ||
done(); | ||
}); | ||
emitter.emit('end', 4, 2); | ||
}); | ||
it('should support synchronous call of callback', function (done) { | ||
var A = 42; | ||
var mapped = emitter.mapAsync(function (param, cb) { cb(null, param); }); | ||
mapped | ||
.on('end', function (result) { | ||
result.should.be.equal(A); | ||
done(); | ||
}) | ||
.on('error', done); | ||
emitter.emit('end', A); | ||
}); | ||
describe('#mapAsync()', function () { | ||
it('should emit error if no arguments passed to callback', function (done) { | ||
var mapped = emitter.mapAsync(function (cb) { | ||
cb(); | ||
}); | ||
mapped.on('error', function () { | ||
done(); | ||
}); | ||
mapped.on('end', function () { throw new Error('Should not emit end'); }); | ||
emitter.emit('end'); | ||
}); | ||
it('should support asynchronous call of callback', function (done) { | ||
var A = 42; | ||
var mapped = emitter.mapAsync(function (param, cb) { setImmediate(cb.bind(null, null, param)); }); | ||
mapped | ||
.on('end', function (result) { | ||
result.should.be.equal(A); | ||
done(); | ||
}) | ||
.on('error', done); | ||
emitter.emit('end', A); | ||
// this is to check type strictness of the err check | ||
it('should emit error on false as first argument to callback', function (done) { | ||
var A = 1, B = 40, C = 2; | ||
var mapped = emitter.mapAsync(function (cb) { | ||
cb(false, A, B, C); | ||
}); | ||
mapped.on('error', function (err, a, b, c) { | ||
err.should.be.false; | ||
a.should.be.equal(A); | ||
b.should.be.equal(B); | ||
c.should.be.equal(C); | ||
done(); | ||
}); | ||
mapped.on('end', function () { throw new Error('Should not emit end'); }); | ||
emitter.emit('end'); | ||
}); | ||
it('should set this to emitter', function (done) { | ||
var mapped = emitter.mapAsync(function (cb) { cb(null, this); }); | ||
mapped | ||
.on('end', function (result) { | ||
result.should.be.equal(mapped); | ||
done(); | ||
}) | ||
.on('error', done); | ||
emitter.emit('end'); | ||
// this is to check type strictness of the err check | ||
it('should emit error on true as first argument to callback', function (done) { | ||
var A = 1, B = 40, C = 2; | ||
var mapped = emitter.mapAsync(function (cb) { | ||
cb(true, A, B, C); | ||
}); | ||
mapped.on('error', function (err, a, b, c) { | ||
err.should.be.true; | ||
a.should.be.equal(A); | ||
b.should.be.equal(B); | ||
c.should.be.equal(C); | ||
done(); | ||
}); | ||
mapped.on('end', function () { throw new Error('Should not emit end'); }); | ||
emitter.emit('end'); | ||
}); | ||
it('should support returning multiple values as multiple arguments', function (done) { | ||
var A = 1, B = 2; | ||
var mapped = emitter.mapAsync(function (cb) { cb(null, A, B); }); | ||
mapped | ||
.on('end', function (a, b) { | ||
a.should.be.equal(A); | ||
b.should.be.equal(B); | ||
done(); | ||
}) | ||
.on('error', done); | ||
emitter.emit('end'); | ||
// this is to check type strictness of the err check | ||
it('should emit end on null as first argument to callback', function (done) { | ||
var A = 1, B = 40, C = 2; | ||
var mapped = emitter.mapAsync(function (cb) { | ||
cb(null, A, B, C); | ||
}); | ||
mapped.on('error', function () { throw new Error('Should not emit error'); }); | ||
mapped.on('end', function (a, b, c) { | ||
a.should.be.equal(A); | ||
b.should.be.equal(B); | ||
c.should.be.equal(C); | ||
done(); | ||
}); | ||
emitter.emit('end'); | ||
}); | ||
it('should emit exceptions as error', function (done) { | ||
var err = new Error('234'); | ||
emitter | ||
.mapAsync(function (cb) { cb(err); }) | ||
.on('end', function () { | ||
done(new Error('Expecting error')); | ||
}) | ||
.on('error', function (error) { | ||
error.should.be.equal(err); | ||
done(); | ||
}); | ||
emitter.emit('end'); | ||
it('should throw if callback called too many times', function (done) { | ||
var mapped = emitter.mapAsync(function (cb) { | ||
cb(null); | ||
expect(function () { | ||
cb(null); | ||
}).to.throw(Error, 'Callback called more than once by function at position 0 (0-based)'); | ||
done(); | ||
}); | ||
mapped.on('error', done); | ||
emitter.emit('end'); | ||
}); | ||
it('should throw exception on non-function arguments', function () { | ||
it('should throw if callback called too many times (with misbehaving callback)', function (done) { | ||
var mapped = emitter.mapAsync(function () {/* bad function, does not call cb() */}, function (cb) { | ||
cb(null); | ||
expect(function () { | ||
emitter.mapAsync(function () {}, 2); | ||
}).to.throw(TypeError, /Argument must be a function/); | ||
cb(null); | ||
}).to.throw(Error, 'Callback called more than once by function at position 1 (0-based)'); | ||
done(); | ||
}); | ||
mapped.on('error', done); | ||
emitter.emit('end'); | ||
}); | ||
it('should call each map function and return results in order (sync)', function (done) { | ||
var f1 = function (a1, a2, cb) { | ||
cb(null, a1 + a2); | ||
}; | ||
var f2 = function (a1, a2, cb) { | ||
cb(null, a1 * a2); | ||
}; | ||
it('should support synchronous call of callback', function (done) { | ||
var A = 42; | ||
var mapped = emitter.mapAsync(function (param, cb) { cb(null, param); }); | ||
mapped | ||
.on('end', function (result) { | ||
result.should.be.equal(A); | ||
done(); | ||
}) | ||
.on('error', done); | ||
emitter.emit('end', A); | ||
}); | ||
var r = emitter.mapAsync(f1, f2); | ||
r.on('end', function (r1, r2) { | ||
r1.should.be.equal(6); | ||
r2.should.be.equal(8); | ||
it('should support asynchronous call of callback', function (done) { | ||
var A = 42; | ||
var mapped = emitter.mapAsync(function (param, cb) { setImmediate(cb.bind(null, null, param)); }); | ||
mapped | ||
.on('end', function (result) { | ||
result.should.be.equal(A); | ||
done(); | ||
}); | ||
emitter.emit('end', 4, 2); | ||
}); | ||
}) | ||
.on('error', done); | ||
emitter.emit('end', A); | ||
}); | ||
it('should call each map function and return results in order (async)', function (done) { | ||
var f1 = function (a1, a2, cb) { | ||
setImmediate(cb.bind(null, null, a1 + a2)); | ||
}; | ||
var f2 = function (a1, a2, cb) { | ||
cb(null, a1 * a2); | ||
}; | ||
it('should set this to emitter', function (done) { | ||
var mapped = emitter.mapAsync(function (cb) { cb(null, this); }); | ||
mapped | ||
.on('end', function (result) { | ||
result.should.be.equal(mapped); | ||
done(); | ||
}) | ||
.on('error', done); | ||
emitter.emit('end'); | ||
}); | ||
var r = emitter.mapAsync(f1, f2); | ||
r.on('end', function (r1, r2) { | ||
r1.should.be.equal(6); | ||
r2.should.be.equal(8); | ||
it('should support returning multiple values as multiple arguments', function (done) { | ||
var A = 1, B = 2; | ||
var mapped = emitter.mapAsync(function (cb) { cb(null, A, B); }); | ||
mapped | ||
.on('end', function (a, b) { | ||
a.should.be.equal(A); | ||
b.should.be.equal(B); | ||
done(); | ||
}) | ||
.on('error', done); | ||
emitter.emit('end'); | ||
}); | ||
it('should emit exceptions as error', function (done) { | ||
var err = new Error('234'); | ||
emitter | ||
.mapAsync(function (cb) { cb(err); }) | ||
.on('end', function () { | ||
done(new Error('Expecting error')); | ||
}) | ||
.on('error', function (error) { | ||
error.should.be.equal(err); | ||
done(); | ||
}); | ||
emitter.emit('end', 4, 2); | ||
}); | ||
emitter.emit('end'); | ||
}); | ||
it('should throw exception on non-function arguments', function () { | ||
expect(function () { | ||
emitter.mapAsync(function () {}, 2); | ||
}).to.throw(TypeError, /Argument must be a function/); | ||
}); | ||
describe('#flatMap()', function () { | ||
it('should call each map function and return results in order (sync)', function (done) { | ||
var f1 = function (a1, a2, cb) { | ||
cb(null, a1 + a2); | ||
}; | ||
var f2 = function (a1, a2, cb) { | ||
cb(null, a1 * a2); | ||
}; | ||
it('should set this to emitter', function (done) { | ||
var mapped = emitter | ||
.flatMap(function () { | ||
var self = this; | ||
return EEX.startAsync(function (eex) { | ||
eex.emit('end', self); | ||
}); | ||
}) | ||
.on('end', function (result) { | ||
result.should.be.equal(mapped); | ||
done(); | ||
}) | ||
.on('error', done); | ||
emitter.emit('end'); | ||
var r = emitter.mapAsync(f1, f2); | ||
r.on('end', function (r1, r2) { | ||
r1.should.be.equal(6); | ||
r2.should.be.equal(8); | ||
done(); | ||
}); | ||
emitter.emit('end', 4, 2); | ||
}); | ||
it('should throw if emitter emit end more than once', function () { | ||
var e = new EEX(); | ||
emitter | ||
.flatMap(function () { | ||
return e; | ||
}); | ||
emitter.emit('end'); | ||
e.emit('end'); | ||
expect(function () { | ||
e.emit('end'); | ||
}).to.throw(Error, 'end/error (or both) event emitted more than once by emitter at position 0 (0-based)'); | ||
}); | ||
it('should call each map function and return results in order (async)', function (done) { | ||
var f1 = function (a1, a2, cb) { | ||
setImmediate(cb.bind(null, null, a1 + a2)); | ||
}; | ||
var f2 = function (a1, a2, cb) { | ||
cb(null, a1 * a2); | ||
}; | ||
it('should throw if emitter emit error more than once', function () { | ||
var e = new EEX(); | ||
emitter | ||
.flatMap(function () { | ||
return e; | ||
}) | ||
.on('error', function () { | ||
// ignore | ||
}); | ||
emitter.emit('end'); | ||
e.emit('error', new Error('123')); | ||
expect(function () { | ||
e.emit('error', new Error('234')); | ||
}).to.throw(Error, 'end/error (or both) event emitted more than once by emitter at position 0 (0-based)'); | ||
var r = emitter.mapAsync(f1, f2); | ||
r.on('end', function (r1, r2) { | ||
r1.should.be.equal(6); | ||
r2.should.be.equal(8); | ||
done(); | ||
}); | ||
emitter.emit('end', 4, 2); | ||
}); | ||
it('should throw if emitter emit end and error', function () { | ||
var e = new EEX(); | ||
emitter | ||
.flatMap(function () { | ||
return e; | ||
}); | ||
emitter.emit('end'); | ||
e.emit('end'); | ||
expect(function () { | ||
e.emit('error', new Error('234')); | ||
}).to.throw(Error, 'end/error (or both) event emitted more than once by emitter at position 0 (0-based)'); | ||
}); | ||
}); | ||
it('should collect results and emit all together in order', function (done) { | ||
var A = 1, B = 40, C = 2, e = new EEX(); | ||
emitter | ||
.flatMap( | ||
function () { | ||
return e; | ||
}, | ||
function () { | ||
return new EEX() | ||
.startPipeline(C) | ||
.on('end', function () { e.startPipeline(A, B); } ); | ||
}) | ||
.on('end', function (r1, r2, r3, r4) { | ||
r1.should.be.equal(A); | ||
r2.should.be.equal(B); | ||
r3.should.be.equal(C); | ||
expect(r4).to.be.undefined; | ||
done(); | ||
}) | ||
.on('error', done); | ||
emitter.emit('end'); | ||
}); | ||
describe('#flatMap()', function () { | ||
it('should emit error after all emitters finished', function (done) { | ||
var e = new EEX(), error = new Error('error!'); | ||
emitter | ||
.flatMap( | ||
function () { | ||
return e; | ||
}, | ||
function () { | ||
return new EEX() | ||
.startPipeline() | ||
.on('end', e.emit.bind(e, 'error', error)); | ||
}) | ||
.on('end', function () { | ||
fail('end emitted', 'end emitted'); | ||
}) | ||
.on('error', function (err) { | ||
err.should.be.equal(error); | ||
done(); | ||
it('should set this to emitter', function (done) { | ||
var mapped = emitter | ||
.flatMap(function () { | ||
var self = this; | ||
return EEX.startAsync(function (eex) { | ||
eex.emit('end', self); | ||
}); | ||
emitter.emit('end'); | ||
}); | ||
}) | ||
.on('end', function (result) { | ||
result.should.be.equal(mapped); | ||
done(); | ||
}) | ||
.on('error', done); | ||
emitter.emit('end'); | ||
}); | ||
it('should throw exception on non-function arguments', function () { | ||
expect(function () { | ||
emitter.flatMap(42); | ||
}).to.throw(TypeError, /Argument must be a function/); | ||
}); | ||
it('should throw if emitter emit end more than once', function () { | ||
var e = new EEX(); | ||
emitter | ||
.flatMap(function () { | ||
return e; | ||
}); | ||
emitter.emit('end'); | ||
e.emit('end'); | ||
expect(function () { | ||
e.emit('end'); | ||
}).to.throw(Error, 'end/error (or both) event emitted more than once by emitter at position 0 (0-based)'); | ||
}); | ||
var i = 0; | ||
[[EventEmitter, EventEmitter], [EventEmitter, EEX], [EEX, EventEmitter], [EEX, EEX]] | ||
.forEach(function (SourceTypes) { | ||
i++; | ||
it('should pipe all events and call map function #' + i, function (done) { | ||
var spyData = sinon.spy(), | ||
spyInfo = sinon.spy(), | ||
spyMsg = sinon.spy(), | ||
A = 1, B = 40, C = 2, DATA = 24, MSG = 'FP (allthethings)'; | ||
it('should throw if emitter emit error more than once', function () { | ||
var e = new EEX(); | ||
emitter | ||
.flatMap(function () { | ||
return e; | ||
}) | ||
.on('error', function () { | ||
// ignore | ||
}); | ||
emitter.emit('end'); | ||
e.emit('error', new Error('123')); | ||
expect(function () { | ||
e.emit('error', new Error('234')); | ||
}).to.throw(Error, 'end/error (or both) event emitted more than once by emitter at position 0 (0-based)'); | ||
}); | ||
emitter | ||
.flatMap(function (a, b, c) { | ||
var emitter2 = new SourceTypes[0](); | ||
it('should throw if emitter emit end and error', function () { | ||
var e = new EEX(); | ||
emitter | ||
.flatMap(function () { | ||
return e; | ||
}); | ||
emitter.emit('end'); | ||
e.emit('end'); | ||
expect(function () { | ||
e.emit('error', new Error('234')); | ||
}).to.throw(Error, 'end/error (or both) event emitted more than once by emitter at position 0 (0-based)'); | ||
}); | ||
setImmediate(function () { | ||
emitter2.emit('info', a); | ||
emitter2.emit('end', b, c); | ||
}); | ||
it('should collect results and emit all together in order', function (done) { | ||
var A = 1, B = 40, C = 2, e = new EEX(); | ||
emitter | ||
.flatMap( | ||
function () { | ||
return e; | ||
}, | ||
function () { | ||
return new EEX() | ||
.startPipeline(C) | ||
.on('end', function () { e.startPipeline(A, B); } ); | ||
}) | ||
.on('end', function (r1, r2, r3, r4) { | ||
r1.should.be.equal(A); | ||
r2.should.be.equal(B); | ||
r3.should.be.equal(C); | ||
expect(r4).to.be.undefined; | ||
done(); | ||
}) | ||
.on('error', done); | ||
emitter.emit('end'); | ||
}); | ||
return emitter2; | ||
}) | ||
.flatMap(function (b, c) { | ||
var emitter3 = new SourceTypes[1](); | ||
it('should emit error after all emitters finished', function (done) { | ||
var e = new EEX(), error = new Error('error!'); | ||
emitter | ||
.flatMap( | ||
function () { | ||
return e; | ||
}, | ||
function () { | ||
return new EEX() | ||
.startPipeline() | ||
.on('end', e.emit.bind(e, 'error', error)); | ||
}) | ||
.on('end', function () { | ||
fail('end emitted', 'end emitted'); | ||
}) | ||
.on('error', function (err) { | ||
err.should.be.equal(error); | ||
done(); | ||
}); | ||
emitter.emit('end'); | ||
}); | ||
setImmediate(function () { | ||
emitter3.emit('data', DATA); | ||
emitter3.emit('end', b + c); | ||
}); | ||
it('should throw exception on non-function arguments', function () { | ||
expect(function () { | ||
emitter.flatMap(42); | ||
}).to.throw(TypeError, /Argument must be a function/); | ||
}); | ||
return emitter3; | ||
}) | ||
.on('error', done) | ||
.on('msg', spyMsg) | ||
.on('info', spyInfo) | ||
.on('data', spyData) | ||
.on('end', function (d) { | ||
spyMsg.calledWith(MSG).should.be.true; | ||
spyInfo.calledWith(A).should.be.true; | ||
spyData.calledWith(DATA).should.be.true; | ||
d.should.equal(B + C); | ||
done(); | ||
}); | ||
emitter.emit('msg', MSG); | ||
emitter.emit('end', A, B, C); | ||
}); | ||
}); | ||
i = 0; | ||
[EventEmitter, EEX].forEach(function (SourceType) { | ||
var i = 0; | ||
[[EventEmitter, EventEmitter], [EventEmitter, EEX], [EEX, EventEmitter], [EEX, EEX]] | ||
.forEach(function (SourceTypes) { | ||
i++; | ||
it('should propagate error event and do not call next map function #' + i, function (done) { | ||
var spyMapper = sinon.spy(), | ||
it('should pipe all events and call map function #' + i, function (done) { | ||
var spyData = sinon.spy(), | ||
spyInfo = sinon.spy(), | ||
spyMsg = sinon.spy(), | ||
A = 1, B = 40, C = 2, MSG = 'FP (allthethings)', | ||
ERR = new Error('Something fishy just happened!'); | ||
A = 1, B = 40, C = 2, DATA = 24, MSG = 'FP (allthethings)'; | ||
emitter | ||
.flatMap(function (a, b, c) { | ||
var emitter2 = new SourceType(); | ||
var emitter2 = new SourceTypes[0](); | ||
setImmediate(function () { | ||
emitter2.emit('info', a); | ||
emitter2.emit('error', ERR); | ||
emitter2.emit('end', b, c); | ||
}); | ||
@@ -730,13 +720,24 @@ | ||
}) | ||
.flatMap(spyMapper) | ||
.on('error', function (err) { | ||
.flatMap(function (b, c) { | ||
var emitter3 = new SourceTypes[1](); | ||
setImmediate(function () { | ||
emitter3.emit('data', DATA); | ||
emitter3.emit('end', b + c); | ||
}); | ||
return emitter3; | ||
}) | ||
.on('error', done) | ||
.on('msg', spyMsg) | ||
.on('info', spyInfo) | ||
.on('data', spyData) | ||
.on('end', function (d) { | ||
spyMsg.calledWith(MSG).should.be.true; | ||
spyInfo.calledWith(A).should.be.true; | ||
spyMapper.callCount.should.be.equal(0); | ||
err.should.equal(ERR); | ||
spyData.calledWith(DATA).should.be.true; | ||
d.should.equal(B + C); | ||
done(); | ||
}) | ||
.on('msg', spyMsg) | ||
.on('info', spyInfo) | ||
.on('end', done.bind(null, new Error('Should not happen'))); | ||
}); | ||
@@ -747,5 +748,76 @@ emitter.emit('msg', MSG); | ||
}); | ||
i = 0; | ||
[EventEmitter, EEX].forEach(function (SourceType) { | ||
i++; | ||
it('should propagate error event and do not call next map function #' + i, function (done) { | ||
var spyMapper = sinon.spy(), | ||
spyInfo = sinon.spy(), | ||
spyMsg = sinon.spy(), | ||
A = 1, B = 40, C = 2, MSG = 'FP (allthethings)', | ||
ERR = new Error('Something fishy just happened!'); | ||
emitter | ||
.flatMap(function (a /* , b, c */) { | ||
var emitter2 = new SourceType(); | ||
setImmediate(function () { | ||
emitter2.emit('info', a); | ||
emitter2.emit('error', ERR); | ||
}); | ||
return emitter2; | ||
}) | ||
.flatMap(spyMapper) | ||
.on('error', function (err) { | ||
spyMsg.calledWith(MSG).should.be.true; | ||
spyInfo.calledWith(A).should.be.true; | ||
spyMapper.callCount.should.be.equal(0); | ||
err.should.equal(ERR); | ||
done(); | ||
}) | ||
.on('msg', spyMsg) | ||
.on('info', spyInfo) | ||
.on('end', done.bind(null, new Error('Should not happen'))); | ||
emitter.emit('msg', MSG); | ||
emitter.emit('end', A, B, C); | ||
}); | ||
}); | ||
}); | ||
describe('#asPromise()', function () { | ||
var p; | ||
beforeEach(function () { | ||
p = emitter.asPromise(); | ||
}); | ||
it('should return a Promise that is bound to end event', function (done) { | ||
var A = 42; | ||
p.then(function (value) { | ||
value.should.equals(A); | ||
done(); | ||
}, done); | ||
setImmediate(emitter.emit.bind(emitter, 'end', A)); | ||
}); | ||
it('should return a Promise that is bound to error event', function (done) { | ||
var ERR = new Error('Something fishy just happened!'); | ||
p.then(function () { | ||
done(new Error('What?')); | ||
}, function (err) { | ||
err.should.equals(ERR); | ||
done(); | ||
}); | ||
setImmediate(emitter.emit.bind(emitter, 'error', ERR)); | ||
}); | ||
}); | ||
})(); | ||
}); |
@@ -1,14 +0,11 @@ | ||
(function () { | ||
'use strict'; | ||
'use strict'; | ||
var chai = require('chai'); | ||
chai.config.includeStack = true; | ||
global.chai = chai; | ||
global.should = chai.should(); | ||
global.expect = chai.expect; | ||
chai.use(require('sinon-chai')); | ||
global.sinon = require('sinon'); | ||
var chai = require('chai'); | ||
chai.config.includeStack = true; | ||
global.chai = chai; | ||
global.should = chai.should(); | ||
global.expect = chai.expect; | ||
chai.use(require('sinon-chai')); | ||
global.sinon = require('sinon'); | ||
Error.stackTraceLimit = Infinity; | ||
})(); | ||
Error.stackTraceLimit = Infinity; |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
12
909
57283