Template repo for tiny cross-platform apps that can be modified on phone, tablet or computer.
1-- Some primitives for tests.
2
3function run_tests()
4 local sorted_names = {}
5 for name,binding in pairs(_G) do
6 if name:find('test_') == 1 then
7 table.insert(sorted_names, name)
8 end
9 end
10 table.sort(sorted_names)
11 Test_errors = {}
12 for _,name in ipairs(sorted_names) do
13 xpcall(_G[name], function(err) prepend_debug_info_to_test_failure(name, err) end)
14 end
15 if #Test_errors > 0 then
16 error(('There were %d test failures:\n%s'):format(#Test_errors, table.concat(Test_errors)))
17 end
18end
19
20function prepend_debug_info_to_test_failure(test_name, err)
21 local err_without_line_number = err:gsub('^[^:]*:[^:]*: ', '')
22 local stack_trace = debug.traceback('', --[[stack frame]]5) -- most likely to be useful, but set to 0 for a complete stack trace
23 local file_and_line_number = stack_trace:gsub('stack traceback:\n', ''):gsub(': .*', '')
24 local full_error = file_and_line_number..':'..test_name..' -- '..err_without_line_number
25 -- uncomment this line for a complete stack trace
26--? local full_error = file_and_line_number..':'..test_name..' -- '..err_without_line_number..'\t\t'..stack_trace:gsub('\n', '\n\t\t')
27 table.insert(Test_errors, full_error)
28end
29
30
31function check(x, msg)
32 if not x then
33 error(msg)
34 end
35end
36
37function check_nil(x, msg)
38 if x ~= nil then
39 error(msg..'; should be nil but got "'..x..'"')
40 end
41end
42
43function check_eq(x, expected, msg)
44 if not eq(x, expected) then
45 error(msg..'; should be "'..expected..'" but got "'..x..'"')
46 end
47end
48
49function eq(a, b)
50 if type(a) ~= type(b) then return false end
51 if type(a) == 'table' then
52 if #a ~= #b then return false end
53 for k, v in pairs(a) do
54 if not eq(b[k], v) then
55 return false
56 end
57 end
58 for k, v in pairs(b) do
59 if not eq(a[k], v) then
60 return false
61 end
62 end
63 return true
64 end
65 return a == b
66end