aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/error.lua264
1 files changed, 224 insertions, 40 deletions
diff --git a/tests/error.lua b/tests/error.lua
index 91ccebc..126161e 100644
--- a/tests/error.lua
+++ b/tests/error.lua
@@ -1,58 +1,242 @@
1-- 1--
2-- Error reporting 2-- Error reporting
3-- 3--
4-- Note: this code is supposed to end in errors; not included in 'make test' 4local which_tests, remaining_tests = {}, {}
5-- 5for k,v in ipairs{...} do
6 print("got arg:", type(v), tostring(v))
7 which_tests[v] = true
8 remaining_tests[v] = true
9end
10
11--##################################################################################################
12
13local lanes = require "lanes".configure{with_timers = false}
14local null = lanes.null
15
16--##################################################################################################
17
18-- Lua51 support
19local table_unpack = unpack or table.unpack
6 20
7local lanes = require "lanes".configure{ with_timers = false} 21--##################################################################################################
8 22
9local function lane( mode_) 23local WR = function(...)
10 set_error_reporting( mode_) 24 local str=""
11 local subf= function() -- this so that we can see the call stack 25 for i=1,select('#',...) do
12 error "aa" 26 local v = select(i,...)
13 --error({}) 27 if type(v) == "function" then
14 --error(error) 28 local infos = debug.getinfo(v)
29 --[[for k,v in pairs(infos) do
30 print(k,v)
31 end]]
32 v = infos.source..":"..infos.linedefined
33 end
34 str= str..tostring(v).."\t"
15 end 35 end
16 local subf2= function() 36 if io then
17 subf() 37 io.stderr:write(str.."\n")
18 end 38 end
19 subf2()
20end 39end
21 40
22local function cleanup(err) 41--##################################################################################################
42
43local lane_body = function(error_value_, finalizer_, finalizer_error_value_)
44 WR( "In Lane body: EV: ", error_value_, " F: ", finalizer_, " FEV: ", finalizer_error_value_)
45 if finalizer_ then
46 local finalizer = function(err_, stack_)
47 finalizer_(err_, stack_)
48 if finalizer_error_value_ then
49 WR ("Finalizer raises ", finalizer_error_value_)
50 error(finalizer_error_value_, 0) -- 0 so that error() doesn't alter the error value
51 end
52 end
53 set_finalizer(finalizer)
54 end
55
56 local subf = function() -- this so that we can see the call stack
57 if error_value_ then
58 error(error_value_, 0) -- 0 so that error() doesn't alter the error value
59 end
60 return "success"
61 end
62 local subf2 = function(b_)
63 return b_ or subf() -- prevent tail call
64 end
65 local subf3 = function(b_)
66 return b_ or subf2() -- prevent tail call
67 end
68 return subf3(false)
23end 69end
24 70
25local lgen = lanes.gen("*", { --[[finalizer=cleanup]] }, lane) 71--##################################################################################################
26 72
27--- 73local lane_finalizer = function(err_, stack_)
28io.stderr:write( "\n** Error catching **\n" ) 74 WR("In finalizer: ", err_, stack_)
29-- 75end
30 76
31local error_reporting_mode = "extended" 77--##################################################################################################
32local h= lgen( error_reporting_mode) 78
33local _,err,stack= h:join() -- wait for the lane (no automatic error propagation) 79local start_lane = function(error_reporting_mode_, error_value_, finalizer_, finalizer_error_value_)
80 return lanes.gen("*", {error_trace_level = error_reporting_mode_}, lane_body)(error_value_, finalizer_, finalizer_error_value_)
81end
34 82
35if err then 83--##################################################################################################
36 assert( type(stack)=="table" ) -- only true if lanes was compiled with ERROR_FULL_STACK == 1 84--##################################################################################################
37 io.stderr:write( "Lane error: "..tostring(err).."\n" )
38 85
39 if error_reporting_mode == "basic" then -- each stack line is a string in basic mode 86local make_table_error_mt = function()
40 io.stderr:write( "\t", table.concat(stack,"\n\t"), "\n" ); 87 return {
41 else -- each stack line is a table in extended mode 88 __tostring = function() return "{error as table}" end,
42 for line, details in pairs( stack) do 89 __eq = function(t1_, t2_)
43 io.stderr:write( "\t", tostring( line), "\n" ); 90 -- because tables transfered through linda/error reporting are identical, but not equal
44 for detail, value in pairs( details) do 91 -- however, due to metatable caching by Lanes, their metatables should be the same
45 io.stderr:write( "\t\t", tostring( detail), ":", tostring( value), "\n") 92 return getmetatable(t1_) == getmetatable(t2_)
46 end 93 end
47 end 94 }
48 end
49end 95end
50 96
51--- 97local lane_error_as_string = "'lane error as string'"
52io.stderr:write( "\n** Error propagation **\n" ) 98local lane_error_as_table = setmetatable({}, make_table_error_mt())
53-- 99local lane_error_as_linda = lanes.linda("'lane error'")
54local h2= lgen( error_reporting_mode) 100
55local _= h2[0] 101local finalizer_error_as_string = "'lane error as string'"
56assert(false) -- does NOT get here 102local finalizer_error_as_table = setmetatable({}, make_table_error_mt())
103local finalizer_error_as_linda = lanes.linda("'lane error'")
104
105local test_settings = {}
106local configure_tests = function()
107 local append_test = function(level, lane_error, finalizer, finalizer_error)
108 -- convert back null to nil
109 lane_error = lane_error ~= null and lane_error or nil
110 finalizer = finalizer ~= null and finalizer or nil
111 finalizer_error = finalizer_error ~= null and finalizer_error or nil
112 -- compose test description string
113 local test_header = table.concat({
114 level .. " error reporting",
115 (lane_error and tostring(lane_error) or "no error") .. " in lane",
116 (finalizer and "with" or "without").. " finalizer" .. ((finalizer and finalizer_error) and " raising " .. tostring(finalizer_error) or "")
117 }, ", ")
118 print(test_header)
119 test_settings[test_header] = { level, lane_error, finalizer, finalizer_error }
120 end
121 -- can't store nil in tables, use null instead
122 local levels = {
123 "minimal",
124 "basic",
125 "extended",
126 }
127 local errors = {
128 null,
129 lane_error_as_string,
130 lane_error_as_table,
131 lane_error_as_linda,
132 }
133 local finalizers = {
134 null,
135 lane_finalizer,
136 }
137 local finalizer_errors = {
138 null,
139 finalizer_error_as_string,
140 finalizer_error_as_table,
141 finalizer_error_as_linda,
142 }
143
144 for _, level in ipairs(levels) do
145 for _, lane_error in ipairs(errors) do
146 for _, finalizer in ipairs(finalizers) do
147 for _, finalizer_error in ipairs(finalizer_errors) do
148 append_test(level, lane_error, finalizer, finalizer_error)
149 end
150 end
151 end
152 end
153end
154
155configure_tests()
156-- do return end
157
158--##################################################################################################
159--##################################################################################################
160
161local do_error_catching_test = function(error_reporting_mode_, error_value_, finalizer_, finalizer_error_value_)
162 local h = start_lane(error_reporting_mode_, error_value_, finalizer_, finalizer_error_value_)
163 local ret,err,stack= h:join() -- wait for the lane (no automatic error propagation)
164 WR("Processing results for {", error_reporting_mode_, error_value_, finalizer_, finalizer_error_value_, "}")
165 if err then
166 assert(ret == nil)
167 assert(error_reporting_mode_ == "minimal" or type(stack)=="table") -- only true if lane was configured with error_trace_level ~= "minimal"
168 if err == error_value_ then
169 WR("Lane regular error: ", err)
170 elseif err == finalizer_error_value_ then
171 WR("Lane finalizer error: ", err)
172 else
173 WR("Unknown error: ", type(err), err)
174 assert(false)
175 end
176 if error_reporting_mode_ == "minimal" then
177 assert(stack == nil, table.concat{"stack is a ", type(stack)})
178 elseif error_reporting_mode_ == "basic" then -- each stack line is a string in basic mode
179 WR("STACK:\n", table.concat(stack,"\n\t"));
180 else -- each stack line is a table in extended mode
181 WR "STACK:"
182 for line, details in pairs(stack) do
183 WR("\t", line);
184 for detail, value in pairs(details) do
185 WR("\t\t", detail, ": ", value)
186 end
187 end
188 end
189 else -- no error
190 assert(ret == "success")
191 WR("No error in lane: ", ret)
192 end
193 WR "TEST OK"
194end
195
196--##################################################################################################
197
198local do_error_propagation_test = function(error_reporting_mode_, error_value_, finalizer_, finalizer_error_value_)
199 local wrapper = function()
200 local raises_error = (error_value_ or finalizer_error_value_) and true or false
201 local h = start_lane(error_reporting_mode_, error_value_, finalizer_, finalizer_error_value_)
202 local _ = h[0]
203 -- if the lane is configured to raise an error, we should not get here
204 assert(not raises_error, "should not get here")
205 end
206 local err, msg = pcall(wrapper)
207 WR("Processing results for {", error_reporting_mode_, error_value_, finalizer_, finalizer_error_value_, "}")
208 if err then
209 WR("Lane error: ", msg)
210 end
211 WR "TEST OK"
212end
213
214--##################################################################################################
215
216local perform_test = function(title_, test_)
217 WR "###########################################################################"
218 WR ("** " .. title_ .. " **")
219 for desc, settings in pairs(test_settings) do
220 WR "---------------------------------------------------------------------------"
221 WR(desc)
222 test_(table_unpack(settings))
223 end
224end
225
226if not next(which_tests) or which_tests.catch then
227 remaining_tests.catch = nil
228 perform_test("Error catching", do_error_catching_test)
229end
230
231--##################################################################################################
232if not next(which_tests) or which_tests.propagate then
233 remaining_tests.propagate = nil
234 perform_test("Error propagation", do_error_propagation_test)
235end
236
237-- ##################################################################################################
238
239local unknown_test, val = next(remaining_tests)
240assert(not unknown_test, tostring(unknown_test) .. " test is unknown")
57 241
58--never ends 242print "\nTHE END"