luaunit.lua 66 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023
  1. --[[
  2. luaunit.lua
  3. Description: A unit testing framework
  4. Homepage: https://github.com/bluebird75/luaunit
  5. Development by Philippe Fremy <phil@freehackers.org>
  6. Based on initial work of Ryu, Gwang (http://www.gpgstudy.com/gpgiki/LuaUnit)
  7. License: BSD License, see LICENSE.txt
  8. Version: 3.0
  9. ]]--
  10. local M={}
  11. -- private exported functions (for testing)
  12. M.private = {}
  13. M.VERSION='3.1'
  14. --[[ Some people like assertEquals( actual, expected ) and some people prefer
  15. assertEquals( expected, actual ).
  16. ]]--
  17. M.ORDER_ACTUAL_EXPECTED = true
  18. M.PRINT_TABLE_REF_IN_ERROR_MSG = false
  19. M.LINE_LENGTH=80
  20. -- set this to false to debug luaunit
  21. local STRIP_LUAUNIT_FROM_STACKTRACE=true
  22. M.VERBOSITY_DEFAULT = 10
  23. M.VERBOSITY_LOW = 1
  24. M.VERBOSITY_QUIET = 0
  25. M.VERBOSITY_VERBOSE = 20
  26. -- set EXPORT_ASSERT_TO_GLOBALS to have all asserts visible as global values
  27. -- EXPORT_ASSERT_TO_GLOBALS = true
  28. -- we need to keep a copy of the script args before it is overriden
  29. local cmdline_argv = rawget(_G, "arg")
  30. M.USAGE=[[Usage: lua <your_test_suite.lua> [options] [testname1 [testname2] ... ]
  31. Options:
  32. -h, --help: Print this help
  33. --version: Print version information
  34. -v, --verbose: Increase verbosity
  35. -q, --quiet: Set verbosity to minimum
  36. -o, --output OUTPUT: Set output type to OUTPUT
  37. Possible values: text, tap, junit, nil
  38. -n, --name NAME: For junit only, mandatory name of xml file
  39. -p, --pattern PATTERN: Execute all test names matching the lua PATTERN
  40. May be repeated to include severals patterns
  41. Make sure you esape magic chars like +? with %
  42. testname1, testname2, ... : tests to run in the form of testFunction,
  43. TestClass or TestClass.testMethod
  44. ]]
  45. ----------------------------------------------------------------
  46. --
  47. -- general utility functions
  48. --
  49. ----------------------------------------------------------------
  50. local function __genSortedIndex( t )
  51. local sortedIndexStr = {}
  52. local sortedIndexInt = {}
  53. local sortedIndex = {}
  54. for key,_ in pairs(t) do
  55. if type(key) == 'string' then
  56. table.insert( sortedIndexStr, key )
  57. else
  58. table.insert( sortedIndexInt, key )
  59. end
  60. end
  61. table.sort( sortedIndexInt )
  62. table.sort( sortedIndexStr )
  63. for _,value in ipairs(sortedIndexInt) do
  64. table.insert( sortedIndex, value )
  65. end
  66. for _,value in ipairs(sortedIndexStr) do
  67. table.insert( sortedIndex, value )
  68. end
  69. return sortedIndex
  70. end
  71. M.private.__genSortedIndex = __genSortedIndex
  72. -- Contains the keys of the table being iterated, already sorted
  73. -- and the last index that has been iterated
  74. -- Example:
  75. -- t a table on which we iterate
  76. -- sortedNextCache[ t ].idx is the sorted index of the table
  77. -- sortedNextCache[ t ].lastIdx is the last index used in the sorted index
  78. local sortedNextCache = {}
  79. local function sortedNext(t, state)
  80. -- Equivalent of the next() function of table iteration, but returns the
  81. -- keys in the alphabetic order. We use a temporary sorted key table that
  82. -- is stored in a global variable. We also store the last index
  83. -- used in the iteration to find the next one quickly
  84. --print("sortedNext: state = "..tostring(state) )
  85. local key
  86. if state == nil then
  87. -- the first time, generate the index
  88. -- cleanup the previous index, just in case...
  89. sortedNextCache[ t ] = nil
  90. sortedNextCache[ t ] = { idx=__genSortedIndex( t ), lastIdx=1 }
  91. key = sortedNextCache[t].idx[1]
  92. return key, t[key]
  93. end
  94. -- normally, the previous index in the orderedTable is there:
  95. local lastIndex = sortedNextCache[ t ].lastIdx
  96. if sortedNextCache[t].idx[lastIndex] == state then
  97. key = sortedNextCache[t].idx[lastIndex+1]
  98. sortedNextCache[ t ].lastIdx = lastIndex+1
  99. else
  100. -- strange, we have to find the next value by ourselves
  101. key = nil
  102. for i = 1,#sortedNextCache[t] do
  103. if sortedNextCache[t].idx[i] == state then
  104. key = sortedNextCache[t].idx[i+1]
  105. sortedNextCache[ t ].lastIdx = i+1
  106. -- break
  107. end
  108. end
  109. end
  110. if key then
  111. return key, t[key]
  112. end
  113. -- no more value to return, cleanup
  114. sortedNextCache[t] = nil
  115. return
  116. end
  117. M.private.sortedNext = sortedNext
  118. local function sortedPairs(t)
  119. -- Equivalent of the pairs() function on tables. Allows to iterate
  120. -- in sorted order. This works only if the key types are all the same
  121. -- and support comparison
  122. return sortedNext, t, nil
  123. end
  124. local function strsplit(delimiter, text)
  125. -- Split text into a list consisting of the strings in text,
  126. -- separated by strings matching delimiter (which may be a pattern).
  127. -- example: strsplit(",%s*", "Anna, Bob, Charlie,Dolores")
  128. local list = {}
  129. local pos = 1
  130. if string.find("", delimiter, 1, true) then -- this would result in endless loops
  131. error("delimiter matches empty string!")
  132. end
  133. while 1 do
  134. local first, last = string.find(text, delimiter, pos, true)
  135. if first then -- found?
  136. table.insert(list, string.sub(text, pos, first-1))
  137. pos = last+1
  138. else
  139. table.insert(list, string.sub(text, pos))
  140. break
  141. end
  142. end
  143. return list
  144. end
  145. M.private.strsplit = strsplit
  146. local function hasNewLine( s )
  147. -- return true if s has a newline
  148. return (string.find(s, '\n', 1, true) ~= nil)
  149. end
  150. M.private.hasNewLine = hasNewLine
  151. local function prefixString( prefix, s )
  152. -- Prefix all the lines of s with prefix
  153. local t = strsplit('\n', s)
  154. return prefix..table.concat(t, '\n'..prefix)
  155. end
  156. M.private.prefixString = prefixString
  157. local function strMatch(s, pattern, start, final )
  158. -- return true if s matches completely the pattern from index start to index end
  159. -- return false in every other cases
  160. -- if start is nil, matches from the beginning of the string
  161. -- if end is nil, matches to the end of the string
  162. start = start or 1
  163. final = final or string.len(s)
  164. local foundStart, foundEnd = string.find(s, pattern, start, false)
  165. if foundStart and foundStart == start and foundEnd == final then
  166. return true
  167. end
  168. return false -- no match
  169. end
  170. M.private.strMatch = strMatch
  171. local function xmlEscape( s )
  172. -- Return s escaped for XML attributes
  173. -- escapes table:
  174. -- " &quot;
  175. -- ' &apos;
  176. -- < &lt;
  177. -- > &gt;
  178. -- & &amp;
  179. return string.gsub( s, '.', {
  180. ['&'] = "&amp;",
  181. ['"'] = "&quot;",
  182. ["'"] = "&apos;",
  183. ['<'] = "&lt;",
  184. ['>'] = "&gt;",
  185. } )
  186. end
  187. M.private.xmlEscape = xmlEscape
  188. local function xmlCDataEscape( s )
  189. -- Return s escaped for CData section
  190. -- escapes: "]]>"
  191. return string.gsub( s, ']]>', ']]&gt;' )
  192. end
  193. M.private.xmlCDataEscape = xmlCDataEscape
  194. local patternLuaunitTrace='(.*[/\\]luaunit%.lua:%d+: .*)'
  195. local function isLuaunitInternalLine( s )
  196. -- return true if line of stack trace comes from inside luaunit
  197. -- print( 'Matching for luaunit: '..s )
  198. local matchStart, matchEnd, capture = string.find( s, patternLuaunitTrace )
  199. if matchStart then
  200. -- print('Match luaunit line')
  201. return true
  202. end
  203. return false
  204. end
  205. local function stripLuaunitTrace( stackTrace )
  206. --[[
  207. -- Example of a traceback:
  208. <<stack traceback:
  209. example_with_luaunit.lua:130: in function 'test2_withFailure'
  210. ./luaunit.lua:1449: in function <./luaunit.lua:1449>
  211. [C]: in function 'xpcall'
  212. ./luaunit.lua:1449: in function 'protectedCall'
  213. ./luaunit.lua:1508: in function 'execOneFunction'
  214. ./luaunit.lua:1596: in function 'runSuiteByInstances'
  215. ./luaunit.lua:1660: in function 'runSuiteByNames'
  216. ./luaunit.lua:1736: in function 'runSuite'
  217. example_with_luaunit.lua:140: in main chunk
  218. [C]: in ?>>
  219. Other example:
  220. <<stack traceback:
  221. ./luaunit.lua:545: in function 'assertEquals'
  222. example_with_luaunit.lua:58: in function 'TestToto.test7'
  223. ./luaunit.lua:1517: in function <./luaunit.lua:1517>
  224. [C]: in function 'xpcall'
  225. ./luaunit.lua:1517: in function 'protectedCall'
  226. ./luaunit.lua:1578: in function 'execOneFunction'
  227. ./luaunit.lua:1677: in function 'runSuiteByInstances'
  228. ./luaunit.lua:1730: in function 'runSuiteByNames'
  229. ./luaunit.lua:1806: in function 'runSuite'
  230. example_with_luaunit.lua:140: in main chunk
  231. [C]: in ?>>
  232. <<stack traceback:
  233. luaunit2/example_with_luaunit.lua:124: in function 'test1_withFailure'
  234. luaunit2/luaunit.lua:1532: in function <luaunit2/luaunit.lua:1532>
  235. [C]: in function 'xpcall'
  236. luaunit2/luaunit.lua:1532: in function 'protectedCall'
  237. luaunit2/luaunit.lua:1591: in function 'execOneFunction'
  238. luaunit2/luaunit.lua:1679: in function 'runSuiteByInstances'
  239. luaunit2/luaunit.lua:1743: in function 'runSuiteByNames'
  240. luaunit2/luaunit.lua:1819: in function 'runSuite'
  241. luaunit2/example_with_luaunit.lua:140: in main chunk
  242. [C]: in ?>>
  243. -- first line is "stack traceback": KEEP
  244. -- next line may be luaunit line: REMOVE
  245. -- next lines are call in the program under testOk: REMOVE
  246. -- next lines are calls from luaunit to call the program under test: KEEP
  247. -- Strategy:
  248. -- keep first line
  249. -- remove lines that are part of luaunit
  250. -- kepp lines until we hit a luaunit line
  251. ]]
  252. -- print( '<<'..stackTrace..'>>' )
  253. local t = strsplit( '\n', stackTrace )
  254. -- print( prettystr(t) )
  255. local idx=2
  256. -- remove lines that are still part of luaunit
  257. while idx <= #t do
  258. if isLuaunitInternalLine( t[idx] ) then
  259. -- print('Removing : '..t[idx] )
  260. table.remove(t, idx)
  261. else
  262. break
  263. end
  264. end
  265. -- keep lines until we hit luaunit again
  266. while (idx <= #t) and (not isLuaunitInternalLine(t[idx])) do
  267. -- print('Keeping : '..t[idx] )
  268. idx = idx+1
  269. end
  270. -- remove remaining luaunit lines
  271. while idx <= #t do
  272. -- print('Removing : '..t[idx] )
  273. table.remove(t, idx)
  274. end
  275. -- print( prettystr(t) )
  276. return table.concat( t, '\n')
  277. end
  278. M.private.stripLuaunitTrace = stripLuaunitTrace
  279. function table.keytostring(k)
  280. -- like prettystr but do not enclose with "" if the string is just alphanumerical
  281. -- this is better for displaying table keys who are often simple strings
  282. if "string" == type( k ) and string.match( k, "^[_%a][_%a%d]*$" ) then
  283. return k
  284. else
  285. return M.prettystr(k)
  286. end
  287. end
  288. function table.tostring( tbl, indentLevel, printTableRefs, recursionTable )
  289. printTableRefs = printTableRefs or M.PRINT_TABLE_REF_IN_ERROR_MSG
  290. recursionTable = recursionTable or {}
  291. recursionTable[tbl] = true
  292. local result, done = {}, {}
  293. local dispOnMultLines = false
  294. for k, v in ipairs( tbl ) do
  295. if recursionTable[v] then
  296. -- recursion detected!
  297. recursionTable['recursionDetected'] = true
  298. table.insert( result, "<"..tostring(v)..">" )
  299. else
  300. table.insert( result, M.private.prettystr_sub( v, indentLevel+1, false, printTableRefs, recursionTable ) )
  301. end
  302. done[ k ] = true
  303. end
  304. for k, v in sortedPairs( tbl ) do
  305. if not done[ k ] then
  306. if recursionTable[v] then
  307. -- recursion detected!
  308. recursionTable['recursionDetected'] = true
  309. table.insert( result, table.keytostring( k ) .. "=" .. "<"..tostring(v)..">" )
  310. else
  311. table.insert( result,
  312. table.keytostring( k ) .. "=" .. M.private.prettystr_sub( v, indentLevel+1, true, printTableRefs, recursionTable ) )
  313. end
  314. end
  315. end
  316. if printTableRefs then
  317. table_ref = "<"..tostring(tbl).."> "
  318. else
  319. table_ref = ''
  320. end
  321. local SEP_LENGTH=2 -- ", "
  322. local totalLength = 0
  323. for k, v in ipairs( result ) do
  324. l = string.len( v )
  325. totalLength = totalLength + l
  326. if l > M.LINE_LENGTH-1 then
  327. dispOnMultLines = true
  328. end
  329. end
  330. -- adjust with length of separator
  331. totalLength = totalLength + SEP_LENGTH * math.max( 0, #result-1) + 2 -- two items need 1 sep, thee items two seps + len of '{}'
  332. if totalLength > M.LINE_LENGTH-1 then
  333. dispOnMultLines = true
  334. end
  335. if dispOnMultLines then
  336. indentString = string.rep(" ", indentLevel)
  337. closingIndentString = string.rep(" ", math.max(0, indentLevel-1) )
  338. result_str = table_ref.."{\n"..indentString .. table.concat( result, ",\n"..indentString ) .. "\n"..closingIndentString.."}"
  339. else
  340. result_str = table_ref.."{".. table.concat( result, ", " ) .. "}"
  341. end
  342. return result_str
  343. end
  344. local function prettystr( v, keeponeline )
  345. --[[ Better string conversion, to display nice variable content:
  346. For strings, if keeponeline is set to true, string is displayed on one line, with visible \n
  347. * string are enclosed with " by default, or with ' if string contains a "
  348. * if table is a class, display class name
  349. * tables are expanded
  350. ]]--
  351. local recursionTable = {}
  352. local s = M.private.prettystr_sub(v, 1, keeponeline, M.PRINT_TABLE_REF_IN_ERROR_MSG, recursionTable)
  353. if recursionTable['recursionDetected'] == true and M.PRINT_TABLE_REF_IN_ERROR_MSG == false then
  354. -- some table contain recursive references,
  355. -- so we must recompute the value by including all table references
  356. -- else the result looks like crap
  357. recursionTable = {}
  358. s = M.private.prettystr_sub(v, 1, keeponeline, true, recursionTable)
  359. end
  360. return s
  361. end
  362. M.prettystr = prettystr
  363. local function prettystr_sub(v, indentLevel, keeponeline, printTableRefs, recursionTable )
  364. if "string" == type( v ) then
  365. if keeponeline then
  366. v = string.gsub( v, "\n", "\\n" )
  367. end
  368. -- use clever delimiters according to content:
  369. -- if string contains ", enclose with '
  370. -- if string contains ', enclose with "
  371. if string.match( string.gsub(v,"[^'\"]",""), '^"+$' ) then
  372. return "'" .. v .. "'"
  373. end
  374. return '"' .. string.gsub(v,'"', '\\"' ) .. '"'
  375. end
  376. if type(v) == 'table' then
  377. --if v.__class__ then
  378. -- return string.gsub( tostring(v), 'table', v.__class__ )
  379. --end
  380. return table.tostring(v, indentLevel, printTableRefs, recursionTable)
  381. end
  382. return tostring(v)
  383. end
  384. M.private.prettystr_sub = prettystr_sub
  385. local function _table_contains(t, element)
  386. if t then
  387. for _, value in pairs(t) do
  388. if type(value) == type(element) then
  389. if type(element) == 'table' then
  390. -- if we wanted recursive items content comparison, we could use
  391. -- _is_table_items_equals(v, expected) but one level of just comparing
  392. -- items is sufficient
  393. if M.private._is_table_equals( value, element ) then
  394. return true
  395. end
  396. else
  397. if value == element then
  398. return true
  399. end
  400. end
  401. end
  402. end
  403. end
  404. return false
  405. end
  406. local function _is_table_items_equals(actual, expected )
  407. if (type(actual) == 'table') and (type(expected) == 'table') then
  408. for k,v in pairs(actual) do
  409. if not _table_contains(expected, v) then
  410. return false
  411. end
  412. end
  413. for k,v in pairs(expected) do
  414. if not _table_contains(actual, v) then
  415. return false
  416. end
  417. end
  418. return true
  419. elseif type(actual) ~= type(expected) then
  420. return false
  421. elseif actual == expected then
  422. return true
  423. end
  424. return false
  425. end
  426. local function _is_table_equals(actual, expected)
  427. if (type(actual) == 'table') and (type(expected) == 'table') then
  428. if (#actual ~= #expected) then
  429. return false
  430. end
  431. local k,v
  432. for k,v in pairs(actual) do
  433. if not _is_table_equals(v, expected[k]) then
  434. return false
  435. end
  436. end
  437. for k,v in pairs(expected) do
  438. if not _is_table_equals(v, actual[k]) then
  439. return false
  440. end
  441. end
  442. return true
  443. elseif type(actual) ~= type(expected) then
  444. return false
  445. elseif actual == expected then
  446. return true
  447. end
  448. return false
  449. end
  450. M.private._is_table_equals = _is_table_equals
  451. ----------------------------------------------------------------
  452. --
  453. -- assertions
  454. --
  455. ----------------------------------------------------------------
  456. local function errorMsgEquality(actual, expected)
  457. local errorMsg
  458. if not M.ORDER_ACTUAL_EXPECTED then
  459. expected, actual = actual, expected
  460. end
  461. local expectedStr = prettystr(expected)
  462. local actualStr = prettystr(actual)
  463. if type(expected) == 'string' or type(expected) == 'table' then
  464. if hasNewLine( expectedStr..actualStr ) then
  465. expectedStr = '\n'..expectedStr
  466. actualStr = '\n'..actualStr
  467. end
  468. errorMsg = "expected: "..expectedStr.."\n"..
  469. "actual: "..actualStr
  470. else
  471. errorMsg = "expected: "..expectedStr..", actual: "..actualStr
  472. end
  473. return errorMsg
  474. end
  475. function M.assertError(f, ...)
  476. -- assert that calling f with the arguments will raise an error
  477. -- example: assertError( f, 1, 2 ) => f(1,2) should generate an error
  478. local no_error, error_msg = pcall( f, ... )
  479. if not no_error then return end
  480. error( "Expected an error when calling function but no error generated", 2 )
  481. end
  482. function M.assertTrue(value)
  483. if not value then
  484. error("expected: true, actual: " ..prettystr(value), 2)
  485. end
  486. end
  487. function M.assertFalse(value)
  488. if value then
  489. error("expected: false, actual: " ..prettystr(value), 2)
  490. end
  491. end
  492. function M.assertNil(value)
  493. if value ~= nil then
  494. error("expected: nil, actual: " ..prettystr(value), 2)
  495. end
  496. end
  497. function M.assertNotNil(value)
  498. if value == nil then
  499. error("expected non nil value, received nil", 2)
  500. end
  501. end
  502. function M.assertEquals(actual, expected)
  503. if type(actual) == 'table' and type(expected) == 'table' then
  504. if not _is_table_equals(actual, expected) then
  505. error( errorMsgEquality(actual, expected), 2 )
  506. end
  507. elseif type(actual) ~= type(expected) then
  508. error( errorMsgEquality(actual, expected), 2 )
  509. elseif actual ~= expected then
  510. error( errorMsgEquality(actual, expected), 2 )
  511. end
  512. end
  513. function M.assertAlmostEquals( actual, expected, margin )
  514. -- check that two floats are close by margin
  515. if type(actual) ~= 'number' or type(expected) ~= 'number' or type(margin) ~= 'number' then
  516. error('assertAlmostEquals: must supply only number arguments.\nArguments supplied: '..actual..', '..expected..', '..margin, 2)
  517. end
  518. if margin < 0 then
  519. error( 'assertAlmostEquals: margin must be positive, current value is '..margin, 2)
  520. end
  521. if not M.ORDER_ACTUAL_EXPECTED then
  522. expected, actual = actual, expected
  523. end
  524. -- help lua in limit cases like assertAlmostEquals( 1.1, 1.0, 0.1)
  525. -- which by default does not work. We need to give margin a small boost
  526. local realmargin = margin + 0.00000000001
  527. if math.abs(expected - actual) > realmargin then
  528. error( 'Values are not almost equal\nExpected: '..expected..' with margin of '..margin..', received: '..actual, 2)
  529. end
  530. end
  531. function M.assertNotEquals(actual, expected)
  532. if type(actual) ~= type(expected) then
  533. return
  534. end
  535. local genError = false
  536. if type(actual) == 'table' and type(expected) == 'table' then
  537. if not _is_table_equals(actual, expected) then
  538. return
  539. end
  540. genError = true
  541. elseif actual == expected then
  542. genError = true
  543. end
  544. if genError then
  545. error( 'Received the not expected value: ' .. prettystr(actual), 2 )
  546. end
  547. end
  548. function M.assertNotAlmostEquals( actual, expected, margin )
  549. -- check that two floats are not close by margin
  550. if type(actual) ~= 'number' or type(expected) ~= 'number' or type(margin) ~= 'number' then
  551. error('assertNotAlmostEquals: must supply only number arguments.\nArguments supplied: '..actual..', '..expected..', '..margin, 2)
  552. end
  553. if margin <= 0 then
  554. error( 'assertNotAlmostEquals: margin must be positive, current value is '..margin, 2)
  555. end
  556. if not M.ORDER_ACTUAL_EXPECTED then
  557. expected, actual = actual, expected
  558. end
  559. -- help lua in limit cases like assertAlmostEquals( 1.1, 1.0, 0.1)
  560. -- which by default does not work. We need to give margin a small boost
  561. local realmargin = margin + 0.00000000001
  562. if math.abs(expected - actual) <= realmargin then
  563. error( 'Values are almost equal\nExpected: '..expected..' with a difference above margin of '..margin..', received: '..actual, 2)
  564. end
  565. end
  566. function M.assertStrContains( str, sub, useRe )
  567. -- this relies on lua string.find function
  568. -- a string always contains the empty string
  569. local subType
  570. local noUseRe = not useRe
  571. if string.find(str, sub, 1, noUseRe) == nil then
  572. if noUseRe then
  573. subType = 'substring'
  574. else
  575. subType = 'regexp'
  576. end
  577. local subPretty = prettystr(sub)
  578. local strPretty = prettystr(str)
  579. if hasNewLine( subPretty..strPretty ) then
  580. subPretty = '\n'..subPretty..'\n'
  581. strPretty = '\n'..strPretty
  582. end
  583. error( 'Error, '..subType..' '..subPretty..' was not found in string '..strPretty, 2)
  584. end
  585. end
  586. function M.assertStrIContains( str, sub )
  587. -- this relies on lua string.find function
  588. -- a string always contains the empty string
  589. local lstr, lsub, subPretty, strPretty
  590. lstr = string.lower(str)
  591. lsub = string.lower(sub)
  592. if string.find(lstr, lsub, 1, true) == nil then
  593. subPretty = prettystr(sub)
  594. strPretty = prettystr(str)
  595. if hasNewLine( subPretty..strPretty ) then
  596. subPretty = '\n'..subPretty..'\n'
  597. strPretty = '\n'..strPretty
  598. end
  599. error( 'Error, substring '..subPretty..' was not found (case insensitively) in string '..strPretty,2)
  600. end
  601. end
  602. function M.assertNotStrContains( str, sub, useRe )
  603. -- this relies on lua string.find function
  604. -- a string always contains the empty string
  605. local substrType
  606. local noUseRe = not useRe
  607. if string.find(str, sub, 1, noUseRe) ~= nil then
  608. local substrType
  609. if noUseRe then
  610. substrType = 'substring'
  611. else
  612. substrType = 'regexp'
  613. end
  614. local subPretty = prettystr(sub)
  615. local strPretty = prettystr(str)
  616. if hasNewLine( subPretty..strPretty ) then
  617. subPretty = '\n'..subPretty..'\n'
  618. strPretty = '\n'..strPretty
  619. end
  620. error( 'Error, '..substrType..' '..subPretty..' was found in string '..strPretty,2)
  621. end
  622. end
  623. function M.assertNotStrIContains( str, sub )
  624. -- this relies on lua string.find function
  625. -- a string always contains the empty string
  626. local lstr, lsub
  627. lstr = string.lower(str)
  628. lsub = string.lower(sub)
  629. if string.find(lstr, lsub, 1, true) ~= nil then
  630. local subPretty = prettystr(sub)
  631. local strPretty = prettystr(str)
  632. if hasNewLine( subPretty..strPretty) then
  633. subPretty = '\n'..subPretty..'\n'
  634. strPretty = '\n'..strPretty
  635. end
  636. error( 'Error, substring '..subPretty..' was found (case insensitively) in string '..strPretty,2)
  637. end
  638. end
  639. function M.assertStrMatches( str, pattern, start, final )
  640. -- Verify a full match for the string
  641. -- for a partial match, simply use assertStrContains with useRe set to true
  642. if not strMatch( str, pattern, start, final ) then
  643. local patternPretty = prettystr(pattern)
  644. local strPretty = prettystr(str)
  645. if hasNewLine( patternPretty..strPretty) then
  646. patternPretty = '\n'..patternPretty..'\n'
  647. strPretty = '\n'..strPretty
  648. end
  649. error( 'Error, pattern '..patternPretty..' was not matched by string '..strPretty,2)
  650. end
  651. end
  652. function M.assertErrorMsgEquals( expectedMsg, func, ... )
  653. -- assert that calling f with the arguments will raise an error
  654. -- example: assertError( f, 1, 2 ) => f(1,2) should generate an error
  655. local no_error, error_msg = pcall( func, ... )
  656. if no_error then
  657. error( 'No error generated when calling function but expected error: "'..expectedMsg..'"', 2 )
  658. end
  659. if not (error_msg == expectedMsg) then
  660. if hasNewLine( error_msg..expectedMsg ) then
  661. expectedMsg = '\n'..expectedMsg
  662. error_msg = '\n'..error_msg
  663. end
  664. error( 'Exact error message expected: "'..expectedMsg..'"\nError message received: "'..error_msg..'"\n',2)
  665. end
  666. end
  667. function M.assertErrorMsgContains( partialMsg, func, ... )
  668. -- assert that calling f with the arguments will raise an error
  669. -- example: assertError( f, 1, 2 ) => f(1,2) should generate an error
  670. local no_error, error_msg = pcall( func, ... )
  671. if no_error then
  672. error( 'No error generated when calling function but expected error containing: '..prettystr(partialMsg), 2 )
  673. end
  674. if not string.find( error_msg, partialMsg, nil, true ) then
  675. local partialMsgStr = prettystr(partialMsg)
  676. local errorMsgStr = prettystr(error_msg)
  677. if hasNewLine(error_msg..partialMsg) then
  678. partialMsgStr = '\n'..partialMsgStr
  679. errorMsgStr = '\n'..errorMsgStr
  680. end
  681. error( 'Error message does not contain: '..partialMsgStr..'\nError message received: '..errorMsgStr..'\n',2)
  682. end
  683. end
  684. function M.assertErrorMsgMatches( expectedMsg, func, ... )
  685. -- assert that calling f with the arguments will raise an error
  686. -- example: assertError( f, 1, 2 ) => f(1,2) should generate an error
  687. local no_error, error_msg = pcall( func, ... )
  688. if no_error then
  689. error( 'No error generated when calling function but expected error matching: "'..expectedMsg..'"', 2 )
  690. end
  691. if not strMatch( error_msg, expectedMsg ) then
  692. if hasNewLine(error_msg..expectedMsg) then
  693. expectedMsg = '\n'..expectedMsg
  694. error_msg = '\n'..error_msg
  695. end
  696. error( 'Error message does not match: "'..expectedMsg..'"\nError message received: "'..error_msg..'"\n',2)
  697. end
  698. end
  699. local function errorMsgTypeMismatch( expectedType, actual )
  700. local actualStr = prettystr(actual)
  701. if hasNewLine(actualStr) then
  702. actualStr = '\n'..actualStr
  703. end
  704. return "Expected: a "..expectedType..' value, actual: type '..type(actual)..', value '..actualStr
  705. end
  706. function M.assertIsNumber(value)
  707. if type(value) ~= 'number' then
  708. error( errorMsgTypeMismatch( 'number', value ), 2 )
  709. end
  710. end
  711. function M.assertIsString(value)
  712. if type(value) ~= "string" then
  713. error( errorMsgTypeMismatch( 'string', value ), 2 )
  714. end
  715. end
  716. function M.assertIsTable(value)
  717. if type(value) ~= 'table' then
  718. error( errorMsgTypeMismatch( 'table', value ), 2 )
  719. end
  720. end
  721. function M.assertIsBoolean(value)
  722. if type(value) ~= 'boolean' then
  723. error( errorMsgTypeMismatch( 'boolean', value ), 2 )
  724. end
  725. end
  726. function M.assertIsNil(value)
  727. if type(value) ~= "nil" then
  728. error( errorMsgTypeMismatch( 'nil', value ), 2 )
  729. end
  730. end
  731. function M.assertIsFunction(value)
  732. if type(value) ~= 'function' then
  733. error( errorMsgTypeMismatch( 'function', value ), 2 )
  734. end
  735. end
  736. function M.assertIsUserdata(value)
  737. if type(value) ~= 'userdata' then
  738. error( errorMsgTypeMismatch( 'userdata', value ), 2 )
  739. end
  740. end
  741. function M.assertIsCoroutine(value)
  742. if type(value) ~= 'thread' then
  743. error( errorMsgTypeMismatch( 'thread', value ), 2 )
  744. end
  745. end
  746. M.assertIsThread = M.assertIsCoroutine
  747. function M.assertIs(actual, expected)
  748. if not M.ORDER_ACTUAL_EXPECTED then
  749. actual, expected = expected, actual
  750. end
  751. if actual ~= expected then
  752. local expectedStr = prettystr(expected)
  753. local actualStr = prettystr(actual)
  754. if hasNewLine(expectedStr..actualStr) then
  755. expectedStr = '\n'..expectedStr..'\n'
  756. actualStr = '\n'..actualStr
  757. else
  758. expectedStr = expectedStr..', '
  759. end
  760. error( 'Expected object and actual object are not the same\nExpected: '..expectedStr..'actual: '..actualStr, 2)
  761. end
  762. end
  763. function M.assertNotIs(actual, expected)
  764. if not M.ORDER_ACTUAL_EXPECTED then
  765. actual, expected = expected, actual
  766. end
  767. if actual == expected then
  768. local expectedStr = prettystr(expected)
  769. if hasNewLine(expectedStr) then
  770. expectedStr = '\n'..expectedStr
  771. end
  772. error( 'Expected object and actual object are the same object: '..expectedStr, 2 )
  773. end
  774. end
  775. function M.assertItemsEquals(actual, expected)
  776. -- checks that the items of table expected
  777. -- are contained in table actual. Warning, this function
  778. -- is at least O(n^2)
  779. if not _is_table_items_equals(actual, expected ) then
  780. local expectedStr = prettystr(expected)
  781. local actualStr = prettystr(actual)
  782. if hasNewLine(expectedStr..actualStr) then
  783. expectedStr = '\n'..expectedStr
  784. actualStr = '\n'..actualStr
  785. end
  786. error( 'Contents of the tables are not identical:\nExpected: '..expectedStr..'\nActual: '..actualStr, 2 )
  787. end
  788. end
  789. M.assert_equals = M.assertEquals
  790. M.assert_not_equals = M.assertNotEquals
  791. M.assert_error = M.assertError
  792. M.assert_true = M.assertTrue
  793. M.assert_false = M.assertFalse
  794. M.assert_is_number = M.assertIsNumber
  795. M.assert_is_string = M.assertIsString
  796. M.assert_is_table = M.assertIsTable
  797. M.assert_is_boolean = M.assertIsBoolean
  798. M.assert_is_nil = M.assertIsNil
  799. M.assert_is_function = M.assertIsFunction
  800. M.assert_is = M.assertIs
  801. M.assert_not_is = M.assertNotIs
  802. if EXPORT_ASSERT_TO_GLOBALS then
  803. assertError = M.assertError
  804. assertTrue = M.assertTrue
  805. assertFalse = M.assertFalse
  806. assertNil = M.assertNil
  807. assertNotNil = M.assertNotNil
  808. assertEquals = M.assertEquals
  809. assertAlmostEquals = M.assertAlmostEquals
  810. assertNotEquals = M.assertNotEquals
  811. assertNotAlmostEquals = M.assertNotAlmostEquals
  812. assertStrContains = M.assertStrContains
  813. assertStrIContains = M.assertStrIContains
  814. assertNotStrContains = M.assertNotStrContains
  815. assertNotStrIContains = M.assertNotStrIContains
  816. assertStrMatches = M.assertStrMatches
  817. assertErrorMsgEquals = M.assertErrorMsgEquals
  818. assertErrorMsgContains = M.assertErrorMsgContains
  819. assertErrorMsgMatches = M.assertErrorMsgMatches
  820. assertIsNumber = M.assertIsNumber
  821. assertIsString = M.assertIsString
  822. assertIsTable = M.assertIsTable
  823. assertIsBoolean = M.assertIsBoolean
  824. assertIsNil = M.assertIsNil
  825. assertIsFunction = M.assertIsFunction
  826. assertIsUserdata = M.assertIsUserdata
  827. assertIsCoroutine = M.assertIsCoroutine
  828. assertIs = M.assertIs
  829. assertNotIs = M.assertNotIs
  830. assertItemsEquals = M.assertItemsEquals
  831. -- aliases
  832. assert_equals = M.assertEquals
  833. assert_not_equals = M.assertNotEquals
  834. assert_error = M.assertError
  835. assert_true = M.assertTrue
  836. assert_false = M.assertFalse
  837. assert_is_number = M.assertIsNumber
  838. assert_is_string = M.assertIsString
  839. assert_is_table = M.assertIsTable
  840. assert_is_boolean = M.assertIsBoolean
  841. assert_is_nil = M.assertIsNil
  842. assert_is_function = M.assertIsFunction
  843. assert_is = M.assertIs
  844. assert_not_is = M.assertNotIs
  845. end
  846. ----------------------------------------------------------------
  847. --
  848. -- Outputters
  849. --
  850. ----------------------------------------------------------------
  851. ----------------------------------------------------------------
  852. -- class TapOutput
  853. ----------------------------------------------------------------
  854. local TapOutput = { -- class
  855. __class__ = 'TapOutput',
  856. runner = nil,
  857. result = nil,
  858. }
  859. local TapOutput_MT = { __index = TapOutput }
  860. -- For a good reference for TAP format, check: http://testanything.org/tap-specification.html
  861. function TapOutput:new()
  862. local t = {}
  863. t.verbosity = M.VERBOSITY_LOW
  864. setmetatable( t, TapOutput_MT )
  865. return t
  866. end
  867. function TapOutput:startSuite()
  868. print("1.."..self.result.testCount)
  869. print('# Started on '..self.result.startDate)
  870. end
  871. function TapOutput:startClass(className)
  872. if className ~= '[TestFunctions]' then
  873. print('# Starting class: '..className)
  874. end
  875. end
  876. function TapOutput:startTest(testName) end
  877. function TapOutput:addFailure( errorMsg, stackTrace )
  878. print(string.format("not ok %d\t%s", self.result.currentTestNumber, self.result.currentNode.testName ))
  879. if self.verbosity > M.VERBOSITY_LOW then
  880. print( prefixString( ' ', errorMsg ) )
  881. end
  882. if self.verbosity > M.VERBOSITY_DEFAULT then
  883. print( prefixString( ' ', stackTrace ) )
  884. end
  885. end
  886. function TapOutput:endTest(testHasFailure)
  887. if not self.result.currentNode:hasFailure() then
  888. print(string.format("ok %d\t%s", self.result.currentTestNumber, self.result.currentNode.testName ))
  889. end
  890. end
  891. function TapOutput:endClass() end
  892. function TapOutput:endSuite()
  893. local t = {}
  894. table.insert(t, string.format('# Ran %d tests in %0.3f seconds, %d successes, %d failures',
  895. self.result.testCount, self.result.duration, self.result.testCount-self.result.failureCount, self.result.failureCount ) )
  896. if self.result.nonSelectedCount > 0 then
  897. table.insert(t, string.format(", %d non selected tests", self.result.nonSelectedCount ) )
  898. end
  899. print( table.concat(t) )
  900. return self.result.failureCount
  901. end
  902. -- class TapOutput end
  903. ----------------------------------------------------------------
  904. -- class JUnitOutput
  905. ----------------------------------------------------------------
  906. -- See directory junitxml for more information about the junit format
  907. local JUnitOutput = { -- class
  908. __class__ = 'JUnitOutput',
  909. runner = nil,
  910. result = nil,
  911. }
  912. local JUnitOutput_MT = { __index = JUnitOutput }
  913. function JUnitOutput:new()
  914. local t = {}
  915. t.testList = {}
  916. t.verbosity = M.VERBOSITY_LOW
  917. t.fd = nil
  918. t.fname = nil
  919. setmetatable( t, JUnitOutput_MT )
  920. return t
  921. end
  922. function JUnitOutput:startSuite()
  923. -- open xml file early to deal with errors
  924. if self.fname == nil then
  925. error('With Junit, an output filename must be supplied with --name!')
  926. end
  927. if string.sub(self.fname,-4) ~= '.xml' then
  928. self.fname = self.fname..'.xml'
  929. end
  930. self.fd = io.open(self.fname, "w")
  931. if self.fd == nil then
  932. error("Could not open file for writing: "..self.fname)
  933. end
  934. print('# XML output to '..self.fname)
  935. print('# Started on '..self.result.startDate)
  936. end
  937. function JUnitOutput:startClass(className)
  938. if className ~= '[TestFunctions]' then
  939. print('# Starting class: '..className)
  940. end
  941. end
  942. function JUnitOutput:startTest(testName)
  943. print('# Starting test: '..testName)
  944. end
  945. function JUnitOutput:addFailure( errorMsg, stackTrace )
  946. print('# Failure: '..errorMsg)
  947. -- print('# '..stackTrace)
  948. end
  949. function JUnitOutput:endTest(testHasFailure)
  950. end
  951. function JUnitOutput:endClass()
  952. end
  953. function JUnitOutput:endSuite()
  954. local t = {}
  955. table.insert(t, string.format('# Ran %d tests in %0.3f seconds, %d successes, %d failures',
  956. self.result.testCount, self.result.duration, self.result.testCount-self.result.failureCount, self.result.failureCount ) )
  957. if self.result.nonSelectedCount > 0 then
  958. table.insert(t, string.format(", %d non selected tests", self.result.nonSelectedCount ) )
  959. end
  960. print( table.concat(t) )
  961. -- XML file writing
  962. self.fd:write('<?xml version="1.0" encoding="UTF-8" ?>\n')
  963. self.fd:write('<testsuites>\n')
  964. self.fd:write(string.format(
  965. ' <testsuite name="LuaUnit" id="00001" package="" hostname="localhost" tests="%d" timestamp="%s" time="%0.3f" errors="0" failures="%d">\n',
  966. self.result.testCount, self.result.startIsodate, self.result.duration, self.result.failureCount ))
  967. self.fd:write(" <properties>\n")
  968. self.fd:write(string.format(' <property name="Lua Version" value="%s"/>\n', _VERSION ) )
  969. self.fd:write(string.format(' <property name="LuaUnit Version" value="%s"/>\n', M.VERSION) )
  970. -- XXX please include system name and version if possible
  971. self.fd:write(" </properties>\n")
  972. for i,node in ipairs(self.result.tests) do
  973. self.fd:write(string.format(' <testcase classname="%s" name="%s" time="%0.3f">\n',
  974. node.className, node.testName, node.duration ) )
  975. if node.status ~= M.NodeStatus.PASS then
  976. self.fd:write(' <failure type="' ..xmlEscape(node.msg) .. '">\n')
  977. self.fd:write(' <![CDATA[' ..xmlCDataEscape(node.stackTrace) .. ']]></failure>\n')
  978. end
  979. self.fd:write(' </testcase>\n')
  980. end
  981. -- Next to lines are Needed to validate junit ANT xsd but really not useful in general:
  982. self.fd:write(' <system-out/>\n')
  983. self.fd:write(' <system-err/>\n')
  984. self.fd:write(' </testsuite>\n')
  985. self.fd:write('</testsuites>\n')
  986. self.fd:close()
  987. return self.result.failureCount
  988. end
  989. -- class TapOutput end
  990. ----------------------------------------------------------------
  991. -- class TextOutput
  992. ----------------------------------------------------------------
  993. --[[
  994. -- Python Non verbose:
  995. For each test: . or F or E
  996. If some failed tests:
  997. ==============
  998. ERROR / FAILURE: TestName (testfile.testclass)
  999. ---------
  1000. Stack trace
  1001. then --------------
  1002. then "Ran x tests in 0.000s"
  1003. then OK or FAILED (failures=1, error=1)
  1004. -- Python Verbose:
  1005. testname (filename.classname) ... ok
  1006. testname (filename.classname) ... FAIL
  1007. testname (filename.classname) ... ERROR
  1008. then --------------
  1009. then "Ran x tests in 0.000s"
  1010. then OK or FAILED (failures=1, error=1)
  1011. -- Ruby:
  1012. Started
  1013. .
  1014. Finished in 0.002695 seconds.
  1015. 1 tests, 2 assertions, 0 failures, 0 errors
  1016. -- Ruby:
  1017. >> ruby tc_simple_number2.rb
  1018. Loaded suite tc_simple_number2
  1019. Started
  1020. F..
  1021. Finished in 0.038617 seconds.
  1022. 1) Failure:
  1023. test_failure(TestSimpleNumber) [tc_simple_number2.rb:16]:
  1024. Adding doesn't work.
  1025. <3> expected but was
  1026. <4>.
  1027. 3 tests, 4 assertions, 1 failures, 0 errors
  1028. -- Java Junit
  1029. .......F.
  1030. Time: 0,003
  1031. There was 1 failure:
  1032. 1) testCapacity(junit.samples.VectorTest)junit.framework.AssertionFailedError
  1033. at junit.samples.VectorTest.testCapacity(VectorTest.java:87)
  1034. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  1035. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  1036. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  1037. FAILURES!!!
  1038. Tests run: 8, Failures: 1, Errors: 0
  1039. -- Maven
  1040. # mvn test
  1041. -------------------------------------------------------
  1042. T E S T S
  1043. -------------------------------------------------------
  1044. Running math.AdditionTest
  1045. Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed:
  1046. 0.03 sec <<< FAILURE!
  1047. Results :
  1048. Failed tests:
  1049. testLireSymbole(math.AdditionTest)
  1050. Tests run: 2, Failures: 1, Errors: 0, Skipped: 0
  1051. -- LuaUnit
  1052. ---- non verbose
  1053. * display . or F or E when running tests
  1054. ---- verbose
  1055. * display test name + ok/fail
  1056. ----
  1057. * blank line
  1058. * number) ERROR or FAILURE: TestName
  1059. Stack trace
  1060. * blank line
  1061. * number) ERROR or FAILURE: TestName
  1062. Stack trace
  1063. then --------------
  1064. then "Ran x tests in 0.000s (%d not selected, %d skipped)"
  1065. then OK or FAILED (failures=1, error=1)
  1066. ]]
  1067. local TextOutput = { __class__ = 'TextOutput' }
  1068. local TextOutput_MT = { -- class
  1069. __index = TextOutput
  1070. }
  1071. function TextOutput:new()
  1072. local t = {}
  1073. t.runner = nil
  1074. t.result = nil
  1075. t.errorList ={}
  1076. t.verbosity = M.VERBOSITY_DEFAULT
  1077. setmetatable( t, TextOutput_MT )
  1078. return t
  1079. end
  1080. function TextOutput:startSuite()
  1081. if self.verbosity > M.VERBOSITY_DEFAULT then
  1082. print( 'Started on '.. self.result.startDate )
  1083. end
  1084. end
  1085. function TextOutput:startClass(className)
  1086. -- display nothing when starting a new class
  1087. end
  1088. function TextOutput:startTest(testName)
  1089. if self.verbosity > M.VERBOSITY_DEFAULT then
  1090. io.stdout:write( " ".. self.result.currentNode.testName.." ... " )
  1091. end
  1092. end
  1093. function TextOutput:addFailure( errorMsg, stackTrace )
  1094. -- nothing
  1095. end
  1096. function TextOutput:endTest(testHasFailure)
  1097. if not testHasFailure then
  1098. if self.verbosity > M.VERBOSITY_DEFAULT then
  1099. io.stdout:write("Ok\n")
  1100. else
  1101. io.stdout:write(".")
  1102. end
  1103. else
  1104. if self.verbosity > M.VERBOSITY_DEFAULT then
  1105. io.stdout:write( 'FAIL\n' )
  1106. print( self.result.currentNode.msg )
  1107. --[[
  1108. -- find out when to do this:
  1109. if self.verbosity > M.VERBOSITY_DEFAULT then
  1110. print( self.result.currentNode.stackTrace )
  1111. end
  1112. ]]
  1113. else
  1114. io.stdout:write("F")
  1115. end
  1116. end
  1117. end
  1118. function TextOutput:endClass()
  1119. -- nothing
  1120. end
  1121. function TextOutput:displayOneFailedTest( index, failure )
  1122. print(index..") "..failure.testName )
  1123. print( failure.msg )
  1124. print( failure.stackTrace )
  1125. print()
  1126. end
  1127. function TextOutput:displayFailedTests()
  1128. if self.result.failureCount == 0 then return end
  1129. print("Failed tests:")
  1130. print("-------------")
  1131. for i,v in ipairs(self.result.failures) do
  1132. self:displayOneFailedTest( i, v )
  1133. end
  1134. end
  1135. function TextOutput:endSuite()
  1136. if self.verbosity > M.VERBOSITY_DEFAULT then
  1137. print("=========================================================")
  1138. else
  1139. print()
  1140. end
  1141. self:displayFailedTests()
  1142. local ignoredString = ""
  1143. print( string.format("Ran %d tests in %0.3f seconds", self.result.testCount, self.result.duration ) )
  1144. if self.result.failureCount == 0 then
  1145. if self.result.nonSelectedCount > 0 then
  1146. ignoredString = string.format('(ignored=%d)', self.result.nonSelectedCount )
  1147. end
  1148. print('OK '.. ignoredString)
  1149. else
  1150. if self.result.nonSelectedCount > 0 then
  1151. ignoredString = ', '..ignoredString
  1152. end
  1153. print(string.format('FAILED (failures=%d%s)', self.result.failureCount, ignoredString ) )
  1154. end
  1155. end
  1156. -- class TextOutput end
  1157. ----------------------------------------------------------------
  1158. -- class NilOutput
  1159. ----------------------------------------------------------------
  1160. local function nopCallable()
  1161. --print(42)
  1162. return nopCallable
  1163. end
  1164. local NilOutput = {
  1165. __class__ = 'NilOuptut',
  1166. }
  1167. local NilOutput_MT = {
  1168. __index = nopCallable,
  1169. }
  1170. function NilOutput:new()
  1171. local t = {}
  1172. t.__class__ = 'NilOutput'
  1173. setmetatable( t, NilOutput_MT )
  1174. return t
  1175. end
  1176. ----------------------------------------------------------------
  1177. --
  1178. -- class LuaUnit
  1179. --
  1180. ----------------------------------------------------------------
  1181. M.LuaUnit = {
  1182. outputType = TextOutput,
  1183. verbosity = M.VERBOSITY_DEFAULT,
  1184. __class__ = 'LuaUnit'
  1185. }
  1186. if EXPORT_ASSERT_TO_GLOBALS then
  1187. LuaUnit = M.LuaUnit
  1188. end
  1189. local LuaUnit_MT = { __index = M.LuaUnit }
  1190. function M.LuaUnit:new()
  1191. local t = {}
  1192. setmetatable( t, LuaUnit_MT )
  1193. return t
  1194. end
  1195. -----------------[[ Utility methods ]]---------------------
  1196. function M.LuaUnit.isFunction(aObject)
  1197. -- return true if aObject is a function
  1198. return 'function' == type(aObject)
  1199. end
  1200. function M.LuaUnit.isClassMethod(aName)
  1201. -- return true if aName contains a class + a method name in the form class:method
  1202. return not not string.find(aName, '.', nil, true )
  1203. end
  1204. function M.LuaUnit.splitClassMethod(someName)
  1205. -- return a pair className, methodName for a name in the form class:method
  1206. -- return nil if not a class + method name
  1207. -- name is class + method
  1208. local hasMethod, methodName, className
  1209. hasMethod = string.find(someName, '.', nil, true )
  1210. if not hasMethod then return nil end
  1211. methodName = string.sub(someName, hasMethod+1)
  1212. className = string.sub(someName,1,hasMethod-1)
  1213. return className, methodName
  1214. end
  1215. function M.LuaUnit.isMethodTestName( s )
  1216. -- return true is the name matches the name of a test method
  1217. -- default rule is that is starts with 'Test' or with 'test'
  1218. if string.sub(s,1,4):lower() == 'test' then
  1219. return true
  1220. end
  1221. return false
  1222. end
  1223. function M.LuaUnit.isTestName( s )
  1224. -- return true is the name matches the name of a test
  1225. -- default rule is that is starts with 'Test' or with 'test'
  1226. if string.sub(s,1,4):lower() == 'test' then
  1227. return true
  1228. end
  1229. return false
  1230. end
  1231. function M.LuaUnit.collectTests()
  1232. -- return a list of all test names in the global namespace
  1233. -- that match LuaUnit.isTestName
  1234. local testNames = {}
  1235. for k, v in pairs(_G) do
  1236. if M.LuaUnit.isTestName( k ) then
  1237. table.insert( testNames , k )
  1238. end
  1239. end
  1240. table.sort( testNames )
  1241. return testNames
  1242. end
  1243. function M.LuaUnit.parseCmdLine( cmdLine )
  1244. -- parse the command line
  1245. -- Supported command line parameters:
  1246. -- --verbose, -v: increase verbosity
  1247. -- --quiet, -q: silence output
  1248. -- --output, -o, + name: select output type
  1249. -- --pattern, -p, + pattern: run test matching pattern, may be repeated
  1250. -- --name, -n, + fname: name of output file for junit, default to stdout
  1251. -- [testnames, ...]: run selected test names
  1252. --
  1253. -- Returns a table with the following fields:
  1254. -- verbosity: nil, M.VERBOSITY_DEFAULT, M.VERBOSITY_QUIET, M.VERBOSITY_VERBOSE
  1255. -- output: nil, 'tap', 'junit', 'text', 'nil'
  1256. -- testNames: nil or a list of test names to run
  1257. -- pattern: nil or a list of patterns
  1258. local result = {}
  1259. local state = nil
  1260. local SET_OUTPUT = 1
  1261. local SET_PATTERN = 2
  1262. local SET_FNAME = 3
  1263. if cmdLine == nil then
  1264. return result
  1265. end
  1266. local function parseOption( option )
  1267. if option == '--help' or option == '-h' then
  1268. result['help'] = true
  1269. return
  1270. end
  1271. if option == '--version' then
  1272. result['version'] = true
  1273. return
  1274. end
  1275. if option == '--verbose' or option == '-v' then
  1276. result['verbosity'] = M.VERBOSITY_VERBOSE
  1277. return
  1278. end
  1279. if option == '--quiet' or option == '-q' then
  1280. result['verbosity'] = M.VERBOSITY_QUIET
  1281. return
  1282. end
  1283. if option == '--output' or option == '-o' then
  1284. state = SET_OUTPUT
  1285. return state
  1286. end
  1287. if option == '--name' or option == '-n' then
  1288. state = SET_FNAME
  1289. return state
  1290. end
  1291. if option == '--pattern' or option == '-p' then
  1292. state = SET_PATTERN
  1293. return state
  1294. end
  1295. error('Unknown option: '..option,3)
  1296. end
  1297. local function setArg( cmdArg, state )
  1298. if state == SET_OUTPUT then
  1299. result['output'] = cmdArg
  1300. return
  1301. end
  1302. if state == SET_FNAME then
  1303. result['fname'] = cmdArg
  1304. return
  1305. end
  1306. if state == SET_PATTERN then
  1307. if result['pattern'] then
  1308. table.insert( result['pattern'], cmdArg )
  1309. else
  1310. result['pattern'] = { cmdArg }
  1311. end
  1312. return
  1313. end
  1314. error('Unknown parse state: '.. state)
  1315. end
  1316. for i, cmdArg in ipairs(cmdLine) do
  1317. if state ~= nil then
  1318. setArg( cmdArg, state, result )
  1319. state = nil
  1320. else
  1321. if cmdArg:sub(1,1) == '-' then
  1322. state = parseOption( cmdArg )
  1323. else
  1324. if result['testNames'] then
  1325. table.insert( result['testNames'], cmdArg )
  1326. else
  1327. result['testNames'] = { cmdArg }
  1328. end
  1329. end
  1330. end
  1331. end
  1332. if result['help'] then
  1333. M.LuaUnit.help()
  1334. end
  1335. if result['version'] then
  1336. M.LuaUnit.version()
  1337. end
  1338. if state ~= nil then
  1339. error('Missing argument after '..cmdLine[ #cmdLine ],2 )
  1340. end
  1341. return result
  1342. end
  1343. function M.LuaUnit.help()
  1344. print(M.USAGE)
  1345. os.exit(0)
  1346. end
  1347. function M.LuaUnit.version()
  1348. print('LuaUnit v'..M.VERSION..' by Philippe Fremy <phil@freehackers.org>')
  1349. os.exit(0)
  1350. end
  1351. function M.LuaUnit.patternInclude( patternFilter, expr )
  1352. -- check if any of patternFilter is contained in expr. If so, return true.
  1353. -- return false if None of the patterns are contained in expr
  1354. -- if patternFilter is nil, return true (no filtering)
  1355. if patternFilter == nil then
  1356. return true
  1357. end
  1358. for i,pattern in ipairs(patternFilter) do
  1359. if string.find(expr, pattern) then
  1360. return true
  1361. end
  1362. end
  1363. return false
  1364. end
  1365. --------------[[ Output methods ]]-------------------------
  1366. local NodeStatus = { -- class
  1367. __class__ = 'NodeStatus',
  1368. }
  1369. M.NodeStatus = NodeStatus
  1370. local NodeStatus_MT = { __index = NodeStatus }
  1371. -- values of status
  1372. NodeStatus.PASS='PASS'
  1373. NodeStatus.FAIL='FAIL'
  1374. function NodeStatus:new( number, testName, className )
  1375. local t = {}
  1376. t.number = number
  1377. t.testName = testName
  1378. t.className = className
  1379. self:pass()
  1380. setmetatable( t, NodeStatus_MT )
  1381. return t
  1382. end
  1383. function NodeStatus:pass()
  1384. self.status = self.PASS
  1385. -- useless but we know it's the field we want to use
  1386. self.msg = nil
  1387. self.stackTrace = nil
  1388. end
  1389. function NodeStatus:fail(msg, stackTrace)
  1390. self.status = self.FAIL
  1391. self.msg = msg
  1392. self.stackTrace = stackTrace
  1393. end
  1394. function NodeStatus:hasFailure()
  1395. -- print('hasFailure: '..prettystr(self))
  1396. return (self.status ~= NodeStatus.PASS)
  1397. end
  1398. function M.LuaUnit:startSuite(testCount, nonSelectedCount)
  1399. self.result = {}
  1400. self.result.failureCount = 0
  1401. self.result.testCount = testCount
  1402. self.result.nonSelectedCount = nonSelectedCount
  1403. self.result.currentTestNumber = 0
  1404. self.result.currentClassName = ""
  1405. self.result.currentNode = nil
  1406. self.result.suiteStarted = true
  1407. self.result.startTime = os.clock()
  1408. self.result.startDate = os.date()
  1409. self.result.startIsodate = os.date('%Y-%m-%dT%H:%M:%S')
  1410. self.result.patternFilter = self.patternFilter
  1411. self.result.tests = {}
  1412. self.result.failures = {}
  1413. self.outputType = self.outputType or TextOutput
  1414. self.output = self.outputType:new()
  1415. self.output.runner = self
  1416. self.output.result = self.result
  1417. self.output.verbosity = self.verbosity
  1418. self.output.fname = self.fname
  1419. self.output:startSuite()
  1420. end
  1421. function M.LuaUnit:startClass( className )
  1422. self.result.currentClassName = className
  1423. self.output:startClass( className )
  1424. end
  1425. function M.LuaUnit:startTest( testName )
  1426. self.result.currentTestNumber = self.result.currentTestNumber + 1
  1427. self.result.currentNode = NodeStatus:new(
  1428. self.result.currentTestNumber,
  1429. testName,
  1430. self.result.currentClassName
  1431. )
  1432. self.result.currentNode.startTime = os.clock()
  1433. table.insert( self.result.tests, self.result.currentNode )
  1434. self.output:startTest( testName )
  1435. end
  1436. function M.LuaUnit:addFailure( errorMsg, stackTrace )
  1437. if self.result.currentNode.status == NodeStatus.PASS then
  1438. self.result.failureCount = self.result.failureCount + 1
  1439. self.result.currentNode:fail( errorMsg, stackTrace )
  1440. table.insert( self.result.failures, self.result.currentNode )
  1441. end
  1442. self.output:addFailure( errorMsg, stackTrace )
  1443. end
  1444. function M.LuaUnit:endTest()
  1445. -- print( 'endTEst() '..prettystr(self.result.currentNode))
  1446. -- print( 'endTEst() '..prettystr(self.result.currentNode:hasFailure()))
  1447. self.result.currentNode.duration = os.clock() - self.result.currentNode.startTime
  1448. self.result.currentNode.startTime = nil
  1449. self.output:endTest( self.result.currentNode:hasFailure() )
  1450. self.result.currentNode = nil
  1451. end
  1452. function M.LuaUnit:endClass()
  1453. self.output:endClass()
  1454. end
  1455. function M.LuaUnit:endSuite()
  1456. if self.result.suiteStarted == false then
  1457. error('LuaUnit:endSuite() -- suite was already ended' )
  1458. end
  1459. self.result.duration = os.clock()-self.result.startTime
  1460. self.result.suiteStarted = false
  1461. self.output:endSuite()
  1462. end
  1463. function M.LuaUnit:setOutputType(outputType)
  1464. -- default to text
  1465. -- tap produces results according to TAP format
  1466. if outputType:upper() == "NIL" then
  1467. self.outputType = NilOutput
  1468. return
  1469. end
  1470. if outputType:upper() == "TAP" then
  1471. self.outputType = TapOutput
  1472. return
  1473. end
  1474. if outputType:upper() == "JUNIT" then
  1475. self.outputType = JUnitOutput
  1476. return
  1477. end
  1478. if outputType:upper() == "TEXT" then
  1479. self.outputType = TextOutput
  1480. return
  1481. end
  1482. error( 'No such format: '..outputType,2)
  1483. end
  1484. function M.LuaUnit:setVerbosity( verbosity )
  1485. self.verbosity = verbosity
  1486. end
  1487. function M.LuaUnit:setFname( fname )
  1488. self.fname = fname
  1489. end
  1490. --------------[[ Runner ]]-----------------
  1491. local SPLITTER = '\n>----------<\n'
  1492. function M.LuaUnit:protectedCall( classInstance , methodInstance, prettyFuncName)
  1493. -- if classInstance is nil, this is just a function call
  1494. -- else, it's method of a class being called.
  1495. local function err_handler(e)
  1496. return debug.traceback(e..SPLITTER, 3)
  1497. end
  1498. local ok, fullErrMsg, stackTrace, errMsg, t
  1499. if classInstance then
  1500. -- stupid Lua < 5.2 does not allow xpcall with arguments so let's use a workaround
  1501. ok, fullErrMsg = xpcall( function () methodInstance(classInstance) end, err_handler )
  1502. else
  1503. ok, fullErrMsg = xpcall( function () methodInstance() end, err_handler )
  1504. end
  1505. if ok then
  1506. return ok
  1507. end
  1508. t = strsplit( SPLITTER, fullErrMsg )
  1509. errMsg = t[1]
  1510. stackTrace = string.sub(t[2],2)
  1511. if prettyFuncName then
  1512. -- we do have the real method name, improve the stack trace
  1513. stackTrace = string.gsub( stackTrace, "in function 'methodInstance'", "in function '"..prettyFuncName.."'")
  1514. -- Needed for Lua 5.3
  1515. stackTrace = string.gsub( stackTrace, "in method 'methodInstance'", "in method '"..prettyFuncName.."'")
  1516. stackTrace = string.gsub( stackTrace, "in upvalue 'methodInstance'", "in method '"..prettyFuncName.."'")
  1517. end
  1518. if STRIP_LUAUNIT_FROM_STACKTRACE then
  1519. stackTrace = stripLuaunitTrace( stackTrace )
  1520. end
  1521. return ok, errMsg, stackTrace
  1522. end
  1523. function M.LuaUnit:execOneFunction(className, methodName, classInstance, methodInstance)
  1524. -- When executing a test function, className and classInstance must be nil
  1525. -- When executing a class method, all parameters must be set
  1526. local ok, errMsg, stackTrace, prettyFuncName
  1527. if type(methodInstance) ~= 'function' then
  1528. error( tostring(methodName)..' must be a function, not '..type(methodInstance))
  1529. end
  1530. if className == nil then
  1531. className = '[TestFunctions]'
  1532. prettyFuncName = methodName
  1533. else
  1534. prettyFuncName = className..'.'..methodName
  1535. end
  1536. if self.lastClassName ~= className then
  1537. if self.lastClassName ~= nil then
  1538. self:endClass()
  1539. end
  1540. self:startClass( className )
  1541. self.lastClassName = className
  1542. end
  1543. self:startTest(prettyFuncName)
  1544. -- run setUp first(if any)
  1545. if classInstance and self.isFunction( classInstance.setUp ) then
  1546. ok, errMsg, stackTrace = self:protectedCall( classInstance, classInstance.setUp, className..'.setUp')
  1547. if not ok then
  1548. self:addFailure( errMsg, stackTrace )
  1549. end
  1550. end
  1551. -- run testMethod()
  1552. if not self.result.currentNode:hasFailure() then
  1553. ok, errMsg, stackTrace = self:protectedCall( classInstance, methodInstance, prettyFuncName)
  1554. if not ok then
  1555. self:addFailure( errMsg, stackTrace )
  1556. end
  1557. end
  1558. -- lastly, run tearDown(if any)
  1559. if classInstance and self.isFunction(classInstance.tearDown) then
  1560. ok, errMsg, stackTrace = self:protectedCall( classInstance, classInstance.tearDown, className..'.tearDown')
  1561. if not ok then
  1562. self:addFailure( errMsg, stackTrace )
  1563. end
  1564. end
  1565. self:endTest()
  1566. end
  1567. function M.LuaUnit.expandOneClass( result, className, classInstance )
  1568. -- add all test methods of classInstance to result
  1569. for methodName, methodInstance in sortedPairs(classInstance) do
  1570. if M.LuaUnit.isFunction(methodInstance) and M.LuaUnit.isMethodTestName( methodName ) then
  1571. table.insert( result, { className..'.'..methodName, classInstance } )
  1572. end
  1573. end
  1574. end
  1575. function M.LuaUnit.expandClasses( listOfNameAndInst )
  1576. -- expand all classes (proveded as {className, classInstance}) to a list of {className.methodName, classInstance}
  1577. -- functions and methods remain untouched
  1578. local result = {}
  1579. for i,v in ipairs( listOfNameAndInst ) do
  1580. local name, instance = v[1], v[2]
  1581. if M.LuaUnit.isFunction(instance) then
  1582. table.insert( result, { name, instance } )
  1583. else
  1584. if type(instance) ~= 'table' then
  1585. error( 'Instance must be a table or a function, not a '..type(instance)..', value '..prettystr(instance))
  1586. end
  1587. if M.LuaUnit.isClassMethod( name ) then
  1588. className, methodName = M.LuaUnit.splitClassMethod( name )
  1589. methodInstance = instance[methodName]
  1590. if methodInstance == nil then
  1591. error( "Could not find method in class "..tostring(className).." for method "..tostring(methodName) )
  1592. end
  1593. table.insert( result, { name, instance } )
  1594. else
  1595. M.LuaUnit.expandOneClass( result, name, instance )
  1596. end
  1597. end
  1598. end
  1599. return result
  1600. end
  1601. function M.LuaUnit.applyPatternFilter( patternFilter, listOfNameAndInst )
  1602. local included = {}
  1603. local excluded = {}
  1604. for i,v in ipairs( listOfNameAndInst ) do
  1605. local name, instance = v[1], v[2]
  1606. if patternFilter and not M.LuaUnit.patternInclude( patternFilter, name ) then
  1607. table.insert( excluded, v )
  1608. else
  1609. table.insert( included, v )
  1610. end
  1611. end
  1612. return included, excluded
  1613. end
  1614. function M.LuaUnit:runSuiteByInstances( listOfNameAndInst )
  1615. -- Run an explicit list of tests. All test instances and names must be supplied.
  1616. -- each test must be one of:
  1617. -- * { function name, function instance }
  1618. -- * { class name, class instance }
  1619. -- * { class.method name, class instance }
  1620. local expandedList, filteredList, filteredOutList, className, methodName, methodInstance
  1621. expandedList = self.expandClasses( listOfNameAndInst )
  1622. filteredList, filteredOutList = self.applyPatternFilter( self.patternFilter, expandedList )
  1623. self:startSuite( #filteredList, #filteredOutList )
  1624. for i,v in ipairs( filteredList ) do
  1625. local name, instance = v[1], v[2]
  1626. if M.LuaUnit.isFunction(instance) then
  1627. self:execOneFunction( nil, name, nil, instance )
  1628. else
  1629. if type(instance) ~= 'table' then
  1630. error( 'Instance must be a table or a function, not a '..type(instance)..', value '..prettystr(instance))
  1631. else
  1632. assert( M.LuaUnit.isClassMethod( name ) )
  1633. className, methodName = M.LuaUnit.splitClassMethod( name )
  1634. methodInstance = instance[methodName]
  1635. if methodInstance == nil then
  1636. error( "Could not find method in class "..tostring(className).." for method "..tostring(methodName) )
  1637. end
  1638. self:execOneFunction( className, methodName, instance, methodInstance )
  1639. end
  1640. end
  1641. end
  1642. if self.lastClassName ~= nil then
  1643. self:endClass()
  1644. end
  1645. self:endSuite()
  1646. end
  1647. function M.LuaUnit:runSuiteByNames( listOfName )
  1648. -- Run an explicit list of test names
  1649. local className, methodName, instanceName, instance, methodInstance
  1650. local listOfNameAndInst = {}
  1651. for i,name in ipairs( listOfName ) do
  1652. if M.LuaUnit.isClassMethod( name ) then
  1653. className, methodName = M.LuaUnit.splitClassMethod( name )
  1654. instanceName = className
  1655. instance = _G[instanceName]
  1656. if instance == nil then
  1657. error( "No such name in global space: "..instanceName )
  1658. end
  1659. if type(instance) ~= 'table' then
  1660. error( 'Instance of '..instanceName..' must be a table, not '..type(instance))
  1661. end
  1662. methodInstance = instance[methodName]
  1663. if methodInstance == nil then
  1664. error( "Could not find method in class "..tostring(className).." for method "..tostring(methodName) )
  1665. end
  1666. else
  1667. -- for functions and classes
  1668. instanceName = name
  1669. instance = _G[instanceName]
  1670. end
  1671. if instance == nil then
  1672. error( "No such name in global space: "..instanceName )
  1673. end
  1674. if (type(instance) ~= 'table' and type(instance) ~= 'function') then
  1675. error( 'Name must match a function or a table: '..instanceName )
  1676. end
  1677. table.insert( listOfNameAndInst, { name, instance } )
  1678. end
  1679. self:runSuiteByInstances( listOfNameAndInst )
  1680. end
  1681. function M.LuaUnit.run(...)
  1682. -- Run some specific test classes.
  1683. -- If no arguments are passed, run the class names specified on the
  1684. -- command line. If no class name is specified on the command line
  1685. -- run all classes whose name starts with 'Test'
  1686. --
  1687. -- If arguments are passed, they must be strings of the class names
  1688. -- that you want to run or generic command line arguments (-o, -p, -v, ...)
  1689. local runner = M.LuaUnit.new()
  1690. return runner:runSuite(...)
  1691. end
  1692. function M.LuaUnit:runSuite( ... )
  1693. local args={...};
  1694. if args[1] ~= nil and type(args[1]) == 'table' and args[1].__class__ == 'LuaUnit' then
  1695. -- run was called with the syntax M.LuaUnit:runSuite()
  1696. -- we support both M.LuaUnit.run() and M.LuaUnit:run()
  1697. -- strip out the first argument
  1698. table.remove(args,1)
  1699. end
  1700. if #args == 0 then
  1701. args = cmdline_argv
  1702. end
  1703. local no_error, error_msg, options, val
  1704. no_error, val = pcall( M.LuaUnit.parseCmdLine, args )
  1705. if not no_error then
  1706. error_msg = val
  1707. print(error_msg)
  1708. print()
  1709. print(M.USAGE)
  1710. os.exit(-1)
  1711. end
  1712. options = val
  1713. if options.verbosity then
  1714. self:setVerbosity( options.verbosity )
  1715. end
  1716. if options.output and options.output:lower() == 'junit' and options.fname == nil then
  1717. print('With junit output, a filename must be supplied with -n or --name')
  1718. os.exit(-1)
  1719. end
  1720. if options.output then
  1721. no_error, val = pcall(self.setOutputType,self,options.output)
  1722. if not no_error then
  1723. error_msg = val
  1724. print(error_msg)
  1725. print()
  1726. print(M.USAGE)
  1727. os.exit(-1)
  1728. end
  1729. end
  1730. if options.fname then
  1731. self:setFname( options.fname )
  1732. end
  1733. if options.pattern then
  1734. self.patternFilter = options.pattern
  1735. end
  1736. local testNames = options['testNames']
  1737. if testNames == nil then
  1738. testNames = M.LuaUnit.collectTests()
  1739. end
  1740. self:runSuiteByNames( testNames )
  1741. return self.result.failureCount
  1742. end
  1743. -- class LuaUnit
  1744. return M