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