package/package.json 000644 0000001500 13251752014 011561 0 ustar 00 000000 000000 {
"name": "stream-equal",
"description": "Test that two readable streams are equal to each other.",
"keywords": [
"stream",
"input",
"output",
"io",
"assert",
"test"
],
"version": "1.1.1",
"repository": {
"type": "git",
"url": "git://github.com/fent/node-stream-equal.git"
},
"author": "fent (https://github.com/fent)",
"main": "./lib/index.js",
"files": [
"lib"
],
"typings": "./lib/index.d.ts",
"scripts": {
"test": "istanbul cover node_modules/.bin/_mocha -- test/*-test.js"
},
"directories": {
"lib": "./lib"
},
"optionalDependencies": {
"@types/node": "*"
},
"devDependencies": {
"istanbul": "^0.4.5",
"mocha": "^5.0.0",
"nock": "^9.0.22",
"request": "^2.85.0"
},
"engines": {
"node": ">=4"
},
"license": "MIT"
}
package/LICENSE 000644 0000002051 13226460166 010310 0 ustar 00 000000 000000 MIT License
Copyright (C) 2012 by fent
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
package/README.md 000644 0000002715 13226460155 010567 0 ustar 00 000000 000000 # node-stream-equal
Test that two readable streams are equal to each other.
[](http://travis-ci.org/fent/node-stream-equal)
[](https://david-dm.org/fent/node-stream-equal)
[](https://codecov.io/gh/fent/node-stream-equal)
# Usage
```js
const streamEqual = require('stream-equal');
const fs = require('fs');
var readStream1 = fs.createReadStream(file);
var readStream2 = fs.createReadStream(file);
streamEqual(readStream1, readStream2, (err, equal) => {
console.log(equal); // true
});
```
# Motive
Useful for testing. This method is faster and uses much less memory than buffering entire streams and comparing their content, specially for bigger files.
You could also get the hash sum of a stream to test it against another stream. But that would take up more CPU due to the hashing and would require a bit more data to be read if they are not equal.
# API
### streamEqual(readStream1, readStream2, [callback(err, equal)])
Will compare each `data` event on both streams, pausing when needed to keep them in sync. `equal` will be either `true` or `false` if there is no `err`. Returns a promise if callback is not given.
# Install
npm install stream-equal
# Tests
Tests are written with [mocha](https://mochajs.org)
```bash
npm test
```
package/lib/index.d.ts 000644 0000000604 13015177176 011756 0 ustar 00 000000 000000 ///
declare function streamEqual(stream1: NodeJS.ReadableStream, stream2: NodeJS.ReadableStream, cb: streamEqual.Cb): undefined;
declare function streamEqual(stream1: NodeJS.ReadableStream, stream2: NodeJS.ReadableStream): Promise;
declare namespace streamEqual {
export type Cb = (err: null|Error, equal: boolean) => void;
}
export= streamEqual;
package/lib/index.js 000644 0000010146 13166465544 011532 0 ustar 00 000000 000000 'use strict';
const PassThrough = require('stream').PassThrough;
/**
* Tests that two readable streams are equal.
*
* @param {Readable|Stream} readStream2
* @param {Readable|Stream} readStream2
* @param {Function(!Error, Boolean)} callback
*/
module.exports = function streamEqual(origStream1, origStream2, callback) {
if (typeof callback !== 'function') {
return streamEqualAsPromised(origStream1, origStream2);
}
var readStream1 = origStream1.pipe(new PassThrough({ objectMode: true }));
var readStream2 = origStream2.pipe(new PassThrough({ objectMode: true }));
var stream1 = {
id: 1,
stream: readStream1,
data: null,
pos: 0,
ended: false,
};
var stream2 = {
id: 2,
stream: readStream2,
data: null,
pos: 0,
ended: false,
};
stream1.read = createRead(stream1, stream2, cleanup);
stream2.read = createRead(stream2, stream1, cleanup);
var onend1 = createOnEnd(stream1, stream2, cleanup);
var onend2 = createOnEnd(stream2, stream1, cleanup);
function cleanup(err, equal) {
origStream1.removeListener('error', cleanup);
readStream1.removeListener('end', onend1);
readStream1.removeListener('readable', stream1.read);
origStream2.removeListener('error', cleanup);
readStream2.removeListener('end', onend2);
readStream1.removeListener('readable', stream2.read);
callback(err, equal);
}
origStream1.on('error', cleanup);
readStream1.on('end', onend1);
origStream2.on('error', cleanup);
readStream2.on('end', onend2);
// Start by reading from the first stream.
stream1.stream.once('readable', stream1.read);
};
/**
* Tests that two readable streams are equal.
*
* @param {Object} readStream1
* @param {Object} readStream2
* @return {Promise}
*/
function streamEqualAsPromised(readStream1, readStream2) {
return new Promise((resolve, reject) => {
module.exports(readStream1, readStream2, (err, result) => {
if (err) {
return reject(err);
}
resolve(result);
});
});
}
/**
* Returns a function that compares emitted `read()` call with that of the
* most recent `read` call from another stream.
*
* @param {Object} stream
* @param {Object} otherStream
* @param {Function(Error, Boolean)} callback
* @return {Function(Buffer|String)}
*/
function createRead(stream, otherStream, callback) {
return () => {
var data = stream.stream.read();
if (!data) {
return stream.stream.once('readable', stream.read);
}
// Make sure `data` is a buffer.
if (!Buffer.isBuffer(data)) {
if (typeof data === 'object') {
data = JSON.stringify(data);
} else {
data = data.toString();
}
data = new Buffer(data);
}
var newPos = stream.pos + data.length;
if (stream.pos < otherStream.pos) {
let minLength = Math.min(data.length, otherStream.data.length);
let streamData = data.slice(0, minLength);
stream.data = data.slice(minLength);
let otherStreamData = otherStream.data.slice(0, minLength);
otherStream.data = otherStream.data.slice(minLength);
// Compare.
for (let i = 0, len = streamData.length; i < len; i++) {
if (streamData[i] !== otherStreamData[i]) {
return callback(null, false);
}
}
} else {
stream.data = data;
}
stream.pos = newPos;
if (newPos > otherStream.pos) {
if (otherStream.ended) {
// If this stream is still emitting `data` events but the other has
// ended, then this is longer than the other one.
return callback(null, false);
}
// If this stream has caught up to the other,
// read from other one.
otherStream.read();
} else {
stream.read();
}
};
}
/**
* Creates a function that gets called when a stream ends.
*
* @param {Object} stream
* @param {Object} otherStream
* @param {Function(!Error, Boolean)} callback
*/
function createOnEnd(stream, otherStream, callback) {
return () => {
stream.ended = true;
if (otherStream.ended) {
callback(null, stream.pos === otherStream.pos);
} else {
otherStream.read();
}
};
}