1
|
var tape = require('tape')
|
2
|
var through = require('through2')
|
3
|
var concat = require('concat-stream')
|
4
|
var net = require('net')
|
5
|
var duplexify = require('./')
|
6
|
|
7
|
var HELLO_WORLD = (Buffer.from && Buffer.from !== Uint8Array.from)
|
8
|
? Buffer.from('hello world')
|
9
|
: new Buffer('hello world')
|
10
|
|
11
|
tape('passthrough', function(t) {
|
12
|
t.plan(2)
|
13
|
|
14
|
var pt = through()
|
15
|
var dup = duplexify(pt, pt)
|
16
|
|
17
|
dup.end('hello world')
|
18
|
dup.on('finish', function() {
|
19
|
t.ok(true, 'should finish')
|
20
|
})
|
21
|
dup.pipe(concat(function(data) {
|
22
|
t.same(data.toString(), 'hello world', 'same in as out')
|
23
|
}))
|
24
|
})
|
25
|
|
26
|
tape('passthrough + double end', function(t) {
|
27
|
t.plan(2)
|
28
|
|
29
|
var pt = through()
|
30
|
var dup = duplexify(pt, pt)
|
31
|
|
32
|
dup.end('hello world')
|
33
|
dup.end()
|
34
|
|
35
|
dup.on('finish', function() {
|
36
|
t.ok(true, 'should finish')
|
37
|
})
|
38
|
dup.pipe(concat(function(data) {
|
39
|
t.same(data.toString(), 'hello world', 'same in as out')
|
40
|
}))
|
41
|
})
|
42
|
|
43
|
tape('async passthrough + end', function(t) {
|
44
|
t.plan(2)
|
45
|
|
46
|
var pt = through.obj({highWaterMark:1}, function(data, enc, cb) {
|
47
|
setTimeout(function() {
|
48
|
cb(null, data)
|
49
|
}, 100)
|
50
|
})
|
51
|
|
52
|
var dup = duplexify(pt, pt)
|
53
|
|
54
|
dup.write('hello ')
|
55
|
dup.write('world')
|
56
|
dup.end()
|
57
|
|
58
|
dup.on('finish', function() {
|
59
|
t.ok(true, 'should finish')
|
60
|
})
|
61
|
dup.pipe(concat(function(data) {
|
62
|
t.same(data.toString(), 'hello world', 'same in as out')
|
63
|
}))
|
64
|
})
|
65
|
|
66
|
tape('duplex', function(t) {
|
67
|
var readExpected = ['read-a', 'read-b', 'read-c']
|
68
|
var writeExpected = ['write-a', 'write-b', 'write-c']
|
69
|
|
70
|
t.plan(readExpected.length+writeExpected.length+2)
|
71
|
|
72
|
var readable = through.obj()
|
73
|
var writable = through.obj(function(data, enc, cb) {
|
74
|
t.same(data, writeExpected.shift(), 'onwrite should match')
|
75
|
cb()
|
76
|
})
|
77
|
|
78
|
var dup = duplexify.obj(writable, readable)
|
79
|
|
80
|
readExpected.slice().forEach(function(data) {
|
81
|
readable.write(data)
|
82
|
})
|
83
|
readable.end()
|
84
|
|
85
|
writeExpected.slice().forEach(function(data) {
|
86
|
dup.write(data)
|
87
|
})
|
88
|
dup.end()
|
89
|
|
90
|
dup.on('data', function(data) {
|
91
|
t.same(data, readExpected.shift(), 'ondata should match')
|
92
|
})
|
93
|
dup.on('end', function() {
|
94
|
t.ok(true, 'should end')
|
95
|
})
|
96
|
dup.on('finish', function() {
|
97
|
t.ok(true, 'should finish')
|
98
|
})
|
99
|
})
|
100
|
|
101
|
tape('async', function(t) {
|
102
|
var dup = duplexify()
|
103
|
var pt = through()
|
104
|
|
105
|
dup.pipe(concat(function(data) {
|
106
|
t.same(data.toString(), 'i was async', 'same in as out')
|
107
|
t.end()
|
108
|
}))
|
109
|
|
110
|
dup.write('i')
|
111
|
dup.write(' was ')
|
112
|
dup.end('async')
|
113
|
|
114
|
setTimeout(function() {
|
115
|
dup.setWritable(pt)
|
116
|
setTimeout(function() {
|
117
|
dup.setReadable(pt)
|
118
|
}, 50)
|
119
|
}, 50)
|
120
|
})
|
121
|
|
122
|
tape('destroy', function(t) {
|
123
|
t.plan(2)
|
124
|
|
125
|
var write = through()
|
126
|
var read = through()
|
127
|
var dup = duplexify(write, read)
|
128
|
|
129
|
write.destroy = function() {
|
130
|
t.ok(true, 'write destroyed')
|
131
|
}
|
132
|
|
133
|
dup.on('close', function() {
|
134
|
t.ok(true, 'close emitted')
|
135
|
})
|
136
|
|
137
|
dup.destroy()
|
138
|
dup.destroy() // should only work once
|
139
|
})
|
140
|
|
141
|
tape('destroy both', function(t) {
|
142
|
t.plan(3)
|
143
|
|
144
|
var write = through()
|
145
|
var read = through()
|
146
|
var dup = duplexify(write, read)
|
147
|
|
148
|
write.destroy = function() {
|
149
|
t.ok(true, 'write destroyed')
|
150
|
}
|
151
|
|
152
|
read.destroy = function() {
|
153
|
t.ok(true, 'read destroyed')
|
154
|
}
|
155
|
|
156
|
dup.on('close', function() {
|
157
|
t.ok(true, 'close emitted')
|
158
|
})
|
159
|
|
160
|
dup.destroy()
|
161
|
dup.destroy() // should only work once
|
162
|
})
|
163
|
|
164
|
tape('bubble read errors', function(t) {
|
165
|
t.plan(2)
|
166
|
|
167
|
var write = through()
|
168
|
var read = through()
|
169
|
var dup = duplexify(write, read)
|
170
|
|
171
|
dup.on('error', function(err) {
|
172
|
t.same(err.message, 'read-error', 'received read error')
|
173
|
})
|
174
|
dup.on('close', function() {
|
175
|
t.ok(true, 'close emitted')
|
176
|
})
|
177
|
|
178
|
read.emit('error', new Error('read-error'))
|
179
|
write.emit('error', new Error('write-error')) // only emit first error
|
180
|
})
|
181
|
|
182
|
tape('bubble write errors', function(t) {
|
183
|
t.plan(2)
|
184
|
|
185
|
var write = through()
|
186
|
var read = through()
|
187
|
var dup = duplexify(write, read)
|
188
|
|
189
|
dup.on('error', function(err) {
|
190
|
t.same(err.message, 'write-error', 'received write error')
|
191
|
})
|
192
|
dup.on('close', function() {
|
193
|
t.ok(true, 'close emitted')
|
194
|
})
|
195
|
|
196
|
write.emit('error', new Error('write-error'))
|
197
|
read.emit('error', new Error('read-error')) // only emit first error
|
198
|
})
|
199
|
|
200
|
tape('reset writable / readable', function(t) {
|
201
|
t.plan(3)
|
202
|
|
203
|
var toUpperCase = function(data, enc, cb) {
|
204
|
cb(null, data.toString().toUpperCase())
|
205
|
}
|
206
|
|
207
|
var passthrough = through()
|
208
|
var upper = through(toUpperCase)
|
209
|
var dup = duplexify(passthrough, passthrough)
|
210
|
|
211
|
dup.once('data', function(data) {
|
212
|
t.same(data.toString(), 'hello')
|
213
|
dup.setWritable(upper)
|
214
|
dup.setReadable(upper)
|
215
|
dup.once('data', function(data) {
|
216
|
t.same(data.toString(), 'HELLO')
|
217
|
dup.once('data', function(data) {
|
218
|
t.same(data.toString(), 'HI')
|
219
|
t.end()
|
220
|
})
|
221
|
})
|
222
|
dup.write('hello')
|
223
|
dup.write('hi')
|
224
|
})
|
225
|
dup.write('hello')
|
226
|
})
|
227
|
|
228
|
tape('cork', function(t) {
|
229
|
var passthrough = through()
|
230
|
var dup = duplexify(passthrough, passthrough)
|
231
|
var ok = false
|
232
|
|
233
|
dup.on('prefinish', function() {
|
234
|
dup.cork()
|
235
|
setTimeout(function() {
|
236
|
ok = true
|
237
|
dup.uncork()
|
238
|
}, 100)
|
239
|
})
|
240
|
dup.on('finish', function() {
|
241
|
t.ok(ok)
|
242
|
t.end()
|
243
|
})
|
244
|
dup.end()
|
245
|
})
|
246
|
|
247
|
tape('prefinish not twice', function(t) {
|
248
|
var passthrough = through()
|
249
|
var dup = duplexify(passthrough, passthrough)
|
250
|
var prefinished = false
|
251
|
|
252
|
dup.on('prefinish', function() {
|
253
|
t.ok(!prefinished, 'only prefinish once')
|
254
|
prefinished = true
|
255
|
})
|
256
|
|
257
|
dup.on('finish', function() {
|
258
|
t.end()
|
259
|
})
|
260
|
|
261
|
dup.end()
|
262
|
})
|
263
|
|
264
|
tape('close', function(t) {
|
265
|
var passthrough = through()
|
266
|
var dup = duplexify(passthrough, passthrough)
|
267
|
|
268
|
passthrough.emit('close')
|
269
|
dup.on('close', function() {
|
270
|
t.ok(true, 'should forward close')
|
271
|
t.end()
|
272
|
})
|
273
|
})
|
274
|
|
275
|
tape('works with node native streams (net)', function(t) {
|
276
|
t.plan(1)
|
277
|
|
278
|
var server = net.createServer(function(socket) {
|
279
|
var dup = duplexify(socket, socket)
|
280
|
|
281
|
dup.once('data', function(chunk) {
|
282
|
t.same(chunk, HELLO_WORLD)
|
283
|
server.close()
|
284
|
socket.end()
|
285
|
t.end()
|
286
|
})
|
287
|
})
|
288
|
|
289
|
server.listen(0, function () {
|
290
|
var socket = net.connect(server.address().port)
|
291
|
var dup = duplexify(socket, socket)
|
292
|
|
293
|
dup.write(HELLO_WORLD)
|
294
|
})
|
295
|
})
|