Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

stream-compare

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

stream-compare - npm Package Compare versions

Comparing version 0.1.0 to 0.2.0

.swp

16

CHANGELOG.md
# Change Log
## [0.1.0](https://github.com/kevinoid/stream-compare/tree/0.1.0) (2016-04-02)
## [v0.2.0](https://github.com/kevinoid/stream-compare/tree/v0.2.0) (2016-04-22)
### Breaking Changes
- Remove callback argument and return Promise unconditionally. Consider using
[promise-nodeify](https://github.com/kevinoid/promise-nodeify) to migrate.
### New Features
- `endEvents` option for controlling comparison on stream end.
- `.checkpoint()` method on returned Promise allows caller to trigger compare.
- `.end()` method on returned Promise allows caller to end comparison.
## [v0.1.0](https://github.com/kevinoid/stream-compare/tree/v0.1.0) (2016-04-02)
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*

504

index.js

@@ -8,5 +8,19 @@ /**

var EventEmitter = require('events').EventEmitter;
var Promise = require('any-promise');
var debug = require('debug')('stream-compare');
var extend = require('extend');
/** Comparison type.
* @enum {string}
* @private
*/
var CompareType = {
/** A full (non-incremental) comparison. */
checkpoint: 'checkpoint',
/** An incremental comparison. */
incremental: 'incremental',
/** A full comparison followed by <code>'end'</code>. */
last: 'last'
};
/** Defines the available read policies.

@@ -16,4 +30,13 @@ * @enum {string}

var ReadPolicy = {
/** Reads are done concurrently using <code>'data'</code> events. */
flowing: 'flowing',
/** Reads from the stream which has output the least data, measured in
* bytes/chars for non-<code>objectMode</code> or values for
* <code>objectMode</code>. */
least: 'least',
/** No reads are done. When using this readPolicy, be sure to either add
* <code>'data'</code> to events, add other <code>'data'</code> listeners,
* <code>.read()</code> the data elsewhere, or call <code>.resume()</code> on
* the streams so that the data will be read and <code>'end'</code> can be
* reached. */
none: 'none'

@@ -24,2 +47,3 @@ };

* @const
* @private
*/

@@ -29,7 +53,7 @@ var DEFAULT_OPTIONS = {

delay: 0,
endEvents: ['end', 'error'],
// Observe Readable events other than 'data' by default
events: ['close', 'end', 'error'],
objectMode: false,
// Can be ''flowing', least', or 'none'
// @type {!ReadPolicy}
/** @type {!ReadPolicy} */
readPolicy: 'least'

@@ -41,11 +65,14 @@ };

* Guarantees/Invariants:
* - Equivalent states are assert.deepStrictEqual.
* - States can be round-tripped to JSON at any point.
* - States are owned by the caller, so any additional properties (which are
* permitted to violate the above guarantees) are preserved and the same
* state object is always returned.
*
* As a result, objects of this class have no methods and do not contain any
* <ul>
* <li>Equivalent states are {@link assert.deepStrictEqual}.</li>
* <li>States can be round-tripped to JSON at any point.</li>
* <li>States are owned by the caller, so any additional properties (which are
* permitted to violate the above guarantees) are preserved and the same
* state object is always returned.</li>
* </ul>
*
* <p>As a result, objects of this class have no methods and do not contain any
* non-state information (e.g. the stream itself or the comparison options)
* and their prototype is never used.
* and their prototype is never used.</p>
*

@@ -55,3 +82,3 @@ * @constructor

function StreamState() {
/** Has the stream emitted 'end' or 'error'. */
/** Has the stream emitted <code>'end'</code> or <code>'error'</code>. */
this.ended = false;

@@ -61,13 +88,143 @@ /** Events emitted by the stream.

this.events = [];
/** Data returned/emitted by the stream (as an Array if in objectMode).
/** Data returned/emitted by the stream (as an <code>Array</code> if in
* <code>objectMode</code>).
* @type Array|Buffer|string */
this.data = undefined;
/** Count of total objects read in objectMode, bytes/chars read otherwise. */
/** Count of total objects read in <code>objectMode</code>, bytes/chars read
* otherwise. */
this.totalDataLen = 0;
}
/** Same as streamCompare, but assumes its arguments are valid.
* @private
/** Options for {@link streamCompare}.
*
* @ template CompareResult
* @typedef {{
* abortOnError: boolean|undefined,
* compare: ((function(!StreamState,!StreamState): CompareResult)|undefined),
* delay: number|undefined,
* endEvents: Array<string>|undefined,
* events: Array<string>|undefined,
* incremental:
* ((function(!StreamState,!StreamState): CompareResult)|undefined),
* objectMode: boolean|undefined,
* readPolicy: ReadPolicy|undefined
* }} StreamCompareOptions
* @property {boolean=} abortOnError Abort comparison and return error emitted
* by either stream. (default: <code>false</code>)
* @property {function(!StreamState,!StreamState)=} compare Comparison function
* which will be called with a StreamState object for each stream, after both
* streams have ended. The value returned by this function will resolve the
* returned promise and be passed to the callback as its second argument. A
* value thrown by this function will reject the promise and be passed to the
* callback as its first argument. This function is required if incremental is
* not specified.
* @property {number=} delay Additional delay (in ms) after streams end before
* comparing. (default: <code>0</code>)
* @property {Array<string>=} endEvents Names of events which signal the end of
* a stream. Final compare is performed once both streams have emitted an end
* event. (default: <code>['end', 'error']</code>)
* @property {Array<string>=} events Names of events to compare.
* (default: <code>['close', 'end', 'error']</code>)
* @property {function(!StreamState,!StreamState)=} incremental Incremental
* comparison function which will be called periodically with a StreamState
* object for each stream. This function may modify the StreamState objects to
* remove data not required for later comparisons (e.g. common output) and may
* perform the comparison before the streams have ended (e.g. due to early
* differences). Any non-null, non-undefined value returned by this function
* will finish the comparison, resolve the returned promise, and be passed to
* the callback as its second argument. A value thrown by this function will
* finish the comparison, reject the promise and be passed to the callback as
* its first argument. If compare is not specified, this function will also be
* called for the final comparison.
* @property {boolean=} objectMode Collect values read into an Array. This
* allows comparison of read values without concatenation and comparison of
* non-string/Buffer types.
* @property {ReadPolicy=} readPolicy Scheduling discipline for reads from th
* streams. (default: <code>'least'</code>)
*/
function streamCompareInternal(stream1, stream2, options, callback) {
// var StreamCompareOptions;
/** Promise returned by {@link streamCompare}.
*
* @ template CompareResult
* @constructor
* @name StreamComparePromise
* @extends Promise<CompareResult>
*/
// var StreamComparePromise;
/** Compares the output of two Readable streams.
*
* @ template CompareResult
* @param {!stream.Readable} stream1 First stream to compare.
* @param {!stream.Readable} stream2 Second stream to compare.
* @param {!StreamCompareOptions<CompareResult>|
* function(!StreamState,!StreamState): CompareResult}
* optionsOrCompare Options, or a comparison function (as described in
* {@link options.compare}).
* @return {StreamComparePromise<CompareResult>} A <code>Promise</code> with
* the comparison result or error.
*/
function streamCompare(stream1, stream2, optionsOrCompare) {
var options;
if (optionsOrCompare) {
if (typeof optionsOrCompare === 'function') {
options = {compare: optionsOrCompare};
} else if (typeof optionsOrCompare === 'object') {
options = optionsOrCompare;
} else {
throw new TypeError('optionsOrCompare must be an object or function');
}
}
options = extend({}, DEFAULT_OPTIONS, options);
if (!options.compare) {
options.compare = options.incremental;
}
// Can change this to duck typing if there are non-EventEmitter streams
if (!(stream1 instanceof EventEmitter)) {
throw new TypeError('stream1 must be an EventEmitter');
}
// Can change this to duck typing if there are non-EventEmitter streams
if (!(stream2 instanceof EventEmitter)) {
throw new TypeError('stream2 must be an EventEmitter');
}
if (options.readPolicy === 'least' &&
(typeof stream1.read !== 'function' ||
typeof stream2.read !== 'function')) {
throw new TypeError('streams must have .read() for readPolicy \'least\'');
}
if (typeof options.compare !== 'function') {
throw new TypeError('options.compare must be a function');
}
if (!options.endEvents ||
typeof options.endEvents !== 'object' ||
options.endEvents.length !== options.endEvents.length | 0) {
throw new TypeError('options.endEvents must be Array-like');
}
options.endEvents = Array.prototype.slice.call(options.endEvents);
if (!options.events ||
typeof options.events !== 'object' ||
options.events.length !== options.events.length | 0) {
throw new TypeError('options.events must be Array-like');
}
options.events = Array.prototype.slice.call(options.events);
if (options.incremental && typeof options.incremental !== 'function') {
throw new TypeError('options.incremental must be a function');
}
if (typeof options.readPolicy !== 'string') {
throw new TypeError('options.readPolicy must be a string');
}
if (!ReadPolicy.hasOwnProperty(options.readPolicy)) {
throw new RangeError('Invalid options.readPolicy \'' +
options.readPolicy + '\'');
}
var reject;
var resolve;
var promise = new Promise(function(resolveArg, rejectArg) {
resolve = resolveArg;
reject = rejectArg;
});
var state1 = new StreamState();

@@ -79,11 +236,15 @@ var state2 = new StreamState();

var listeners2 = {};
var endListener1;
var endListener2;
var postEndImmediate;
var postEndTimeout;
/** Gets the name of a stream for logging purposes. */
/** Gets the name of a stream for logging purposes.
* @private
*/
function streamName(stream) {
return stream === stream1 ? 'stream1' : 'stream2';
return stream === stream1 ? 'stream1' :
stream === stream2 ? 'stream2' :
'unknown stream';
}
function done() {
function done(err, result) {
isDone = true;

@@ -97,6 +258,7 @@

stream1.removeListener('readable', readNext);
stream1.removeListener('error', endListener1);
stream1.removeListener('error', done);
stream1.removeListener('error', onStreamError);
stream1.removeListener('end', readNextOnEnd);
stream1.removeListener('end', endListener1);
options.endEvents.forEach(function(eventName) {
stream1.removeListener(eventName, endListener1);
});

@@ -107,36 +269,44 @@ Object.keys(listeners2).forEach(function(eventName) {

stream2.removeListener('readable', readNext);
stream2.removeListener('error', endListener2);
stream2.removeListener('error', done);
stream2.removeListener('error', onStreamError);
stream2.removeListener('end', readNextOnEnd);
stream2.removeListener('end', endListener2);
options.endEvents.forEach(function(eventName) {
stream2.removeListener(eventName, endListener2);
});
debug('All done. Calling callback...');
return callback.apply(this, arguments);
clearImmediate(postEndImmediate);
clearTimeout(postEndTimeout);
debug('Comparison finished.');
}
function doCompare() {
debug('Performing final compare.');
var result, resultErr;
try {
result = options.compare(state1, state2);
} catch (err) {
resultErr = err;
}
done(resultErr, result);
function onStreamError(err) {
debug(streamName(this) + ' emitted error', err);
reject(err);
done();
}
function doneIfIncremental() {
var result, resultErr, threw;
function doCompare(compareFn, type) {
debug('Performing %s compare.', type);
var hasResultOrError = false;
try {
result = options.incremental(state1, state2);
var result = compareFn(state1, state2);
if (result !== undefined && result !== null) {
debug('Comparison produced a result:', result);
hasResultOrError = true;
resolve(result);
}
} catch (err) {
threw = true;
resultErr = err;
debug('Comparison produced an error:', err);
hasResultOrError = true;
reject(err);
}
if ((result !== undefined && result !== null) || threw) {
debug('Incremental comparison was conclusive. Finishing...');
done(resultErr, result);
if (hasResultOrError) {
done();
return true;
} else if (type === CompareType.last) {
resolve();
done();
return true;
}

@@ -147,4 +317,31 @@

/** Compares the states of the two streams non-incrementally.
* @function
* @name StreamComparePromise#checkpoint
*/
promise.checkpoint = function checkpoint() {
if (isDone) {
debug('Ignoring checkpoint() after settling.');
return;
}
doCompare(options.compare, CompareType.checkpoint);
};
/** Compares the states of the two streams non-incrementally then ends the
* comparison whether or not compare produced a result or error.
* @function
* @name StreamComparePromise#end
*/
promise.end = function end() {
if (isDone) {
debug('Ignoring end() after settling.');
return;
}
doCompare(options.compare, CompareType.last);
};
// Note: Add event listeners before endListeners so end/error is recorded
Array.prototype.forEach.call(options.events, function(eventName) {
options.events.forEach(function(eventName) {
if (listeners1[eventName]) {

@@ -159,5 +356,3 @@ return;

function listener() {
debug('\'' + eventName + '\' event from ' + streamName(this) + '.');
function listener(/* event args */) {
this.events.push({

@@ -169,23 +364,32 @@ name: eventName,

if (options.incremental) {
doneIfIncremental();
doCompare(options.incremental, CompareType.incremental);
}
}
listeners1[eventName] = listener.bind(state1);
listeners1[eventName] = function listener1() {
debug('\'' + eventName + '\' event from stream1.');
listener.apply(state1, arguments);
};
stream1.on(eventName, listeners1[eventName]);
listeners2[eventName] = listener.bind(state2);
listeners2[eventName] = function listener2() {
debug('\'' + eventName + '\' event from stream2.');
listener.apply(state2, arguments);
};
stream2.on(eventName, listeners2[eventName]);
});
/** @this {!StreamState} */
function endListener() {
/** Handles stream end events.
* @this {!Readable}
* @private
*/
function endListener(state) {
// Note: If incremental is conclusive for 'end' event, this will be called
// with isDone === true, since removeListener doesn't affect listeners for
// an event which is already in-progress.
if (this.ended || isDone) {
if (state.ended || isDone) {
return;
}
this.ended = true;
state.ended = true;
++ended;

@@ -196,3 +400,3 @@

if (options.incremental) {
if (doneIfIncremental()) {
if (doCompare(options.incremental, CompareType.incremental)) {
return;

@@ -203,10 +407,13 @@ }

if (ended === 2) {
var postEndCompare = function() {
doCompare(options.compare, CompareType.last);
};
if (options.delay) {
debug('All streams have ended. Delaying for ' + options.delay +
'ms before final compare.');
setTimeout(doCompare, options.delay);
postEndTimeout = setTimeout(postEndCompare, options.delay);
} else {
// Let pending I/O and callbacks complete to catch some errant events
debug('All streams have ended. Delaying before final compare.');
setImmediate(doCompare);
postEndImmediate = setImmediate(postEndCompare);
}

@@ -216,14 +423,18 @@ }

endListener1 = endListener.bind(state1);
stream1.on('end', endListener1);
function endListener1() {
endListener.call(this, state1);
}
function endListener2() {
endListener.call(this, state2);
}
options.endEvents.forEach(function(eventName) {
if (!options.abortOnError || eventName !== 'error') {
stream1.on(eventName, endListener1);
stream2.on(eventName, endListener2);
}
});
endListener2 = endListener.bind(state2);
stream2.on('end', endListener2);
if (options.abortOnError) {
stream1.once('error', done);
stream2.once('error', done);
} else {
stream1.on('error', endListener1);
stream2.on('error', endListener2);
stream1.once('error', onStreamError);
stream2.once('error', onStreamError);
}

@@ -239,2 +450,3 @@

* @param {*} data Data read from the stream for this StreamState.
* @private
*/

@@ -284,8 +496,14 @@ function addData(data) {

/** Handles data read from the stream for a given state. */
/** Handles data read from the stream for a given state.
* @private
*/
function handleData(state, data) {
debug('Read data from ', streamName(this));
try {
addData.call(state, data);
} catch (err) {
done(err);
debug('Error adding data from ' + streamName(this), err);
reject(err);
done();
return;

@@ -295,7 +513,9 @@ }

if (options.incremental) {
doneIfIncremental();
doCompare(options.incremental, CompareType.incremental);
}
}
/** Reads from the non-ended stream which has the smallest totalDataLen. */
/** Reads from the non-ended stream which has the smallest totalDataLen.
* @private
*/
function readNext() {

@@ -324,3 +544,3 @@ var stream, state;

handleData(state, data);
handleData.call(stream, state, data);
}

@@ -334,2 +554,4 @@ }

* from the other stream.
*
* @private
*/

@@ -351,4 +573,4 @@ function readNextOnEnd() {

debug('Will read from streams in flowing mode.');
stream1.on('data', handleData.bind(null, state1));
stream2.on('data', handleData.bind(null, state2));
stream1.on('data', handleData.bind(stream1, state1));
stream2.on('data', handleData.bind(stream2, state2));
break;

@@ -360,3 +582,3 @@

stream2.once('end', readNextOnEnd);
readNext();
process.nextTick(readNext);
break;

@@ -368,128 +590,4 @@

}
}
/** Compares the output of two Readable streams.
*
* Options:
* - abortOnError: Abort comparison and return error emitted by either stream.
* (default: false)
* - compare: Comparison function which will be called with a StreamState
* object for each stream, after both streams have ended. The value
* returned by this function will resolve the returned promise and be passed
* to the callback as its second argument. A value thrown by this function
* will reject the promise and be passed to the callback as its first
* argument.
* This function is required if incremental is not specified.
* - delay: Additional delay (in ms) after streams end before comparing.
* (default: 0)
* - events: Names of events to compare. (default: ['close', 'end', 'error'])
* - incremental: Incremental comparison function which will be called
* periodically with a StreamState object for each stream. This function
* may modify the StreamState objects to remove data not required for later
* comparisons (e.g. common output) and may perform the comparison before
* the streams have ended (e.g. due to early differences). Any non-null,
* non-undefined value returned by this function will finish the comparison,
* resolve the returned promise, and be passed to the callback as its second
* argument. A value thrown by this function will finish the comparison,
* reject the promise and be passed to the callback as its first argument.
* If compare is not specified, this function will also be called for the
* final comparison.
* - objectMode: Collect values read into an Array. This allows comparison
* of read values without concatenation and comparison of non-string/Buffer
* types.
* - readPolicy: Scheduling discipline for reads from the streams.
* - 'flowing': Reads are done concurrently using 'data' events.
* - 'least': Reads from the stream which has output the least data, measured
* in bytes/chars for non-objectMode or values for objectMode.
* - 'none': No reads are done. When using this readPolicy, be sure to
* either add 'data' to events, add other 'data' listeners, .read() the
* data elsewhere, or call .resume() on the streams so that the data will
* be read and 'end' can be reached.
* (default: 'least')
*
* @param {!stream.Readable} stream1 First stream to compare.
* @param {!stream.Readable} stream2 Second stream to compare.
* @param {!Object|function(!StreamState,!StreamState)} optionsOrCompare
* Options, or a comparison function (as described in options.compare).
* @param {?function(Error, Object=)=} callback Callback with comparison result
* or error.
* @return {Promise|undefined} If <code>callback</code> is not given and
* <code>global.Promise</code> is defined, a <code>Promise</code> with the
* comparison result or error.
*/
function streamCompare(stream1, stream2, optionsOrCompare, callback) {
if (!callback && typeof Promise === 'function') {
// eslint-disable-next-line no-undef
return new Promise(function(resolve, reject) {
streamCompare(stream1, stream2, optionsOrCompare, function(err, result) {
if (err) { reject(err); } else { resolve(result); }
});
});
}
if (typeof callback !== 'function') {
throw new TypeError('callback must be a function');
}
// From this point on errors are returned using callback. As long as callers
// pass a callback or have global.Promise, this function will never throw and
// callers don't need to wrap in a try/catch.
var options;
try {
if (optionsOrCompare) {
if (typeof optionsOrCompare === 'function') {
options = {compare: optionsOrCompare};
} else if (typeof optionsOrCompare === 'object') {
options = optionsOrCompare;
} else {
throw new TypeError('optionsOrCompare must be an object or function');
}
}
options = extend({}, DEFAULT_OPTIONS, options);
if (!options.compare) {
options.compare = options.incremental;
}
// Can change this to duck typing if there are non-EventEmitter streams
if (!(stream1 instanceof EventEmitter)) {
throw new TypeError('stream1 must be an EventEmitter');
}
// Can change this to duck typing if there are non-EventEmitter streams
if (!(stream2 instanceof EventEmitter)) {
throw new TypeError('stream2 must be an EventEmitter');
}
if (options.readPolicy === 'least' &&
(typeof stream1.read !== 'function' ||
typeof stream2.read !== 'function')) {
throw new TypeError('streams must have .read() for readPolicy \'least\'');
}
if (typeof options.compare !== 'function') {
throw new TypeError('options.compare must be a function');
}
if (!options.events ||
typeof options.events !== 'object' ||
options.events.length !== options.events.length | 0) {
throw new TypeError('options.events must be Array-like');
}
if (options.incremental && typeof options.incremental !== 'function') {
throw new TypeError('options.incremental must be a function');
}
if (typeof options.readPolicy !== 'string') {
throw new TypeError('options.readPolicy must be a string');
}
if (!ReadPolicy.hasOwnProperty(options.readPolicy)) {
throw new RangeError('Invalid options.readPolicy \'' +
options.readPolicy + '\'');
}
} catch (err) {
process.nextTick(function() {
callback(err);
});
return undefined;
}
streamCompareInternal(stream1, stream2, options, callback);
return undefined;
return promise;
}

@@ -496,0 +594,0 @@

@@ -8,3 +8,14 @@ /**

/** Incrementally compares and reduces an Array-like property of the states
* using a given comparison function. */
* using a given comparison function.
*
* @ template CompareResult
* @param {!StreamState} state1 First state to compare.
* @param {!StreamState} state2 Second state to compare.
* @param {string} propName Name of Array-like property to compare.
* @param {function(*, *): CompareResult} compare Comparison function to apply
* to the <code>propName</code> values from each state.
* @return {CompareResult} Result of comparing <code>propName</code> values, up
* to the minimum common length.
* @private
*/
function incrementalProp(state1, state2, propName, compare) {

@@ -43,18 +54,22 @@ var values1 = state1[propName];

*
* Given a function which compares output data (e.g. assert.deepStrictEqual),
* this function returns an incremental comparison function which compares
* only the amount of data output by both streams (unless the stream has ended,
* in which case all remaining data is compared) and removes the compared data
* if no comparison result is returned/thrown.
* Given a function which compares output data (e.g.
* <code>assert.deepStrictEqual</code>), this function returns an incremental
* comparison function which compares only the amount of data output by both
* streams (unless the stream has ended, in which case all remaining data is
* compared) and removes the compared data if no comparison result is
* returned/thrown.
*
* @param {function((string|Buffer|Array), (string|Buffer|Array))} compareData
* Data comparison function which will be called with data output by each
* @ template CompareResult
* @param {function((string|Buffer|Array), (string|Buffer|Array)):
* CompareResult} compareData Data comparison function which will be called
* with data output by each stream.
* @param {?function(!Array<!{name:string,args:Array}>,
* !Array<!{name:string,args:Array}>): CompareResult=} compareEvents Events
* comparison function which will be called with the events output by each
* stream.
* @param {?function(!Array.<!{name:string,args:Array}>,
* !Array.<!{name:string,args:Array}>)=} compareEvents Events comparison
* function which will be called with be called with with events output by
* each stream.
* @returns {function(!StreamState, !StreamState)} Incremental comparison
* function which compares the stream states using compareData and
* compareEvents, and removes compared values if no result is reached.
* @returns {function(!StreamState, !StreamState): CompareResult} Incremental
* comparison function which compares the stream states using
* <code>compareData</code> and <code>compareEvents</code>, and removes
* compared values if no result is reached.
* @alias makeIncremental
*/

@@ -61,0 +76,0 @@ module.exports = function makeIncremental(compareData, compareEvents) {

{
"name": "stream-compare",
"version": "0.1.0",
"version": "0.2.0",
"description": "Compare the behavior of readable streams.",

@@ -32,3 +32,3 @@ "keywords": [

"postversion": "rimraf doc && git clone -b gh-pages -l -q . doc && npm run doc && git -C doc add . && git -C doc commit -n -m \"Docs for v$npm_package_version\"",
"preversion": "git-branch-is master && travis-status -b -c -qwx && depcheck && david",
"preversion": "git-branch-is master && travis-status -b -c -qwx && depcheck --ignores bluebird && david",
"test": "npm run lint && npm run test-unit",

@@ -43,2 +43,3 @@ "test-cov": "npm run lint && npm run test-unit-cov",

"dependencies": {
"any-promise": "^1.1.0",
"debug": "^2.2.0",

@@ -53,3 +54,4 @@ "extend": "^3.0.0"

"eslint": "^2.3.0",
"eslint-config-airbnb": "^6.0.1",
"eslint-config-airbnb-base": "^1.0.3",
"eslint-plugin-import": "^1.5.0",
"istanbul": "^0.4.1",

@@ -56,0 +58,0 @@ "jsdoc": "^3.4.0",

@@ -22,3 +22,3 @@ stream-compare

var stream2 = fs.createReadStream(file);
streamCompare(stream1, stream2, assert.deepStrictEqual, function(err) {
streamCompare(stream1, stream2, assert.deepStrictEqual).catch(function(err) {
console.log(err); // AssertionError if streams differ

@@ -36,3 +36,3 @@ });

- Support for caller-defined comparisons, which can return errors or values
and are not limited to equality.
not limited to equality.
- Support for both incremental and one-shot comparisons.

@@ -82,3 +82,3 @@ - Support for caller-defined data reduction to avoid storing the entire stream

};
streamCompare(stream1, stream2, options, function(err) {
streamCompare(stream1, stream2, options).catch(function(err) {
console.log(err); // AssertionError if stream data values differ

@@ -99,3 +99,3 @@ });

};
streamCompare(stream1, stream2, options, function(err) {
streamCompare(stream1, stream2, options).catch(function(err) {
console.log(err); // AssertionError if stream data values differ

@@ -118,3 +118,3 @@ });

};
streamCompare(stream1, stream2, options, function(err) {
streamCompare(stream1, stream2, options).catch(function(err) {
console.log(err); // AssertionError if stream events (including 'data') differ

@@ -124,2 +124,34 @@ });

### Control comparison checkpoints
The returned Promise includes additional methods for controlling the
comparison. A non-incremental compare can be run before both streams end
using `.checkpoint()`. Additionally, the comparison can be concluded before
both streams end using `.end()`. The full details are available in the [API
Documentation](https://kevinoid.github.io/stream-compare/api/StreamComparePromise.html).
```js
var PassThrough = require('stream').PassThrough;
var stream1 = new PassThrough();
var stream2 = new PassThrough();
var comparison = streamCompare(stream1, stream2, assert.deepStrictEqual);
comparison.then(
function() { console.log('streams are equal'); },
function(err) { console.log('streams differ: ' + err); }
);
stream1.write('Hello');
stream2.write('Hello');
process.nextTick(function() {
comparison.checkpoint();
stream1.write(' world!');
stream2.write(' world!');
process.nextTick(function() {
comparison.end();
});
});
```
More examples can be found in the [test

@@ -126,0 +158,0 @@ specifications](https://kevinoid.github.io/stream-compare/specs).

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc