1--[[
2        luaunit.lua
3
4Description: A unit testing framework
5Homepage: https://github.com/bluebird75/luaunit
6Development by Philippe Fremy <phil@freehackers.org>
7Based on initial work of Ryu, Gwang (http://www.gpgstudy.com/gpgiki/LuaUnit)
8License: BSD License, see LICENSE.txt
9Version: 3.2
10]]--
11
12require("math")
13local M={}
14
15-- private exported functions (for testing)
16M.private = {}
17
18M.VERSION='3.2'
19
20--[[ Some people like assertEquals( actual, expected ) and some people prefer
21assertEquals( expected, actual ).
22]]--
23M.ORDER_ACTUAL_EXPECTED = true
24M.PRINT_TABLE_REF_IN_ERROR_MSG = false
25M.TABLE_EQUALS_KEYBYCONTENT = true
26M.LINE_LENGTH=80
27
28-- set this to false to debug luaunit
29local STRIP_LUAUNIT_FROM_STACKTRACE=true
30
31M.VERBOSITY_DEFAULT = 10
32M.VERBOSITY_LOW     = 1
33M.VERBOSITY_QUIET   = 0
34M.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
40local cmdline_argv = rawget(_G, "arg")
41
42M.FAILURE_PREFIX = 'LuaUnit test FAILURE: ' -- prefix string for failed tests
43
44M.USAGE=[[Usage: lua <your_test_suite.lua> [options] [testname1 [testname2] ... ]
45Options:
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
68local crossTypeOrdering = {
69    number = 1,
70    boolean = 2,
71    string = 3,
72    table = 4,
73    other = 5
74}
75local 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
81local 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
90end
91
92local 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
102end
103M.private.__genSortedIndex = __genSortedIndex
104
105local 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
152end
153
154local 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
160end
161M.private.sortedPairs = sortedPairs
162
163local 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
182end
183M.private.strsplit = strsplit
184
185local function hasNewLine( s )
186    -- return true if s has a newline
187    return (string.find(s, '\n', 1, true) ~= nil)
188end
189M.private.hasNewLine = hasNewLine
190
191local function prefixString( prefix, s )
192    -- Prefix all the lines of s with prefix
193    return prefix .. table.concat(strsplit('\n', s), '\n' .. prefix)
194end
195M.private.prefixString = prefixString
196
197local 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
207end
208M.private.strMatch = strMatch
209
210local 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    } )
226end
227M.private.xmlEscape = xmlEscape
228
229local function xmlCDataEscape( s )
230    -- Return s escaped for CData section, escapes: "]]>"
231    return string.gsub( s, ']]>', ']]&gt;' )
232end
233M.private.xmlCDataEscape = xmlCDataEscape
234
235local 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
321end
322M.private.stripLuaunitTrace = stripLuaunitTrace
323
324
325local 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)
346end
347
348local 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
365end
366M.prettystr = prettystr
367
368local 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
388end
389M.private.prettystrPadded = prettystrPadded
390
391local 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)
398end
399M.private._table_keytostring = _table_keytostring
400
401local TABLE_TOSTRING_SEP = ", "
402local TABLE_TOSTRING_SEP_LEN = string.len(TABLE_TOSTRING_SEP)
403
404local 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)
463end
464M.private._table_tostring = _table_tostring -- prettystr_sub() needs it
465
466local 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
486end
487
488local 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
507end
508
509local 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
571end
572M.private._is_table_equals = _is_table_equals
573
574local 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)
579end
580
581local function fail_fmt(level, ...)
582     -- failure with printf-style formatted message and given error level
583    failure(string.format(...), (level or 1) + 1)
584end
585M.private.fail_fmt = fail_fmt
586
587local function error_fmt(level, ...)
588     -- printf-style error()
589    error(string.format(...), (level or 1) + 1)
590end
591
592----------------------------------------------------------------
593--
594--                     assertions
595--
596----------------------------------------------------------------
597
598local 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))
608end
609
610function 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
616end
617
618function M.assertTrue(value)
619    if not value then
620        failure("expected: true, actual: " ..prettystr(value), 2)
621    end
622end
623
624function M.assertFalse(value)
625    if value then
626        failure("expected: false, actual: " ..prettystr(value), 2)
627    end
628end
629
630function M.assertIsNil(value)
631    if value ~= nil then
632        failure("expected: nil, actual: " ..prettystr(value), 2)
633    end
634end
635
636function M.assertNotIsNil(value)
637    if value == nil then
638        failure("expected non nil value, received nil", 2)
639    end
640end
641
642function 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
652end
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:
657local EPSILON = 0.00000000001
658function 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
668end
669
670function 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
679end
680
681function 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))
694end
695
696function 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
705end
706
707function 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
715end
716
717function 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
725end
726
727function 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
735end
736
737function 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
745end
746
747function 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
755end
756
757function 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
769end
770
771function 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
783end
784
785function 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
797end
798
799--[[
800Add type assertion functions to the module table M. Each of these functions
801takes a single parameter "value", and checks that its Lua type matches the
802expected string (derived from the function name):
803
804M.assertIsXxx(value) -> ensure that type(value) conforms to "xxx"
805]]
806for _, 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
821end
822
823--[[
824Add non-type assertion functions to the module table M. Each of these functions
825takes a single parameter "value", and checks that its Lua type differs from the
826expected string (derived from the function name):
827
828M.assertNotIsXxx(value) -> ensure that type(value) is not "xxx"
829]]
830for _, 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
845end
846
847function 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
856end
857
858function 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
866end
867
868function 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
877end
878
879----------------------------------------------------------------
880--                     Compatibility layer
881----------------------------------------------------------------
882
883-- for compatibility with LuaUnit v2.x
884function M.wrapFunctions(...)
885    io.stderr:write( [[Use of WrapFunction() is no longer needed.
886Just prefix your test function names with "test" or "Test" and they
887will 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    ]]
906end
907
908local 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
1005for _,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
1013end
1014
1015----------------------------------------------------------------
1016--
1017--                     Outputters
1018--
1019----------------------------------------------------------------
1020
1021----------------------------------------------------------------
1022--                     class TapOutput
1023----------------------------------------------------------------
1024
1025
1026local TapOutput = { __class__ = 'TapOutput' } -- class
1027local 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
1077local JUnitOutput = { __class__ = 'JUnitOutput' } -- class
1078local 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
1171For each test: . or F or E
1172
1173If some failed tests:
1174    ==============
1175    ERROR / FAILURE: TestName (testfile.testclass)
1176    ---------
1177    Stack trace
1178
1179
1180then --------------
1181then "Ran x tests in 0.000s"
1182then OK or FAILED (failures=1, error=1)
1183
1184-- Python Verbose:
1185testname (filename.classname) ... ok
1186testname (filename.classname) ... FAIL
1187testname (filename.classname) ... ERROR
1188
1189then --------------
1190then "Ran x tests in 0.000s"
1191then OK or FAILED (failures=1, error=1)
1192
1193-- Ruby:
1194Started
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
1202Loaded suite tc_simple_number2
1203Started
1204F..
1205Finished in 0.038617 seconds.
1206
1207  1) Failure:
1208test_failure(TestSimpleNumber) [tc_simple_number2.rb:16]:
1209Adding doesn't work.
1210<3> expected but was
1211<4>.
1212
12133 tests, 4 assertions, 1 failures, 0 errors
1214
1215-- Java Junit
1216.......F.
1217Time: 0,003
1218There was 1 failure:
12191) 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
1225FAILURES!!!
1226Tests run: 8,  Failures: 1,  Errors: 0
1227
1228
1229-- Maven
1230
1231# mvn test
1232-------------------------------------------------------
1233 T E S T S
1234-------------------------------------------------------
1235Running math.AdditionTest
1236Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed:
12370.03 sec <<< FAILURE!
1238
1239Results :
1240
1241Failed tests:
1242  testLireSymbole(math.AdditionTest)
1243
1244Tests 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
1260then --------------
1261then "Ran x tests in 0.000s (%d not selected, %d skipped)"
1262then OK or FAILED (failures=1, error=1)
1263
1264
1265]]
1266
1267local TextOutput = { __class__ = 'TextOutput' } -- class
1268local 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
1364local function nopCallable()
1365    --print(42)
1366    return nopCallable
1367end
1368
1369local NilOutput = { __class__ = 'NilOuptut' } -- class
1370local NilOutput_MT = { __index = nopCallable } -- metatable
1371
1372function NilOutput:new()
1373    return setmetatable( { __class__ = 'NilOutput' }, NilOutput_MT )
1374end
1375
1376----------------------------------------------------------------
1377--
1378--                     class LuaUnit
1379--
1380----------------------------------------------------------------
1381
1382M.LuaUnit = {
1383    outputType = TextOutput,
1384    verbosity = M.VERBOSITY_DEFAULT,
1385    __class__ = 'LuaUnit'
1386}
1387local LuaUnit_MT = { __index = M.LuaUnit }
1388
1389if EXPORT_ASSERT_TO_GLOBALS then
1390    LuaUnit = M.LuaUnit
1391end
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@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
2140M.run = M.LuaUnit.run
2141M.Run = M.LuaUnit.run
2142
2143function M:setVerbosity( verbosity )
2144    M.LuaUnit.verbosity = verbosity
2145end
2146M.set_verbosity = M.setVerbosity
2147M.SetVerbosity = M.setVerbosity
2148
2149
2150return M
2151