Home | History | Annotate | Download | only in lua
      1 --[[
      2         luaunit.lua
      3 
      4 Description: A unit testing framework
      5 Homepage: https://github.com/bluebird75/luaunit
      6 Development by Philippe Fremy <phil (a] freehackers.org>
      7 Based on initial work of Ryu, Gwang (http://www.gpgstudy.com/gpgiki/LuaUnit)
      8 License: BSD License, see LICENSE.txt
      9 Version: 3.2
     10 ]]--
     11 
     12 require("math")
     13 local M={}
     14 
     15 -- private exported functions (for testing)
     16 M.private = {}
     17 
     18 M.VERSION='3.2'
     19 
     20 --[[ Some people like assertEquals( actual, expected ) and some people prefer
     21 assertEquals( expected, actual ).
     22 ]]--
     23 M.ORDER_ACTUAL_EXPECTED = true
     24 M.PRINT_TABLE_REF_IN_ERROR_MSG = false
     25 M.TABLE_EQUALS_KEYBYCONTENT = true
     26 M.LINE_LENGTH=80
     27 
     28 -- set this to false to debug luaunit
     29 local STRIP_LUAUNIT_FROM_STACKTRACE=true
     30 
     31 M.VERBOSITY_DEFAULT = 10
     32 M.VERBOSITY_LOW     = 1
     33 M.VERBOSITY_QUIET   = 0
     34 M.VERBOSITY_VERBOSE = 20
     35 
     36 -- set EXPORT_ASSERT_TO_GLOBALS to have all asserts visible as global values
     37 -- EXPORT_ASSERT_TO_GLOBALS = true
     38 
     39 -- we need to keep a copy of the script args before it is overriden
     40 local cmdline_argv = rawget(_G, "arg")
     41 
     42 M.FAILURE_PREFIX = 'LuaUnit test FAILURE: ' -- prefix string for failed tests
     43 
     44 M.USAGE=[[Usage: lua <your_test_suite.lua> [options] [testname1 [testname2] ... ]
     45 Options:
     46   -h, --help:             Print this help
     47   --version:              Print version information
     48   -v, --verbose:          Increase verbosity
     49   -q, --quiet:            Set verbosity to minimum
     50   -e, --error:            Stop on first error
     51   -f, --failure:          Stop on first failure or error
     52   -o, --output OUTPUT:    Set output type to OUTPUT
     53                           Possible values: text, tap, junit, nil
     54   -n, --name NAME:        For junit only, mandatory name of xml file
     55   -p, --pattern PATTERN:  Execute all test names matching the Lua PATTERN
     56                           May be repeated to include severals patterns
     57                           Make sure you escape magic chars like +? with %
     58   testname1, testname2, ... : tests to run in the form of testFunction,
     59                               TestClass or TestClass.testMethod
     60 ]]
     61 
     62 ----------------------------------------------------------------
     63 --
     64 --                 general utility functions
     65 --
     66 ----------------------------------------------------------------
     67 
     68 local crossTypeOrdering = {
     69     number = 1,
     70     boolean = 2,
     71     string = 3,
     72     table = 4,
     73     other = 5
     74 }
     75 local crossTypeComparison = {
     76     number = function(a, b) return a < b end,
     77     string = function(a, b) return a < b end,
     78     other = function(a, b) return tostring(a) < tostring(b) end,
     79 }
     80 
     81 local function crossTypeSort(a, b)
     82     local type_a, type_b = type(a), type(b)
     83     if type_a == type_b then
     84         local func = crossTypeComparison[type_a] or crossTypeComparison.other
     85         return func(a, b)
     86     end
     87     type_a = crossTypeOrdering[type_a] or crossTypeOrdering.other
     88     type_b = crossTypeOrdering[type_b] or crossTypeOrdering.other
     89     return type_a < type_b
     90 end
     91 
     92 local function __genSortedIndex( t )
     93     -- Returns a sequence consisting of t's keys, sorted.
     94     local sortedIndex = {}
     95 
     96     for key,_ in pairs(t) do
     97         table.insert(sortedIndex, key)
     98     end
     99 
    100     table.sort(sortedIndex, crossTypeSort)
    101     return sortedIndex
    102 end
    103 M.private.__genSortedIndex = __genSortedIndex
    104 
    105 local function sortedNext(state, control)
    106     -- Equivalent of the next() function of table iteration, but returns the
    107     -- keys in sorted order (see __genSortedIndex and crossTypeSort).
    108     -- The state is a temporary variable during iteration and contains the
    109     -- sorted key table (state.sortedIdx). It also stores the last index (into
    110     -- the keys) used by the iteration, to find the next one quickly.
    111     local key
    112 
    113     --print("sortedNext: control = "..tostring(control) )
    114     if control == nil then
    115         -- start of iteration
    116         state.lastIdx = 1
    117         key = state.sortedIdx[1]
    118         return key, state.t[key]
    119     end
    120 
    121     -- normally, we expect the control variable to match the last key used
    122     if control ~= state.sortedIdx[state.lastIdx] then
    123         -- strange, we have to find the next value by ourselves
    124         -- the key table is sorted in crossTypeSort() order! -> use bisection
    125         local count = #state.sortedIdx
    126         local lower, upper = 1, count
    127         repeat
    128             state.lastIdx = math.modf((lower + upper) / 2)
    129             key = state.sortedIdx[state.lastIdx]
    130             if key == control then break; end -- key found (and thus prev index)
    131             if crossTypeSort(key, control) then
    132                 -- key < control, continue search "right" (towards upper bound)
    133                 lower = state.lastIdx + 1
    134             else
    135                 -- key > control, continue search "left" (towards lower bound)
    136                 upper = state.lastIdx - 1
    137             end
    138         until lower > upper
    139         if lower > upper then -- only true if the key wasn't found, ...
    140             state.lastIdx = count -- ... so ensure no match for the code below
    141         end
    142     end
    143 
    144     -- proceed by retrieving the next value (or nil) from the sorted keys
    145     state.lastIdx = state.lastIdx + 1
    146     key = state.sortedIdx[state.lastIdx]
    147     if key then
    148         return key, state.t[key]
    149     end
    150 
    151     -- getting here means returning `nil`, which will end the iteration
    152 end
    153 
    154 local function sortedPairs(tbl)
    155     -- Equivalent of the pairs() function on tables. Allows to iterate in
    156     -- sorted order. As required by "generic for" loops, this will return the
    157     -- iterator (function), an "invariant state", and the initial control value.
    158     -- (see http://www.lua.org/pil/7.2.html)
    159     return sortedNext, {t = tbl, sortedIdx = __genSortedIndex(tbl)}, nil
    160 end
    161 M.private.sortedPairs = sortedPairs
    162 
    163 local function strsplit(delimiter, text)
    164 -- Split text into a list consisting of the strings in text,
    165 -- separated by strings matching delimiter (which may be a pattern).
    166 -- example: strsplit(",%s*", "Anna, Bob, Charlie,Dolores")
    167     if string.find("", delimiter, 1, true) then -- this would result in endless loops
    168         error("delimiter matches empty string!")
    169     end
    170     local list, pos, first, last = {}, 1
    171     while true do
    172         first, last = text:find(delimiter, pos, true)
    173         if first then -- found?
    174             table.insert(list, text:sub(pos, first - 1))
    175             pos = last + 1
    176         else
    177             table.insert(list, text:sub(pos))
    178             break
    179         end
    180     end
    181     return list
    182 end
    183 M.private.strsplit = strsplit
    184 
    185 local function hasNewLine( s )
    186     -- return true if s has a newline
    187     return (string.find(s, '\n', 1, true) ~= nil)
    188 end
    189 M.private.hasNewLine = hasNewLine
    190 
    191 local function prefixString( prefix, s )
    192     -- Prefix all the lines of s with prefix
    193     return prefix .. table.concat(strsplit('\n', s), '\n' .. prefix)
    194 end
    195 M.private.prefixString = prefixString
    196 
    197 local function strMatch(s, pattern, start, final )
    198     -- return true if s matches completely the pattern from index start to index end
    199     -- return false in every other cases
    200     -- if start is nil, matches from the beginning of the string
    201     -- if final is nil, matches to the end of the string
    202     start = start or 1
    203     final = final or string.len(s)
    204 
    205     local foundStart, foundEnd = string.find(s, pattern, start, false)
    206     return foundStart == start and foundEnd == final
    207 end
    208 M.private.strMatch = strMatch
    209 
    210 local function xmlEscape( s )
    211     -- Return s escaped for XML attributes
    212     -- escapes table:
    213     -- "   &quot;
    214     -- '   &apos;
    215     -- <   &lt;
    216     -- >   &gt;
    217     -- &   &amp;
    218 
    219     return string.gsub( s, '.', {
    220         ['&'] = "&amp;",
    221         ['"'] = "&quot;",
    222         ["'"] = "&apos;",
    223         ['<'] = "&lt;",
    224         ['>'] = "&gt;",
    225     } )
    226 end
    227 M.private.xmlEscape = xmlEscape
    228 
    229 local function xmlCDataEscape( s )
    230     -- Return s escaped for CData section, escapes: "]]>"
    231     return string.gsub( s, ']]>', ']]&gt;' )
    232 end
    233 M.private.xmlCDataEscape = xmlCDataEscape
    234 
    235 local function stripLuaunitTrace( stackTrace )
    236     --[[
    237     -- Example of  a traceback:
    238     <<stack traceback:
    239         example_with_luaunit.lua:130: in function 'test2_withFailure'
    240         ./luaunit.lua:1449: in function <./luaunit.lua:1449>
    241         [C]: in function 'xpcall'
    242         ./luaunit.lua:1449: in function 'protectedCall'
    243         ./luaunit.lua:1508: in function 'execOneFunction'
    244         ./luaunit.lua:1596: in function 'runSuiteByInstances'
    245         ./luaunit.lua:1660: in function 'runSuiteByNames'
    246         ./luaunit.lua:1736: in function 'runSuite'
    247         example_with_luaunit.lua:140: in main chunk
    248         [C]: in ?>>
    249 
    250         Other example:
    251     <<stack traceback:
    252         ./luaunit.lua:545: in function 'assertEquals'
    253         example_with_luaunit.lua:58: in function 'TestToto.test7'
    254         ./luaunit.lua:1517: in function <./luaunit.lua:1517>
    255         [C]: in function 'xpcall'
    256         ./luaunit.lua:1517: in function 'protectedCall'
    257         ./luaunit.lua:1578: in function 'execOneFunction'
    258         ./luaunit.lua:1677: in function 'runSuiteByInstances'
    259         ./luaunit.lua:1730: in function 'runSuiteByNames'
    260         ./luaunit.lua:1806: in function 'runSuite'
    261         example_with_luaunit.lua:140: in main chunk
    262         [C]: in ?>>
    263 
    264     <<stack traceback:
    265         luaunit2/example_with_luaunit.lua:124: in function 'test1_withFailure'
    266         luaunit2/luaunit.lua:1532: in function <luaunit2/luaunit.lua:1532>
    267         [C]: in function 'xpcall'
    268         luaunit2/luaunit.lua:1532: in function 'protectedCall'
    269         luaunit2/luaunit.lua:1591: in function 'execOneFunction'
    270         luaunit2/luaunit.lua:1679: in function 'runSuiteByInstances'
    271         luaunit2/luaunit.lua:1743: in function 'runSuiteByNames'
    272         luaunit2/luaunit.lua:1819: in function 'runSuite'
    273         luaunit2/example_with_luaunit.lua:140: in main chunk
    274         [C]: in ?>>
    275 
    276 
    277     -- first line is "stack traceback": KEEP
    278     -- next line may be luaunit line: REMOVE
    279     -- next lines are call in the program under testOk: REMOVE
    280     -- next lines are calls from luaunit to call the program under test: KEEP
    281 
    282     -- Strategy:
    283     -- keep first line
    284     -- remove lines that are part of luaunit
    285     -- kepp lines until we hit a luaunit line
    286     ]]
    287 
    288     local function isLuaunitInternalLine( s )
    289         -- return true if line of stack trace comes from inside luaunit
    290         return s:find('[/\\]luaunit%.lua:%d+: ') ~= nil
    291     end
    292 
    293     -- print( '<<'..stackTrace..'>>' )
    294 
    295     local t = strsplit( '\n', stackTrace )
    296     -- print( prettystr(t) )
    297 
    298     local idx = 2
    299 
    300     -- remove lines that are still part of luaunit
    301     while t[idx] and isLuaunitInternalLine( t[idx] ) do
    302         -- print('Removing : '..t[idx] )
    303         table.remove(t, idx)
    304     end
    305 
    306     -- keep lines until we hit luaunit again
    307     while t[idx] and (not isLuaunitInternalLine(t[idx])) do
    308         -- print('Keeping : '..t[idx] )
    309         idx = idx + 1
    310     end
    311 
    312     -- remove remaining luaunit lines
    313     while t[idx] do
    314         -- print('Removing : '..t[idx] )
    315         table.remove(t, idx)
    316     end
    317 
    318     -- print( prettystr(t) )
    319     return table.concat( t, '\n')
    320 
    321 end
    322 M.private.stripLuaunitTrace = stripLuaunitTrace
    323 
    324 
    325 local function prettystr_sub(v, indentLevel, keeponeline, printTableRefs, recursionTable )
    326     local type_v = type(v)
    327     if "string" == type_v  then
    328         if keeponeline then v = v:gsub("\n", "\\n") end
    329 
    330         -- use clever delimiters according to content:
    331         -- enclose with single quotes if string contains ", but no '
    332         if v:find('"', 1, true) and not v:find("'", 1, true) then
    333             return "'" .. v .. "'"
    334         end
    335         -- use double quotes otherwise, escape embedded "
    336         return '"' .. v:gsub('"', '\\"') .. '"'
    337 
    338     elseif "table" == type_v then
    339         --if v.__class__ then
    340         --    return string.gsub( tostring(v), 'table', v.__class__ )
    341         --end
    342         return M.private._table_tostring(v, indentLevel, printTableRefs, recursionTable)
    343     end
    344 
    345     return tostring(v)
    346 end
    347 
    348 local function prettystr( v, keeponeline )
    349     --[[ Better string conversion, to display nice variable content:
    350     For strings, if keeponeline is set to true, string is displayed on one line, with visible \n
    351     * string are enclosed with " by default, or with ' if string contains a "
    352     * if table is a class, display class name
    353     * tables are expanded
    354     ]]--
    355     local recursionTable = {}
    356     local s = prettystr_sub(v, 1, keeponeline, M.PRINT_TABLE_REF_IN_ERROR_MSG, recursionTable)
    357     if recursionTable.recursionDetected and not M.PRINT_TABLE_REF_IN_ERROR_MSG then
    358         -- some table contain recursive references,
    359         -- so we must recompute the value by including all table references
    360         -- else the result looks like crap
    361         recursionTable = {}
    362         s = prettystr_sub(v, 1, keeponeline, true, recursionTable)
    363     end
    364     return s
    365 end
    366 M.prettystr = prettystr
    367 
    368 local function prettystrPadded(value1, value2, suffix_a, suffix_b)
    369     --[[
    370     This function helps with the recurring task of constructing the "expected
    371     vs. actual" error messages. It takes two arbitrary values and formats
    372     corresponding strings with prettystr().
    373 
    374     To keep the (possibly complex) output more readable in case the resulting
    375     strings contain line breaks, they get automatically prefixed with additional
    376     newlines. Both suffixes are optional (default to empty strings), and get
    377     appended to the "value1" string. "suffix_a" is used if line breaks were
    378     encountered, "suffix_b" otherwise.
    379 
    380     Returns the two formatted strings (including padding/newlines).
    381     ]]
    382     local str1, str2 = prettystr(value1), prettystr(value2)
    383     if hasNewLine(str1) or hasNewLine(str2) then
    384         -- line break(s) detected, add padding
    385         return "\n" .. str1 .. (suffix_a or ""), "\n" .. str2
    386     end
    387     return str1 .. (suffix_b or ""), str2
    388 end
    389 M.private.prettystrPadded = prettystrPadded
    390 
    391 local function _table_keytostring(k)
    392     -- like prettystr but do not enclose with "" if the string is just alphanumerical
    393     -- this is better for displaying table keys who are often simple strings
    394     if "string" == type(k) and k:match("^[_%a][_%w]*$") then
    395         return k
    396     end
    397     return prettystr(k)
    398 end
    399 M.private._table_keytostring = _table_keytostring
    400 
    401 local TABLE_TOSTRING_SEP = ", "
    402 local TABLE_TOSTRING_SEP_LEN = string.len(TABLE_TOSTRING_SEP)
    403 
    404 local function _table_tostring( tbl, indentLevel, printTableRefs, recursionTable )
    405     printTableRefs = printTableRefs or M.PRINT_TABLE_REF_IN_ERROR_MSG
    406     recursionTable = recursionTable or {}
    407     recursionTable[tbl] = true
    408 
    409     local result, dispOnMultLines = {}, false
    410 
    411     local entry, count, seq_index = nil, 0, 1
    412     for k, v in sortedPairs( tbl ) do
    413         if k == seq_index then
    414             -- for the sequential part of tables, we'll skip the "<key>=" output
    415             entry = ''
    416             seq_index = seq_index + 1
    417         else
    418             entry = _table_keytostring( k ) .. "="
    419         end
    420         if recursionTable[v] then -- recursion detected!
    421             recursionTable.recursionDetected = true
    422             entry = entry .. "<"..tostring(v)..">"
    423         else
    424             entry = entry ..
    425                 prettystr_sub( v, indentLevel+1, true, printTableRefs, recursionTable )
    426         end
    427         count = count + 1
    428         result[count] = entry
    429     end
    430 
    431     -- set dispOnMultLines if the maximum LINE_LENGTH would be exceeded
    432     local totalLength = 0
    433     for k, v in ipairs( result ) do
    434         totalLength = totalLength + string.len( v )
    435         if totalLength >= M.LINE_LENGTH then
    436             dispOnMultLines = true
    437             break
    438         end
    439     end
    440 
    441     if not dispOnMultLines then
    442         -- adjust with length of separator(s):
    443         -- two items need 1 sep, three items two seps, ... plus len of '{}'
    444         if count > 0 then
    445             totalLength = totalLength + TABLE_TOSTRING_SEP_LEN * (count - 1)
    446         end
    447         dispOnMultLines = totalLength + 2 >= M.LINE_LENGTH
    448     end
    449 
    450     -- now reformat the result table (currently holding element strings)
    451     if dispOnMultLines then
    452         local indentString = string.rep("    ", indentLevel - 1)
    453         result = {"{\n    ", indentString,
    454                   table.concat(result, ",\n    " .. indentString), "\n",
    455                   indentString, "}"}
    456     else
    457         result = {"{", table.concat(result, TABLE_TOSTRING_SEP), "}"}
    458     end
    459     if printTableRefs then
    460         table.insert(result, 1, "<"..tostring(tbl).."> ") -- prepend table ref
    461     end
    462     return table.concat(result)
    463 end
    464 M.private._table_tostring = _table_tostring -- prettystr_sub() needs it
    465 
    466 local function _table_contains(t, element)
    467     if t then
    468         for _, value in pairs(t) do
    469             if type(value) == type(element) then
    470                 if type(element) == 'table' then
    471                     -- if we wanted recursive items content comparison, we could use
    472                     -- _is_table_items_equals(v, expected) but one level of just comparing
    473                     -- items is sufficient
    474                     if M.private._is_table_equals( value, element ) then
    475                         return true
    476                     end
    477                 else
    478                     if value == element then
    479                         return true
    480                     end
    481                 end
    482             end
    483         end
    484     end
    485     return false
    486 end
    487 
    488 local function _is_table_items_equals(actual, expected )
    489     if (type(actual) == 'table') and (type(expected) == 'table') then
    490         for k,v in pairs(actual) do
    491             if not _table_contains(expected, v) then
    492                 return false
    493             end
    494         end
    495         for k,v in pairs(expected) do
    496             if not _table_contains(actual, v) then
    497                 return false
    498             end
    499         end
    500         return true
    501     elseif type(actual) ~= type(expected) then
    502         return false
    503     elseif actual == expected then
    504         return true
    505     end
    506     return false
    507 end
    508 
    509 local function _is_table_equals(actual, expected)
    510     if (type(actual) == 'table') and (type(expected) == 'table') then
    511         if (#actual ~= #expected) then
    512             return false
    513         end
    514 
    515         local actualTableKeys = {}
    516         for k,v in pairs(actual) do
    517             if M.TABLE_EQUALS_KEYBYCONTENT and type(k) == "table" then
    518                 -- If the keys are tables, things get a bit tricky here as we
    519                 -- can have _is_table_equals(k1, k2) and t[k1] ~= t[k2]. So we
    520                 -- collect actual's table keys, group them by length for
    521                 -- performance, and then for each table key in expected we look
    522                 -- it up in actualTableKeys.
    523                 if not actualTableKeys[#k] then actualTableKeys[#k] = {} end
    524                 table.insert(actualTableKeys[#k], k)
    525             else
    526                 if not _is_table_equals(v, expected[k]) then
    527                     return false
    528                 end
    529             end
    530         end
    531 
    532         for k,v in pairs(expected) do
    533             if M.TABLE_EQUALS_KEYBYCONTENT and type(k) == "table" then
    534                 local candidates = actualTableKeys[#k]
    535                 if not candidates then return false end
    536                 local found
    537                 for i, candidate in pairs(candidates) do
    538                     if _is_table_equals(candidate, k) then
    539                         found = candidate
    540                         -- Remove the candidate we matched against from the list
    541                         -- of candidates, so each key in actual can only match
    542                         -- one key in expected.
    543                         candidates[i] = nil
    544                         break
    545                     end
    546                 end
    547                 if not(found and _is_table_equals(actual[found], v)) then return false end
    548             else
    549                 if not _is_table_equals(v, actual[k]) then
    550                     return false
    551                 end
    552             end
    553         end
    554 
    555         if M.TABLE_EQUALS_KEYBYCONTENT then
    556             for _, keys in pairs(actualTableKeys) do
    557                 -- if there are any keys left in any actualTableKeys[i] then
    558                 -- that is a key in actual with no matching key in expected,
    559                 -- and so the tables aren't equal.
    560                 if next(keys) then return false end
    561             end
    562         end
    563 
    564         return true
    565     elseif type(actual) ~= type(expected) then
    566         return false
    567     elseif actual == expected then
    568         return true
    569     end
    570     return false
    571 end
    572 M.private._is_table_equals = _is_table_equals
    573 
    574 local function failure(msg, level)
    575     -- raise an error indicating a test failure
    576     -- for error() compatibility we adjust "level" here (by +1), to report the
    577     -- calling context
    578     error(M.FAILURE_PREFIX .. msg, (level or 1) + 1)
    579 end
    580 
    581 local function fail_fmt(level, ...)
    582      -- failure with printf-style formatted message and given error level
    583     failure(string.format(...), (level or 1) + 1)
    584 end
    585 M.private.fail_fmt = fail_fmt
    586 
    587 local function error_fmt(level, ...)
    588      -- printf-style error()
    589     error(string.format(...), (level or 1) + 1)
    590 end
    591 
    592 ----------------------------------------------------------------
    593 --
    594 --                     assertions
    595 --
    596 ----------------------------------------------------------------
    597 
    598 local function errorMsgEquality(actual, expected)
    599     if not M.ORDER_ACTUAL_EXPECTED then
    600         expected, actual = actual, expected
    601     end
    602     if type(expected) == 'string' or type(expected) == 'table' then
    603         expected, actual = prettystrPadded(expected, actual)
    604         return string.format("expected: %s\nactual: %s", expected, actual)
    605     end
    606     return string.format("expected: %s, actual: %s",
    607                          prettystr(expected), prettystr(actual))
    608 end
    609 
    610 function M.assertError(f, ...)
    611     -- assert that calling f with the arguments will raise an error
    612     -- example: assertError( f, 1, 2 ) => f(1,2) should generate an error
    613     if pcall( f, ... ) then
    614         failure( "Expected an error when calling function but no error generated", 2 )
    615     end
    616 end
    617 
    618 function M.assertTrue(value)
    619     if not value then
    620         failure("expected: true, actual: " ..prettystr(value), 2)
    621     end
    622 end
    623 
    624 function M.assertFalse(value)
    625     if value then
    626         failure("expected: false, actual: " ..prettystr(value), 2)
    627     end
    628 end
    629 
    630 function M.assertIsNil(value)
    631     if value ~= nil then
    632         failure("expected: nil, actual: " ..prettystr(value), 2)
    633     end
    634 end
    635 
    636 function M.assertNotIsNil(value)
    637     if value == nil then
    638         failure("expected non nil value, received nil", 2)
    639     end
    640 end
    641 
    642 function M.assertEquals(actual, expected)
    643     if type(actual) == 'table' and type(expected) == 'table' then
    644         if not _is_table_equals(actual, expected) then
    645             failure( errorMsgEquality(actual, expected), 2 )
    646         end
    647     elseif type(actual) ~= type(expected) then
    648         failure( errorMsgEquality(actual, expected), 2 )
    649     elseif actual ~= expected then
    650         failure( errorMsgEquality(actual, expected), 2 )
    651     end
    652 end
    653 
    654 -- Help Lua in corner cases like almostEquals(1.1, 1.0, 0.1), which by default
    655 -- may not work. We need to give margin a small boost; EPSILON defines the
    656 -- default value to use for this:
    657 local EPSILON = 0.00000000001
    658 function M.almostEquals( actual, expected, margin, margin_boost )
    659     if type(actual) ~= 'number' or type(expected) ~= 'number' or type(margin) ~= 'number' then
    660         error_fmt(3, 'almostEquals: must supply only number arguments.\nArguments supplied: %s, %s, %s',
    661             prettystr(actual), prettystr(expected), prettystr(margin))
    662     end
    663     if margin <= 0 then
    664         error('almostEquals: margin must be positive, current value is ' .. margin, 3)
    665     end
    666     local realmargin = margin + (margin_boost or EPSILON)
    667     return math.abs(expected - actual) <= realmargin
    668 end
    669 
    670 function M.assertAlmostEquals( actual, expected, margin )
    671     -- check that two floats are close by margin
    672     if not M.almostEquals(actual, expected, margin) then
    673         if not M.ORDER_ACTUAL_EXPECTED then
    674             expected, actual = actual, expected
    675         end
    676         fail_fmt(2, 'Values are not almost equal\nExpected: %s with margin of %s, received: %s',
    677                  expected, margin, actual)
    678     end
    679 end
    680 
    681 function M.assertNotEquals(actual, expected)
    682     if type(actual) ~= type(expected) then
    683         return
    684     end
    685 
    686     if type(actual) == 'table' and type(expected) == 'table' then
    687         if not _is_table_equals(actual, expected) then
    688             return
    689         end
    690     elseif actual ~= expected then
    691         return
    692     end
    693     fail_fmt(2, 'Received the not expected value: %s', prettystr(actual))
    694 end
    695 
    696 function M.assertNotAlmostEquals( actual, expected, margin )
    697     -- check that two floats are not close by margin
    698     if M.almostEquals(actual, expected, margin) then
    699         if not M.ORDER_ACTUAL_EXPECTED then
    700             expected, actual = actual, expected
    701         end
    702         fail_fmt(2, 'Values are almost equal\nExpected: %s with a difference above margin of %s, received: %s',
    703                  expected, margin, actual)
    704     end
    705 end
    706 
    707 function M.assertStrContains( str, sub, useRe )
    708     -- this relies on lua string.find function
    709     -- a string always contains the empty string
    710     if not string.find(str, sub, 1, not useRe) then
    711         sub, str = prettystrPadded(sub, str, '\n')
    712         fail_fmt(2, 'Error, %s %s was not found in string %s',
    713                  useRe and 'regexp' or 'substring', sub, str)
    714     end
    715 end
    716 
    717 function M.assertStrIContains( str, sub )
    718     -- this relies on lua string.find function
    719     -- a string always contains the empty string
    720     if not string.find(str:lower(), sub:lower(), 1, true) then
    721         sub, str = prettystrPadded(sub, str, '\n')
    722         fail_fmt(2, 'Error, substring %s was not found (case insensitively) in string %s',
    723                  sub, str)
    724     end
    725 end
    726 
    727 function M.assertNotStrContains( str, sub, useRe )
    728     -- this relies on lua string.find function
    729     -- a string always contains the empty string
    730     if string.find(str, sub, 1, not useRe) then
    731         sub, str = prettystrPadded(sub, str, '\n')
    732         fail_fmt(2, 'Error, %s %s was found in string %s',
    733                  useRe and 'regexp' or 'substring', sub, str)
    734     end
    735 end
    736 
    737 function M.assertNotStrIContains( str, sub )
    738     -- this relies on lua string.find function
    739     -- a string always contains the empty string
    740     if string.find(str:lower(), sub:lower(), 1, true) then
    741         sub, str = prettystrPadded(sub, str, '\n')
    742         fail_fmt(2, 'Error, substring %s was found (case insensitively) in string %s',
    743                  sub, str)
    744     end
    745 end
    746 
    747 function M.assertStrMatches( str, pattern, start, final )
    748     -- Verify a full match for the string
    749     -- for a partial match, simply use assertStrContains with useRe set to true
    750     if not strMatch( str, pattern, start, final ) then
    751         pattern, str = prettystrPadded(pattern, str, '\n')
    752         fail_fmt(2, 'Error, pattern %s was not matched by string %s',
    753                  pattern, str)
    754     end
    755 end
    756 
    757 function M.assertErrorMsgEquals( expectedMsg, func, ... )
    758     -- assert that calling f with the arguments will raise an error
    759     -- example: assertError( f, 1, 2 ) => f(1,2) should generate an error
    760     local no_error, error_msg = pcall( func, ... )
    761     if no_error then
    762         failure( 'No error generated when calling function but expected error: "'..expectedMsg..'"', 2 )
    763     end
    764     if error_msg ~= expectedMsg then
    765         error_msg, expectedMsg = prettystrPadded(error_msg, expectedMsg)
    766         fail_fmt(2, 'Exact error message expected: %s\nError message received: %s\n',
    767                  expectedMsg, error_msg)
    768     end
    769 end
    770 
    771 function M.assertErrorMsgContains( partialMsg, func, ... )
    772     -- assert that calling f with the arguments will raise an error
    773     -- example: assertError( f, 1, 2 ) => f(1,2) should generate an error
    774     local no_error, error_msg = pcall( func, ... )
    775     if no_error then
    776         failure( 'No error generated when calling function but expected error containing: '..prettystr(partialMsg), 2 )
    777     end
    778     if not string.find( error_msg, partialMsg, nil, true ) then
    779         error_msg, partialMsg = prettystrPadded(error_msg, partialMsg)
    780         fail_fmt(2, 'Error message does not contain: %s\nError message received: %s\n',
    781                  partialMsg, error_msg)
    782     end
    783 end
    784 
    785 function M.assertErrorMsgMatches( expectedMsg, func, ... )
    786     -- assert that calling f with the arguments will raise an error
    787     -- example: assertError( f, 1, 2 ) => f(1,2) should generate an error
    788     local no_error, error_msg = pcall( func, ... )
    789     if no_error then
    790         failure( 'No error generated when calling function but expected error matching: "'..expectedMsg..'"', 2 )
    791     end
    792     if not strMatch( error_msg, expectedMsg ) then
    793         expectedMsg, error_msg = prettystrPadded(expectedMsg, error_msg)
    794         fail_fmt(2, 'Error message does not match: %s\nError message received: %s\n',
    795                  expectedMsg, error_msg)
    796     end
    797 end
    798 
    799 --[[
    800 Add type assertion functions to the module table M. Each of these functions
    801 takes a single parameter "value", and checks that its Lua type matches the
    802 expected string (derived from the function name):
    803 
    804 M.assertIsXxx(value) -> ensure that type(value) conforms to "xxx"
    805 ]]
    806 for _, funcName in ipairs(
    807     {'assertIsNumber', 'assertIsString', 'assertIsTable', 'assertIsBoolean',
    808      'assertIsFunction', 'assertIsUserdata', 'assertIsThread'}
    809 ) do
    810     local typeExpected = funcName:match("^assertIs([A-Z]%a*)$")
    811     -- Lua type() always returns lowercase, also make sure the match() succeeded
    812     typeExpected = typeExpected and typeExpected:lower()
    813                    or error("bad function name '"..funcName.."' for type assertion")
    814 
    815     M[funcName] = function(value)
    816         if type(value) ~= typeExpected then
    817             fail_fmt(2, 'Expected: a %s value, actual: type %s, value %s',
    818                      typeExpected, type(value), prettystrPadded(value))
    819         end
    820     end
    821 end
    822 
    823 --[[
    824 Add non-type assertion functions to the module table M. Each of these functions
    825 takes a single parameter "value", and checks that its Lua type differs from the
    826 expected string (derived from the function name):
    827 
    828 M.assertNotIsXxx(value) -> ensure that type(value) is not "xxx"
    829 ]]
    830 for _, funcName in ipairs(
    831     {'assertNotIsNumber', 'assertNotIsString', 'assertNotIsTable', 'assertNotIsBoolean',
    832      'assertNotIsFunction', 'assertNotIsUserdata', 'assertNotIsThread'}
    833 ) do
    834     local typeUnexpected = funcName:match("^assertNotIs([A-Z]%a*)$")
    835     -- Lua type() always returns lowercase, also make sure the match() succeeded
    836     typeUnexpected = typeUnexpected and typeUnexpected:lower()
    837                    or error("bad function name '"..funcName.."' for type assertion")
    838 
    839     M[funcName] = function(value)
    840         if type(value) == typeUnexpected then
    841             fail_fmt(2, 'Not expected: a %s type, actual: value %s',
    842                      typeUnexpected, prettystrPadded(value))
    843         end
    844     end
    845 end
    846 
    847 function M.assertIs(actual, expected)
    848     if actual ~= expected then
    849         if not M.ORDER_ACTUAL_EXPECTED then
    850             actual, expected = expected, actual
    851         end
    852         expected, actual = prettystrPadded(expected, actual, '\n', ', ')
    853         fail_fmt(2, 'Expected object and actual object are not the same\nExpected: %sactual: %s',
    854                  expected, actual)
    855     end
    856 end
    857 
    858 function M.assertNotIs(actual, expected)
    859     if actual == expected then
    860         if not M.ORDER_ACTUAL_EXPECTED then
    861             expected = actual
    862         end
    863         fail_fmt(2, 'Expected object and actual object are the same object: %s',
    864                  prettystrPadded(expected))
    865     end
    866 end
    867 
    868 function M.assertItemsEquals(actual, expected)
    869     -- checks that the items of table expected
    870     -- are contained in table actual. Warning, this function
    871     -- is at least O(n^2)
    872     if not _is_table_items_equals(actual, expected ) then
    873         expected, actual = prettystrPadded(expected, actual)
    874         fail_fmt(2, 'Contents of the tables are not identical:\nExpected: %s\nActual: %s',
    875                  expected, actual)
    876     end
    877 end
    878 
    879 ----------------------------------------------------------------
    880 --                     Compatibility layer
    881 ----------------------------------------------------------------
    882 
    883 -- for compatibility with LuaUnit v2.x
    884 function M.wrapFunctions(...)
    885     io.stderr:write( [[Use of WrapFunction() is no longer needed.
    886 Just prefix your test function names with "test" or "Test" and they
    887 will be picked up and run by LuaUnit.]] )
    888     -- In LuaUnit version <= 2.1 , this function was necessary to include
    889     -- a test function inside the global test suite. Nowadays, the functions
    890     -- are simply run directly as part of the test discovery process.
    891     -- so just do nothing !
    892 
    893     --[[
    894     local testClass, testFunction
    895     testClass = {}
    896     local function storeAsMethod(idx, testName)
    897         testFunction = _G[testName]
    898         testClass[testName] = testFunction
    899     end
    900     for i,v in ipairs({...}) do
    901         storeAsMethod( i, v )
    902     end
    903 
    904     return testClass
    905     ]]
    906 end
    907 
    908 local list_of_funcs = {
    909     -- { official function name , alias }
    910 
    911     -- general assertions
    912     { 'assertEquals'            , 'assert_equals' },
    913     { 'assertItemsEquals'       , 'assert_items_equals' },
    914     { 'assertNotEquals'         , 'assert_not_equals' },
    915     { 'assertAlmostEquals'      , 'assert_almost_equals' },
    916     { 'assertNotAlmostEquals'   , 'assert_not_almost_equals' },
    917     { 'assertTrue'              , 'assert_true' },
    918     { 'assertFalse'             , 'assert_false' },
    919     { 'assertStrContains'       , 'assert_str_contains' },
    920     { 'assertStrIContains'      , 'assert_str_icontains' },
    921     { 'assertNotStrContains'    , 'assert_not_str_contains' },
    922     { 'assertNotStrIContains'   , 'assert_not_str_icontains' },
    923     { 'assertStrMatches'        , 'assert_str_matches' },
    924     { 'assertError'             , 'assert_error' },
    925     { 'assertErrorMsgEquals'    , 'assert_error_msg_equals' },
    926     { 'assertErrorMsgContains'  , 'assert_error_msg_contains' },
    927     { 'assertErrorMsgMatches'   , 'assert_error_msg_matches' },
    928     { 'assertIs'                , 'assert_is' },
    929     { 'assertNotIs'             , 'assert_not_is' },
    930     { 'wrapFunctions'           , 'WrapFunctions' },
    931     { 'wrapFunctions'           , 'wrap_functions' },
    932 
    933     -- type assertions: assertIsXXX -> assert_is_xxx
    934     { 'assertIsNumber'          , 'assert_is_number' },
    935     { 'assertIsString'          , 'assert_is_string' },
    936     { 'assertIsTable'           , 'assert_is_table' },
    937     { 'assertIsBoolean'         , 'assert_is_boolean' },
    938     { 'assertIsNil'             , 'assert_is_nil' },
    939     { 'assertIsFunction'        , 'assert_is_function' },
    940     { 'assertIsThread'          , 'assert_is_thread' },
    941     { 'assertIsUserdata'        , 'assert_is_userdata' },
    942 
    943     -- type assertions: assertIsXXX -> assertXxx
    944     { 'assertIsNumber'          , 'assertNumber' },
    945     { 'assertIsString'          , 'assertString' },
    946     { 'assertIsTable'           , 'assertTable' },
    947     { 'assertIsBoolean'         , 'assertBoolean' },
    948     { 'assertIsNil'             , 'assertNil' },
    949     { 'assertIsFunction'        , 'assertFunction' },
    950     { 'assertIsThread'          , 'assertThread' },
    951     { 'assertIsUserdata'        , 'assertUserdata' },
    952 
    953     -- type assertions: assertIsXXX -> assert_xxx (luaunit v2 compat)
    954     { 'assertIsNumber'          , 'assert_number' },
    955     { 'assertIsString'          , 'assert_string' },
    956     { 'assertIsTable'           , 'assert_table' },
    957     { 'assertIsBoolean'         , 'assert_boolean' },
    958     { 'assertIsNil'             , 'assert_nil' },
    959     { 'assertIsFunction'        , 'assert_function' },
    960     { 'assertIsThread'          , 'assert_thread' },
    961     { 'assertIsUserdata'        , 'assert_userdata' },
    962 
    963     -- type assertions: assertNotIsXXX -> assert_not_is_xxx
    964     { 'assertNotIsNumber'       , 'assert_not_is_number' },
    965     { 'assertNotIsString'       , 'assert_not_is_string' },
    966     { 'assertNotIsTable'        , 'assert_not_is_table' },
    967     { 'assertNotIsBoolean'      , 'assert_not_is_boolean' },
    968     { 'assertNotIsNil'          , 'assert_not_is_nil' },
    969     { 'assertNotIsFunction'     , 'assert_not_is_function' },
    970     { 'assertNotIsThread'       , 'assert_not_is_thread' },
    971     { 'assertNotIsUserdata'     , 'assert_not_is_userdata' },
    972 
    973     -- type assertions: assertNotIsXXX -> assertNotXxx (luaunit v2 compat)
    974     { 'assertNotIsNumber'       , 'assertNotNumber' },
    975     { 'assertNotIsString'       , 'assertNotString' },
    976     { 'assertNotIsTable'        , 'assertNotTable' },
    977     { 'assertNotIsBoolean'      , 'assertNotBoolean' },
    978     { 'assertNotIsNil'          , 'assertNotNil' },
    979     { 'assertNotIsFunction'     , 'assertNotFunction' },
    980     { 'assertNotIsThread'       , 'assertNotThread' },
    981     { 'assertNotIsUserdata'     , 'assertNotUserdata' },
    982 
    983     -- type assertions: assertNotIsXXX -> assert_not_xxx
    984     { 'assertNotIsNumber'       , 'assert_not_number' },
    985     { 'assertNotIsString'       , 'assert_not_string' },
    986     { 'assertNotIsTable'        , 'assert_not_table' },
    987     { 'assertNotIsBoolean'      , 'assert_not_boolean' },
    988     { 'assertNotIsNil'          , 'assert_not_nil' },
    989     { 'assertNotIsFunction'     , 'assert_not_function' },
    990     { 'assertNotIsThread'       , 'assert_not_thread' },
    991     { 'assertNotIsUserdata'     , 'assert_not_userdata' },
    992 
    993     -- all assertions with Coroutine duplicate Thread assertions
    994     { 'assertIsThread'          , 'assertIsCoroutine' },
    995     { 'assertIsThread'          , 'assertCoroutine' },
    996     { 'assertIsThread'          , 'assert_is_coroutine' },
    997     { 'assertIsThread'          , 'assert_coroutine' },
    998     { 'assertNotIsThread'       , 'assertNotIsCoroutine' },
    999     { 'assertNotIsThread'       , 'assertNotCoroutine' },
   1000     { 'assertNotIsThread'       , 'assert_not_is_coroutine' },
   1001     { 'assertNotIsThread'       , 'assert_not_coroutine' },
   1002 }
   1003 
   1004 -- Create all aliases in M
   1005 for _,v in ipairs( list_of_funcs ) do
   1006     funcname, alias = v[1], v[2]
   1007     M[alias] = M[funcname]
   1008 
   1009     if EXPORT_ASSERT_TO_GLOBALS then
   1010         _G[funcname] = M[funcname]
   1011         _G[alias] = M[funcname]
   1012     end
   1013 end
   1014 
   1015 ----------------------------------------------------------------
   1016 --
   1017 --                     Outputters
   1018 --
   1019 ----------------------------------------------------------------
   1020 
   1021 ----------------------------------------------------------------
   1022 --                     class TapOutput
   1023 ----------------------------------------------------------------
   1024 
   1025 
   1026 local TapOutput = { __class__ = 'TapOutput' } -- class
   1027 local TapOutput_MT = { __index = TapOutput } -- metatable
   1028 
   1029     -- For a good reference for TAP format, check: http://testanything.org/tap-specification.html
   1030 
   1031     function TapOutput:new()
   1032         return setmetatable( { verbosity = M.VERBOSITY_LOW }, TapOutput_MT)
   1033     end
   1034     function TapOutput:startSuite()
   1035         print("1.."..self.result.testCount)
   1036         print('# Started on '..self.result.startDate)
   1037     end
   1038     function TapOutput:startClass(className)
   1039         if className ~= '[TestFunctions]' then
   1040             print('# Starting class: '..className)
   1041         end
   1042     end
   1043     function TapOutput:startTest(testName) end
   1044 
   1045     function TapOutput:addFailure( node )
   1046         io.stdout:write("not ok ", self.result.currentTestNumber, "\t", node.testName, "\n")
   1047         if self.verbosity > M.VERBOSITY_LOW then
   1048            print( prefixString( '    ', node.msg ) )
   1049         end
   1050         if self.verbosity > M.VERBOSITY_DEFAULT then
   1051            print( prefixString( '    ', node.stackTrace ) )
   1052         end
   1053     end
   1054     TapOutput.addError = TapOutput.addFailure
   1055 
   1056     function TapOutput:endTest( node )
   1057         if node:isPassed() then
   1058             io.stdout:write("ok     ", self.result.currentTestNumber, "\t", node.testName, "\n")
   1059         end
   1060     end
   1061 
   1062     function TapOutput:endClass() end
   1063 
   1064     function TapOutput:endSuite()
   1065         print( '# '..M.LuaUnit.statusLine( self.result ) )
   1066         return self.result.notPassedCount
   1067     end
   1068 
   1069 
   1070 -- class TapOutput end
   1071 
   1072 ----------------------------------------------------------------
   1073 --                     class JUnitOutput
   1074 ----------------------------------------------------------------
   1075 
   1076 -- See directory junitxml for more information about the junit format
   1077 local JUnitOutput = { __class__ = 'JUnitOutput' } -- class
   1078 local JUnitOutput_MT = { __index = JUnitOutput } -- metatable
   1079 
   1080     function JUnitOutput:new()
   1081         return setmetatable(
   1082             { testList = {}, verbosity = M.VERBOSITY_LOW }, JUnitOutput_MT)
   1083     end
   1084     function JUnitOutput:startSuite()
   1085 
   1086         -- open xml file early to deal with errors
   1087         if self.fname == nil then
   1088             error('With Junit, an output filename must be supplied with --name!')
   1089         end
   1090         if string.sub(self.fname,-4) ~= '.xml' then
   1091             self.fname = self.fname..'.xml'
   1092         end
   1093         self.fd = io.open(self.fname, "w")
   1094         if self.fd == nil then
   1095             error("Could not open file for writing: "..self.fname)
   1096         end
   1097 
   1098         print('# XML output to '..self.fname)
   1099         print('# Started on '..self.result.startDate)
   1100     end
   1101     function JUnitOutput:startClass(className)
   1102         if className ~= '[TestFunctions]' then
   1103             print('# Starting class: '..className)
   1104         end
   1105     end
   1106     function JUnitOutput:startTest(testName)
   1107         print('# Starting test: '..testName)
   1108     end
   1109 
   1110     function JUnitOutput:addFailure( node )
   1111         print('# Failure: ' .. node.msg)
   1112         -- print('# ' .. node.stackTrace)
   1113     end
   1114 
   1115     function JUnitOutput:addError( node )
   1116         print('# Error: ' .. node.msg)
   1117         -- print('# ' .. node.stackTrace)
   1118     end
   1119 
   1120     function JUnitOutput:endTest( node )
   1121     end
   1122 
   1123     function JUnitOutput:endClass()
   1124     end
   1125 
   1126     function JUnitOutput:endSuite()
   1127         print( '# '..M.LuaUnit.statusLine(self.result))
   1128 
   1129         -- XML file writing
   1130         self.fd:write('<?xml version="1.0" encoding="UTF-8" ?>\n')
   1131         self.fd:write('<testsuites>\n')
   1132         self.fd:write(string.format(
   1133             '    <testsuite name="LuaUnit" id="00001" package="" hostname="localhost" tests="%d" timestamp="%s" time="%0.3f" errors="%d" failures="%d">\n',
   1134             self.result.runCount, self.result.startIsodate, self.result.duration, self.result.errorCount, self.result.failureCount ))
   1135         self.fd:write("        <properties>\n")
   1136         self.fd:write(string.format('            <property name="Lua Version" value="%s"/>\n', _VERSION ) )
   1137         self.fd:write(string.format('            <property name="LuaUnit Version" value="%s"/>\n', M.VERSION) )
   1138         -- XXX please include system name and version if possible
   1139         self.fd:write("        </properties>\n")
   1140 
   1141         for i,node in ipairs(self.result.tests) do
   1142             self.fd:write(string.format('        <testcase classname="%s" name="%s" time="%0.3f">\n',
   1143                 node.className, node.testName, node.duration ) )
   1144             if node:isNotPassed() then
   1145                 self.fd:write(node:statusXML())
   1146             end
   1147             self.fd:write('        </testcase>\n')
   1148         end
   1149 
   1150         -- Next two lines are needed to validate junit ANT xsd, but really not useful in general:
   1151         self.fd:write('    <system-out/>\n')
   1152         self.fd:write('    <system-err/>\n')
   1153 
   1154         self.fd:write('    </testsuite>\n')
   1155         self.fd:write('</testsuites>\n')
   1156         self.fd:close()
   1157         return self.result.notPassedCount
   1158     end
   1159 
   1160 
   1161 -- class TapOutput end
   1162 
   1163 ----------------------------------------------------------------
   1164 --                     class TextOutput
   1165 ----------------------------------------------------------------
   1166 
   1167 --[[
   1168 
   1169 -- Python Non verbose:
   1170 
   1171 For each test: . or F or E
   1172 
   1173 If some failed tests:
   1174     ==============
   1175     ERROR / FAILURE: TestName (testfile.testclass)
   1176     ---------
   1177     Stack trace
   1178 
   1179 
   1180 then --------------
   1181 then "Ran x tests in 0.000s"
   1182 then OK or FAILED (failures=1, error=1)
   1183 
   1184 -- Python Verbose:
   1185 testname (filename.classname) ... ok
   1186 testname (filename.classname) ... FAIL
   1187 testname (filename.classname) ... ERROR
   1188 
   1189 then --------------
   1190 then "Ran x tests in 0.000s"
   1191 then OK or FAILED (failures=1, error=1)
   1192 
   1193 -- Ruby:
   1194 Started
   1195  .
   1196  Finished in 0.002695 seconds.
   1197 
   1198  1 tests, 2 assertions, 0 failures, 0 errors
   1199 
   1200 -- Ruby:
   1201 >> ruby tc_simple_number2.rb
   1202 Loaded suite tc_simple_number2
   1203 Started
   1204 F..
   1205 Finished in 0.038617 seconds.
   1206 
   1207   1) Failure:
   1208 test_failure(TestSimpleNumber) [tc_simple_number2.rb:16]:
   1209 Adding doesn't work.
   1210 <3> expected but was
   1211 <4>.
   1212 
   1213 3 tests, 4 assertions, 1 failures, 0 errors
   1214 
   1215 -- Java Junit
   1216 .......F.
   1217 Time: 0,003
   1218 There was 1 failure:
   1219 1) testCapacity(junit.samples.VectorTest)junit.framework.AssertionFailedError
   1220     at junit.samples.VectorTest.testCapacity(VectorTest.java:87)
   1221     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   1222     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
   1223     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
   1224 
   1225 FAILURES!!!
   1226 Tests run: 8,  Failures: 1,  Errors: 0
   1227 
   1228 
   1229 -- Maven
   1230 
   1231 # mvn test
   1232 -------------------------------------------------------
   1233  T E S T S
   1234 -------------------------------------------------------
   1235 Running math.AdditionTest
   1236 Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed:
   1237 0.03 sec <<< FAILURE!
   1238 
   1239 Results :
   1240 
   1241 Failed tests:
   1242   testLireSymbole(math.AdditionTest)
   1243 
   1244 Tests run: 2, Failures: 1, Errors: 0, Skipped: 0
   1245 
   1246 
   1247 -- LuaUnit
   1248 ---- non verbose
   1249 * display . or F or E when running tests
   1250 ---- verbose
   1251 * display test name + ok/fail
   1252 ----
   1253 * blank line
   1254 * number) ERROR or FAILURE: TestName
   1255    Stack trace
   1256 * blank line
   1257 * number) ERROR or FAILURE: TestName
   1258    Stack trace
   1259 
   1260 then --------------
   1261 then "Ran x tests in 0.000s (%d not selected, %d skipped)"
   1262 then OK or FAILED (failures=1, error=1)
   1263 
   1264 
   1265 ]]
   1266 
   1267 local TextOutput = { __class__ = 'TextOutput' } -- class
   1268 local TextOutput_MT = { __index = TextOutput } -- metatable
   1269 
   1270     function TextOutput:new()
   1271         return setmetatable(
   1272             { errorList = {}, verbosity = M.VERBOSITY_DEFAULT }, TextOutput_MT )
   1273     end
   1274 
   1275     function TextOutput:startSuite()
   1276         if self.verbosity > M.VERBOSITY_DEFAULT then
   1277             print( 'Started on '.. self.result.startDate )
   1278         end
   1279     end
   1280 
   1281     function TextOutput:startClass(className)
   1282         -- display nothing when starting a new class
   1283     end
   1284 
   1285     function TextOutput:startTest(testName)
   1286         if self.verbosity > M.VERBOSITY_DEFAULT then
   1287             io.stdout:write( "    ", self.result.currentNode.testName, " ... " )
   1288         end
   1289     end
   1290 
   1291     function TextOutput:addFailure( node )
   1292         -- nothing
   1293     end
   1294 
   1295     function TextOutput:addError( node )
   1296         -- nothing
   1297     end
   1298 
   1299     function TextOutput:endTest( node )
   1300         if node:isPassed() then
   1301             if self.verbosity > M.VERBOSITY_DEFAULT then
   1302                 io.stdout:write("Ok\n")
   1303             else
   1304                 io.stdout:write(".")
   1305             end
   1306         else
   1307             if self.verbosity > M.VERBOSITY_DEFAULT then
   1308                 print( node.status )
   1309                 print( node.msg )
   1310                 --[[
   1311                 -- find out when to do this:
   1312                 if self.verbosity > M.VERBOSITY_DEFAULT then
   1313                     print( node.stackTrace )
   1314                 end
   1315                 ]]
   1316             else
   1317                 -- write only the first character of status
   1318                 io.stdout:write(string.sub(node.status, 1, 1))
   1319             end
   1320         end
   1321     end
   1322 
   1323     function TextOutput:endClass()
   1324         -- nothing
   1325     end
   1326 
   1327     function TextOutput:displayOneFailedTest( index, failure )
   1328         print(index..") "..failure.testName )
   1329         print( failure.msg )
   1330         print( failure.stackTrace )
   1331         print()
   1332     end
   1333 
   1334     function TextOutput:displayFailedTests()
   1335         if self.result.notPassedCount == 0 then return end
   1336         print("Failed tests:")
   1337         print("-------------")
   1338         for i,v in ipairs(self.result.notPassed) do
   1339             self:displayOneFailedTest( i, v )
   1340         end
   1341     end
   1342 
   1343     function TextOutput:endSuite()
   1344         if self.verbosity > M.VERBOSITY_DEFAULT then
   1345             print("=========================================================")
   1346         else
   1347             print()
   1348         end
   1349         self:displayFailedTests()
   1350         print( M.LuaUnit.statusLine( self.result ) )
   1351         local ignoredString = ""
   1352         if self.result.notPassedCount == 0 then
   1353             print('OK')
   1354         end
   1355     end
   1356 
   1357 -- class TextOutput end
   1358 
   1359 
   1360 ----------------------------------------------------------------
   1361 --                     class NilOutput
   1362 ----------------------------------------------------------------
   1363 
   1364 local function nopCallable()
   1365     --print(42)
   1366     return nopCallable
   1367 end
   1368 
   1369 local NilOutput = { __class__ = 'NilOuptut' } -- class
   1370 local NilOutput_MT = { __index = nopCallable } -- metatable
   1371 
   1372 function NilOutput:new()
   1373     return setmetatable( { __class__ = 'NilOutput' }, NilOutput_MT )
   1374 end
   1375 
   1376 ----------------------------------------------------------------
   1377 --
   1378 --                     class LuaUnit
   1379 --
   1380 ----------------------------------------------------------------
   1381 
   1382 M.LuaUnit = {
   1383     outputType = TextOutput,
   1384     verbosity = M.VERBOSITY_DEFAULT,
   1385     __class__ = 'LuaUnit'
   1386 }
   1387 local LuaUnit_MT = { __index = M.LuaUnit }
   1388 
   1389 if EXPORT_ASSERT_TO_GLOBALS then
   1390     LuaUnit = M.LuaUnit
   1391 end
   1392 
   1393     function M.LuaUnit:new()
   1394         return setmetatable( {}, LuaUnit_MT )
   1395     end
   1396 
   1397     -----------------[[ Utility methods ]]---------------------
   1398 
   1399     function M.LuaUnit.asFunction(aObject)
   1400         -- return "aObject" if it is a function, and nil otherwise
   1401         if 'function' == type(aObject) then return aObject end
   1402     end
   1403 
   1404     function M.LuaUnit.isClassMethod(aName)
   1405         -- return true if aName contains a class + a method name in the form class:method
   1406         return string.find(aName, '.', nil, true) ~= nil
   1407     end
   1408 
   1409     function M.LuaUnit.splitClassMethod(someName)
   1410         -- return a pair className, methodName for a name in the form class:method
   1411         -- return nil if not a class + method name
   1412         -- name is class + method
   1413         local hasMethod, methodName, className
   1414         hasMethod = string.find(someName, '.', nil, true )
   1415         if not hasMethod then return nil end
   1416         methodName = string.sub(someName, hasMethod+1)
   1417         className = string.sub(someName,1,hasMethod-1)
   1418         return className, methodName
   1419     end
   1420 
   1421     function M.LuaUnit.isMethodTestName( s )
   1422         -- return true is the name matches the name of a test method
   1423         -- default rule is that is starts with 'Test' or with 'test'
   1424         return string.sub(s, 1, 4):lower() == 'test'
   1425     end
   1426 
   1427     function M.LuaUnit.isTestName( s )
   1428         -- return true is the name matches the name of a test
   1429         -- default rule is that is starts with 'Test' or with 'test'
   1430         return string.sub(s, 1, 4):lower() == 'test'
   1431     end
   1432 
   1433     function M.LuaUnit.collectTests()
   1434         -- return a list of all test names in the global namespace
   1435         -- that match LuaUnit.isTestName
   1436 
   1437         local testNames = {}
   1438         for k, v in pairs(_G) do
   1439             if M.LuaUnit.isTestName( k ) then
   1440                 table.insert( testNames , k )
   1441             end
   1442         end
   1443         table.sort( testNames )
   1444         return testNames
   1445     end
   1446 
   1447     function M.LuaUnit.parseCmdLine( cmdLine )
   1448         -- parse the command line
   1449         -- Supported command line parameters:
   1450         -- --verbose, -v: increase verbosity
   1451         -- --quiet, -q: silence output
   1452         -- --error, -e: treat errors as fatal (quit program)
   1453         -- --output, -o, + name: select output type
   1454         -- --pattern, -p, + pattern: run test matching pattern, may be repeated
   1455         -- --name, -n, + fname: name of output file for junit, default to stdout
   1456         -- [testnames, ...]: run selected test names
   1457         --
   1458         -- Returns a table with the following fields:
   1459         -- verbosity: nil, M.VERBOSITY_DEFAULT, M.VERBOSITY_QUIET, M.VERBOSITY_VERBOSE
   1460         -- output: nil, 'tap', 'junit', 'text', 'nil'
   1461         -- testNames: nil or a list of test names to run
   1462         -- pattern: nil or a list of patterns
   1463 
   1464         local result = {}
   1465         local state = nil
   1466         local SET_OUTPUT = 1
   1467         local SET_PATTERN = 2
   1468         local SET_FNAME = 3
   1469 
   1470         if cmdLine == nil then
   1471             return result
   1472         end
   1473 
   1474         local function parseOption( option )
   1475             if option == '--help' or option == '-h' then
   1476                 result['help'] = true
   1477                 return
   1478             elseif option == '--version' then
   1479                 result['version'] = true
   1480                 return
   1481             elseif option == '--verbose' or option == '-v' then
   1482                 result['verbosity'] = M.VERBOSITY_VERBOSE
   1483                 return
   1484             elseif option == '--quiet' or option == '-q' then
   1485                 result['verbosity'] = M.VERBOSITY_QUIET
   1486                 return
   1487             elseif option == '--error' or option == '-e' then
   1488                 result['quitOnError'] = true
   1489                 return
   1490             elseif option == '--failure' or option == '-f' then
   1491                 result['quitOnFailure'] = true
   1492                 return
   1493             elseif option == '--output' or option == '-o' then
   1494                 state = SET_OUTPUT
   1495                 return state
   1496             elseif option == '--name' or option == '-n' then
   1497                 state = SET_FNAME
   1498                 return state
   1499             elseif option == '--pattern' or option == '-p' then
   1500                 state = SET_PATTERN
   1501                 return state
   1502             end
   1503             error('Unknown option: '..option,3)
   1504         end
   1505 
   1506         local function setArg( cmdArg, state )
   1507             if state == SET_OUTPUT then
   1508                 result['output'] = cmdArg
   1509                 return
   1510             elseif state == SET_FNAME then
   1511                 result['fname'] = cmdArg
   1512                 return
   1513             elseif state == SET_PATTERN then
   1514                 if result['pattern'] then
   1515                     table.insert( result['pattern'], cmdArg )
   1516                 else
   1517                     result['pattern'] = { cmdArg }
   1518                 end
   1519                 return
   1520             end
   1521             error('Unknown parse state: '.. state)
   1522         end
   1523 
   1524 
   1525         for i, cmdArg in ipairs(cmdLine) do
   1526             if state ~= nil then
   1527                 setArg( cmdArg, state, result )
   1528                 state = nil
   1529             else
   1530                 if cmdArg:sub(1,1) == '-' then
   1531                     state = parseOption( cmdArg )
   1532                 else
   1533                     if result['testNames'] then
   1534                         table.insert( result['testNames'], cmdArg )
   1535                     else
   1536                         result['testNames'] = { cmdArg }
   1537                     end
   1538                 end
   1539             end
   1540         end
   1541 
   1542         if result['help'] then
   1543             M.LuaUnit.help()
   1544         end
   1545 
   1546         if result['version'] then
   1547             M.LuaUnit.version()
   1548         end
   1549 
   1550         if state ~= nil then
   1551             error('Missing argument after '..cmdLine[ #cmdLine ],2 )
   1552         end
   1553 
   1554         return result
   1555     end
   1556 
   1557     function M.LuaUnit.help()
   1558         print(M.USAGE)
   1559         os.exit(0)
   1560     end
   1561 
   1562     function M.LuaUnit.version()
   1563         print('LuaUnit v'..M.VERSION..' by Philippe Fremy <phil (a] freehackers.org>')
   1564         os.exit(0)
   1565     end
   1566 
   1567     function M.LuaUnit.patternInclude( patternFilter, expr )
   1568         -- check if any of patternFilter is contained in expr. If so, return true.
   1569         -- return false if None of the patterns are contained in expr
   1570         -- if patternFilter is nil, return true (no filtering)
   1571         if patternFilter == nil then
   1572             return true
   1573         end
   1574 
   1575         for i,pattern in ipairs(patternFilter) do
   1576             if string.find(expr, pattern) then
   1577                 return true
   1578             end
   1579         end
   1580 
   1581         return false
   1582     end
   1583 
   1584 ----------------------------------------------------------------
   1585 --                     class NodeStatus
   1586 ----------------------------------------------------------------
   1587 
   1588     local NodeStatus = { __class__ = 'NodeStatus' } -- class
   1589     local NodeStatus_MT = { __index = NodeStatus } -- metatable
   1590     M.NodeStatus = NodeStatus
   1591 
   1592     -- values of status
   1593     NodeStatus.PASS  = 'PASS'
   1594     NodeStatus.FAIL  = 'FAIL'
   1595     NodeStatus.ERROR = 'ERROR'
   1596 
   1597     function NodeStatus:new( number, testName, className )
   1598         local t = { number = number, testName = testName, className = className }
   1599         setmetatable( t, NodeStatus_MT )
   1600         t:pass()
   1601         return t
   1602     end
   1603 
   1604     function NodeStatus:pass()
   1605         self.status = self.PASS
   1606         -- useless but we know it's the field we want to use
   1607         self.msg = nil
   1608         self.stackTrace = nil
   1609     end
   1610 
   1611     function NodeStatus:fail(msg, stackTrace)
   1612         self.status = self.FAIL
   1613         self.msg = msg
   1614         self.stackTrace = stackTrace
   1615     end
   1616 
   1617     function NodeStatus:error(msg, stackTrace)
   1618         self.status = self.ERROR
   1619         self.msg = msg
   1620         self.stackTrace = stackTrace
   1621     end
   1622 
   1623     function NodeStatus:isPassed()
   1624         return self.status == NodeStatus.PASS
   1625     end
   1626 
   1627     function NodeStatus:isNotPassed()
   1628         -- print('hasFailure: '..prettystr(self))
   1629         return self.status ~= NodeStatus.PASS
   1630     end
   1631 
   1632     function NodeStatus:isFailure()
   1633         return self.status == NodeStatus.FAIL
   1634     end
   1635 
   1636     function NodeStatus:isError()
   1637         return self.status == NodeStatus.ERROR
   1638     end
   1639 
   1640     function NodeStatus:statusXML()
   1641         if self:isError() then
   1642             return table.concat(
   1643                 {'            <error type="', xmlEscape(self.msg), '">\n',
   1644                  '                <![CDATA[', xmlCDataEscape(self.stackTrace),
   1645                  ']]></error>\n'})
   1646         elseif self:isFailure() then
   1647             return table.concat(
   1648                 {'            <failure type="', xmlEscape(self.msg), '">\n',
   1649                  '                <![CDATA[', xmlCDataEscape(self.stackTrace),
   1650                  ']]></failure>\n'})
   1651         end
   1652         return '            <passed/>\n' -- (not XSD-compliant! normally shouldn't get here)
   1653     end
   1654 
   1655     --------------[[ Output methods ]]-------------------------
   1656 
   1657     function M.LuaUnit.statusLine(result)
   1658         -- return status line string according to results
   1659         local s = string.format('Ran %d tests in %0.3f seconds, %d successes',
   1660             result.runCount, result.duration, result.passedCount )
   1661         if result.notPassedCount > 0 then
   1662             if result.failureCount > 0 then
   1663                 s = s..string.format(', %d failures', result.failureCount )
   1664             end
   1665             if result.errorCount > 0 then
   1666                 s = s..string.format(', %d errors', result.errorCount )
   1667             end
   1668         else
   1669             s = s..', 0 failures'
   1670         end
   1671         if result.nonSelectedCount > 0 then
   1672             s = s..string.format(", %d non-selected", result.nonSelectedCount )
   1673         end
   1674         return s
   1675     end
   1676 
   1677     function M.LuaUnit:startSuite(testCount, nonSelectedCount)
   1678         self.result = {}
   1679         self.result.testCount = testCount
   1680         self.result.nonSelectedCount = nonSelectedCount
   1681         self.result.passedCount = 0
   1682         self.result.runCount = 0
   1683         self.result.currentTestNumber = 0
   1684         self.result.currentClassName = ""
   1685         self.result.currentNode = nil
   1686         self.result.suiteStarted = true
   1687         self.result.startTime = os.clock()
   1688         self.result.startDate = os.date(os.getenv('LUAUNIT_DATEFMT'))
   1689         self.result.startIsodate = os.date('%Y-%m-%dT%H:%M:%S')
   1690         self.result.patternFilter = self.patternFilter
   1691         self.result.tests = {}
   1692         self.result.failures = {}
   1693         self.result.errors = {}
   1694         self.result.notPassed = {}
   1695 
   1696         self.outputType = self.outputType or TextOutput
   1697         self.output = self.outputType:new()
   1698         self.output.runner = self
   1699         self.output.result = self.result
   1700         self.output.verbosity = self.verbosity
   1701         self.output.fname = self.fname
   1702         self.output:startSuite()
   1703     end
   1704 
   1705     function M.LuaUnit:startClass( className )
   1706         self.result.currentClassName = className
   1707         self.output:startClass( className )
   1708     end
   1709 
   1710     function M.LuaUnit:startTest( testName  )
   1711         self.result.currentTestNumber = self.result.currentTestNumber + 1
   1712         self.result.runCount = self.result.runCount + 1
   1713         self.result.currentNode = NodeStatus:new(
   1714             self.result.currentTestNumber,
   1715             testName,
   1716             self.result.currentClassName
   1717         )
   1718         self.result.currentNode.startTime = os.clock()
   1719         table.insert( self.result.tests, self.result.currentNode )
   1720         self.output:startTest( testName )
   1721     end
   1722 
   1723     function M.LuaUnit:addStatus( err )
   1724         -- "err" is expected to be a table / result from protectedCall()
   1725         if err.status == NodeStatus.PASS then return end
   1726 
   1727         local node = self.result.currentNode
   1728 
   1729         --[[ As a first approach, we will report only one error or one failure for one test.
   1730 
   1731         However, we can have the case where the test is in failure, and the teardown is in error.
   1732         In such case, it's a good idea to report both a failure and an error in the test suite. This is
   1733         what Python unittest does for example. However, it mixes up counts so need to be handled carefully: for
   1734         example, there could be more (failures + errors) count that tests. What happens to the current node ?
   1735 
   1736         We will do this more intelligent version later.
   1737         ]]
   1738 
   1739         -- if the node is already in failure/error, just don't report the new error (see above)
   1740         if node.status ~= NodeStatus.PASS then return end
   1741 
   1742         table.insert( self.result.notPassed, node )
   1743 
   1744         if err.status == NodeStatus.FAIL then
   1745             node:fail( err.msg, err.trace )
   1746             table.insert( self.result.failures, node )
   1747             self.output:addFailure( node )
   1748         elseif err.status == NodeStatus.ERROR then
   1749             node:error( err.msg, err.trace )
   1750             table.insert( self.result.errors, node )
   1751             self.output:addError( node )
   1752         end
   1753     end
   1754 
   1755     function M.LuaUnit:endTest()
   1756         local node = self.result.currentNode
   1757         -- print( 'endTest() '..prettystr(node))
   1758         -- print( 'endTest() '..prettystr(node:isNotPassed()))
   1759         node.duration = os.clock() - node.startTime
   1760         node.startTime = nil
   1761         self.output:endTest( node )
   1762 
   1763         if node:isPassed() then
   1764             self.result.passedCount = self.result.passedCount + 1
   1765         elseif node:isError() then
   1766             if self.quitOnError or self.quitOnFailure then
   1767                 -- Runtime error - abort test execution as requested by
   1768                 -- "--error" option. This is done by setting a special
   1769                 -- flag that gets handled in runSuiteByInstances().
   1770                 print("\nERROR during LuaUnit test execution:\n" .. node.msg)
   1771                 self.result.aborted = true
   1772             end
   1773         elseif node:isFailure() then
   1774             if self.quitOnFailure then
   1775                 -- Failure - abort test execution as requested by
   1776                 -- "--failure" option. This is done by setting a special
   1777                 -- flag that gets handled in runSuiteByInstances().
   1778                 print("\nFailure during LuaUnit test execution:\n" .. node.msg)
   1779                 self.result.aborted = true
   1780             end
   1781         end
   1782         self.result.currentNode = nil
   1783     end
   1784 
   1785     function M.LuaUnit:endClass()
   1786         self.output:endClass()
   1787     end
   1788 
   1789     function M.LuaUnit:endSuite()
   1790         if self.result.suiteStarted == false then
   1791             error('LuaUnit:endSuite() -- suite was already ended' )
   1792         end
   1793         self.result.duration = os.clock()-self.result.startTime
   1794         self.result.suiteStarted = false
   1795 
   1796         -- Expose test counts for outputter's endSuite(). This could be managed
   1797         -- internally instead, but unit tests (and existing use cases) might
   1798         -- rely on these fields being present.
   1799         self.result.notPassedCount = #self.result.notPassed
   1800         self.result.failureCount = #self.result.failures
   1801         self.result.errorCount = #self.result.errors
   1802 
   1803         self.output:endSuite()
   1804     end
   1805 
   1806     function M.LuaUnit:setOutputType(outputType)
   1807         -- default to text
   1808         -- tap produces results according to TAP format
   1809         if outputType:upper() == "NIL" then
   1810             self.outputType = NilOutput
   1811             return
   1812         end
   1813         if outputType:upper() == "TAP" then
   1814             self.outputType = TapOutput
   1815             return
   1816         end
   1817         if outputType:upper() == "JUNIT" then
   1818             self.outputType = JUnitOutput
   1819             return
   1820         end
   1821         if outputType:upper() == "TEXT" then
   1822             self.outputType = TextOutput
   1823             return
   1824         end
   1825         error( 'No such format: '..outputType,2)
   1826     end
   1827 
   1828     --------------[[ Runner ]]-----------------
   1829 
   1830     function M.LuaUnit:protectedCall(classInstance, methodInstance, prettyFuncName)
   1831         -- if classInstance is nil, this is just a function call
   1832         -- else, it's method of a class being called.
   1833 
   1834         local function err_handler(e)
   1835             -- transform error into a table, adding the traceback information
   1836             return {
   1837                 status = NodeStatus.ERROR,
   1838                 msg = e,
   1839                 trace = string.sub(debug.traceback("", 3), 2)
   1840             }
   1841         end
   1842 
   1843         local ok, err
   1844         if classInstance then
   1845             -- stupid Lua < 5.2 does not allow xpcall with arguments so let's use a workaround
   1846             ok, err = xpcall( function () methodInstance(classInstance) end, err_handler )
   1847         else
   1848             ok, err = xpcall( function () methodInstance() end, err_handler )
   1849         end
   1850         if ok then
   1851             return {status = NodeStatus.PASS}
   1852         end
   1853 
   1854         -- determine if the error was a failed test:
   1855         -- We do this by stripping the failure prefix from the error message,
   1856         -- while keeping track of the gsub() count. A non-zero value -> failure
   1857         local failed
   1858         err.msg, failed = err.msg:gsub(M.FAILURE_PREFIX, "", 1)
   1859         if failed > 0 then
   1860             err.status = NodeStatus.FAIL
   1861         end
   1862 
   1863         -- reformat / improve the stack trace
   1864         if prettyFuncName then -- we do have the real method name
   1865             err.trace = err.trace:gsub("in (%a+) 'methodInstance'", "in %1 '"..prettyFuncName.."'")
   1866         end
   1867         if STRIP_LUAUNIT_FROM_STACKTRACE then
   1868             err.trace = stripLuaunitTrace(err.trace)
   1869         end
   1870 
   1871         return err -- return the error "object" (table)
   1872     end
   1873 
   1874 
   1875     function M.LuaUnit:execOneFunction(className, methodName, classInstance, methodInstance)
   1876         -- When executing a test function, className and classInstance must be nil
   1877         -- When executing a class method, all parameters must be set
   1878 
   1879         if type(methodInstance) ~= 'function' then
   1880             error( tostring(methodName)..' must be a function, not '..type(methodInstance))
   1881         end
   1882 
   1883         local prettyFuncName
   1884         if className == nil then
   1885             className = '[TestFunctions]'
   1886             prettyFuncName = methodName
   1887         else
   1888             prettyFuncName = className..'.'..methodName
   1889         end
   1890 
   1891         if self.lastClassName ~= className then
   1892             if self.lastClassName ~= nil then
   1893                 self:endClass()
   1894             end
   1895             self:startClass( className )
   1896             self.lastClassName = className
   1897         end
   1898 
   1899         self:startTest(prettyFuncName)
   1900 
   1901         -- run setUp first (if any)
   1902         if classInstance then
   1903             local func = self.asFunction( classInstance.setUp )
   1904                          or self.asFunction( classInstance.Setup )
   1905                          or self.asFunction( classInstance.setup )
   1906                          or self.asFunction( classInstance.SetUp )
   1907             if func then
   1908                 self:addStatus(self:protectedCall(classInstance, func, className..'.setUp'))
   1909             end
   1910         end
   1911 
   1912         -- run testMethod()
   1913         if self.result.currentNode:isPassed() then
   1914             self:addStatus(self:protectedCall(classInstance, methodInstance, prettyFuncName))
   1915         end
   1916 
   1917         -- lastly, run tearDown (if any)
   1918         if classInstance then
   1919             local func = self.asFunction( classInstance.tearDown )
   1920                          or self.asFunction( classInstance.TearDown )
   1921                          or self.asFunction( classInstance.teardown )
   1922                          or self.asFunction( classInstance.Teardown )
   1923             if func then
   1924                 self:addStatus(self:protectedCall(classInstance, func, className..'.tearDown'))
   1925             end
   1926         end
   1927 
   1928         self:endTest()
   1929     end
   1930 
   1931     function M.LuaUnit.expandOneClass( result, className, classInstance )
   1932         -- add all test methods of classInstance to result
   1933         for methodName, methodInstance in sortedPairs(classInstance) do
   1934             if M.LuaUnit.asFunction(methodInstance) and M.LuaUnit.isMethodTestName( methodName ) then
   1935                 table.insert( result, { className..'.'..methodName, classInstance } )
   1936             end
   1937         end
   1938     end
   1939 
   1940     function M.LuaUnit.expandClasses( listOfNameAndInst )
   1941         -- expand all classes (provided as {className, classInstance}) to a list of {className.methodName, classInstance}
   1942         -- functions and methods remain untouched
   1943         local result = {}
   1944 
   1945         for i,v in ipairs( listOfNameAndInst ) do
   1946             local name, instance = v[1], v[2]
   1947             if M.LuaUnit.asFunction(instance) then
   1948                 table.insert( result, { name, instance } )
   1949             else
   1950                 if type(instance) ~= 'table' then
   1951                     error( 'Instance must be a table or a function, not a '..type(instance)..', value '..prettystr(instance))
   1952                 end
   1953                 if M.LuaUnit.isClassMethod( name ) then
   1954                     local className, methodName = M.LuaUnit.splitClassMethod( name )
   1955                     local methodInstance = instance[methodName]
   1956                     if methodInstance == nil then
   1957                         error( "Could not find method in class "..tostring(className).." for method "..tostring(methodName) )
   1958                     end
   1959                     table.insert( result, { name, instance } )
   1960                 else
   1961                     M.LuaUnit.expandOneClass( result, name, instance )
   1962                 end
   1963             end
   1964         end
   1965 
   1966         return result
   1967     end
   1968 
   1969     function M.LuaUnit.applyPatternFilter( patternFilter, listOfNameAndInst )
   1970         local included, excluded = {}, {}
   1971         for i, v in ipairs( listOfNameAndInst ) do
   1972             -- local name, instance = v[1], v[2]
   1973             if M.LuaUnit.patternInclude( patternFilter, v[1] ) then
   1974                 table.insert( included, v )
   1975             else
   1976                 table.insert( excluded, v )
   1977             end
   1978         end
   1979         return included, excluded
   1980     end
   1981 
   1982     function M.LuaUnit:runSuiteByInstances( listOfNameAndInst )
   1983         -- Run an explicit list of tests. All test instances and names must be supplied.
   1984         -- each test must be one of:
   1985         --   * { function name, function instance }
   1986         --   * { class name, class instance }
   1987         --   * { class.method name, class instance }
   1988 
   1989         local expandedList, filteredList, filteredOutList, className, methodName, methodInstance
   1990         expandedList = self.expandClasses( listOfNameAndInst )
   1991 
   1992         filteredList, filteredOutList = self.applyPatternFilter( self.patternFilter, expandedList )
   1993 
   1994         self:startSuite( #filteredList, #filteredOutList )
   1995 
   1996         for i,v in ipairs( filteredList ) do
   1997             local name, instance = v[1], v[2]
   1998             if M.LuaUnit.asFunction(instance) then
   1999                 self:execOneFunction( nil, name, nil, instance )
   2000             else
   2001                 if type(instance) ~= 'table' then
   2002                     error( 'Instance must be a table or a function, not a '..type(instance)..', value '..prettystr(instance))
   2003                 else
   2004                     assert( M.LuaUnit.isClassMethod( name ) )
   2005                     className, methodName = M.LuaUnit.splitClassMethod( name )
   2006                     methodInstance = instance[methodName]
   2007                     if methodInstance == nil then
   2008                         error( "Could not find method in class "..tostring(className).." for method "..tostring(methodName) )
   2009                     end
   2010                     self:execOneFunction( className, methodName, instance, methodInstance )
   2011                 end
   2012             end
   2013             if self.result.aborted then break end -- "--error" or "--failure" option triggered
   2014         end
   2015 
   2016         if self.lastClassName ~= nil then
   2017             self:endClass()
   2018         end
   2019 
   2020         self:endSuite()
   2021 
   2022         if self.result.aborted then
   2023             print("LuaUnit ABORTED (as requested by --error or --failure option)")
   2024             os.exit(-2)
   2025         end
   2026     end
   2027 
   2028     function M.LuaUnit:runSuiteByNames( listOfName )
   2029         -- Run an explicit list of test names
   2030 
   2031         local  className, methodName, instanceName, instance, methodInstance
   2032         local listOfNameAndInst = {}
   2033 
   2034         for i,name in ipairs( listOfName ) do
   2035             if M.LuaUnit.isClassMethod( name ) then
   2036                 className, methodName = M.LuaUnit.splitClassMethod( name )
   2037                 instanceName = className
   2038                 instance = _G[instanceName]
   2039 
   2040                 if instance == nil then
   2041                     error( "No such name in global space: "..instanceName )
   2042                 end
   2043 
   2044                 if type(instance) ~= 'table' then
   2045                     error( 'Instance of '..instanceName..' must be a table, not '..type(instance))
   2046                 end
   2047 
   2048                 methodInstance = instance[methodName]
   2049                 if methodInstance == nil then
   2050                     error( "Could not find method in class "..tostring(className).." for method "..tostring(methodName) )
   2051                 end
   2052 
   2053             else
   2054                 -- for functions and classes
   2055                 instanceName = name
   2056                 instance = _G[instanceName]
   2057             end
   2058 
   2059             if instance == nil then
   2060                 error( "No such name in global space: "..instanceName )
   2061             end
   2062 
   2063             if (type(instance) ~= 'table' and type(instance) ~= 'function') then
   2064                 error( 'Name must match a function or a table: '..instanceName )
   2065             end
   2066 
   2067             table.insert( listOfNameAndInst, { name, instance } )
   2068         end
   2069 
   2070         self:runSuiteByInstances( listOfNameAndInst )
   2071     end
   2072 
   2073     function M.LuaUnit.run(...)
   2074         -- Run some specific test classes.
   2075         -- If no arguments are passed, run the class names specified on the
   2076         -- command line. If no class name is specified on the command line
   2077         -- run all classes whose name starts with 'Test'
   2078         --
   2079         -- If arguments are passed, they must be strings of the class names
   2080         -- that you want to run or generic command line arguments (-o, -p, -v, ...)
   2081 
   2082         local runner = M.LuaUnit.new()
   2083         return runner:runSuite(...)
   2084     end
   2085 
   2086     function M.LuaUnit:runSuite( ... )
   2087 
   2088         local args = {...}
   2089         if type(args[1]) == 'table' and args[1].__class__ == 'LuaUnit' then
   2090             -- run was called with the syntax M.LuaUnit:runSuite()
   2091             -- we support both M.LuaUnit.run() and M.LuaUnit:run()
   2092             -- strip out the first argument
   2093             table.remove(args,1)
   2094         end
   2095 
   2096         if #args == 0 then
   2097             args = cmdline_argv
   2098         end
   2099 
   2100         local no_error, val = pcall( M.LuaUnit.parseCmdLine, args )
   2101         if not no_error then
   2102             print(val) -- error message
   2103             print()
   2104             print(M.USAGE)
   2105             os.exit(-1)
   2106         end
   2107 
   2108         local options = val
   2109 
   2110         -- We expect these option fields to be either `nil` or contain
   2111         -- valid values, so it's safe to always copy them directly.
   2112         self.verbosity     = options.verbosity
   2113         self.quitOnError   = options.quitOnError
   2114         self.quitOnFailure = options.quitOnFailure
   2115         self.fname         = options.fname
   2116         self.patternFilter = options.pattern
   2117 
   2118         if options.output and options.output:lower() == 'junit' and options.fname == nil then
   2119             print('With junit output, a filename must be supplied with -n or --name')
   2120             os.exit(-1)
   2121         end
   2122 
   2123         if options.output then
   2124             no_error, val = pcall(self.setOutputType, self, options.output)
   2125             if not no_error then
   2126                 print(val) -- error message
   2127                 print()
   2128                 print(M.USAGE)
   2129                 os.exit(-1)
   2130             end
   2131         end
   2132 
   2133         self:runSuiteByNames( options.testNames or M.LuaUnit.collectTests() )
   2134 
   2135         return self.result.notPassedCount
   2136     end
   2137 -- class LuaUnit
   2138 
   2139 -- For compatbility with LuaUnit v2
   2140 M.run = M.LuaUnit.run
   2141 M.Run = M.LuaUnit.run
   2142 
   2143 function M:setVerbosity( verbosity )
   2144     M.LuaUnit.verbosity = verbosity
   2145 end
   2146 M.set_verbosity = M.setVerbosity
   2147 M.SetVerbosity = M.setVerbosity
   2148 
   2149 
   2150 return M
   2151