Skip to content

Commit

Permalink
Merge pull request #300 from o-lim/master
Browse files Browse the repository at this point in the history
Fix some issues and add some improvements
  • Loading branch information
DorianGray committed Dec 17, 2014
2 parents f30467f + 9e65c3f commit 2f01762
Show file tree
Hide file tree
Showing 24 changed files with 866 additions and 179 deletions.
82 changes: 53 additions & 29 deletions bin/busted
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ require 'busted.init'(busted)
local defaultOutput = path.is_windows and 'plainTerminal' or 'utfTerminal'
local defaultLoaders = 'lua,moonscript'
local defaultPattern = '_spec'
local defaultSeed = tostring(os.time())
local lpathprefix = './src/?.lua;./src/?/?.lua;./src/?/init.lua'
local cpathprefix = path.is_windows and './csrc/?.dll;./csrc/?/?.dll;' or './csrc/?.so;./csrc/?/?.so;'

Expand All @@ -35,14 +36,15 @@ cli:add_option('--exclude-tags=TAGS', 'do not run tests with these #tags, takes
cli:add_option('-m, --lpath=PATH', 'optional path to be prefixed to the Lua module search path', lpathprefix)
cli:add_option('--cpath=PATH', 'optional path to be prefixed to the Lua C module search path', cpathprefix)
cli:add_option('-r, --run=RUN', 'config to run from .busted file')
cli:add_option('--seed=SEED', 'random seed value to use for randomizing test order', defaultSeed)
cli:add_option('--lang=LANG', 'language for error messages', 'en')
cli:add_option('--loaders=NAME', 'test file loaders', defaultLoaders)
cli:add_option('--helper=PATH', 'A helper script that is run before tests')

cli:add_flag('-c, --coverage', 'do code coverage analysis (requires `LuaCov` to be installed)')

cli:add_flag('-v, --verbose', 'verbose output of errors')
cli:add_flag('-s, --enable-sound', 'executes `say` command if available')
cli:add_flag('--randomize', 'force randomized test order')
cli:add_flag('--suppress-pending', 'suppress `pending` test output')
cli:add_flag('--defer-print', 'defer print to when test suite is complete')

Expand Down Expand Up @@ -79,8 +81,6 @@ end
-- Load test directory
local rootFile = path.normpath(path.join(fpath, cliArgs.ROOT))

local pattern = cliArgs.pattern

local tags = {}
local excludeTags = {}

Expand Down Expand Up @@ -134,6 +134,38 @@ for _, excluded in pairs(excludeTags) do
end
end

-- watch for test errors
local failures = 0
local errors = 0

busted.subscribe({ 'error' }, function(element, parent, status)
if element.descriptor == 'output' then
print('Cannot load output library: ' .. element.name)
end
errors = errors + 1
return nil, true
end)

busted.subscribe({ 'failure' }, function(element, parent, status)
if element.descriptor == 'it' then
failures = failures + 1
else
errors = errors + 1
end
return nil, true
end)

-- Set up randomization options
busted.randomize = cliArgs.randomize
local randomseed = tonumber(cliArgs.seed)
if randomseed then
busted.randomseed = randomseed
else
print('Argument to --seed must be a number')
busted.randomseed = defaultSeed
errors = errors + 1
end

-- Set up output handler to listen to events
local outputHandlerOptions = {
verbose = cliArgs.verbose,
Expand All @@ -142,32 +174,32 @@ local outputHandlerOptions = {
deferPrint = cliArgs['defer-print']
}

local outputHandler = outputHandlerLoader(cliArgs.output, cliArgs.o, outputHandlerOptions, busted)
local outputHandler = outputHandlerLoader(cliArgs.output, cliArgs.o, outputHandlerOptions, busted, defaultOutput)
outputHandler:subscribe(outputHandlerOptions)

if cliArgs.s then
require 'busted.outputHandlers.sound'(outputHandlerOptions, busted)
end

local checkTag = function(name, tag, modifier)
local hasTag = function(name, tag)
local found = name:find('#' .. tag)
return (modifier == (found ~= nil))
return (found ~= nil)
end

local checkTags = function(name)
for i, tag in pairs(tags) do
if not checkTag(name, tag, true) then
for i, tag in pairs(excludeTags) do
if hasTag(name, tag) then
return nil, false
end
end

for i, tag in pairs(excludeTags) do
if not checkTag(name, tag, false) then
return nil, false
for i, tag in pairs(tags) do
if hasTag(name, tag) then
return nil, true
end
end

return nil, true
return nil, (#tags == 0)
end

if cliArgs.t ~= '' or cliArgs['exclude-tags'] ~= '' then
Expand All @@ -176,31 +208,23 @@ if cliArgs.t ~= '' or cliArgs['exclude-tags'] ~= '' then
busted.subscribe({ 'register', 'pending' }, checkTags, { priority = 1 })
end

local pattern = cliArgs.pattern
local testFileLoader = require 'busted.modules.test_file_loader'(busted, loaders)
testFileLoader(rootFile, pattern)

-- watch for test errors
local failures = 0
local errors = 0

busted.subscribe({ 'error' }, function(...)
local fileList = testFileLoader(rootFile, pattern)
if #fileList == 0 then
print('No test files found matching Lua pattern: ' .. pattern)
errors = errors + 1
return nil, true
end)

busted.subscribe({ 'test', 'end' }, function(element, parent, status)
if status == 'failure' then
failures = failures + 1
end
return nil, true
end)
end

busted.publish({ 'suite', 'start' })
busted.execute()
busted.publish({ 'suite', 'end' })

local exit = 0
if failures > 0 or errors > 0 then
exit = 1
exit = failures + errors
if exit > 255 then
exit = 255
end
end
os.exit(exit)
1 change: 1 addition & 0 deletions busted-2.0.rc3-0.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ build = {
['busted.environment'] = 'busted/environment.lua',
['busted.compatibility'] = 'busted/compatibility.lua',
['busted.done'] = 'busted/done.lua',
['busted.status'] = 'busted/status.lua',
['busted.init'] = 'busted/init.lua',

['busted.modules.configuration_loader'] = 'busted/modules/configuration_loader.lua',
Expand Down
13 changes: 13 additions & 0 deletions busted/compatibility.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
return {
getfenv = getfenv or function(f)
f = (type(f) == 'function' and f or debug.getinfo(f + 1, 'f').func)
local name, value
local up = 0

repeat
up = up + 1
name, value = debug.getupvalue(f, up)
until name == '_ENV' or name == nil

return (name and value or _G)
end,

setfenv = setfenv or function(f, t)
f = (type(f) == 'function' and f or debug.getinfo(f + 1, 'f').func)
local name
Expand Down
81 changes: 73 additions & 8 deletions busted/core.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
local metatype = function(obj)
local otype = type(obj)
if otype == 'table' then
local mt = getmetatable(obj)
if mt and mt.__type then
return mt.__type
end
end
return otype
end

local failureMt = {
__index = {},
__tostring = function(e) return e.message end,
__type = 'failure'
}

local pendingMt = {
__index = {},
__tostring = function(p) return p.message end,
__type = 'pending'
}

local getfenv = require 'busted.compatibility'.getfenv
local setfenv = require 'busted.compatibility'.setfenv
local throw = error

return function()
local mediator = require 'mediator'()

Expand All @@ -12,10 +39,18 @@ return function()
busted.executors = {}
local executors = {}

busted.status = require 'busted.status'

busted.getTrace = function(element, level, msg)
level = level or 3

local info = debug.getinfo(level, 'Sl')
while info.what == 'C' or info.short_src:match('luassert[/\\].*%.lua$') or
info.short_src:match('busted[/\\].*%.lua$') do
level = level + 1
info = debug.getinfo(level, 'Sl')
end

info.traceback = debug.traceback('', level)
info.message = msg

Expand Down Expand Up @@ -64,23 +99,50 @@ return function()
return parent
end

function busted.safe(descriptor, run, element, setenv)
if setenv and (type(run) == 'function' or getmetatable(run).__call) then
function busted.fail(msg, level)
local _, emsg = pcall(error, msg, level+2)
local e = { message = emsg }
setmetatable(e, failureMt)
throw(e, level+1)
end

function busted.pending(msg)
local p = { message = msg }
setmetatable(p, pendingMt)
throw(p)
end

function busted.replaceErrorWithFail(callable)
local env = {}
local f = getmetatable(callable).__call or callable
setmetatable(env, { __index = getfenv(f) })
env.error = busted.fail
setfenv(f, env)
end

function busted.wrapEnv(callable)
if (type(callable) == 'function' or getmetatable(callable).__call) then
-- prioritize __call if it exists, like in files
environment.wrap(getmetatable(run).__call or run)
environment.wrap(getmetatable(callable).__call or callable)
end
end

function busted.safe(descriptor, run, element)
busted.context.push(element)
local trace, message
local status = 'success'

local ret = { xpcall(run, function(msg)
message = busted.rewriteMessage(element, msg)
local errType = metatype(msg)
status = (errType == 'string' and 'error' or errType)
message = busted.rewriteMessage(element, tostring(msg))
trace = busted.getTrace(element, 3, msg)
end) }

if not ret[1] then
busted.publish({ 'error', descriptor }, element, busted.context.parent(element), message, trace)
busted.publish({ status, descriptor }, element, busted.context.parent(element), message, trace)
end
ret[1] = busted.status(status)

busted.context.pop()
return unpack(ret)
Expand All @@ -97,15 +159,18 @@ return function()

local trace

if descriptor ~= 'file' then
trace = busted.getTrace(busted.context.get(), 3, name)
local ctx = busted.context.get()
if busted.context.parent(ctx) then
trace = busted.getTrace(ctx, 3, name)
end

busted.publish({ 'register', descriptor }, name, fn, trace)
end

busted.executors[descriptor] = publisher
environment.set(descriptor, publisher)
if descriptor ~= 'file' then
environment.set(descriptor, publisher)
end

busted.subscribe({ 'register', descriptor }, function(name, fn, trace)
local ctx = busted.context.get()
Expand Down
Loading

0 comments on commit 2f01762

Please sign in to comment.