Skip to content

Instantly share code, notes, and snippets.

@markandgo
Last active December 14, 2015 18:39
Show Gist options
  • Save markandgo/5130894 to your computer and use it in GitHub Desktop.
Save markandgo/5130894 to your computer and use it in GitHub Desktop.
Suspect, a simple unit testing module with support for a custom output handler. Includes bonus/optional asserts.lua
local assert = assert
local tostring = tostring
local pcall = pcall
local FORMAT_ASSERT_EQUALS = 'expected %s to be equal to %s'
local FORMAT_ASSERT_UNEQ = 'all values are %s'
asserteq = function(...)
local values = {...}
local first = values[1]
local i = 2
repeat
if first ~= values[i] then error(FORMAT_ASSERT_EQUALS:format(tostring(first),tostring(values[i]))) end
i=i+1
until not values[i]
end
assertnoteq = function(...)
local values = {...}
local first = values[1]
local i = 2
repeat
if first ~= values[i] then
return
end
i=i+1
until not values[i]
error(FORMAT_ASSERT_UNEQ:format(tostring(first)))
end
asserttruthy = function(v)
assert(v,'value is '..tostring(v))
end
asserttrue = function(v)
assert(v == true,'value is '..tostring(v))
end
assertfalsy = function(v)
assert(not v,'value is '..tostring(v))
end
assertfalse = function(v)
assert(v == false,'value is '..tostring(v))
end
asserterror = function(func)
assert(not pcall(func),'function ran without an error')
end
6 TESTS, 5 PASSED, 1 FAILED
1 P dummy test
2 P previous test contains correct description/passed/errormessage
3 F fail with error message
4 P have an error message from previous test
5 P return a string from getresults
6 P Previous string: 4 TESTS, 3 PASSED, 1 FAILED
TEST 3: fail with error message
.\asserts.lua:12: expected 1 to be equal to 2
stack traceback:
[C]: in function 'error'
.\asserts.lua:12: in function 'asserteq'
test_suspect.lua:14: in function <test_suspect.lua:13>
[C]: in function 'xpcall'
.\suspect.lua:81: in function 'assert'
test_suspect.lua:13: in main chunk
[C]: ?
--[[
USAGE:
suspect.assert(description,func)
suspect.assert('pass',function() t = 1+1 end)
suspect.assert('fail',function() t = nil+1 end)
suspect.clear() // clear all test results
boolean: omitTraceback
string: filename
string: results
results = suspect.getresults(omitTraceback)
suspect.write(filename,omitTraceback)
suspect.print(omitTraceback)
pass (results,...) to custom output handler
--]]
-- specify a different output handler
local OUTPUT_HANDLER = nil
local FORMAT_TITLE = '%s'
local FORMAT_SUMMARY = '%s TESTS, %s PASSED, %s FAILED'
local FORMAT_TEST_RESULT = '%-8s %-5s %s'
local FORMAT_ERROR_MSG = 'TEST %s: %s\n%s'
local DEFAULT_TITLE = 'UNIT TEST'
local insert = table.insert
local concat = table.concat
local gettraceback = function(errormessage)
return errormessage..debug.traceback('',2)
end
-- ==========================
-- OUTPUT HANDLER
-- ==========================
-- string: results.description
-- string: results.errormessage
-- boolean: results.passed
-- ...: optional parameters
local function output(results,...)
local messages = {}
local errors = {}
local passed_counter = 0
local omitTraceback = ...
local total_tests = #results
for i = 1,total_tests do
local passed = results[i].passed
local errormessage = results[i].errormessage
local description = results[i].description
if passed then passed_counter = passed_counter+1 end
insert(messages,FORMAT_TEST_RESULT:format(i,passed and 'P' or 'F',description))
if errormessage and not omitTraceback then insert(errors,FORMAT_ERROR_MSG:format(i,description,errormessage)) end
end
insert(messages,1,FORMAT_SUMMARY:format(total_tests,passed_counter,total_tests-passed_counter))
insert(messages,2,'')
if #errors > 0 then
insert(messages,'')
local errormessages = concat(errors,'\n\n')
insert(messages,errormessages)
end
return concat(messages,'\n')
end
-- ==========================
-- MODULE
-- ==========================
if OUTPUT_HANDLER then output = OUTPUT_HANDLER end
local suspect =
{
tests = {},
}
function suspect.clear()
suspect.tests = {}
end
function suspect.assert(description,func)
local passed,errormessage = xpcall(func,gettraceback)
local test = {}
test.description = description
test.passed = passed
test.errormessage = errormessage
insert(suspect.tests,test)
return passed,errormessage
end
-- pass ... to output handler
function suspect.print(...)
print(suspect.getresults(...))
end
function suspect.getresults(...)
return output(suspect.tests,...)
end
function suspect.write(filename,...)
local file,err = io.open(filename,'w')
assert(file,err)
file:write(suspect.getresults(...))
file:close()
end
return suspect
local suspect = require 'suspect'
require 'asserts'
local s = suspect
s.assert('dummy test',function()
end)
s.assert('previous test contains correct description/passed/errormessage',function()
local test = s.tests[1]
asserteq(test.description,'dummy test')
asserttrue(test.passed)
assertfalsy(test.errormessage)
end)
s.assert('fail with error message',function()
asserteq(1,2)
end)
s.assert('have an error message from previous test',function()
local test = s.tests[3]
asserttruthy(test.errormessage)
assertfalsy(test.passed)
end)
local results
s.assert('return a string from getresults',function()
results = s.getresults()
asserteq(type(results),'string')
end)
s.assert('Previous string: 4 TESTS, 3 PASSED, 1 FAILED',function()
asserttruthy(results:match('4 TESTS, 3 PASSED, 1 FAILED'))
end)
s.print(true)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment