1ebec4837c8d04df8b976ff97f2ad7e5f4605ea3
[luaevent.git] / test / lunit.lua
blob1ebec4837c8d04df8b976ff97f2ad7e5f4605ea3
2 --[[--------------------------------------------------------------------------
4 This file is part of lunit 0.4pre (alpha).
6 For Details about lunit look at: http://www.nessie.de/mroth/lunit/
8 Author: Michael Roth <mroth@nessie.de>
10 Copyright (c) 2004 Michael Roth <mroth@nessie.de>
12 Permission is hereby granted, free of charge, to any person
13 obtaining a copy of this software and associated documentation
14 files (the "Software"), to deal in the Software without restriction,
15 including without limitation the rights to use, copy, modify, merge,
16 publish, distribute, sublicense, and/or sell copies of the Software,
17 and to permit persons to whom the Software is furnished to do so,
18 subject to the following conditions:
20 The above copyright notice and this permission notice shall be
21 included in all copies or substantial portions of the Software.
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
26 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
27 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
28 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 --]]--------------------------------------------------------------------------
36 -----------------------
37 -- Intialize package --
38 -----------------------
40 local P = { }
41 lunit = P
43 -- Import
44 local type = type
45 local print = print
46 local ipairs = ipairs
47 local pairs = pairs
48 local string = string
49 local table = table
50 local pcall = pcall
51 local xpcall = xpcall
52 local traceback = debug.traceback
53 local error = error
54 local setmetatable = setmetatable
55 local rawset = rawset
56 local orig_assert = assert
57 local getfenv = getfenv
58 local setfenv = setfenv
59 local tostring = tostring
62 -- Start package scope
63 setfenv(1, P)
68 --------------------------------
69 -- Private data and functions --
70 --------------------------------
72 local run_testcase
73 local do_assert, check_msg
74 local stats = { }
75 local testcases = { }
76 local stats_inc, tc_mt
81 --------------------------
82 -- Type check functions --
83 --------------------------
85 function is_nil(x)
86 return type(x) == "nil"
87 end
89 function is_boolean(x)
90 return type(x) == "boolean"
91 end
93 function is_number(x)
94 return type(x) == "number"
95 end
97 function is_string(x)
98 return type(x) == "string"
99 end
101 function is_table(x)
102 return type(x) == "table"
105 function is_function(x)
106 return type(x) == "function"
109 function is_thread(x)
110 return type(x) == "thread"
113 function is_userdata(x)
114 return type(x) == "userdata"
120 ----------------------
121 -- Assert functions --
122 ----------------------
124 function assert(assertion, msg)
125 stats_inc("assertions")
126 check_msg("assert", msg)
127 do_assert(not not assertion, "assertion failed (was: "..tostring(assertion)..")", msg) -- (convert assertion to bool)
128 return assertion
132 function assert_fail(msg)
133 stats_inc("assertions")
134 check_msg("assert_fail", msg)
135 do_assert(false, "failure", msg)
139 function assert_true(actual, msg)
140 stats_inc("assertions")
141 check_msg("assert_true", msg)
142 do_assert(is_boolean(actual), "true expected but was a "..type(actual), msg)
143 do_assert(actual == true, "true expected but was false", msg)
144 return actual
148 function assert_false(actual, msg)
149 stats_inc("assertions")
150 check_msg("assert_false", msg)
151 do_assert(is_boolean(actual), "false expected but was a "..type(actual), msg)
152 do_assert(actual == false, "false expected but was true", msg)
153 return actual
157 function assert_equal(expected, actual, msg)
158 stats_inc("assertions")
159 check_msg("assert_equal", msg)
160 do_assert(expected == actual, "expected '"..tostring(expected).."' but was '"..tostring(actual).."'", msg)
161 return actual
165 function assert_not_equal(unexpected, actual, msg)
166 stats_inc("assertions")
167 check_msg("assert_not_equal", msg)
168 do_assert(unexpected ~= actual, "'"..tostring(expected).."' not expected but was one", msg)
169 return actual
173 function assert_match(pattern, actual, msg)
174 stats_inc("assertions")
175 check_msg("assert_match", msg)
176 do_assert(is_string(pattern), "assert_match expects the pattern as a string")
177 do_assert(is_string(actual), "expected a string to match pattern '"..pattern.."' but was a '"..type(actual).."'", msg)
178 do_assert(not not string.find(actual, pattern), "expected '"..actual.."' to match pattern '"..pattern.."' but doesn't", msg)
179 return actual
183 function assert_not_match(pattern, actual, msg)
184 stats_inc("assertions")
185 check_msg("assert_not_match", msg)
186 do_assert(is_string(actual), "expected a string to not match pattern '"..pattern.."' but was a '"..type(actual).."'", msg)
187 do_assert(string.find(actual, pattern) == nil, "expected '"..actual.."' to not match pattern '"..pattern.."' but it does", msg)
188 return actual
192 function assert_nil(actual, msg)
193 stats_inc("assertions")
194 check_msg("assert_nil", msg)
195 do_assert(is_nil(actual), "nil expected but was a "..type(actual), msg)
196 return actual
200 function assert_not_nil(actual, msg)
201 stats_inc("assertions")
202 check_msg("assert_not_nil", msg)
203 do_assert(not is_nil(actual), "nil not expected but was one", msg)
204 return actual
208 function assert_boolean(actual, msg)
209 stats_inc("assertions")
210 check_msg("assert_boolean", msg)
211 do_assert(is_boolean(actual), "boolean expected but was a "..type(actual), msg)
212 return actual
216 function assert_not_boolean(actual, msg)
217 stats_inc("assertions")
218 check_msg("assert_not_boolean", msg)
219 do_assert(not is_boolean(actual), "boolean not expected but was one", msg)
220 return actual
224 function assert_number(actual, msg)
225 stats_inc("assertions")
226 check_msg("assert_number", msg)
227 do_assert(is_number(actual), "number expected but was a "..type(actual), msg)
228 return actual
232 function assert_not_number(actual, msg)
233 stats_inc("assertions")
234 check_msg("assert_not_number", msg)
235 do_assert(not is_number(actual), "number not expected but was one", msg)
236 return actual
240 function assert_string(actual, msg)
241 stats_inc("assertions")
242 check_msg("assert_string", msg)
243 do_assert(is_string(actual), "string expected but was a "..type(actual), msg)
244 return actual
248 function assert_not_string(actual, msg)
249 stats_inc("assertions")
250 check_msg("assert_not_string", msg)
251 do_assert(not is_string(actual), "string not expected but was one", msg)
252 return actual
256 function assert_table(actual, msg)
257 stats_inc("assertions")
258 check_msg("assert_table", msg)
259 do_assert(is_table(actual), "table expected but was a "..type(actual), msg)
260 return actual
264 function assert_not_table(actual, msg)
265 stats_inc("assertions")
266 check_msg("assert_not_table", msg)
267 do_assert(not is_table(actual), "table not expected but was one", msg)
268 return actual
272 function assert_function(actual, msg)
273 stats_inc("assertions")
274 check_msg("assert_function", msg)
275 do_assert(is_function(actual), "function expected but was a "..type(actual), msg)
276 return actual
280 function assert_not_function(actual, msg)
281 stats_inc("assertions")
282 check_msg("assert_not_function", msg)
283 do_assert(not is_function(actual), "function not expected but was one", msg)
284 return actual
288 function assert_thread(actual, msg)
289 stats_inc("assertions")
290 check_msg("assert_thread", msg)
291 do_assert(is_thread(actual), "thread expected but was a "..type(actual), msg)
292 return actual
296 function assert_not_thread(actual, msg)
297 stats_inc("assertions")
298 check_msg("assert_not_thread", msg)
299 do_assert(not is_thread(actual), "thread not expected but was one", msg)
300 return actual
304 function assert_userdata(actual, msg)
305 stats_inc("assertions")
306 check_msg("assert_userdata", msg)
307 do_assert(is_userdata(actual), "userdata expected but was a "..type(actual), msg)
308 return actual
312 function assert_not_userdata(actual, msg)
313 stats_inc("assertions")
314 check_msg("assert_not_userdata", msg)
315 do_assert(not is_userdata(actual), "userdata not expected but was one", msg)
316 return actual
320 function assert_error(msg, func)
321 stats_inc("assertions")
322 if is_nil(func) then func, msg = msg, nil end
323 check_msg("assert_error", msg)
324 do_assert(is_function(func), "assert_error expects a function as the last argument but it was a "..type(func))
325 local ok, errmsg = pcall(func)
326 do_assert(ok == false, "error expected but no error occurred", msg)
330 function assert_pass(msg, func)
331 stats_inc("assertions")
332 if is_nil(func) then func, msg = msg, nil end
333 check_msg("assert_pass", msg)
334 do_assert(is_function(func), "assert_pass expects a function as the last argument but it was a "..type(func))
335 local ok, errmsg = pcall(func)
336 if not ok then do_assert(ok == true, "no error expected but error was: "..errmsg, msg) end
342 -----------------------------------------------------------
343 -- Assert implementation that assumes it was called from --
344 -- lunit code which was called directly from user code. --
345 -----------------------------------------------------------
347 function do_assert(assertion, base_msg, user_msg)
348 orig_assert(is_boolean(assertion))
349 orig_assert(is_string(base_msg))
350 orig_assert(is_string(user_msg) or is_nil(user_msg))
351 if not assertion then
352 if user_msg then
353 error(base_msg..": "..user_msg, 3)
354 else
355 error(base_msg.."!", 3)
360 -------------------------------------------
361 -- Checks the msg argument in assert_xxx --
362 -------------------------------------------
364 function check_msg(name, msg)
365 orig_assert(is_string(name))
366 if not (is_nil(msg) or is_string(msg)) then
367 error("lunit."..name.."() expects the optional message as a string but it was a "..type(msg).."!" ,3)
374 -------------------------------------
375 -- Creates a new TestCase 'Object' --
376 -------------------------------------
378 function TestCase(name)
379 do_assert(is_string(name), "lunit.TestCase() needs a string as an argument")
380 local tc = {
381 __lunit_name = name;
382 __lunit_setup = nil;
383 __lunit_tests = { };
384 __lunit_teardown = nil;
386 setmetatable(tc, tc_mt)
387 table.insert(testcases, tc)
388 return tc
391 tc_mt = {
392 __newindex = function(tc, key, value)
393 rawset(tc, key, value)
394 if is_string(key) and is_function(value) then
395 local name = string.lower(key)
396 if string.find(name, "^test") or string.find(name, "test$") then
397 table.insert(tc.__lunit_tests, key)
398 elseif name == "setup" then
399 tc.__lunit_setup = value
400 elseif name == "teardown" then
401 tc.__lunit_teardown = value
409 -----------------------------------------
410 -- Wrap Functions in a TestCase object --
411 -----------------------------------------
413 function wrap(name, ...)
414 if is_function(name) then
415 table.insert(arg, 1, name)
416 name = "Anonymous Testcase"
419 local tc = TestCase(name)
420 for index, test in ipairs(arg) do
421 tc["Test #"..index] = test
423 return tc
431 ----------------------------------
432 -- Runs the complete Test Suite --
433 ----------------------------------
435 function run()
437 ---------------------------
438 -- Initialize statistics --
439 ---------------------------
441 stats.testcases = 0 -- Total number of Test Cases
442 stats.tests = 0 -- Total number of all Tests in all Test Cases
443 stats.run = 0 -- Number of Tests run
444 stats.notrun = 0 -- Number of Tests not run
445 stats.failed = 0 -- Number of Tests failed
446 stats.warnings = 0 -- Number of Warnings (teardown)
447 stats.errors = 0 -- Number of Errors (setup)
448 stats.passed = 0 -- Number of Test passed
449 stats.assertions = 0 -- Number of all assertions made in all Test in all Test Cases
451 --------------------------------
452 -- Count Test Cases and Tests --
453 --------------------------------
455 stats.testcases = table.getn(testcases)
457 for _, tc in ipairs(testcases) do
458 stats_inc("tests" , table.getn(tc.__lunit_tests))
461 ------------------
462 -- Print Header --
463 ------------------
465 print()
466 print("#### Test Suite with "..stats.tests.." Tests in "..stats.testcases.." Test Cases loaded.")
468 ------------------------
469 -- Run all Test Cases --
470 ------------------------
472 for _, tc in ipairs(testcases) do
473 run_testcase(tc)
476 ------------------
477 -- Print Footer --
478 ------------------
480 print()
481 print("#### Test Suite finished.")
483 local msg_assertions = stats.assertions.." Assertions checked. "
484 local msg_passed = stats.passed == stats.tests and "All Tests passed" or stats.passed.." Tests passed"
485 local msg_failed = stats.failed > 0 and ", "..stats.failed.." failed" or ""
486 local msg_run = stats.notrun > 0 and ", "..stats.notrun.." not run" or ""
487 local msg_warn = stats.warnings > 0 and ", "..stats.warnings.." warnings" or ""
489 print()
490 print(msg_assertions..msg_passed..msg_failed..msg_run..msg_warn.."!")
492 -----------------
493 -- Return code --
494 -----------------
496 if stats.passed == stats.tests then
497 return 0
498 else
499 return 1
506 -----------------------------
507 -- Runs a single Test Case --
508 -----------------------------
510 function run_testcase(tc)
512 orig_assert(is_table(tc))
513 orig_assert(is_table(tc.__lunit_tests))
514 orig_assert(is_string(tc.__lunit_name))
515 orig_assert(is_nil(tc.__lunit_setup) or is_function(tc.__lunit_setup))
516 orig_assert(is_nil(tc.__lunit_teardown) or is_function(tc.__lunit_teardown))
518 ----------------------------------
519 -- Protected call to a function --
520 ----------------------------------
522 local function call(errprefix, func)
523 orig_assert(is_string(errprefix))
524 orig_assert(is_function(func))
525 local ok, errmsg = xpcall(function() func(tc) end, traceback)
526 if not ok then
527 print()
528 print(errprefix..": "..errmsg)
530 return ok
533 ------------------------------------
534 -- Calls setup() on the Test Case --
535 ------------------------------------
537 local function setup(testname)
538 if tc.__lunit_setup then
539 return call("ERROR: "..testname..": setup() failed", tc.__lunit_setup)
540 else
541 return true
545 ------------------------------------------
546 -- Calls a single Test on the Test Case --
547 ------------------------------------------
549 local function run(testname)
550 orig_assert(is_string(testname))
551 orig_assert(is_function(tc[testname]))
552 local ok = call("FAIL: "..testname, tc[testname])
553 if not ok then
554 stats_inc("failed")
555 else
556 stats_inc("passed")
558 return ok
561 ---------------------------------------
562 -- Calls teardown() on the Test Case --
563 ---------------------------------------
565 local function teardown(testname)
566 if tc.__lunit_teardown then
567 if not call("WARNING: "..testname..": teardown() failed", tc.__lunit_teardown) then
568 stats_inc("warnings")
573 ---------------------------------
574 -- Run all Tests on a TestCase --
575 ---------------------------------
577 print()
578 print("#### Running '"..tc.__lunit_name.."' ("..table.getn(tc.__lunit_tests).." Tests)...")
580 for _, testname in ipairs(tc.__lunit_tests) do
581 if setup(testname) then
582 run(testname)
583 stats_inc("run")
584 teardown(testname)
585 else
586 print("WARN: Skipping '"..testname.."'...")
587 stats_inc("notrun")
596 ---------------------
597 -- Import function --
598 ---------------------
600 function import(name)
602 do_assert(is_string(name), "lunit.import() expects a single string as argument")
604 local user_env = getfenv(2)
606 --------------------------------------------------
607 -- Installs a specific function in the user env --
608 --------------------------------------------------
610 local function install(funcname)
611 user_env[funcname] = P[funcname]
615 ----------------------------------------------------------
616 -- Install functions matching a pattern in the user env --
617 ----------------------------------------------------------
619 local function install_pattern(pattern)
620 for funcname, _ in pairs(P) do
621 if string.find(funcname, pattern) then
622 install(funcname)
627 ------------------------------------------------------------
628 -- Installs assert() and all assert_xxx() in the user env --
629 ------------------------------------------------------------
631 local function install_asserts()
632 install_pattern("^assert.*")
635 -------------------------------------------
636 -- Installs all is_xxx() in the user env --
637 -------------------------------------------
639 local function install_tests()
640 install_pattern("^is_.+")
643 if name == "asserts" or name == "assertions" then
644 install_asserts()
645 elseif name == "tests" or name == "checks" then
646 install_tests()
647 elseif name == "all" then
648 install_asserts()
649 install_tests()
650 install("TestCase")
651 elseif string.find(name, "^assert.*") and P[name] then
652 install(name)
653 elseif string.find(name, "^is_.+") and P[name] then
654 install(name)
655 elseif name == "TestCase" then
656 install("TestCase")
657 else
658 error("luniit.import(): invalid function '"..name.."' to import", 2)
665 --------------------------------------------------
666 -- Installs a private environment on the caller --
667 --------------------------------------------------
669 function setprivfenv()
670 local new_env = { }
671 local new_env_mt = { __index = getfenv(2) }
672 setmetatable(new_env, new_env_mt)
673 setfenv(2, new_env)
679 --------------------------------------------------
680 -- Increments a counter in the statistics table --
681 --------------------------------------------------
683 function stats_inc(varname, value)
684 orig_assert(is_table(stats))
685 orig_assert(is_string(varname))
686 orig_assert(is_nil(value) or is_number(value))
687 if not stats[varname] then return end
688 stats[varname] = stats[varname] + (value or 1)