Skip to content

Instantly share code, notes, and snippets.

@lipp
Last active December 10, 2015 22:28
Show Gist options
  • Save lipp/4502382 to your computer and use it in GitHub Desktop.
Save lipp/4502382 to your computer and use it in GitHub Desktop.
busted mockup for async tests with e.g. lua-ev providing: describe,before,before_each,it clone and run locally: lua async_spec.lua; lua sync_spec.lua; lua copas_spec.lua;
package.path = './?.lua;'..package.path
local ev = require'ev'
local loop = ev.Loop.default
require'busted'
describe(
'All async in this context',
function()
before(
async,
function(done)
local count = 0
ev.Timer.new(
function(loop,io)
count = count + 1
print('before',count)
if count == 3 then
print('lets start')
io:stop(loop)
done()
end
end,0.1,0.1):start(loop)
end)
before_each(
async,
function(done)
ev.Timer.new(
function()
print('before_each')
done()
end,0.01):start(loop)
end)
it(
'async test',
async,
function(done)
local timer = ev.Timer.new(
function()
assert.is_truthy(true)
done()
end,0.2)
timer:start(loop)
end)
it(
'async test 2',
async,
function(done)
local timer = ev.Timer.new(
function()
assert.is_truthy(false)
assert.is_truthy(true)
done()
end,0.2)
timer:start(loop)
end)
it(
'should epic fail',
async,
function(done)
does_not_exist.foo = 3
end)
it(
'spies work',
function()
local thing = {
greet = function()
end
}
print('SPY',spy)
for k,v in pairs(spy) do
print(k,v)
end
spy.on(thing, "greet")
thing.greet("Hi!")
assert.spy(thing.greet).was.called()
assert.spy(thing.greet).was.called_with("Hi!")
end)
describe(
'with nested contexts',
function()
before(
async,
function(done)
print('before in nested')
done()
end)
it(
'a nested test',
async,
function(done)
print('NESTED TEST')
local timer = ev.Timer.new(
function()
print('NESTED TEST BAKS')
assert.is_truthy('horst')
assert.is_truthy(true)
assert.is_truthy(true)
done()
end,0.2)
timer:start(loop)
end)
end)
end)
busted.run('ev',loop)
-- busted maock up with async support
require'pl' -- for pretty.write table formating
assert = require'luassert'
spy = require('luassert.spy')
mock = require('luassert.mock')
stub = require('luassert.stub')
local assert_call = getmetatable(assert.is_truthy).__call
local push = table.insert
local root_context = {parents = {}}
local tests = {}
local done = {}
local started = {}
busted = {}
local last_test = 1
local next_test
next_test = function()
if #done < #tests then
if not done[last_test] and not started[last_test] then
local test = tests[last_test]
if test.context then
if test.context.before and not test.context.before_done then
test.context.before(
function()
test.context.before_done = true
next_test()
end)
return
end
if test.context.before_each and test.context.last_before ~= last_test then
test.context.last_before = last_test
test.context.before_each(next_test)
return
end
end
test.status = {
description = test.name,
info = test.info,
trace = ''
}
test.info = nil
local new_env = {}
setmetatable(new_env,{__index = _G})
-- this part is nasty!
-- intercept all calls to luasser states / proxies.
-- uses much of internal knowlage of luassert!!!!
-- the metatable of is_truthy is the same as for other
-- luasserts.
getmetatable(new_env.assert.is_truthy).__call = function(...)
local results = {pcall(assert_call,...)}
local args = {...}
local is_proxy = true
-- ducktype if this is an assertion 'result' and not a proxy
for k,v in pairs(args[1] or {}) do
if k == 'positive_message' or k == 'negative_message' then
is_proxy = false
end
end
if is_proxy then
return unpack(results,2)
else
if results[1] and not test.status.type then
test.status.type = 'success'
elseif not results[1] and test.status.type ~= 'failure' then
test.status.trace = debug.traceback("", 2)
test.status.type = 'failure'
print(test.status.type)
test.status.err = results[2]
end
end
end
-- not sure if this is needed yet...
-- new_env.pcall = function(...)
-- local ok,err = pcall(...)
-- if not ok then
-- test.status.type = 'failure'
-- test.status.err = err
-- end
-- end
setfenv(test.f,new_env)
local done = function()
done[last_test] = true
last_test = last_test + 1
next_test()
end
started[last_test] = true
local ok,err = pcall(test.f,done)
if not ok then
if type(err) == "table" then
err = pretty.write(err)
end
test.status.err = err
done()
end
end
end
end
local current_context = root_context
busted.describe = function(desc,more)
local parents = {}
for i,parent in ipairs(current_context.parents) do
parents[i] = parent
end
push(parents,current_context)
local context = {
desc = desc,
parents = parents
}
current_context = context
more()
end
busted.before = function(sync_before,async_before)
if async_before then
current_context.before = async_before
else
current_context.before = function(done)
sync_before()
done()
end
end
end
busted.before_each = function(sync_before,async_before)
if async_before then
current_context.before_each = async_before
else
current_context.before_each = function(done)
sync_before()
done()
end
end
end
busted.it = function(name,sync_test,async_test)
local test = {}
test.context = current_context
test.name = name
local debug_info
if async_test then
debug_info = debug.getinfo(async_test)
test.f = async_test
else
debug_info = debug.getinfo(sync_test)
-- make sync test run async
test.f = function(done)
setfenv(sync_test,getfenv(1))
sync_test()
done()
end
end
test.info = {
source = debug_info.source,
short_src = debug_info.short_src,
linedefined = debug_info.linedefined,
}
tests[#tests+1] = test
end
local report = function()
for _,test in ipairs(tests) do
print(pretty.write(test.status))
end
end
busted.run = function(type,...)
local args = {...}
if not type then
next_test()
elseif type == 'ev' then
local loop = args[1]
local ev = require'ev'
ev.Timer.new(next_test,0.0001):start(loop)
loop:loop()
elseif type == 'copas' then
local copas = require'copas'
copas.addthread(
function()
repeat
next_test()
copas.step(0)
until #done == #tests
end)
end
for _,test in ipairs(tests) do
if test.status.type ~= 'success' and not test.status.err then
test.status.type = 'failure'
test.status.err = 'No assertions made'
test.status.trace = ''
end
end
report()
end
it = busted.it
describe = busted.describe
before = busted.before
before_each = busted.before_each
return busted
package.path = './?.lua;'..package.path
local copas = require'copas'
local socket = require'socket'
require'busted'
local port = 19281
describe(
'When someone connects to echo server',
function()
before(
async,
function(done)
copas.addserver(
socket.bind('*',port),
function(skt)
print('new client')
while true do
local data = copas.receive(skt)
if not data then
return
end
copas.send(skt,data..'\n')
end
end)
done()
end)
before_each(
async,
function(done)
print('before each async')
done()
end)
it(
'sent messages and maing bad test fails',
async,
function(done)
print('A')
copas.addthread(
function()
local s = socket.connect('localhost',port)
s:settimeout(0)
local client = copas.wrap(s)
local msg = 'HALLO'
client:send(msg..'\n')
client:receive('*l')
s:close()
assert.is_truthy(false)
assert.is_truthy(false)
print('F A')
done()
end)
end)
it(
'sent messages are echoed correctly',
async,
function(done)
print('B')
copas.addthread(
function()
local s = socket.connect('localhost',port)
s:settimeout(0)
local client = copas.wrap(s)
local msg = 'HALLO'
client:send(msg..'\n')
local echoed = client:receive('*l')
s:close()
assert.is_truthy(echoed == msg)
print('F B')
done()
end)
end)
it(
'sent messages are echoed correctly with two clients',
async,
function(done)
local other_finished
copas.addthread(
function()
local s = socket.connect('localhost',port)
s:settimeout(0)
local client = copas.wrap(s)
local msg = 'HALLO'
client:send(msg..'\n')
local echoed = client:receive('*l')
s:close()
assert.is_truthy(echoed == msg)
if other_finished then
done()
else
other_finished = true
end
end)
copas.addthread(
function()
local s = socket.connect('localhost',port)
s:settimeout(0)
local client = copas.wrap(s)
local msg = 'HALLO'
client:send(msg..'\n')
local echoed = client:receive('*l')
s:close()
assert.is_truthy(echoed == msg)
if other_finished then
done()
else
other_finished = true
end
end)
end)
it(
'this is sync though',
function()
print('sync')
assert.is_truthy(true)
assert.is_truthy(true)
assert.is_truthy(true)
end)
describe(
'deeper context',
function()
before_each(
function()
print('before each sync')
end)
it(
'sent messages are echoed correctly two times in a row',
async,
function(done)
print('DEEP')
copas.addthread(
function()
local s = socket.connect('localhost',port)
s:settimeout(0)
local client = copas.wrap(s)
local msg = 'HALLO'
client:send(msg..'\n')
local echoed = client:receive('*l')
assert.is_truthy(echoed == msg)
msg = 'HALLO again'
client:send(msg..'\n')
local echoed = client:receive('*l')
s:close()
assert.is_truthy(echoed == msg)
print('F DEEP')
done()
end)
end)
end)
end)
busted.run('copas')
-- normal / sync test
package.path = './?.lua;'..package.path
require'busted'
it(
'sync test',
function(done)
assert.is_truthy(true)
end)
busted.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment