1
var Helper = require('./spec_helper').Helper;
2
var FakeStream = require('./spec_helper').FakeStream;
3
var sinon = require('sinon');
4
var should = require('should');
5
var assert = require('assert');
6
var LineReader = require('phusion_passenger/line_reader').LineReader;
8
describe('LineReader', function() {
11
beforeEach(function() {
12
this.stream = new FakeStream();
13
this.reader = new LineReader(this.stream);
16
it('does nothing when the stream is idle', function(done) {
18
this.reader.readLine(function(line) {
24
setTimeout(function() {
32
describe('when one partial line has been received', function() {
33
beforeEach(function() {
34
this.stream.emit('data', 'hello');
37
it('buffers the data', function() {
38
this.reader.buffer.should.equal('hello');
41
it('resumes the stream', function() {
42
this.stream.paused.should.be.false;
43
this.reader.paused.should.be.false;
46
describe('when the rest of the line is received later', function() {
47
beforeEach(function() {
48
this.stream.emit('data', " world\n");
51
it('memorizes a line', function() {
52
this.reader.lines.should.eql(["hello world\n"]);
55
it('empties the buffer', function() {
56
this.reader.buffer.should.eql('');
59
it('pauses the stream', function() {
60
this.stream.paused.should.be.true;
61
this.reader.paused.should.be.true;
65
describe('when the rest of the line, plus a partial line, is received later', function() {
66
beforeEach(function() {
67
this.stream.emit('data', " world\nhey");
70
it('memorizes a line', function() {
71
this.reader.lines.should.eql(["hello world\n"]);
74
it('buffers the partial line', function() {
75
this.reader.buffer.should.eql('hey');
78
it('pauses the stream', function() {
79
this.stream.paused.should.be.true;
80
this.reader.paused.should.be.true;
84
describe('when the rest of the line, plus a full line, is received later', function() {
85
beforeEach(function() {
86
this.stream.emit('data', " world\nhey\n");
89
it('memorizes two lines', function() {
90
this.reader.lines.should.eql(["hello world\n", "hey\n"]);
93
it('empties the buffer', function() {
94
this.reader.buffer.should.eql('');
97
it('pauses the stream', function() {
98
this.stream.paused.should.be.true;
99
this.reader.paused.should.be.true;
104
describe('when one full line has been received', function() {
105
beforeEach(function() {
106
this.stream.emit('data', "hello world\n");
109
it('memorizes the line', function() {
110
this.reader.lines.should.eql(["hello world\n"]);
113
it('empties the buffer', function() {
114
this.reader.buffer.should.eql('');
117
it('pauses the stream', function() {
118
this.stream.paused.should.be.true;
119
this.reader.paused.should.be.true;
123
describe('when multiple full lines have been received', function() {
124
beforeEach(function() {
125
this.stream.emit('data', "hello world\nhey\n");
128
it('memorizes all lines', function() {
129
this.reader.lines.should.eql(["hello world\n", "hey\n"]);
132
it('empties the buffer', function() {
133
this.reader.buffer.should.eql('');
136
it('pauses the stream', function() {
137
this.stream.paused.should.be.true;
138
this.reader.paused.should.be.true;
142
describe('when multiple full lines and one partial line have been received', function() {
143
beforeEach(function() {
144
this.stream.emit('data', "hello world\nhey\nfoo");
147
it('memorizes all full lines', function() {
148
this.reader.lines.should.eql(["hello world\n", "hey\n"]);
151
it('buffers the partial line', function() {
152
this.reader.buffer.should.eql('foo');
155
it('pauses the stream', function() {
156
this.stream.paused.should.be.true;
157
this.reader.paused.should.be.true;
161
describe('on EOF', function() {
162
describe('if the buffer is non-empty', function() {
163
beforeEach(function() {
164
this.reader.buffer = 'hello';
165
this.stream.emit('end');
168
it('memorizes the buffer contents as a line', function() {
169
this.reader.lines.should.eql(["hello"]);
173
it('marks the reader as having reached EOF', function() {
174
this.stream.emit('end');
175
this.reader.endReached().should.be.true;
178
it('pauses the stream', function() {
179
this.stream.emit('end');
180
this.stream.paused.should.be.true;
181
this.reader.paused.should.be.true;
185
describe('.readLine', function() {
186
describe('if there is at least one line in memory', function() {
187
beforeEach(function() {
188
this.reader.lines = ["hello\n", "world\n"];
191
it('pops the first line in memory', function(done) {
192
this.reader.readLine(function(line) {
193
line.should.eql("hello\n");
198
describe('if the line memory is non-empty after reading', function() {
199
it('pauses the stream', function(done) {
201
this.reader.readLine(function(line) {
202
line.should.eql("hello\n");
203
process.nextTick(function() {
204
self.stream.paused.should.be.true;
205
self.reader.paused.should.be.true;
212
describe('if the line memory is empty after reading', function() {
213
beforeEach(function() {
214
this.reader.lines = ["hello\n"];
217
it('resumes the stream', function(done) {
219
this.reader.readLine(function(line) {
220
line.should.eql("hello\n");
221
process.nextTick(function() {
222
self.stream.paused.should.be.false;
223
self.reader.paused.should.be.false;
230
describe('if the stream had already reached EOF', function() {
231
beforeEach(function() {
232
this.reader.eof = true;
233
this.reader.lines = ["hello\n"];
236
it('yields the line upon first call', function(done) {
237
this.reader.readLine(function(line) {
238
line.should.eql("hello\n");
243
it('yields undefined once the line memory has become empty', function(done) {
245
this.reader.readLine(function(line) {
246
line.should.eql("hello\n");
247
self.reader.readLine(function(line2) {
248
should(line2).equal(undefined);
249
self.reader.readLine(function(line3) {
250
should(line3).equal(undefined);
258
describe('when calling readLine again in the callback', function() {
259
beforeEach(function() {
260
this.reader.lines = ["hello\n"];
263
it('waits until another line has been memorized', function(done) {
266
this.reader.readLine(function(line) {
267
line.should.eql("hello\n");
268
self.reader.readLine(function(line2) {
271
line2.should.eql("world\n");
275
setTimeout(function() {
278
self.stream.emit('data', "world\n");
285
it('resumes the stream', function(done) {
288
this.reader.readLine(function(line) {
289
line.should.eql("hello\n");
290
self.reader.readLine(function(line2) {
293
assert.fail("never reached");
296
process.nextTick(function() {
299
self.stream.paused.should.be.false;
300
self.reader.paused.should.be.false;
309
describe('if there is no line in memory', function() {
310
it('waits until a line has been memorized', function(done) {
311
var state = 'waiting';
313
this.reader.readLine(function(line) {
314
state.should.eql('line fed');
315
line.should.eql("hello\n");
318
setTimeout(function() {
319
state.should.eql('waiting');
321
self.stream.emit('data', "hello\n");
325
describe('if the stream had already reached EOF', function(done) {
326
beforeEach(function() {
327
this.reader.eof = true;
330
it('yields undefined', function() {
331
this.reader.readLine(function(line) {
332
should(line).equal(undefined);