-
Notifications
You must be signed in to change notification settings - Fork 3
/
test.coffee
349 lines (319 loc) · 10.6 KB
/
test.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
async = require '../coffee/async2'
assert = require('chai').assert
a = `undefined`
describe 'async2', ->
start = undefined
beforeEach ->
start = new Date
it 'auto-instantiates a new async', ->
a = async
.serial(-> 'hello')
assert.notEqual async, a
it 'allows chainable manual instantiation', ->
a = async.new() # alternative to (new async).
assert.notEqual async, a
it 'allows explicit blocking with serial()', (done) ->
async
.serial(-> async.delay 100, @ )
.serial(-> async.delay 50, @ )
.end ->
assert.closeTo 100+50, since(start), 25
done()
it 'allows explicit non-blocking with parallel()', (done) ->
async
.parallel(-> async.delay 100, @ )
.parallel(-> async.delay 50, @ )
.end ->
assert.closeTo Math.max(100,50), since(start), 25
done()
it 'allows auto-blocking with then() based on function argument length', (done) ->
async
.then((result) -> async.delay 200, @ ) # serial
.then(-> async.delay 100, @ ) # parallel
.then(-> async.delay 50, @ ) # parallel
.end ->
assert.closeTo 200+Math.max(100,50), since(start), 25
done()
it 'can accomplish async.js::auto() with chain ordering', (done) ->
# see also: https://github.com/caolan/async#auto
async.auto
get_data: -> # no args; parallel
# async code to get some data
async.delay 10, @
make_folder: (result) -> # args; serial
# async code to create a directory to store a file in
# this is run at the same time as getting the data
async.delay 50, @
write_file: (result) -> # args; serial
# once there is some data and the directory exists
# write the data to a file in the directory
async.delay 100, @
email_link: (result) -> # args; serial
# once the file is written let's email a link to it...
# results.write_file contains the filename returned by write_file
async.delay 250, @
end: -> # couple different ways this last part could have been done
assert.closeTo Math.max(10,50)+100+250, since(start), 25
done()
it 'can accomplish async.js::waterfall() with serial()', (done) ->
# see also: https://github.com/caolan/async#waterfall
async
.serial(-> @ null, 'async.js is silly. pass it on.' )
.serial((result) -> @ null, result + ' hehe.')
.serial((result) -> @ null, result + ' ok maybe its not too silly.' )
.end (err, result) ->
assert.equal result, 'async.js is silly. pass it on. hehe. ok maybe its not too silly.'
done()
it 'backward-compatible with async.js; series() and parallel() accept enumerable objects, executing immediately', (done) ->
async.series [
-> async.delay 100, @
-> async.delay 50, @
], ->
assert.closeTo 100+50, since(start), 25
async.parallel [
-> async.delay 100, @
-> async.delay 50, @
], ->
assert.closeTo (100+50)+100, since(start), 25
done()
it 'follows node (results..., cb) and (err, results..., cb) conventions', (done) ->
fs =
readFile: (path, done) ->
async.delay 20, -> done null, "tons o' data from #{path}."
tweet = fbook = gplus = (data, done) -> done null, data
results = {}
(new async())
.serial((next) ->
next null, 'pretend/path/to/file'
)
.serial(fs.readFile)
.parallel [ tweet, fbook, gplus ],
(err, data) ->
assert.equal "tons o' data from pretend/path/to/file.", data
done()
it 'can process callbacks before, beforeEach, afterEach', (done) ->
results = []
check = (what, done) ->
setTimeout (->
results.push what
done null, what
), 50
async
.before((result) -> 'awake' )
.beforeEach((result) -> 'ready to switch focus' )
.do((result) -> check 'mobile', @ )
.then(-> check 'email', @ )
.then(-> check 'Fbook', @ )
.then(-> check 'GPlus', @ )
.afterEach((result) -> 'cleaned up after task' )
.end (err) ->
assert.equal 'mobile email Fbook GPlus', results.join ' '
assert.closeTo 50+Math.max(50,50,50), since(start), 25
done()
it 'can do whilst()', (done) ->
a = 0
out = []
async.whilst (-> a < 5 ),
((done) -> async.delay 50, -> out.push a++; done() ), ->
assert.equal '0 1 2 3 4', out.join ' '
assert.closeTo 5*50, since(start), 25
done()
it 'passes cb as only argument to first serial fn', (done) ->
async.flow()
.serial((next) ->
assert.typeOf next, 'function'
done()
)
.go()
it 'passes cb as last arg of predictable arg length to subsequent serial fns', (done) ->
async.flow()
.serial((next) ->
assert.typeOf next, 'function'
next()
)
.serial((next) ->
assert.typeOf next, 'function'
next null, 1
)
.serial((a, next) ->
assert.equal a, 1
assert.typeOf next, 'function'
next null, 1, 2
)
.serial((a, b, next) ->
assert.equal a, 1
assert.equal b, 2
assert.typeOf next, 'function'
next null, 1, 2, 3, 4, 5, 6
)
.serial((a..., next) ->
assert.deepEqual a, [ 1, 2, 3, 4, 5, 6 ]
assert.typeOf next, 'function'
done()
)
.go()
it 'passes err, results... arguments to finally() in a series', (done) ->
async.flow()
.serial((next) ->
next 'bad', 1, 2, 3, 4, 5, 6
)
.finally (err, results...) ->
assert.equal err, 'bad'
assert.deepEqual results, [ 1, 2, 3, 4, 5, 6 ]
done()
it 'receives beginning result within optional chainable instantiator', (done) ->
async.with(score: 1)
.serial((result, next) ->
assert.deepEqual result, score: 1
assert.typeOf next, 'function'
result.score += 10
assert.equal result.score, 11
next null, result
)
.end (err, result) ->
assert.equal err, null
assert.deepEqual result, score: 11
done()
it 'may receive multiple beginning results', (done) ->
req = params: id: 5
res = current_user: id: 6
flow = async.flow req, res
flow.serial (req, res, next) ->
assert.equal arguments.length, 3
assert.typeOf req, 'object'
assert.typeOf res, 'object'
assert.typeOf next, 'function'
res.current_user.id = 7
next null, req, res
flow.go (err, req, res) ->
assert.equal res.current_user.id, 7
done()
it 'is MUCH easier to use within loops', (done) ->
flow = new async
for i in [1..10]
((i) ->
method = if i%3 then 'parallel' else 'serial' # an overcomplicated display of flexibility
flow[method] (next) ->
async.delay 25, ->
#console.log "#{method} #{i}"
next()
)(i)
flow.go (err, results...) ->
#console.log 'try this in async.js!'
done()
it 'is sometimes useful to call go() with no fns queued', (done) ->
flow = new async
flow.go ->
done()
it 'can waterfall serial results to parallel functions in the same flow', (done) ->
tweet = fbook = gplus = (data, cb) -> # mock async broadcast fns
assert.equal 'asynchronous data', data
cb null
async
.serial(-> @ null, 'asynchronous data' ) # e.g., fs.readFile()
.parallel((data) -> tweet data, @ )
.parallel((data) -> fbook data, @ )
.parallel((data) -> gplus data, @ )
.finally done
it 'can be written similarly to jQuery.ajax()', (done) ->
called = false
async
before: ->
#loading.show()
called = true
do: (next) ->
# main logic
assert.ok called
next 'err', 'result'
error: (err) ->
assert.equal 'err', 'err'
#alert err
success: (result) ->
assert false, 'success() should not have been called here'
#console.log data
complete: (err, result) ->
assert.equal err, 'err'
assert.equal result, 'result'
#loading.hide()
done()
it 'can be written similarly to javascript try/catch/finally exception handling', (done) ->
called = false
async
.try(->
@ new Error 'thrown node cb style'
)
.catch((err) ->
called = true
assert.equal ''+err, 'Error: thrown node cb style'
)
.finally (err, result) ->
assert.ok called
assert.equal ''+err, 'Error: thrown node cb style'
assert.typeOf result, 'undefined'
done()
it 'can be written similarly to ruby begin/rescue/else/ensure exception handling', (done) ->
called = false
async
.begin(->
@ new Error 'thrown node cb style'
)
.rescue((err) ->
called = true
assert.equal ''+err, 'Error: thrown node cb style'
)
.else((result) ->
console.log 'Else'
assert false, 'else() should not have been called here'
)
.ensure (err, result) ->
assert.ok called
assert.equal ''+err, 'Error: thrown node cb style'
assert.typeOf result, 'undefined'
done()
it 'can do serially-queued automatic-kick-start execution like `nextTick()` or `setTimeout(f,0)`, but grouped', (done) ->
out = ''
debug = (m,s,cb) -> async.delay s, -> out += m; cb null
Z = new async
Z.serial ->
debug 'a', 100, @
X = new async
X.serial ->
debug 'b', 50, @
Z.serial ->
debug 'c', 300, @
Z.go()
X.serial ->
debug 'd', 30, @
X.go()
async.delay l=100+50+300+30+25, ->
assert.equal 'bdac', out
out = ''
# push is always serial
# above 12 lines behave the same as below 9
# basically you can push onto the end of the serial array
# at any time, even while it is being processed.
# and its ok to call go() more than once; duplicate calls
# will be ignored unless there are actually some functions enqueued
# and it is not already processing.
async.nextTickGroup 'Z', ->
debug 'a', 100, @
async.push 'X', -> # push is an alias; its the same fn
debug 'b', 50, @
async
.push 'Z', ->
# should not begin until after Za has completed; its a series
assert.closeTo l+100, since(start), 25
debug 'c', 300, @
.nextTickGroup 'X', ->
debug 'd', 30, @
async.delay 100+50+300+30+25, ->
assert.equal 'bdac', out
done()
it 'can still keep pushing after queue has emptied', (done) ->
out = ''
debug = (m,s,cb) -> async.delay s, -> out += m; cb null
async.push 'Z', ->
debug 'e', 10, @
async.delay 10+25, ->
assert.equal out, 'e'
done()