summaryrefslogtreecommitdiff
path: root/tests/basic.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tests/basic.lua')
-rw-r--r--tests/basic.lua331
1 files changed, 331 insertions, 0 deletions
diff --git a/tests/basic.lua b/tests/basic.lua
new file mode 100644
index 0000000..ee31ed1
--- /dev/null
+++ b/tests/basic.lua
@@ -0,0 +1,331 @@
1--
2-- BASIC.LUA Copyright (c) 2007-08, Asko Kauppi <akauppi@gmail.com>
3--
4-- Selftests for Lua Lanes
5--
6-- To do:
7-- - ...
8--
9
10require "lanes"
11require "assert" -- assert.fails()
12
13local lanes_gen= assert( lanes.gen )
14local lanes_linda= assert( lanes.linda )
15
16local tostring= assert( tostring )
17
18local function PRINT(...)
19 local str=""
20 for i=1,select('#',...) do
21 str= str..tostring(select(i,...)).."\t"
22 end
23 if io then
24 io.stderr:write(str.."\n")
25 end
26end
27
28
29---=== Local helpers ===---
30
31local tables_match
32
33-- true if 'a' is a subtable of 'b'
34--
35local function subtable( a, b )
36 --
37 assert( type(a)=="table" and type(b)=="table" )
38
39 for k,v in pairs(b) do
40 if type(v)~=type(a[k]) then
41 return false -- not subtable (different types, or missing key)
42 elseif type(v)=="table" then
43 if not tables_match(v,a[k]) then return false end
44 else
45 if a[k] ~= v then return false end
46 end
47 end
48 return true -- is a subtable
49end
50
51-- true when contents of 'a' and 'b' are identific
52--
53tables_match= function( a, b )
54 return subtable( a, b ) and subtable( b, a )
55end
56
57
58---=== Tasking (basic) ===---
59
60local function task( a, b, c )
61 --error "111" -- testing error messages
62 assert(hey)
63 local v=0
64 for i=a,b,c do
65 v= v+i
66 end
67 return v, hey
68end
69
70local task_launch= lanes_gen( "", { globals={hey=true} }, task )
71 -- base stdlibs, normal priority
72
73-- 'task_launch' is a factory of multithreaded tasks, we can launch several:
74
75local lane1= task_launch( 100,200,3 )
76local lane2= task_launch( 200,300,4 )
77
78-- At this stage, states may be "pending", "running" or "done"
79
80local st1,st2= lane1.status, lane2.status
81PRINT(st1,st2)
82assert( st1=="pending" or st1=="running" or st1=="done" )
83assert( st2=="pending" or st2=="running" or st2=="done" )
84
85-- Accessing results ([1..N]) pends until they are available
86--
87PRINT("waiting...")
88local v1, v1_hey= lane1[1], lane1[2]
89local v2, v2_hey= lane2[1], lane2[2]
90
91PRINT( v1, v1_hey )
92assert( v1_hey == true )
93
94PRINT( v2, v2_hey )
95assert( v2_hey == true )
96
97assert( lane1.status == "done" )
98assert( lane1.status == "done" )
99
100
101---=== Tasking (cancelling) ===---
102
103local task_launch2= lanes_gen( "", { cancelstep=100, globals={hey=true} }, task )
104
105local N=999999999
106local lane9= task_launch2(1,N,1) -- huuuuuuge...
107
108-- Wait until state changes "pending"->"running"
109--
110local st
111local t0= os.time()
112while os.time()-t0 < 5 do
113 st= lane9.status
114 io.stderr:write( (i==1) and st.." " or '.' )
115 if st~="pending" then break end
116end
117PRINT(" "..st)
118
119if st=="error" then
120 local _= lane9[0] -- propagate the error here
121end
122if st=="done" then
123 error( "Looping to "..N.." was not long enough (cannot test cancellation)" )
124end
125assert( st=="running" )
126
127lane9:cancel()
128
129local t0= os.time()
130while os.time()-t0 < 5 do
131 st= lane9.status
132 io.stderr:write( (i==1) and st.." " or '.' )
133 if st~="running" then break end
134end
135PRINT(" "..st)
136assert( st == "cancelled" )
137
138
139---=== Communications ===---
140
141local function WR(...) io.stderr:write(...) end
142
143local chunk= function( linda )
144
145 local function receive() return linda:receive( "->" ) end
146 local function send(...) linda:send( "<-", ... ) end
147
148 WR( "Lane starts!\n" )
149
150 local v
151 v=receive(); WR( v.." received\n" ); assert( v==1 )
152 v=receive(); WR( v.." received\n" ); assert( v==2 )
153 v=receive(); WR( v.." received\n" ); assert( v==3 )
154
155 send( 1,2,3 ); WR( "1,2,3 sent\n" )
156 send 'a'; WR( "'a' sent\n" )
157 send { 'a', 'b', 'c', d=10 }; WR( "{'a','b','c',d=10} sent\n" )
158
159 v=receive(); WR( v.." received\n" ); assert( v==4 )
160
161 WR( "Lane ends!\n" )
162end
163
164local linda= lanes_linda()
165assert( type(linda) == "userdata" )
166 --
167 -- ["->"] master -> slave
168 -- ["<-"] slave <- master
169
170local function PEEK() return linda:get("<-") end
171local function SEND(...) linda:send( "->", ... ) end
172local function RECEIVE() return linda:receive( "<-" ) end
173
174local t= lanes_gen("io",chunk)(linda) -- prepare & launch
175
176SEND(1); WR( "1 sent\n" )
177SEND(2); WR( "2 sent\n" )
178for i=1,100 do
179 WR "."
180 assert( PEEK() == nil ) -- nothing coming in, yet
181end
182SEND(3); WR( "3 sent\n" )
183
184local a,b,c= RECEIVE(), RECEIVE(), RECEIVE()
185 WR( a..", "..b..", "..c.." received\n" )
186assert( a==1 and b==2 and c==3 )
187
188local a= RECEIVE(); WR( a.." received\n" )
189assert( a=='a' )
190
191local a= RECEIVE(); WR( type(a).." received\n" )
192assert( tables_match( a, {'a','b','c',d=10} ) )
193
194assert( PEEK() == nil )
195SEND(4)
196
197
198---=== Stdlib naming ===---
199
200local function io_os_f()
201 assert(io)
202 assert(os)
203 assert(print)
204 return true
205end
206
207local f1= lanes_gen( "io,os", io_os_f ) -- any delimiter will do
208local f2= lanes_gen( "io+os", io_os_f )
209local f3= lanes_gen( "io,os,base", io_os_f )
210
211assert.fails( function() lanes_gen( "xxx", io_os_f ) end )
212
213assert( f1()[1] )
214assert( f2()[1] )
215assert( f3()[1] )
216
217
218---=== Comms criss cross ===---
219
220-- We make two identical lanes, which are using the same Linda channel.
221--
222local tc= lanes_gen( "io",
223 function( linda, ch_in, ch_out )
224
225 local function STAGE(str)
226 io.stderr:write( ch_in..": "..str.."\n" )
227 linda:send( nil, ch_out, str )
228 local v= linda:receive( nil, ch_in )
229 assert(v==str)
230 end
231 STAGE("Hello")
232 STAGE("I was here first!")
233 STAGE("So waht?")
234 end
235)
236
237local linda= lanes_linda()
238
239local a,b= tc(linda, "A","B"), tc(linda, "B","A") -- launching two lanes, twisted comms
240
241local _= a[1],b[1] -- waits until they are both ready
242
243
244---=== Receive & send of code ===---
245
246local upvalue="123"
247
248local function chunk2( linda )
249 assert( upvalue=="123" ) -- even when running as separate thread
250
251 -- function name & line number should be there even as separate thread
252 --
253 local info= debug.getinfo(1) -- 1 = us
254 --
255 for k,v in pairs(info) do PRINT(k,v) end
256
257 assert( info.nups == 2 ) -- one upvalue + PRINT
258 assert( info.what == "Lua" )
259
260 --assert( info.name == "chunk2" ) -- name does not seem to come through
261 assert( string.match( info.source, "^@tests[/\\]basic.lua$" ) )
262 assert( string.match( info.short_src, "^tests[/\\]basic.lua$" ) )
263
264 -- These vary so let's not be picky (they're there..)
265 --
266 assert( info.linedefined > 200 ) -- start of 'chunk2'
267 assert( info.currentline > info.linedefined ) -- line of 'debug.getinfo'
268 assert( info.lastlinedefined > info.currentline ) -- end of 'chunk2'
269
270 local func,k= linda:receive( "down" )
271 assert( type(func)=="function" )
272 assert( k=="down" )
273
274 func(linda)
275
276 local str= linda:receive( "down" )
277 assert( str=="ok" )
278
279 linda:send( "up", function() return ":)" end, "ok2" )
280end
281
282local linda= lanes.linda()
283
284local t2= lanes_gen( "debug,string", chunk2 )(linda) -- prepare & launch
285
286linda:send( "down", function(linda) linda:send( "up", "ready!" ) end,
287 "ok" )
288
289-- wait to see if the tiny function gets executed
290--
291local s= linda:receive( "up" )
292PRINT(s)
293assert( s=="ready!" )
294
295-- returns of the 'chunk2' itself
296--
297local f= linda:receive( "up" )
298assert( type(f)=="function" )
299
300local s2= f()
301assert( s2==":)" )
302
303local ok2= linda:receive( "up" )
304assert( ok2 == "ok2" )
305
306
307---=== :join test ===---
308
309-- NOTE: 'unpack()' cannot be used on the lane handle; it will always return nil
310-- (unless [1..n] has been read earlier, in which case it would seemingly
311-- work).
312
313local S= lanes_gen( "table",
314 function(arg)
315 aux= {}
316 for i, v in ipairs(arg) do
317 table.insert (aux, 1, v)
318 end
319 return unpack(aux)
320end )
321
322h= S { 12, 13, 14 } -- execution starts, h[1..3] will get the return values
323
324local a,b,c,d= h:join()
325assert(a==14)
326assert(b==13)
327assert(c==12)
328assert(d==nil)
329
330--
331io.stderr:write "Done! :)\n"