]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
Rework lua tests one more time.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Sat, 28 Feb 2015 00:11:56 +0000 (00:11 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Sat, 28 Feb 2015 00:11:56 +0000 (00:11 +0000)
12 files changed:
config.h.in
test/CMakeLists.txt
test/lua/compat_env.lua [new file with mode: 0644]
test/lua/telescope.lua [new file with mode: 0644]
test/lua/tests.lua [new file with mode: 0644]
test/lua/unit/rsa.lua [moved from test/lua/rsa.lua with 100% similarity]
test/lua/unit/test.data [moved from test/lua/test.data with 100% similarity]
test/lua/unit/testkey [moved from test/lua/testkey with 100% similarity]
test/lua/unit/testkey.pub [moved from test/lua/testkey.pub with 100% similarity]
test/rspamd_lua_test.c
test/rspamd_test_suite.c
test/tests.h

index e45f95f4cf96c0ab55435a0a503b463c63ae0906..37267d468e8c75a65733c786e9f1dc4b29e63341 100644 (file)
 
 #define MODULES_NUM        ${RSPAMD_MODULES_NUM}
 
+#define BUILDROOT "${CMAKE_BINARY_DIR}"
+
 /* sys/types */
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
index b4fa018d2772ad9259290de97219b78e7ae213f6..18a826026f1641c2aa915987967fd3c997020c69 100644 (file)
@@ -24,10 +24,18 @@ TARGET_LINK_LIBRARIES(rspamd-test stemmer)
 
 IF(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
        # Also add dependencies for convenience
-       FILE(GLOB LUA_TESTS "${CMAKE_CURRENT_SOURCE_DIR}/lua/*")
+       FILE(GLOB_RECURSE LUA_TESTS "${CMAKE_CURRENT_SOURCE_DIR}/lua/*")
+       ADD_CUSTOM_TARGET(units-dir COMMAND
+               ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/lua/unit"
+       )
+       ADD_DEPENDENCIES(rspamd-test units-dir)
        FOREACH(_LF IN LISTS LUA_TESTS)
                GET_FILENAME_COMPONENT(_NM "${_LF}" NAME)
-               SET(_DS "${CMAKE_CURRENT_BINARY_DIR}/lua/${_NM}")
+               IF("${_LF}" MATCHES "^.*/unit/.*$")
+                       SET(_DS "${CMAKE_CURRENT_BINARY_DIR}/lua/unit/${_NM}")
+               ELSE()
+                       SET(_DS "${CMAKE_CURRENT_BINARY_DIR}/lua/${_NM}")
+               ENDIF()
                ADD_CUSTOM_TARGET("${_NM}" COMMAND
                        ${CMAKE_COMMAND} -E copy_if_different ${_LF} ${_DS}
                        SOURCES "${_LF}"
diff --git a/test/lua/compat_env.lua b/test/lua/compat_env.lua
new file mode 100644 (file)
index 0000000..2ecd4b6
--- /dev/null
@@ -0,0 +1,391 @@
+--[[
+
+  compat_env v$(_VERSION) - Lua 5.1/5.2 environment compatibility functions
+
+SYNOPSIS
+
+  -- Get load/loadfile compatibility functions only if using 5.1.
+  local CL = pcall(load, '') and _G or require 'compat_env'
+  local load     = CL.load
+  local loadfile = CL.loadfile
+  
+  -- The following now works in both Lua 5.1 and 5.2:
+  assert(load('return 2*pi', nil, 't', {pi=math.pi}))()
+  assert(loadfile('ex.lua', 't', {print=print}))()
+  
+  -- Get getfenv/setfenv compatibility functions only if using 5.2.
+  local getfenv = _G.getfenv or require 'compat_env'.getfenv
+  local setfenv = _G.setfenv or require 'compat_env'.setfenv
+  local function f() return x end
+  setfenv(f, {x=2})
+  print(x, getfenv(f).x) --> 2, 2
+
+DESCRIPTION
+
+  This module provides Lua 5.1/5.2 environment related compatibility functions.
+  This includes implementations of Lua 5.2 style `load` and `loadfile`
+  for use in Lua 5.1.  It also includes Lua 5.1 style `getfenv` and `setfenv`
+  for use in Lua 5.2.
+API
+
+  local CL = require 'compat_env'
+  
+  CL.load (ld [, source [, mode [, env] ] ]) --> f [, err]
+
+    This behaves the same as the Lua 5.2 `load` in both
+    Lua 5.1 and 5.2.
+    http://www.lua.org/manual/5.2/manual.html#pdf-load
+    
+  CL.loadfile ([filename [, mode [, env] ] ]) --> f [, err]
+  
+    This behaves the same as the Lua 5.2 `loadfile` in both
+    Lua 5.1 and 5.2.
+    http://www.lua.org/manual/5.2/manual.html#pdf-loadfile
+    
+  CL.getfenv ([f]) --> t
+
+    This is identical to the Lua 5.1 `getfenv` in Lua 5.1.
+    This behaves similar to the Lua 5.1 `getfenv` in Lua 5.2.
+    When a global environment is to be returned, or when `f` is a
+    C function, this returns `_G`  since Lua 5.2 doesn't have
+    (thread) global and C function environments.  This will also
+    return `_G` if the Lua function `f` lacks an `_ENV`
+    upvalue, but it will raise an error if uncertain due to lack of
+    debug info.  It is not normally considered good design to use
+    this function; when possible, use `load` or `loadfile` instead.
+    http://www.lua.org/manual/5.1/manual.html#pdf-getfenv
+    
+  CL.setfenv (f, t)
+  
+    This is identical to the Lua 5.1 `setfenv` in Lua 5.1.
+    This behaves similar to the Lua 5.1 `setfenv` in Lua 5.2.
+    This will do nothing if `f` is a Lua function that
+    lacks an `_ENV` upvalue, but it will raise an error if uncertain
+    due to lack of debug info.  See also Design Notes below.
+    It is not normally considered good design to use
+    this function; when possible, use `load` or `loadfile` instead.
+    http://www.lua.org/manual/5.1/manual.html#pdf-setfenv
+    
+DESIGN NOTES
+
+  This module intends to provide robust and fairly complete reimplementations
+  of the environment related Lua 5.1 and Lua 5.2 functions.
+  No effort is made, however, to simulate rare or difficult to simulate features,
+  such as thread environments, although this is liable to change in the future.
+  Such 5.1 capabilities are discouraged and ideally
+  removed from 5.1 code, thereby allowing your code to work in both 5.1 and 5.2.
+  
+  In Lua 5.2, a `setfenv(f, {})`, where `f` lacks any upvalues, will be silently
+  ignored since there is no `_ENV` in this function to write to, and the
+  environment will have no effect inside the function anyway.  However,
+  this does mean that `getfenv(setfenv(f, t))` does not necessarily equal `t`,
+  which is incompatible with 5.1 code (a possible workaround would be [1]).
+  If `setfenv(f, {})` has an upvalue but no debug info, then this will raise
+  an error to prevent inadvertently executing potentially untrusted code in the
+  global environment.
+  
+  It is not normally considered good design to use `setfenv` and `getfenv`
+  (one reason they were removed in 5.2).  When possible, consider replacing
+  these with `load` or `loadfile`, which are more restrictive and have native
+  implementations in 5.2.
+  
+  This module might be merged into a more general Lua 5.1/5.2 compatibility
+  library (e.g. a full reimplementation of Lua 5.2 `_G`).  However,
+  `load/loadfile/getfenv/setfenv` perhaps are among the more cumbersome
+  functions not to have.
+
+INSTALLATION
+
+  Download compat_env.lua:
+  
+    wget https://raw.github.com/gist/1654007/compat_env.lua
+
+  Copy compat_env.lua into your LUA_PATH.
+  
+  Alternately, unpack, test, and install into LuaRocks:
+  
+     wget https://raw.github.com/gist/1422205/sourceunpack.lua
+     lua sourceunpack.lua compat_env.lua
+     (cd out && luarocks make)
+
+Related work
+
+  http://lua-users.org/wiki/LuaVersionCompatibility
+  https://github.com/stevedonovan/Penlight/blob/master/lua/pl/utils.lua
+    - penlight implementations of getfenv/setfenv
+  http://lua-users.org/lists/lua-l/2010-06/msg00313.html
+    - initial getfenv/setfenv implementation
+    
+References
+
+  [1] http://lua-users.org/lists/lua-l/2010-06/msg00315.html
+
+Copyright
+
+(c) 2012 David Manura.  Licensed under the same terms as Lua 5.1/5.2 (MIT license).
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+--]]---------------------------------------------------------------------
+
+local M = {_TYPE='module', _NAME='compat_env', _VERSION='0.2.20120124'}
+
+local function check_chunk_type(s, mode)
+  local nmode = mode or 'bt' 
+  local is_binary = s and #s > 0 and s:byte(1) == 27
+  if is_binary and not nmode:match'b' then
+    return nil, ("attempt to load a binary chunk (mode is '%s')"):format(mode)
+  elseif not is_binary and not nmode:match't' then
+    return nil, ("attempt to load a text chunk (mode is '%s')"):format(mode)
+  end
+  return true
+end
+
+local IS_52_LOAD = pcall(load, '')
+if IS_52_LOAD then
+  M.load     = _G.load
+  M.loadfile = _G.loadfile
+else
+  -- 5.2 style `load` implemented in 5.1
+  function M.load(ld, source, mode, env)
+    local f
+    if type(ld) == 'string' then
+      local s = ld
+      local ok, err = check_chunk_type(s, mode); if not ok then return ok, err end
+      local err; f, err = loadstring(s, source); if not f then return f, err end
+    elseif type(ld) == 'function' then
+      local ld2 = ld
+      if (mode or 'bt') ~= 'bt' then
+        local first = ld()
+        local ok, err = check_chunk_type(first, mode); if not ok then return ok, err end
+        ld2 = function()
+          if first then
+            local chunk=first; first=nil; return chunk
+          else return ld() end
+        end
+      end
+      local err; f, err = load(ld2, source); if not f then return f, err end
+    else
+      error(("bad argument #1 to 'load' (function expected, got %s)"):format(type(ld)), 2)
+    end
+    if env then setfenv(f, env) end
+    return f
+  end
+
+  -- 5.2 style `loadfile` implemented in 5.1
+  function M.loadfile(filename, mode, env)
+    if (mode or 'bt') ~= 'bt' then
+      local ioerr
+      local fh, err = io.open(filename, 'rb'); if not fh then return fh, err end
+      local function ld() local chunk; chunk,ioerr = fh:read(4096); return chunk end
+      local f, err = M.load(ld, filename and '@'..filename, mode, env)
+      fh:close()
+      if not f then return f, err end
+      if ioerr then return nil, ioerr end
+      return f
+    else
+      local f, err = loadfile(filename); if not f then return f, err end
+      if env then setfenv(f, env) end
+      return f
+    end
+  end
+end
+
+if _G.setfenv then -- Lua 5.1
+  M.setfenv = _G.setfenv
+  M.getfenv = _G.getfenv
+else -- >= Lua 5.2
+  -- helper function for `getfenv`/`setfenv`
+  local function envlookup(f)
+    local name, val
+    local up = 0
+    local unknown
+    repeat
+      up=up+1; name, val = debug.getupvalue(f, up)
+      if name == '' then unknown = true end
+    until name == '_ENV' or name == nil
+    if name ~= '_ENV' then
+      up = nil
+      if unknown then error("upvalues not readable in Lua 5.2 when debug info missing", 3) end
+    end
+    return (name == '_ENV') and up, val, unknown
+  end
+
+  -- helper function for `getfenv`/`setfenv`
+  local function envhelper(f, name)
+    if type(f) == 'number' then
+      if f < 0 then
+        error(("bad argument #1 to '%s' (level must be non-negative)"):format(name), 3)
+      elseif f < 1 then
+        error("thread environments unsupported in Lua 5.2", 3) --[*]
+      end
+      f = debug.getinfo(f+2, 'f').func
+    elseif type(f) ~= 'function' then
+      error(("bad argument #1 to '%s' (number expected, got %s)"):format(type(name, f)), 2)
+    end
+    return f
+  end
+  -- [*] might simulate with table keyed by coroutine.running()
+  
+  -- 5.1 style `setfenv` implemented in 5.2
+  function M.setfenv(f, t)
+    local f = envhelper(f, 'setfenv')
+    local up, val, unknown = envlookup(f)
+    if up then
+      debug.upvaluejoin(f, up, function() return up end, 1) -- unique upvalue [*]
+      debug.setupvalue(f, up, t)
+    else
+      local what = debug.getinfo(f, 'S').what
+      if what ~= 'Lua' and what ~= 'main' then -- not Lua func
+        error("'setfenv' cannot change environment of given object", 2)
+      end -- else ignore no _ENV upvalue (warning: incompatible with 5.1)
+    end
+    -- added in https://gist.github.com/2255007
+    return f
+  end
+  -- [*] http://lua-users.org/lists/lua-l/2010-06/msg00313.html
+
+  -- 5.1 style `getfenv` implemented in 5.2
+  function M.getfenv(f)
+    if f == 0 or f == nil then return _G end -- simulated behavior
+    local f = envhelper(f, 'setfenv')
+    local up, val = envlookup(f)
+    if not up then return _G end -- simulated behavior [**]
+    return val
+  end
+  -- [**] possible reasons: no _ENV upvalue, C function
+end
+
+
+return M
+
+--[[ FILE rockspec.in
+
+package = 'compat_env'
+version = '$(_VERSION)-1'
+source = {
+  url = 'https://raw.github.com/gist/1654007/$(GITID)/compat_env.lua',
+  --url = 'https://raw.github.com/gist/1654007/compat_env.lua', -- latest raw
+  --url = 'https://gist.github.com/gists/1654007/download',
+  md5 = '$(MD5)'
+}
+description = {
+  summary = 'Lua 5.1/5.2 environment compatibility functions',
+  detailed = [=[
+    Provides Lua 5.1/5.2 environment related compatibility functions.
+    This includes implementations of Lua 5.2 style `load` and `loadfile`
+    for use in Lua 5.1.  It also includes Lua 5.1 style `getfenv` and `setfenv`
+    for use in Lua 5.2.
+  ]=],
+  license = 'MIT/X11',
+  homepage = 'https://gist.github.com/1654007',
+  maintainer = 'David Manura'
+}
+dependencies = {}  -- Lua 5.1 or 5.2
+build = {
+  type = 'builtin',
+  modules = {
+    ['compat_env'] = 'compat_env.lua'
+  }
+}
+
+--]]---------------------------------------------------------------------
+
+--[[ FILE test.lua
+
+-- test.lua - test suite for compat_env module.
+
+local CL = require 'compat_env'
+local load     = CL.load
+local loadfile = CL.loadfile
+local setfenv  = CL.setfenv
+local getfenv  = CL.getfenv
+
+local function checkeq(a, b, e)
+  if a ~= b then error(
+    'not equal ['..tostring(a)..'] ['..tostring(b)..'] ['..tostring(e)..']')
+  end
+end
+local function checkerr(pat, ok, err)
+  assert(not ok, 'checkerr')
+  assert(type(err) == 'string' and err:match(pat), err)
+end
+
+-- test `load`
+checkeq(load('return 2')(), 2)
+checkerr('expected near', load'return 2 2')
+checkerr('text chunk', load('return 2', nil, 'b'))
+checkerr('text chunk', load('', nil, 'b'))
+checkerr('binary chunk', load('\027', nil, 't'))
+checkeq(load('return 2*x',nil,'bt',{x=5})(), 10)
+checkeq(debug.getinfo(load('')).source, '')
+checkeq(debug.getinfo(load('', 'foo')).source, 'foo')
+
+-- test `loadfile`
+local fh = assert(io.open('tmp.lua', 'wb'))
+fh:write('return (...) or x')
+fh:close()
+checkeq(loadfile('tmp.lua')(2), 2)
+checkeq(loadfile('tmp.lua', 't')(2), 2)
+checkerr('text chunk', loadfile('tmp.lua', 'b'))
+checkeq(loadfile('tmp.lua', nil, {x=3})(), 3)
+checkeq(debug.getinfo(loadfile('tmp.lua')).source, '@tmp.lua')
+checkeq(debug.getinfo(loadfile('tmp.lua', 't', {})).source, '@tmp.lua')
+os.remove'tmp.lua'
+
+-- test `setfenv`/`getfenv`
+x = 5
+local a,b=true; local function f(c) if a then return x,b,c end end
+setfenv(f, {x=3})
+checkeq(f(), 3)
+checkeq(getfenv(f).x, 3)
+checkerr('cannot change', pcall(setfenv, string.len, {})) -- C function
+checkeq(getfenv(string.len), _G) -- C function
+local function g()
+  setfenv(1, {x=4})
+  checkeq(getfenv(1).x, 4)
+  return x
+end
+checkeq(g(), 4) -- numeric level
+if _G._VERSION ~= 'Lua 5.1' then
+  checkerr('unsupported', pcall(setfenv, 0, {}))
+end
+checkeq(getfenv(0), _G)
+checkeq(getfenv(), _G) -- no arg
+checkeq(x, 5) -- main unaltered
+setfenv(function()end, {}) -- no upvalues, ignore
+checkeq(getfenv(function()end), _G) -- no upvaluse
+if _G._VERSION ~= 'Lua 5.1' then
+  checkeq(getfenv(setfenv(function()end, {})), _G) -- warning: incompatible with 5.1
+end
+x = nil
+
+print 'OK'
+
+--]]---------------------------------------------------------------------
+
+--[[ FILE CHANGES.txt
+0.2.20120124
+  Renamed module to compat_env (from compat_load)
+  Add getfenv/setfenv functions
+
+0.1.20120121
+  Initial public release
+--]]
diff --git a/test/lua/telescope.lua b/test/lua/telescope.lua
new file mode 100644 (file)
index 0000000..abe96bc
--- /dev/null
@@ -0,0 +1,621 @@
+--[[
+The MIT License
+
+Copyright (c) 2009-2012 [Norman Clarke](mailto:norman@njclarke.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+]]--
+
+--- Telescope is a test library for Lua that allows for flexible, declarative
+-- tests. The documentation produced here is intended largely for developers
+-- working on Telescope.  For information on using Telescope, please visit the
+-- project homepage at: <a href="http://github.com/norman/telescope">http://github.com/norman/telescope#readme</a>.
+-- @release 0.6
+-- @class module
+-- @module 'telescope'
+local _M = {}
+
+local compat_env = require 'compat_env'
+
+local getfenv = _G.getfenv or compat_env.getfenv
+local setfenv = _G.setfenv or compat_env.setfenv
+
+
+local _VERSION = "0.6.0"
+
+--- The status codes that can be returned by an invoked test. These should not be overidden.
+-- @name status_codes
+-- @class table
+-- @field err - This is returned when an invoked test results in an error
+-- rather than a passed or failed assertion.
+-- @field fail - This is returned when an invoked test contains one or more failing assertions.
+-- @field pass - This is returned when all of a test's assertions pass.
+-- @field pending - This is returned when a test does not have a corresponding function.
+-- @field unassertive - This is returned when an invoked test does not produce
+-- errors, but does not contain any assertions.
+local status_codes = {
+  err         = 2,
+  fail        = 4,
+  pass        = 8,
+  pending     = 16,
+  unassertive = 32
+}
+
+--- Labels used to show the various <tt>status_codes</tt> as a single character.
+-- These can be overidden if you wish.
+-- @name status_labels
+-- @class table
+-- @see status_codes
+-- @field status_codes.err         'E'
+-- @field status_codes.fail        'F'
+-- @field status_codes.pass        'P'
+-- @field status_codes.pending     '?'
+-- @field status_codes.unassertive 'U'
+
+local status_labels = {
+  [status_codes.err]         = 'E',
+  [status_codes.fail]        = 'F',
+  [status_codes.pass]        = 'P',
+  [status_codes.pending]     = '?',
+  [status_codes.unassertive] = 'U'
+}
+
+--- The default names for context blocks. It defaults to "context", "spec" and
+-- "describe."
+-- @name context_aliases
+-- @class table
+local context_aliases = {"context", "describe", "spec"}
+--- The default names for test blocks. It defaults to "test," "it", "expect",
+-- "they" and "should."
+-- @name test_aliases
+-- @class table
+local test_aliases    = {"test", "it", "expect", "should", "they"}
+
+--- The default names for "before" blocks. It defaults to "before" and "setup."
+-- The function in the before block will be run before each sibling test function
+-- or context.
+-- @name before_aliases
+-- @class table
+local before_aliases  = {"before", "setup"}
+
+--- The default names for "after" blocks. It defaults to "after" and "teardown."
+-- The function in the after block will be run after each sibling test function
+-- or context.
+-- @name after_aliases
+-- @class table
+local after_aliases  = {"after", "teardown"}
+
+-- Prefix to place before all assertion messages. Used by make_assertion().
+local assertion_message_prefix  = "Assert failed: expected "
+
+--- The default assertions.
+-- These are the assertions built into telescope. You can override them or
+-- create your own custom assertions using <tt>make_assertion</tt>.
+-- <ul>
+-- <tt><li>assert_blank(a)</tt> - true if a is nil, or the empty string</li>
+-- <tt><li>assert_empty(a)</tt> - true if a is an empty table</li>
+-- <tt><li>assert_equal(a, b)</tt> - true if a == b</li>
+-- <tt><li>assert_error(f)</tt> - true if function f produces an error</li>
+-- <tt><li>assert_false(a)</tt> - true if a is false</li>
+-- <tt><li>assert_greater_than(a, b)</tt> - true if a > b</li>
+-- <tt><li>assert_gte(a, b)</tt> - true if a >= b</li>
+-- <tt><li>assert_less_than(a, b)</tt> - true if a < b</li>
+-- <tt><li>assert_lte(a, b)</tt> - true if a <= b</li>
+-- <tt><li>assert_match(a, b)</tt> - true if b is a string that matches pattern a</li>
+-- <tt><li>assert_nil(a)</tt> - true if a is nil</li>
+-- <tt><li>assert_true(a)</tt> - true if a is true</li>
+-- <tt><li>assert_type(a, b)</tt> - true if a is of type b</li>
+-- <tt><li>assert_not_blank(a)</tt>  - true if a is not nil and a is not the empty string</li>
+-- <tt><li>assert_not_empty(a)</tt> - true if a is a table, and a is not empty</li>
+-- <tt><li>assert_not_equal(a, b)</tt> - true if a ~= b</li>
+-- <tt><li>assert_not_error(f)</tt> - true if function f does not produce an error</li>
+-- <tt><li>assert_not_false(a)</tt> - true if a is not false</li>
+-- <tt><li>assert_not_greater_than(a, b)</tt> - true if not (a > b)</li>
+-- <tt><li>assert_not_gte(a, b)</tt> - true if not (a >= b)</li>
+-- <tt><li>assert_not_less_than(a, b)</tt> - true if not (a < b)</li>
+-- <tt><li>assert_not_lte(a, b)</tt> - true if not (a <= b)</li>
+-- <tt><li>assert_not_match(a, b)</tt> - true if the string b does not match the pattern a</li>
+-- <tt><li>assert_not_nil(a)</tt> - true if a is not nil</li>
+-- <tt><li>assert_not_true(a)</tt> - true if a is not true</li>
+-- <tt><li>assert_not_type(a, b)</tt> - true if a is not of type b</li>
+-- </ul>
+-- @see make_assertion
+-- @name assertions
+-- @class table
+local assertions = {}
+
+--- Create a custom assertion.
+-- This creates an assertion along with a corresponding negative assertion. It
+-- is used internally by telescope to create the default assertions.
+-- @param name The base name of the assertion.
+-- <p>
+-- The name will be used as the basis of the positive and negative assertions;
+-- i.e., the name <tt>equal</tt> would be used to create the assertions
+-- <tt>assert_equal</tt> and <tt>assert_not_equal</tt>.
+-- </p>
+-- @param message The base message that will be shown.
+-- <p>
+-- The assertion message is what is shown when the assertion fails.  It will be
+-- prefixed with the string in <tt>telescope.assertion_message_prefix</tt>.
+-- The variables passed to <tt>telescope.make_assertion</tt> are interpolated
+-- in the message string using <tt>string.format</tt>.  When creating the
+-- inverse assertion, the message is reused, with <tt>" to be "</tt> replaced
+-- by <tt>" not to be "</tt>. Hence a recommended format is something like:
+-- <tt>"%s to be similar to %s"</tt>.
+-- </p>
+-- @param func The assertion function itself.
+-- <p>
+-- The assertion function can have any number of arguments.
+-- </p>
+-- @usage <tt>make_assertion("equal", "%s to be equal to %s", function(a, b)
+-- return a == b end)</tt>
+-- @function make_assertion
+local function make_assertion(name, message, func)
+  local num_vars = 0
+  -- if the last vararg ends up nil, we'll need to pad the table with nils so
+  -- that string.format gets the number of args it expects
+  local format_message
+  if type(message) == "function" then
+    format_message = message
+  else
+    for _, _ in message:gmatch("%%s") do num_vars = num_vars + 1 end
+    format_message = function(message, ...)
+      local a = {}
+      local args = {...}
+      local nargs = select('#', ...)
+      if nargs > num_vars then        
+        local userErrorMessage = args[num_vars+1]
+        if type(userErrorMessage) == "string" then
+          return(assertion_message_prefix .. userErrorMessage)
+        else
+          error(string.format('assert_%s expected %d arguments but got %d', name, num_vars, #args))
+        end
+      end
+      for i = 1, nargs do a[i] = tostring(v) end
+      for i = nargs+1, num_vars do a[i] = 'nil' end
+      return (assertion_message_prefix .. message):format(unpack(a))
+    end
+  end
+
+  assertions["assert_" .. name] = function(...)
+    if assertion_callback then assertion_callback(...) end
+    if not func(...) then
+      error({format_message(message, ...), debug.traceback()})
+    end
+  end
+end
+
+--- (local) Return a table with table t's values as keys and keys as values.
+-- @param t The table.
+local function invert_table(t)
+  local t2 = {}
+  for k, v in pairs(t) do t2[v] = k end
+  return t2
+end
+
+-- (local) Truncate a string "s" to length "len", optionally followed by the
+-- string given in "after" if truncated; for example, truncate_string("hello
+-- world", 3, "...")
+-- @param s The string to truncate.
+-- @param len The desired length.
+-- @param after A string to append to s, if it is truncated.
+local function truncate_string(s, len, after)
+  if #s <= len then
+    return s
+  else
+    local s = s:sub(1, len):gsub("%s*$", '')
+    if after then return s .. after else return s end
+  end
+end
+
+--- (local) Filter a table's values by function. This function iterates over a
+-- table , returning only the table entries that, when passed into function f,
+-- yield a truthy value.
+-- @param t The table over which to iterate.
+-- @param f The filter function.
+local function filter(t, f)
+  local a, b
+  return function()
+    repeat a, b = next(t, a)
+      if not b then return end
+      if f(a, b) then return a, b end
+    until not b
+  end
+end
+
+--- (local) Finds the value in the contexts table indexed with i, and returns a table
+-- of i's ancestor contexts.
+-- @param i The index in the <tt>contexts</tt> table to get ancestors for.
+-- @param contexts The table in which to find the ancestors.
+local function ancestors(i, contexts)
+  if i == 0 then return end
+  local a = {}
+  local function func(j)
+    if contexts[j].parent == 0 then return nil end
+    table.insert(a, contexts[j].parent)
+    func(contexts[j].parent)
+  end
+  func(i)
+  return a
+end
+
+make_assertion("blank",        "'%s' to be blank",                         function(a) return a == '' or a == nil end)
+make_assertion("empty",        "'%s' to be an empty table",                function(a) return not next(a) end)
+make_assertion("equal",        "'%s' to be equal to '%s'",                 function(a, b) return a == b end)
+make_assertion("error",        "result to be an error",                    function(f) return not pcall(f) end)
+make_assertion("false",        "'%s' to be false",                         function(a) return a == false end)
+make_assertion("greater_than", "'%s' to be greater than '%s'",             function(a, b) return a > b end)
+make_assertion("gte",          "'%s' to be greater than or equal to '%s'", function(a, b) return a >= b end)
+make_assertion("less_than",    "'%s' to be less than '%s'",                function(a, b) return a < b end)
+make_assertion("lte",          "'%s' to be less than or equal to '%s'",    function(a, b) return a <= b end)
+make_assertion("match",        "'%s' to be a match for %s",                function(a, b) return (tostring(b)):match(a) end)
+make_assertion("nil",          "'%s' to be nil",                           function(a) return a == nil end)
+make_assertion("true",         "'%s' to be true",                          function(a) return a == true end)
+make_assertion("type",         "'%s' to be a %s",                          function(a, b) return type(a) == b end)
+
+make_assertion("not_blank",    "'%s' not to be blank",                     function(a) return a ~= '' and a ~= nil end)
+make_assertion("not_empty",    "'%s' not to be an empty table",            function(a) return not not next(a) end)
+make_assertion("not_equal",    "'%s' not to be equal to '%s'",             function(a, b) return a ~= b end)
+make_assertion("not_error",    "result not to be an error",                function(f) return not not pcall(f) end)
+make_assertion("not_match",    "'%s' not to be a match for %s",            function(a, b) return not (tostring(b)):match(a) end)
+make_assertion("not_nil",      "'%s' not to be nil",                       function(a) return a ~= nil end)
+make_assertion("not_type",     "'%s' not to be a %s",                      function(a, b) return type(a) ~= b end)
+
+--- Build a contexts table from the test file or function given in <tt>target</tt>.
+-- If the optional <tt>contexts</tt> table argument is provided, then the
+-- resulting contexts will be added to it.
+-- <p>
+-- The resulting contexts table's structure is as follows:
+-- </p>
+-- <code>
+-- {
+--   {parent = 0, name = "this is a context", context = true},
+--   {parent = 1, name = "this is a nested context", context = true},
+--   {parent = 2, name = "this is a test", test = function},
+--   {parent = 2, name = "this is another test", test = function},
+--   {parent = 0, name = "this is test outside any context", test = function},
+-- }
+-- </code>
+-- @param contexts A optional table in which to collect the resulting contexts
+-- and function.
+-- @function load_contexts
+local function load_contexts(target, contexts)
+  local env = {}
+  local current_index = 0
+  local context_table = contexts or {}
+
+  local function context_block(name, func)
+    table.insert(context_table, {parent = current_index, name = name, context = true})
+    local previous_index = current_index
+    current_index = #context_table
+    func()
+    current_index = previous_index
+  end
+
+  local function test_block(name, func)
+    local test_table = {name = name, parent = current_index, test = func or true}
+    if current_index ~= 0 then
+      test_table.context_name = context_table[current_index].name
+    else
+      test_table.context_name = 'top level'
+    end
+    table.insert(context_table, test_table)
+  end
+
+  local function before_block(func)
+    context_table[current_index].before = func
+  end
+
+  local function after_block(func)
+    context_table[current_index].after = func
+  end
+
+  for _, v in ipairs(after_aliases)   do env[v] = after_block end
+  for _, v in ipairs(before_aliases)  do env[v] = before_block end
+  for _, v in ipairs(context_aliases) do env[v] = context_block end
+  for _, v in ipairs(test_aliases)    do env[v] = test_block end
+
+  -- Set these functions in the module's meta table to allow accessing
+  -- telescope's test and context functions without env tricks. This will
+  -- however add tests to a context table used inside the module, so multiple
+  -- test files will add tests to the same top-level context, which may or may
+  -- not be desired.
+  setmetatable(_M, {__index = env})
+
+  setmetatable(env, {__index = _G})
+
+  local func, err = type(target) == 'string' and assert(loadfile(target)) or target
+  if err then error(err) end
+  setfenv(func, env)()
+  return context_table
+end
+
+-- in-place table reverse.
+function table.reverse(t)
+     local len = #t+1
+     for i=1, (len-1)/2 do
+          t[i], t[len-i] = t[len-i], t[i]
+     end
+end
+
+--- Run all tests.
+-- This function will exectute each function in the contexts table.
+-- @param contexts The contexts created by <tt>load_contexts</tt>.
+-- @param callbacks A table of callback functions to be invoked before or after
+-- various test states.
+-- <p>
+-- There is a callback for each test <tt>status_code</tt>, and callbacks to run
+-- before or after each test invocation regardless of outcome.
+-- </p>
+-- <ul>
+-- <li>after - will be invoked after each test</li>
+-- <li>before - will be invoked before each test</li>
+-- <li>err - will be invoked after each test which results in an error</li>
+-- <li>fail - will be invoked after each failing test</li>
+-- <li>pass - will be invoked after each passing test</li>
+-- <li>pending - will be invoked after each pending test</li>
+-- <li>unassertive - will be invoked after each test which doesn't assert
+-- anything</li>
+-- </ul>
+-- <p>
+-- Callbacks can be used, for example, to drop into a debugger upon a failed
+-- assertion or error, for profiling, or updating a GUI progress meter.
+-- </p>
+-- @param test_filter A function to filter tests that match only conditions that you specify.
+-- <p>
+-- For example, the folling would allow you to run only tests whose name matches a pattern:
+-- </p>
+-- <p>
+-- <code>
+-- function(t) return t.name:match("%s* lexer") end
+-- </code>
+-- </p>
+-- @return A table of result tables. Each result table has the following
+-- fields:
+-- <ul>
+-- <li>assertions_invoked - the number of assertions the test invoked</li>
+-- <li>context            - the name of the context</li>
+-- <li>message            - a table with an error message and stack trace</li>
+-- <li>name               - the name of the test</li>
+-- <li>status_code        - the resulting status code</li>
+-- <li>status_label       - the label for the status_code</li>
+-- </ul>
+-- @see load_contexts
+-- @see status_codes
+-- @function run
+local function run(contexts, callbacks, test_filter)
+
+  local results = {}
+  local status_names = invert_table(status_codes)
+  local test_filter = test_filter or function(a) return a end
+
+  -- Setup a new environment suitable for running a new test
+  local function newEnv()
+    local env = {}
+
+    -- Make sure globals are accessible in the new environment
+    setmetatable(env, {__index = _G})
+
+    -- Setup all the assert functions in the new environment
+    for k, v in pairs(assertions) do
+      setfenv(v, env)
+      env[k] = v
+    end
+
+    return env
+  end
+
+  local env = newEnv()
+
+  local function invoke_callback(name, test)
+    if not callbacks then return end
+    if type(callbacks[name]) == "table" then
+      for _, c in ipairs(callbacks[name]) do c(test) end
+    elseif callbacks[name] then
+      callbacks[name](test)
+    end
+  end
+
+  local function invoke_test(func)
+    local assertions_invoked = 0
+    env.assertion_callback = function()
+      assertions_invoked = assertions_invoked + 1
+    end
+    setfenv(func, env)
+    local result, message = xpcall(func, debug.traceback)
+    if result and assertions_invoked > 0 then
+      return status_codes.pass, assertions_invoked, nil
+    elseif result then
+      return status_codes.unassertive, 0, nil
+    elseif type(message) == "table" then
+      return status_codes.fail, assertions_invoked, message
+    else
+      return status_codes.err, assertions_invoked, {message, debug.traceback()}
+    end
+  end
+
+  for i, v in filter(contexts, function(i, v) return v.test and test_filter(v) end) do
+    env = newEnv()    -- Setup a new environment for this test
+
+    local ancestors = ancestors(i, contexts)
+    local context_name = 'Top level'
+    if contexts[i].parent ~= 0 then
+      context_name = contexts[contexts[i].parent].name
+    end
+    local result = {
+      assertions_invoked = 0,
+      name               = contexts[i].name,
+      context            = context_name,
+      test               = i
+    }
+    table.sort(ancestors)
+    -- this "before" is the test callback passed into the runner
+    invoke_callback("before", result)
+    
+    -- run all the "before" blocks/functions
+    for _, a in ipairs(ancestors) do
+      if contexts[a].before then 
+        setfenv(contexts[a].before, env)
+        contexts[a].before() 
+      end
+    end
+
+    -- check if it's a function because pending tests will just have "true"
+    if type(v.test) == "function" then
+      result.status_code, result.assertions_invoked, result.message = invoke_test(v.test)
+      invoke_callback(status_names[result.status_code], result)
+    else
+      result.status_code = status_codes.pending
+      invoke_callback("pending", result)
+    end
+    result.status_label = status_labels[result.status_code]
+
+    -- Run all the "after" blocks/functions
+    table.reverse(ancestors)
+    for _, a in ipairs(ancestors) do
+      if contexts[a].after then 
+        setfenv(contexts[a].after, env)
+        contexts[a].after() 
+      end
+    end
+
+    invoke_callback("after", result)
+    results[i] = result
+  end
+
+  return results
+
+end
+
+--- Return a detailed report for each context, with the status of each test.
+-- @param contexts The contexts returned by <tt>load_contexts</tt>.
+-- @param results The results returned by <tt>run</tt>.
+-- @function test_report
+local function test_report(contexts, results)
+
+  local buffer               = {}
+  local leading_space        = "  "
+  local level                = 0
+  local line_char            = "-"
+  local previous_level       = 0
+  local status_format_len    = 3
+  local status_format        = "[%s]"
+  local width                = 72
+  local context_name_format  = "%-" .. width - status_format_len .. "s"
+  local function_name_format = "%-" .. width - status_format_len .. "s"
+
+  local function space()
+    return leading_space:rep(level - 1)
+  end
+
+  local function add_divider()
+    table.insert(buffer, line_char:rep(width))
+  end
+  add_divider()
+  for i, item in ipairs(contexts) do
+    local ancestors = ancestors(i, contexts)
+    previous_level = level or 0
+    level = #ancestors
+    -- the 4 here is the length of "..." plus one space of padding
+    local name = truncate_string(item.name, width - status_format_len - 4 - #ancestors, '...')
+    if previous_level ~= level and level == 0 then add_divider() end
+    if item.context then
+      table.insert(buffer, context_name_format:format(space() .. name .. ':'))
+    elseif results[i] then
+      table.insert(buffer, function_name_format:format(space() .. name) ..
+        status_format:format(results[i].status_label))
+    end
+  end
+  add_divider()
+  return table.concat(buffer, "\n")
+
+end
+
+--- Return a table of stack traces for tests which produced a failure or an error.
+-- @param contexts The contexts returned by <tt>load_contexts</tt>.
+-- @param results The results returned by <tt>run</tt>.
+-- @function error_report
+local function error_report(contexts, results)
+  local buffer = {}
+  for _, r in filter(results, function(i, r) return r.message end) do
+    local name = contexts[r.test].name
+    table.insert(buffer, name .. ":\n" .. r.message[1] .. "\n" .. r.message[2])
+  end
+  if #buffer > 0 then return table.concat(buffer, "\n") end
+end
+
+--- Get a one-line report and a summary table with the status counts. The
+-- counts given are: total tests, assertions, passed tests, failed tests,
+-- pending tests, and tests which didn't assert anything.
+-- @return A report that can be printed
+-- @return A table with the various counts. Its fields are:
+-- <tt>assertions</tt>, <tt>errors</tt>, <tt>failed</tt>, <tt>passed</tt>,
+-- <tt>pending</tt>, <tt>tests</tt>, <tt>unassertive</tt>.
+-- @param contexts The contexts returned by <tt>load_contexts</tt>.
+-- @param results The results returned by <tt>run</tt>.
+-- @function summary_report
+local function summary_report(contexts, results)
+  local r = {
+    assertions  = 0,
+    errors      = 0,
+    failed      = 0,
+    passed      = 0,
+    pending     = 0,
+    tests       = 0,
+    unassertive = 0
+  }
+  for _, v in pairs(results) do
+    r.tests = r.tests + 1
+    r.assertions = r.assertions + v.assertions_invoked
+    if v.status_code == status_codes.err then r.errors = r.errors + 1
+    elseif v.status_code == status_codes.fail then r.failed = r.failed + 1
+    elseif v.status_code == status_codes.pass then r.passed = r.passed + 1
+    elseif v.status_code == status_codes.pending then r.pending = r.pending + 1
+    elseif v.status_code == status_codes.unassertive then r.unassertive = r.unassertive + 1
+    end
+  end
+  local buffer = {}
+  for _, k in ipairs({"tests", "passed", "assertions", "failed", "errors", "unassertive", "pending"}) do
+    local number = r[k]
+    local label = k
+    if number == 1 then
+      label = label:gsub("s$", "")
+    end
+    table.insert(buffer, ("%d %s"):format(number, label))
+  end
+  return table.concat(buffer, " "), r
+end
+
+_M.after_aliases            = after_aliases
+_M.make_assertion           = make_assertion
+_M.assertion_message_prefix = assertion_message_prefix
+_M.before_aliases           = before_aliases
+_M.context_aliases          = context_aliases
+_M.error_report             = error_report
+_M.load_contexts            = load_contexts
+_M.run                      = run
+_M.test_report              = test_report
+_M.status_codes             = status_codes
+_M.status_labels            = status_labels
+_M.summary_report           = summary_report
+_M.test_aliases             = test_aliases
+_M.version                  = _VERSION
+_M._VERSION                 = _VERSION
+
+return _M
diff --git a/test/lua/tests.lua b/test/lua/tests.lua
new file mode 100644 (file)
index 0000000..0f6b06b
--- /dev/null
@@ -0,0 +1,22 @@
+-- Run all unit tests in 'unit' directory
+
+local telescope = require "telescope"
+
+local contexts = {}
+
+for _,t in ipairs(tests_list) do
+  telescope.load_contexts(t, contexts)
+end
+local buffer = {}
+local results = telescope.run(contexts, callbacks, test_pattern)
+local summary, data = telescope.summary_report(contexts, results)
+table.insert(buffer, telescope.test_report(contexts, results))
+
+if #buffer > 0 then print(table.concat(buffer, "\n")) end
+
+for _, v in pairs(results) do
+  if v.status_code == telescope.status_codes.err or
+    v.status_code == telescope.status_codes.fail then
+    os.exit(1)
+  end
+end
\ No newline at end of file
similarity index 100%
rename from test/lua/rsa.lua
rename to test/lua/unit/rsa.lua
similarity index 100%
rename from test/lua/test.data
rename to test/lua/unit/test.data
similarity index 100%
rename from test/lua/testkey
rename to test/lua/unit/testkey
index cd3b152cda9c46849ee6cdba4350ca3e32069d01..bdc23e91ca7400727193bbb7acb54ba700f4bc6a 100644 (file)
 #include "util.h"
 #include "lua/lua_common.h"
 
-static const char *lua_src = "./lua";
+static const char *lua_src = BUILDROOT "/test/lua/tests.lua";
+
+static int
+traceback (lua_State *L)
+{
+       if (!lua_isstring (L, 1)) {
+               return 1;
+       }
+
+       lua_getfield (L, LUA_GLOBALSINDEX, "debug");
+
+       if (!lua_istable(L, -1)) {
+               lua_pop(L, 1);
+               return 1;
+       }
+
+       lua_getfield (L, -1, "traceback");
+
+       if (!lua_isfunction(L, -1)) {
+               lua_pop(L, 2);
+               return 1;
+       }
+       lua_pushvalue (L, 1);
+       lua_pushinteger (L, 2);
+       lua_call(L, 2, 1);
+
+       return 1;
+}
 
 void
-rspamd_lua_test_func (int argc, char **argv)
+rspamd_lua_test_func (void)
 {
        lua_State *L = rspamd_lua_init (NULL);
-       gchar rp[PATH_MAX], path_buf[PATH_MAX];
+       gchar *rp, rp_buf[PATH_MAX], path_buf[PATH_MAX], *tmp, *dir, *pattern;
        const gchar *old_path;
-       guint i;
+       glob_t globbuf;
+       gint i, len;
 
-       msg_info ("Starting lua tests");
+       rspamd_printf ("Starting lua tests\n");
 
-       if (realpath (lua_src, rp) == NULL) {
-               msg_err ("cannod find path %s: %s", lua_src, strerror (errno));
+       if ((rp = realpath (lua_src, rp_buf)) == NULL) {
+               msg_err ("cannot find path %s: %s",
+                               lua_src, strerror (errno));
                g_assert (0);
        }
 
+       tmp = g_strdup (rp);
+       dir = dirname (tmp);
        /* Set lua path */
        lua_getglobal (L, "package");
        lua_getfield (L, -1, "path");
        old_path = luaL_checkstring (L, -1);
 
-       rspamd_snprintf (path_buf, sizeof (path_buf), "%s;%s/?.lua;%s/busted/?.lua",
-                       old_path, rp, rp);
+       rspamd_snprintf (path_buf, sizeof (path_buf), "%s;%s/?.lua;%s/unit/?.lua",
+                       old_path, dir, dir);
        lua_pop (L, 1);
        lua_pushstring (L, path_buf);
        lua_setfield (L, -2, "path");
        lua_pop (L, 1);
 
-       lua_getglobal (L, "arg");
+       lua_newtable (L);
 
-       if (lua_type (L, -1) != LUA_TTABLE) {
-               lua_newtable (L);
-       }
+       globbuf.gl_offs = 0;
+       len = strlen (dir) + sizeof ("/unit/") + sizeof ("*.lua");
+       pattern = g_malloc (len);
+       rspamd_snprintf (pattern, len, "%s/unit/%s", dir, "*.lua");
 
-       for (i = 0; i < argc - 1; i ++) {
-               lua_pushinteger (L, i + 1);
-               lua_pushstring (L, argv[i]);
-               lua_settable (L, -3);
+       if (glob (pattern, GLOB_DOOFFS, NULL, &globbuf) == 0) {
+               for (i = 0; i < (gint)globbuf.gl_pathc; i++) {
+                       lua_pushinteger (L, i + 1);
+                       lua_pushstring (L, globbuf.gl_pathv[i]);
+                       lua_settable (L, -3);
+               }
+               globfree (&globbuf);
+               g_free (pattern);
+       }
+       else {
+               msg_err ("pattern %s doesn't match: %s", pattern,
+                               strerror (errno));
+               g_assert (0);
        }
 
-       lua_setglobal (L, "arg");
-       lua_pop (L, 1);
+       lua_setglobal (L, "tests_list");
+
+       lua_pushcfunction (L, traceback);
+       luaL_loadfile (L, rp);
 
-       rspamd_snprintf (path_buf, sizeof (path_buf),
-                       "require 'busted.runner'({ batch = true })");
-       if (luaL_dostring (L, path_buf) != 0) {
-               rspamd_fprintf (stderr, "run test failed: %s", lua_tostring (L, -1));
+       if (lua_pcall (L, 0, 0, lua_gettop (L) - 1) != 0) {
+               msg_err ("run test failed: %s", lua_tostring (L, -1));
                g_assert (0);
        }
 
index a70a0102f9d057d08363160eebc0781d508cf910..1023c5cf0aa27e561b6fd477dcd7d56749e7e898 100644 (file)
@@ -13,39 +13,35 @@ main (int argc, char **argv)
 {
        struct rspamd_config            *cfg;
 
-       if (argc > 0 && strcmp (argv[1], "lua") == 0) {
-               /* Special lua testing mode */
-               rspamd_lua_test_func (argc - 1, &argv[2]);
-       }
+       rspamd_main = (struct rspamd_main *)g_malloc (sizeof (struct rspamd_main));
+       memset (rspamd_main, 0, sizeof (struct rspamd_main));
+       rspamd_main->server_pool = rspamd_mempool_new (rspamd_mempool_suggest_size ());
+       rspamd_main->cfg = (struct rspamd_config *)g_malloc (sizeof (struct rspamd_config));
+       cfg = rspamd_main->cfg;
+       bzero (cfg, sizeof (struct rspamd_config));
+       cfg->cfg_pool = rspamd_mempool_new (rspamd_mempool_suggest_size ());
+       cfg->log_type = RSPAMD_LOG_CONSOLE;
+       cfg->log_level = G_LOG_LEVEL_INFO;
 
-       g_test_init (&argc, &argv, NULL);
+       rspamd_set_logger (cfg, g_quark_from_static_string("rspamd-test"), rspamd_main);
+       (void)rspamd_log_open (rspamd_main->logger);
 
-       rspamd_main = (struct rspamd_main *)g_malloc (sizeof (struct rspamd_main));
+       g_test_init (&argc, &argv, NULL);
 
 #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION <= 30))
        g_thread_init (NULL);
 #endif
 
        g_mime_init (0);
-       memset (rspamd_main, 0, sizeof (struct rspamd_main));
-       rspamd_main->server_pool = rspamd_mempool_new (rspamd_mempool_suggest_size ());
-       rspamd_main->cfg = (struct rspamd_config *)g_malloc (sizeof (struct rspamd_config));
-       cfg = rspamd_main->cfg;
-       bzero (cfg, sizeof (struct rspamd_config));
-       cfg->cfg_pool = rspamd_mempool_new (rspamd_mempool_suggest_size ());
 
        base = event_init ();
 
        if (g_test_verbose ()) {
                cfg->log_level = G_LOG_LEVEL_DEBUG;
+               rspamd_set_logger (cfg, g_quark_from_static_string("rspamd-test"), rspamd_main);
+               (void)rspamd_log_reopen (rspamd_main->logger);
        }
-       else {
-               cfg->log_level = G_LOG_LEVEL_INFO;
-       }
-       cfg->log_type = RSPAMD_LOG_CONSOLE;
-       /* First set logger to console logger */
-       rspamd_set_logger (cfg, g_quark_from_static_string("rspamd-test"), rspamd_main);
-       (void)rspamd_log_open (rspamd_main->logger);
+
        g_log_set_default_handler (rspamd_glib_log_function, rspamd_main->logger);
 
        g_test_add_func ("/rspamd/mem_pool", rspamd_mem_pool_test_func);
@@ -61,6 +57,7 @@ main (int argc, char **argv)
        g_test_add_func ("/rspamd/upstream", rspamd_upstream_test_func);
        g_test_add_func ("/rspamd/shingles", rspamd_shingles_test_func);
        g_test_add_func ("/rspamd/http", rspamd_http_test_func);
+       g_test_add_func ("/rspamd/lua", rspamd_lua_test_func);
 
        g_test_run ();
 
index ae69d9d96c362c71a3f933b56c4f226d1e02eba3..1d14bde4bb689e8462e2af9e70e9610886d56bc7 100644 (file)
@@ -41,6 +41,6 @@ void rspamd_shingles_test_func (void);
 
 void rspamd_http_test_func (void);
 
-void rspamd_lua_test_func (int argc, char **argv);
+void rspamd_lua_test_func (void);
 
 #endif