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 -----------------------
52 local traceback
= debug
.traceback
54 local setmetatable
= setmetatable
56 local orig_assert
= assert
57 local getfenv
= getfenv
58 local setfenv
= setfenv
59 local tostring = tostring
65 -- Start package scope
71 --------------------------------
72 -- Private data and functions --
73 --------------------------------
76 local do_assert
, check_msg
79 local stats_inc
, tc_mt
84 --------------------------
85 -- Type check functions --
86 --------------------------
89 return type(x
) == "nil"
92 function is_boolean(x
)
93 return type(x
) == "boolean"
97 return type(x
) == "number"
100 function is_string(x
)
101 return type(x
) == "string"
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)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
356 error(base_msg
..": "..user_msg
, 3)
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")
387 __lunit_teardown
= nil;
389 setmetatable(tc
, tc_mt
)
390 table.insert(testcases
, tc
)
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
434 ----------------------------------
435 -- Runs the complete Test Suite --
436 ----------------------------------
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))
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
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 ""
493 print(msg_assertions
..msg_passed
..msg_failed
..msg_run
..msg_warn
.."!")
499 if stats
.passed
== stats
.tests
then
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
)
531 print(errprefix
..": "..errmsg
)
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
)
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
])
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 ---------------------------------
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
590 print("WARN: Skipping '"..testname
.."'...")
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
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
649 elseif name
== "tests" or name
== "checks" then
651 elseif name
== "all" then
655 elseif string.find(name
, "^assert.*") and P
[name
] then
657 elseif string.find(name
, "^is_.+") and P
[name
] then
659 elseif name
== "TestCase" then
662 error("luniit.import(): invalid function '"..name
.."' to import", 2)
669 --------------------------------------------------
670 -- Installs a private environment on the caller --
671 --------------------------------------------------
673 function setprivfenv()
675 local new_env_mt
= { __index
= getfenv(2) }
676 setmetatable(new_env
, new_env_mt
)
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)