--
--
local loadstring = loadstring or load
local pairs = pairs
local pcall = pcall
local require = require
local tostring = tostring
local type = type
local match = require 'string'.match
local unpack = require 'table'.unpack or unpack
local _G = _G
local tb = require 'Test.Builder'.new()
_ENV = nil
local m = {}
function m.plan (arg)
tb:plan(arg)
end
function m.done_testing (num_tests)
tb:done_testing(num_tests)
end
function m.skip_all (reason)
tb:skip_all(reason)
end
function m.BAIL_OUT (reason)
tb:BAIL_OUT(reason)
end
function m.ok (test, name)
tb:ok(test, name)
end
function m.nok (test, name)
tb:ok(not test, name)
end
function m.is (got, expected, name)
local pass = got == expected
tb:ok(pass, name)
if not pass then
tb:diag(" got: " .. tostring(got)
.. "\n expected: " .. tostring(expected))
end
end
function m.isnt (got, expected, name)
local pass = got ~= expected
tb:ok(pass, name)
if not pass then
tb:diag(" got: " .. tostring(got)
.. "\n expected: anything else")
end
end
function m.like (got, pattern, name)
if type(pattern) ~= 'string' then
tb:ok(false, name)
tb:diag("pattern isn't a string : " .. tostring(pattern))
return
end
got = tostring(got)
local pass = match(got, pattern)
tb:ok(pass, name)
if not pass then
tb:diag(" '" .. got .. "'"
.. "\n doesn't match '" .. pattern .. "'")
end
end
function m.unlike (got, pattern, name)
if type(pattern) ~= 'string' then
tb:ok(false, name)
tb:diag("pattern isn't a string : " .. tostring(pattern))
return
end
got = tostring(got)
local pass = not match(got, pattern)
tb:ok(pass, name)
if not pass then
tb:diag(" '" .. got .. "'"
.. "\n matches '" .. pattern .. "'")
end
end
local cmp = {
['<'] = function (a, b) return a < b end,
['<='] = function (a, b) return a <= b end,
['>'] = function (a, b) return a > b end,
['>='] = function (a, b) return a >= b end,
['=='] = function (a, b) return a == b end,
['~='] = function (a, b) return a ~= b end,
}
function m.cmp_ok (this, op, that, name)
local f = cmp[op]
if not f then
tb:ok(false, name)
tb:diag("unknown operator : " .. tostring(op))
return
end
local pass = f(this, that)
tb:ok(pass, name)
if not pass then
tb:diag(" " .. tostring(this)
.. "\n " .. op
.. "\n " .. tostring(that))
end
end
function m.type_ok (val, t, name)
if type(t) ~= 'string' then
tb:ok(false, name)
tb:diag("type isn't a string : " .. tostring(t))
return
end
if type(val) == t then
tb:ok(true, name)
else
tb:ok(false, name)
tb:diag(" " .. tostring(val) .. " isn't a '" .. t .."' it's a '" .. type(val) .. "'")
end
end
function m.subtest (name, func)
tb:subtest(name, func)
end
function m.pass (name)
tb:ok(true, name)
end
function m.fail (name)
tb:ok(false, name)
end
function m.require_ok (mod)
local r, msg = pcall(require, mod)
tb:ok(r, "require '" .. tostring(mod) .. "'")
if not r then
tb:diag(" " .. msg)
end
return r
end
function m.eq_array (got, expected, name)
if type(got) ~= 'table' then
tb:ok(false, name)
tb:diag("got value isn't a table : " .. tostring(got))
return
elseif type(expected) ~= 'table' then
tb:ok(false, name)
tb:diag("expected value isn't a table : " .. tostring(expected))
return
end
for i = 1, #expected do
local v = expected[i]
local val = got[i]
if val ~= v then
tb:ok(false, name)
tb:diag(" at index: " .. tostring(i)
.. "\n got: " .. tostring(val)
.. "\n expected: " .. tostring(v))
return
end
end
local extra = #got - #expected
if extra ~= 0 then
tb:ok(false, name)
tb:diag(" " .. tostring(extra) .. " unexpected item(s)")
else
tb:ok(true, name)
end
end
function m.is_deeply (got, expected, name)
if type(got) ~= 'table' then
tb:ok(false, name)
tb:diag("got value isn't a table : " .. tostring(got))
return
elseif type(expected) ~= 'table' then
tb:ok(false, name)
tb:diag("expected value isn't a table : " .. tostring(expected))
return
end
local msg1
local msg2
local seen = {}
local function deep_eq (t1, t2, key_path)
if t1 == t2 or seen[t1] then
return true
end
seen[t1] = true
for k, v2 in pairs(t2) do
local v1 = t1[k]
if type(v1) == 'table' and type(v2) == 'table' then
local r = deep_eq(v1, v2, key_path .. "." .. tostring(k))
if not r then
return false
end
else
if v1 ~= v2 then
key_path = key_path .. "." .. tostring(k)
msg1 = " got" .. key_path .. ": " .. tostring(v1)
msg2 = "expected" .. key_path .. ": " .. tostring(v2)
return false
end
end
end
for k in pairs(t1) do
local v2 = t2[k]
if v2 == nil then
key_path = key_path .. "." .. tostring(k)
msg1 = " got" .. key_path .. ": " .. tostring(t1[k])
msg2 = "expected" .. key_path .. ": " .. tostring(v2)
return false
end
end
return true
end -- deep_eq
local pass = deep_eq(got, expected, '')
tb:ok(pass, name)
if not pass then
tb:diag(" Tables begin differing at:")
tb:diag(" " .. msg1)
tb:diag(" " .. msg2)
end
end
local function compile(code, name)
local msg
code, msg = loadstring(code)
if not code then
tb:ok(false, name, 1)
tb:diag(" can't compile code :"
.. "\n " .. msg)
end
return code
end
function m.error_is (code, arg2, arg3, arg4)
local params, expected, name
if type(arg2) == 'table' then
params = arg2
expected = arg3
name = arg4
else
params = {}
expected = arg2
name = arg3
end
if type(code) == 'string' then
code = compile(code, name)
if not code then
return
end
end
local r, msg = pcall(code, unpack(params))
if r then
tb:ok(false, name)
tb:diag(" unexpected success"
.. "\n expected: " .. tostring(expected))
else
msg = tostring(msg)
expected = tostring(expected)
local pass = msg == expected
tb:ok(pass, name)
if not pass then
tb:diag(" got: " .. msg
.. "\n expected: " .. expected)
end
end
end
function m.error_like (code, arg2, arg3, arg4)
local params, pattern, name
if type(arg2) == 'table' then
params = arg2
pattern = arg3
name = arg4
else
params = {}
pattern = arg2
name = arg3
end
if type(code) == 'string' then
code = compile(code, name)
if not code then
return
end
end
local r, msg = pcall(code, unpack(params))
if r then
tb:ok(false, name)
tb:diag(" unexpected success"
.. "\n expected: " .. tostring(pattern))
else
if type(pattern) ~= 'string' then
tb:ok(false, name)
tb:diag("pattern isn't a string : " .. tostring(pattern))
return
end
msg = tostring(msg)
local pass = match(msg, pattern)
tb:ok(pass, name)
if not pass then
tb:diag(" '" .. msg .. "'"
.. "\n doesn't match '" .. pattern .. "'")
end
end
end
function m.lives_ok (code, arg2, arg3)
local params, name
if type(arg2) == 'table' then
params = arg2
name = arg3
else
params = {}
name = arg2
end
if type(code) == 'string' then
code = compile(code, name)
if not code then
return
end
end
local r, msg = pcall(code, unpack(params))
tb:ok(r, name)
if not r then
tb:diag(" " .. msg)
end
end
function m.diag (msg)
tb:diag(msg)
end
function m.note (msg)
tb:note(msg)
end
function m.skip (reason, count)
count = count or 1
for _ = 1, count do
tb:skip(reason)
end
end
function m.todo_skip (reason, count)
count = count or 1
for _ = 1, count do
tb:todo_skip(reason)
end
end
function m.skip_rest (reason)
tb:skip_rest(reason)
end
function m.todo (reason, count)
tb:todo(reason, count)
end
for k, v in pairs(m) do -- injection
_G[k] = v
end
m._VERSION = "0.3.2"
m._DESCRIPTION = "lua-TestMore : an Unit Testing Framework"
m._COPYRIGHT = "Copyright (c) 2009-2015 Francois Perrad"
return m
--
-- This library is licensed under the terms of the MIT/X11 license,
-- like Lua itself.
--