1ebec4837c8d04df8b976ff97f2ad7e5f4605ea3
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
62 -- Start package scope
68 --------------------------------
69 -- Private data and functions --
70 --------------------------------
73 local do_assert
, check_msg
76 local stats_inc
, tc_mt
81 --------------------------
82 -- Type check functions --
83 --------------------------
86 return type(x
) == "nil"
89 function is_boolean(x
)
90 return type(x
) == "boolean"
94 return type(x
) == "number"
98 return type(x
) == "string"
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)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
)
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
353 error(base_msg
..": "..user_msg
, 3)
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")
384 __lunit_teardown
= nil;
386 setmetatable(tc
, tc_mt
)
387 table.insert(testcases
, tc
)
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
431 ----------------------------------
432 -- Runs the complete Test Suite --
433 ----------------------------------
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
))
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
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 ""
490 print(msg_assertions
..msg_passed
..msg_failed
..msg_run
..msg_warn
.."!")
496 if stats
.passed
== stats
.tests
then
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
)
528 print(errprefix
..": "..errmsg
)
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
)
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
])
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 ---------------------------------
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
586 print("WARN: Skipping '"..testname
.."'...")
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
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
645 elseif name
== "tests" or name
== "checks" then
647 elseif name
== "all" then
651 elseif string.find(name
, "^assert.*") and P
[name
] then
653 elseif string.find(name
, "^is_.+") and P
[name
] then
655 elseif name
== "TestCase" then
658 error("luniit.import(): invalid function '"..name
.."' to import", 2)
665 --------------------------------------------------
666 -- Installs a private environment on the caller --
667 --------------------------------------------------
669 function setprivfenv()
671 local new_env_mt
= { __index
= getfenv(2) }
672 setmetatable(new_env
, new_env_mt
)
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)