From 8c1bd481c09f25255aa3ff2c73fbdeb9e9aa9d86 Mon Sep 17 00:00:00 2001 From: overlookmotel Date: Sun, 6 Oct 2019 17:23:02 +0100 Subject: [PATCH] WIP tests 1 --- package-lock.json | 12 ++++++ package.json | 4 +- test/index.test.js | 3 ++ test/streams.js | 99 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 test/streams.js diff --git a/package-lock.json b/package-lock.json index 12855d2..f4dda2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -353,6 +353,12 @@ "@types/yargs": "^13.0.0" } }, + "@offirmo/random": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@offirmo/random/-/random-2.0.4.tgz", + "integrity": "sha1-bnHQosawDnicL/A1YpKd72nIk9A=", + "dev": true + }, "@overlookmotel/eslint-config": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/@overlookmotel/eslint-config/-/eslint-config-4.3.2.tgz", @@ -5191,6 +5197,12 @@ "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", "dev": true }, + "stream-gen": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-gen/-/stream-gen-2.0.1.tgz", + "integrity": "sha512-v8XTQUS49pphqUqPAJjPtEzkC7rPcZwK27QstEk2+WlPmftxI+LF0eo9btw4boIcArYhUYfyfl4MD92TAiWRjA==", + "dev": true + }, "string-length": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", diff --git a/package.json b/package.json index 56974ef..b42561b 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ }, "dependencies": {}, "devDependencies": { + "@offirmo/random": "^2.0.4", "@overlookmotel/eslint-config": "^4.3.2", "@overlookmotel/eslint-config-jest": "^2.1.0", "coveralls": "^3.0.6", @@ -25,7 +26,8 @@ "eslint-plugin-import": "^2.18.2", "eslint-plugin-jest": "^22.17.0", "eslint-plugin-node": "^10.0.0", - "jest": "^24.9.0" + "jest": "^24.9.0", + "stream-gen": "^2.0.1" }, "keywords": [ "stream", diff --git a/test/index.test.js b/test/index.test.js index 4ca049e..83a73c6 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -8,6 +8,9 @@ // Modules const streamChop = require('../index'); +// Imports +const {createReadStream} = require('./streams.js'); + // Init require('./support'); diff --git a/test/streams.js b/test/streams.js new file mode 100644 index 0000000..18867f0 --- /dev/null +++ b/test/streams.js @@ -0,0 +1,99 @@ +/* -------------------- + * stream-chop + * Functions to create test streams + * ------------------*/ + +/* eslint-disable no-bitwise */ + +'use strict'; + +// Modules +const {GeneratorReadStream, GeneratorWriteStream} = require('stream-gen'), + Random = require('@offirmo/random'); + +// Constants +const SEED = 0; + +// Exports + +module.exports = { + createReadStream, + createWriteStream +}; + +/** + * Create readable byte stream of specified length. + * Stream of bytes is drawn from MT pseudo-random generator. + * Output for same `start` and `len` is deterministic. + * + * @param {number} start - Start bytes of sequence + * @param {number} len - Length of sequence + * @returns {Stream} - Readable data stream + */ +function createReadStream(start, len) { + const gen = createGenerator(start, len); + return new GeneratorReadStream(gen); +} + +/** + * Create writable stream. + * It checks that data piped into it matches expected + * i.e. same data as in stream from `createReadStream()`. + * Callback is called with error if data does not match, or with `null` when stream ends without error. + * + * @param {number} start - Start bytes of sequence + * @param {number} len - Length of sequence + * @param {function} cb - Callback - called with `null` when stream ends, or an error if matching fail + * @returns {Stream} - Readable data stream + */ +function createWriteStream(start, len, cb) { + const gen = createGenerator(start, len); + return new GeneratorWriteStream(gen, cb); +} + +function createGenerator(start, len) { + // Init MT pseudo-random number generator + const mt = Random.engines.mt19937(); + mt.seed(SEED); + + // Init empty buffer + let leftover = 0, + leftoverBytes = 0; + + // Discard start + if (start > 0) { + const discardBytes = start % 4, + discardQuads = (start - discardBytes) / 4; + if (discardQuads > 0) mt.discard(discardQuads); + + if (discardBytes > 0) { + // Get new 32-bit number, discard unneeded bytes, and put rest in leftover + leftover = mt(); + leftover >>= discardBytes * 8; + leftoverBytes = 4 - discardBytes; + } + } + + // Create generator to produce bytes + let bytesRemaining = len; + function next() { + // If finished, end generator + if (bytesRemaining === 0) return {value: undefined, done: true}; + + // If no leftover, pull another 32-bit number from MT. + if (leftoverBytes === 0) { + leftover = mt(); + leftoverBytes = 4; + } + + // Pull lowest byte from leftover + const value = leftover & 0xFF; + leftover >>= 8; + leftoverBytes--; + bytesRemaining--; + + return {value, done: false}; + } + + return () => ({next}); +}