]> source.dussan.org Git - rspamd.git/commitdiff
Reorganize lua tests.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Fri, 27 Feb 2015 15:55:46 +0000 (15:55 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Fri, 27 Feb 2015 15:55:46 +0000 (15:55 +0000)
73 files changed:
test/CMakeLists.txt
test/busted.lua [deleted file]
test/busted/compatibility.lua [deleted file]
test/busted/context.lua [deleted file]
test/busted/core.lua [deleted file]
test/busted/done.lua [deleted file]
test/busted/environment.lua [deleted file]
test/busted/init.lua [deleted file]
test/busted/languages/ar.lua [deleted file]
test/busted/languages/de.lua [deleted file]
test/busted/languages/en.lua [deleted file]
test/busted/languages/fr.lua [deleted file]
test/busted/languages/ja.lua [deleted file]
test/busted/languages/nl.lua [deleted file]
test/busted/languages/ru.lua [deleted file]
test/busted/languages/th.lua [deleted file]
test/busted/languages/ua.lua [deleted file]
test/busted/languages/zh.lua [deleted file]
test/busted/modules/configuration_loader.lua [deleted file]
test/busted/modules/files/lua.lua [deleted file]
test/busted/modules/files/moonscript.lua [deleted file]
test/busted/modules/files/terra.lua [deleted file]
test/busted/modules/helper_loader.lua [deleted file]
test/busted/modules/luacov.lua [deleted file]
test/busted/modules/output_handler_loader.lua [deleted file]
test/busted/modules/test_file_loader.lua [deleted file]
test/busted/outputHandlers/TAP.lua [deleted file]
test/busted/outputHandlers/base.lua [deleted file]
test/busted/outputHandlers/json.lua [deleted file]
test/busted/outputHandlers/junit.lua [deleted file]
test/busted/outputHandlers/plainTerminal.lua [deleted file]
test/busted/outputHandlers/sound.lua [deleted file]
test/busted/outputHandlers/utfTerminal.lua [deleted file]
test/busted/runner.lua [deleted file]
test/busted/status.lua [deleted file]
test/busted/utils.lua [deleted file]
test/lua/busted.lua [new file with mode: 0644]
test/lua/busted/compatibility.lua [new file with mode: 0644]
test/lua/busted/context.lua [new file with mode: 0644]
test/lua/busted/core.lua [new file with mode: 0644]
test/lua/busted/done.lua [new file with mode: 0644]
test/lua/busted/environment.lua [new file with mode: 0644]
test/lua/busted/init.lua [new file with mode: 0644]
test/lua/busted/languages/ar.lua [new file with mode: 0644]
test/lua/busted/languages/de.lua [new file with mode: 0644]
test/lua/busted/languages/en.lua [new file with mode: 0644]
test/lua/busted/languages/fr.lua [new file with mode: 0644]
test/lua/busted/languages/ja.lua [new file with mode: 0644]
test/lua/busted/languages/nl.lua [new file with mode: 0644]
test/lua/busted/languages/ru.lua [new file with mode: 0644]
test/lua/busted/languages/th.lua [new file with mode: 0644]
test/lua/busted/languages/ua.lua [new file with mode: 0644]
test/lua/busted/languages/zh.lua [new file with mode: 0644]
test/lua/busted/modules/configuration_loader.lua [new file with mode: 0644]
test/lua/busted/modules/files/lua.lua [new file with mode: 0644]
test/lua/busted/modules/files/moonscript.lua [new file with mode: 0644]
test/lua/busted/modules/files/terra.lua [new file with mode: 0644]
test/lua/busted/modules/helper_loader.lua [new file with mode: 0644]
test/lua/busted/modules/luacov.lua [new file with mode: 0644]
test/lua/busted/modules/output_handler_loader.lua [new file with mode: 0644]
test/lua/busted/modules/test_file_loader.lua [new file with mode: 0644]
test/lua/busted/outputHandlers/TAP.lua [new file with mode: 0644]
test/lua/busted/outputHandlers/base.lua [new file with mode: 0644]
test/lua/busted/outputHandlers/json.lua [new file with mode: 0644]
test/lua/busted/outputHandlers/junit.lua [new file with mode: 0644]
test/lua/busted/outputHandlers/plainTerminal.lua [new file with mode: 0644]
test/lua/busted/outputHandlers/sound.lua [new file with mode: 0644]
test/lua/busted/outputHandlers/utfTerminal.lua [new file with mode: 0644]
test/lua/busted/runner.lua [new file with mode: 0644]
test/lua/busted/status.lua [new file with mode: 0644]
test/lua/busted/utils.lua [new file with mode: 0644]
test/lua/rsa.lua
test/rspamd_lua_test.c

index 9932fb87dd728cc90851efb1fc823f5171a11d69..32d5334cbfc3ef52db108aa4e978acf07c5d24ac 100644 (file)
@@ -23,9 +23,17 @@ TARGET_LINK_LIBRARIES(rspamd-test ${RSPAMD_REQUIRED_LIBRARIES})
 TARGET_LINK_LIBRARIES(rspamd-test stemmer)
 
 IF(NOT ${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR}) 
-       FILE(COPY "${CMAKE_CURRENT_SOURCE_DIR}/busted.lua" 
-                         "${CMAKE_CURRENT_SOURCE_DIR}/busted"
-                         "${CMAKE_CURRENT_SOURCE_DIR}/lua"
+       FILE(COPY "${CMAKE_CURRENT_SOURCE_DIR}/lua"
                          DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+
+       # Also add dependencies for convenience
+       FILE(GLOB LUA_TESTS "${CMAKE_CURRENT_SOURCE_DIR}/lua/*")
+       FOREACH(_LF IN LISTS "${LUA_TESTS}")
+               GET_FILENAME_COMPONENT(_NM _LF NAME)
+               ADD_CUSTOM_COMMAND(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${_NM}"
+                       "${CMAKE_COMMAND} -E copy_if_different ${_LF} ${CMAKE_CURRENT_BINARY_DIR}/${_NM}"
+               )
+               ADD_DEPENDENCIES(rspamd-test "${CMAKE_CURRENT_BINARY_DIR}/${_NM}")
+       ENDFOREACH()
        
 ENDIF()
\ No newline at end of file
diff --git a/test/busted.lua b/test/busted.lua
deleted file mode 100644 (file)
index 917d21d..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
--- This is a dummy file so it can be used in busted's specs
--- without adding ./?/init.lua to the lua path
-return require 'busted.init'
diff --git a/test/busted/compatibility.lua b/test/busted/compatibility.lua
deleted file mode 100644 (file)
index 7837656..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-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 value
-  end,
-
-  setfenv = setfenv or function(f, t)
-    f = (type(f) == 'function' and f or debug.getinfo(f + 1, 'f').func)
-    local name
-    local up = 0
-
-    repeat
-      up = up + 1
-      name = debug.getupvalue(f, up)
-    until name == '_ENV' or name == nil
-
-    if name then
-      debug.upvaluejoin(f, up, function() return name end, 1)
-      debug.setupvalue(f, up, t)
-    end
-
-    if f ~= 0 then return f end
-  end,
-
-  unpack = table.unpack or unpack,
-
-  osexit = function(code, close)
-    if close and _VERSION == 'Lua 5.1' then
-      -- From Lua 5.1 manual:
-      -- > The userdata itself is freed only in the next
-      -- > garbage-collection cycle.
-      -- Call collectgarbage() while collectgarbage('count')
-      -- changes + 3 times, at least 3 times,
-      -- at max 100 times (to prevent infinite loop).
-      local times_const = 0
-      for i = 1, 100 do
-        local count_before = collectgarbage("count")
-        collectgarbage()
-        local count_after = collectgarbage("count")
-        if count_after == count_before then
-          times_const = times_const + 1
-          if times_const > 3 then
-            break
-          end
-        else
-          times_const = 0
-        end
-      end
-    end
-    os.exit(code, close)
-  end,
-}
diff --git a/test/busted/context.lua b/test/busted/context.lua
deleted file mode 100644 (file)
index 4cf0f3b..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-local tablex = require 'pl.tablex'
-
-local function save()
-  local g = {}
-  for k,_ in next, _G, nil do
-    g[k] = rawget(_G, k)
-  end
-  return {
-    gmt = getmetatable(_G),
-    g = g,
-    loaded = tablex.copy(package.loaded)
-  }
-end
-
-local function restore(state)
-  setmetatable(_G, state.gmt)
-  for k,_ in next, _G, nil do
-    rawset(_G, k, state.g[k])
-  end
-  for k,_ in pairs(package.loaded) do
-    package.loaded[k] = state.loaded[k]
-  end
-end
-
-return function()
-  local context = {}
-
-  local data = {}
-  local parents = {}
-  local children = {}
-  local stack = {}
-
-  function context.ref()
-    local ref = {}
-    local ctx = data
-
-    function ref.get(key)
-      if not key then return ctx end
-      return ctx[key]
-    end
-
-    function ref.set(key, value)
-      ctx[key] = value
-    end
-
-    function ref.clear()
-      data = {}
-      parents = {}
-      children = {}
-      stack = {}
-      ctx = data
-    end
-
-    function ref.attach(child)
-      if not children[ctx] then children[ctx] = {} end
-      parents[child] = ctx
-      table.insert(children[ctx], child)
-    end
-
-    function ref.children(parent)
-      return children[parent] or {}
-    end
-
-    function ref.parent(child)
-      return parents[child]
-    end
-
-    function ref.push(current)
-      if not parents[current] then error('Detached child. Cannot push.') end
-      if ctx ~= current and current.descriptor == 'file' then
-        current.state = save()
-      end
-      table.insert(stack, ctx)
-      ctx = current
-    end
-
-    function ref.pop()
-      local current = ctx
-      ctx = table.remove(stack)
-      if ctx ~= current and current.state then
-        restore(current.state)
-        current.state = nil
-      end
-      if not ctx then error('Context stack empty. Cannot pop.') end
-    end
-
-    return ref
-  end
-
-  return context
-end
diff --git a/test/busted/core.lua b/test/busted/core.lua
deleted file mode 100644 (file)
index 802e60c..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-local getfenv = require 'busted.compatibility'.getfenv
-local setfenv = require 'busted.compatibility'.setfenv
-local unpack = require 'busted.compatibility'.unpack
-local path = require 'pl.path'
-local pretty = require 'pl.pretty'
-local throw = error
-
-local failureMt = {
-  __index = {},
-  __tostring = function(e) return tostring(e.message) end,
-  __type = 'failure'
-}
-
-local failureMtNoString = {
-  __index = {},
-  __type = 'failure'
-}
-
-local pendingMt = {
-  __index = {},
-  __tostring = function(p) return p.message end,
-  __type = 'pending'
-}
-
-local function metatype(obj)
-  local otype = type(obj)
-  return otype == 'table' and (getmetatable(obj) or {}).__type or otype
-end
-
-local function hasToString(obj)
-  return type(obj) == 'string' or (getmetatable(obj) or {}).__tostring
-end
-
-return function()
-  local mediator = require 'mediator'()
-
-  local busted = {}
-  busted.version = '2.0.rc6-0'
-
-  local root = require 'busted.context'()
-  busted.context = root.ref()
-
-  local environment = require 'busted.environment'(busted.context)
-  busted.environment = {
-    set = environment.set,
-
-    wrap = function(callable)
-      if (type(callable) == 'function' or getmetatable(callable).__call) then
-        -- prioritize __call if it exists, like in files
-        environment.wrap((getmetatable(callable) or {}).__call or callable)
-      end
-    end
-  }
-
-  busted.executors = {}
-  local executors = {}
-
-  busted.status = require 'busted.status'
-
-  function busted.getTrace(element, level, msg)
-    level = level or  3
-
-    local thisdir = path.dirname(debug.getinfo(1, 'Sl').source)
-    local info = debug.getinfo(level, 'Sl')
-    while info.what == 'C' or info.short_src:match('luassert[/\\].*%.lua$') or
-          (info.source:sub(1,1) == '@' and thisdir == path.dirname(info.source)) do
-      level = level + 1
-      info = debug.getinfo(level, 'Sl')
-    end
-
-    info.traceback = debug.traceback('', level)
-    info.message = msg
-
-    local file = busted.getFile(element)
-    return file.getTrace(file.name, info)
-  end
-
-  function busted.rewriteMessage(element, message, trace)
-    local file = busted.getFile(element)
-    local msg = hasToString(message) and tostring(message)
-    msg = msg or (message ~= nil and pretty.write(message) or 'Nil error')
-    msg = (file.rewriteMessage and file.rewriteMessage(file.name, msg) or msg)
-
-    local hasFileLine = msg:match('^[^\n]-:%d+: .*')
-    if not hasFileLine then
-      local trace = trace or busted.getTrace(element, 3, message)
-      local fileline = trace.short_src .. ':' .. trace.currentline .. ': '
-      msg = fileline .. msg
-    end
-
-    return msg
-  end
-
-  function busted.publish(...)
-    return mediator:publish(...)
-  end
-
-  function busted.subscribe(...)
-    return mediator:subscribe(...)
-  end
-
-  function busted.getFile(element)
-    local parent = busted.context.parent(element)
-
-    while parent do
-      if parent.file then
-        local file = parent.file[1]
-        return {
-          name = file.name,
-          getTrace = file.run.getTrace,
-          rewriteMessage = file.run.rewriteMessage
-        }
-      end
-
-      if parent.descriptor == 'file' then
-        return {
-          name = parent.name,
-          getTrace = parent.run.getTrace,
-          rewriteMessage = parent.run.rewriteMessage
-        }
-      end
-
-      parent = busted.context.parent(parent)
-    end
-
-    return parent
-  end
-
-  function busted.fail(msg, level)
-    local rawlevel = (type(level) ~= 'number' or level <= 0) and level
-    local level = level or 1
-    local _, emsg = pcall(throw, msg, rawlevel or level+2)
-    local e = { message = emsg }
-    setmetatable(e, hasToString(msg) and failureMt or failureMtNoString)
-    throw(e, rawlevel or 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) or {}).__call or callable
-    setmetatable(env, { __index = getfenv(f) })
-    env.error = busted.fail
-    setfenv(f, env)
-  end
-
-  function busted.safe(descriptor, run, element)
-    busted.context.push(element)
-    local trace, message
-    local status = 'success'
-
-    local ret = { xpcall(run, function(msg)
-      local errType = metatype(msg)
-      status = ((errType == 'pending' or errType == 'failure') and errType or 'error')
-      trace = busted.getTrace(element, 3, msg)
-      message = busted.rewriteMessage(element, msg, trace)
-    end) }
-
-    if not ret[1] then
-      busted.publish({ status, descriptor }, element, busted.context.parent(element), message, trace)
-    end
-    ret[1] = busted.status(status)
-
-    busted.context.pop()
-    return unpack(ret)
-  end
-
-  function busted.register(descriptor, executor)
-    executors[descriptor] = executor
-
-    local publisher = function(name, fn)
-      if not fn and type(name) == 'function' then
-        fn = name
-        name = nil
-      end
-
-      local trace
-
-      local ctx = busted.context.get()
-      if busted.context.parent(ctx) then
-        trace = busted.getTrace(ctx, 3, name)
-      end
-
-      local publish = function(f)
-        busted.publish({ 'register', descriptor }, name, f, trace)
-      end
-
-      if fn then publish(fn) else return publish end
-    end
-
-    busted.executors[descriptor] = publisher
-    if descriptor ~= 'file' then
-      environment.set(descriptor, publisher)
-    end
-
-    busted.subscribe({ 'register', descriptor }, function(name, fn, trace)
-      local ctx = busted.context.get()
-      local plugin = {
-        descriptor = descriptor,
-        name = name,
-        run = fn,
-        trace = trace
-      }
-
-      busted.context.attach(plugin)
-
-      if not ctx[descriptor] then
-        ctx[descriptor] = { plugin }
-      else
-        ctx[descriptor][#ctx[descriptor]+1] = plugin
-      end
-    end)
-  end
-
-  function busted.alias(alias, descriptor)
-    local publisher = busted.executors[descriptor]
-    busted.executors[alias] = publisher
-    environment.set(alias, publisher)
-  end
-
-  function busted.execute(current)
-    if not current then current = busted.context.get() end
-    for _, v in pairs(busted.context.children(current)) do
-      local executor = executors[v.descriptor]
-      if executor and not busted.skipAll then
-        busted.safe(v.descriptor, function() executor(v) end, v)
-      end
-    end
-  end
-
-  return busted
-end
diff --git a/test/busted/done.lua b/test/busted/done.lua
deleted file mode 100644 (file)
index e631904..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-local M = {}
-
--- adds tokens to the current wait list, does not change order/unordered
-M.wait = function(self, ...)
-  local tlist = { ... }
-
-  for _, token in ipairs(tlist) do
-    if type(token) ~= 'string' then
-      error('Wait tokens must be strings. Got '..type(token), 2)
-    end
-    table.insert(self.tokens, token)
-  end
-end
-
--- set list as unordered, adds tokens to current wait list
-M.wait_unordered = function(self, ...)
-  self.ordered = false
-  self:wait(...)
-end
-
--- set list as ordered, adds tokens to current wait list
-M.wait_ordered = function(self, ...)
-  self.ordered = true
-  self:wait(...)
-end
-
--- generates a message listing tokens received/open
-M.tokenlist = function(self)
-  local list
-
-  if #self.tokens_done == 0 then
-    list = 'No tokens received.'
-  else
-    list = 'Tokens received ('..tostring(#self.tokens_done)..')'
-    local s = ': '
-
-    for _,t in ipairs(self.tokens_done) do
-      list = list .. s .. '\''..t..'\''
-      s = ', '
-    end
-
-    list = list .. '.'
-  end
-
-  if #self.tokens == 0 then
-    list = list .. ' No more tokens expected.'
-  else
-    list = list .. ' Tokens not received ('..tostring(#self.tokens)..')'
-    local s = ': '
-
-    for _, t in ipairs(self.tokens) do
-      list = list .. s .. '\''..t..'\''
-      s = ', '
-    end
-
-    list = list .. '.'
-  end
-
-  return list
-end
-
--- marks a token as completed, checks for ordered/unordered, checks for completeness
-M.done = function(self, ...) self:_done(...) end  -- extra wrapper for same error level constant as __call method
-M._done = function(self, token)
-  if token then
-    if type(token) ~= 'string' then
-      error('Wait tokens must be strings. Got '..type(token), 3)
-    end
-
-    if self.ordered then
-      if self.tokens[1] == token then
-        table.remove(self.tokens, 1)
-        table.insert(self.tokens_done, token)
-      else
-        if self.tokens[1] then
-          error(('Bad token, expected \'%s\' got \'%s\'. %s'):format(self.tokens[1], token, self:tokenlist()), 3)
-        else
-          error(('Bad token (no more tokens expected) got \'%s\'. %s'):format(token, self:tokenlist()), 3)
-        end
-      end
-    else
-      -- unordered
-      for i, t in ipairs(self.tokens) do
-        if t == token then
-          table.remove(self.tokens, i)
-          table.insert(self.tokens_done, token)
-          token = nil
-          break
-        end
-      end
-
-      if token then
-        error(('Unknown token \'%s\'. %s'):format(token, self:tokenlist()), 3)
-      end
-    end
-  end
-  if not next(self.tokens) then
-    -- no more tokens, so we're really done...
-    self.done_cb()
-  end
-end
-
-
--- wraps a done callback into a done-object supporting tokens to sign-off
-M.new = function(done_callback)
-  local obj = {
-    tokens = {},
-    tokens_done = {},
-    done_cb = done_callback,
-    ordered = true,  -- default for sign off of tokens
-  }
-
-  return setmetatable( obj, {
-    __call = function(self, ...)
-      self:_done(...)
-    end,
-    __index = M,
-  })
-end
-
-return M
diff --git a/test/busted/environment.lua b/test/busted/environment.lua
deleted file mode 100644 (file)
index 686b138..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-local setfenv = require 'busted.compatibility'.setfenv
-
-return function(context)
-
-  local environment = {}
-
-  local function getEnv(self, key)
-    if not self then return nil end
-    return
-      self.env and self.env[key] or
-      getEnv(context.parent(self), key) or
-      _G[key]
-  end
-
-  local function setEnv(self, key, value)
-    if not self.env then self.env = {} end
-    self.env[key] = value
-  end
-
-  local function __index(self, key)
-    return getEnv(context.get(), key)
-  end
-
-  local function __newindex(self, key, value)
-    setEnv(context.get(), key, value)
-  end
-
-  local env = setmetatable({}, { __index=__index, __newindex=__newindex })
-
-  function environment.wrap(fn)
-    return setfenv(fn, env)
-  end
-
-  function environment.set(key, value)
-    local env = context.get('env')
-
-    if not env then
-      env = {}
-      context.set('env', env)
-    end
-
-    env[key] = value
-  end
-  return environment
-end
diff --git a/test/busted/init.lua b/test/busted/init.lua
deleted file mode 100644 (file)
index da052f5..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-local unpack = require 'busted.compatibility'.unpack
-local shuffle = require 'busted.utils'.shuffle
-
-local function sort(elements)
-  table.sort(elements, function(t1, t2)
-    if t1.name and t2.name then
-      return t1.name < t2.name
-    end
-    return t2.name ~= nil
-  end)
-  return elements
-end
-
-local function remove(descriptors, element)
-  for _, descriptor in ipairs(descriptors) do
-    element.env[descriptor] = function(...)
-      error("'" .. descriptor .. "' not supported inside current context block", 2)
-    end
-  end
-end
-
-local function init(busted)
-  local function exec(descriptor, element)
-    if not element.env then element.env = {} end
-
-    remove({ 'randomize' }, element)
-    remove({ 'pending' }, element)
-    remove({ 'describe', 'context', 'it', 'spec', 'test' }, element)
-    remove({ 'setup', 'teardown', 'before_each', 'after_each' }, element)
-
-    local parent = busted.context.parent(element)
-    setmetatable(element.env, {
-      __newindex = function(self, key, value)
-        if not parent.env then parent.env = {} end
-        parent.env[key] = value
-      end
-    })
-
-    local ret = { busted.safe(descriptor, element.run, element) }
-    return unpack(ret)
-  end
-
-  local function execAll(descriptor, current, propagate)
-    local parent = busted.context.parent(current)
-
-    if propagate and parent then
-      local success, ancestor = execAll(descriptor, parent, propagate)
-      if not success then
-        return success, ancestor
-      end
-    end
-
-    local list = current[descriptor] or {}
-
-    local success = true
-    for _, v in pairs(list) do
-      if not exec(descriptor, v):success() then
-        success = nil
-      end
-    end
-    return success, current
-  end
-
-  local function dexecAll(descriptor, current, propagate)
-    local parent = busted.context.parent(current)
-    local list = current[descriptor] or {}
-
-    local success = true
-    for _, v in pairs(list) do
-      if not exec(descriptor, v):success() then
-        success = nil
-      end
-    end
-
-    if propagate and parent then
-      if not dexecAll(descriptor, parent, propagate) then
-        success = nil
-      end
-    end
-    return success
-  end
-
-  local file = function(file)
-    busted.publish({ 'file', 'start' }, file.name)
-
-    busted.environment.wrap(file.run)
-    if not file.env then file.env = {} end
-
-    local randomize = busted.randomize
-    file.env.randomize = function() randomize = true end
-
-    if busted.safe('file', file.run, file):success() then
-      if randomize then
-        file.randomseed = busted.randomseed
-        shuffle(busted.context.children(file), busted.randomseed)
-      elseif busted.sort then
-        sort(busted.context.children(file))
-      end
-      if execAll('setup', file) then
-        busted.execute(file)
-      end
-      dexecAll('teardown', file)
-    end
-
-    busted.publish({ 'file', 'end' }, file.name)
-  end
-
-  local describe = function(describe)
-    local parent = busted.context.parent(describe)
-
-    busted.publish({ 'describe', 'start' }, describe, parent)
-
-    if not describe.env then describe.env = {} end
-
-    local randomize = busted.randomize
-    describe.env.randomize = function() randomize = true end
-
-    if busted.safe('describe', describe.run, describe):success() then
-      if randomize then
-        describe.randomseed = busted.randomseed
-        shuffle(busted.context.children(describe), busted.randomseed)
-      elseif busted.sort then
-        sort(busted.context.children(describe))
-      end
-      if execAll('setup', describe) then
-        busted.execute(describe)
-      end
-      dexecAll('teardown', describe)
-    end
-
-    busted.publish({ 'describe', 'end' }, describe, parent)
-  end
-
-  local it = function(element)
-    local parent = busted.context.parent(element)
-    local finally
-
-    busted.publish({ 'test', 'start' }, element, parent)
-
-    if not element.env then element.env = {} end
-
-    remove({ 'randomize' }, element)
-    remove({ 'describe', 'context', 'it', 'spec', 'test' }, element)
-    remove({ 'setup', 'teardown', 'before_each', 'after_each' }, element)
-    element.env.finally = function(fn) finally = fn end
-    element.env.pending = function(msg) busted.pending(msg) end
-
-    local status = busted.status('success')
-    local updateErrorStatus = function(descriptor)
-      if element.message then element.message = element.message .. '\n' end
-      element.message = (element.message or '') .. 'Error in ' .. descriptor
-      status:update('error')
-    end
-
-    local pass, ancestor = execAll('before_each', parent, true)
-    if pass then
-      status:update(busted.safe('it', element.run, element))
-    else
-      updateErrorStatus('before_each')
-    end
-
-    if not element.env.done then
-      remove({ 'pending' }, element)
-      if finally then status:update(busted.safe('finally', finally, element)) end
-      if not dexecAll('after_each', ancestor, true) then
-        updateErrorStatus('after_each')
-      end
-
-      busted.publish({ 'test', 'end' }, element, parent, tostring(status))
-    end
-  end
-
-  local pending = function(element)
-    local parent = busted.context.parent(element)
-    busted.publish({ 'test', 'start' }, element, parent)
-    busted.publish({ 'test', 'end' }, element, parent, 'pending')
-  end
-
-  busted.register('file', file)
-
-  busted.register('describe', describe)
-
-  busted.register('it', it)
-
-  busted.register('pending', pending)
-
-  busted.register('setup')
-  busted.register('teardown')
-  busted.register('before_each')
-  busted.register('after_each')
-
-  busted.alias('context', 'describe')
-  busted.alias('spec', 'it')
-  busted.alias('test', 'it')
-
-  local assert = require 'luassert'
-  local spy    = require 'luassert.spy'
-  local mock   = require 'luassert.mock'
-  local stub   = require 'luassert.stub'
-
-  busted.environment.set('assert', assert)
-  busted.environment.set('spy', spy)
-  busted.environment.set('mock', mock)
-  busted.environment.set('stub', stub)
-
-  busted.replaceErrorWithFail(assert)
-  busted.replaceErrorWithFail(assert.True)
-
-  return busted
-end
-
-return setmetatable({}, {
-  __call = function(self, busted)
-    local root = busted.context.get()
-    init(busted)
-
-    return setmetatable(self, {
-      __index = function(self, key)
-        return rawget(root.env, key) or busted.executors[key]
-      end,
-
-      __newindex = function(self, key, value)
-        error('Attempt to modify busted')
-      end
-    })
-  end
-})
diff --git a/test/busted/languages/ar.lua b/test/busted/languages/ar.lua
deleted file mode 100644 (file)
index d0b96e6..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-local s = require('say')
-
-s:set_namespace('ar')
-
--- 'Pending: test.lua @ 12 \n description
-s:set('output.pending', 'عالِق')
-s:set('output.failure', 'فَشَل')
-s:set('output.failure', 'نَجاح')
-
-s:set('output.pending_plural', 'عالِق')
-s:set('output.failure_plural', 'إخْفاقات')
-s:set('output.success_plural', 'نَجاحات')
-
-s:set('output.pending_zero', 'عالِق')
-s:set('output.failure_zero', 'إخْفاقات')
-s:set('output.success_zero', 'نَجاحات')
-
-s:set('output.pending_single', 'عالِق')
-s:set('output.failure_single', 'فَشَل')
-s:set('output.success_single', 'نَجاح')
-
-s:set('output.seconds', 'ثَوانٍ')
-
--- definitions following are not used within the 'say' namespace
-return {
-  failure_messages = {
-    'فَشِلَت %d مِنْ الإِختِبارات',
-    'فَشِلَت إخْتِباراتُك',
-    'برمجيَّتُكَ ضَعيْفة، أنْصَحُكَ بالتَّقاعُد',
-    'تقع برمجيَّتُكَ في مَنطِقَةِ الخَطَر',
-    'أقترِحُ ألّا تَتَقَدَّم بالإختِبار، علَّ يبْقى الطابِقُ مَستوراَ',
-    'جَدَّتي، فِي أَثْناءِ نَومِها، تَكتبُ بَرمَجياتٍ أفْضلُ مِن هذه',
-    'يَوَدُّ ليْ مُساعَدَتُكْ، لَكِنّْ...'
-  },
-  success_messages = {
-    'رائِع! تَمَّ إجْتِيازُ جَميعُ الإختِباراتِ بِنَجاحٍ',
-    'قُل ما شِئت، لا أكتَرِث: busted شَهِدَ لي!',
-    'حَقَّ عَليْكَ الإفتِخار',
-    'نَجاحٌ مُبْهِر!',
-    'عَليكَ بالإحتِفال؛ نَجَحَت جَميعُ التَجارُب'
-  }
-}
diff --git a/test/busted/languages/de.lua b/test/busted/languages/de.lua
deleted file mode 100644 (file)
index e624a46..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-local s = require('say')
-
-s:set_namespace('de')
-
--- 'Pending: test.lua @ 12 \n description
-s:set('output.pending', 'Noch nicht erledigt')
-s:set('output.failure', 'Fehlgeschlagen')
-s:set('output.success', 'Erfolgreich')
-
-s:set('output.pending_plural', 'übersprungen')
-s:set('output.failure_plural', 'fehlgeschlagen')
-s:set('output.success_plural', 'erfolgreich')
-
-s:set('output.pending_zero', 'übersprungen')
-s:set('output.failure_zero', 'fehlgeschlagen')
-s:set('output.success_zero', 'erfolgreich')
-
-s:set('output.pending_single', 'übersprungen')
-s:set('output.failure_single', 'fehlgeschlagen')
-s:set('output.success_single', 'erfolgreich')
-
-s:set('output.seconds', 'Sekunden')
-
--- definitions following are not used within the 'say' namespace
-return {
-  failure_messages = {
-    'Du hast %d kaputte Tests.',
-    'Deine Tests sind kaputt.',
-    'Dein Code ist schlecht; du solltest dich schlecht fühlen.',
-    'Dein Code befindet sich in der Gefahrenzone.',
-    'Ein seltsames Spiel. Der einzig gewinnbringende Zug ist nicht zu testen.',
-    'Meine Großmutter hat auf einem 386er bessere Tests geschrieben.',
-    'Immer wenn ein Test fehlschlägt, stirbt ein kleines Kätzchen.',
-    'Das fühlt sich schlecht an, oder?'
-  },
-  success_messages = {
-    'Yeah, die Tests laufen durch.',
-    'Fühlt sich gut an, oder?',
-    'Großartig!',
-    'Tests sind durchgelaufen, Zeit für ein Bier.',
-  }
-}
diff --git a/test/busted/languages/en.lua b/test/busted/languages/en.lua
deleted file mode 100644 (file)
index 285d1ba..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-local s = require('say')
-
-s:set_namespace('en')
-
--- 'Pending: test.lua @ 12 \n description
-s:set('output.pending', 'Pending')
-s:set('output.failure', 'Failure')
-s:set('output.error', 'Error')
-s:set('output.success', 'Success')
-
-s:set('output.pending_plural', 'pending')
-s:set('output.failure_plural', 'failures')
-s:set('output.error_plural', 'errors')
-s:set('output.success_plural', 'successes')
-
-s:set('output.pending_zero', 'pending')
-s:set('output.failure_zero', 'failures')
-s:set('output.error_zero', 'errors')
-s:set('output.success_zero', 'successes')
-
-s:set('output.pending_single', 'pending')
-s:set('output.failure_single', 'failure')
-s:set('output.error_single', 'error')
-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')
-
--- definitions following are not used within the 'say' namespace
-return {
-  failure_messages = {
-    'You have %d busted specs',
-    'Your specs are busted',
-    'Your code is bad and you should feel bad',
-    'Your code is in the Danger Zone',
-    'Strange game. The only way to win is not to test',
-    'My grandmother wrote better specs on a 3 86',
-    'Every time there\'s a failure, drink another beer',
-    'Feels bad man'
-  },
-  success_messages = {
-    'Aww yeah, passing specs',
-    'Doesn\'t matter, had specs',
-    'Feels good, man',
-    'Great success',
-    'Tests pass, drink another beer',
-  }
-}
diff --git a/test/busted/languages/fr.lua b/test/busted/languages/fr.lua
deleted file mode 100644 (file)
index 236d87c..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-local s = require('say')
-
-s:set_namespace('fr')
-
--- 'Pending: test.lua @ 12 \n description
-s:set('output.pending', 'En attente')
-s:set('output.failure', 'Echec')
-s:set('output.success', 'Reussite')
-
-s:set('output.pending_plural', 'en attente')
-s:set('output.failure_plural', 'echecs')
-s:set('output.success_plural', 'reussites')
-
-s:set('output.pending_zero', 'en attente')
-s:set('output.failure_zero', 'echec')
-s:set('output.success_zero', 'reussite')
-
-s:set('output.pending_single', 'en attente')
-s:set('output.failure_single', 'echec')
-s:set('output.success_single', 'reussite')
-
-s:set('output.seconds', 'secondes')
-
-s:set('output.no_test_files_match', 'Aucun test n\'est pourrait trouvé qui corresponde au motif de Lua: %s')
-
--- definitions following are not used within the 'say' namespace
-return {
-  failure_messages = {
-    'Vous avez %d test(s) qui a/ont echoue(s)',
-    'Vos tests ont echoue.',
-    'Votre code source est mauvais et vous devrez vous sentir mal',
-    'Vous avez un code source de Destruction Massive',
-    'Jeu plutot etrange game. Le seul moyen de gagner est de ne pas l\'essayer',
-    'Meme ma grand-mere ecrivait de meilleurs tests sur un PIII x86',
-    'A chaque erreur, prenez une biere',
-    'Ca craint, mon pote'
-  },
-  success_messages = {
-    'Oh yeah, tests reussis',
-    'Pas grave, y\'a eu du succes',
-    'C\'est du bon, mon pote. Que du bon!',
-    'Reussi, haut la main!',
-    'Test reussi. Un de plus. Offre toi une biere, sur mon compte!',
-  }
-}
diff --git a/test/busted/languages/ja.lua b/test/busted/languages/ja.lua
deleted file mode 100644 (file)
index d726fa8..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-local s = require('say')
-
-s:set_namespace('ja')
-
--- 'Pending: test.lua @ 12 \n description
-s:set('output.pending', '保留')
-s:set('output.failure', '失敗')
-s:set('output.success', '成功')
-
-s:set('output.pending_plural', '保留')
-s:set('output.failure_plural', '失敗')
-s:set('output.success_plural', '成功')
-
-s:set('output.pending_zero', '保留')
-s:set('output.failure_zero', '失敗')
-s:set('output.success_zero', '成功')
-
-s:set('output.pending_single', '保留')
-s:set('output.failure_single', '失敗')
-s:set('output.success_single', '成功')
-
-s:set('output.seconds', '秒')
-
--- definitions following are not used within the 'say' namespace
-return {
-  failure_messages = {
-    '%d個の仕様が破綻しています',
-    '仕様が破綻しています',
-    'あなたの書くコードは良くないので反省するべきです',
-    'あなたの書くコードは危険地帯にあります',
-    'おかしなゲームです。勝利する唯一の方法はテストをしないことです',
-    '私の祖母でもPentium Pentium III x86の上でもっといいコードを書いていましたよ',
-    'いつも失敗しているのでビールでも飲みましょう',
-    '罪悪感を持ちましょう',
-  },
-  success_messages = {
-    'オォーイェー、テストが通った',
-    '問題ない、テストがある',
-    '順調ですね',
-    '大成功',
-    'テストが通ったし、ビールでも飲もう',
-  }
-}
diff --git a/test/busted/languages/nl.lua b/test/busted/languages/nl.lua
deleted file mode 100644 (file)
index 6173320..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-local s = require('say')
-
-s:set_namespace('nl')
-
--- 'Pending: test.lua @ 12 \n description
-s:set('output.pending', 'Hangend')
-s:set('output.failure', 'Mislukt')
-s:set('output.success', 'Succes')
-
-s:set('output.pending_plural', 'hangenden')
-s:set('output.failure_plural', 'mislukkingen')
-s:set('output.success_plural', 'successen')
-
-s:set('output.pending_zero', 'hangend')
-s:set('output.failure_zero', 'mislukt')
-s:set('output.success_zero', 'successen')
-
-s:set('output.pending_single', 'hangt')
-s:set('output.failure_single', 'mislukt')
-s:set('output.success_single', 'succes')
-
-s:set('output.seconds', 'seconden')
-
--- definitions following are not used within the 'say' namespace
-return {
-  failure_messages = {
-    'Je hebt %d busted specs',
-    'Je specs zijn busted',
-    'Je code is slecht en zo zou jij je ook moeten voelen',
-    'Je code zit in de Gevaren Zone',
-    'Vreemd spelletje. The enige manier om te winnen is door niet te testen',
-    'Mijn oma schreef betere specs op een 3 86',
-    'Elke keer dat iets mislukt, nog een biertje drinken',
-    'Voelt klote man'
-  },
-  success_messages = {
-    'Joeperdepoep, de specs zijn er door',
-    'Doet er niet toe, had specs',
-    'Voelt goed, man',
-    'Fantastisch success',
-    'Testen geslaagd, neem nog een biertje',
-  }
-}
diff --git a/test/busted/languages/ru.lua b/test/busted/languages/ru.lua
deleted file mode 100644 (file)
index d0f4034..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-local s = require('say')
-
-s:set_namespace('ru')
-
--- 'Pending: test.lua @ 12 \n description
-s:set('output.pending', 'Ожидает')
-s:set('output.failure', 'Поломалcя')
-s:set('output.success', 'Прошeл')
-
-s:set('output.pending_plural', 'ожидают')
-s:set('output.failure_plural', 'поломалиcь')
-s:set('output.success_plural', 'прошли')
-
-s:set('output.pending_zero', 'ожидающих')
-s:set('output.failure_zero', 'поломанных')
-s:set('output.success_zero', 'прошедших')
-
-s:set('output.pending_single', 'ожидает')
-s:set('output.failure_single', 'поломался')
-s:set('output.success_single', 'прошел')
-
-s:set('output.seconds', 'секунд')
-
----- definitions following are not used within the 'say' namespace
-return {
-  failure_messages = {
-    'У тебя %d просратых тестов',
-    'Твои тесты поломаны',
-    'Твой код говеный - пойди напейся!'
-  },
-  success_messages = {
-    'Поехали!',
-    'Жизнь - хороша!',
-    'Ффух в этот раз пронесло!',
-    'Ура!'
-  }
-}
diff --git a/test/busted/languages/th.lua b/test/busted/languages/th.lua
deleted file mode 100644 (file)
index 0f8e0a1..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-local s = require('say')
-
-s:set_namespace('th')
-
--- 'Pending: test.lua @ 12 \n description
-s:set('output.pending', 'อยู่ระหว่างดำเนินการ')
-s:set('output.failure', 'ล้มเหลว')
-s:set('output.success', 'สำเร็จ')
-
-s:set('output.pending_plural', 'อยู่ระหว่างดำเนินการ')
-s:set('output.failure_plural', 'ล้มเหลว')
-s:set('output.success_plural', 'สำเร็จ')
-
-s:set('output.pending_zero', 'อยู่ระหว่างดำเนินการ')
-s:set('output.failure_zero', 'ล้มเหลว')
-s:set('output.success_zero', 'สำเร็จ')
-
-s:set('output.pending_single', 'อยู่ระหว่างดำเนินการ')
-s:set('output.failure_single', 'ล้มเหลว')
-s:set('output.success_single', 'สำเร็จ')
-
-s:set('output.seconds', 'วินาที')
-
--- definitions following are not used within the 'say' namespace
-return {
-  failure_messages = {
-    'คุณมี %d บัสเต็ดสเปค',
-    'สเปคของคุณคือ บัสเต็ด',
-    'โค้ดของคุณไม่ดีเลย คุณควรรู้สึกแย่น่ะ',
-    'โค้ดของคุณอยู่ในเขตอันตราย!',
-    'มันแปลกๆน่ะ วิธีที่จะชนะไม่ได้มีแค่เทสอย่างเดียว',
-    'ยายผมเขียนสเปคดีกว่านี้อีก บนเครื่อง 386',
-    'ทุกๆครั้งที่ล้มเหลว, ดื่มเบียร์แก้วใหม่',
-    'แย่จัง นายท่าน'
-  },
-  success_messages = {
-    'อุ๊ตะ!!!, สเปคผ่าน!',
-    'ไม่สำคัญ, มีสเปค',
-    'ฟินเลยดิ นายท่าน',
-    'สำเร็จ ยอดเยี่ยม',
-    'เทสผ่าน, ดื่มเบียร์ๆๆๆ',
-  }
-}
diff --git a/test/busted/languages/ua.lua b/test/busted/languages/ua.lua
deleted file mode 100644 (file)
index 40afcfb..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-local s = require('say')
-
-s:set_namespace('ua')
-
--- 'Pending: test.lua @ 12 \n description
-s:set('output.pending', 'Очікує')
-s:set('output.failure', 'Зламався')
-s:set('output.success', 'Пройшов')
-
-s:set('output.pending_plural', 'очікують')
-s:set('output.failure_plural', 'зламались')
-s:set('output.success_plural', 'пройшли')
-
-s:set('output.pending_zero', 'очікуючих')
-s:set('output.failure_zero', 'зламаних')
-s:set('output.success_zero', 'пройдених')
-
-s:set('output.pending_single', 'очікує')
-s:set('output.failure_single', 'зламався')
-s:set('output.success_single', 'пройшов')
-
-s:set('output.seconds', 'секунд')
-
-
----- definitions following are not used within the 'say' namespace
-return {
-  failure_messages = {
-    'Ти зрадив %d тестів!',
-    'Ой йо..',
-    'Вороги поламали наші тести!'
-  },
-  success_messages = {
-    'Слава Україні! Героям Слава!',
-    'Тестування успішно пройдено!',
-    'Всі баги знищено!'
-  }
-}
diff --git a/test/busted/languages/zh.lua b/test/busted/languages/zh.lua
deleted file mode 100644 (file)
index 21f97e5..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-local s = require('say')
-
-s:set_namespace('zh')
-
--- 'Pending: test.lua @ 12 \n description
-s:set('output.pending', '开发中')
-s:set('output.failure', '失败')
-s:set('output.success', '成功')
-
-s:set('output.pending_plural', '开发中')
-s:set('output.failure_plural', '失败')
-s:set('output.success_plural', '成功')
-
-s:set('output.pending_zero', '开发中')
-s:set('output.failure_zero', '失败')
-s:set('output.success_zero', '成功')
-
-s:set('output.pending_single', '开发中')
-s:set('output.failure_single', '失败')
-s:set('output.success_single', '成功')
-
-s:set('output.seconds', '秒')
-
--- definitions following are not used within the 'say' namespace 
-return {
-  failure_messages = {
-    '你一共提交了[%d]个测试用例',
-    '又出错了!',
-    '到底哪里不对呢?',
-    '出错了,又要加班了!',
-    '囧,出Bug了!',
-    '据说比尔盖兹也写了一堆Bug,别灰心!',
-    '又出错了,休息一下吧',
-    'Bug好多,心情好坏!'
-  },
-  success_messages = {
-    '牛X,测试通过了!',
-    '测试通过了,感觉不错吧,兄弟!',
-    '哥们,干得漂亮!',
-    '终于通过了!干一杯先!',
-    '阿弥陀佛~,菩萨显灵了!',
-  }
-}
diff --git a/test/busted/modules/configuration_loader.lua b/test/busted/modules/configuration_loader.lua
deleted file mode 100644 (file)
index f437a04..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-return function()
-  local tablex = require 'pl.tablex'
-
-  -- Function to load the .busted configuration file if available
-  local loadBustedConfigurationFile = function(configFile, config, defaults)
-    if type(configFile) ~= 'table' then
-      return config, '.busted file does not return a table.'
-    end
-
-    local defaults = defaults or {}
-    local run = config.run or defaults.run
-
-    if run and run ~= '' then
-      local runConfig = configFile[run]
-
-      if type(runConfig) == 'table' then
-        config = tablex.merge(runConfig, config, true)
-      else
-        return config, 'Task `' .. run .. '` not found, or not a table.'
-      end
-    end
-
-    if type(configFile.default) == 'table' then
-      config = tablex.merge(configFile.default, config, true)
-    end
-
-    config = tablex.merge(defaults, config, true)
-
-    return config
-  end
-
-  return loadBustedConfigurationFile
-end
-
diff --git a/test/busted/modules/files/lua.lua b/test/busted/modules/files/lua.lua
deleted file mode 100644 (file)
index a4218f6..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-local path = require 'pl.path'
-
-local ret = {}
-
-local getTrace =  function(filename, info)
-  local index = info.traceback:find('\n%s*%[C]')
-  info.traceback = info.traceback:sub(1, index)
-  return info, false
-end
-
-ret.match = function(busted, filename)
-  return path.extension(filename) == '.lua'
-end
-
-
-ret.load = function(busted, filename)
-  local file, err = loadfile(filename)
-  if not file then
-    busted.publish({ 'error', 'file' }, { descriptor = 'file', name = filename }, nil, err, {})
-  end
-  return file, getTrace
-end
-
-return ret
diff --git a/test/busted/modules/files/moonscript.lua b/test/busted/modules/files/moonscript.lua
deleted file mode 100644 (file)
index 145b942..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-local path = require 'pl.path'
-
-local ok, moonscript, line_tables, util = pcall(function()
-  return require 'moonscript', require 'moonscript.line_tables', require 'moonscript.util'
-end)
-
-local _cache = {}
-
--- find the line number of `pos` chars into fname
-local lookup_line = function(fname, pos)
-  if not _cache[fname] then
-    local f = io.open(fname)
-    _cache[fname] = f:read('*a')
-    f:close()
-  end
-
-  return util.pos_to_line(_cache[fname], pos)
-end
-
-local rewrite_linenumber = function(fname, lineno)
-  local tbl = line_tables['@' .. fname]
-  if fname and tbl then
-    for i = lineno, 0 ,-1 do
-      if tbl[i] then
-        return lookup_line(fname, tbl[i])
-      end
-    end
-  end
-
-  return lineno
-end
-
-local rewrite_filename = function(filename)
-  -- sometimes moonscript gives files like [string "./filename.moon"], so
-  -- we'll chop it up to only get the filename.
-  return filename:match('string "(.+)"') or filename
-end
-
-local rewrite_traceback = function(fname, trace)
-  local rewrite_one = function(line, pattern, sub)
-    if line == nil then return '' end
-
-    local fname, lineno = line:match(pattern)
-
-    if fname and lineno then
-      fname = rewrite_filename(fname)
-      local new_lineno = rewrite_linenumber(fname, tonumber(lineno))
-      if new_lineno then
-        line = line:gsub(sub:format(tonumber(lineno)), sub:format(tonumber(new_lineno)))
-      end
-    end
-
-    return line
-  end
-
-  local lines = {}
-  local j = 0
-
-  for line in trace:gmatch('[^\r\n]+') do
-    j = j + 1
-    line = rewrite_one(line, '%s*(.-):(%d+): ', ':%d:')
-    line = rewrite_one(line, '<(.*):(%d+)>', ':%d>')
-    lines[j] = line
-  end
-
-  return '\n' .. table.concat(lines, trace:match('[\r\n]+')) .. '\n'
-end
-
-local ret = {}
-
-local getTrace =  function(filename, info)
-  local index = info.traceback:find('\n%s*%[C]')
-  info.traceback = info.traceback:sub(1, index)
-
-  info.short_src = rewrite_filename(info.short_src)
-  info.traceback = rewrite_traceback(filename, info.traceback)
-  info.linedefined = rewrite_linenumber(filename, info.linedefined)
-  info.currentline = rewrite_linenumber(filename, info.currentline)
-
-  return info
-end
-
-local rewriteMessage = function(filename, message)
-  local fname, line, msg = message:match('^([^\n]-):(%d+): (.*)')
-  if not fname then
-    return message
-  end
-
-  fname = rewrite_filename(fname)
-  line = rewrite_linenumber(fname, tonumber(line))
-
-  return fname .. ':' .. tostring(line) .. ': ' .. msg
-end
-
-ret.match = function(busted, filename)
-  return ok and path.extension(filename) == '.moon'
-end
-
-
-ret.load = function(busted, filename)
-  local file, err = moonscript.loadfile(filename)
-  if not file then
-    busted.publish({ 'error', 'file' }, { descriptor = 'file', name = filename }, nil, err, {})
-  end
-  return file, getTrace, rewriteMessage
-end
-
-return ret
diff --git a/test/busted/modules/files/terra.lua b/test/busted/modules/files/terra.lua
deleted file mode 100644 (file)
index 02956f7..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-local path = require 'pl.path'
-
-local ret = {}
-local ok, terralib = pcall(function() return require 'terralib' end)
-
-local getTrace =  function(filename, info)
-  local index = info.traceback:find('\n%s*%[C]')
-  info.traceback = info.traceback:sub(1, index)
-  return info
-end
-
-ret.match = function(busted, filename)
-  return ok and path.extension(filename) == '.t'
-end
-
-ret.load = function(busted, filename)
-  local file, err = terralib.loadfile(filename)
-  if not file then
-    busted.publish({ 'error', 'file' }, { descriptor = 'file', name = filename }, nil, err, {})
-  end
-  return file, getTrace
-end
-
-return ret
diff --git a/test/busted/modules/helper_loader.lua b/test/busted/modules/helper_loader.lua
deleted file mode 100644 (file)
index 166f7cc..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-local utils = require 'busted.utils'
-local hasMoon, moonscript = pcall(require, 'moonscript')
-
-return function()
-  local loadHelper = function(helper, hpath, options, busted)
-    local success, err = pcall(function()
-      arg = options.arguments
-      if helper:match('%.lua$') then
-        dofile(utils.normpath(hpath))
-      elseif hasMoon and helper:match('%.moon$') then
-        moonscript.dofile(utils.normpath(hpath))
-      else
-        require(helper)
-      end
-    end)
-
-    if not success then
-      busted.publish({ 'error', 'helper' }, { descriptor = 'helper', name = helper }, nil, err, {})
-    end
-  end
-
-  return loadHelper
-end
diff --git a/test/busted/modules/luacov.lua b/test/busted/modules/luacov.lua
deleted file mode 100644 (file)
index 99cfc8f..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-return function()
-  -- Function to initialize luacov if available
-  local loadLuaCov = 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')
-    end
-
-    -- call it to start
-    luacov()
-
-    -- exclude busted files
-    table.insert(luacov.configuration.exclude, 'busted_bootstrap$')
-    table.insert(luacov.configuration.exclude, 'busted%.')
-    table.insert(luacov.configuration.exclude, 'luassert%.')
-    table.insert(luacov.configuration.exclude, 'say%.')
-    table.insert(luacov.configuration.exclude, 'pl%.')
-  end
-
-  return loadLuaCov
-end
diff --git a/test/busted/modules/output_handler_loader.lua b/test/busted/modules/output_handler_loader.lua
deleted file mode 100644 (file)
index d522118..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-local utils = require 'busted.utils'
-local hasMoon, moonscript = pcall(require, 'moonscript')
-
-return function()
-  local loadOutputHandler = function(output, opath, options, busted, defaultOutput)
-    local handler
-
-    local success, err = pcall(function()
-      if output:match('%.lua$') then
-        handler = dofile(utils.normpath(opath))
-      elseif hasMoon and output:match('%.moon$') then
-        handler = moonscript.dofile(utils.normpath(opath))
-      else
-        handler = require('busted.outputHandlers.' .. output)
-      end
-    end)
-
-    if not success and err:match("module '.-' not found:") then
-      success, err = pcall(function() handler = require(output) end)
-    end
-
-    if not success then
-      busted.publish({ 'error', 'output' }, { descriptor = 'output', name = output }, nil, err, {})
-      handler = require('busted.outputHandlers.' .. defaultOutput)
-    end
-
-    return handler(options, busted)
-  end
-
-  return loadOutputHandler
-end
diff --git a/test/busted/modules/test_file_loader.lua b/test/busted/modules/test_file_loader.lua
deleted file mode 100644 (file)
index 391cce5..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-local s = require 'say'
-
-return function(busted, loaders, options)
-  local path = require 'pl.path'
-  local dir = require 'pl.dir'
-  local tablex = require 'pl.tablex'
-  local shuffle = require 'busted.utils'.shuffle
-  local fileLoaders = {}
-
-  for _, v in pairs(loaders) do
-    local loader = require('busted.modules.files.'..v)
-    fileLoaders[#fileLoaders+1] = loader
-  end
-
-  local getTestFiles = function(rootFile, pattern)
-    local fileList
-
-    if path.isfile(rootFile) then
-      fileList = { rootFile }
-    elseif path.isdir(rootFile) then
-      local getfiles = options.recursive and dir.getallfiles or dir.getfiles
-      fileList = getfiles(rootFile)
-
-      fileList = tablex.filter(fileList, function(filename)
-        return path.basename(filename):find(pattern)
-      end)
-
-      fileList = tablex.filter(fileList, function(filename)
-        if path.is_windows then
-          return not filename:find('%\\%.%w+.%w+')
-        else
-          return not filename:find('/%.%w+.%w+')
-        end
-      end)
-    else
-      fileList = {}
-    end
-
-    return fileList
-  end
-
-  -- runs a testfile, loading its tests
-  local loadTestFile = function(busted, filename)
-    for _, v in pairs(fileLoaders) do
-      if v.match(busted, filename) then
-        return v.load(busted, filename)
-      end
-    end
-  end
-
-  local loadTestFiles = function(rootFile, pattern, loaders)
-    local fileList = getTestFiles(rootFile, pattern)
-
-    if options.shuffle then
-      shuffle(fileList, options.seed)
-    elseif options.sort then
-      table.sort(fileList)
-    end
-
-    for i, fileName in ipairs(fileList) do
-      local testFile, getTrace, rewriteMessage = loadTestFile(busted, fileName, loaders)
-
-      if testFile then
-        local file = setmetatable({
-          getTrace = getTrace,
-          rewriteMessage = rewriteMessage
-        }, {
-          __call = testFile
-        })
-
-        busted.executors.file(fileName, file)
-      end
-    end
-
-    if #fileList == 0 then
-      busted.publish({ 'error' }, {}, nil, s('output.no_test_files_match'):format(pattern), {})
-    end
-
-    return fileList
-  end
-
-  return loadTestFiles, loadTestFile, getTestFiles
-end
-
diff --git a/test/busted/outputHandlers/TAP.lua b/test/busted/outputHandlers/TAP.lua
deleted file mode 100644 (file)
index b46350e..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-local pretty = require 'pl.pretty'
-
-return function(options, busted)
-  local handler = require 'busted.outputHandlers.base'(busted)
-
-  handler.suiteEnd = function()
-    local total = handler.successesCount + handler.errorsCount + handler.failuresCount
-    print('1..' .. total)
-
-    local success = 'ok %u - %s'
-    local failure = 'not ' .. success
-    local counter = 0
-
-    for i,t in pairs(handler.successes) do
-      counter = counter + 1
-      print(success:format(counter, t.name))
-    end
-
-    local showFailure = function(t)
-      counter = counter + 1
-      local message = t.message
-      local trace = t.trace or {}
-
-      if message == nil then
-        message = 'Nil error'
-      elseif type(message) ~= 'string' then
-        message = pretty.write(message)
-      end
-
-      print(failure:format(counter, t.name))
-      print('# ' .. t.element.trace.short_src .. ' @ ' .. t.element.trace.currentline)
-      print('# Failure message: ' .. message:gsub('\n', '\n# '))
-      if options.verbose and trace.traceback then
-        print('# ' .. trace.traceback:gsub('^\n', '', 1):gsub('\n', '\n# '))
-      end
-    end
-
-    for i,t in pairs(handler.errors) do
-      showFailure(t)
-    end
-    for i,t in pairs(handler.failures) do
-      showFailure(t)
-    end
-
-    return nil, true
-  end
-
-  busted.subscribe({ 'suite', 'end' }, handler.suiteEnd)
-
-  return handler
-end
diff --git a/test/busted/outputHandlers/base.lua b/test/busted/outputHandlers/base.lua
deleted file mode 100644 (file)
index 5ea9540..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-return function(busted)
-  local handler = {
-    successes = {},
-    successesCount = 0,
-    pendings = {},
-    pendingsCount = 0,
-    failures = {},
-    failuresCount = 0,
-    errors = {},
-    errorsCount = 0,
-    inProgress = {}
-  }
-
-  handler.cancelOnPending = function(element, parent, status)
-    return not ((element.descriptor == 'pending' or status == 'pending') and handler.options.suppressPending)
-  end
-
-  handler.subscribe = function(handler, options)
-    require('busted.languages.en')
-    handler.options = options
-
-    if options.language ~= 'en' then
-      require('busted.languages.' .. options.language)
-    end
-
-    busted.subscribe({ 'suite', 'reinitialize' }, handler.baseSuiteRepeat, { priority = 1 })
-    busted.subscribe({ 'suite', 'start' }, handler.baseSuiteStart, { priority = 1 })
-    busted.subscribe({ 'suite', 'end' }, handler.baseSuiteEnd, { priority = 1 })
-    busted.subscribe({ 'test', 'start' }, handler.baseTestStart, { priority = 1, predicate = handler.cancelOnPending })
-    busted.subscribe({ 'test', 'end' }, handler.baseTestEnd, { priority = 1, predicate = handler.cancelOnPending })
-    busted.subscribe({ 'pending' }, handler.basePending, { priority = 1, predicate = handler.cancelOnPending })
-    busted.subscribe({ 'failure', 'it' }, handler.baseTestFailure, { priority = 1 })
-    busted.subscribe({ 'error', 'it' }, handler.baseTestError, { priority = 1 })
-    busted.subscribe({ 'failure' }, handler.baseError, { priority = 1 })
-    busted.subscribe({ 'error' }, handler.baseError, { priority = 1 })
-  end
-
-  handler.getFullName = function(context)
-    local parent = busted.context.parent(context)
-    local names = { (context.name or context.descriptor) }
-
-    while parent and (parent.name or parent.descriptor) and
-          parent.descriptor ~= 'file' do
-
-      table.insert(names, 1, parent.name or parent.descriptor)
-      parent = busted.context.parent(parent)
-    end
-
-    return table.concat(names, ' ')
-  end
-
-  handler.format = function(element, parent, message, debug, isError)
-    local formatted = {
-      trace = debug or element.trace,
-      element = element,
-      name = handler.getFullName(element),
-      message = message,
-      isError = isError
-    }
-    formatted.element.trace = element.trace or debug
-
-    return formatted
-  end
-
-  handler.getDuration = function()
-    if not handler.endTime or not handler.startTime then
-      return 0
-    end
-
-    return handler.endTime - handler.startTime
-  end
-
-  handler.baseSuiteStart = function()
-    handler.startTime = os.clock()
-    return nil, true
-  end
-
-  handler.baseSuiteRepeat = function()
-    handler.successes = {}
-    handler.successesCount = 0
-    handler.pendings = {}
-    handler.pendingsCount = 0
-    handler.failures = {}
-    handler.failuresCount = 0
-    handler.errors = {}
-    handler.errorsCount = 0
-    handler.inProgress = {}
-
-    return nil, true
-  end
-
-  handler.baseSuiteEnd = function()
-    handler.endTime = os.clock()
-    return nil, true
-  end
-
-  handler.baseTestStart = function(element, parent)
-    handler.inProgress[tostring(element)] = {}
-    return nil, true
-  end
-
-  handler.baseTestEnd = function(element, parent, status, debug)
-    local isError
-    local insertTable
-
-    if status == 'success' then
-      insertTable = handler.successes
-      handler.successesCount = handler.successesCount + 1
-    elseif status == 'pending' then
-      insertTable = handler.pendings
-      handler.pendingsCount = handler.pendingsCount + 1
-    elseif status == 'failure' then
-      insertTable = handler.failures
-      -- failure count already incremented in error handler
-    elseif status == 'error' then
-      -- error count already incremented in error handler
-      insertTable = handler.errors
-      isError = true
-    end
-
-    local formatted = handler.format(element, parent, element.message, debug, isError)
-
-    local id = tostring(element)
-    if handler.inProgress[id] then
-      for k, v in pairs(handler.inProgress[id]) do
-        formatted[k] = v
-      end
-
-      handler.inProgress[id] = nil
-    end
-
-    table.insert(insertTable, formatted)
-
-    return nil, true
-  end
-
-  local function saveInProgress(element, message, debug)
-    local id = tostring(element)
-    handler.inProgress[id].message = message
-    handler.inProgress[id].trace = debug
-  end
-
-  local function saveError(element, parent, message, debug)
-    if parent.randomseed then
-      message = 'Random Seed: ' .. parent.randomseed .. '\n' .. message
-    end
-    saveInProgress(element, message, debug)
-  end
-
-  handler.basePending = function(element, parent, message, debug)
-    saveInProgress(element, message, debug)
-    return nil, true
-  end
-
-  handler.baseTestFailure = function(element, parent, message, debug)
-    handler.failuresCount = handler.failuresCount + 1
-    saveError(element, parent, message, debug)
-    return nil, true
-  end
-
-  handler.baseTestError = function(element, parent, message, debug)
-    handler.errorsCount = handler.errorsCount + 1
-    saveError(element, parent, message, debug)
-    return nil, true
-  end
-
-  handler.baseError = function(element, parent, message, debug)
-    if element.descriptor ~= 'it' then
-      handler.errorsCount = handler.errorsCount + 1
-      table.insert(handler.errors, handler.format(element, parent, message, debug, true))
-    end
-
-    return nil, true
-  end
-
-  return handler
-end
diff --git a/test/busted/outputHandlers/json.lua b/test/busted/outputHandlers/json.lua
deleted file mode 100644 (file)
index f19a336..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-local json = require 'dkjson'
-
-return function(options, busted)
-  local handler = require 'busted.outputHandlers.base'(busted)
-
-  handler.suiteEnd = function()
-    print(json.encode({
-      pendings = handler.pendings,
-      successes = handler.successes,
-      failures = handler.failures,
-      errors = handler.errors,
-      duration = handler.getDuration()
-    }))
-
-    return nil, true
-  end
-
-  busted.subscribe({ 'suite', 'end' }, handler.suiteEnd)
-
-  return handler
-end
diff --git a/test/busted/outputHandlers/junit.lua b/test/busted/outputHandlers/junit.lua
deleted file mode 100644 (file)
index 36e7893..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-local xml = require 'pl.xml'
-local socket = require("socket")
-local string = require("string")
-
-return function(options, busted)
-  local handler = require 'busted.outputHandlers.base'(busted)
-  local top = {
-    start_time = socket.gettime(),
-    xml_doc = xml.new('testsuites', {
-      tests = 0,
-      errors = 0,
-      failures = 0,
-      skip = 0,
-    })
-  }
-  local stack = {}
-  local testStartTime
-
-  handler.suiteStart = function(count, total)
-    local suite = {
-      start_time = socket.gettime(),
-      xml_doc = xml.new('testsuite', {
-        name = 'Run ' .. count .. ' of ' .. total,
-        tests = 0,
-        errors = 0,
-        failures = 0,
-        skip = 0,
-        timestamp = os.date('!%Y-%m-%dT%T'),
-      })
-    }
-    top.xml_doc:add_direct_child(suite.xml_doc)
-    table.insert(stack, top)
-    top = suite
-
-    return nil, true
-  end
-
-  local function elapsed(start_time)
-    return string.format("%.2f", (socket.gettime() - start_time))
-  end
-
-  handler.suiteEnd = function(count, total)
-    local suite = top
-    suite.xml_doc.attr.time = elapsed(suite.start_time)
-
-    top = table.remove(stack)
-    top.xml_doc.attr.tests = top.xml_doc.attr.tests + suite.xml_doc.attr.tests
-    top.xml_doc.attr.errors = top.xml_doc.attr.errors + suite.xml_doc.attr.errors
-    top.xml_doc.attr.failures = top.xml_doc.attr.failures + suite.xml_doc.attr.failures
-    top.xml_doc.attr.skip = top.xml_doc.attr.skip + suite.xml_doc.attr.skip
-
-    return nil, true
-  end
-
-  handler.exit = function()
-    top.xml_doc.attr.time = elapsed(top.start_time)
-    print(xml.tostring(top.xml_doc, '', '\t', nil, false))
-
-    return nil, true
-  end
-
-  local function testStatus(element, parent, message, status, trace)
-    local testcase_node = xml.new('testcase', {
-      classname = element.trace.short_src .. ':' .. element.trace.currentline,
-      name = handler.getFullName(element),
-      time = elapsed(testStartTime)
-    })
-    top.xml_doc:add_direct_child(testcase_node)
-
-    if status ~= 'success' then
-      testcase_node:addtag(status)
-      if message then testcase_node:text(message) end
-      if trace and trace.traceback then testcase_node:text(trace.traceback) end
-      testcase_node:up()
-    end
-  end
-
-  handler.testStart = function(element, parent)
-    testStartTime = socket.gettime()
-
-    return nil, true
-  end
-
-  handler.testEnd = function(element, parent, status)
-    top.xml_doc.attr.tests = top.xml_doc.attr.tests + 1
-
-    if status == 'success' then
-      testStatus(element, parent, nil, 'success')
-    elseif status == 'pending' then
-      top.xml_doc.attr.skip = top.xml_doc.attr.skip + 1
-      local formatted = handler.pendings[#handler.pendings]
-      local trace = element.trace ~= formatted.trace and formatted.trace
-      testStatus(element, parent, formatted.message, 'skipped', trace)
-    end
-
-    return nil, true
-  end
-
-  handler.failureTest = function(element, parent, message, trace)
-    top.xml_doc.attr.failures = top.xml_doc.attr.failures + 1
-    testStatus(element, parent, message, 'failure', trace)
-    return nil, true
-  end
-
-  handler.errorTest = function(element, parent, message, trace)
-    top.xml_doc.attr.errors = top.xml_doc.attr.errors + 1
-    testStatus(element, parent, message, 'error', trace)
-    return nil, true
-  end
-
-  handler.error = function(element, parent, message, trace)
-    if element.descriptor ~= 'it' then
-      top.xml_doc.attr.errors = top.xml_doc.attr.errors + 1
-      top.xml_doc:addtag('error')
-      top.xml_doc:text(message)
-      if trace and trace.traceback then
-        top.xml_doc:text(trace.traceback)
-      end
-      top.xml_doc:up()
-    end
-
-    return nil, true
-  end
-
-  busted.subscribe({ 'exit' }, handler.exit)
-  busted.subscribe({ 'suite', 'start' }, handler.suiteStart)
-  busted.subscribe({ 'suite', 'end' }, handler.suiteEnd)
-  busted.subscribe({ 'test', 'start' }, handler.testStart, { predicate = handler.cancelOnPending })
-  busted.subscribe({ 'test', 'end' }, handler.testEnd, { predicate = handler.cancelOnPending })
-  busted.subscribe({ 'error', 'it' }, handler.errorTest)
-  busted.subscribe({ 'failure', 'it' }, handler.failureTest)
-  busted.subscribe({ 'error' }, handler.error)
-  busted.subscribe({ 'failure' }, handler.error)
-
-  return handler
-end
diff --git a/test/busted/outputHandlers/plainTerminal.lua b/test/busted/outputHandlers/plainTerminal.lua
deleted file mode 100644 (file)
index fc4b092..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-local s = require 'say'
-local pretty = require 'pl.pretty'
-
-return function(options, busted)
-  local handler = require 'busted.outputHandlers.base'(busted)
-
-  local successDot =  '+'
-  local failureDot =  '-'
-  local errorDot =  '*'
-  local pendingDot = '.'
-
-  local pendingDescription = function(pending)
-    local name = pending.name
-
-    local string = s('output.pending') .. ' → ' ..
-      pending.trace.short_src .. ' @ ' ..
-      pending.trace.currentline  ..
-      '\n' .. name
-
-    if type(pending.message) == 'string' then
-      string = string .. '\n' .. pending.message
-    elseif pending.message ~= nil then
-      string = string .. '\n' .. pretty.write(pending.message)
-    end
-
-    return string
-  end
-
-  local failureMessage = function(failure)
-    local string
-    if type(failure.message) == 'string' then
-      string = failure.message
-    elseif failure.message == nil then
-      string = 'Nil error'
-    else
-      string = pretty.write(failure.message)
-    end
-
-    return string
-  end
-
-  local failureDescription = function(failure, isError)
-    local string = s('output.failure') .. ' → '
-    if isError then
-      string = s('output.error') .. ' → '
-    end
-
-    if not failure.element.trace or not failure.element.trace.short_src then
-      string = string ..
-        failureMessage(failure) .. '\n' ..
-        failure.name
-    else
-      string = string ..
-        failure.element.trace.short_src .. ' @ ' ..
-        failure.element.trace.currentline .. '\n' ..
-        failure.name .. '\n' ..
-        failureMessage(failure)
-    end
-
-    if options.verbose and failure.trace and failure.trace.traceback then
-      string = string .. '\n' .. failure.trace.traceback
-    end
-
-    return string
-  end
-
-  local statusString = function()
-    local successString = s('output.success_plural')
-    local failureString = s('output.failure_plural')
-    local pendingString = s('output.pending_plural')
-    local errorString = s('output.error_plural')
-
-    local ms = handler.getDuration()
-    local successes = handler.successesCount
-    local pendings = handler.pendingsCount
-    local failures = handler.failuresCount
-    local errors = handler.errorsCount
-
-    if successes == 0 then
-      successString = s('output.success_zero')
-    elseif successes == 1 then
-      successString = s('output.success_single')
-    end
-
-    if failures == 0 then
-      failureString = s('output.failure_zero')
-    elseif failures == 1 then
-      failureString = s('output.failure_single')
-    end
-
-    if pendings == 0 then
-      pendingString = s('output.pending_zero')
-    elseif pendings == 1 then
-      pendingString = s('output.pending_single')
-    end
-
-    if errors == 0 then
-      errorString = s('output.error_zero')
-    elseif errors == 1 then
-      errorString = s('output.error_single')
-    end
-
-    local formattedTime = ('%.6f'):format(ms):gsub('([0-9])0+$', '%1')
-
-    return successes .. ' ' .. successString .. ' / ' ..
-      failures .. ' ' .. failureString .. ' / ' ..
-      errors .. ' ' .. errorString .. ' / ' ..
-      pendings .. ' ' .. pendingString .. ' : ' ..
-      formattedTime .. ' ' .. s('output.seconds')
-  end
-
-  handler.testEnd = function(element, parent, status, debug)
-    if not options.deferPrint then
-      local string = successDot
-
-      if status == 'pending' then
-        string = pendingDot
-      elseif status == 'failure' then
-        string = failureDot
-      elseif status == 'error' then
-        string = errorDot
-      end
-
-      io.write(string)
-      io.flush()
-    end
-
-    return nil, true
-  end
-
-  handler.suiteStart = function(count, total)
-    local runString = (total > 1 and '\nRepeating all tests (run %d of %d) . . .\n\n' or '')
-    io.write(runString:format(count, total))
-    io.flush()
-  end
-
-  handler.suiteEnd = function()
-    print('')
-    print(statusString())
-
-    for i, pending in pairs(handler.pendings) do
-      print('')
-      print(pendingDescription(pending))
-    end
-
-    for i, err in pairs(handler.failures) do
-      print('')
-      print(failureDescription(err))
-    end
-
-    for i, err in pairs(handler.errors) do
-      print('')
-      print(failureDescription(err, true))
-    end
-
-    return nil, true
-  end
-
-  handler.error = function(element, parent, message, debug)
-    io.write(errorDot)
-    io.flush()
-
-    return nil, true
-  end
-
-  busted.subscribe({ 'test', 'end' }, handler.testEnd, { predicate = handler.cancelOnPending })
-  busted.subscribe({ 'suite', 'start' }, handler.suiteStart)
-  busted.subscribe({ 'suite', 'end' }, handler.suiteEnd)
-  busted.subscribe({ 'error', 'file' }, handler.error)
-  busted.subscribe({ 'failure', 'file' }, handler.error)
-  busted.subscribe({ 'error', 'describe' }, handler.error)
-  busted.subscribe({ 'failure', 'describe' }, handler.error)
-
-  return handler
-end
diff --git a/test/busted/outputHandlers/sound.lua b/test/busted/outputHandlers/sound.lua
deleted file mode 100644 (file)
index 8ac1a46..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-local app = require 'pl.app'
-return function(options, busted)
-  local handler = require 'busted.outputHandlers.base'(busted)
-  local language = require('busted.languages.' .. options.language)
-
-  handler.suiteEnd = function()
-    local system = app.platform()
-    local sayer_pre, sayer_post
-    local messages
-
-    if system == 'Linux' then
-      sayer_pre = 'espeak -s 160 '
-      sayer_post = ' > /dev/null 2>&1'
-    elseif system and system:match('^Windows') then
-      sayer_pre = 'echo '
-      sayer_post = ' | ptts'
-    else
-      sayer_pre = 'say '
-      sayer_post = ''
-    end
-
-    if handler.failuresCount > 0 then
-      messages = language.failure_messages
-    else
-      messages = language.success_messages
-    end
-
-    io.popen(sayer_pre .. '"' .. messages[math.random(1, #messages)] .. '"' .. sayer_post)
-
-    return nil, true
-  end
-
-  busted.subscribe({ 'suite', 'end' }, handler.suiteEnd)
-
-  return handler
-end
diff --git a/test/busted/outputHandlers/utfTerminal.lua b/test/busted/outputHandlers/utfTerminal.lua
deleted file mode 100644 (file)
index f34015c..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-local ansicolors = require 'ansicolors'
-local s = require 'say'
-local pretty = require 'pl.pretty'
-
-return function(options, busted)
-  local handler = require 'busted.outputHandlers.base'(busted)
-
-  local successDot = ansicolors('%{green}●')
-  local failureDot = ansicolors('%{red}◼')
-  local errorDot   = ansicolors('%{magenta}✱')
-  local pendingDot = ansicolors('%{yellow}◌')
-
-  local pendingDescription = function(pending)
-    local name = pending.name
-
-    local string = ansicolors('%{yellow}' .. s('output.pending')) .. ' → ' ..
-      ansicolors('%{cyan}' .. pending.trace.short_src) .. ' @ ' ..
-      ansicolors('%{cyan}' .. pending.trace.currentline)  ..
-      '\n' .. ansicolors('%{bright}' .. name)
-
-    if type(pending.message) == 'string' then
-      string = string .. '\n' .. pending.message
-    elseif pending.message ~= nil then
-      string = string .. '\n' .. pretty.write(pending.message)
-    end
-
-    return string
-  end
-
-  local failureMessage = function(failure)
-    local string
-    if type(failure.message) == 'string' then
-      string = failure.message
-    elseif failure.message == nil then
-      string = 'Nil error'
-    else
-      string = pretty.write(failure.message)
-    end
-
-    return string
-  end
-
-  local failureDescription = function(failure, isError)
-    local string = ansicolors('%{red}' .. s('output.failure')) .. ' → '
-    if isError then
-      string = ansicolors('%{magenta}' .. s('output.error')) .. ' → '
-    end
-
-    if not failure.element.trace or not failure.element.trace.short_src then
-      string = string ..
-        ansicolors('%{cyan}' .. failureMessage(failure)) .. '\n' ..
-        ansicolors('%{bright}' .. failure.name)
-    else
-      string = string ..
-        ansicolors('%{cyan}' .. failure.element.trace.short_src) .. ' @ ' ..
-        ansicolors('%{cyan}' .. failure.element.trace.currentline) .. '\n' ..
-        ansicolors('%{bright}' .. failure.name) .. '\n' ..
-        failureMessage(failure)
-    end
-
-    if options.verbose and failure.trace and failure.trace.traceback then
-      string = string .. '\n' .. failure.trace.traceback
-    end
-
-    return string
-  end
-
-  local statusString = function()
-    local successString = s('output.success_plural')
-    local failureString = s('output.failure_plural')
-    local pendingString = s('output.pending_plural')
-    local errorString = s('output.error_plural')
-
-    local ms = handler.getDuration()
-    local successes = handler.successesCount
-    local pendings = handler.pendingsCount
-    local failures = handler.failuresCount
-    local errors = handler.errorsCount
-
-    if successes == 0 then
-      successString = s('output.success_zero')
-    elseif successes == 1 then
-      successString = s('output.success_single')
-    end
-
-    if failures == 0 then
-      failureString = s('output.failure_zero')
-    elseif failures == 1 then
-      failureString = s('output.failure_single')
-    end
-
-    if pendings == 0 then
-      pendingString = s('output.pending_zero')
-    elseif pendings == 1 then
-      pendingString = s('output.pending_single')
-    end
-
-    if errors == 0 then
-      errorString = s('output.error_zero')
-    elseif errors == 1 then
-      errorString = s('output.error_single')
-    end
-
-    local formattedTime = ('%.6f'):format(ms):gsub('([0-9])0+$', '%1')
-
-    return ansicolors('%{green}' .. successes) .. ' ' .. successString .. ' / ' ..
-      ansicolors('%{red}' .. failures) .. ' ' .. failureString .. ' / ' ..
-      ansicolors('%{magenta}' .. errors) .. ' ' .. errorString .. ' / ' ..
-      ansicolors('%{yellow}' .. pendings) .. ' ' .. pendingString .. ' : ' ..
-      ansicolors('%{bright}' .. formattedTime) .. ' ' .. s('output.seconds')
-  end
-
-  handler.testEnd = function(element, parent, status, debug)
-    if not options.deferPrint then
-      local string = successDot
-
-      if status == 'pending' then
-        string = pendingDot
-      elseif status == 'failure' then
-        string = failureDot
-      elseif status == 'error' then
-        string = errorDot
-      end
-
-      io.write(string)
-      io.flush()
-    end
-
-    return nil, true
-  end
-
-  handler.suiteStart = function(count, total)
-    local runString = (total > 1 and '\nRepeating all tests (run %d of %d) . . .\n\n' or '')
-    io.write(runString:format(count, total))
-    io.flush()
-  end
-
-  handler.suiteEnd = function(count, total)
-    print('')
-    print(statusString())
-
-    for i, pending in pairs(handler.pendings) do
-      print('')
-      print(pendingDescription(pending))
-    end
-
-    for i, err in pairs(handler.failures) do
-      print('')
-      print(failureDescription(err))
-    end
-
-    for i, err in pairs(handler.errors) do
-      print('')
-      print(failureDescription(err, true))
-    end
-
-    return nil, true
-  end
-
-  handler.error = function(element, parent, message, debug)
-    io.write(errorDot)
-    io.flush()
-
-    return nil, true
-  end
-
-  busted.subscribe({ 'test', 'end' }, handler.testEnd, { predicate = handler.cancelOnPending })
-  busted.subscribe({ 'suite', 'start' }, handler.suiteStart)
-  busted.subscribe({ 'suite', 'end' }, handler.suiteEnd)
-  busted.subscribe({ 'error', 'file' }, handler.error)
-  busted.subscribe({ 'failure', 'file' }, handler.error)
-  busted.subscribe({ 'error', 'describe' }, handler.error)
-  busted.subscribe({ 'failure', 'describe' }, handler.error)
-
-  return handler
-end
diff --git a/test/busted/runner.lua b/test/busted/runner.lua
deleted file mode 100644 (file)
index 91ce94e..0000000
+++ /dev/null
@@ -1,400 +0,0 @@
--- Busted command-line runner
-
-local path = require 'pl.path'
-local term = require 'term'
-local utils = require 'busted.utils'
-local loaded = false
-
-return function(options)
-  if loaded then return else loaded = true end
-
-  local opt = options or {}
-  local isBatch = opt.batch
-  local cli = require 'cliargs'
-  local busted = require 'busted.core'()
-
-  local configLoader = require 'busted.modules.configuration_loader'()
-  local helperLoader = require 'busted.modules.helper_loader'()
-  local outputHandlerLoader = require 'busted.modules.output_handler_loader'()
-
-  local luacov = require 'busted.modules.luacov'()
-
-  local osexit = require 'busted.compatibility'.osexit
-
-  require 'busted'(busted)
-
-  -- Default cli arg values
-  local defaultOutput = term.isatty(io.stdout) and 'utfTerminal' or 'plainTerminal'
-  local defaultLoaders = 'lua,moonscript'
-  local defaultPattern = '_spec'
-  local defaultSeed = '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;'
-
-  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 cliArgsParsed = {}
-
-  local function processOption(key, value, altkey, opt)
-    if altkey then cliArgsParsed[altkey] = value end
-    cliArgsParsed[key] = value
-    return true
-  end
-
-  local function processNumber(key, value, altkey, opt)
-    local number = tonumber(value)
-    if not number then
-      return nil, 'argument to ' .. opt:gsub('=.*', '') .. ' must be a number'
-    end
-    if altkey then cliArgsParsed[altkey] = number end
-    cliArgsParsed[key] = number
-    return true
-  end
-
-  local function processVersion()
-    -- Return early if asked for the version
-    print(busted.version)
-    osexit(0, true)
-  end
-
-  -- Load up the command-line interface options
-  cli:set_name(path.basename(fileName))
-  cli:add_flag('--version', 'prints the program version and exits', processVersion)
-
-  if isBatch then
-    cli:optarg('ROOT', 'test script file/folder. Folders will be traversed for any file that matches the --pattern option.', 'spec', 1)
-
-    cli:add_option('-p, --pattern=PATTERN', 'only run test files matching the Lua pattern', defaultPattern, processOption)
-  end
-
-  cli:add_option('-o, --output=LIBRARY', 'output library to load', defaultOutput, processOption)
-  cli:add_option('-d, --cwd=cwd', 'path to current working directory', './', processOption)
-  cli:add_option('-t, --tags=TAGS', 'only run tests with these #tags', nil, processOption)
-  cli:add_option('--exclude-tags=TAGS', 'do not run tests with these #tags, takes precedence over --tags', nil, processOption)
-  cli:add_option('--filter=PATTERN', 'only run test names matching the Lua pattern', nil, processOption)
-  cli:add_option('--filter-out=PATTERN', 'do not run test names matching the Lua pattern, takes precedence over --filter', nil, processOption)
-  cli:add_option('-m, --lpath=PATH', 'optional path to be prefixed to the Lua module search path', lpathprefix, processOption)
-  cli:add_option('--cpath=PATH', 'optional path to be prefixed to the Lua C module search path', cpathprefix, processOption)
-  cli:add_option('-r, --run=RUN', 'config to run from .busted file', nil, processOption)
-  cli:add_option('--repeat=COUNT', 'run the tests repeatedly', '1', processNumber)
-  cli:add_option('--seed=SEED', 'random seed value to use for shuffling test order', defaultSeed, processNumber)
-  cli:add_option('--lang=LANG', 'language for error messages', 'en', processOption)
-  cli:add_option('--loaders=NAME', 'test file loaders', defaultLoaders, processOption)
-  cli:add_option('--helper=PATH', 'A helper script that is run before tests', nil, processOption)
-
-  cli:add_option('-Xoutput OPTION', 'pass `OPTION` as an option to the output handler. If `OPTION` contains commas, it is split into multiple options at the commas.', nil, processOption)
-  cli:add_option('-Xhelper OPTION', 'pass `OPTION` as an option to the helper script. If `OPTION` contains commas, it is split into multiple options at the commas.', nil, processOption)
-
-  cli:add_flag('-c, --coverage', 'do code coverage analysis (requires `LuaCov` to be installed)', processOption)
-  cli:add_flag('-v, --verbose', 'verbose output of errors', processOption)
-  cli:add_flag('-s, --enable-sound', 'executes `say` command if available', processOption)
-  cli:add_flag('-l, --list', 'list the names of all tests instead of running them', processOption)
-  cli:add_flag('--no-keep-going', 'quit after first error or failure', processOption)
-  cli:add_flag('--no-recursive', 'do not recurse into subdirectories', processOption)
-  cli:add_flag('--shuffle', 'randomize file and test order, takes precedence over --sort (--shuffle-test and --shuffle-files)', processOption)
-  cli:add_flag('--shuffle-files', 'randomize file execution order, takes precedence over --sort-files', processOption)
-  cli:add_flag('--shuffle-tests', 'randomize test order within a file, takes precedence over --sort-tests', processOption)
-  cli:add_flag('--sort', 'sort file and test order (--sort-tests and --sort-files)', processOption)
-  cli:add_flag('--sort-files', 'sort file execution order', processOption)
-  cli:add_flag('--sort-tests', 'sort test order within a file', processOption)
-  cli:add_flag('--suppress-pending', 'suppress `pending` test output', processOption)
-  cli:add_flag('--defer-print', 'defer print to when test suite is complete', processOption)
-
-  -- Parse the cli arguments
-  local cliArgs = cli:parse(arg)
-  if not cliArgs then
-    osexit(1, true)
-  end
-
-  -- Load current working directory
-  local fpath = utils.normpath(cliArgs.cwd)
-
-  -- Load busted config file if available
-  local configFile = { }
-  local bustedConfigFilePath = utils.normpath(path.join(fpath, '.busted'))
-  local bustedConfigFile = pcall(function() configFile = loadfile(bustedConfigFilePath)() end)
-  if bustedConfigFile then
-    local config, err = configLoader(configFile, cliArgsParsed, cliArgs)
-    if err then
-      print('Error: ' .. err)
-      osexit(1, true)
-    else
-      cliArgs = config
-    end
-  end
-
-  local tags = {}
-  local excludeTags = {}
-
-  if cliArgs.tags and cliArgs.tags ~= '' then
-    tags = utils.split(cliArgs.tags, ',')
-  end
-
-  if cliArgs['exclude-tags'] and cliArgs['exclude-tags'] ~= '' then
-    excludeTags = utils.split(cliArgs['exclude-tags'], ',')
-  end
-
-  -- If coverage arg is passed in, load LuaCovsupport
-  if cliArgs.coverage then
-    luacov()
-  end
-
-  -- Add additional package paths based on lpath and cpath cliArgs
-  if #cliArgs.lpath > 0 then
-    lpathprefix = cliArgs.lpath
-    lpathprefix = lpathprefix:gsub('^%.([/%\\])', fpath .. '%1')
-    lpathprefix = lpathprefix:gsub(';%.([/%\\])', ';' .. fpath .. '%1')
-    package.path = (lpathprefix .. ';' .. package.path):gsub(';;',';')
-  end
-
-  if #cliArgs.cpath > 0 then
-    cpathprefix = cliArgs.cpath
-    cpathprefix = cpathprefix:gsub('^%.([/%\\])', fpath .. '%1')
-    cpathprefix = cpathprefix:gsub(';%.([/%\\])', ';' .. fpath .. '%1')
-    package.cpath = (cpathprefix .. ';' .. package.cpath):gsub(';;',';')
-  end
-
-  local loaders = {}
-  if #cliArgs.loaders > 0 then
-    string.gsub(cliArgs.loaders, '([^,]+)', function(c) loaders[#loaders+1] = c end)
-  end
-
-  -- We report an error if the same tag appears in both `options.tags`
-  -- and `options.excluded_tags` because it does not make sense for the
-  -- user to tell Busted to include and exclude the same tests at the
-  -- same time.
-  for _, excluded in pairs(excludeTags) do
-    for _, included in pairs(tags) do
-      if excluded == included then
-        print('Error: Cannot use --tags and --exclude-tags for the same tags')
-        osexit(1, true)
-      end
-    end
-  end
-
-  -- watch for test errors
-  local failures = 0
-  local errors = 0
-  local quitOnError = cliArgs['no-keep-going']
-
-  busted.subscribe({ 'error', 'output' }, function(element, parent, message)
-    print('Error: Cannot load output library: ' .. element.name .. '\n' .. message)
-    return nil, true
-  end)
-
-  busted.subscribe({ 'error', 'helper' }, function(element, parent, message)
-    print('Error: Cannot load helper script: ' .. element.name .. '\n' .. message)
-    return nil, true
-  end)
-
-  busted.subscribe({ 'error' }, function(element, parent, message)
-    errors = errors + 1
-    busted.skipAll = quitOnError
-    return nil, true
-  end)
-
-  busted.subscribe({ 'failure' }, function(element, parent, message)
-    if element.descriptor == 'it' then
-      failures = failures + 1
-    else
-      errors = errors + 1
-    end
-    busted.skipAll = quitOnError
-    return nil, true
-  end)
-
-  -- Set up output handler to listen to events
-  local outputHandlerOptions = {
-    verbose = cliArgs.verbose,
-    suppressPending = cliArgs['suppress-pending'],
-    language = cliArgs.lang,
-    deferPrint = cliArgs['defer-print'],
-    arguments = utils.split(cliArgs.Xoutput or '', ',') or {}
-  }
-
-  local opath = utils.normpath(path.join(fpath, cliArgs.output))
-  local outputHandler = outputHandlerLoader(cliArgs.output, opath, outputHandlerOptions, busted, defaultOutput)
-  outputHandler:subscribe(outputHandlerOptions)
-
-  if cliArgs['enable-sound'] then
-    require 'busted.outputHandlers.sound'(outputHandlerOptions, busted)
-  end
-
-  -- Set up randomization options
-  busted.sort = cliArgs['sort-tests'] or cliArgs.sort
-  busted.randomize = cliArgs['shuffle-tests'] or cliArgs.shuffle
-  busted.randomseed = tonumber(cliArgs.seed) or os.time()
-
-  local getFullName = function(name)
-    local parent = busted.context.get()
-    local names = { name }
-
-    while parent and (parent.name or parent.descriptor) and
-          parent.descriptor ~= 'file' do
-      table.insert(names, 1, parent.name or parent.descriptor)
-      parent = busted.context.parent(parent)
-    end
-
-    return table.concat(names, ' ')
-  end
-
-  local hasTag = function(name, tag)
-    local found = name:find('#' .. tag)
-    return (found ~= nil)
-  end
-
-  local filterExcludeTags = function(name)
-    for i, tag in pairs(excludeTags) do
-      if hasTag(name, tag) then
-        return nil, false
-      end
-    end
-    return nil, true
-  end
-
-  local filterTags = function(name)
-    local fullname = getFullName(name)
-    for i, tag in pairs(tags) do
-      if hasTag(fullname, tag) then
-        return nil, true
-      end
-    end
-    return nil, (#tags == 0)
-  end
-
-  local filterOutNames = function(name)
-    local found = (getFullName(name):find(cliArgs['filter-out']) ~= nil)
-    return nil, not found
-  end
-
-  local filterNames = function(name)
-    local found = (getFullName(name):find(cliArgs.filter) ~= nil)
-    return nil, found
-  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
-      print(fullname)
-    end
-    return nil, false
-  end
-
-  local ignoreAll = function()
-    return nil, false
-  end
-
-  local skipOnError = function()
-    return nil, (failures == 0 and errors == 0)
-  end
-
-  local applyFilter = function(descriptors, name, fn)
-    if cliArgs[name] and cliArgs[name] ~= '' then
-      for _, descriptor in ipairs(descriptors) do
-        busted.subscribe({ 'register', descriptor }, fn, { priority = 1 })
-      end
-    end
-  end
-
-  if cliArgs.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({ 'it', 'pending' }, 'list', printNameOnly)
-  end
-
-  applyFilter({ 'setup', 'teardown', 'before_each', 'after_each' }, 'no-keep-going', skipOnError)
-  applyFilter({ 'file', 'describe', 'it', 'pending' }, 'no-keep-going', skipOnError)
-
-  -- The following filters are applied in reverse order
-  applyFilter({ 'it', 'pending' }            , 'filter'      , filterNames      )
-  applyFilter({ 'describe', 'it', 'pending' }, 'filter-out'  , filterOutNames   )
-  applyFilter({ 'it', 'pending' }            , 'tags'        , filterTags       )
-  applyFilter({ 'describe', 'it', 'pending' }, 'exclude-tags', filterExcludeTags)
-
-  -- Set up helper script
-  if cliArgs.helper and cliArgs.helper ~= '' then
-    local helperOptions = {
-      verbose = cliArgs.verbose,
-      language = cliArgs.lang,
-      arguments = utils.split(cliArgs.Xhelper or '', ',') or {}
-    }
-
-    local hpath = utils.normpath(path.join(fpath, cliArgs.helper))
-    helperLoader(cliArgs.helper, hpath, helperOptions, busted)
-  end
-
-  -- Set up test loader options
-  local testFileLoaderOptions = {
-    verbose = cliArgs.verbose,
-    sort = cliArgs['sort-files'] or cliArgs.sort,
-    shuffle = cliArgs['shuffle-files'] or cliArgs.shuffle,
-    recursive = not cliArgs['no-recursive'],
-    seed = busted.randomseed
-  }
-
-  -- Load test directory
-  local rootFile = cliArgs.ROOT and utils.normpath(path.join(fpath, cliArgs.ROOT)) or fileName
-  local pattern = cliArgs.pattern
-  local testFileLoader = require 'busted.modules.test_file_loader'(busted, loaders, testFileLoaderOptions)
-  local fileList = testFileLoader(rootFile, pattern)
-
-  if not cliArgs.ROOT then
-    local ctx = busted.context.get()
-    local file = busted.context.children(ctx)[1]
-    getmetatable(file.run).__call = info.func
-  end
-
-  busted.subscribe({'suite', 'reinitialize'}, function()
-    local oldctx = busted.context.get()
-    local children = busted.context.children(oldctx)
-
-    busted.context.clear()
-    local ctx = busted.context.get()
-    for k, v in pairs(oldctx) do
-      ctx[k] = v
-    end
-
-    for _, child in pairs(children) do
-      for descriptor, _ in pairs(busted.executors) do
-        child[descriptor] = nil
-      end
-      busted.context.attach(child)
-    end
-
-    busted.randomseed = tonumber(cliArgs.seed) or os.time()
-
-    return nil, true
-  end)
-
-  local runs = tonumber(cliArgs['repeat']) or 1
-  for i = 1, runs do
-    if i > 1 then
-      busted.publish({ 'suite', 'reinitialize' })
-    end
-
-    busted.publish({ 'suite', 'start' }, i, runs)
-    busted.execute()
-    busted.publish({ 'suite', 'end' }, i, runs)
-
-    if quitOnError and (failures > 0 or errors > 0) then
-      break
-    end
-  end
-
-  busted.publish({ 'exit' })
-
-  local exit = 0
-  if failures > 0 or errors > 0 then
-    exit = failures + errors
-    if exit > 255 then
-      exit = 255
-    end
-  end
-  osexit(exit, true)
-end
diff --git a/test/busted/status.lua b/test/busted/status.lua
deleted file mode 100644 (file)
index c68ce7f..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-local function get_status(status)
-  local smap = {
-    ['success'] = 'success',
-    ['pending'] = 'pending',
-    ['failure'] = 'failure',
-    ['error'] = 'error',
-    ['true'] = 'success',
-    ['false'] = 'failure',
-    ['nil'] = 'error',
-  }
-  return smap[tostring(status)] or 'error'
-end
-
-return function(inital_status)
-  local objstat = get_status(inital_status)
-  local obj = {
-    success = function(self) return (objstat == 'success') end,
-    pending = function(self) return (objstat == 'pending') end,
-    failure = function(self) return (objstat == 'failure') end,
-    error   = function(self) return (objstat == 'error') end,
-
-    get = function(self)
-      return objstat
-    end,
-
-    set = function(self, status)
-      objstat = get_status(status)
-    end,
-
-    update = function(self, status)
-      -- prefer current failure/error status over new status
-      status = get_status(status)
-      if objstat == 'success' or (objstat == 'pending' and status ~= 'success') then
-        objstat = status
-      end
-    end
-  }
-
-  return setmetatable(obj, {
-    __index = {},
-    __tostring = function(self) return objstat end
-  })
-end
diff --git a/test/busted/utils.lua b/test/busted/utils.lua
deleted file mode 100644 (file)
index 4e02bc0..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-local path = require 'pl.path'
-
-math.randomseed(os.time())
-
--- Do not use pl.path.normpath
--- It is broken for paths with leading '../../'
-local function normpath(fpath)
-  if type(fpath) ~= 'string' then
-    error(fpath .. ' is not a string')
-  end
-  local sep = '/'
-  if path.is_windows then
-    sep = '\\'
-    if fpath:match '^\\\\' then -- UNC
-      return '\\\\' .. normpath(fpath:sub(3))
-    end
-    fpath = fpath:gsub('/','\\')
-  end
-  local np_gen1, np_gen2 = '([^SEP]+)SEP(%.%.SEP?)', 'SEP+%.?SEP'
-  local np_pat1 = np_gen1:gsub('SEP', sep)
-  local np_pat2 = np_gen2:gsub('SEP', sep)
-  local k
-  repeat -- /./ -> /
-    fpath, k = fpath:gsub(np_pat2, sep)
-  until k == 0
-  repeat -- A/../ -> (empty)
-    local oldpath = fpath
-    fpath, k = fpath:gsub(np_pat1, function(d, up)
-      if d == '..' then return nil end
-      if d == '.' then return up end
-      return ''
-    end)
-  until k == 0 or oldpath == fpath
-  if fpath == '' then fpath = '.' end
-  return fpath
-end
-
-return {
-  split = require 'pl.utils'.split,
-
-  normpath = normpath,
-
-  shuffle = function(t, seed)
-    if seed then math.randomseed(seed) end
-    local n = #t
-    while n >= 2 do
-      local k = math.random(n)
-      t[n], t[k] = t[k], t[n]
-      n = n - 1
-    end
-    return t
-  end
-}
diff --git a/test/lua/busted.lua b/test/lua/busted.lua
new file mode 100644 (file)
index 0000000..917d21d
--- /dev/null
@@ -0,0 +1,3 @@
+-- This is a dummy file so it can be used in busted's specs
+-- without adding ./?/init.lua to the lua path
+return require 'busted.init'
diff --git a/test/lua/busted/compatibility.lua b/test/lua/busted/compatibility.lua
new file mode 100644 (file)
index 0000000..7837656
--- /dev/null
@@ -0,0 +1,60 @@
+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 value
+  end,
+
+  setfenv = setfenv or function(f, t)
+    f = (type(f) == 'function' and f or debug.getinfo(f + 1, 'f').func)
+    local name
+    local up = 0
+
+    repeat
+      up = up + 1
+      name = debug.getupvalue(f, up)
+    until name == '_ENV' or name == nil
+
+    if name then
+      debug.upvaluejoin(f, up, function() return name end, 1)
+      debug.setupvalue(f, up, t)
+    end
+
+    if f ~= 0 then return f end
+  end,
+
+  unpack = table.unpack or unpack,
+
+  osexit = function(code, close)
+    if close and _VERSION == 'Lua 5.1' then
+      -- From Lua 5.1 manual:
+      -- > The userdata itself is freed only in the next
+      -- > garbage-collection cycle.
+      -- Call collectgarbage() while collectgarbage('count')
+      -- changes + 3 times, at least 3 times,
+      -- at max 100 times (to prevent infinite loop).
+      local times_const = 0
+      for i = 1, 100 do
+        local count_before = collectgarbage("count")
+        collectgarbage()
+        local count_after = collectgarbage("count")
+        if count_after == count_before then
+          times_const = times_const + 1
+          if times_const > 3 then
+            break
+          end
+        else
+          times_const = 0
+        end
+      end
+    end
+    os.exit(code, close)
+  end,
+}
diff --git a/test/lua/busted/context.lua b/test/lua/busted/context.lua
new file mode 100644 (file)
index 0000000..4cf0f3b
--- /dev/null
@@ -0,0 +1,91 @@
+local tablex = require 'pl.tablex'
+
+local function save()
+  local g = {}
+  for k,_ in next, _G, nil do
+    g[k] = rawget(_G, k)
+  end
+  return {
+    gmt = getmetatable(_G),
+    g = g,
+    loaded = tablex.copy(package.loaded)
+  }
+end
+
+local function restore(state)
+  setmetatable(_G, state.gmt)
+  for k,_ in next, _G, nil do
+    rawset(_G, k, state.g[k])
+  end
+  for k,_ in pairs(package.loaded) do
+    package.loaded[k] = state.loaded[k]
+  end
+end
+
+return function()
+  local context = {}
+
+  local data = {}
+  local parents = {}
+  local children = {}
+  local stack = {}
+
+  function context.ref()
+    local ref = {}
+    local ctx = data
+
+    function ref.get(key)
+      if not key then return ctx end
+      return ctx[key]
+    end
+
+    function ref.set(key, value)
+      ctx[key] = value
+    end
+
+    function ref.clear()
+      data = {}
+      parents = {}
+      children = {}
+      stack = {}
+      ctx = data
+    end
+
+    function ref.attach(child)
+      if not children[ctx] then children[ctx] = {} end
+      parents[child] = ctx
+      table.insert(children[ctx], child)
+    end
+
+    function ref.children(parent)
+      return children[parent] or {}
+    end
+
+    function ref.parent(child)
+      return parents[child]
+    end
+
+    function ref.push(current)
+      if not parents[current] then error('Detached child. Cannot push.') end
+      if ctx ~= current and current.descriptor == 'file' then
+        current.state = save()
+      end
+      table.insert(stack, ctx)
+      ctx = current
+    end
+
+    function ref.pop()
+      local current = ctx
+      ctx = table.remove(stack)
+      if ctx ~= current and current.state then
+        restore(current.state)
+        current.state = nil
+      end
+      if not ctx then error('Context stack empty. Cannot pop.') end
+    end
+
+    return ref
+  end
+
+  return context
+end
diff --git a/test/lua/busted/core.lua b/test/lua/busted/core.lua
new file mode 100644 (file)
index 0000000..802e60c
--- /dev/null
@@ -0,0 +1,237 @@
+local getfenv = require 'busted.compatibility'.getfenv
+local setfenv = require 'busted.compatibility'.setfenv
+local unpack = require 'busted.compatibility'.unpack
+local path = require 'pl.path'
+local pretty = require 'pl.pretty'
+local throw = error
+
+local failureMt = {
+  __index = {},
+  __tostring = function(e) return tostring(e.message) end,
+  __type = 'failure'
+}
+
+local failureMtNoString = {
+  __index = {},
+  __type = 'failure'
+}
+
+local pendingMt = {
+  __index = {},
+  __tostring = function(p) return p.message end,
+  __type = 'pending'
+}
+
+local function metatype(obj)
+  local otype = type(obj)
+  return otype == 'table' and (getmetatable(obj) or {}).__type or otype
+end
+
+local function hasToString(obj)
+  return type(obj) == 'string' or (getmetatable(obj) or {}).__tostring
+end
+
+return function()
+  local mediator = require 'mediator'()
+
+  local busted = {}
+  busted.version = '2.0.rc6-0'
+
+  local root = require 'busted.context'()
+  busted.context = root.ref()
+
+  local environment = require 'busted.environment'(busted.context)
+  busted.environment = {
+    set = environment.set,
+
+    wrap = function(callable)
+      if (type(callable) == 'function' or getmetatable(callable).__call) then
+        -- prioritize __call if it exists, like in files
+        environment.wrap((getmetatable(callable) or {}).__call or callable)
+      end
+    end
+  }
+
+  busted.executors = {}
+  local executors = {}
+
+  busted.status = require 'busted.status'
+
+  function busted.getTrace(element, level, msg)
+    level = level or  3
+
+    local thisdir = path.dirname(debug.getinfo(1, 'Sl').source)
+    local info = debug.getinfo(level, 'Sl')
+    while info.what == 'C' or info.short_src:match('luassert[/\\].*%.lua$') or
+          (info.source:sub(1,1) == '@' and thisdir == path.dirname(info.source)) do
+      level = level + 1
+      info = debug.getinfo(level, 'Sl')
+    end
+
+    info.traceback = debug.traceback('', level)
+    info.message = msg
+
+    local file = busted.getFile(element)
+    return file.getTrace(file.name, info)
+  end
+
+  function busted.rewriteMessage(element, message, trace)
+    local file = busted.getFile(element)
+    local msg = hasToString(message) and tostring(message)
+    msg = msg or (message ~= nil and pretty.write(message) or 'Nil error')
+    msg = (file.rewriteMessage and file.rewriteMessage(file.name, msg) or msg)
+
+    local hasFileLine = msg:match('^[^\n]-:%d+: .*')
+    if not hasFileLine then
+      local trace = trace or busted.getTrace(element, 3, message)
+      local fileline = trace.short_src .. ':' .. trace.currentline .. ': '
+      msg = fileline .. msg
+    end
+
+    return msg
+  end
+
+  function busted.publish(...)
+    return mediator:publish(...)
+  end
+
+  function busted.subscribe(...)
+    return mediator:subscribe(...)
+  end
+
+  function busted.getFile(element)
+    local parent = busted.context.parent(element)
+
+    while parent do
+      if parent.file then
+        local file = parent.file[1]
+        return {
+          name = file.name,
+          getTrace = file.run.getTrace,
+          rewriteMessage = file.run.rewriteMessage
+        }
+      end
+
+      if parent.descriptor == 'file' then
+        return {
+          name = parent.name,
+          getTrace = parent.run.getTrace,
+          rewriteMessage = parent.run.rewriteMessage
+        }
+      end
+
+      parent = busted.context.parent(parent)
+    end
+
+    return parent
+  end
+
+  function busted.fail(msg, level)
+    local rawlevel = (type(level) ~= 'number' or level <= 0) and level
+    local level = level or 1
+    local _, emsg = pcall(throw, msg, rawlevel or level+2)
+    local e = { message = emsg }
+    setmetatable(e, hasToString(msg) and failureMt or failureMtNoString)
+    throw(e, rawlevel or 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) or {}).__call or callable
+    setmetatable(env, { __index = getfenv(f) })
+    env.error = busted.fail
+    setfenv(f, env)
+  end
+
+  function busted.safe(descriptor, run, element)
+    busted.context.push(element)
+    local trace, message
+    local status = 'success'
+
+    local ret = { xpcall(run, function(msg)
+      local errType = metatype(msg)
+      status = ((errType == 'pending' or errType == 'failure') and errType or 'error')
+      trace = busted.getTrace(element, 3, msg)
+      message = busted.rewriteMessage(element, msg, trace)
+    end) }
+
+    if not ret[1] then
+      busted.publish({ status, descriptor }, element, busted.context.parent(element), message, trace)
+    end
+    ret[1] = busted.status(status)
+
+    busted.context.pop()
+    return unpack(ret)
+  end
+
+  function busted.register(descriptor, executor)
+    executors[descriptor] = executor
+
+    local publisher = function(name, fn)
+      if not fn and type(name) == 'function' then
+        fn = name
+        name = nil
+      end
+
+      local trace
+
+      local ctx = busted.context.get()
+      if busted.context.parent(ctx) then
+        trace = busted.getTrace(ctx, 3, name)
+      end
+
+      local publish = function(f)
+        busted.publish({ 'register', descriptor }, name, f, trace)
+      end
+
+      if fn then publish(fn) else return publish end
+    end
+
+    busted.executors[descriptor] = publisher
+    if descriptor ~= 'file' then
+      environment.set(descriptor, publisher)
+    end
+
+    busted.subscribe({ 'register', descriptor }, function(name, fn, trace)
+      local ctx = busted.context.get()
+      local plugin = {
+        descriptor = descriptor,
+        name = name,
+        run = fn,
+        trace = trace
+      }
+
+      busted.context.attach(plugin)
+
+      if not ctx[descriptor] then
+        ctx[descriptor] = { plugin }
+      else
+        ctx[descriptor][#ctx[descriptor]+1] = plugin
+      end
+    end)
+  end
+
+  function busted.alias(alias, descriptor)
+    local publisher = busted.executors[descriptor]
+    busted.executors[alias] = publisher
+    environment.set(alias, publisher)
+  end
+
+  function busted.execute(current)
+    if not current then current = busted.context.get() end
+    for _, v in pairs(busted.context.children(current)) do
+      local executor = executors[v.descriptor]
+      if executor and not busted.skipAll then
+        busted.safe(v.descriptor, function() executor(v) end, v)
+      end
+    end
+  end
+
+  return busted
+end
diff --git a/test/lua/busted/done.lua b/test/lua/busted/done.lua
new file mode 100644 (file)
index 0000000..e631904
--- /dev/null
@@ -0,0 +1,121 @@
+local M = {}
+
+-- adds tokens to the current wait list, does not change order/unordered
+M.wait = function(self, ...)
+  local tlist = { ... }
+
+  for _, token in ipairs(tlist) do
+    if type(token) ~= 'string' then
+      error('Wait tokens must be strings. Got '..type(token), 2)
+    end
+    table.insert(self.tokens, token)
+  end
+end
+
+-- set list as unordered, adds tokens to current wait list
+M.wait_unordered = function(self, ...)
+  self.ordered = false
+  self:wait(...)
+end
+
+-- set list as ordered, adds tokens to current wait list
+M.wait_ordered = function(self, ...)
+  self.ordered = true
+  self:wait(...)
+end
+
+-- generates a message listing tokens received/open
+M.tokenlist = function(self)
+  local list
+
+  if #self.tokens_done == 0 then
+    list = 'No tokens received.'
+  else
+    list = 'Tokens received ('..tostring(#self.tokens_done)..')'
+    local s = ': '
+
+    for _,t in ipairs(self.tokens_done) do
+      list = list .. s .. '\''..t..'\''
+      s = ', '
+    end
+
+    list = list .. '.'
+  end
+
+  if #self.tokens == 0 then
+    list = list .. ' No more tokens expected.'
+  else
+    list = list .. ' Tokens not received ('..tostring(#self.tokens)..')'
+    local s = ': '
+
+    for _, t in ipairs(self.tokens) do
+      list = list .. s .. '\''..t..'\''
+      s = ', '
+    end
+
+    list = list .. '.'
+  end
+
+  return list
+end
+
+-- marks a token as completed, checks for ordered/unordered, checks for completeness
+M.done = function(self, ...) self:_done(...) end  -- extra wrapper for same error level constant as __call method
+M._done = function(self, token)
+  if token then
+    if type(token) ~= 'string' then
+      error('Wait tokens must be strings. Got '..type(token), 3)
+    end
+
+    if self.ordered then
+      if self.tokens[1] == token then
+        table.remove(self.tokens, 1)
+        table.insert(self.tokens_done, token)
+      else
+        if self.tokens[1] then
+          error(('Bad token, expected \'%s\' got \'%s\'. %s'):format(self.tokens[1], token, self:tokenlist()), 3)
+        else
+          error(('Bad token (no more tokens expected) got \'%s\'. %s'):format(token, self:tokenlist()), 3)
+        end
+      end
+    else
+      -- unordered
+      for i, t in ipairs(self.tokens) do
+        if t == token then
+          table.remove(self.tokens, i)
+          table.insert(self.tokens_done, token)
+          token = nil
+          break
+        end
+      end
+
+      if token then
+        error(('Unknown token \'%s\'. %s'):format(token, self:tokenlist()), 3)
+      end
+    end
+  end
+  if not next(self.tokens) then
+    -- no more tokens, so we're really done...
+    self.done_cb()
+  end
+end
+
+
+-- wraps a done callback into a done-object supporting tokens to sign-off
+M.new = function(done_callback)
+  local obj = {
+    tokens = {},
+    tokens_done = {},
+    done_cb = done_callback,
+    ordered = true,  -- default for sign off of tokens
+  }
+
+  return setmetatable( obj, {
+    __call = function(self, ...)
+      self:_done(...)
+    end,
+    __index = M,
+  })
+end
+
+return M
diff --git a/test/lua/busted/environment.lua b/test/lua/busted/environment.lua
new file mode 100644 (file)
index 0000000..686b138
--- /dev/null
@@ -0,0 +1,45 @@
+local setfenv = require 'busted.compatibility'.setfenv
+
+return function(context)
+
+  local environment = {}
+
+  local function getEnv(self, key)
+    if not self then return nil end
+    return
+      self.env and self.env[key] or
+      getEnv(context.parent(self), key) or
+      _G[key]
+  end
+
+  local function setEnv(self, key, value)
+    if not self.env then self.env = {} end
+    self.env[key] = value
+  end
+
+  local function __index(self, key)
+    return getEnv(context.get(), key)
+  end
+
+  local function __newindex(self, key, value)
+    setEnv(context.get(), key, value)
+  end
+
+  local env = setmetatable({}, { __index=__index, __newindex=__newindex })
+
+  function environment.wrap(fn)
+    return setfenv(fn, env)
+  end
+
+  function environment.set(key, value)
+    local env = context.get('env')
+
+    if not env then
+      env = {}
+      context.set('env', env)
+    end
+
+    env[key] = value
+  end
+  return environment
+end
diff --git a/test/lua/busted/init.lua b/test/lua/busted/init.lua
new file mode 100644 (file)
index 0000000..da052f5
--- /dev/null
@@ -0,0 +1,227 @@
+local unpack = require 'busted.compatibility'.unpack
+local shuffle = require 'busted.utils'.shuffle
+
+local function sort(elements)
+  table.sort(elements, function(t1, t2)
+    if t1.name and t2.name then
+      return t1.name < t2.name
+    end
+    return t2.name ~= nil
+  end)
+  return elements
+end
+
+local function remove(descriptors, element)
+  for _, descriptor in ipairs(descriptors) do
+    element.env[descriptor] = function(...)
+      error("'" .. descriptor .. "' not supported inside current context block", 2)
+    end
+  end
+end
+
+local function init(busted)
+  local function exec(descriptor, element)
+    if not element.env then element.env = {} end
+
+    remove({ 'randomize' }, element)
+    remove({ 'pending' }, element)
+    remove({ 'describe', 'context', 'it', 'spec', 'test' }, element)
+    remove({ 'setup', 'teardown', 'before_each', 'after_each' }, element)
+
+    local parent = busted.context.parent(element)
+    setmetatable(element.env, {
+      __newindex = function(self, key, value)
+        if not parent.env then parent.env = {} end
+        parent.env[key] = value
+      end
+    })
+
+    local ret = { busted.safe(descriptor, element.run, element) }
+    return unpack(ret)
+  end
+
+  local function execAll(descriptor, current, propagate)
+    local parent = busted.context.parent(current)
+
+    if propagate and parent then
+      local success, ancestor = execAll(descriptor, parent, propagate)
+      if not success then
+        return success, ancestor
+      end
+    end
+
+    local list = current[descriptor] or {}
+
+    local success = true
+    for _, v in pairs(list) do
+      if not exec(descriptor, v):success() then
+        success = nil
+      end
+    end
+    return success, current
+  end
+
+  local function dexecAll(descriptor, current, propagate)
+    local parent = busted.context.parent(current)
+    local list = current[descriptor] or {}
+
+    local success = true
+    for _, v in pairs(list) do
+      if not exec(descriptor, v):success() then
+        success = nil
+      end
+    end
+
+    if propagate and parent then
+      if not dexecAll(descriptor, parent, propagate) then
+        success = nil
+      end
+    end
+    return success
+  end
+
+  local file = function(file)
+    busted.publish({ 'file', 'start' }, file.name)
+
+    busted.environment.wrap(file.run)
+    if not file.env then file.env = {} end
+
+    local randomize = busted.randomize
+    file.env.randomize = function() randomize = true end
+
+    if busted.safe('file', file.run, file):success() then
+      if randomize then
+        file.randomseed = busted.randomseed
+        shuffle(busted.context.children(file), busted.randomseed)
+      elseif busted.sort then
+        sort(busted.context.children(file))
+      end
+      if execAll('setup', file) then
+        busted.execute(file)
+      end
+      dexecAll('teardown', file)
+    end
+
+    busted.publish({ 'file', 'end' }, file.name)
+  end
+
+  local describe = function(describe)
+    local parent = busted.context.parent(describe)
+
+    busted.publish({ 'describe', 'start' }, describe, parent)
+
+    if not describe.env then describe.env = {} end
+
+    local randomize = busted.randomize
+    describe.env.randomize = function() randomize = true end
+
+    if busted.safe('describe', describe.run, describe):success() then
+      if randomize then
+        describe.randomseed = busted.randomseed
+        shuffle(busted.context.children(describe), busted.randomseed)
+      elseif busted.sort then
+        sort(busted.context.children(describe))
+      end
+      if execAll('setup', describe) then
+        busted.execute(describe)
+      end
+      dexecAll('teardown', describe)
+    end
+
+    busted.publish({ 'describe', 'end' }, describe, parent)
+  end
+
+  local it = function(element)
+    local parent = busted.context.parent(element)
+    local finally
+
+    busted.publish({ 'test', 'start' }, element, parent)
+
+    if not element.env then element.env = {} end
+
+    remove({ 'randomize' }, element)
+    remove({ 'describe', 'context', 'it', 'spec', 'test' }, element)
+    remove({ 'setup', 'teardown', 'before_each', 'after_each' }, element)
+    element.env.finally = function(fn) finally = fn end
+    element.env.pending = function(msg) busted.pending(msg) end
+
+    local status = busted.status('success')
+    local updateErrorStatus = function(descriptor)
+      if element.message then element.message = element.message .. '\n' end
+      element.message = (element.message or '') .. 'Error in ' .. descriptor
+      status:update('error')
+    end
+
+    local pass, ancestor = execAll('before_each', parent, true)
+    if pass then
+      status:update(busted.safe('it', element.run, element))
+    else
+      updateErrorStatus('before_each')
+    end
+
+    if not element.env.done then
+      remove({ 'pending' }, element)
+      if finally then status:update(busted.safe('finally', finally, element)) end
+      if not dexecAll('after_each', ancestor, true) then
+        updateErrorStatus('after_each')
+      end
+
+      busted.publish({ 'test', 'end' }, element, parent, tostring(status))
+    end
+  end
+
+  local pending = function(element)
+    local parent = busted.context.parent(element)
+    busted.publish({ 'test', 'start' }, element, parent)
+    busted.publish({ 'test', 'end' }, element, parent, 'pending')
+  end
+
+  busted.register('file', file)
+
+  busted.register('describe', describe)
+
+  busted.register('it', it)
+
+  busted.register('pending', pending)
+
+  busted.register('setup')
+  busted.register('teardown')
+  busted.register('before_each')
+  busted.register('after_each')
+
+  busted.alias('context', 'describe')
+  busted.alias('spec', 'it')
+  busted.alias('test', 'it')
+
+  local assert = require 'luassert'
+  local spy    = require 'luassert.spy'
+  local mock   = require 'luassert.mock'
+  local stub   = require 'luassert.stub'
+
+  busted.environment.set('assert', assert)
+  busted.environment.set('spy', spy)
+  busted.environment.set('mock', mock)
+  busted.environment.set('stub', stub)
+
+  busted.replaceErrorWithFail(assert)
+  busted.replaceErrorWithFail(assert.True)
+
+  return busted
+end
+
+return setmetatable({}, {
+  __call = function(self, busted)
+    local root = busted.context.get()
+    init(busted)
+
+    return setmetatable(self, {
+      __index = function(self, key)
+        return rawget(root.env, key) or busted.executors[key]
+      end,
+
+      __newindex = function(self, key, value)
+        error('Attempt to modify busted')
+      end
+    })
+  end
+})
diff --git a/test/lua/busted/languages/ar.lua b/test/lua/busted/languages/ar.lua
new file mode 100644 (file)
index 0000000..d0b96e6
--- /dev/null
@@ -0,0 +1,42 @@
+local s = require('say')
+
+s:set_namespace('ar')
+
+-- 'Pending: test.lua @ 12 \n description
+s:set('output.pending', 'عالِق')
+s:set('output.failure', 'فَشَل')
+s:set('output.failure', 'نَجاح')
+
+s:set('output.pending_plural', 'عالِق')
+s:set('output.failure_plural', 'إخْفاقات')
+s:set('output.success_plural', 'نَجاحات')
+
+s:set('output.pending_zero', 'عالِق')
+s:set('output.failure_zero', 'إخْفاقات')
+s:set('output.success_zero', 'نَجاحات')
+
+s:set('output.pending_single', 'عالِق')
+s:set('output.failure_single', 'فَشَل')
+s:set('output.success_single', 'نَجاح')
+
+s:set('output.seconds', 'ثَوانٍ')
+
+-- definitions following are not used within the 'say' namespace
+return {
+  failure_messages = {
+    'فَشِلَت %d مِنْ الإِختِبارات',
+    'فَشِلَت إخْتِباراتُك',
+    'برمجيَّتُكَ ضَعيْفة، أنْصَحُكَ بالتَّقاعُد',
+    'تقع برمجيَّتُكَ في مَنطِقَةِ الخَطَر',
+    'أقترِحُ ألّا تَتَقَدَّم بالإختِبار، علَّ يبْقى الطابِقُ مَستوراَ',
+    'جَدَّتي، فِي أَثْناءِ نَومِها، تَكتبُ بَرمَجياتٍ أفْضلُ مِن هذه',
+    'يَوَدُّ ليْ مُساعَدَتُكْ، لَكِنّْ...'
+  },
+  success_messages = {
+    'رائِع! تَمَّ إجْتِيازُ جَميعُ الإختِباراتِ بِنَجاحٍ',
+    'قُل ما شِئت، لا أكتَرِث: busted شَهِدَ لي!',
+    'حَقَّ عَليْكَ الإفتِخار',
+    'نَجاحٌ مُبْهِر!',
+    'عَليكَ بالإحتِفال؛ نَجَحَت جَميعُ التَجارُب'
+  }
+}
diff --git a/test/lua/busted/languages/de.lua b/test/lua/busted/languages/de.lua
new file mode 100644 (file)
index 0000000..e624a46
--- /dev/null
@@ -0,0 +1,42 @@
+local s = require('say')
+
+s:set_namespace('de')
+
+-- 'Pending: test.lua @ 12 \n description
+s:set('output.pending', 'Noch nicht erledigt')
+s:set('output.failure', 'Fehlgeschlagen')
+s:set('output.success', 'Erfolgreich')
+
+s:set('output.pending_plural', 'übersprungen')
+s:set('output.failure_plural', 'fehlgeschlagen')
+s:set('output.success_plural', 'erfolgreich')
+
+s:set('output.pending_zero', 'übersprungen')
+s:set('output.failure_zero', 'fehlgeschlagen')
+s:set('output.success_zero', 'erfolgreich')
+
+s:set('output.pending_single', 'übersprungen')
+s:set('output.failure_single', 'fehlgeschlagen')
+s:set('output.success_single', 'erfolgreich')
+
+s:set('output.seconds', 'Sekunden')
+
+-- definitions following are not used within the 'say' namespace
+return {
+  failure_messages = {
+    'Du hast %d kaputte Tests.',
+    'Deine Tests sind kaputt.',
+    'Dein Code ist schlecht; du solltest dich schlecht fühlen.',
+    'Dein Code befindet sich in der Gefahrenzone.',
+    'Ein seltsames Spiel. Der einzig gewinnbringende Zug ist nicht zu testen.',
+    'Meine Großmutter hat auf einem 386er bessere Tests geschrieben.',
+    'Immer wenn ein Test fehlschlägt, stirbt ein kleines Kätzchen.',
+    'Das fühlt sich schlecht an, oder?'
+  },
+  success_messages = {
+    'Yeah, die Tests laufen durch.',
+    'Fühlt sich gut an, oder?',
+    'Großartig!',
+    'Tests sind durchgelaufen, Zeit für ein Bier.',
+  }
+}
diff --git a/test/lua/busted/languages/en.lua b/test/lua/busted/languages/en.lua
new file mode 100644 (file)
index 0000000..285d1ba
--- /dev/null
@@ -0,0 +1,49 @@
+local s = require('say')
+
+s:set_namespace('en')
+
+-- 'Pending: test.lua @ 12 \n description
+s:set('output.pending', 'Pending')
+s:set('output.failure', 'Failure')
+s:set('output.error', 'Error')
+s:set('output.success', 'Success')
+
+s:set('output.pending_plural', 'pending')
+s:set('output.failure_plural', 'failures')
+s:set('output.error_plural', 'errors')
+s:set('output.success_plural', 'successes')
+
+s:set('output.pending_zero', 'pending')
+s:set('output.failure_zero', 'failures')
+s:set('output.error_zero', 'errors')
+s:set('output.success_zero', 'successes')
+
+s:set('output.pending_single', 'pending')
+s:set('output.failure_single', 'failure')
+s:set('output.error_single', 'error')
+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')
+
+-- definitions following are not used within the 'say' namespace
+return {
+  failure_messages = {
+    'You have %d busted specs',
+    'Your specs are busted',
+    'Your code is bad and you should feel bad',
+    'Your code is in the Danger Zone',
+    'Strange game. The only way to win is not to test',
+    'My grandmother wrote better specs on a 3 86',
+    'Every time there\'s a failure, drink another beer',
+    'Feels bad man'
+  },
+  success_messages = {
+    'Aww yeah, passing specs',
+    'Doesn\'t matter, had specs',
+    'Feels good, man',
+    'Great success',
+    'Tests pass, drink another beer',
+  }
+}
diff --git a/test/lua/busted/languages/fr.lua b/test/lua/busted/languages/fr.lua
new file mode 100644 (file)
index 0000000..236d87c
--- /dev/null
@@ -0,0 +1,45 @@
+local s = require('say')
+
+s:set_namespace('fr')
+
+-- 'Pending: test.lua @ 12 \n description
+s:set('output.pending', 'En attente')
+s:set('output.failure', 'Echec')
+s:set('output.success', 'Reussite')
+
+s:set('output.pending_plural', 'en attente')
+s:set('output.failure_plural', 'echecs')
+s:set('output.success_plural', 'reussites')
+
+s:set('output.pending_zero', 'en attente')
+s:set('output.failure_zero', 'echec')
+s:set('output.success_zero', 'reussite')
+
+s:set('output.pending_single', 'en attente')
+s:set('output.failure_single', 'echec')
+s:set('output.success_single', 'reussite')
+
+s:set('output.seconds', 'secondes')
+
+s:set('output.no_test_files_match', 'Aucun test n\'est pourrait trouvé qui corresponde au motif de Lua: %s')
+
+-- definitions following are not used within the 'say' namespace
+return {
+  failure_messages = {
+    'Vous avez %d test(s) qui a/ont echoue(s)',
+    'Vos tests ont echoue.',
+    'Votre code source est mauvais et vous devrez vous sentir mal',
+    'Vous avez un code source de Destruction Massive',
+    'Jeu plutot etrange game. Le seul moyen de gagner est de ne pas l\'essayer',
+    'Meme ma grand-mere ecrivait de meilleurs tests sur un PIII x86',
+    'A chaque erreur, prenez une biere',
+    'Ca craint, mon pote'
+  },
+  success_messages = {
+    'Oh yeah, tests reussis',
+    'Pas grave, y\'a eu du succes',
+    'C\'est du bon, mon pote. Que du bon!',
+    'Reussi, haut la main!',
+    'Test reussi. Un de plus. Offre toi une biere, sur mon compte!',
+  }
+}
diff --git a/test/lua/busted/languages/ja.lua b/test/lua/busted/languages/ja.lua
new file mode 100644 (file)
index 0000000..d726fa8
--- /dev/null
@@ -0,0 +1,43 @@
+local s = require('say')
+
+s:set_namespace('ja')
+
+-- 'Pending: test.lua @ 12 \n description
+s:set('output.pending', '保留')
+s:set('output.failure', '失敗')
+s:set('output.success', '成功')
+
+s:set('output.pending_plural', '保留')
+s:set('output.failure_plural', '失敗')
+s:set('output.success_plural', '成功')
+
+s:set('output.pending_zero', '保留')
+s:set('output.failure_zero', '失敗')
+s:set('output.success_zero', '成功')
+
+s:set('output.pending_single', '保留')
+s:set('output.failure_single', '失敗')
+s:set('output.success_single', '成功')
+
+s:set('output.seconds', '秒')
+
+-- definitions following are not used within the 'say' namespace
+return {
+  failure_messages = {
+    '%d個の仕様が破綻しています',
+    '仕様が破綻しています',
+    'あなたの書くコードは良くないので反省するべきです',
+    'あなたの書くコードは危険地帯にあります',
+    'おかしなゲームです。勝利する唯一の方法はテストをしないことです',
+    '私の祖母でもPentium Pentium III x86の上でもっといいコードを書いていましたよ',
+    'いつも失敗しているのでビールでも飲みましょう',
+    '罪悪感を持ちましょう',
+  },
+  success_messages = {
+    'オォーイェー、テストが通った',
+    '問題ない、テストがある',
+    '順調ですね',
+    '大成功',
+    'テストが通ったし、ビールでも飲もう',
+  }
+}
diff --git a/test/lua/busted/languages/nl.lua b/test/lua/busted/languages/nl.lua
new file mode 100644 (file)
index 0000000..6173320
--- /dev/null
@@ -0,0 +1,43 @@
+local s = require('say')
+
+s:set_namespace('nl')
+
+-- 'Pending: test.lua @ 12 \n description
+s:set('output.pending', 'Hangend')
+s:set('output.failure', 'Mislukt')
+s:set('output.success', 'Succes')
+
+s:set('output.pending_plural', 'hangenden')
+s:set('output.failure_plural', 'mislukkingen')
+s:set('output.success_plural', 'successen')
+
+s:set('output.pending_zero', 'hangend')
+s:set('output.failure_zero', 'mislukt')
+s:set('output.success_zero', 'successen')
+
+s:set('output.pending_single', 'hangt')
+s:set('output.failure_single', 'mislukt')
+s:set('output.success_single', 'succes')
+
+s:set('output.seconds', 'seconden')
+
+-- definitions following are not used within the 'say' namespace
+return {
+  failure_messages = {
+    'Je hebt %d busted specs',
+    'Je specs zijn busted',
+    'Je code is slecht en zo zou jij je ook moeten voelen',
+    'Je code zit in de Gevaren Zone',
+    'Vreemd spelletje. The enige manier om te winnen is door niet te testen',
+    'Mijn oma schreef betere specs op een 3 86',
+    'Elke keer dat iets mislukt, nog een biertje drinken',
+    'Voelt klote man'
+  },
+  success_messages = {
+    'Joeperdepoep, de specs zijn er door',
+    'Doet er niet toe, had specs',
+    'Voelt goed, man',
+    'Fantastisch success',
+    'Testen geslaagd, neem nog een biertje',
+  }
+}
diff --git a/test/lua/busted/languages/ru.lua b/test/lua/busted/languages/ru.lua
new file mode 100644 (file)
index 0000000..d0f4034
--- /dev/null
@@ -0,0 +1,37 @@
+local s = require('say')
+
+s:set_namespace('ru')
+
+-- 'Pending: test.lua @ 12 \n description
+s:set('output.pending', 'Ожидает')
+s:set('output.failure', 'Поломалcя')
+s:set('output.success', 'Прошeл')
+
+s:set('output.pending_plural', 'ожидают')
+s:set('output.failure_plural', 'поломалиcь')
+s:set('output.success_plural', 'прошли')
+
+s:set('output.pending_zero', 'ожидающих')
+s:set('output.failure_zero', 'поломанных')
+s:set('output.success_zero', 'прошедших')
+
+s:set('output.pending_single', 'ожидает')
+s:set('output.failure_single', 'поломался')
+s:set('output.success_single', 'прошел')
+
+s:set('output.seconds', 'секунд')
+
+---- definitions following are not used within the 'say' namespace
+return {
+  failure_messages = {
+    'У тебя %d просратых тестов',
+    'Твои тесты поломаны',
+    'Твой код говеный - пойди напейся!'
+  },
+  success_messages = {
+    'Поехали!',
+    'Жизнь - хороша!',
+    'Ффух в этот раз пронесло!',
+    'Ура!'
+  }
+}
diff --git a/test/lua/busted/languages/th.lua b/test/lua/busted/languages/th.lua
new file mode 100644 (file)
index 0000000..0f8e0a1
--- /dev/null
@@ -0,0 +1,43 @@
+local s = require('say')
+
+s:set_namespace('th')
+
+-- 'Pending: test.lua @ 12 \n description
+s:set('output.pending', 'อยู่ระหว่างดำเนินการ')
+s:set('output.failure', 'ล้มเหลว')
+s:set('output.success', 'สำเร็จ')
+
+s:set('output.pending_plural', 'อยู่ระหว่างดำเนินการ')
+s:set('output.failure_plural', 'ล้มเหลว')
+s:set('output.success_plural', 'สำเร็จ')
+
+s:set('output.pending_zero', 'อยู่ระหว่างดำเนินการ')
+s:set('output.failure_zero', 'ล้มเหลว')
+s:set('output.success_zero', 'สำเร็จ')
+
+s:set('output.pending_single', 'อยู่ระหว่างดำเนินการ')
+s:set('output.failure_single', 'ล้มเหลว')
+s:set('output.success_single', 'สำเร็จ')
+
+s:set('output.seconds', 'วินาที')
+
+-- definitions following are not used within the 'say' namespace
+return {
+  failure_messages = {
+    'คุณมี %d บัสเต็ดสเปค',
+    'สเปคของคุณคือ บัสเต็ด',
+    'โค้ดของคุณไม่ดีเลย คุณควรรู้สึกแย่น่ะ',
+    'โค้ดของคุณอยู่ในเขตอันตราย!',
+    'มันแปลกๆน่ะ วิธีที่จะชนะไม่ได้มีแค่เทสอย่างเดียว',
+    'ยายผมเขียนสเปคดีกว่านี้อีก บนเครื่อง 386',
+    'ทุกๆครั้งที่ล้มเหลว, ดื่มเบียร์แก้วใหม่',
+    'แย่จัง นายท่าน'
+  },
+  success_messages = {
+    'อุ๊ตะ!!!, สเปคผ่าน!',
+    'ไม่สำคัญ, มีสเปค',
+    'ฟินเลยดิ นายท่าน',
+    'สำเร็จ ยอดเยี่ยม',
+    'เทสผ่าน, ดื่มเบียร์ๆๆๆ',
+  }
+}
diff --git a/test/lua/busted/languages/ua.lua b/test/lua/busted/languages/ua.lua
new file mode 100644 (file)
index 0000000..40afcfb
--- /dev/null
@@ -0,0 +1,37 @@
+local s = require('say')
+
+s:set_namespace('ua')
+
+-- 'Pending: test.lua @ 12 \n description
+s:set('output.pending', 'Очікує')
+s:set('output.failure', 'Зламався')
+s:set('output.success', 'Пройшов')
+
+s:set('output.pending_plural', 'очікують')
+s:set('output.failure_plural', 'зламались')
+s:set('output.success_plural', 'пройшли')
+
+s:set('output.pending_zero', 'очікуючих')
+s:set('output.failure_zero', 'зламаних')
+s:set('output.success_zero', 'пройдених')
+
+s:set('output.pending_single', 'очікує')
+s:set('output.failure_single', 'зламався')
+s:set('output.success_single', 'пройшов')
+
+s:set('output.seconds', 'секунд')
+
+
+---- definitions following are not used within the 'say' namespace
+return {
+  failure_messages = {
+    'Ти зрадив %d тестів!',
+    'Ой йо..',
+    'Вороги поламали наші тести!'
+  },
+  success_messages = {
+    'Слава Україні! Героям Слава!',
+    'Тестування успішно пройдено!',
+    'Всі баги знищено!'
+  }
+}
diff --git a/test/lua/busted/languages/zh.lua b/test/lua/busted/languages/zh.lua
new file mode 100644 (file)
index 0000000..21f97e5
--- /dev/null
@@ -0,0 +1,43 @@
+local s = require('say')
+
+s:set_namespace('zh')
+
+-- 'Pending: test.lua @ 12 \n description
+s:set('output.pending', '开发中')
+s:set('output.failure', '失败')
+s:set('output.success', '成功')
+
+s:set('output.pending_plural', '开发中')
+s:set('output.failure_plural', '失败')
+s:set('output.success_plural', '成功')
+
+s:set('output.pending_zero', '开发中')
+s:set('output.failure_zero', '失败')
+s:set('output.success_zero', '成功')
+
+s:set('output.pending_single', '开发中')
+s:set('output.failure_single', '失败')
+s:set('output.success_single', '成功')
+
+s:set('output.seconds', '秒')
+
+-- definitions following are not used within the 'say' namespace 
+return {
+  failure_messages = {
+    '你一共提交了[%d]个测试用例',
+    '又出错了!',
+    '到底哪里不对呢?',
+    '出错了,又要加班了!',
+    '囧,出Bug了!',
+    '据说比尔盖兹也写了一堆Bug,别灰心!',
+    '又出错了,休息一下吧',
+    'Bug好多,心情好坏!'
+  },
+  success_messages = {
+    '牛X,测试通过了!',
+    '测试通过了,感觉不错吧,兄弟!',
+    '哥们,干得漂亮!',
+    '终于通过了!干一杯先!',
+    '阿弥陀佛~,菩萨显灵了!',
+  }
+}
diff --git a/test/lua/busted/modules/configuration_loader.lua b/test/lua/busted/modules/configuration_loader.lua
new file mode 100644 (file)
index 0000000..f437a04
--- /dev/null
@@ -0,0 +1,34 @@
+return function()
+  local tablex = require 'pl.tablex'
+
+  -- Function to load the .busted configuration file if available
+  local loadBustedConfigurationFile = function(configFile, config, defaults)
+    if type(configFile) ~= 'table' then
+      return config, '.busted file does not return a table.'
+    end
+
+    local defaults = defaults or {}
+    local run = config.run or defaults.run
+
+    if run and run ~= '' then
+      local runConfig = configFile[run]
+
+      if type(runConfig) == 'table' then
+        config = tablex.merge(runConfig, config, true)
+      else
+        return config, 'Task `' .. run .. '` not found, or not a table.'
+      end
+    end
+
+    if type(configFile.default) == 'table' then
+      config = tablex.merge(configFile.default, config, true)
+    end
+
+    config = tablex.merge(defaults, config, true)
+
+    return config
+  end
+
+  return loadBustedConfigurationFile
+end
+
diff --git a/test/lua/busted/modules/files/lua.lua b/test/lua/busted/modules/files/lua.lua
new file mode 100644 (file)
index 0000000..a4218f6
--- /dev/null
@@ -0,0 +1,24 @@
+local path = require 'pl.path'
+
+local ret = {}
+
+local getTrace =  function(filename, info)
+  local index = info.traceback:find('\n%s*%[C]')
+  info.traceback = info.traceback:sub(1, index)
+  return info, false
+end
+
+ret.match = function(busted, filename)
+  return path.extension(filename) == '.lua'
+end
+
+
+ret.load = function(busted, filename)
+  local file, err = loadfile(filename)
+  if not file then
+    busted.publish({ 'error', 'file' }, { descriptor = 'file', name = filename }, nil, err, {})
+  end
+  return file, getTrace
+end
+
+return ret
diff --git a/test/lua/busted/modules/files/moonscript.lua b/test/lua/busted/modules/files/moonscript.lua
new file mode 100644 (file)
index 0000000..145b942
--- /dev/null
@@ -0,0 +1,108 @@
+local path = require 'pl.path'
+
+local ok, moonscript, line_tables, util = pcall(function()
+  return require 'moonscript', require 'moonscript.line_tables', require 'moonscript.util'
+end)
+
+local _cache = {}
+
+-- find the line number of `pos` chars into fname
+local lookup_line = function(fname, pos)
+  if not _cache[fname] then
+    local f = io.open(fname)
+    _cache[fname] = f:read('*a')
+    f:close()
+  end
+
+  return util.pos_to_line(_cache[fname], pos)
+end
+
+local rewrite_linenumber = function(fname, lineno)
+  local tbl = line_tables['@' .. fname]
+  if fname and tbl then
+    for i = lineno, 0 ,-1 do
+      if tbl[i] then
+        return lookup_line(fname, tbl[i])
+      end
+    end
+  end
+
+  return lineno
+end
+
+local rewrite_filename = function(filename)
+  -- sometimes moonscript gives files like [string "./filename.moon"], so
+  -- we'll chop it up to only get the filename.
+  return filename:match('string "(.+)"') or filename
+end
+
+local rewrite_traceback = function(fname, trace)
+  local rewrite_one = function(line, pattern, sub)
+    if line == nil then return '' end
+
+    local fname, lineno = line:match(pattern)
+
+    if fname and lineno then
+      fname = rewrite_filename(fname)
+      local new_lineno = rewrite_linenumber(fname, tonumber(lineno))
+      if new_lineno then
+        line = line:gsub(sub:format(tonumber(lineno)), sub:format(tonumber(new_lineno)))
+      end
+    end
+
+    return line
+  end
+
+  local lines = {}
+  local j = 0
+
+  for line in trace:gmatch('[^\r\n]+') do
+    j = j + 1
+    line = rewrite_one(line, '%s*(.-):(%d+): ', ':%d:')
+    line = rewrite_one(line, '<(.*):(%d+)>', ':%d>')
+    lines[j] = line
+  end
+
+  return '\n' .. table.concat(lines, trace:match('[\r\n]+')) .. '\n'
+end
+
+local ret = {}
+
+local getTrace =  function(filename, info)
+  local index = info.traceback:find('\n%s*%[C]')
+  info.traceback = info.traceback:sub(1, index)
+
+  info.short_src = rewrite_filename(info.short_src)
+  info.traceback = rewrite_traceback(filename, info.traceback)
+  info.linedefined = rewrite_linenumber(filename, info.linedefined)
+  info.currentline = rewrite_linenumber(filename, info.currentline)
+
+  return info
+end
+
+local rewriteMessage = function(filename, message)
+  local fname, line, msg = message:match('^([^\n]-):(%d+): (.*)')
+  if not fname then
+    return message
+  end
+
+  fname = rewrite_filename(fname)
+  line = rewrite_linenumber(fname, tonumber(line))
+
+  return fname .. ':' .. tostring(line) .. ': ' .. msg
+end
+
+ret.match = function(busted, filename)
+  return ok and path.extension(filename) == '.moon'
+end
+
+
+ret.load = function(busted, filename)
+  local file, err = moonscript.loadfile(filename)
+  if not file then
+    busted.publish({ 'error', 'file' }, { descriptor = 'file', name = filename }, nil, err, {})
+  end
+  return file, getTrace, rewriteMessage
+end
+
+return ret
diff --git a/test/lua/busted/modules/files/terra.lua b/test/lua/busted/modules/files/terra.lua
new file mode 100644 (file)
index 0000000..02956f7
--- /dev/null
@@ -0,0 +1,24 @@
+local path = require 'pl.path'
+
+local ret = {}
+local ok, terralib = pcall(function() return require 'terralib' end)
+
+local getTrace =  function(filename, info)
+  local index = info.traceback:find('\n%s*%[C]')
+  info.traceback = info.traceback:sub(1, index)
+  return info
+end
+
+ret.match = function(busted, filename)
+  return ok and path.extension(filename) == '.t'
+end
+
+ret.load = function(busted, filename)
+  local file, err = terralib.loadfile(filename)
+  if not file then
+    busted.publish({ 'error', 'file' }, { descriptor = 'file', name = filename }, nil, err, {})
+  end
+  return file, getTrace
+end
+
+return ret
diff --git a/test/lua/busted/modules/helper_loader.lua b/test/lua/busted/modules/helper_loader.lua
new file mode 100644 (file)
index 0000000..166f7cc
--- /dev/null
@@ -0,0 +1,23 @@
+local utils = require 'busted.utils'
+local hasMoon, moonscript = pcall(require, 'moonscript')
+
+return function()
+  local loadHelper = function(helper, hpath, options, busted)
+    local success, err = pcall(function()
+      arg = options.arguments
+      if helper:match('%.lua$') then
+        dofile(utils.normpath(hpath))
+      elseif hasMoon and helper:match('%.moon$') then
+        moonscript.dofile(utils.normpath(hpath))
+      else
+        require(helper)
+      end
+    end)
+
+    if not success then
+      busted.publish({ 'error', 'helper' }, { descriptor = 'helper', name = helper }, nil, err, {})
+    end
+  end
+
+  return loadHelper
+end
diff --git a/test/lua/busted/modules/luacov.lua b/test/lua/busted/modules/luacov.lua
new file mode 100644 (file)
index 0000000..99cfc8f
--- /dev/null
@@ -0,0 +1,22 @@
+return function()
+  -- Function to initialize luacov if available
+  local loadLuaCov = 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')
+    end
+
+    -- call it to start
+    luacov()
+
+    -- exclude busted files
+    table.insert(luacov.configuration.exclude, 'busted_bootstrap$')
+    table.insert(luacov.configuration.exclude, 'busted%.')
+    table.insert(luacov.configuration.exclude, 'luassert%.')
+    table.insert(luacov.configuration.exclude, 'say%.')
+    table.insert(luacov.configuration.exclude, 'pl%.')
+  end
+
+  return loadLuaCov
+end
diff --git a/test/lua/busted/modules/output_handler_loader.lua b/test/lua/busted/modules/output_handler_loader.lua
new file mode 100644 (file)
index 0000000..d522118
--- /dev/null
@@ -0,0 +1,31 @@
+local utils = require 'busted.utils'
+local hasMoon, moonscript = pcall(require, 'moonscript')
+
+return function()
+  local loadOutputHandler = function(output, opath, options, busted, defaultOutput)
+    local handler
+
+    local success, err = pcall(function()
+      if output:match('%.lua$') then
+        handler = dofile(utils.normpath(opath))
+      elseif hasMoon and output:match('%.moon$') then
+        handler = moonscript.dofile(utils.normpath(opath))
+      else
+        handler = require('busted.outputHandlers.' .. output)
+      end
+    end)
+
+    if not success and err:match("module '.-' not found:") then
+      success, err = pcall(function() handler = require(output) end)
+    end
+
+    if not success then
+      busted.publish({ 'error', 'output' }, { descriptor = 'output', name = output }, nil, err, {})
+      handler = require('busted.outputHandlers.' .. defaultOutput)
+    end
+
+    return handler(options, busted)
+  end
+
+  return loadOutputHandler
+end
diff --git a/test/lua/busted/modules/test_file_loader.lua b/test/lua/busted/modules/test_file_loader.lua
new file mode 100644 (file)
index 0000000..391cce5
--- /dev/null
@@ -0,0 +1,84 @@
+local s = require 'say'
+
+return function(busted, loaders, options)
+  local path = require 'pl.path'
+  local dir = require 'pl.dir'
+  local tablex = require 'pl.tablex'
+  local shuffle = require 'busted.utils'.shuffle
+  local fileLoaders = {}
+
+  for _, v in pairs(loaders) do
+    local loader = require('busted.modules.files.'..v)
+    fileLoaders[#fileLoaders+1] = loader
+  end
+
+  local getTestFiles = function(rootFile, pattern)
+    local fileList
+
+    if path.isfile(rootFile) then
+      fileList = { rootFile }
+    elseif path.isdir(rootFile) then
+      local getfiles = options.recursive and dir.getallfiles or dir.getfiles
+      fileList = getfiles(rootFile)
+
+      fileList = tablex.filter(fileList, function(filename)
+        return path.basename(filename):find(pattern)
+      end)
+
+      fileList = tablex.filter(fileList, function(filename)
+        if path.is_windows then
+          return not filename:find('%\\%.%w+.%w+')
+        else
+          return not filename:find('/%.%w+.%w+')
+        end
+      end)
+    else
+      fileList = {}
+    end
+
+    return fileList
+  end
+
+  -- runs a testfile, loading its tests
+  local loadTestFile = function(busted, filename)
+    for _, v in pairs(fileLoaders) do
+      if v.match(busted, filename) then
+        return v.load(busted, filename)
+      end
+    end
+  end
+
+  local loadTestFiles = function(rootFile, pattern, loaders)
+    local fileList = getTestFiles(rootFile, pattern)
+
+    if options.shuffle then
+      shuffle(fileList, options.seed)
+    elseif options.sort then
+      table.sort(fileList)
+    end
+
+    for i, fileName in ipairs(fileList) do
+      local testFile, getTrace, rewriteMessage = loadTestFile(busted, fileName, loaders)
+
+      if testFile then
+        local file = setmetatable({
+          getTrace = getTrace,
+          rewriteMessage = rewriteMessage
+        }, {
+          __call = testFile
+        })
+
+        busted.executors.file(fileName, file)
+      end
+    end
+
+    if #fileList == 0 then
+      busted.publish({ 'error' }, {}, nil, s('output.no_test_files_match'):format(pattern), {})
+    end
+
+    return fileList
+  end
+
+  return loadTestFiles, loadTestFile, getTestFiles
+end
+
diff --git a/test/lua/busted/outputHandlers/TAP.lua b/test/lua/busted/outputHandlers/TAP.lua
new file mode 100644 (file)
index 0000000..b46350e
--- /dev/null
@@ -0,0 +1,51 @@
+local pretty = require 'pl.pretty'
+
+return function(options, busted)
+  local handler = require 'busted.outputHandlers.base'(busted)
+
+  handler.suiteEnd = function()
+    local total = handler.successesCount + handler.errorsCount + handler.failuresCount
+    print('1..' .. total)
+
+    local success = 'ok %u - %s'
+    local failure = 'not ' .. success
+    local counter = 0
+
+    for i,t in pairs(handler.successes) do
+      counter = counter + 1
+      print(success:format(counter, t.name))
+    end
+
+    local showFailure = function(t)
+      counter = counter + 1
+      local message = t.message
+      local trace = t.trace or {}
+
+      if message == nil then
+        message = 'Nil error'
+      elseif type(message) ~= 'string' then
+        message = pretty.write(message)
+      end
+
+      print(failure:format(counter, t.name))
+      print('# ' .. t.element.trace.short_src .. ' @ ' .. t.element.trace.currentline)
+      print('# Failure message: ' .. message:gsub('\n', '\n# '))
+      if options.verbose and trace.traceback then
+        print('# ' .. trace.traceback:gsub('^\n', '', 1):gsub('\n', '\n# '))
+      end
+    end
+
+    for i,t in pairs(handler.errors) do
+      showFailure(t)
+    end
+    for i,t in pairs(handler.failures) do
+      showFailure(t)
+    end
+
+    return nil, true
+  end
+
+  busted.subscribe({ 'suite', 'end' }, handler.suiteEnd)
+
+  return handler
+end
diff --git a/test/lua/busted/outputHandlers/base.lua b/test/lua/busted/outputHandlers/base.lua
new file mode 100644 (file)
index 0000000..5ea9540
--- /dev/null
@@ -0,0 +1,177 @@
+return function(busted)
+  local handler = {
+    successes = {},
+    successesCount = 0,
+    pendings = {},
+    pendingsCount = 0,
+    failures = {},
+    failuresCount = 0,
+    errors = {},
+    errorsCount = 0,
+    inProgress = {}
+  }
+
+  handler.cancelOnPending = function(element, parent, status)
+    return not ((element.descriptor == 'pending' or status == 'pending') and handler.options.suppressPending)
+  end
+
+  handler.subscribe = function(handler, options)
+    require('busted.languages.en')
+    handler.options = options
+
+    if options.language ~= 'en' then
+      require('busted.languages.' .. options.language)
+    end
+
+    busted.subscribe({ 'suite', 'reinitialize' }, handler.baseSuiteRepeat, { priority = 1 })
+    busted.subscribe({ 'suite', 'start' }, handler.baseSuiteStart, { priority = 1 })
+    busted.subscribe({ 'suite', 'end' }, handler.baseSuiteEnd, { priority = 1 })
+    busted.subscribe({ 'test', 'start' }, handler.baseTestStart, { priority = 1, predicate = handler.cancelOnPending })
+    busted.subscribe({ 'test', 'end' }, handler.baseTestEnd, { priority = 1, predicate = handler.cancelOnPending })
+    busted.subscribe({ 'pending' }, handler.basePending, { priority = 1, predicate = handler.cancelOnPending })
+    busted.subscribe({ 'failure', 'it' }, handler.baseTestFailure, { priority = 1 })
+    busted.subscribe({ 'error', 'it' }, handler.baseTestError, { priority = 1 })
+    busted.subscribe({ 'failure' }, handler.baseError, { priority = 1 })
+    busted.subscribe({ 'error' }, handler.baseError, { priority = 1 })
+  end
+
+  handler.getFullName = function(context)
+    local parent = busted.context.parent(context)
+    local names = { (context.name or context.descriptor) }
+
+    while parent and (parent.name or parent.descriptor) and
+          parent.descriptor ~= 'file' do
+
+      table.insert(names, 1, parent.name or parent.descriptor)
+      parent = busted.context.parent(parent)
+    end
+
+    return table.concat(names, ' ')
+  end
+
+  handler.format = function(element, parent, message, debug, isError)
+    local formatted = {
+      trace = debug or element.trace,
+      element = element,
+      name = handler.getFullName(element),
+      message = message,
+      isError = isError
+    }
+    formatted.element.trace = element.trace or debug
+
+    return formatted
+  end
+
+  handler.getDuration = function()
+    if not handler.endTime or not handler.startTime then
+      return 0
+    end
+
+    return handler.endTime - handler.startTime
+  end
+
+  handler.baseSuiteStart = function()
+    handler.startTime = os.clock()
+    return nil, true
+  end
+
+  handler.baseSuiteRepeat = function()
+    handler.successes = {}
+    handler.successesCount = 0
+    handler.pendings = {}
+    handler.pendingsCount = 0
+    handler.failures = {}
+    handler.failuresCount = 0
+    handler.errors = {}
+    handler.errorsCount = 0
+    handler.inProgress = {}
+
+    return nil, true
+  end
+
+  handler.baseSuiteEnd = function()
+    handler.endTime = os.clock()
+    return nil, true
+  end
+
+  handler.baseTestStart = function(element, parent)
+    handler.inProgress[tostring(element)] = {}
+    return nil, true
+  end
+
+  handler.baseTestEnd = function(element, parent, status, debug)
+    local isError
+    local insertTable
+
+    if status == 'success' then
+      insertTable = handler.successes
+      handler.successesCount = handler.successesCount + 1
+    elseif status == 'pending' then
+      insertTable = handler.pendings
+      handler.pendingsCount = handler.pendingsCount + 1
+    elseif status == 'failure' then
+      insertTable = handler.failures
+      -- failure count already incremented in error handler
+    elseif status == 'error' then
+      -- error count already incremented in error handler
+      insertTable = handler.errors
+      isError = true
+    end
+
+    local formatted = handler.format(element, parent, element.message, debug, isError)
+
+    local id = tostring(element)
+    if handler.inProgress[id] then
+      for k, v in pairs(handler.inProgress[id]) do
+        formatted[k] = v
+      end
+
+      handler.inProgress[id] = nil
+    end
+
+    table.insert(insertTable, formatted)
+
+    return nil, true
+  end
+
+  local function saveInProgress(element, message, debug)
+    local id = tostring(element)
+    handler.inProgress[id].message = message
+    handler.inProgress[id].trace = debug
+  end
+
+  local function saveError(element, parent, message, debug)
+    if parent.randomseed then
+      message = 'Random Seed: ' .. parent.randomseed .. '\n' .. message
+    end
+    saveInProgress(element, message, debug)
+  end
+
+  handler.basePending = function(element, parent, message, debug)
+    saveInProgress(element, message, debug)
+    return nil, true
+  end
+
+  handler.baseTestFailure = function(element, parent, message, debug)
+    handler.failuresCount = handler.failuresCount + 1
+    saveError(element, parent, message, debug)
+    return nil, true
+  end
+
+  handler.baseTestError = function(element, parent, message, debug)
+    handler.errorsCount = handler.errorsCount + 1
+    saveError(element, parent, message, debug)
+    return nil, true
+  end
+
+  handler.baseError = function(element, parent, message, debug)
+    if element.descriptor ~= 'it' then
+      handler.errorsCount = handler.errorsCount + 1
+      table.insert(handler.errors, handler.format(element, parent, message, debug, true))
+    end
+
+    return nil, true
+  end
+
+  return handler
+end
diff --git a/test/lua/busted/outputHandlers/json.lua b/test/lua/busted/outputHandlers/json.lua
new file mode 100644 (file)
index 0000000..f19a336
--- /dev/null
@@ -0,0 +1,21 @@
+local json = require 'dkjson'
+
+return function(options, busted)
+  local handler = require 'busted.outputHandlers.base'(busted)
+
+  handler.suiteEnd = function()
+    print(json.encode({
+      pendings = handler.pendings,
+      successes = handler.successes,
+      failures = handler.failures,
+      errors = handler.errors,
+      duration = handler.getDuration()
+    }))
+
+    return nil, true
+  end
+
+  busted.subscribe({ 'suite', 'end' }, handler.suiteEnd)
+
+  return handler
+end
diff --git a/test/lua/busted/outputHandlers/junit.lua b/test/lua/busted/outputHandlers/junit.lua
new file mode 100644 (file)
index 0000000..36e7893
--- /dev/null
@@ -0,0 +1,136 @@
+local xml = require 'pl.xml'
+local socket = require("socket")
+local string = require("string")
+
+return function(options, busted)
+  local handler = require 'busted.outputHandlers.base'(busted)
+  local top = {
+    start_time = socket.gettime(),
+    xml_doc = xml.new('testsuites', {
+      tests = 0,
+      errors = 0,
+      failures = 0,
+      skip = 0,
+    })
+  }
+  local stack = {}
+  local testStartTime
+
+  handler.suiteStart = function(count, total)
+    local suite = {
+      start_time = socket.gettime(),
+      xml_doc = xml.new('testsuite', {
+        name = 'Run ' .. count .. ' of ' .. total,
+        tests = 0,
+        errors = 0,
+        failures = 0,
+        skip = 0,
+        timestamp = os.date('!%Y-%m-%dT%T'),
+      })
+    }
+    top.xml_doc:add_direct_child(suite.xml_doc)
+    table.insert(stack, top)
+    top = suite
+
+    return nil, true
+  end
+
+  local function elapsed(start_time)
+    return string.format("%.2f", (socket.gettime() - start_time))
+  end
+
+  handler.suiteEnd = function(count, total)
+    local suite = top
+    suite.xml_doc.attr.time = elapsed(suite.start_time)
+
+    top = table.remove(stack)
+    top.xml_doc.attr.tests = top.xml_doc.attr.tests + suite.xml_doc.attr.tests
+    top.xml_doc.attr.errors = top.xml_doc.attr.errors + suite.xml_doc.attr.errors
+    top.xml_doc.attr.failures = top.xml_doc.attr.failures + suite.xml_doc.attr.failures
+    top.xml_doc.attr.skip = top.xml_doc.attr.skip + suite.xml_doc.attr.skip
+
+    return nil, true
+  end
+
+  handler.exit = function()
+    top.xml_doc.attr.time = elapsed(top.start_time)
+    print(xml.tostring(top.xml_doc, '', '\t', nil, false))
+
+    return nil, true
+  end
+
+  local function testStatus(element, parent, message, status, trace)
+    local testcase_node = xml.new('testcase', {
+      classname = element.trace.short_src .. ':' .. element.trace.currentline,
+      name = handler.getFullName(element),
+      time = elapsed(testStartTime)
+    })
+    top.xml_doc:add_direct_child(testcase_node)
+
+    if status ~= 'success' then
+      testcase_node:addtag(status)
+      if message then testcase_node:text(message) end
+      if trace and trace.traceback then testcase_node:text(trace.traceback) end
+      testcase_node:up()
+    end
+  end
+
+  handler.testStart = function(element, parent)
+    testStartTime = socket.gettime()
+
+    return nil, true
+  end
+
+  handler.testEnd = function(element, parent, status)
+    top.xml_doc.attr.tests = top.xml_doc.attr.tests + 1
+
+    if status == 'success' then
+      testStatus(element, parent, nil, 'success')
+    elseif status == 'pending' then
+      top.xml_doc.attr.skip = top.xml_doc.attr.skip + 1
+      local formatted = handler.pendings[#handler.pendings]
+      local trace = element.trace ~= formatted.trace and formatted.trace
+      testStatus(element, parent, formatted.message, 'skipped', trace)
+    end
+
+    return nil, true
+  end
+
+  handler.failureTest = function(element, parent, message, trace)
+    top.xml_doc.attr.failures = top.xml_doc.attr.failures + 1
+    testStatus(element, parent, message, 'failure', trace)
+    return nil, true
+  end
+
+  handler.errorTest = function(element, parent, message, trace)
+    top.xml_doc.attr.errors = top.xml_doc.attr.errors + 1
+    testStatus(element, parent, message, 'error', trace)
+    return nil, true
+  end
+
+  handler.error = function(element, parent, message, trace)
+    if element.descriptor ~= 'it' then
+      top.xml_doc.attr.errors = top.xml_doc.attr.errors + 1
+      top.xml_doc:addtag('error')
+      top.xml_doc:text(message)
+      if trace and trace.traceback then
+        top.xml_doc:text(trace.traceback)
+      end
+      top.xml_doc:up()
+    end
+
+    return nil, true
+  end
+
+  busted.subscribe({ 'exit' }, handler.exit)
+  busted.subscribe({ 'suite', 'start' }, handler.suiteStart)
+  busted.subscribe({ 'suite', 'end' }, handler.suiteEnd)
+  busted.subscribe({ 'test', 'start' }, handler.testStart, { predicate = handler.cancelOnPending })
+  busted.subscribe({ 'test', 'end' }, handler.testEnd, { predicate = handler.cancelOnPending })
+  busted.subscribe({ 'error', 'it' }, handler.errorTest)
+  busted.subscribe({ 'failure', 'it' }, handler.failureTest)
+  busted.subscribe({ 'error' }, handler.error)
+  busted.subscribe({ 'failure' }, handler.error)
+
+  return handler
+end
diff --git a/test/lua/busted/outputHandlers/plainTerminal.lua b/test/lua/busted/outputHandlers/plainTerminal.lua
new file mode 100644 (file)
index 0000000..fc4b092
--- /dev/null
@@ -0,0 +1,175 @@
+local s = require 'say'
+local pretty = require 'pl.pretty'
+
+return function(options, busted)
+  local handler = require 'busted.outputHandlers.base'(busted)
+
+  local successDot =  '+'
+  local failureDot =  '-'
+  local errorDot =  '*'
+  local pendingDot = '.'
+
+  local pendingDescription = function(pending)
+    local name = pending.name
+
+    local string = s('output.pending') .. ' → ' ..
+      pending.trace.short_src .. ' @ ' ..
+      pending.trace.currentline  ..
+      '\n' .. name
+
+    if type(pending.message) == 'string' then
+      string = string .. '\n' .. pending.message
+    elseif pending.message ~= nil then
+      string = string .. '\n' .. pretty.write(pending.message)
+    end
+
+    return string
+  end
+
+  local failureMessage = function(failure)
+    local string
+    if type(failure.message) == 'string' then
+      string = failure.message
+    elseif failure.message == nil then
+      string = 'Nil error'
+    else
+      string = pretty.write(failure.message)
+    end
+
+    return string
+  end
+
+  local failureDescription = function(failure, isError)
+    local string = s('output.failure') .. ' → '
+    if isError then
+      string = s('output.error') .. ' → '
+    end
+
+    if not failure.element.trace or not failure.element.trace.short_src then
+      string = string ..
+        failureMessage(failure) .. '\n' ..
+        failure.name
+    else
+      string = string ..
+        failure.element.trace.short_src .. ' @ ' ..
+        failure.element.trace.currentline .. '\n' ..
+        failure.name .. '\n' ..
+        failureMessage(failure)
+    end
+
+    if options.verbose and failure.trace and failure.trace.traceback then
+      string = string .. '\n' .. failure.trace.traceback
+    end
+
+    return string
+  end
+
+  local statusString = function()
+    local successString = s('output.success_plural')
+    local failureString = s('output.failure_plural')
+    local pendingString = s('output.pending_plural')
+    local errorString = s('output.error_plural')
+
+    local ms = handler.getDuration()
+    local successes = handler.successesCount
+    local pendings = handler.pendingsCount
+    local failures = handler.failuresCount
+    local errors = handler.errorsCount
+
+    if successes == 0 then
+      successString = s('output.success_zero')
+    elseif successes == 1 then
+      successString = s('output.success_single')
+    end
+
+    if failures == 0 then
+      failureString = s('output.failure_zero')
+    elseif failures == 1 then
+      failureString = s('output.failure_single')
+    end
+
+    if pendings == 0 then
+      pendingString = s('output.pending_zero')
+    elseif pendings == 1 then
+      pendingString = s('output.pending_single')
+    end
+
+    if errors == 0 then
+      errorString = s('output.error_zero')
+    elseif errors == 1 then
+      errorString = s('output.error_single')
+    end
+
+    local formattedTime = ('%.6f'):format(ms):gsub('([0-9])0+$', '%1')
+
+    return successes .. ' ' .. successString .. ' / ' ..
+      failures .. ' ' .. failureString .. ' / ' ..
+      errors .. ' ' .. errorString .. ' / ' ..
+      pendings .. ' ' .. pendingString .. ' : ' ..
+      formattedTime .. ' ' .. s('output.seconds')
+  end
+
+  handler.testEnd = function(element, parent, status, debug)
+    if not options.deferPrint then
+      local string = successDot
+
+      if status == 'pending' then
+        string = pendingDot
+      elseif status == 'failure' then
+        string = failureDot
+      elseif status == 'error' then
+        string = errorDot
+      end
+
+      io.write(string)
+      io.flush()
+    end
+
+    return nil, true
+  end
+
+  handler.suiteStart = function(count, total)
+    local runString = (total > 1 and '\nRepeating all tests (run %d of %d) . . .\n\n' or '')
+    io.write(runString:format(count, total))
+    io.flush()
+  end
+
+  handler.suiteEnd = function()
+    print('')
+    print(statusString())
+
+    for i, pending in pairs(handler.pendings) do
+      print('')
+      print(pendingDescription(pending))
+    end
+
+    for i, err in pairs(handler.failures) do
+      print('')
+      print(failureDescription(err))
+    end
+
+    for i, err in pairs(handler.errors) do
+      print('')
+      print(failureDescription(err, true))
+    end
+
+    return nil, true
+  end
+
+  handler.error = function(element, parent, message, debug)
+    io.write(errorDot)
+    io.flush()
+
+    return nil, true
+  end
+
+  busted.subscribe({ 'test', 'end' }, handler.testEnd, { predicate = handler.cancelOnPending })
+  busted.subscribe({ 'suite', 'start' }, handler.suiteStart)
+  busted.subscribe({ 'suite', 'end' }, handler.suiteEnd)
+  busted.subscribe({ 'error', 'file' }, handler.error)
+  busted.subscribe({ 'failure', 'file' }, handler.error)
+  busted.subscribe({ 'error', 'describe' }, handler.error)
+  busted.subscribe({ 'failure', 'describe' }, handler.error)
+
+  return handler
+end
diff --git a/test/lua/busted/outputHandlers/sound.lua b/test/lua/busted/outputHandlers/sound.lua
new file mode 100644 (file)
index 0000000..8ac1a46
--- /dev/null
@@ -0,0 +1,36 @@
+local app = require 'pl.app'
+return function(options, busted)
+  local handler = require 'busted.outputHandlers.base'(busted)
+  local language = require('busted.languages.' .. options.language)
+
+  handler.suiteEnd = function()
+    local system = app.platform()
+    local sayer_pre, sayer_post
+    local messages
+
+    if system == 'Linux' then
+      sayer_pre = 'espeak -s 160 '
+      sayer_post = ' > /dev/null 2>&1'
+    elseif system and system:match('^Windows') then
+      sayer_pre = 'echo '
+      sayer_post = ' | ptts'
+    else
+      sayer_pre = 'say '
+      sayer_post = ''
+    end
+
+    if handler.failuresCount > 0 then
+      messages = language.failure_messages
+    else
+      messages = language.success_messages
+    end
+
+    io.popen(sayer_pre .. '"' .. messages[math.random(1, #messages)] .. '"' .. sayer_post)
+
+    return nil, true
+  end
+
+  busted.subscribe({ 'suite', 'end' }, handler.suiteEnd)
+
+  return handler
+end
diff --git a/test/lua/busted/outputHandlers/utfTerminal.lua b/test/lua/busted/outputHandlers/utfTerminal.lua
new file mode 100644 (file)
index 0000000..f34015c
--- /dev/null
@@ -0,0 +1,176 @@
+local ansicolors = require 'ansicolors'
+local s = require 'say'
+local pretty = require 'pl.pretty'
+
+return function(options, busted)
+  local handler = require 'busted.outputHandlers.base'(busted)
+
+  local successDot = ansicolors('%{green}●')
+  local failureDot = ansicolors('%{red}◼')
+  local errorDot   = ansicolors('%{magenta}✱')
+  local pendingDot = ansicolors('%{yellow}◌')
+
+  local pendingDescription = function(pending)
+    local name = pending.name
+
+    local string = ansicolors('%{yellow}' .. s('output.pending')) .. ' → ' ..
+      ansicolors('%{cyan}' .. pending.trace.short_src) .. ' @ ' ..
+      ansicolors('%{cyan}' .. pending.trace.currentline)  ..
+      '\n' .. ansicolors('%{bright}' .. name)
+
+    if type(pending.message) == 'string' then
+      string = string .. '\n' .. pending.message
+    elseif pending.message ~= nil then
+      string = string .. '\n' .. pretty.write(pending.message)
+    end
+
+    return string
+  end
+
+  local failureMessage = function(failure)
+    local string
+    if type(failure.message) == 'string' then
+      string = failure.message
+    elseif failure.message == nil then
+      string = 'Nil error'
+    else
+      string = pretty.write(failure.message)
+    end
+
+    return string
+  end
+
+  local failureDescription = function(failure, isError)
+    local string = ansicolors('%{red}' .. s('output.failure')) .. ' → '
+    if isError then
+      string = ansicolors('%{magenta}' .. s('output.error')) .. ' → '
+    end
+
+    if not failure.element.trace or not failure.element.trace.short_src then
+      string = string ..
+        ansicolors('%{cyan}' .. failureMessage(failure)) .. '\n' ..
+        ansicolors('%{bright}' .. failure.name)
+    else
+      string = string ..
+        ansicolors('%{cyan}' .. failure.element.trace.short_src) .. ' @ ' ..
+        ansicolors('%{cyan}' .. failure.element.trace.currentline) .. '\n' ..
+        ansicolors('%{bright}' .. failure.name) .. '\n' ..
+        failureMessage(failure)
+    end
+
+    if options.verbose and failure.trace and failure.trace.traceback then
+      string = string .. '\n' .. failure.trace.traceback
+    end
+
+    return string
+  end
+
+  local statusString = function()
+    local successString = s('output.success_plural')
+    local failureString = s('output.failure_plural')
+    local pendingString = s('output.pending_plural')
+    local errorString = s('output.error_plural')
+
+    local ms = handler.getDuration()
+    local successes = handler.successesCount
+    local pendings = handler.pendingsCount
+    local failures = handler.failuresCount
+    local errors = handler.errorsCount
+
+    if successes == 0 then
+      successString = s('output.success_zero')
+    elseif successes == 1 then
+      successString = s('output.success_single')
+    end
+
+    if failures == 0 then
+      failureString = s('output.failure_zero')
+    elseif failures == 1 then
+      failureString = s('output.failure_single')
+    end
+
+    if pendings == 0 then
+      pendingString = s('output.pending_zero')
+    elseif pendings == 1 then
+      pendingString = s('output.pending_single')
+    end
+
+    if errors == 0 then
+      errorString = s('output.error_zero')
+    elseif errors == 1 then
+      errorString = s('output.error_single')
+    end
+
+    local formattedTime = ('%.6f'):format(ms):gsub('([0-9])0+$', '%1')
+
+    return ansicolors('%{green}' .. successes) .. ' ' .. successString .. ' / ' ..
+      ansicolors('%{red}' .. failures) .. ' ' .. failureString .. ' / ' ..
+      ansicolors('%{magenta}' .. errors) .. ' ' .. errorString .. ' / ' ..
+      ansicolors('%{yellow}' .. pendings) .. ' ' .. pendingString .. ' : ' ..
+      ansicolors('%{bright}' .. formattedTime) .. ' ' .. s('output.seconds')
+  end
+
+  handler.testEnd = function(element, parent, status, debug)
+    if not options.deferPrint then
+      local string = successDot
+
+      if status == 'pending' then
+        string = pendingDot
+      elseif status == 'failure' then
+        string = failureDot
+      elseif status == 'error' then
+        string = errorDot
+      end
+
+      io.write(string)
+      io.flush()
+    end
+
+    return nil, true
+  end
+
+  handler.suiteStart = function(count, total)
+    local runString = (total > 1 and '\nRepeating all tests (run %d of %d) . . .\n\n' or '')
+    io.write(runString:format(count, total))
+    io.flush()
+  end
+
+  handler.suiteEnd = function(count, total)
+    print('')
+    print(statusString())
+
+    for i, pending in pairs(handler.pendings) do
+      print('')
+      print(pendingDescription(pending))
+    end
+
+    for i, err in pairs(handler.failures) do
+      print('')
+      print(failureDescription(err))
+    end
+
+    for i, err in pairs(handler.errors) do
+      print('')
+      print(failureDescription(err, true))
+    end
+
+    return nil, true
+  end
+
+  handler.error = function(element, parent, message, debug)
+    io.write(errorDot)
+    io.flush()
+
+    return nil, true
+  end
+
+  busted.subscribe({ 'test', 'end' }, handler.testEnd, { predicate = handler.cancelOnPending })
+  busted.subscribe({ 'suite', 'start' }, handler.suiteStart)
+  busted.subscribe({ 'suite', 'end' }, handler.suiteEnd)
+  busted.subscribe({ 'error', 'file' }, handler.error)
+  busted.subscribe({ 'failure', 'file' }, handler.error)
+  busted.subscribe({ 'error', 'describe' }, handler.error)
+  busted.subscribe({ 'failure', 'describe' }, handler.error)
+
+  return handler
+end
diff --git a/test/lua/busted/runner.lua b/test/lua/busted/runner.lua
new file mode 100644 (file)
index 0000000..91ce94e
--- /dev/null
@@ -0,0 +1,400 @@
+-- Busted command-line runner
+
+local path = require 'pl.path'
+local term = require 'term'
+local utils = require 'busted.utils'
+local loaded = false
+
+return function(options)
+  if loaded then return else loaded = true end
+
+  local opt = options or {}
+  local isBatch = opt.batch
+  local cli = require 'cliargs'
+  local busted = require 'busted.core'()
+
+  local configLoader = require 'busted.modules.configuration_loader'()
+  local helperLoader = require 'busted.modules.helper_loader'()
+  local outputHandlerLoader = require 'busted.modules.output_handler_loader'()
+
+  local luacov = require 'busted.modules.luacov'()
+
+  local osexit = require 'busted.compatibility'.osexit
+
+  require 'busted'(busted)
+
+  -- Default cli arg values
+  local defaultOutput = term.isatty(io.stdout) and 'utfTerminal' or 'plainTerminal'
+  local defaultLoaders = 'lua,moonscript'
+  local defaultPattern = '_spec'
+  local defaultSeed = '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;'
+
+  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 cliArgsParsed = {}
+
+  local function processOption(key, value, altkey, opt)
+    if altkey then cliArgsParsed[altkey] = value end
+    cliArgsParsed[key] = value
+    return true
+  end
+
+  local function processNumber(key, value, altkey, opt)
+    local number = tonumber(value)
+    if not number then
+      return nil, 'argument to ' .. opt:gsub('=.*', '') .. ' must be a number'
+    end
+    if altkey then cliArgsParsed[altkey] = number end
+    cliArgsParsed[key] = number
+    return true
+  end
+
+  local function processVersion()
+    -- Return early if asked for the version
+    print(busted.version)
+    osexit(0, true)
+  end
+
+  -- Load up the command-line interface options
+  cli:set_name(path.basename(fileName))
+  cli:add_flag('--version', 'prints the program version and exits', processVersion)
+
+  if isBatch then
+    cli:optarg('ROOT', 'test script file/folder. Folders will be traversed for any file that matches the --pattern option.', 'spec', 1)
+
+    cli:add_option('-p, --pattern=PATTERN', 'only run test files matching the Lua pattern', defaultPattern, processOption)
+  end
+
+  cli:add_option('-o, --output=LIBRARY', 'output library to load', defaultOutput, processOption)
+  cli:add_option('-d, --cwd=cwd', 'path to current working directory', './', processOption)
+  cli:add_option('-t, --tags=TAGS', 'only run tests with these #tags', nil, processOption)
+  cli:add_option('--exclude-tags=TAGS', 'do not run tests with these #tags, takes precedence over --tags', nil, processOption)
+  cli:add_option('--filter=PATTERN', 'only run test names matching the Lua pattern', nil, processOption)
+  cli:add_option('--filter-out=PATTERN', 'do not run test names matching the Lua pattern, takes precedence over --filter', nil, processOption)
+  cli:add_option('-m, --lpath=PATH', 'optional path to be prefixed to the Lua module search path', lpathprefix, processOption)
+  cli:add_option('--cpath=PATH', 'optional path to be prefixed to the Lua C module search path', cpathprefix, processOption)
+  cli:add_option('-r, --run=RUN', 'config to run from .busted file', nil, processOption)
+  cli:add_option('--repeat=COUNT', 'run the tests repeatedly', '1', processNumber)
+  cli:add_option('--seed=SEED', 'random seed value to use for shuffling test order', defaultSeed, processNumber)
+  cli:add_option('--lang=LANG', 'language for error messages', 'en', processOption)
+  cli:add_option('--loaders=NAME', 'test file loaders', defaultLoaders, processOption)
+  cli:add_option('--helper=PATH', 'A helper script that is run before tests', nil, processOption)
+
+  cli:add_option('-Xoutput OPTION', 'pass `OPTION` as an option to the output handler. If `OPTION` contains commas, it is split into multiple options at the commas.', nil, processOption)
+  cli:add_option('-Xhelper OPTION', 'pass `OPTION` as an option to the helper script. If `OPTION` contains commas, it is split into multiple options at the commas.', nil, processOption)
+
+  cli:add_flag('-c, --coverage', 'do code coverage analysis (requires `LuaCov` to be installed)', processOption)
+  cli:add_flag('-v, --verbose', 'verbose output of errors', processOption)
+  cli:add_flag('-s, --enable-sound', 'executes `say` command if available', processOption)
+  cli:add_flag('-l, --list', 'list the names of all tests instead of running them', processOption)
+  cli:add_flag('--no-keep-going', 'quit after first error or failure', processOption)
+  cli:add_flag('--no-recursive', 'do not recurse into subdirectories', processOption)
+  cli:add_flag('--shuffle', 'randomize file and test order, takes precedence over --sort (--shuffle-test and --shuffle-files)', processOption)
+  cli:add_flag('--shuffle-files', 'randomize file execution order, takes precedence over --sort-files', processOption)
+  cli:add_flag('--shuffle-tests', 'randomize test order within a file, takes precedence over --sort-tests', processOption)
+  cli:add_flag('--sort', 'sort file and test order (--sort-tests and --sort-files)', processOption)
+  cli:add_flag('--sort-files', 'sort file execution order', processOption)
+  cli:add_flag('--sort-tests', 'sort test order within a file', processOption)
+  cli:add_flag('--suppress-pending', 'suppress `pending` test output', processOption)
+  cli:add_flag('--defer-print', 'defer print to when test suite is complete', processOption)
+
+  -- Parse the cli arguments
+  local cliArgs = cli:parse(arg)
+  if not cliArgs then
+    osexit(1, true)
+  end
+
+  -- Load current working directory
+  local fpath = utils.normpath(cliArgs.cwd)
+
+  -- Load busted config file if available
+  local configFile = { }
+  local bustedConfigFilePath = utils.normpath(path.join(fpath, '.busted'))
+  local bustedConfigFile = pcall(function() configFile = loadfile(bustedConfigFilePath)() end)
+  if bustedConfigFile then
+    local config, err = configLoader(configFile, cliArgsParsed, cliArgs)
+    if err then
+      print('Error: ' .. err)
+      osexit(1, true)
+    else
+      cliArgs = config
+    end
+  end
+
+  local tags = {}
+  local excludeTags = {}
+
+  if cliArgs.tags and cliArgs.tags ~= '' then
+    tags = utils.split(cliArgs.tags, ',')
+  end
+
+  if cliArgs['exclude-tags'] and cliArgs['exclude-tags'] ~= '' then
+    excludeTags = utils.split(cliArgs['exclude-tags'], ',')
+  end
+
+  -- If coverage arg is passed in, load LuaCovsupport
+  if cliArgs.coverage then
+    luacov()
+  end
+
+  -- Add additional package paths based on lpath and cpath cliArgs
+  if #cliArgs.lpath > 0 then
+    lpathprefix = cliArgs.lpath
+    lpathprefix = lpathprefix:gsub('^%.([/%\\])', fpath .. '%1')
+    lpathprefix = lpathprefix:gsub(';%.([/%\\])', ';' .. fpath .. '%1')
+    package.path = (lpathprefix .. ';' .. package.path):gsub(';;',';')
+  end
+
+  if #cliArgs.cpath > 0 then
+    cpathprefix = cliArgs.cpath
+    cpathprefix = cpathprefix:gsub('^%.([/%\\])', fpath .. '%1')
+    cpathprefix = cpathprefix:gsub(';%.([/%\\])', ';' .. fpath .. '%1')
+    package.cpath = (cpathprefix .. ';' .. package.cpath):gsub(';;',';')
+  end
+
+  local loaders = {}
+  if #cliArgs.loaders > 0 then
+    string.gsub(cliArgs.loaders, '([^,]+)', function(c) loaders[#loaders+1] = c end)
+  end
+
+  -- We report an error if the same tag appears in both `options.tags`
+  -- and `options.excluded_tags` because it does not make sense for the
+  -- user to tell Busted to include and exclude the same tests at the
+  -- same time.
+  for _, excluded in pairs(excludeTags) do
+    for _, included in pairs(tags) do
+      if excluded == included then
+        print('Error: Cannot use --tags and --exclude-tags for the same tags')
+        osexit(1, true)
+      end
+    end
+  end
+
+  -- watch for test errors
+  local failures = 0
+  local errors = 0
+  local quitOnError = cliArgs['no-keep-going']
+
+  busted.subscribe({ 'error', 'output' }, function(element, parent, message)
+    print('Error: Cannot load output library: ' .. element.name .. '\n' .. message)
+    return nil, true
+  end)
+
+  busted.subscribe({ 'error', 'helper' }, function(element, parent, message)
+    print('Error: Cannot load helper script: ' .. element.name .. '\n' .. message)
+    return nil, true
+  end)
+
+  busted.subscribe({ 'error' }, function(element, parent, message)
+    errors = errors + 1
+    busted.skipAll = quitOnError
+    return nil, true
+  end)
+
+  busted.subscribe({ 'failure' }, function(element, parent, message)
+    if element.descriptor == 'it' then
+      failures = failures + 1
+    else
+      errors = errors + 1
+    end
+    busted.skipAll = quitOnError
+    return nil, true
+  end)
+
+  -- Set up output handler to listen to events
+  local outputHandlerOptions = {
+    verbose = cliArgs.verbose,
+    suppressPending = cliArgs['suppress-pending'],
+    language = cliArgs.lang,
+    deferPrint = cliArgs['defer-print'],
+    arguments = utils.split(cliArgs.Xoutput or '', ',') or {}
+  }
+
+  local opath = utils.normpath(path.join(fpath, cliArgs.output))
+  local outputHandler = outputHandlerLoader(cliArgs.output, opath, outputHandlerOptions, busted, defaultOutput)
+  outputHandler:subscribe(outputHandlerOptions)
+
+  if cliArgs['enable-sound'] then
+    require 'busted.outputHandlers.sound'(outputHandlerOptions, busted)
+  end
+
+  -- Set up randomization options
+  busted.sort = cliArgs['sort-tests'] or cliArgs.sort
+  busted.randomize = cliArgs['shuffle-tests'] or cliArgs.shuffle
+  busted.randomseed = tonumber(cliArgs.seed) or os.time()
+
+  local getFullName = function(name)
+    local parent = busted.context.get()
+    local names = { name }
+
+    while parent and (parent.name or parent.descriptor) and
+          parent.descriptor ~= 'file' do
+      table.insert(names, 1, parent.name or parent.descriptor)
+      parent = busted.context.parent(parent)
+    end
+
+    return table.concat(names, ' ')
+  end
+
+  local hasTag = function(name, tag)
+    local found = name:find('#' .. tag)
+    return (found ~= nil)
+  end
+
+  local filterExcludeTags = function(name)
+    for i, tag in pairs(excludeTags) do
+      if hasTag(name, tag) then
+        return nil, false
+      end
+    end
+    return nil, true
+  end
+
+  local filterTags = function(name)
+    local fullname = getFullName(name)
+    for i, tag in pairs(tags) do
+      if hasTag(fullname, tag) then
+        return nil, true
+      end
+    end
+    return nil, (#tags == 0)
+  end
+
+  local filterOutNames = function(name)
+    local found = (getFullName(name):find(cliArgs['filter-out']) ~= nil)
+    return nil, not found
+  end
+
+  local filterNames = function(name)
+    local found = (getFullName(name):find(cliArgs.filter) ~= nil)
+    return nil, found
+  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
+      print(fullname)
+    end
+    return nil, false
+  end
+
+  local ignoreAll = function()
+    return nil, false
+  end
+
+  local skipOnError = function()
+    return nil, (failures == 0 and errors == 0)
+  end
+
+  local applyFilter = function(descriptors, name, fn)
+    if cliArgs[name] and cliArgs[name] ~= '' then
+      for _, descriptor in ipairs(descriptors) do
+        busted.subscribe({ 'register', descriptor }, fn, { priority = 1 })
+      end
+    end
+  end
+
+  if cliArgs.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({ 'it', 'pending' }, 'list', printNameOnly)
+  end
+
+  applyFilter({ 'setup', 'teardown', 'before_each', 'after_each' }, 'no-keep-going', skipOnError)
+  applyFilter({ 'file', 'describe', 'it', 'pending' }, 'no-keep-going', skipOnError)
+
+  -- The following filters are applied in reverse order
+  applyFilter({ 'it', 'pending' }            , 'filter'      , filterNames      )
+  applyFilter({ 'describe', 'it', 'pending' }, 'filter-out'  , filterOutNames   )
+  applyFilter({ 'it', 'pending' }            , 'tags'        , filterTags       )
+  applyFilter({ 'describe', 'it', 'pending' }, 'exclude-tags', filterExcludeTags)
+
+  -- Set up helper script
+  if cliArgs.helper and cliArgs.helper ~= '' then
+    local helperOptions = {
+      verbose = cliArgs.verbose,
+      language = cliArgs.lang,
+      arguments = utils.split(cliArgs.Xhelper or '', ',') or {}
+    }
+
+    local hpath = utils.normpath(path.join(fpath, cliArgs.helper))
+    helperLoader(cliArgs.helper, hpath, helperOptions, busted)
+  end
+
+  -- Set up test loader options
+  local testFileLoaderOptions = {
+    verbose = cliArgs.verbose,
+    sort = cliArgs['sort-files'] or cliArgs.sort,
+    shuffle = cliArgs['shuffle-files'] or cliArgs.shuffle,
+    recursive = not cliArgs['no-recursive'],
+    seed = busted.randomseed
+  }
+
+  -- Load test directory
+  local rootFile = cliArgs.ROOT and utils.normpath(path.join(fpath, cliArgs.ROOT)) or fileName
+  local pattern = cliArgs.pattern
+  local testFileLoader = require 'busted.modules.test_file_loader'(busted, loaders, testFileLoaderOptions)
+  local fileList = testFileLoader(rootFile, pattern)
+
+  if not cliArgs.ROOT then
+    local ctx = busted.context.get()
+    local file = busted.context.children(ctx)[1]
+    getmetatable(file.run).__call = info.func
+  end
+
+  busted.subscribe({'suite', 'reinitialize'}, function()
+    local oldctx = busted.context.get()
+    local children = busted.context.children(oldctx)
+
+    busted.context.clear()
+    local ctx = busted.context.get()
+    for k, v in pairs(oldctx) do
+      ctx[k] = v
+    end
+
+    for _, child in pairs(children) do
+      for descriptor, _ in pairs(busted.executors) do
+        child[descriptor] = nil
+      end
+      busted.context.attach(child)
+    end
+
+    busted.randomseed = tonumber(cliArgs.seed) or os.time()
+
+    return nil, true
+  end)
+
+  local runs = tonumber(cliArgs['repeat']) or 1
+  for i = 1, runs do
+    if i > 1 then
+      busted.publish({ 'suite', 'reinitialize' })
+    end
+
+    busted.publish({ 'suite', 'start' }, i, runs)
+    busted.execute()
+    busted.publish({ 'suite', 'end' }, i, runs)
+
+    if quitOnError and (failures > 0 or errors > 0) then
+      break
+    end
+  end
+
+  busted.publish({ 'exit' })
+
+  local exit = 0
+  if failures > 0 or errors > 0 then
+    exit = failures + errors
+    if exit > 255 then
+      exit = 255
+    end
+  end
+  osexit(exit, true)
+end
diff --git a/test/lua/busted/status.lua b/test/lua/busted/status.lua
new file mode 100644 (file)
index 0000000..c68ce7f
--- /dev/null
@@ -0,0 +1,43 @@
+local function get_status(status)
+  local smap = {
+    ['success'] = 'success',
+    ['pending'] = 'pending',
+    ['failure'] = 'failure',
+    ['error'] = 'error',
+    ['true'] = 'success',
+    ['false'] = 'failure',
+    ['nil'] = 'error',
+  }
+  return smap[tostring(status)] or 'error'
+end
+
+return function(inital_status)
+  local objstat = get_status(inital_status)
+  local obj = {
+    success = function(self) return (objstat == 'success') end,
+    pending = function(self) return (objstat == 'pending') end,
+    failure = function(self) return (objstat == 'failure') end,
+    error   = function(self) return (objstat == 'error') end,
+
+    get = function(self)
+      return objstat
+    end,
+
+    set = function(self, status)
+      objstat = get_status(status)
+    end,
+
+    update = function(self, status)
+      -- prefer current failure/error status over new status
+      status = get_status(status)
+      if objstat == 'success' or (objstat == 'pending' and status ~= 'success') then
+        objstat = status
+      end
+    end
+  }
+
+  return setmetatable(obj, {
+    __index = {},
+    __tostring = function(self) return objstat end
+  })
+end
diff --git a/test/lua/busted/utils.lua b/test/lua/busted/utils.lua
new file mode 100644 (file)
index 0000000..4e02bc0
--- /dev/null
@@ -0,0 +1,53 @@
+local path = require 'pl.path'
+
+math.randomseed(os.time())
+
+-- Do not use pl.path.normpath
+-- It is broken for paths with leading '../../'
+local function normpath(fpath)
+  if type(fpath) ~= 'string' then
+    error(fpath .. ' is not a string')
+  end
+  local sep = '/'
+  if path.is_windows then
+    sep = '\\'
+    if fpath:match '^\\\\' then -- UNC
+      return '\\\\' .. normpath(fpath:sub(3))
+    end
+    fpath = fpath:gsub('/','\\')
+  end
+  local np_gen1, np_gen2 = '([^SEP]+)SEP(%.%.SEP?)', 'SEP+%.?SEP'
+  local np_pat1 = np_gen1:gsub('SEP', sep)
+  local np_pat2 = np_gen2:gsub('SEP', sep)
+  local k
+  repeat -- /./ -> /
+    fpath, k = fpath:gsub(np_pat2, sep)
+  until k == 0
+  repeat -- A/../ -> (empty)
+    local oldpath = fpath
+    fpath, k = fpath:gsub(np_pat1, function(d, up)
+      if d == '..' then return nil end
+      if d == '.' then return up end
+      return ''
+    end)
+  until k == 0 or oldpath == fpath
+  if fpath == '' then fpath = '.' end
+  return fpath
+end
+
+return {
+  split = require 'pl.utils'.split,
+
+  normpath = normpath,
+
+  shuffle = function(t, seed)
+    if seed then math.randomseed(seed) end
+    local n = #t
+    while n >= 2 do
+      local k = math.random(n)
+      t[n], t[k] = t[k], t[n]
+      n = n - 1
+    end
+    return t
+  end
+}
index 83a6a9e4576ae0fb6cbafe00234ee11e27b35eec..073062fd14228a06bd8d2d95a91d0485752226de 100644 (file)
@@ -1,39 +1,47 @@
 -- Test rsa signing
 
-local pubkey = 'testkey.pub'
-local privkey = 'testkey'
-local data = 'test.data'
-local signature = 'test.sig'
+require "busted" ()
 
--- Signing test
-local rsa_key = rsa_privkey.load(string.format('%s/%s', test_dir, privkey))
+describe("rsa signarture test", function()
+  local rsa_privkey = require "rspamd_rsa_privkey"
+  local rsa_pubkey = require "rspamd_rsa_pubkey"
+  local rsa_signature = require "rspamd_rsa_signature"
+  local rsa = require "rspamd_rsa"
+  local pubkey = 'testkey.pub'
+  local privkey = 'testkey'
+  local data = 'test.data'
+  local signature = 'test.sig'
 
-if not rsa_key then
-       return -1
-end
+  -- Signing test
+  local rsa_key = rsa_privkey.load(string.format('%s/%s', test_dir, privkey))
 
-local rsa_sig = rsa.sign_file(rsa_key, string.format('%s/%s', test_dir, data))
+  if not rsa_key then
+    return -1
+  end
 
-if not rsa_sig then
-       return -1
-end
+  local rsa_sig = rsa.sign_file(rsa_key, string.format('%s/%s', test_dir, data))
 
-rsa_sig:save(string.format('%s/%s', test_dir, signature), true)
+  if not rsa_sig then
+    return -1
+  end
 
--- Verifying test
-rsa_key = rsa_pubkey.load(string.format('%s/%s', test_dir, pubkey))
+  rsa_sig:save(string.format('%s/%s', test_dir, signature), true)
 
-if not rsa_key then
-       return -1
-end
+  -- Verifying test
+  rsa_key = rsa_pubkey.load(string.format('%s/%s', test_dir, pubkey))
 
-rsa_sig = rsa_signature.load(string.format('%s/%s', test_dir, signature))
+  if not rsa_key then
+    return -1
+  end
 
-if not rsa_sig then
-       return -1
-end
+  rsa_sig = rsa_signature.load(string.format('%s/%s', test_dir, signature))
 
-if not rsa.verify_file(rsa_key, rsa_sig, string.format('%s/%s', test_dir, data)) then
-       return -1
-end
+  if not rsa_sig then
+    return -1
+  end
 
+  if not rsa.verify_file(rsa_key, rsa_sig, string.format('%s/%s', test_dir, data)) then
+    return -1
+  end
+
+end)
index 46303b35686a66ada7bc2b721868eff42831be00..da9405fa5adce66a3d16f89e5b02e201ca174248 100644 (file)
@@ -37,6 +37,7 @@ rspamd_lua_test_func (void)
        glob_t globbuf;
        gchar *pattern;
        guint i, len;
+       struct stat st;
 
        msg_info ("Starting lua tests");
 
@@ -54,6 +55,15 @@ rspamd_lua_test_func (void)
                for (i = 0; i < globbuf.gl_pathc; i++) {
                        lua_file = globbuf.gl_pathv[i];
 
+                       if (stat (lua_file, &st) == -1 || !S_ISREG (st.st_mode)) {
+                               continue;
+                       }
+
+                       if (strstr (lua_file, "busted") != NULL) {
+                               /* Skip busted code itself */
+                               continue;
+                       }
+
                        if (luaL_loadfile (L, lua_file) != 0) {
                                msg_err ("load test from %s failed", lua_file);
                                g_assert (0);