├── .gitignore ├── .npmignore ├── .travis.yml ├── License ├── Makefile ├── Readme.md ├── lib └── combined_stream.js ├── package.json └── test ├── common.js ├── fixture ├── file1.txt └── file2.txt ├── integration ├── test-callback-streams.js ├── test-data-size.js ├── test-delayed-streams-and-buffers-and-strings.js ├── test-delayed-streams.js ├── test-empty-string.js ├── test-is-stream-like.js ├── test-max-data-size.js ├── test-pipe-memory-leak.js ├── test-recursion-append.js ├── test-recursion-callback.js └── test-unpaused-streams.js └── run.js /.gitignore: -------------------------------------------------------------------------------- 1 | *.un~ 2 | *.log 3 | /node_modules 4 | /test/tmp 5 | yarn.lock 6 | 7 | Vim swap files 8 | .*.sw[a-z] 9 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | .npmignore 3 | .travis.yml 4 | Makefile 5 | *.un~ 6 | /node_modules 7 | /test 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | - "0.12" 5 | - "4" 6 | - "6" 7 | - "8" 8 | - "10" 9 | -------------------------------------------------------------------------------- /License: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Debuggable Limited 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL := /bin/bash 2 | 3 | test: 4 | @./test/run.js 5 | 6 | .PHONY: test 7 | 8 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # combined-stream 2 | 3 | A stream that emits multiple other streams one after another. 4 | 5 | **NB** Currently `combined-stream` works with streams version 1 only. There is ongoing effort to switch this library to streams version 2. Any help is welcome. :) Meanwhile you can explore other libraries that provide streams2 support with more or less compatibility with `combined-stream`. 6 | 7 | - [combined-stream2](https://www.npmjs.com/package/combined-stream2): A drop-in streams2-compatible replacement for the combined-stream module. 8 | 9 | - [multistream](https://www.npmjs.com/package/multistream): A stream that emits multiple other streams one after another. 10 | 11 | ## Installation 12 | 13 | ``` bash 14 | npm install combined-stream 15 | ``` 16 | 17 | ## Usage 18 | 19 | Here is a simple example that shows how you can use combined-stream to combine 20 | two files into one: 21 | 22 | ``` javascript 23 | var CombinedStream = require('combined-stream'); 24 | var fs = require('fs'); 25 | 26 | var combinedStream = CombinedStream.create(); 27 | combinedStream.append(fs.createReadStream('file1.txt')); 28 | combinedStream.append(fs.createReadStream('file2.txt')); 29 | 30 | combinedStream.pipe(fs.createWriteStream('combined.txt')); 31 | ``` 32 | 33 | While the example above works great, it will pause all source streams until 34 | they are needed. If you don't want that to happen, you can set `pauseStreams` 35 | to `false`: 36 | 37 | ``` javascript 38 | var CombinedStream = require('combined-stream'); 39 | var fs = require('fs'); 40 | 41 | var combinedStream = CombinedStream.create({pauseStreams: false}); 42 | combinedStream.append(fs.createReadStream('file1.txt')); 43 | combinedStream.append(fs.createReadStream('file2.txt')); 44 | 45 | combinedStream.pipe(fs.createWriteStream('combined.txt')); 46 | ``` 47 | 48 | However, what if you don't have all the source streams yet, or you don't want 49 | to allocate the resources (file descriptors, memory, etc.) for them right away? 50 | Well, in that case you can simply provide a callback that supplies the stream 51 | by calling a `next()` function: 52 | 53 | ``` javascript 54 | var CombinedStream = require('combined-stream'); 55 | var fs = require('fs'); 56 | 57 | var combinedStream = CombinedStream.create(); 58 | combinedStream.append(function(next) { 59 | next(fs.createReadStream('file1.txt')); 60 | }); 61 | combinedStream.append(function(next) { 62 | next(fs.createReadStream('file2.txt')); 63 | }); 64 | 65 | combinedStream.pipe(fs.createWriteStream('combined.txt')); 66 | ``` 67 | 68 | ## API 69 | 70 | ### CombinedStream.create([options]) 71 | 72 | Returns a new combined stream object. Available options are: 73 | 74 | * `maxDataSize` 75 | * `pauseStreams` 76 | 77 | The effect of those options is described below. 78 | 79 | ### combinedStream.pauseStreams = `true` 80 | 81 | Whether to apply back pressure to the underlaying streams. If set to `false`, 82 | the underlaying streams will never be paused. If set to `true`, the 83 | underlaying streams will be paused right after being appended, as well as when 84 | `delayedStream.pipe()` wants to throttle. 85 | 86 | ### combinedStream.maxDataSize = `2 * 1024 * 1024` 87 | 88 | The maximum amount of bytes (or characters) to buffer for all source streams. 89 | If this value is exceeded, `combinedStream` emits an `'error'` event. 90 | 91 | ### combinedStream.dataSize = `0` 92 | 93 | The amount of bytes (or characters) currently buffered by `combinedStream`. 94 | 95 | ### combinedStream.append(stream) 96 | 97 | Appends the given `stream` to the combinedStream object. If `pauseStreams` is 98 | set to `true, this stream will also be paused right away. 99 | 100 | `streams` can also be a function that takes one parameter called `next`. `next` 101 | is a function that must be invoked in order to provide the `next` stream, see 102 | example above. 103 | 104 | Regardless of how the `stream` is appended, combined-stream always attaches an 105 | `'error'` listener to it, so you don't have to do that manually. 106 | 107 | Special case: `stream` can also be a String or Buffer. 108 | 109 | ### combinedStream.write(data) 110 | 111 | You should not call this, `combinedStream` takes care of piping the appended 112 | streams into itself for you. 113 | 114 | ### combinedStream.resume() 115 | 116 | Causes `combinedStream` to start drain the streams it manages. The function is 117 | idempotent, and also emits a `'resume'` event each time which usually goes to 118 | the stream that is currently being drained. 119 | 120 | ### combinedStream.pause(); 121 | 122 | If `combinedStream.pauseStreams` is set to `false`, this does nothing. 123 | Otherwise a `'pause'` event is emitted, this goes to the stream that is 124 | currently being drained, so you can use it to apply back pressure. 125 | 126 | ### combinedStream.end(); 127 | 128 | Sets `combinedStream.writable` to false, emits an `'end'` event, and removes 129 | all streams from the queue. 130 | 131 | ### combinedStream.destroy(); 132 | 133 | Same as `combinedStream.end()`, except it emits a `'close'` event instead of 134 | `'end'`. 135 | 136 | ## License 137 | 138 | combined-stream is licensed under the MIT license. 139 | -------------------------------------------------------------------------------- /lib/combined_stream.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var Stream = require('stream').Stream; 3 | var DelayedStream = require('delayed-stream'); 4 | 5 | module.exports = CombinedStream; 6 | function CombinedStream() { 7 | this.writable = false; 8 | this.readable = true; 9 | this.dataSize = 0; 10 | this.maxDataSize = 2 * 1024 * 1024; 11 | this.pauseStreams = true; 12 | 13 | this._released = false; 14 | this._streams = []; 15 | this._currentStream = null; 16 | this._insideLoop = false; 17 | this._pendingNext = false; 18 | } 19 | util.inherits(CombinedStream, Stream); 20 | 21 | CombinedStream.create = function(options) { 22 | var combinedStream = new this(); 23 | 24 | options = options || {}; 25 | for (var option in options) { 26 | combinedStream[option] = options[option]; 27 | } 28 | 29 | return combinedStream; 30 | }; 31 | 32 | CombinedStream.isStreamLike = function(stream) { 33 | return (typeof stream !== 'function') 34 | && (typeof stream !== 'string') 35 | && (typeof stream !== 'boolean') 36 | && (typeof stream !== 'number') 37 | && (!Buffer.isBuffer(stream)); 38 | }; 39 | 40 | CombinedStream.prototype.append = function(stream) { 41 | var isStreamLike = CombinedStream.isStreamLike(stream); 42 | 43 | if (isStreamLike) { 44 | if (!(stream instanceof DelayedStream)) { 45 | var newStream = DelayedStream.create(stream, { 46 | maxDataSize: Infinity, 47 | pauseStream: this.pauseStreams, 48 | }); 49 | stream.on('data', this._checkDataSize.bind(this)); 50 | stream = newStream; 51 | } 52 | 53 | this._handleErrors(stream); 54 | 55 | if (this.pauseStreams) { 56 | stream.pause(); 57 | } 58 | } 59 | 60 | this._streams.push(stream); 61 | return this; 62 | }; 63 | 64 | CombinedStream.prototype.pipe = function(dest, options) { 65 | Stream.prototype.pipe.call(this, dest, options); 66 | this.resume(); 67 | return dest; 68 | }; 69 | 70 | CombinedStream.prototype._getNext = function() { 71 | this._currentStream = null; 72 | 73 | if (this._insideLoop) { 74 | this._pendingNext = true; 75 | return; // defer call 76 | } 77 | 78 | this._insideLoop = true; 79 | try { 80 | do { 81 | this._pendingNext = false; 82 | this._realGetNext(); 83 | } while (this._pendingNext); 84 | } finally { 85 | this._insideLoop = false; 86 | } 87 | }; 88 | 89 | CombinedStream.prototype._realGetNext = function() { 90 | var stream = this._streams.shift(); 91 | 92 | 93 | if (typeof stream == 'undefined') { 94 | this.end(); 95 | return; 96 | } 97 | 98 | if (typeof stream !== 'function') { 99 | this._pipeNext(stream); 100 | return; 101 | } 102 | 103 | var getStream = stream; 104 | getStream(function(stream) { 105 | var isStreamLike = CombinedStream.isStreamLike(stream); 106 | if (isStreamLike) { 107 | stream.on('data', this._checkDataSize.bind(this)); 108 | this._handleErrors(stream); 109 | } 110 | 111 | this._pipeNext(stream); 112 | }.bind(this)); 113 | }; 114 | 115 | CombinedStream.prototype._pipeNext = function(stream) { 116 | this._currentStream = stream; 117 | 118 | var isStreamLike = CombinedStream.isStreamLike(stream); 119 | if (isStreamLike) { 120 | stream.on('end', this._getNext.bind(this)); 121 | stream.pipe(this, {end: false}); 122 | return; 123 | } 124 | 125 | var value = stream; 126 | this.write(value); 127 | this._getNext(); 128 | }; 129 | 130 | CombinedStream.prototype._handleErrors = function(stream) { 131 | var self = this; 132 | stream.on('error', function(err) { 133 | self._emitError(err); 134 | }); 135 | }; 136 | 137 | CombinedStream.prototype.write = function(data) { 138 | this.emit('data', data); 139 | }; 140 | 141 | CombinedStream.prototype.pause = function() { 142 | if (!this.pauseStreams) { 143 | return; 144 | } 145 | 146 | if(this.pauseStreams && this._currentStream && typeof(this._currentStream.pause) == 'function') this._currentStream.pause(); 147 | this.emit('pause'); 148 | }; 149 | 150 | CombinedStream.prototype.resume = function() { 151 | if (!this._released) { 152 | this._released = true; 153 | this.writable = true; 154 | this._getNext(); 155 | } 156 | 157 | if(this.pauseStreams && this._currentStream && typeof(this._currentStream.resume) == 'function') this._currentStream.resume(); 158 | this.emit('resume'); 159 | }; 160 | 161 | CombinedStream.prototype.end = function() { 162 | this._reset(); 163 | this.emit('end'); 164 | }; 165 | 166 | CombinedStream.prototype.destroy = function() { 167 | this._reset(); 168 | this.emit('close'); 169 | }; 170 | 171 | CombinedStream.prototype._reset = function() { 172 | this.writable = false; 173 | this._streams = []; 174 | this._currentStream = null; 175 | }; 176 | 177 | CombinedStream.prototype._checkDataSize = function() { 178 | this._updateDataSize(); 179 | if (this.dataSize <= this.maxDataSize) { 180 | return; 181 | } 182 | 183 | var message = 184 | 'DelayedStream#maxDataSize of ' + this.maxDataSize + ' bytes exceeded.'; 185 | this._emitError(new Error(message)); 186 | }; 187 | 188 | CombinedStream.prototype._updateDataSize = function() { 189 | this.dataSize = 0; 190 | 191 | var self = this; 192 | this._streams.forEach(function(stream) { 193 | if (!stream.dataSize) { 194 | return; 195 | } 196 | 197 | self.dataSize += stream.dataSize; 198 | }); 199 | 200 | if (this._currentStream && this._currentStream.dataSize) { 201 | this.dataSize += this._currentStream.dataSize; 202 | } 203 | }; 204 | 205 | CombinedStream.prototype._emitError = function(err) { 206 | this._reset(); 207 | this.emit('error', err); 208 | }; 209 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Felix Geisendörfer (http://debuggable.com/)", 3 | "name": "combined-stream", 4 | "description": "A stream that emits multiple other streams one after another.", 5 | "version": "1.0.8", 6 | "homepage": "https://github.com/felixge/node-combined-stream", 7 | "repository": { 8 | "type": "git", 9 | "url": "git://github.com/felixge/node-combined-stream.git" 10 | }, 11 | "main": "./lib/combined_stream", 12 | "scripts": { 13 | "test": "node test/run.js" 14 | }, 15 | "engines": { 16 | "node": ">= 0.8" 17 | }, 18 | "dependencies": { 19 | "delayed-stream": "~1.0.0" 20 | }, 21 | "devDependencies": { 22 | "far": "~0.0.7" 23 | }, 24 | "license": "MIT" 25 | } 26 | -------------------------------------------------------------------------------- /test/common.js: -------------------------------------------------------------------------------- 1 | var common = module.exports; 2 | 3 | var path = require('path'); 4 | var fs = require('fs'); 5 | var root = path.join(__dirname, '..'); 6 | 7 | common.dir = { 8 | fixture: root + '/test/fixture', 9 | tmp: root + '/test/tmp', 10 | }; 11 | 12 | // Create tmp directory if it does not exist 13 | // Not using fs.exists so as to be node 0.6.x compatible 14 | try { 15 | fs.statSync(common.dir.tmp); 16 | } 17 | catch (e) { 18 | // Dir does not exist 19 | fs.mkdirSync(common.dir.tmp); 20 | } 21 | 22 | common.CombinedStream = require(root); 23 | common.assert = require('assert'); 24 | -------------------------------------------------------------------------------- /test/fixture/file1.txt: -------------------------------------------------------------------------------- 1 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 2 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 3 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 4 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 5 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 6 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 7 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 8 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 9 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 10 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 11 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 12 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 13 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 14 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 15 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 16 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 17 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 18 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 19 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 20 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 21 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 22 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 23 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 24 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 25 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 26 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 27 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 28 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 29 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 30 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 31 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 32 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 33 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 34 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 35 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 36 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 37 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 38 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 39 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 40 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 41 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 42 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 43 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 44 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 45 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 46 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 47 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 48 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 49 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 50 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 51 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 52 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 53 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 54 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 55 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 56 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 57 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 58 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 59 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 60 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 61 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 62 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 63 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 64 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 65 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 66 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 67 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 68 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 69 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 70 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 71 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 72 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 73 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 74 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 75 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 76 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 77 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 78 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 79 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 80 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 81 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 82 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 83 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 84 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 85 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 86 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 87 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 88 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 89 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 90 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 91 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 92 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 93 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 94 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 95 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 96 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 97 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 98 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 99 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 100 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 101 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 102 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 103 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 104 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 105 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 106 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 107 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 108 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 109 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 110 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 111 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 112 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 113 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 114 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 115 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 116 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 117 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 118 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 119 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 120 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 121 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 122 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 123 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 124 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 125 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 126 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 127 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 128 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 129 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 130 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 131 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 132 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 133 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 134 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 135 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 136 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 137 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 138 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 139 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 140 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 141 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 142 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 143 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 144 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 145 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 146 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 147 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 148 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 149 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 150 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 151 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 152 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 153 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 154 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 155 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 156 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 157 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 158 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 159 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 160 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 161 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 162 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 163 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 164 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 165 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 166 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 167 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 168 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 169 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 170 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 171 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 172 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 173 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 174 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 175 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 176 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 177 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 178 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 179 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 180 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 181 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 182 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 183 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 184 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 185 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 186 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 187 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 188 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 189 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 190 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 191 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 192 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 193 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 194 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 195 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 196 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 197 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 198 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 199 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 200 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 201 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 202 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 203 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 204 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 205 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 206 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 207 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 208 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 209 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 210 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 211 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 212 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 213 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 214 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 215 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 216 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 217 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 218 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 219 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 220 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 221 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 222 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 223 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 224 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 225 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 226 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 227 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 228 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 229 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 230 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 231 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 232 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 233 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 234 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 235 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 236 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 237 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 238 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 239 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 240 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 241 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 242 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 243 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 244 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 245 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 246 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 247 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 248 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 249 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 250 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 251 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 252 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 253 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 254 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 255 | 10101010101010101010101010101010101010101010101010101010101010101010101010101010 256 | 01010101010101010101010101010101010101010101010101010101010101010101010101010101 257 | -------------------------------------------------------------------------------- /test/fixture/file2.txt: -------------------------------------------------------------------------------- 1 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 2 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 3 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 4 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 5 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 6 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 7 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 8 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 9 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 10 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 11 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 12 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 13 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 14 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 15 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 16 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 17 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 18 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 19 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 20 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 21 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 22 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 23 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 24 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 25 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 26 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 27 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 28 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 29 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 30 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 31 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 32 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 33 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 34 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 35 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 36 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 37 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 38 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 39 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 40 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 41 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 42 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 43 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 44 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 45 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 46 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 47 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 48 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 49 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 50 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 51 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 52 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 53 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 54 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 55 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 56 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 57 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 58 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 59 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 60 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 61 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 62 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 63 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 64 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 65 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 66 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 67 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 68 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 69 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 70 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 71 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 72 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 73 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 74 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 75 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 76 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 77 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 78 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 79 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 80 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 81 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 82 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 83 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 84 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 85 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 86 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 87 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 88 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 89 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 90 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 91 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 92 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 93 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 94 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 95 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 96 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 97 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 98 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 99 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 100 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 101 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 102 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 103 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 104 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 105 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 106 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 107 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 108 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 109 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 110 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 111 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 112 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 113 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 114 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 115 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 116 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 117 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 118 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 119 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 120 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 121 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 122 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 123 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 124 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 125 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 126 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 127 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 128 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 129 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 130 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 131 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 132 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 133 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 134 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 135 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 136 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 137 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 138 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 139 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 140 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 141 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 142 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 143 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 144 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 145 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 146 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 147 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 148 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 149 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 150 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 151 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 152 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 153 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 154 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 155 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 156 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 157 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 158 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 159 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 160 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 161 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 162 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 163 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 164 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 165 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 166 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 167 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 168 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 169 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 170 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 171 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 172 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 173 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 174 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 175 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 176 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 177 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 178 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 179 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 180 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 181 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 182 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 183 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 184 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 185 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 186 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 187 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 188 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 189 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 190 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 191 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 192 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 193 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 194 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 195 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 196 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 197 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 198 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 199 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 200 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 201 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 202 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 203 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 204 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 205 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 206 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 207 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 208 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 209 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 210 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 211 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 212 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 213 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 214 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 215 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 216 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 217 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 218 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 219 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 220 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 221 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 222 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 223 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 224 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 225 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 226 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 227 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 228 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 229 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 230 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 231 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 232 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 233 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 234 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 235 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 236 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 237 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 238 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 239 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 240 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 241 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 242 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 243 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 244 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 245 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 246 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 247 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 248 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 249 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 250 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 251 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 252 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 253 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 254 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 255 | 20202020202020202020202020202020202020202020202020202020202020202020202020202020 256 | 02020202020202020202020202020202020202020202020202020202020202020202020202020202 257 | -------------------------------------------------------------------------------- /test/integration/test-callback-streams.js: -------------------------------------------------------------------------------- 1 | var common = require('../common'); 2 | var assert = common.assert; 3 | var CombinedStream = common.CombinedStream; 4 | var fs = require('fs'); 5 | 6 | var FILE1 = common.dir.fixture + '/file1.txt'; 7 | var FILE2 = common.dir.fixture + '/file2.txt'; 8 | var EXPECTED = fs.readFileSync(FILE1) + fs.readFileSync(FILE2); 9 | var written; 10 | 11 | (function testDelayedStreams() { 12 | var combinedStream = CombinedStream.create(); 13 | combinedStream.append(function(next) { 14 | next(fs.createReadStream(FILE1)); 15 | }); 16 | combinedStream.append(function(next) { 17 | next(fs.createReadStream(FILE2)); 18 | }); 19 | 20 | var tmpFile = common.dir.tmp + '/combined.txt'; 21 | var dest = fs.createWriteStream(tmpFile); 22 | combinedStream.pipe(dest); 23 | 24 | dest.on('close', function() { 25 | written = fs.readFileSync(tmpFile, 'utf8'); 26 | }); 27 | })(); 28 | 29 | process.on('exit', function () { 30 | assert.strictEqual(written, EXPECTED); 31 | }); 32 | -------------------------------------------------------------------------------- /test/integration/test-data-size.js: -------------------------------------------------------------------------------- 1 | var common = require('../common'); 2 | var assert = common.assert; 3 | var CombinedStream = common.CombinedStream; 4 | 5 | (function testDataSizeGetter() { 6 | var combinedStream = CombinedStream.create(); 7 | 8 | assert.strictEqual(combinedStream.dataSize, 0); 9 | 10 | // Test one stream 11 | combinedStream._streams.push({dataSize: 10}); 12 | combinedStream._updateDataSize(); 13 | assert.strictEqual(combinedStream.dataSize, 10); 14 | 15 | // Test two streams 16 | combinedStream._streams.push({dataSize: 23}); 17 | combinedStream._updateDataSize(); 18 | assert.strictEqual(combinedStream.dataSize, 33); 19 | 20 | // Test currentStream 21 | combinedStream._currentStream = {dataSize: 20}; 22 | combinedStream._updateDataSize(); 23 | assert.strictEqual(combinedStream.dataSize, 53); 24 | 25 | // Test currentStream without dataSize 26 | combinedStream._currentStream = {}; 27 | combinedStream._updateDataSize(); 28 | assert.strictEqual(combinedStream.dataSize, 33); 29 | 30 | // Test stream function 31 | combinedStream._streams.push(function() {}); 32 | combinedStream._updateDataSize(); 33 | assert.strictEqual(combinedStream.dataSize, 33); 34 | })(); 35 | -------------------------------------------------------------------------------- /test/integration/test-delayed-streams-and-buffers-and-strings.js: -------------------------------------------------------------------------------- 1 | var common = require('../common'); 2 | var assert = common.assert; 3 | var CombinedStream = common.CombinedStream; 4 | var fs = require('fs'); 5 | 6 | var FILE1 = common.dir.fixture + '/file1.txt'; 7 | var BUFFER = new Buffer('Bacon is delicious'); 8 | var FILE2 = common.dir.fixture + '/file2.txt'; 9 | var STRING = 'The € kicks the $\'s ass!'; 10 | 11 | var EXPECTED = 12 | fs.readFileSync(FILE1) 13 | + BUFFER 14 | + fs.readFileSync(FILE2) 15 | + STRING; 16 | var GOT; 17 | 18 | (function testDelayedStreams() { 19 | var combinedStream = CombinedStream.create(); 20 | combinedStream.append(fs.createReadStream(FILE1)); 21 | combinedStream.append(BUFFER); 22 | combinedStream.append(fs.createReadStream(FILE2)); 23 | combinedStream.append(function(next) { 24 | next(STRING); 25 | }); 26 | 27 | var tmpFile = common.dir.tmp + '/combined-file1-buffer-file2-string.txt'; 28 | var dest = fs.createWriteStream(tmpFile); 29 | combinedStream.pipe(dest); 30 | 31 | dest.on('close', function() { 32 | GOT = fs.readFileSync(tmpFile, 'utf8'); 33 | }); 34 | })(); 35 | 36 | process.on('exit', function() { 37 | assert.strictEqual(GOT, EXPECTED); 38 | }); 39 | -------------------------------------------------------------------------------- /test/integration/test-delayed-streams.js: -------------------------------------------------------------------------------- 1 | var common = require('../common'); 2 | var assert = common.assert; 3 | var CombinedStream = common.CombinedStream; 4 | var fs = require('fs'); 5 | 6 | var FILE1 = common.dir.fixture + '/file1.txt'; 7 | var FILE2 = common.dir.fixture + '/file2.txt'; 8 | var EXPECTED = fs.readFileSync(FILE1) + fs.readFileSync(FILE2); 9 | var GOT; 10 | 11 | (function testDelayedStreams() { 12 | var combinedStream = CombinedStream.create(); 13 | combinedStream.append(fs.createReadStream(FILE1)); 14 | combinedStream.append(fs.createReadStream(FILE2)); 15 | 16 | var stream1 = combinedStream._streams[0]; 17 | var stream2 = combinedStream._streams[1]; 18 | 19 | stream1.on('end', function() { 20 | assert.equal(stream2.dataSize, 0); 21 | }); 22 | 23 | var tmpFile = common.dir.tmp + '/combined.txt'; 24 | var dest = fs.createWriteStream(tmpFile); 25 | combinedStream.pipe(dest); 26 | 27 | dest.on('close', function() { 28 | GOT = fs.readFileSync(tmpFile, 'utf8'); 29 | }); 30 | })(); 31 | 32 | process.on('exit', function() { 33 | console.error(GOT.length, EXPECTED.length); 34 | assert.strictEqual(GOT, EXPECTED); 35 | }); 36 | -------------------------------------------------------------------------------- /test/integration/test-empty-string.js: -------------------------------------------------------------------------------- 1 | var common = require('../common'); 2 | var assert = common.assert; 3 | var CombinedStream = common.CombinedStream; 4 | var util = require('util'); 5 | var Stream = require('stream').Stream; 6 | 7 | var s = CombinedStream.create(); 8 | 9 | 10 | function StringStream(){ 11 | this.writable=true; 12 | this.str="" 13 | } 14 | util.inherits(StringStream,Stream); 15 | 16 | StringStream.prototype.write=function(chunk,encoding){ 17 | this.str+=chunk.toString(); 18 | this.emit('data',chunk); 19 | } 20 | 21 | StringStream.prototype.end=function(chunk,encoding){ 22 | this.emit('end'); 23 | } 24 | 25 | StringStream.prototype.toString=function(){ 26 | return this.str; 27 | } 28 | 29 | 30 | s.append("foo."); 31 | s.append(""); 32 | s.append("bar"); 33 | 34 | var ss = new StringStream(); 35 | 36 | s.pipe(ss); 37 | s.resume(); 38 | 39 | assert.equal(ss.toString(),"foo.bar"); 40 | -------------------------------------------------------------------------------- /test/integration/test-is-stream-like.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var common = require('../common'); 3 | var assert = common.assert; 4 | var CombinedStream = common.CombinedStream; 5 | var FILE1 = common.dir.fixture + '/file1.txt'; 6 | var fileStream = fs.createReadStream(FILE1); 7 | 8 | var foo = function(){}; 9 | 10 | (function testIsStreamLike() { 11 | assert(! CombinedStream.isStreamLike(true)); 12 | assert(! CombinedStream.isStreamLike("I am a string")); 13 | assert(! CombinedStream.isStreamLike(7)); 14 | assert(! CombinedStream.isStreamLike(foo)); 15 | 16 | assert(CombinedStream.isStreamLike(fileStream)); 17 | })(); -------------------------------------------------------------------------------- /test/integration/test-max-data-size.js: -------------------------------------------------------------------------------- 1 | var common = require('../common'); 2 | var assert = common.assert; 3 | var CombinedStream = common.CombinedStream; 4 | var fs = require('fs'); 5 | 6 | var FILE1 = common.dir.fixture + '/file1.txt'; 7 | var FILE2 = common.dir.fixture + '/file2.txt'; 8 | var EXPECTED = fs.readFileSync(FILE1) + fs.readFileSync(FILE2); 9 | 10 | (function testDelayedStreams() { 11 | var combinedStream = CombinedStream.create({pauseStreams: false, maxDataSize: 20736}); 12 | combinedStream.append(fs.createReadStream(FILE1)); 13 | combinedStream.append(fs.createReadStream(FILE2)); 14 | 15 | var gotErr = null; 16 | combinedStream.on('error', function(err) { 17 | gotErr = err; 18 | }); 19 | 20 | process.on('exit', function() { 21 | assert.ok(gotErr); 22 | assert.ok(gotErr.message.match(/bytes/)); 23 | }); 24 | })(); 25 | -------------------------------------------------------------------------------- /test/integration/test-pipe-memory-leak.js: -------------------------------------------------------------------------------- 1 | var common = require('../common'); 2 | var assert = common.assert; 3 | var CombinedStream = common.CombinedStream; 4 | var fs = require('fs'); 5 | var LARGE = common.dir.fixture + '/large.txt'; 6 | var FILE1 = common.dir.fixture + '/file1.txt'; 7 | 8 | var Readable = require('stream').Readable; 9 | var Writable = require('stream').Writable; 10 | 11 | var rss = process.memoryUsage().rss; 12 | var ws = Writable(); 13 | ws._write = function (chunk, enc, next) { 14 | setTimeout(function() { 15 | var rssDiff = process.memoryUsage().rss - rss; 16 | fs.unlink(LARGE, function(){}); 17 | assert.ok(rssDiff < totalSize); 18 | process.exit(); 19 | next(); 20 | }, 5000); 21 | return false; 22 | }; 23 | 24 | var rs = Readable(); 25 | var totalSize = 1024 * 1024 * 500; // 500MB 26 | var readBytes = 0; 27 | 28 | rs._read = function(n) { 29 | var buff = new Buffer(n); 30 | this.push(buff); 31 | readBytes += n; 32 | if (readBytes > totalSize) this.push(null); 33 | }; 34 | 35 | rs.pipe(fs.createWriteStream(LARGE)).on('finish', function() { 36 | var combinedStream = CombinedStream.create(); 37 | combinedStream.append(fs.createReadStream(FILE1)); 38 | combinedStream.append(fs.createReadStream(LARGE)); 39 | 40 | combinedStream.pipe(ws); 41 | }); -------------------------------------------------------------------------------- /test/integration/test-recursion-append.js: -------------------------------------------------------------------------------- 1 | var common = require('../common'); 2 | var assert = common.assert; 3 | var CombinedStream = common.CombinedStream; 4 | 5 | var s = CombinedStream.create(); 6 | 7 | for (var i = 0; i < 1e4; i++) 8 | s.append('test'); 9 | 10 | // Shouldn't throw "RangeError: Maximum call stack size exceeded" 11 | s.resume(); 12 | -------------------------------------------------------------------------------- /test/integration/test-recursion-callback.js: -------------------------------------------------------------------------------- 1 | var common = require('../common'); 2 | var assert = common.assert; 3 | var CombinedStream = common.CombinedStream; 4 | 5 | var s = CombinedStream.create(); 6 | 7 | for (var i = 0; i < 1e4; i++) 8 | s.append(function (next) { 9 | next('test') 10 | }); 11 | 12 | // Shouldn't throw "RangeError: Maximum call stack size exceeded" 13 | s.resume(); 14 | -------------------------------------------------------------------------------- /test/integration/test-unpaused-streams.js: -------------------------------------------------------------------------------- 1 | var common = require('../common'); 2 | var assert = common.assert; 3 | var CombinedStream = common.CombinedStream; 4 | var fs = require('fs'); 5 | 6 | var FILE1 = common.dir.fixture + '/file1.txt'; 7 | var FILE2 = common.dir.fixture + '/file2.txt'; 8 | var EXPECTED = fs.readFileSync(FILE1) + fs.readFileSync(FILE2); 9 | 10 | (function testDelayedStreams() { 11 | var combinedStream = CombinedStream.create({pauseStreams: false}); 12 | combinedStream.append(fs.createReadStream(FILE1)); 13 | combinedStream.append(fs.createReadStream(FILE2)); 14 | 15 | var stream1 = combinedStream._streams[0]; 16 | var stream2 = combinedStream._streams[1]; 17 | 18 | stream1.on('end', function() { 19 | assert.ok(stream2.dataSize > 0); 20 | }); 21 | 22 | var tmpFile = common.dir.tmp + '/combined.txt'; 23 | var dest = fs.createWriteStream(tmpFile); 24 | combinedStream.pipe(dest); 25 | 26 | dest.on('end', function() { 27 | var written = fs.readFileSync(tmpFile, 'utf8'); 28 | assert.strictEqual(written, EXPECTED); 29 | }); 30 | })(); 31 | -------------------------------------------------------------------------------- /test/run.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var far = require('far').create(); 3 | 4 | far.add(__dirname); 5 | far.include(/test-.*\.js$/); 6 | 7 | far.execute(); 8 | --------------------------------------------------------------------------------