diff --git a/.travis.yml b/.travis.yml index c2125f70..7891c871 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ before_install: - luarocks install moonscript install: - - luarocks make busted-scm-0.rockspec + - luarocks make script: busted diff --git a/README.md b/README.md index 232978e6..cc932118 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Busted +busted ====== [![Join the chat at https://gitter.im/Olivine-Labs/busted](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Olivine-Labs/busted?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) diff --git a/busted-scm-0.rockspec b/busted-scm-1.rockspec similarity index 92% rename from busted-scm-0.rockspec rename to busted-scm-1.rockspec index 3fda00d7..6aefb184 100644 --- a/busted-scm-0.rockspec +++ b/busted-scm-1.rockspec @@ -1,5 +1,5 @@ package = 'busted' -version = 'scm-0' +version = 'scm-1' source = { url = "git://github.com/Olivine-Labs/busted", branch = "master" @@ -19,15 +19,15 @@ description = { } dependencies = { 'lua >= 5.1', - 'lua_cliargs = 3.0-1', + 'lua_cliargs = 3.0', 'luafilesystem >= 1.5.0', - 'luasystem >= 0.2.0-0', + 'luasystem >= 0.2.0', 'dkjson >= 2.1.0', - 'say >= 1.3-0', - 'luassert >= 1.7.8-0', - 'lua-term >= 0.1-1', - 'penlight >= 1.3.2-2', - 'mediator_lua >= 1.1.1-0', + 'say >= 1.3', + 'luassert >= 1.7.8', + 'lua-term >= 0.1', + 'penlight >= 1.3.2', + 'mediator_lua >= 1.1.1', } build = { @@ -49,6 +49,7 @@ build = { ['busted.modules.configuration_loader'] = 'busted/modules/configuration_loader.lua', ['busted.modules.luacov'] = 'busted/modules/luacov.lua', + ['busted.modules.standalone_loader'] = 'busted/modules/standalone_loader.lua', ['busted.modules.test_file_loader'] = 'busted/modules/test_file_loader.lua', ['busted.modules.output_handler_loader'] = 'busted/modules/output_handler_loader.lua', ['busted.modules.helper_loader'] = 'busted/modules/helper_loader.lua', @@ -79,6 +80,7 @@ build = { ['busted.languages.th'] = 'busted/languages/th.lua', ['busted.languages.ua'] = 'busted/languages/ua.lua', ['busted.languages.zh'] = 'busted/languages/zh.lua', + ['busted.languages.it'] = 'busted/languages/it.lua', }, install = { bin = { diff --git a/busted/block.lua b/busted/block.lua index 4eca1d91..8ecc98ae 100644 --- a/busted/block.lua +++ b/busted/block.lua @@ -144,11 +144,11 @@ return function(busted) end if busted.safe(descriptor, element.run, element):success() then - if randomize then + if busted.sort then + sort(busted.context.children(element)) + elseif randomize then element.randomseed = randomseed shuffle(busted.context.children(element), randomseed) - elseif busted.sort then - sort(busted.context.children(element)) end if block.setup(element) then diff --git a/busted/compatibility.lua b/busted/compatibility.lua index d8816a9a..39371ea6 100644 --- a/busted/compatibility.lua +++ b/busted/compatibility.lua @@ -33,8 +33,8 @@ return { loadstring = loadstring or load, unpack = table.unpack or unpack, - exit = function(code) - if code ~= 0 and _VERSION:match('^Lua 5%.[12]$') then + exit = function(code, force) + if not force and code ~= 0 and _VERSION:match('^Lua 5%.[12]$') then error() elseif code ~= 0 then code = 1 diff --git a/busted/core.lua b/busted/core.lua index 88408344..1983866f 100644 --- a/busted/core.lua +++ b/busted/core.lua @@ -45,7 +45,7 @@ return function() local mediator = require 'mediator'() local busted = {} - busted.version = '2.0.rc12-0' + busted.version = '2.0.0-0' local root = require 'busted.context'() busted.context = root.ref() diff --git a/busted/execute.lua b/busted/execute.lua index f940cf06..8e0eea8c 100644 --- a/busted/execute.lua +++ b/busted/execute.lua @@ -45,11 +45,11 @@ return function(busted) busted.safe_publish('suite', { 'suite', 'reset' }, root, i, runs) end - if options.shuffle then + if options.sort then + sort(busted.context.children(root)) + elseif options.shuffle then root.randomseed = busted.randomseed shuffle(busted.context.children(root), busted.randomseed) - elseif options.sort then - sort(busted.context.children(root)) end local seed = (busted.randomize and busted.randomseed or nil) diff --git a/busted/languages/en.lua b/busted/languages/en.lua index 285d1ba1..dcfb4cce 100644 --- a/busted/languages/en.lua +++ b/busted/languages/en.lua @@ -26,6 +26,7 @@ s:set('output.success_single', 'success') s:set('output.seconds', 'seconds') s:set('output.no_test_files_match', 'No test files found matching Lua pattern: %s') +s:set('output.file_not_found', 'Cannot find file or directory: %s') -- definitions following are not used within the 'say' namespace return { diff --git a/busted/languages/it.lua b/busted/languages/it.lua new file mode 100644 index 00000000..a073bfe3 --- /dev/null +++ b/busted/languages/it.lua @@ -0,0 +1,50 @@ +local s = require('say') + +s:set_namespace('it') + +-- 'Pending: test.lua @ 12 \n description +s:set('output.pending', 'In attesa') +s:set('output.failure', 'Fallimento') +s:set('output.error', 'Errore') +s:set('output.success', 'Successo') + +s:set('output.pending_plural', 'in attesa') +s:set('output.failure_plural', 'fallimenti') +s:set('output.error_plural', 'errori') +s:set('output.success_plural', 'successi') + +s:set('output.pending_zero', 'in attesa') +s:set('output.failure_zero', 'fallimenti') +s:set('output.error_zero', 'errori') +s:set('output.success_zero', 'successi') + +s:set('output.pending_single', 'in attesa') +s:set('output.failure_single', 'fallimento') +s:set('output.error_single', 'errore') +s:set('output.success_single', 'successo') + +s:set('output.seconds', 'secondi') + +s:set('output.no_test_files_match', 'Nessun file di test trovat che corrisponde al pattern Lua: %s') +s:set('output.file_not_found', 'Nessun file o cartella trovato: %s') + +-- definitions following are not used within the 'say' namespace +return { + failure_messages = { + "Hai %d specifiche non conformi", + "Le tue specifiche non sono conformi", + "Il tuo codice fa schifo e dovresti sentirti male per questo", + "Il tuo codice è in pericolo", + "Strano. Il solo modo per terminare con successo i tuoi test è fare nessun test", + "Mia nonna ha scritto migliori specifiche su un 3 86", + "Ogni volta che trovi un errore, bevi un'altra birra", + "I fallimenti fanno male alla salute" + }, + success_messages = { + "Ma andiamo! Specifiche Ok!", + "Non importa, avevi le specifiche", + "Bella zio", + "Gran successo", + "Test passato, hai vinto una birra" + } +} diff --git a/busted/modules/cli.lua b/busted/modules/cli.lua index e2b4cfc8..dba2938f 100644 --- a/busted/modules/cli.lua +++ b/busted/modules/cli.lua @@ -12,7 +12,7 @@ return function(options) local configLoader = require 'busted.modules.configuration_loader'() -- Default cli arg values - local defaultOutput = options.defaultOutput + local defaultOutput = options.output or 'utfTerminal' local defaultLoaders = 'lua,moonscript' local defaultPattern = '_spec' local defaultSeed = '/dev/urandom or os.time()' @@ -124,7 +124,7 @@ return function(options) cli:option('-e STATEMENT', 'execute statement STATEMENT', nil, processMultiOption) cli:option('-o, --output=LIBRARY', 'output library to load', defaultOutput, processOption) cli:option('-C, --directory=DIR', 'change to directory DIR before running tests. If multiple options are specified, each is interpreted relative to the previous one.', './', processDir) - cli:option('-f, --config-file=FILE', 'load configuration options from FILE', nil, processOptions) + cli:option('-f, --config-file=FILE', 'load configuration options from FILE', nil, processOption) cli:option('-t, --tags=TAGS', 'only run tests with these #tags', {}, processList) cli:option('--exclude-tags=TAGS', 'do not run tests with these #tags, takes precedence over --tags', {}, processList) cli:option('--filter=PATTERN', 'only run test names matching the Lua pattern', {}, processMultiOption) @@ -168,17 +168,34 @@ return function(options) end -- Load busted config file if available - local bustedConfigFilePath = cliArgs.f or path.normpath(path.join(cliArgs.directory, '.busted')) - local bustedConfigFile = loadfile(bustedConfigFilePath) - if bustedConfigFile then - local ok, config = pcall(function() - local conf, err = configLoader(bustedConfigFile(), cliArgsParsed, cliArgs) - return conf or error(err, 0) - end) - if not ok then - return nil, appName .. ': error: ' .. config + local bustedConfigFilePath + if cliArgs.f then + -- if the file is given, then we require it to exist + if not path.isfile(cliArgs.f) then + return nil, ("specified config file '%s' not found"):format(cliArgs.f) + end + bustedConfigFilePath = cliArgs.f + else + -- try default file + bustedConfigFilePath = path.normpath(path.join(cliArgs.directory, '.busted')) + if not path.isfile(bustedConfigFilePath) then + bustedConfigFilePath = nil -- clear default file, since it doesn't exist + end + end + if bustedConfigFilePath then + local bustedConfigFile, err = loadfile(bustedConfigFilePath) + if not bustedConfigFile then + return nil, ("failed loading config file `%s`: %s"):format(bustedConfigFilePath, err) else - cliArgs = config + local ok, config = pcall(function() + local conf, err = configLoader(bustedConfigFile(), cliArgsParsed, cliArgs) + return conf or error(err, 0) + end) + if not ok then + return nil, appName .. ': error: ' .. config + else + cliArgs = config + end end else cliArgs = tablex.merge(cliArgs, cliArgsParsed, true) diff --git a/busted/modules/configuration_loader.lua b/busted/modules/configuration_loader.lua index c2504dce..9ad0b487 100644 --- a/busted/modules/configuration_loader.lua +++ b/busted/modules/configuration_loader.lua @@ -7,7 +7,7 @@ return function() return nil, '.busted file does not return a table.' end - local defaults = defaults or {} + defaults = defaults or {} local run = config.run or defaults.run if run and run ~= '' then diff --git a/busted/modules/filter_loader.lua b/busted/modules/filter_loader.lua index 1d54b485..7154ff2a 100644 --- a/busted/modules/filter_loader.lua +++ b/busted/modules/filter_loader.lua @@ -55,11 +55,13 @@ return function() return nil, (#options.filter == 0) end - local printNameOnly = function(name, fn, trace) - local fullname = getFullName(name) - if trace and trace.what == 'Lua' then - print(trace.short_src .. ':' .. trace.currentline .. ': ' .. fullname) - else + local printTestName = function(element, parent, status) + if not (options.suppressPending and status == 'pending') then + local fullname = getFullName() + local trace = element.trace + if trace and trace.what == 'Lua' then + fullname = trace.short_src .. ':' .. trace.currentline .. ': ' .. fullname + end print(fullname) end return nil, false @@ -69,6 +71,15 @@ return function() return nil, false end + local noop = function() end + local stubOut = function(descriptor, name, fn, ...) + if fn == noop then + return nil, true + end + busted.publish({ 'register', descriptor }, name, noop, ...) + return nil, false + end + local skipOnError = function() return nil, not busted.skipAll end @@ -81,13 +92,28 @@ return function() end end + local applyDescFilter = function(descriptors, name, fn) + if options[name] and options[name] ~= '' then + for _, descriptor in ipairs(descriptors) do + local f = function(...) return fn(descriptor, ...) end + busted.subscribe({ 'register', descriptor }, f, { priority = 1 }) + end + end + end + if options.list then busted.subscribe({ 'suite', 'start' }, ignoreAll, { priority = 1 }) busted.subscribe({ 'suite', 'end' }, ignoreAll, { priority = 1 }) - applyFilter({ 'setup', 'teardown', 'before_each', 'after_each' }, 'list', ignoreAll) - applyFilter({ 'lazy_setup', 'lazy_teardown' }, 'list', ignoreAll) - applyFilter({ 'strict_setup', 'strict_teardown' }, 'list', ignoreAll) - applyFilter({ 'it', 'pending' }, 'list', printNameOnly) + busted.subscribe({ 'file', 'start' }, ignoreAll, { priority = 1 }) + busted.subscribe({ 'file', 'end' }, ignoreAll, { priority = 1 }) + busted.subscribe({ 'describe', 'start' }, ignoreAll, { priority = 1 }) + busted.subscribe({ 'describe', 'end' }, ignoreAll, { priority = 1 }) + busted.subscribe({ 'test', 'start' }, ignoreAll, { priority = 1 }) + busted.subscribe({ 'test', 'end' }, printTestName, { priority = 1 }) + applyDescFilter({ 'setup', 'teardown', 'before_each', 'after_each' }, 'list', stubOut) + applyDescFilter({ 'lazy_setup', 'lazy_teardown' }, 'list', stubOut) + applyDescFilter({ 'strict_setup', 'strict_teardown' }, 'list', stubOut) + applyDescFilter({ 'it', 'pending' }, 'list', stubOut) end applyFilter({ 'lazy_setup', 'lazy_teardown' }, 'nokeepgoing', skipOnError) diff --git a/busted/modules/helper_loader.lua b/busted/modules/helper_loader.lua index 693b903d..56ae6673 100644 --- a/busted/modules/helper_loader.lua +++ b/busted/modules/helper_loader.lua @@ -1,11 +1,13 @@ local path = require 'pl.path' local hasMoon, moonscript = pcall(require, 'moonscript') +local utils = require 'busted.utils' return function() local loadHelper = function(busted, helper, options) - local old_arg = arg + local old_arg = _G.arg local success, err = pcall(function() - arg = options.arguments + utils.copy_interpreter_args(options.arguments) + _G.arg = options.arguments if helper:match('%.lua$') then dofile(path.normpath(helper)) elseif hasMoon and helper:match('%.moon$') then diff --git a/busted/modules/luacov.lua b/busted/modules/luacov.lua index 99cfc8f5..51a9ad33 100644 --- a/busted/modules/luacov.lua +++ b/busted/modules/luacov.lua @@ -4,7 +4,7 @@ return function() local result, luacov = pcall(require, 'luacov.runner') if not result then - return print('LuaCov not found on the system, try running without --coverage option, or install LuaCov first') + return nil, 'LuaCov not found on the system, try running without --coverage option, or install LuaCov first' end -- call it to start @@ -16,6 +16,7 @@ return function() table.insert(luacov.configuration.exclude, 'luassert%.') table.insert(luacov.configuration.exclude, 'say%.') table.insert(luacov.configuration.exclude, 'pl%.') + return true end return loadLuaCov diff --git a/busted/modules/output_handler_loader.lua b/busted/modules/output_handler_loader.lua index ebcd2da1..b393c7f4 100644 --- a/busted/modules/output_handler_loader.lua +++ b/busted/modules/output_handler_loader.lua @@ -1,10 +1,12 @@ local path = require 'pl.path' local hasMoon, moonscript = pcall(require, 'moonscript') +local utils = require 'busted.utils' return function() local loadOutputHandler = function(busted, output, options) local handlers = {} + utils.copy_interpreter_args(options.arguments) local success, err = pcall(function() for word in output:gmatch("%a+") do if word:match('%.lua$') then diff --git a/busted/modules/standalone_loader.lua b/busted/modules/standalone_loader.lua new file mode 100644 index 00000000..6299aa5f --- /dev/null +++ b/busted/modules/standalone_loader.lua @@ -0,0 +1,28 @@ +local getTrace = function(filename, info) + local index = info.traceback:find('\n%s*%[C]') + info.traceback = info.traceback:sub(1, index) + return info +end + +return function(busted) + local loadCurrentFile = function(info, options) + local filename = 'string' + if info.source:sub(1,1) == '@' or info.source:sub(1,1) == '=' then + filename = info.source:sub(2) + end + + -- Setup test file to be compatible with live coding + if info.func then + local file = setmetatable({ + getTrace = getTrace, + rewriteMessage = nil + }, { + __call = info.func + }) + + busted.executors.file(filename, file) + end + end + + return loadCurrentFile +end diff --git a/busted/modules/test_file_loader.lua b/busted/modules/test_file_loader.lua index a6b9b68b..3a6be09b 100644 --- a/busted/modules/test_file_loader.lua +++ b/busted/modules/test_file_loader.lua @@ -37,12 +37,13 @@ return function(busted, loaders) fileList = tablex.filter(fileList, function(filename) if path.is_windows then - return not filename:find('%\\%.%w+.%w+') + return not filename:find('%\\%.%w+.%w+', #rootFile) else - return not filename:find('/%.%w+.%w+') + return not filename:find('/%.%w+.%w+', #rootFile) end end) else + busted.publish({ 'error' }, {}, nil, s('output.file_not_found'):format(rootFile), {}) fileList = {} end diff --git a/busted/options.lua b/busted/options.lua index a3b62bfa..c6f5d6cc 100644 --- a/busted/options.lua +++ b/busted/options.lua @@ -1,4 +1,4 @@ return { standalone = true, - defaultOutput = 'utfTerminal', + output = nil, } diff --git a/busted/outputHandlers/TAP.lua b/busted/outputHandlers/TAP.lua index 72dc9c8f..cd0e7407 100644 --- a/busted/outputHandlers/TAP.lua +++ b/busted/outputHandlers/TAP.lua @@ -1,4 +1,5 @@ local pretty = require 'pl.pretty' +local io = io return function(options) local busted = require 'busted' @@ -16,6 +17,7 @@ return function(options) handler.suiteEnd = function() print('1..' .. counter) + io.flush() return nil, true end @@ -45,6 +47,7 @@ return function(options) local testName = fileline .. handler.getFullName(element) print('# ' .. testName) end + io.flush() return nil, true end @@ -62,6 +65,7 @@ return function(options) elseif status == 'error' then showFailure(handler.errors[#handler.errors]) end + io.flush() return nil, true end @@ -71,6 +75,7 @@ return function(options) counter = counter + 1 showFailure(handler.errors[#handler.errors]) end + io.flush() return nil, true end diff --git a/busted/outputHandlers/gtest.lua b/busted/outputHandlers/gtest.lua index 137c4848..7af93cb3 100644 --- a/busted/outputHandlers/gtest.lua +++ b/busted/outputHandlers/gtest.lua @@ -1,6 +1,7 @@ local s = require 'say' local pretty = require 'pl.pretty' local term = require 'term' +local io = io local colors @@ -17,8 +18,8 @@ return function(options) local busted = require 'busted' local handler = require 'busted.outputHandlers.base'() - local repeatSuiteString = '\nRepeating all tests (run %d of %d) . . .\n\n' - local randomizeString = colors.yellow('Note: Randomizing test order with a seed of %d.\n') + local repeatSuiteString = '\nRepeating all tests (run %u of %u) . . .\n\n' + local randomizeString = colors.yellow('Note: Randomizing test order with a seed of %u.\n') local suiteStartString = colors.green ('[==========]') .. ' Running tests from scanned files.\n' local globalSetup = colors.green ('[----------]') .. ' Global test environment setup.\n' local fileStartString = colors.green ('[----------]') .. ' Running tests from %s\n' @@ -27,28 +28,28 @@ return function(options) local skippedString = colors.yellow ('[ SKIPPED ]') .. ' %s (%.2f ms)\n' local failureString = colors.red ('[ FAILED ]') .. ' %s (%.2f ms)\n' local errorString = colors.magenta('[ ERROR ]') .. ' %s (%.2f ms)\n' - local fileEndString = colors.green ('[----------]') .. ' %d %s from %s (%.2f ms total)\n\n' + local fileEndString = colors.green ('[----------]') .. ' %u %s from %s (%.2f ms total)\n\n' local globalTeardown = colors.green ('[----------]') .. ' Global test environment teardown.\n' - local suiteEndString = colors.green ('[==========]') .. ' %d %s from %d test %s ran. (%.2f ms total)\n' - local successStatus = colors.green ('[ PASSED ]') .. ' %d %s.\n' + local suiteEndString = colors.green ('[==========]') .. ' %u %s from %u test %s ran. (%.2f ms total)\n' + local successStatus = colors.green ('[ PASSED ]') .. ' %u %s.\n' local summaryStrings = { skipped = { - header = colors.yellow ('[ SKIPPED ]') .. ' %d %s, listed below:\n', + header = colors.yellow ('[ SKIPPED ]') .. ' %u %s, listed below:\n', test = colors.yellow ('[ SKIPPED ]') .. ' %s\n', - footer = ' %d SKIPPED %s\n', + footer = ' %u SKIPPED %s\n', }, failure = { - header = colors.red ('[ FAILED ]') .. ' %d %s, listed below:\n', + header = colors.red ('[ FAILED ]') .. ' %u %s, listed below:\n', test = colors.red ('[ FAILED ]') .. ' %s\n', - footer = ' %d FAILED %s\n', + footer = ' %u FAILED %s\n', }, error = { - header = colors.magenta('[ ERROR ]') .. ' %d %s, listed below:\n', + header = colors.magenta('[ ERROR ]') .. ' %u %s, listed below:\n', test = colors.magenta('[ ERROR ]') .. ' %s\n', - footer = ' %d %s\n', + footer = ' %u %s\n', }, } diff --git a/busted/outputHandlers/junit.lua b/busted/outputHandlers/junit.lua index 8ebe6b2a..a4c162de 100644 --- a/busted/outputHandlers/junit.lua +++ b/busted/outputHandlers/junit.lua @@ -1,5 +1,6 @@ local xml = require 'pl.xml' local string = require("string") +local io = io return function(options) local busted = require 'busted' @@ -131,7 +132,7 @@ return function(options) handler.testEnd = function(element, parent, status) top.xml_doc.attr.tests = top.xml_doc.attr.tests + 1 - testcase_node.time = formatDuration(element.duration) + testcase_node:set_attrib("time", formatDuration(element.duration)) if status == 'success' then testStatus(element, parent, nil, 'success') diff --git a/busted/outputHandlers/plainTerminal.lua b/busted/outputHandlers/plainTerminal.lua index 1378b71d..b0a73242 100644 --- a/busted/outputHandlers/plainTerminal.lua +++ b/busted/outputHandlers/plainTerminal.lua @@ -1,5 +1,6 @@ local s = require 'say' local pretty = require 'pl.pretty' +local io = io return function(options) local busted = require 'busted' @@ -130,7 +131,7 @@ return function(options) end handler.suiteStart = function(suite, count, total) - local runString = (total > 1 and '\nRepeating all tests (run %d of %d) . . .\n\n' or '') + local runString = (total > 1 and '\nRepeating all tests (run %u of %u) . . .\n\n' or '') io.write(runString:format(count, total)) io.flush() diff --git a/busted/outputHandlers/sound.lua b/busted/outputHandlers/sound.lua index 8a749693..84fa7c8b 100644 --- a/busted/outputHandlers/sound.lua +++ b/busted/outputHandlers/sound.lua @@ -1,4 +1,6 @@ local app = require 'pl.app' +local io = io + return function(options) local busted = require 'busted' local handler = require 'busted.outputHandlers.base'() diff --git a/busted/outputHandlers/utfTerminal.lua b/busted/outputHandlers/utfTerminal.lua index 3a2c0456..ca32b8aa 100644 --- a/busted/outputHandlers/utfTerminal.lua +++ b/busted/outputHandlers/utfTerminal.lua @@ -1,5 +1,6 @@ local s = require 'say' local pretty = require 'pl.pretty' +local io = io local colors @@ -139,7 +140,7 @@ return function(options) end handler.suiteStart = function(suite, count, total) - local runString = (total > 1 and '\nRepeating all tests (run %d of %d) . . .\n\n' or '') + local runString = (total > 1 and '\nRepeating all tests (run %u of %u) . . .\n\n' or '') io.write(runString:format(count, total)) io.flush() diff --git a/busted/runner.lua b/busted/runner.lua index 59529c95..6605eec1 100644 --- a/busted/runner.lua +++ b/busted/runner.lua @@ -9,11 +9,11 @@ local loadstring = require 'busted.compatibility'.loadstring local loaded = false return function(options) - if loaded then return else loaded = true end + if loaded then return function() end else loaded = true end local isatty = io.type(io.stdout) == 'file' and term.isatty(io.stdout) options = tablex.update(require 'busted.options', options or {}) - options.defaultOutput = isatty and 'utfTerminal' or 'plainTerminal' + options.output = options.output or (isatty and 'utfTerminal' or 'plainTerminal') local busted = require 'busted.core'() @@ -29,33 +29,38 @@ return function(options) local level = 2 local info = debug.getinfo(level, 'Sf') local source = info.source - local fileName = source:sub(1,1) == '@' and source:sub(2) or source + local fileName = source:sub(1,1) == '@' and source:sub(2) or nil + local forceExit = fileName == nil -- Parse the cli arguments - local appName = path.basename(fileName) + local appName = path.basename(fileName or 'busted') cli:set_name(appName) local cliArgs, err = cli:parse(arg) if not cliArgs then io.stderr:write(err .. '\n') - exit(1) + exit(1, forceExit) end if cliArgs.version then -- Return early if asked for the version print(busted.version) - exit(0) + exit(0, forceExit) end -- Load current working directory local _, err = path.chdir(path.normpath(cliArgs.directory)) if err then io.stderr:write(appName .. ': error: ' .. err .. '\n') - exit(1) + exit(1, forceExit) end -- If coverage arg is passed in, load LuaCovsupport if cliArgs.coverage then - luacov() + local ok, err = luacov() + if not ok then + io.stderr:write(appName .. ': error: ' .. err .. '\n') + exit(1, forceExit) + end end -- If auto-insulate is disabled, re-register file without insulation @@ -123,7 +128,7 @@ return function(options) -- Set up output handler to listen to events outputHandlerLoader(busted, cliArgs.output, { - defaultOutput = options.defaultOutput, + defaultOutput = options.output, enableSound = cliArgs['enable-sound'], verbose = cliArgs.verbose, suppressPending = cliArgs['suppress-pending'], @@ -132,15 +137,24 @@ return function(options) arguments = cliArgs.Xoutput, }) - -- Load tag and test filters - filterLoader(busted, { - tags = cliArgs.tags, - excludeTags = cliArgs['exclude-tags'], - filter = cliArgs.filter, - filterOut = cliArgs['filter-out'], - list = cliArgs.list, - nokeepgoing = not cliArgs['keep-going'], - }) + -- Pre-load the LuaJIT 'ffi' module if applicable + local isJit = (tostring(assert):match('builtin') ~= nil) + if isJit then + -- pre-load the ffi module, such that it becomes part of the environment + -- and Busted will not try to GC and reload it. The ffi is not suited + -- for that and will occasionally segfault if done so. + local ffi = require "ffi" + + -- Now patch ffi.cdef to only be called once with each definition, as it + -- will error on re-registering. + local old_cdef = ffi.cdef + local exists = {} + ffi.cdef = function(def) + if exists[def] then return end + exists[def] = true + return old_cdef(def) + end + end -- Set up helper script if cliArgs.helper and cliArgs.helper ~= '' then @@ -151,22 +165,31 @@ return function(options) }) end - -- Load test directory - local rootFiles = cliArgs.ROOT or { fileName } - local patterns = cliArgs.pattern - local testFileLoader = require 'busted.modules.test_file_loader'(busted, cliArgs.loaders) - testFileLoader(rootFiles, patterns, { - excludes = cliArgs['exclude-pattern'], - verbose = cliArgs.verbose, - recursive = cliArgs['recursive'], + -- Load tag and test filters + filterLoader(busted, { + tags = cliArgs.tags, + excludeTags = cliArgs['exclude-tags'], + filter = cliArgs.filter, + filterOut = cliArgs['filter-out'], + list = cliArgs.list, + nokeepgoing = not cliArgs['keep-going'], + suppressPending = cliArgs['suppress-pending'], }) - -- If running standalone, setup test file to be compatible with live coding - if options.standalone then - local ctx = busted.context.get() - local children = busted.context.children(ctx) - local file = children[#children] - debug.getmetatable(file.run).__call = info.func + if cliArgs.ROOT then + -- Load test directories/files + local rootFiles = cliArgs.ROOT + local patterns = cliArgs.pattern + local testFileLoader = require 'busted.modules.test_file_loader'(busted, cliArgs.loaders) + testFileLoader(rootFiles, patterns, { + excludes = cliArgs['exclude-pattern'], + verbose = cliArgs.verbose, + recursive = cliArgs['recursive'], + }) + else + -- Running standalone, use standalone loader + local testFileLoader = require 'busted.modules.standalone_loader'(busted) + testFileLoader(info, { verbose = cliArgs.verbose }) end local runs = cliArgs['repeat'] @@ -180,6 +203,6 @@ return function(options) busted.publish({ 'exit' }) if options.standalone or failures > 0 or errors > 0 then - exit(failures + errors) + exit(failures + errors, forceExit) end end diff --git a/busted/utils.lua b/busted/utils.lua index 75f4b5d9..bf771487 100644 --- a/busted/utils.lua +++ b/busted/utils.lua @@ -1,4 +1,15 @@ return { + copy_interpreter_args = function(arguments) + -- copy non-positive command-line args auto-inserted by Lua interpreter + if arguments and _G.arg then + local i = 0 + while _G.arg[i] do + arguments[i] = _G.arg[i] + i = i - 1 + end + end + end, + split = require 'pl.utils'.split, shuffle = function(t, seed) diff --git a/busted-2.0.rc12-1.rockspec b/rockspecs/busted-2.0.0-0.rockspec similarity index 93% rename from busted-2.0.rc12-1.rockspec rename to rockspecs/busted-2.0.0-0.rockspec index 36f81192..d871847e 100644 --- a/busted-2.0.rc12-1.rockspec +++ b/rockspecs/busted-2.0.0-0.rockspec @@ -1,8 +1,8 @@ package = 'busted' -version = '2.0.rc12-1' +version = '2.0.0-0' source = { - url = 'https://github.com/Olivine-Labs/busted/archive/v2.0.rc12-1.tar.gz', - dir = 'busted-2.0.rc12-1' + url = 'https://github.com/Olivine-Labs/busted/archive/v2.0.0-0.tar.gz', + dir = 'busted-2.0.0-0' } description = { summary = 'Elegant Lua unit testing.', @@ -24,7 +24,7 @@ dependencies = { 'luasystem >= 0.2.0-0', 'dkjson >= 2.1.0', 'say >= 1.3-0', - 'luassert >= 1.7.8-0', + 'luassert >= 1.8.0-0', 'lua-term >= 0.1-1', 'penlight >= 1.3.2-2', 'mediator_lua >= 1.1.1-0', @@ -49,6 +49,7 @@ build = { ['busted.modules.configuration_loader'] = 'busted/modules/configuration_loader.lua', ['busted.modules.luacov'] = 'busted/modules/luacov.lua', + ['busted.modules.standalone_loader'] = 'busted/modules/standalone_loader.lua', ['busted.modules.test_file_loader'] = 'busted/modules/test_file_loader.lua', ['busted.modules.output_handler_loader'] = 'busted/modules/output_handler_loader.lua', ['busted.modules.helper_loader'] = 'busted/modules/helper_loader.lua', @@ -79,6 +80,7 @@ build = { ['busted.languages.th'] = 'busted/languages/th.lua', ['busted.languages.ua'] = 'busted/languages/ua.lua', ['busted.languages.zh'] = 'busted/languages/zh.lua', + ['busted.languages.it'] = 'busted/languages/it.lua', }, install = { bin = { diff --git a/rockspecs/busted-2.0.0-1.rockspec b/rockspecs/busted-2.0.0-1.rockspec new file mode 100644 index 00000000..7d2fc389 --- /dev/null +++ b/rockspecs/busted-2.0.0-1.rockspec @@ -0,0 +1,89 @@ +package = 'busted' +version = '2.0.0-1' +source = { + url = 'https://github.com/Olivine-Labs/busted/archive/v2.0.0.tar.gz', + dir = 'busted-2.0.0' +} +description = { + summary = 'Elegant Lua unit testing.', + detailed = [[ + An elegant, extensible, testing framework. + Ships with a large amount of useful asserts, + plus the ability to write your own. Output + in pretty or plain terminal format, JSON, + or TAP for CI integration. Great for TDD + and unit, integration, and functional tests. + ]], + homepage = 'http://olivinelabs.com/busted/', + license = 'MIT ' +} +dependencies = { + 'lua >= 5.1', + 'lua_cliargs = 3.0', + 'luafilesystem >= 1.5.0', + 'luasystem >= 0.2.0', + 'dkjson >= 2.1.0', + 'say >= 1.3', + 'luassert >= 1.8.0', + 'lua-term >= 0.1', + 'penlight >= 1.3.2', + 'mediator_lua >= 1.1.1', +} + +build = { + type = 'builtin', + modules = { + ['busted.core'] = 'busted/core.lua', + ['busted.context'] = 'busted/context.lua', + ['busted.environment'] = 'busted/environment.lua', + ['busted.compatibility'] = 'busted/compatibility.lua', + ['busted.options'] = 'busted/options.lua', + ['busted.done'] = 'busted/done.lua', + ['busted.runner'] = 'busted/runner.lua', + ['busted.status'] = 'busted/status.lua', + ['busted.utils'] = 'busted/utils.lua', + ['busted.block'] = 'busted/block.lua', + ['busted.execute'] = 'busted/execute.lua', + ['busted.init'] = 'busted/init.lua', + + ['busted.modules.configuration_loader'] = 'busted/modules/configuration_loader.lua', + ['busted.modules.luacov'] = 'busted/modules/luacov.lua', + ['busted.modules.standalone_loader'] = 'busted/modules/standalone_loader.lua', + ['busted.modules.test_file_loader'] = 'busted/modules/test_file_loader.lua', + ['busted.modules.output_handler_loader'] = 'busted/modules/output_handler_loader.lua', + ['busted.modules.helper_loader'] = 'busted/modules/helper_loader.lua', + ['busted.modules.filter_loader'] = 'busted/modules/filter_loader.lua', + ['busted.modules.cli'] = 'busted/modules/cli.lua', + + ['busted.modules.files.lua'] = 'busted/modules/files/lua.lua', + ['busted.modules.files.moonscript'] = 'busted/modules/files/moonscript.lua', + ['busted.modules.files.terra'] = 'busted/modules/files/terra.lua', + + ['busted.outputHandlers.base'] = 'busted/outputHandlers/base.lua', + ['busted.outputHandlers.utfTerminal'] = 'busted/outputHandlers/utfTerminal.lua', + ['busted.outputHandlers.plainTerminal'] = 'busted/outputHandlers/plainTerminal.lua', + ['busted.outputHandlers.TAP'] = 'busted/outputHandlers/TAP.lua', + ['busted.outputHandlers.json'] = 'busted/outputHandlers/json.lua', + ['busted.outputHandlers.junit'] = 'busted/outputHandlers/junit.lua', + ['busted.outputHandlers.gtest'] = 'busted/outputHandlers/gtest.lua', + ['busted.outputHandlers.sound'] = 'busted/outputHandlers/sound.lua', + + ['busted.languages.en'] = 'busted/languages/en.lua', + ['busted.languages.ar'] = 'busted/languages/ar.lua', + ['busted.languages.de'] = 'busted/languages/de.lua', + ['busted.languages.es'] = 'busted/languages/es.lua', + ['busted.languages.fr'] = 'busted/languages/fr.lua', + ['busted.languages.ja'] = 'busted/languages/ja.lua', + ['busted.languages.nl'] = 'busted/languages/nl.lua', + ['busted.languages.ru'] = 'busted/languages/ru.lua', + ['busted.languages.th'] = 'busted/languages/th.lua', + ['busted.languages.ua'] = 'busted/languages/ua.lua', + ['busted.languages.zh'] = 'busted/languages/zh.lua', + ['busted.languages.it'] = 'busted/languages/it.lua', + }, + install = { + bin = { + ['busted'] = 'bin/busted' + } + } +} diff --git a/spec/.hidden/.busted_bad b/spec/.hidden/.busted_bad index b1df1c77..e80083a0 100644 --- a/spec/.hidden/.busted_bad +++ b/spec/.hidden/.busted_bad @@ -5,7 +5,7 @@ return { default = { ['ROOT'] = {'specs'}, ['pattern'] = '_spec%.lua$', - ['loaders'] = doesnotexist.loaders, + ['loaders'] = doesnotexist.loaders, -- errors when run ['verbose'] = true, }, test = { diff --git a/spec/.hidden/.busted_bad_syntax b/spec/.hidden/.busted_bad_syntax new file mode 100644 index 00000000..5acd1c3b --- /dev/null +++ b/spec/.hidden/.busted_bad_syntax @@ -0,0 +1,14 @@ +return { + _all = { + ['ROOT'] = {'tests'}, + }, + default = { + ['ROOT'] = {'specs'}, + ['pattern'] = '_spec%.lua$', + ['loaders'] = doesnotexist.loaders, + ['verbose'] = true, + }, + test = { + ['pattern'] = '_test%.lua$', + } +-- } -- missing bracket, errors when compiled diff --git a/spec/cl_spec.lua b/spec/cl_spec.lua index 2bfa915c..ff3929cb 100644 --- a/spec/cl_spec.lua +++ b/spec/cl_spec.lua @@ -211,6 +211,24 @@ describe('Tests the busted command-line options', function() assert.is_equal(1, errcnt) end) + it('tests running a non-existing configfile', function() + local success, errcnt = executeBusted('--config-file=spec/.hidden/.this_one_does_not_exist --pattern=cl_execute_fail.lua$') + assert.is_false(success) + assert.is_equal(0, errcnt) + end) + + it('tests running a non-compiling configfile', function() + local success, errcnt = executeBusted('--config-file=spec/.hidden/.busted_bad_syntax --pattern=cl_execute_fail.lua$') + assert.is_false(success) + assert.is_equal(0, errcnt) + end) + + it('tests running a configfile throwing errors when being run', function() + local success, errcnt, out, err = executeBusted('--config-file=spec/.hidden/.busted_bad --pattern=cl_execute_fail.lua$') + assert.is_false(success) + assert.is_equal(0, errcnt) + end) + it('tests running with --output specified', function() local success, errcnt = executeBusted('--pattern=cl_success.lua$ --output=TAP') assert.is_true(success) @@ -300,6 +318,12 @@ describe('Test busted running standalone', function() local success, errcnt = executeLua('spec/cl_standalone.lua --help') assert.is_false(success) end) + + it('tests running via stdin', function() + local success, errcnt = executeLua('< spec/cl_standalone.lua') + assert.is_false(success) + assert.is_equal(3, errcnt) + end) end) describe('Test busted command-line runner', function() @@ -448,6 +472,20 @@ describe('Tests error messages through the command line', function() assert.is_equal(expectedMsg, errmsg) end) + it('when test file not found', function() + local _, _, result = executeBusted('--output=plainTerminal does_not_exist.lua') + local errmsg = result:match('Error %-> (.-)\n') + local expected = 'Cannot find file or directory: does_not_exist.lua' + assert.is_equal(expected, errmsg) + end) + + it('when test directory not found', function() + local _, _, result = executeBusted('--output=plainTerminal does_not_exist') + local errmsg = result:match('Error %-> (.-)\n') + local expected = 'Cannot find file or directory: does_not_exist' + assert.is_equal(expected, errmsg) + end) + it('when no test files matching Lua pattern', function() local _, _, result = executeBusted('--output=plainTerminal --pattern=this_filename_does_simply_not_exist$') local errmsg = result:match('Error %-> (.-)\n') @@ -747,3 +785,12 @@ describe('Tests execute option', function() assert.is_equal('hello world', result:match('(.-)\n')) end) end) + +describe('Tests root specification', function() + it('allows hidden directories in root path', function() + local success, errcnt, result = executeBusted('spec/.hidden') + assert.is_false(success) + assert.is_equal(1, errcnt) + assert.is_truthy(result:find('should not be executed')) + end) +end) diff --git a/spec/insulate-expose_spec.lua b/spec/insulate-expose_spec.lua index 0409a3d1..bba84bd6 100644 --- a/spec/insulate-expose_spec.lua +++ b/spec/insulate-expose_spec.lua @@ -13,9 +13,9 @@ describe('Tests insulation', function() it('updates package.loaded', function() assert.is_not_nil(pl) - assert.is_not_nil(List) + assert.is_not_nil(Date) assert.is_not_nil(package.loaded.pl) - assert.is_not_nil(package.loaded['pl.List']) + assert.is_not_nil(package.loaded['pl.Date']) end) end) @@ -27,9 +27,9 @@ describe('Tests insulation', function() it('restores package.loaded', function() assert.is_nil(pl) - assert.is_nil(List) + assert.is_nil(Date) assert.is_nil(package.loaded.pl) - assert.is_nil(package.loaded['pl.List']) + assert.is_nil(package.loaded['pl.Date']) end) end) end) @@ -54,9 +54,9 @@ insulate('', function() it('updates package.loaded', function() assert.is_not_nil(pl) - assert.is_not_nil(List) + assert.is_not_nil(Date) assert.is_not_nil(package.loaded.pl) - assert.is_not_nil(package.loaded['pl.List']) + assert.is_not_nil(package.loaded['pl.Date']) end) end) end) @@ -74,9 +74,9 @@ insulate('', function() it('does not restore package.loaded', function() assert.is_not_nil(pl) - assert.is_not_nil(List) + assert.is_not_nil(Date) assert.is_not_nil(package.loaded.pl) - assert.is_not_nil(package.loaded['pl.List']) + assert.is_not_nil(package.loaded['pl.Date']) end) end) end) @@ -93,9 +93,9 @@ insulate('', function() end) it('Tests package.loaded persists without insulate', function() - assert.is_not_nil(List) + assert.is_not_nil(Date) assert.is_not_nil(package.loaded.pl) - assert.is_not_nil(package.loaded['pl.List']) + assert.is_not_nil(package.loaded['pl.Date']) end) end) @@ -107,9 +107,9 @@ describe('Tests after insulating an expose block', function() it('restores package.loaded', function() assert.is_nil(pl) - assert.is_nil(List) + assert.is_nil(Date) assert.is_nil(package.loaded.pl) - assert.is_nil(package.loaded['pl.List']) + assert.is_nil(package.loaded['pl.Date']) end) end) diff --git a/spec/modules/cli_spec.lua b/spec/modules/cli_spec.lua index c8d6d0d7..b70dfcb7 100644 --- a/spec/modules/cli_spec.lua +++ b/spec/modules/cli_spec.lua @@ -6,7 +6,7 @@ describe('Tests command-line interface', function() local defaultOutput = 'default_output_handler' local lpath = './src/?.lua;./src/?/?.lua;./src/?/init.lua' local cpath = path.is_windows and './csrc/?.dll;./csrc/?/?.dll;' or './csrc/?.so;./csrc/?/?.so;' - local cli = require 'busted.modules.cli'({ standalone = false, defaultOutput = defaultOutput }) + local cli = require 'busted.modules.cli'({ standalone = false, output = defaultOutput }) local args = cli:parse({}) assert.is_equal(defaultOutput, args.o) assert.is_equal(defaultOutput, args.output) @@ -330,7 +330,7 @@ describe('Tests using .busted tasks', function() local defaultOutput = 'default_output_handler' local lpath = './src/?.lua;./src/?/?.lua;./src/?/init.lua' local cpath = path.is_windows and './csrc/?.dll;./csrc/?/?.dll;' or './csrc/?.so;./csrc/?/?.so;' - local cli = require 'busted.modules.cli'({ standalone = false, defaultOutput = defaultOutput }) + local cli = require 'busted.modules.cli'({ standalone = false, output = defaultOutput }) local args = cli:parse({ '--directory=spec/.hidden' }) assert.is_equal(defaultOutput, args.o) assert.is_equal(defaultOutput, args.output) @@ -389,7 +389,7 @@ describe('Tests using .busted tasks', function() local defaultOutput = 'default_output_handler' local lpath = './src/?.lua;./src/?/?.lua;./src/?/init.lua' local cpath = path.is_windows and './csrc/?.dll;./csrc/?/?.dll;' or './csrc/?.so;./csrc/?/?.so;' - local cli = require 'busted.modules.cli'({ standalone = false, defaultOutput = defaultOutput }) + local cli = require 'busted.modules.cli'({ standalone = false, output = defaultOutput }) local args = cli:parse({ '--config-file', 'spec/.hidden/.busted' }) assert.is_equal(defaultOutput, args.o) assert.is_equal(defaultOutput, args.output) @@ -444,7 +444,7 @@ describe('Tests using .busted tasks', function() end) it('load configuration options', function() - local cli = require 'busted.modules.cli'({ standalone = false, defaultOutput = defaultOutput }) + local cli = require 'busted.modules.cli'({ standalone = false, output = defaultOutput }) local args = cli:parse({ '--directory=spec/.hidden', '--run=test' }) assert.is_same({'_test1%.lua$', '_test2%.lua$'}, args.pattern) assert.is_same({'_exclude1', '_exclude2'}, args['exclude-pattern']) @@ -459,7 +459,7 @@ describe('Tests using .busted tasks', function() end) it('load configuration options and override with command-line', function() - local cli = require 'busted.modules.cli'({ standalone = false, defaultOutput = defaultOutput }) + local cli = require 'busted.modules.cli'({ standalone = false, output = defaultOutput }) local args = cli:parse({ '--directory=spec/.hidden', '--run=test', '-t', 'tag1', '-p', 'patt', '--filter=fin', '--filter-out=fout', '--exclude-pattern', '', '--loaders=moonscript' }) assert.is_same({'patt'}, args.pattern) assert.is_same({''}, args['exclude-pattern']) @@ -473,7 +473,7 @@ describe('Tests using .busted tasks', function() end) it('detects error in configuration file', function() - local cli = require 'busted.modules.cli'({ standalone = false, defaultOutput = defaultOutput }) + local cli = require 'busted.modules.cli'({ standalone = false, output = defaultOutput }) cli:set_name('app') local args, err = cli:parse({ '--config-file=spec/.hidden/.busted_bad', '--run=test' }) assert.is_nil(args) @@ -483,7 +483,7 @@ describe('Tests using .busted tasks', function() end) it('detects invalid configuration file', function() - local cli = require 'busted.modules.cli'({ standalone = false, defaultOutput = defaultOutput }) + local cli = require 'busted.modules.cli'({ standalone = false, output = defaultOutput }) cli:set_name('myapp') local args, err = cli:parse({ '--config-file=spec/.hidden/.busted_empty' }) assert.is_nil(args) @@ -491,7 +491,7 @@ describe('Tests using .busted tasks', function() end) it('detects unknown/invalid task', function() - local cli = require 'busted.modules.cli'({ standalone = false, defaultOutput = defaultOutput }) + local cli = require 'busted.modules.cli'({ standalone = false, output = defaultOutput }) cli:set_name('appname') local args, err = cli:parse({ '--config-file=spec/.hidden/.busted', '--run=invalid' }) assert.is_nil(args) diff --git a/try b/try index fe04aa13..5566fd10 100755 --- a/try +++ b/try @@ -1,4 +1,4 @@ #!/bin/sh sudo luarocks remove busted --force -sudo luarocks make busted-scm-0.rockspec -busted +sudo luarocks make +busted $@ diff --git a/try.bat b/try.bat index 0d4dba36..d06a8233 100644 --- a/try.bat +++ b/try.bat @@ -1,4 +1,4 @@ call luarocks remove busted --force -call luarocks make busted-scm-0.rockspec +call luarocks make cls -call busted +call busted %*