callbag-take
Version:
Callbag operator that limits the total amount of data sent through
351 lines (322 loc) • 8.41 kB
JavaScript
const test = require('tape');
const take = require('./index');
test('it takes from a pullable source', t => {
t.plan(24);
const upwardsExpected = [
[0, 'function'],
[1, 'undefined'],
[1, 'undefined'],
[1, 'undefined'],
[2, 'undefined'],
];
const downwardsExpectedType = [
[0, 'function'],
[1, 'number'],
[1, 'number'],
[1, 'number'],
[2, 'undefined'],
];
const downwardsExpected = [10, 20, 30];
function makeSource() {
let _sink;
let sent = 0;
const source = (type, data) => {
const e = upwardsExpected.shift();
t.equals(type, e[0], 'upwards type is expected: ' + e[0]);
t.equals(typeof data, e[1], 'upwards data is expected: ' + e[1]);
if (type === 0) {
_sink = data;
_sink(0, source);
return;
}
if (type !== 1) return;
if (sent === 0) {
sent++;
setTimeout(() => {
_sink(1, 10);
});
return;
} else if (sent === 1) {
sent++;
setTimeout(() => {
_sink(1, 20);
});
return;
} else if (sent === 2) {
sent++;
setTimeout(() => {
_sink(1, 30);
});
return;
} else if (sent === 3) {
sent++;
setTimeout(() => {
_sink(1, 40);
});
return;
} else if (sent === 4) {
sent++;
setTimeout(() => {
_sink(1, 50);
});
return;
} else if (sent === 5) {
sent++;
_sink(2);
return;
}
};
return source;
}
function makeSink() {
let talkback;
return (type, data) => {
const et = downwardsExpectedType.shift();
t.equals(type, et[0], 'downwards type is expected: ' + et[0]);
t.equals(typeof data, et[1], 'downwards data type is expected: ' + et[1]);
if (type === 0) {
talkback = data;
return talkback(1);
}
if (type === 1) {
const e = downwardsExpected.shift();
t.equals(data, e, 'downwards data is expected: ' + e);
return talkback(1);
}
};
}
const source = makeSource();
const taken = take(3)(source);
const sink = makeSink();
taken(0, sink);
setTimeout(() => {
t.pass('nothing else happens');
t.end();
}, 300);
});
test('it takes an async listenable source', t => {
t.plan(18);
const upwardsExpected = [[0, 'function'], [2, 'undefined']];
const downwardsExpectedType = [
[0, 'function'],
[1, 'number'],
[1, 'number'],
[1, 'number'],
[2, 'undefined'],
];
const downwardsExpected = [10, 20, 30];
function makeSource() {
let sent = 0;
let id;
const source = (type, data) => {
const e = upwardsExpected.shift();
t.equals(type, e[0], 'upwards type is expected: ' + e[0]);
t.equals(typeof data, e[1], 'upwards data is expected: ' + e[1]);
if (type === 0) {
const sink = data;
id = setInterval(() => {
sink(1, ++sent * 10);
}, 100);
sink(0, source);
} else if (type === 2) {
clearInterval(id);
}
};
return source;
}
function sink(type, data) {
const et = downwardsExpectedType.shift();
t.equals(type, et[0], 'downwards type is expected: ' + et[0]);
t.equals(typeof data, et[1], 'downwards data type is expected: ' + et[1]);
if (type === 1) {
const e = downwardsExpected.shift();
t.equals(data, e, 'downwards data is expected: ' + e);
}
}
const source = makeSource();
const taken = take(3)(source);
taken(0, sink);
setTimeout(() => {
t.pass('nothing else happens');
t.end();
}, 700);
});
test('it returns a source that disposes upon upwards END', t => {
t.plan(16);
const upwardsExpected = [[0, 'function'], [2, 'undefined']];
const downwardsExpectedType = [
[0, 'function'],
[1, 'number'],
[1, 'number'],
[1, 'number'],
];
const downwardsExpected = [10, 20, 30];
function makeSource() {
let sent = 0;
let id;
const source = (type, data) => {
const e = upwardsExpected.shift();
t.equals(type, e[0], 'upwards type is expected: ' + e[0]);
t.equals(typeof data, e[1], 'upwards data is expected: ' + e[1]);
if (type === 0) {
const sink = data;
id = setInterval(() => {
sink(1, ++sent * 10);
}, 100);
sink(0, source);
} else if (type === 2) {
clearInterval(id);
}
};
return source;
}
function makeSink(type, data) {
let talkback;
return (type, data) => {
const et = downwardsExpectedType.shift();
t.equals(type, et[0], 'downwards type is expected: ' + et[0]);
t.equals(typeof data, et[1], 'downwards data type is expected: ' + et[1]);
if (type === 0) {
talkback = data;
}
if (type === 1) {
const e = downwardsExpected.shift();
t.equals(data, e, 'downwards data is expected: ' + e);
}
if (downwardsExpected.length === 0) {
talkback(2);
}
};
}
const source = makeSource();
const taken = take(9)(source);
const sink = makeSink();
taken(0, sink);
setTimeout(() => {
t.pass('nothing else happens');
t.end();
}, 700);
});
test('it does not redundantly terminate a synchronous pullable source', t => {
t.plan(23);
let terminations = 0;
const rangeInfinite = start => (type, sink) => {
if (type !== 0) return;
var counter = start;
sink(0, (type, data) => {
const e = upwardsExpected.shift();
t.equals(type, e[0], 'upwards type is expected: ' + e[0]);
t.equals(typeof data, e[1], 'upwards data is expected: ' + e[1]);
if (type === 1) {
const send = counter;
counter++;
sink(1, send);
}
if (type === 2) {
terminations += 1;
}
});
};
const upwardsExpected = [
[1, 'undefined'],
[1, 'undefined'],
[1, 'undefined'],
[2, 'undefined'],
];
const downwardsExpectedType = [
[0, 'function'],
[1, 'number'],
[1, 'number'],
[1, 'number'],
[2, 'undefined'],
];
const downwardsExpected = [7, 8, 9];
function makeSink() {
let talkback;
return (type, data) => {
const et = downwardsExpectedType.shift();
t.equals(type, et[0], 'downwards type is expected: ' + et[0]);
t.equals(typeof data, et[1], 'downwards data type is expected: ' + et[1]);
if (type === 0) {
talkback = data;
talkback(1);
}
if (type === 1) {
const e = downwardsExpected.shift();
t.equals(data, e, 'downwards data is expected: ' + e);
talkback(1);
}
};
}
const source = rangeInfinite(7);
const taken = take(3)(source);
const sink = makeSink();
taken(0, sink);
setTimeout(() => {
t.equal(terminations, 1, 'only 1 source termination happened');
t.pass('nothing else happens');
t.end();
}, 700);
});
test('it does not mutually terminate a sink', t => {
let terminations = 0;
let loggerTerminations = 0;
const rangeInfinite = start => (type, sink) => {
if (type !== 0) return;
var counter = start;
sink(0, (type, data) => {
if (type === 1) {
const send = counter;
counter++;
sink(1, send);
}
if (type === 2) {
terminations += 1;
}
});
};
function makeSink() {
let talkback;
return (type, data) => {
if (type === 0) {
talkback = data;
talkback(1);
}
if (type === 1) {
talkback(1);
}
};
}
const logger = source => (start, sink) => {
if (start !== 0) return;
let sourceTalkback;
function talkback(t, d) {
if (t === 2) {
loggerTerminations += 1;
}
sourceTalkback(t, d)
}
source(0, (t, d) => {
if (t === 2) {
loggerTerminations += 1;
}
if (t === 0) {
sourceTalkback = d;
sink(0, talkback);
}
else {
sink(t, d)
}
})
}
const source = rangeInfinite(7);
const taken = take(3)(logger(take(3)(source)));
const sink = makeSink();
taken(0, sink);
setTimeout(() => {
t.equal(terminations, 1, 'only 1 source termination happened');
t.equal(loggerTerminations, 1, 'logger only observed 1 termination')
t.pass('nothing else happens');
t.end();
}, 700);
});