UNPKG

rafa

Version:

Rafa.js is a Javascript framework for building concurrent applications.

164 lines (140 loc) 5.9 kB
module.exports = (assert, Rafa) => { suite("flatMap", () => { // basic test: flatMap should push values from the returned inner stream // to the outer.flatMap's children. Done messages from the inner should // be converted to normal messages for the outer. test("pushes values from inner stream", done => { var outer = Rafa.stream(); var values = []; // create flatMap handler outer.flatMap(value => { var inner = Rafa.stream(); var vals = value.split(","); // defer writing value and done messages to inner. // messages are 'a' and 'b' setTimeout(() => { Rafa.message(vals[0]).push(inner); Rafa.doneMessage(vals[1]).push(inner); }); return inner; }) .each(v => values.push(v)) // should catch both inner messages .done(v => values.push('x'+v)); // should never be called // init flatMap by pushing message to outer stream Rafa.message("a,b").push(outer); // defer to wait for inner messages. // values should only have two items, 'a' and 'b'; they should not // have been added by the done handler otherwise they would start with // 'x' setTimeout(() => { assert.equal(values.length, 2); assert.equal(values[0], "a"); assert.equal(values[1], "b"); done(); }); }); // error messages from the outer stream should pass through test("errors from parent pass through", () => { var stream = Rafa.stream(); var value; stream.flatMap(Rafa.noop).error(err => value = err); stream.write(new Error("foo")); assert.equal(value.message, "foo"); }); // Parent steam must wait for the inner stream to complete before // sending more messages through. Push a message, then check that the // parent context is in a pending state until the inner stream completes. test("parent push incomplete until child stream is done", done => { var outer = Rafa.stream(); outer.flatMap(message => { var inner = Rafa.stream(); // defer to allow testing the context.pending value // send a done message to clear the context setTimeout(() => inner.write(message.value + 1, true)); return inner; }); // create a context to track, push a message to the outer stream which // will create the inner stream and defer a write. The context should be // pending until the inner stream send the done message. var context = Rafa.context(); outer.push(context, Rafa.message(1)); assert.equal(context.pending, 1); setTimeout(() => { assert.equal(context.pending, 0); done(); }); }); // If the inner stream returns a promise, then the outer stream's // context should wait until the promise is fulfilled. test("inner returns a promise", done => { var outer = Rafa.stream(); var inner = Rafa.stream(); var future = Rafa.future(); var context = Rafa.context(); var values = []; outer.flatMap(() => inner.map(v => future.promise)) .each(v => values.push(v)); // push a message to the outer stream. // context should be pending the inner stream outer.push(context, Rafa.message(1)); assert.equal(context.pending, 1); // push a done message to the inner stream; inner creates a promise. inner.write(2, true); setTimeout(() => { // resolving the promise should push the promise's value to the // outer stream and into the values array. outer stream's context // should no longer be pending. future.resolve(3); setTimeout(() => { assert.equal(values[0], 3); assert.equal(context.pending, 0); done(); }); }); }); // downstream promise should force the inner and outer stream to wait test("downstream promise", done => { var outer = Rafa.stream(); var inner = Rafa.stream(); var outercontext = Rafa.context(); var innercontext = Rafa.context(); var future = Rafa.future(); outer.flatMap(v => inner.map(iv => v + iv)) .map(() => future.promise).each(Rafa.noop); // push from outer creates inner, outercontext should be pending // inner's done message outer.push(outercontext, Rafa.message(1)); assert.equal(outercontext.pending, 1); // push from inner goes to flatMap's child which then maps to a promise. // inner's context should be pending the promise. outer's context // is now pending the inner and promise. inner.push(innercontext, Rafa.message(2)); assert.equal(innercontext.pending, 1); assert.equal(outercontext.pending, 2); // resolve the promise should reduce contexts: inner is done, outer // is still pending inner. (need to recreate a promise to continue test) future.resolve(3); setTimeout(() => { assert.equal(outercontext.pending, 1); assert.equal(innercontext.pending, 0); // reset future = Rafa.future(); innercontext = Rafa.context(); // push done from inner goes to flatMap's child which then maps to a // promise. inner and outer's context should be pending the promise. // outer is no longer pending the inner because of the done message. inner.push(innercontext, Rafa.doneMessage(2)); assert.equal(innercontext.pending, 1); assert.equal(outercontext.pending, 1); // resolve the promise should cause both the inner and outer context // to be cleared. future.resolve(3); setTimeout(() => { assert.equal(outercontext.pending, 0); assert.equal(innercontext.pending, 0); done(); }); }); }); }); };