123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- local moduleName = ... or 'mispec'
- local M = {}
- _G[moduleName] = M
- -- Helpers:
- function ok(expression, desc)
- if expression == nil then expression = false end
- desc = desc or 'expression is not ok'
- if not expression then
- error(desc .. '\n' .. debug.traceback())
- end
- end
- function ko(expression, desc)
- if expression == nil then expression = false end
- desc = desc or 'expression is not ko'
- if expression then
- error(desc .. '\n' .. debug.traceback())
- end
- end
- function eq(a, b)
- if type(a) ~= type(b) then
- error('type ' .. type(a) .. ' is not equal to ' .. type(b) .. '\n' .. debug.traceback())
- end
- if type(a) == 'function' then
- return string.dump(a) == string.dump(b)
- end
- if a == b then return true end
- if type(a) ~= 'table' then
- error(string.format("%q",tostring(a)) .. ' is not equal to ' .. string.format("%q",tostring(b)) .. '\n' .. debug.traceback())
- end
- for k,v in pairs(a) do
- if b[k] == nil or not eq(v, b[k]) then return false end
- end
- for k,v in pairs(b) do
- if a[k] == nil or not eq(v, a[k]) then return false end
- end
- return true
- end
- function failwith(message, func, ...)
- local status, err = pcall(func, ...)
- if status then
- local messagePart = ""
- if message then
- messagePart = " containing \"" .. message .. "\""
- end
- error("Error expected" .. messagePart .. '\n' .. debug.traceback())
- end
- if (message and not string.find(err, message)) then
- error("expected errormessage \"" .. err .. "\" to contain \"" .. message .. "\"" .. '\n' .. debug.traceback() )
- end
- return true
- end
- function fail(func, ...)
- return failwith(nil, func, ...)
- end
- local function eventuallyImpl(func, retries, delayMs)
- local prevEventually = _G.eventually
- _G.eventually = function() error("Cannot nest eventually/andThen.") end
- local status, err = pcall(func)
- _G.eventually = prevEventually
- if status then
- M.queuedEventuallyCount = M.queuedEventuallyCount - 1
- M.runNextPending()
- else
- if retries > 0 then
- local t = tmr.create()
- t:register(delayMs, tmr.ALARM_SINGLE, M.runNextPending)
- t:start()
- table.insert(M.pending, 1, function() eventuallyImpl(func, retries - 1, delayMs) end)
- else
- M.failed = M.failed + 1
- print("\n ! it failed:", err)
- -- remove all pending eventuallies as spec has failed at this point
- for i = 1, M.queuedEventuallyCount - 1 do
- table.remove(M.pending, 1)
- end
- M.queuedEventuallyCount = 0
- M.runNextPending()
- end
- end
- end
- function eventually(func, retries, delayMs)
- retries = retries or 10
- delayMs = delayMs or 300
- M.queuedEventuallyCount = M.queuedEventuallyCount + 1
- table.insert(M.pending, M.queuedEventuallyCount, function()
- eventuallyImpl(func, retries, delayMs)
- end)
- end
- function andThen(func)
- eventually(func, 0, 0)
- end
- function describe(name, itshoulds)
- M.name = name
- M.itshoulds = itshoulds
- end
- -- Module:
- M.runNextPending = function()
- local next = table.remove(M.pending, 1)
- if next then
- node.task.post(next)
- next = nil
- else
- M.succeeded = M.total - M.failed
- local elapsedSeconds = (tmr.now() - M.startTime) / 1000 / 1000
- print(string.format(
- '\n\nCompleted in %d seconds; %d failed out of %d.',
- elapsedSeconds, M.failed, M.total))
- M.pending = nil
- M.queuedEventuallyCount = nil
- end
- end
- M.run = function()
- M.pending = {}
- M.queuedEventuallyCount = 0
- M.startTime = tmr.now()
- M.total = 0
- M.failed = 0
- local it = {}
- it.should = function(_, desc, func)
- table.insert(M.pending, function()
- print('\n * ' .. desc)
- M.total = M.total + 1
- if M.pre then M.pre() end
- local status, err = pcall(func)
- if not status then
- print("\n ! it failed:", err)
- M.failed = M.failed + 1
- end
- if M.post then M.post() end
- M.runNextPending()
- end)
- end
- it.initialize = function(_, pre) M.pre = pre end;
- it.cleanup = function(_, post) M.post = post end;
- M.itshoulds(it)
- print('' .. M.name .. ', it should:')
- M.runNextPending()
- M.itshoulds = nil
- M.name = nil
- end
- print ("loaded mispec")
|