2 -- Copyright (C) 2008-2010 Matthew Wild
3 -- Copyright (C) 2008-2010 Waqas Hussain
5 -- This project is MIT/X11 licensed. Please see the
6 -- COPYING file in the source package for more information.
9 local tests_passed
= true;
11 function run_all_tests()
12 package
.loaded
["net.connlisteners"] = { get
= function () return {} end };
14 dotest
"util.multitable"
17 dotest
"core.stanza_router"
18 dotest
"core.s2smanager"
19 dotest
"core.configmanager"
23 dotest
"util.sasl.scram"
25 dotest
"util.throttle"
29 dotest
"util.xmppstream"
31 dotest
"net.http.parser"
33 dosingletest("test_sasl.lua", "latin1toutf8");
34 dosingletest("test_utf8.lua", "valid");
37 local verbosity
= tonumber(arg
[1]) or 2;
39 if os
.getenv("WINDIR") then
40 package
.path
= package
.path
..";..\\?.lua";
41 package
.cpath
= package
.cpath
..";..\\?.dll";
43 package
.path
= package
.path
..";../?.lua";
44 package
.cpath
= package
.cpath
..";../?.so";
51 local envloadfile
= require
"util.envload".envloadfile
;
53 local env_mt
= { __index
= function (t
,k
) return rawget(_realG
, k
) or print("WARNING: Attempt to access nil global '"..tostring(k
).."'"); end };
54 function testlib_new_env(t
)
55 return setmetatable(t
or {}, env_mt
);
58 function assert_equal(a
, b
, message
, level
)
60 error("\n assert_equal failed: "..tostring(a
).." ~= "..tostring(b
)..(message
and ("\n Message: "..message
) or ""), (level
or 1) + 1);
61 elseif verbosity
>= 4 then
62 print("assert_equal succeeded: "..tostring(a
).." == "..tostring(b
));
66 function assert_table(a
, message
, level
)
67 assert_equal(type(a
), "table", message
, (level
or 1) + 1);
69 function assert_function(a
, message
, level
)
70 assert_equal(type(a
), "function", message
, (level
or 1) + 1);
72 function assert_string(a
, message
, level
)
73 assert_equal(type(a
), "string", message
, (level
or 1) + 1);
75 function assert_boolean(a
, message
)
76 assert_equal(type(a
), "boolean", message
);
78 function assert_is(a
, message
)
79 assert_equal(not not a
, true, message
);
81 function assert_is_not(a
, message
)
82 assert_equal(not not a
, false, message
);
86 function dosingletest(testname
, fname
)
87 local tests
= setmetatable({}, { __index
= _realG
});
88 tests
.__unit
= testname
;
90 local chunk
, err
= envloadfile(testname
, tests
);
92 print("WARNING: ", "Failed to load tests for "..testname
, err
);
96 local success
, err
= pcall(chunk
);
98 print("WARNING: ", "Failed to initialise tests for "..testname
, err
);
102 if type(tests
[fname
]) ~= "function" then
103 error(testname
.." has no test '"..fname
.."'", 0);
107 local line_hook
, line_info
= new_line_coverage_monitor(testname
);
108 debug
.sethook(line_hook
, "l")
109 local success
, ret
= pcall(tests
[fname
]);
112 tests_passed
= false;
113 print("TEST FAILED! Unit: ["..testname
.."] Function: ["..fname
.."]");
114 print(" Location: "..ret
:gsub(":%s*\n", "\n"));
115 line_info(fname
, false, report_file
);
116 elseif verbosity
>= 2 then
117 print("TEST SUCCEEDED: ", testname
, fname
);
118 print(string.format("TEST COVERED %d/%d lines", line_info(fname
, true, report_file
)));
120 line_info(name
, success
, report_file
);
124 function dotest(unitname
)
125 local _fakeG
= setmetatable({}, {__index
= _realG
});
127 local tests
= setmetatable({}, { __index
= _fakeG
});
128 tests
.__unit
= unitname
;
129 local chunk
, err
= envloadfile("test_"..unitname
:gsub("%.", "_")..".lua", tests
);
131 print("WARNING: ", "Failed to load tests for "..unitname
, err
);
135 local success
, err
= pcall(chunk
);
137 print("WARNING: ", "Failed to initialise tests for "..unitname
, err
);
140 if tests
.env
then setmetatable(tests
.env
, { __index
= _realG
}); end
141 local unit
= setmetatable({}, { __index
= setmetatable({ _G
= tests
.env
or _fakeG
}, { __index
= tests
.env
or _fakeG
}) });
142 local fn
= "../"..unitname
:gsub("%.", "/")..".lua";
143 local chunk
, err
= envloadfile(fn
, unit
);
145 print("WARNING: ", "Failed to load module: "..unitname
, err
);
149 local oldmodule
, old_M
= _fakeG
.module
, _fakeG
._M
;
150 _fakeG
.module
= function ()
151 setmetatable(unit
, nil);
154 local success
, ret
= pcall(chunk
);
155 _fakeG
.module
, _fakeG
._M
= oldmodule
, old_M
;
157 print("WARNING: ", "Failed to initialise module: "..unitname
, ret
);
161 if type(ret
) == "table" then
162 for k
,v
in pairs(ret
) do
167 for name
, f
in pairs(unit
) do
168 local test
= rawget(tests
, name
);
169 if type(f
) ~= "function" then
170 if verbosity
>= 3 then
171 print("INFO: ", "Skipping "..unitname
.."."..name
.." because it is not a function");
173 elseif type(test
) ~= "function" then
174 if verbosity
>= 1 then
175 print("WARNING: ", unitname
.."."..name
.." has no test!");
178 if verbosity
>= 4 then
179 print("INFO: ", "Testing "..unitname
.."."..name
);
181 local line_hook
, line_info
= new_line_coverage_monitor(fn
);
182 debug
.sethook(line_hook
, "l")
183 local success
, ret
= pcall(test
, f
, unit
);
186 tests_passed
= false;
187 print("TEST FAILED! Unit: ["..unitname
.."] Function: ["..name
.."]");
188 print(" Location: "..ret
:gsub(":%s*\n", "\n"));
189 line_info(name
, false, report_file
);
190 elseif verbosity
>= 2 then
191 print("TEST SUCCEEDED: ", unitname
, name
);
192 print(string.format("TEST COVERED %d/%d lines", line_info(name
, true, report_file
)));
194 line_info(name
, success
, report_file
);
200 function runtest(f
, msg
)
201 if not f
then print("SUBTEST NOT FOUND: "..(msg
or "(no description)")); return; end
202 local success
, ret
= pcall(f
);
203 if success
and verbosity
>= 2 then
204 print("SUBTEST PASSED: "..(msg
or "(no description)"));
205 elseif (not success
) and verbosity
>= 0 then
206 tests_passed
= false;
207 print("SUBTEST FAILED: "..(msg
or "(no description)"));
212 function new_line_coverage_monitor(file
)
213 local lines_hit
, funcs_hit
= {}, {};
214 local total_lines
, covered_lines
= 0, 0;
216 for line
in io
.lines(file
) do
217 total_lines
= total_lines
+ 1;
220 return function (event
, line
) -- Line hook
221 if not lines_hit
[line
] then
222 local info
= debug
.getinfo(2, "fSL")
223 if not info
.source
:find(file
) then return; end
224 if not funcs_hit
[info
.func
] and info
.activelines
then
225 funcs_hit
[info
.func
] = true;
226 for line
in pairs(info
.activelines
) do
227 lines_hit
[line
] = false; -- Marks it as hittable, but not hit yet
230 if lines_hit
[line
] == false then
231 --print("New line hit: "..line.." in "..debug.getinfo(2, "S").source);
232 lines_hit
[line
] = true;
233 covered_lines
= covered_lines
+ 1;
237 function (test_name
, success
) -- Get info
238 local fn
= file
:gsub("^%W*", "");
239 local total_active_lines
= 0;
240 local coverage_file
= io
.open("reports/coverage_"..fn
:gsub("%W+", "_")..".report", "a+");
241 for line
, active
in pairs(lines_hit
) do
242 if active
~= nil then total_active_lines
= total_active_lines
+ 1; end
243 if coverage_file
then
244 if active
== false then coverage_file
:write(fn
, "|", line
, "|", name
or "", "|miss\n");
245 else coverage_file
:write(fn
, "|", line
, "|", name
or "", "|", tostring(success
), "\n"); end
248 if coverage_file
then coverage_file
:close(); end
249 return covered_lines
, total_active_lines
, lines_hit
;
255 os
.exit(tests_passed
and 0 or 1);