UNPKG

14.4 kBJavaScriptView Raw
1/*
2 * l8 test suite
3 */
4
5"use strict";
6
7var l8 = require( "l8/lib/l8.js" )
8require( "l8/lib/transpiler.js" )
9require( "l8/lib/call.js" )
10require( "l8/lib/selector.js" )
11require( "l8/lib/aggregator.js" )
12require( "l8/lib/timeout.js" )
13require( "l8/lib/generator.js" )
14require( "l8/lib/semaphore.js" )
15require( "l8/lib/signal.js" )
16require( "l8/lib/queue.js" )
17require( "l8/lib/mutex.js" )
18require( "l8/lib/lock.js" )
19require( "l8/lib/parole.js" )
20
21/* ----------------------------------------------------------------------------
22 * Tests
23 */
24
25var trace = l8.trace
26var bug = trace
27var de = true
28l8.debug( true)
29l8.logger( function(){ return function(){} } )
30l8.trace( "SILENT TRACE" )
31l8.logger( null )
32l8.trace( "L8 TEST SUITE" )
33
34var test // current test id
35
36 var traces = []
37 function t(){
38 if( traces.length > 200 ){
39 trace( "!!! too many traces, infinite loop? exiting...")
40 process.exit( 1)
41 }
42 var buf = ["test" + (test ? " " + test : ""), "" + l8.current.currentStep]
43 for( var ii = 0 ; ii < arguments.length ; ii++ ) buf.push( arguments[ii])
44 buf = trace.apply( this, buf)
45 traces.push( buf)
46 return buf
47 }
48
49 function check(){
50 var ii = 0
51 var msg
52 var tt = 0
53 var tmsg
54 while( ii < arguments.length ){
55 msg = arguments[ii++]
56 while( true ){
57 tmsg = traces[tt]
58 if( tmsg && tmsg.indexOf( msg) >= 0 )break;
59 if( ++tt >= traces.length ){
60 msg = "FAILED test " + test + ", missing trace: " + msg
61 trace( msg)
62 for( var jj = 0 ; jj < ii ; jj++ ){
63 trace( arguments[jj])
64 }
65 traces = []
66 throw new Error( msg)
67 }
68 }
69 }
70 trace( "Test " + test, "PASSED")
71 traces = []
72 }
73
74 var test_1 = function test1(){
75 test = 1
76 t( "go")
77 l8.begin
78 .step( function(){ t( "start") })
79 .step( function(){ t( "step") })
80 .step( function(){ t( "sleep")
81 this.sleep( 100)
82 t( "sleeping") })
83 .step( function(){ t( "sleep done") })
84 .failure( function( e ){ t( "!!! unexpected failure", e) })
85 .final( function(){ t( "final")
86 check( "start",
87 "step",
88 "sleep",
89 "sleeping",
90 "sleep done",
91 "final"
92 )
93 test_2()
94 })
95 .end
96 }
97
98 var test_2 = l8.Task( function test2(){
99 test = 2; this
100 .step( function(){ t( "start") })
101 .step( function(){ setTimeout( this.walk, 0) })
102 .step( function(){ t( "sleep/timeout done") })
103 .failure( function( e ){ t( "unexpected failure", e) })
104 .final( function(){ t( "final")
105 check( "start",
106 "sleep/timeout done",
107 "final"
108 )
109 test_3()
110 })
111 })
112
113 var test_3 = l8.Task( function test3(){
114 test = 3; this
115 .step( function(){ t( "start") })
116 .step( function(){ t( "add step 1"); this
117 .step( function(){ t( "first step") })
118 t( "add step 2"); this
119 .step( function(){ t( "second step") }) })
120 .step( function(){ t("third & final step") })
121 .success( function(){ t("success") })
122 .failure( function( e ){ t( "unexpected failure", e) })
123 .final( function(){ t( "final")
124 check( "start",
125 "success",
126 "final"
127 )
128 test_4()
129 })
130 })
131
132 var test_4 = l8.Task( function test4(){
133 test = 4; this
134 .step( function(){ t( "start") })
135 .step( function(){ t( "raise error")
136 throw new Error( "step error") })
137 .step( function(){ t("!!! skipped step") })
138 .failure( function(){ t("error raised", this.error) })
139 .final( function(){ t( "final")
140 check( "start",
141 "error raised",
142 "final"
143 )
144 test_5()
145 })
146 })
147
148 var test_5 = l8.Task( function test5(){
149 test = 5; t( "start"); this
150 .fork( function(){ this.label = t( "fork 1"); this
151 .step( function(){ this.sleep( 10) })
152 .step( function(){ t( "end fork 1") }) })
153 .fork( function(){ this.label = t( "fork 2"); this
154 .step( function(){ this.sleep( 5) })
155 .step( function(){ t( "end fork 2") }) })
156 .step( function(){ t( "joined") })
157 .fork( function(){ this.label = t( "fork 3"); this
158 .step( function(){ this.sleep( 1) })
159 .final( function(){ t( "final of fork 3") }) })
160 .fork( function(){ this.label = t( "fork 4"); this
161 .final( function(){ t( "final of fork 4") }) })
162 .step( function(){ t( "joined again") })
163 .failure( function( e ){ t( "unexpected failure", e) })
164 .final( function(){ t( "final")
165 check( "start",
166 "fork 1",
167 "fork 2",
168 "end fork 2",
169 "end fork 1",
170 "joined",
171 "fork 3",
172 "fork 4",
173 "final of fork 4",
174 "final of fork 3",
175 "joined again",
176 "final"
177 )
178 test_6()
179 })
180 })
181
182 var test_6 = l8.Task( function test6(){
183 function other1(){ l8.step( function(){ t( "in other1")} )}
184 function other2(){ l8.fork( function(){ t( "in other2")} )}
185 test = 6; this
186 .step( function(){ other1(); t( "other1() called") })
187 .step( function(){ t( "other1 result", this.result); this
188 other2(); t( "other2() called") })
189 .step( function(){ t( "other2 result", this.result) })
190 .failure( function( e ){ t( "unexpected failure", e) })
191 .final( function(){ t( "final result", this.result)
192 check( "other1() called",
193 "in other1",
194 "other1 result",
195 "other2() called",
196 "in other2",
197 "other2 result",
198 "final result"
199 )
200 test_7()
201 })
202 })
203
204 var test_7 = l8.Task( function test7(){
205 test = 7
206 var ii; this
207 .step( function(){ t( "simple, times", ii = 3) })
208 .repeat( function(){ t( "repeat simple step", ii)
209 if( --ii === 0 ){
210 t( "break simple repeat")
211 this.break
212 } })
213 .step( function(){ t( "simple repeat done") })
214 .step( function(){ t( "sleep, times", ii = 2) })
215 .repeat( function(){ this
216 .step( function(){ t( "repeat sleep", ii)
217 this.sleep( 1) })
218 .step( function(){ t( "done sleep", ii) })
219 .step( function(){ if( --ii === 0 ){
220 t( "break sleep repeat")
221 this.break
222 } }) })
223 .step( function(){ t( "done ") })
224 .failure( function( e ){ t( "unexpected failure", e) })
225 .final( function(){ t( "final result", this.result)
226 check( "simple, times",
227 "repeat simple step",
228 "break simple repeat",
229 "simple repeat done",
230 "sleep, times",
231 "done sleep",
232 "break sleep repeat",
233 "done",
234 "final result"
235 )
236 test_8()
237 })
238 })
239
240 // l8.compile() needs to be provided a well scoped "eval()" or else it's result
241 // function would lack access to the global variables referenced by the code to
242 // (re)compile.
243 l8.eval = function( expr ){ return eval( expr) }
244
245 var test_8 = l8.compile( function xx(){
246 test = 8
247 var f1 = l8.Task( function( p1, p2 ){
248 t( "p1", p1, "p2", p2)
249 return [p1,p2]
250 })
251 step;
252 t( "pass parameter, get result");
253 f1( "aa", "bb")
254 step( r );
255 t( "both", r.join( "+"))
256 f1( "11", "22")
257 step( a, b ); t( "a", a, "b", b)
258 fork; return "f1"
259 fork; return "f2"
260 step( f1, f2 ); t( "f1", f1, "f2", f2)
261 fork; f1( "hello", "world")
262 fork; f1( "keep calm", "carry on")
263 step( h, k ); t( h.join( "! "), k.join( "? "))
264 failure( e ); t( "unexpected error", e)
265 final; check(
266 "p1, aa, p2, bb",
267 "both, aa+bb",
268 "a, 11, b, 22",
269 "f1, f1, f2, f2",
270 "hello! world, keep calm? carry on"
271 )
272 test_9()
273 })
274
275 var test_9 = l8.Task( function(){
276 test = 9
277 var fibonacci = function(){
278 var i = 0, j = 1;
279 repeat; begin
280 t( "yield", i)
281 this.yield( i);
282 var tmp = i;
283 i = j;
284 j += tmp;
285 end
286 step; t( "producer done")
287 failure( e ); t( "fib, unexpected error", e)
288 }
289 fibonacci = l8.compileGenerator( fibonacci)
290 var gen = fibonacci()
291 var count_down = 10
292 this.repeat( function(){
293 this.step( function( ){
294 if( !count_down-- ) this.break
295 gen.next()
296 }).step( function( r ){
297 t( count_down, "fibo", r)
298 })
299 }).step( function(){
300 t( "consumer done")
301 }).failure( function( e ){ t( "unexpected error", e)
302 }).final( function(){
303 check(
304 "fibo, 1",
305 "fibo, 1",
306 "fibo, 2",
307 "fibo, 3",
308 "fibo, 5",
309 "fibo, 8",
310 "fibo, 13",
311 "fibo, 21",
312 "fibo, 34",
313 "yield, 55",
314 "consumer done"
315 )
316 test_10()
317 })
318 })
319
320 var test_10 = l8.Task( function(){
321 test = 10
322 var inner = l8.Task( function(){
323 innerer( this)
324 this.step( function( ){ t( "!!! Unexpected step in inner()")})
325 this.success( function( r ){ t( "inner success", r) })
326 this.final( function( e, r ){ t( "inner final", e, r) })
327 })
328 var innerer = l8.Task( function( ret ){
329 innerest( ret)
330 this.step( function( ){ t( "!!! Unexpected step in innerer()")})
331 this.success( function( r ){ t( "innerer success", r) })
332 this.final( function( e, r ){ t( "innerer final", e, r) })
333 })
334 var innerest = l8.Task( function( ret ){
335 this.final( function( e, r ){ t( "innerest final", e, r) })
336 ret.return( "From innerest")
337 this.step( function( ){ t( "!!! Unexpected step in innerer()")})
338 this.success( function( r ){ t( "!!! Unexpected success", r) })
339 })
340 this
341 .step( function( ){ t( "inner()") })
342 .step( function( ){ inner() })
343 .step( function( r ){ t( "return", r) })
344 .failure( function( e ){ t( "Unexpected error", e) })
345 .final( function( ){
346 check(
347 "inner()",
348 "innerest final, From innerest",
349 "innerer success, From innerest",
350 "innerer final, From innerest",
351 "inner success, From innerest",
352 "inner final, From innerest",
353 "return, From innerest"
354 )
355 test_11()
356 })
357 })
358
359 var test_11 = l8.Task( function(){
360 test = 11
361 // Let's compare the speed, first "classical" style, using callbacks
362 function recur( n, next ){
363 if( --n > 0 ){
364 // Note: l8.tick() is about 20 times slower in chrome than in nodejs...
365 l8.tick( function(){ recur( n, next) })
366 }else{
367 next()
368 }
369 }
370 // And then l8 style, using steps
371 var l8recur = l8.Task( function l8recur_task( n ){
372 // No l8.tick() involved, l8 scheduler instead
373 if( --n > 0 ){ l8recur( n) }
374 })
375 var now
376 var n = 3
377 var p = 10000 // 100000; sometimes, it si very very slow, browser issue?
378 var factor = 2 // 50 by december 2012, 2 by feb 2013
379 var ii // 15 was average in nodejs initially.
380 var duration // 2013/02/03, 0,23 in Chrome, with browserify, 5 in cloud9
381 var l8duration
382 var tid
383 var last_tid
384 var was_debug = l8.debug()
385 this
386 .step( function(){ this.sleep( 1) })
387 .step( function(){ now = l8.now; l8.debug( false) })
388 .step( function(){
389 var done = 0
390 var task = this
391 for( var ii = 0 ; ii < p ; ii++ ){
392 l8.tick( function(){
393 recur( n, function(){ if( ++done === p ) task.resume() })
394 })
395 }
396 task.pause()
397 })
398 .step( function(){ this.sleep( 1) })
399 .step( function(){
400 duration = -1 + l8.now - now
401 t( n * p, "times async recur()", duration, "millisecs")
402 })
403 .step( function(){ this.sleep( 1) })
404 .step( function(){
405 now = l8.now
406 ii = 0
407 tid = l8.current.id
408 })
409 .repeat( function(){
410 if( ii >= p / factor ) this.break
411 l8recur( n)
412 ii++
413 })
414 .step( function(){ this.sleep( 1) })
415 .fork( function(){ last_tid = this.current.id } )
416 .step( function(){
417 l8.debug( was_debug )
418 l8duration = (-1 + (l8.now - now)) * factor
419 t( n * p, "times l8recur()", l8duration, "estimated millisecs")
420 t( l8duration / duration, "times slower than if native")
421 t( (n * p) / duration * 1000, "native calls/sec")
422 t( (n * p) / l8duration * 1000, "l8 calls/sec")
423 t( (last_tid - tid) / l8duration * 1000 * factor, "l8 tasks/sec")
424 })
425 .failure( function( e ){ t( "!!! unexpected error", e) })
426 .final( function(){
427 check(
428 "l8 calls/sec"
429 )
430 test_12()
431 })
432 })
433
434 var test_12 = l8.Task( function(){
435 try{
436 test = 12
437 var trace = function(){
438 t( "Current task " + l8.current
439 + " gets message '" + l8.get( "message")
440 + "' from " + l8.binding( "message").task)
441 }
442 var subtask = function(){
443 l8.label = "sub"
444 l8.step( function(){ trace() })
445 l8.step( function(){ l8.var( "message", "deeper") })
446 l8.step( function(){ l8.sleep( 100) })
447 l8.step( function(){ trace() })
448 }
449 l8.task( function(){
450 l8.label = "main"
451 l8.var( "message", "top")
452 l8.spawn( subtask )
453 l8.step( function(){ trace() })
454 l8.step( function(){ l8.join() })
455 })
456 l8.failure( function( e ){ t( "!!! unexpected error", e) })
457 l8.final( function(){
458 check(
459 "top",
460 "top",
461 "deeper"
462 )
463 test_last()
464 })
465 }catch( e ){ t( "!!! error " + e) }
466 })
467
468 var test_last = function(){
469 trace( "SUCCESS!!! All tests ok")
470 process.exit( 0)
471 }
472
473trace( "starting l8")
474l8.countdown( 10)
475test_1()