Merge branch 'release/0.4.6'
[luaevent.git] / test / lunit.lua
blob15ea06f0c815ad49f64bded02d11631bfbcce91b
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 if not setfenv then
63 _ENV = P
64 else
65 -- Start package scope
66 setfenv(1, P)
67 end
71 --------------------------------
72 -- Private data and functions --
73 --------------------------------
75 local run_testcase
76 local do_assert, check_msg
77 local stats = { }
78 local testcases = { }
79 local stats_inc, tc_mt
84 --------------------------
85 -- Type check functions --
86 --------------------------
88 function is_nil(x)
89 return type(x) == "nil"
90 end
92 function is_boolean(x)
93 return type(x) == "boolean"
94 end
96 function is_number(x)
97 return type(x) == "number"
98 end
100 function is_string(x)
101 return type(x) == "string"
104 function is_table(x)
105 return type(x) == "table"
108 function is_function(x)
109 return type(x) == "function"
112 function is_thread(x)
113 return type(x) == "thread"
116 function is_userdata(x)
117 return type(x) == "userdata"
123 ----------------------
124 -- Assert functions --
125 ----------------------
127 function assert(assertion, msg)
128 stats_inc("assertions")
129 check_msg("assert", msg)
130 do_assert(not not assertion, "assertion failed (was: "..tostring(assertion)..")", msg) -- (convert assertion to bool)
131 return assertion
135 function assert_fail(msg)
136 stats_inc("assertions")
137 check_msg("assert_fail", msg)
138 do_assert(false, "failure", msg)
142 function assert_true(actual, msg)
143 stats_inc("assertions")
144 check_msg("assert_true", msg)
145 do_assert(is_boolean(actual), "true expected but was a "..type(actual), msg)
146 do_assert(actual == true, "true expected but was false", msg)
147 return actual
151 function assert_false(actual, msg)
152 stats_inc("assertions")
153 check_msg("assert_false", msg)
154 do_assert(is_boolean(actual), "false expected but was a "..type(actual), msg)
155 do_assert(actual == false, "false expected but was true", msg)
156 return actual
160 function assert_equal(expected, actual, msg)
161 stats_inc("assertions")
162 check_msg("assert_equal", msg)
163 do_assert(expected == actual, "expected '"..tostring(expected).."' but was '"..tostring(actual).."'", msg)
164 return actual
168 function assert_not_equal(unexpected, actual, msg)
169 stats_inc("assertions")
170 check_msg("assert_not_equal", msg)
171 do_assert(unexpected ~= actual, "'"..tostring(expected).."' not expected but was one", msg)
172 return actual
176 function assert_match(pattern, actual, msg)
177 stats_inc("assertions")
178 check_msg("assert_match", msg)
179 do_assert(is_string(pattern), "assert_match expects the pattern as a string")
180 do_assert(is_string(actual), "expected a string to match pattern '"..pattern.."' but was a '"..type(actual).."'", msg)
181 do_assert(not not string.find(actual, pattern), "expected '"..actual.."' to match pattern '"..pattern.."' but doesn't", msg)
182 return actual
186 function assert_not_match(pattern, actual, msg)
187 stats_inc("assertions")
188 check_msg("assert_not_match", msg)
189 do_assert(is_string(actual), "expected a string to not match pattern '"..pattern.."' but was a '"..type(actual).."'", msg)
190 do_assert(string.find(actual, pattern) == nil, "expected '"..actual.."' to not match pattern '"..pattern.."' but it does", msg)
191 return actual
195 function assert_nil(actual, msg)
196 stats_inc("assertions")
197 check_msg("assert_nil", msg)
198 do_assert(is_nil(actual), "nil expected but was a "..type(actual), msg)
199 return actual
203 function assert_not_nil(actual, msg)
204 stats_inc("assertions")
205 check_msg("assert_not_nil", msg)
206 do_assert(not is_nil(actual), "nil not expected but was one", msg)
207 return actual
211 function assert_boolean(actual, msg)
212 stats_inc("assertions")
213 check_msg("assert_boolean", msg)
214 do_assert(is_boolean(actual), "boolean expected but was a "..type(actual), msg)
215 return actual
219 function assert_not_boolean(actual, msg)
220 stats_inc("assertions")
221 check_msg("assert_not_boolean", msg)
222 do_assert(not is_boolean(actual), "boolean not expected but was one", msg)
223 return actual
227 function assert_number(actual, msg)
228 stats_inc("assertions")
229 check_msg("assert_number", msg)
230 do_assert(is_number(actual), "number expected but was a "..type(actual), msg)
231 return actual
235 function assert_not_number(actual, msg)
236 stats_inc("assertions")
237 check_msg("assert_not_number", msg)
238 do_assert(not is_number(actual), "number not expected but was one", msg)
239 return actual
243 function assert_string(actual, msg)
244 stats_inc("assertions")
245 check_msg("assert_string", msg)
246 do_assert(is_string(actual), "string expected but was a "..type(actual), msg)
247 return actual
251 function assert_not_string(actual, msg)
252 stats_inc("assertions")
253 check_msg("assert_not_string", msg)
254 do_assert(not is_string(actual), "string not expected but was one", msg)
255 return actual
259 function assert_table(actual, msg)
260 stats_inc("assertions")
261 check_msg("assert_table", msg)
262 do_assert(is_table(actual), "table expected but was a "..type(actual), msg)
263 return actual
267 function assert_not_table(actual, msg)
268 stats_inc("assertions")
269 check_msg("assert_not_table", msg)
270 do_assert(not is_table(actual), "table not expected but was one", msg)
271 return actual
275 function assert_function(actual, msg)
276 stats_inc("assertions")
277 check_msg("assert_function", msg)
278 do_assert(is_function(actual), "function expected but was a "..type(actual), msg)
279 return actual
283 function assert_not_function(actual, msg)
284 stats_inc("assertions")
285 check_msg("assert_not_function", msg)
286 do_assert(not is_function(actual), "function not expected but was one", msg)
287 return actual
291 function assert_thread(actual, msg)
292 stats_inc("assertions")
293 check_msg("assert_thread", msg)
294 do_assert(is_thread(actual), "thread expected but was a "..type(actual), msg)
295 return actual
299 function assert_not_thread(actual, msg)
300 stats_inc("assertions")
301 check_msg("assert_not_thread", msg)
302 do_assert(not is_thread(actual), "thread not expected but was one", msg)
303 return actual
307 function assert_userdata(actual, msg)
308 stats_inc("assertions")
309 check_msg("assert_userdata", msg)
310 do_assert(is_userdata(actual), "userdata expected but was a "..type(actual), msg)
311 return actual
315 function assert_not_userdata(actual, msg)
316 stats_inc("assertions")
317 check_msg("assert_not_userdata", msg)
318 do_assert(not is_userdata(actual), "userdata not expected but was one", msg)
319 return actual
323 function assert_error(msg, func)
324 stats_inc("assertions")
325 if is_nil(func) then func, msg = msg, nil end
326 check_msg("assert_error", msg)
327 do_assert(is_function(func), "assert_error expects a function as the last argument but it was a "..type(func))
328 local ok, errmsg = pcall(func)
329 do_assert(ok == false, "error expected but no error occurred", msg)
333 function assert_pass(msg, func)
334 stats_inc("assertions")
335 if is_nil(func) then func, msg = msg, nil end
336 check_msg("assert_pass", msg)
337 do_assert(is_function(func), "assert_pass expects a function as the last argument but it was a "..type(func))
338 local ok, errmsg = pcall(func)
339 if not ok then do_assert(ok == true, "no error expected but error was: "..errmsg, msg) end
345 -----------------------------------------------------------
346 -- Assert implementation that assumes it was called from --
347 -- lunit code which was called directly from user code. --
348 -----------------------------------------------------------
350 function do_assert(assertion, base_msg, user_msg)
351 orig_assert(is_boolean(assertion))
352 orig_assert(is_string(base_msg))
353 orig_assert(is_string(user_msg) or is_nil(user_msg))
354 if not assertion then
355 if user_msg then
356 error(base_msg..": "..user_msg, 3)
357 else
358 error(base_msg.."!", 3)
363 -------------------------------------------
364 -- Checks the msg argument in assert_xxx --
365 -------------------------------------------
367 function check_msg(name, msg)
368 orig_assert(is_string(name))
369 if not (is_nil(msg) or is_string(msg)) then
370 error("lunit."..name.."() expects the optional message as a string but it was a "..type(msg).."!" ,3)
377 -------------------------------------
378 -- Creates a new TestCase 'Object' --
379 -------------------------------------
381 function TestCase(name)
382 do_assert(is_string(name), "lunit.TestCase() needs a string as an argument")
383 local tc = {
384 __lunit_name = name;
385 __lunit_setup = nil;
386 __lunit_tests = { };
387 __lunit_teardown = nil;
389 setmetatable(tc, tc_mt)
390 table.insert(testcases, tc)
391 return tc
394 tc_mt = {
395 __newindex = function(tc, key, value)
396 rawset(tc, key, value)
397 if is_string(key) and is_function(value) then
398 local name = string.lower(key)
399 if string.find(name, "^test") or string.find(name, "test$") then
400 table.insert(tc.__lunit_tests, key)
401 elseif name == "setup" then
402 tc.__lunit_setup = value
403 elseif name == "teardown" then
404 tc.__lunit_teardown = value
412 -----------------------------------------
413 -- Wrap Functions in a TestCase object --
414 -----------------------------------------
416 function wrap(name, ...)
417 if is_function(name) then
418 table.insert(arg, 1, name)
419 name = "Anonymous Testcase"
422 local tc = TestCase(name)
423 for index, test in ipairs(arg) do
424 tc["Test #"..index] = test
426 return tc
434 ----------------------------------
435 -- Runs the complete Test Suite --
436 ----------------------------------
438 function run()
440 ---------------------------
441 -- Initialize statistics --
442 ---------------------------
444 stats.testcases = 0 -- Total number of Test Cases
445 stats.tests = 0 -- Total number of all Tests in all Test Cases
446 stats.run = 0 -- Number of Tests run
447 stats.notrun = 0 -- Number of Tests not run
448 stats.failed = 0 -- Number of Tests failed
449 stats.warnings = 0 -- Number of Warnings (teardown)
450 stats.errors = 0 -- Number of Errors (setup)
451 stats.passed = 0 -- Number of Test passed
452 stats.assertions = 0 -- Number of all assertions made in all Test in all Test Cases
454 --------------------------------
455 -- Count Test Cases and Tests --
456 --------------------------------
458 stats.testcases = #testcases -- table.getn(testcases)
460 for _, tc in ipairs(testcases) do
461 stats_inc("tests" , #tc.__lunit_tests) --table.getn(tc.__lunit_tests))
464 ------------------
465 -- Print Header --
466 ------------------
468 print()
469 print("#### Test Suite with "..stats.tests.." Tests in "..stats.testcases.." Test Cases loaded.")
471 ------------------------
472 -- Run all Test Cases --
473 ------------------------
475 for _, tc in ipairs(testcases) do
476 run_testcase(tc)
479 ------------------
480 -- Print Footer --
481 ------------------
483 print()
484 print("#### Test Suite finished.")
486 local msg_assertions = stats.assertions.." Assertions checked. "
487 local msg_passed = stats.passed == stats.tests and "All Tests passed" or stats.passed.." Tests passed"
488 local msg_failed = stats.failed > 0 and ", "..stats.failed.." failed" or ""
489 local msg_run = stats.notrun > 0 and ", "..stats.notrun.." not run" or ""
490 local msg_warn = stats.warnings > 0 and ", "..stats.warnings.." warnings" or ""
492 print()
493 print(msg_assertions..msg_passed..msg_failed..msg_run..msg_warn.."!")
495 -----------------
496 -- Return code --
497 -----------------
499 if stats.passed == stats.tests then
500 return 0
501 else
502 return 1
509 -----------------------------
510 -- Runs a single Test Case --
511 -----------------------------
513 function run_testcase(tc)
515 orig_assert(is_table(tc))
516 orig_assert(is_table(tc.__lunit_tests))
517 orig_assert(is_string(tc.__lunit_name))
518 orig_assert(is_nil(tc.__lunit_setup) or is_function(tc.__lunit_setup))
519 orig_assert(is_nil(tc.__lunit_teardown) or is_function(tc.__lunit_teardown))
521 ----------------------------------
522 -- Protected call to a function --
523 ----------------------------------
525 local function call(errprefix, func)
526 orig_assert(is_string(errprefix))
527 orig_assert(is_function(func))
528 local ok, errmsg = xpcall(function() func(tc) end, traceback)
529 if not ok then
530 print()
531 print(errprefix..": "..errmsg)
533 return ok
536 ------------------------------------
537 -- Calls setup() on the Test Case --
538 ------------------------------------
540 local function setup(testname)
541 if tc.__lunit_setup then
542 return call("ERROR: "..testname..": setup() failed", tc.__lunit_setup)
543 else
544 return true
548 ------------------------------------------
549 -- Calls a single Test on the Test Case --
550 ------------------------------------------
552 local function run(testname)
553 orig_assert(is_string(testname))
554 orig_assert(is_function(tc[testname]))
555 local ok = call("FAIL: "..testname, tc[testname])
556 if not ok then
557 stats_inc("failed")
558 else
559 stats_inc("passed")
561 return ok
564 ---------------------------------------
565 -- Calls teardown() on the Test Case --
566 ---------------------------------------
568 local function teardown(testname)
569 if tc.__lunit_teardown then
570 if not call("WARNING: "..testname..": teardown() failed", tc.__lunit_teardown) then
571 stats_inc("warnings")
576 ---------------------------------
577 -- Run all Tests on a TestCase --
578 ---------------------------------
580 print()
581 --print("#### Running '"..tc.__lunit_name.."' ("..table.getn(tc.__lunit_tests).." Tests)...")
582 print("#### Running '"..tc.__lunit_name.."' ("..#tc.__lunit_tests.." Tests)...")
584 for _, testname in ipairs(tc.__lunit_tests) do
585 if setup(testname) then
586 run(testname)
587 stats_inc("run")
588 teardown(testname)
589 else
590 print("WARN: Skipping '"..testname.."'...")
591 stats_inc("notrun")
600 ---------------------
601 -- Import function --
602 ---------------------
604 function import(name)
606 do_assert(is_string(name), "lunit.import() expects a single string as argument")
608 local user_env = getfenv(2)
610 --------------------------------------------------
611 -- Installs a specific function in the user env --
612 --------------------------------------------------
614 local function install(funcname)
615 user_env[funcname] = P[funcname]
619 ----------------------------------------------------------
620 -- Install functions matching a pattern in the user env --
621 ----------------------------------------------------------
623 local function install_pattern(pattern)
624 for funcname, _ in pairs(P) do
625 if string.find(funcname, pattern) then
626 install(funcname)
631 ------------------------------------------------------------
632 -- Installs assert() and all assert_xxx() in the user env --
633 ------------------------------------------------------------
635 local function install_asserts()
636 install_pattern("^assert.*")
639 -------------------------------------------
640 -- Installs all is_xxx() in the user env --
641 -------------------------------------------
643 local function install_tests()
644 install_pattern("^is_.+")
647 if name == "asserts" or name == "assertions" then
648 install_asserts()
649 elseif name == "tests" or name == "checks" then
650 install_tests()
651 elseif name == "all" then
652 install_asserts()
653 install_tests()
654 install("TestCase")
655 elseif string.find(name, "^assert.*") and P[name] then
656 install(name)
657 elseif string.find(name, "^is_.+") and P[name] then
658 install(name)
659 elseif name == "TestCase" then
660 install("TestCase")
661 else
662 error("luniit.import(): invalid function '"..name.."' to import", 2)
669 --------------------------------------------------
670 -- Installs a private environment on the caller --
671 --------------------------------------------------
673 function setprivfenv()
674 local new_env = { }
675 local new_env_mt = { __index = getfenv(2) }
676 setmetatable(new_env, new_env_mt)
677 setfenv(2, new_env)
683 --------------------------------------------------
684 -- Increments a counter in the statistics table --
685 --------------------------------------------------
687 function stats_inc(varname, value)
688 orig_assert(is_table(stats))
689 orig_assert(is_string(varname))
690 orig_assert(is_nil(value) or is_number(value))
691 if not stats[varname] then return end
692 stats[varname] = stats[varname] + (value or 1)