First Debian packaging attempt

squeeze-backports
Victor Seva 13 years ago
parent 8de567f413
commit 8fe75f9300

5
debian/changelog vendored

@ -0,0 +1,5 @@
lua-ngcp (0.1.0) UNRELEASED; urgency=low
* Initial Release.
-- Victor Seva <vseva@sipwise.com> Fri, 10 May 2013 13:56:44 +0200

1
debian/compat vendored

@ -0,0 +1 @@
9

18
debian/control vendored

@ -0,0 +1,18 @@
Source: lua-ngcp
Priority: extra
Maintainer: Victor Seva <vseva@sipwise.com>
Build-Depends: debhelper (>= 8~), dh-lua (>= 16~)
Standards-Version: 3.9.4
Section: libs
Homepage: git://git.mgm.sipwise.com/kamailio-conf-lua
Package: lua-ngcp
Section: libs
Architecture: any
Depends: lua-sql-mysql, ${shlibs:Depends}, ${misc:Depends}
Provides: ${lua:Provides}
XB-Lua-Versions: ${lua:Versions}
Description: lua framework for ngcp-kamailio config
This package provides the lua ngcp lib that ngcp-template-kamailio
uses.

28
debian/copyright vendored

@ -0,0 +1,28 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: ngcp-liblua
Source: git://git.mgm.sipwise.com/kamailio-conf-lua
Files: *
Copyright: 2013 Sipwise GmbH, Austria
License: GPL-3.0+
Files: debian/*
Copyright: 2013 SipWise Team <development@sipwise.com>
License: GPL-3.0+
License: GPL-3.0+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
.
This package is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
.
On Debian systems, the complete text of the GNU General
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".

@ -0,0 +1,8 @@
LUA_VERSION=5.1
PKG_NAME=ngcp
LUA_HEADER=
LUA_SOURCES=$(wildcard ngcp/*.lua)
LUA_SOURCES_MANGLER=
LUA_MODNAME=ngcp
LUA_TEST=

@ -0,0 +1,4 @@
PKG_NAME=ngcp
LUA_SOURCES=$(wildcard ngcp/*.lua)
LUA_MODNAME=ngcp

13
debian/rules vendored

@ -0,0 +1,13 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
%:
dh $@ --buildsystem=lua --with lua

@ -0,0 +1 @@
3.0 (native)

@ -1,659 +0,0 @@
------ THIS FILE IS TANGLED FROM LITERATE SOURCE FILES ------
-- Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>
-- See terms in file COPYRIGHT, or at http://lemock.luaforge.net
module( 'lemock', package.seeall )
_VERSION = "LeMock 0.6"
_COPYRIGHT = "Copyright (C) 2009 Tommy Pettersson <ptp@lysator.liu.se>"
local class, object, qtostring, sfmt, add_to_set
local elements_of_set, value_equal
function object (class)
return setmetatable( {}, class )
end
function class (parent)
local c = object(parent)
c.__index = c
return c
end
sfmt = string.format
function qtostring (v)
if type(v) == 'string' then
return sfmt( '%q', v )
else
return tostring( v )
end
end
function add_to_set (o, setname, element)
if not o[setname] then
o[setname] = {}
end
local l = o[setname]
for i = 1, #l do
if l[i] == element then return end
end
l[#l+1] = element
end
function elements_of_set (o, setname)
local l = o[setname]
local i = l and #l+1 or 0
return function ()
i = i - 1
if i > 0 then return l[i] end
end
end
function value_equal (a, b)
if a == b then return true end
if a ~= a and b ~= b then return true end -- NaN == NaN
return false
end
local mock_controller_map = setmetatable( {}, {__mode='k'} )
-- All the classes are private
local Action, Argv, Callable, Controller, Mock
Action = {}
-- abstract
Action.generic = class()
function Action.generic:add_close (label)
add_to_set( self, 'closelist', label )
end
function Action.generic:add_depend (d)
add_to_set( self, 'dependlist', d )
end
function Action.generic:add_label (label)
add_to_set( self, 'labellist', label )
end
function Action.generic:assert_satisfied ()
assert( self.replay_count <= self.max_replays, "lemock internal error" )
if not (
self.min_replays <= self.replay_count
) then
error( sfmt( "Wrong replay count %d (expected %d..%d) for %s"
, self.replay_count
, self.min_replays, self.max_replays
, self:tostring()
)
, 0
)
end
end
function Action.generic:blocks ()
if self:is_satisfied() then
return function () end
end
return elements_of_set( self, 'labellist' )
end
function Action.generic:closes ()
return elements_of_set( self, 'closelist' )
end
function Action.generic:depends ()
return elements_of_set( self, 'dependlist' )
end
function Action.generic:has_label (l)
for x in elements_of_set( self, 'labellist' ) do
if x == l then return true end
end
return false
end
function Action.generic:is_expected ()
return self.replay_count < self.max_replays
and not self.is_blocked
and not self.is_closed
end
function Action.generic:is_satisfied ()
return
self.min_replays <= self.replay_count
end
function Action.generic:match (key)
if getmetatable(self) ~= getmetatable(key) then return false end
if self.mock ~= key.mock then return false end
return self:is_expected()
end
function Action.generic:new (mock)
local a = object( self )
a.mock = mock
a.replay_count = 0
a.min_replays = 1
a.max_replays = 1
return a
end
function Action.generic:set_times (a, b)
min = a or 1
max = b or min
min, max = tonumber(min), tonumber(max)
if (not min) or (not max) or (min >= math.huge)
or (min ~= min) or (max ~= max) -- NaN
or (min < 0) or (max <= 0) or (min > max) then
error( sfmt( "Unrealistic time arguments (%s, %s)"
, qtostring( min )
, qtostring( max )
)
, 0
)
end
self.min_replays = min
self.max_replays = max
end
Action.generic_call = class( Action.generic )
Action.generic_call.can_return = true
function Action.generic_call:get_returnvalue ()
if self.has_returnvalue then
return self.returnvalue:unpack()
end
end
function Action.generic_call:set_returnvalue (...)
self.returnvalue = Argv:new(...)
self.has_returnvalue = true
end
function Action.generic_call:match (q)
if not Action.generic.match( self, q ) then return false end
if not self.argv:equal( q.argv ) then return false end
return true
end
function Action.generic_call:new (m, ...)
local a = Action.generic.new( self, m )
a.argv = Argv:new(...)
return a
end
-- concrete
Action.call = class( Action.generic_call )
function Action.call:match (q)
if not Action.generic_call.match( self, q ) then return false end
if self.key ~= q.key then return false end
return true
end
function Action.call:new (m, key, ...)
local a = Action.generic_call.new( self, m, ... )
a.key = key
return a
end
function Action.call:tostring ()
if self.has_returnvalue then
return sfmt( "call %s(%s) => %s"
, tostring(self.key)
, self.argv:tostring()
, self.returnvalue:tostring()
)
else
return sfmt( "call %s(%s)"
, tostring(self.key)
, self.argv:tostring()
)
end
end
Action.index = class( Action.generic )
Action.index.can_return = true
function Action.index:get_returnvalue ()
return self.returnvalue
end
function Action.index:set_returnvalue (v)
self.returnvalue = v
self.has_returnvalue = true
end
function Action.index:match (q)
if not Action.generic.match( self, q ) then return false end
if self.key ~= q.key then return false end
return true
end
function Action.index:new (m, key)
local a = Action.generic.new( self, m )
a.key = key
return a
end
function Action.index:tostring ()
local key = 'index '..tostring( self.key )
if self.has_returnvalue then
return sfmt( "index %s => %s"
, tostring( self.key )
, qtostring( self.returnvalue )
)
elseif self.is_callable then
return sfmt( "index %s()"
, tostring( self.key )
)
else
return sfmt( "index %s"
, tostring( self.key )
)
end
end
Action.newindex = class( Action.generic )
function Action.newindex:match (q)
if not Action.generic.match( self, q ) then return false end
if self.key ~= q.key then return false end
if not value_equal( self.val, q.val )
and self.val ~= Argv.ANYARG
and q.val ~= Argv.ANYARG then return false end
return true
end
function Action.newindex:new (m, key, val)
local a = Action.generic.new( self, m )
a.key = key
a.val = val
return a
end
function Action.newindex:tostring ()
return sfmt( "newindex %s = %s"
, tostring(self.key)
, qtostring(self.val)
)
end
Action.selfcall = class( Action.generic_call )
function Action.selfcall:match (q)
return Action.generic_call.match( self, q )
end
function Action.selfcall:new (m, ...)
local a = Action.generic_call.new( self, m, ... )
return a
end
function Action.selfcall:tostring ()
if self.has_returnvalue then
return sfmt( "selfcall (%s) => %s"
, self.argv:tostring()
, self.returnvalue:tostring()
)
else
return sfmt( "selfcall (%s)"
, self.argv:tostring()
)
end
end
Argv = class()
Argv.ANYARGS = newproxy() local ANYARGS = Argv.ANYARGS
Argv.ANYARG = newproxy() local ANYARG = Argv.ANYARG
function Argv:equal (other)
local a1, n1 = self.v, self.len
local a2, n2 = other.v, other.len
if n1-1 <= n2 and a1[n1] == ANYARGS then
n1 = n1-1
n2 = n1
elseif n2-1 <= n1 and a2[n2] == ANYARGS then
n2 = n2-1
n1 = n2
end
if n1 ~= n2 then
return false
end
for i = 1, n1 do
local v1, v2 = a1[i], a2[i]
if not value_equal(v1,v2) and v1 ~= ANYARG and v2 ~= ANYARG then
return false
end
end
return true
end
function Argv:new (...)
local av = object( self )
av.v = {...}
av.len = select('#',...)
for i = 1, av.len - 1 do
if av.v[i] == Argv.ANYARGS then
error( "ANYARGS not at end.", 0 )
end
end
return av
end
function Argv:tostring ()
local res = {}
local function w (v)
res[#res+1] = qtostring( v )
end
local av, ac = self.v, self.len
for i = 1, ac do
if av[i] == Argv.ANYARG then
res[#res+1] = 'ANYARG'
elseif av[i] == Argv.ANYARGS then
res[#res+1] = 'ANYARGS'
else
w( av[i] )
end
if i < ac then
res[#res+1] = ',' -- can not use qtostring in w()
end
end
return table.concat( res )
end
function Argv:unpack ()
return unpack( self.v, 1, self.len )
end
Callable = {}
Callable.generic = class()
Callable.record = class( Callable.generic )
Callable.replay = class( Callable.generic )
function Callable.generic:new ( index_action )
local f = object( self )
f.action = index_action
return f
end
function Callable.record:__call (...)
local index_action = self.action
local m = index_action.mock
local mc = mock_controller_map[m]
assert( mc.is_recording, "client uses cached callable from recording" )
mc:make_callable( index_action )
mc:add_action( Action.call:new( m, index_action.key, ... ))
end
function Callable.replay:__call (...)
local index_action = self.action
local m = index_action.mock
local mc = mock_controller_map[m]
local call_action = mc:lookup( Action.call:new( m, index_action.key, ... ))
mc:replay_action( call_action )
if call_action.throws_error then
error( call_action.errorvalue, 2 )
end
return call_action:get_returnvalue()
end
Controller = class()
-- Exported methods
function Controller:close (...)
if not self.is_recording then
error( "Can not insert close in replay mode.", 2 )
end
local action = self:get_last_action()
for _, close in ipairs{ ... } do
action:add_close( close )
end
return self -- for chaining
end
function Controller:depend (...)
if not self.is_recording then
error( "Can not add dependency in replay mode.", 2 )
end
local action = self:get_last_action()
for _, dependency in ipairs{ ... } do
action:add_depend( dependency )
end
return self -- for chaining
end
function Controller:error (value)
if not self.is_recording then
error( "Error called during replay.", 2 )
end
local action = self:get_last_action()
if action.has_returnvalue or action.throws_error then
error( "Returns and/or Error called twice for same action.", 2 )
end
action.throws_error = true
action.errorvalue = value
return self -- for chaining
end
function Controller:label (...)
if not self.is_recording then
error( "Can not add labels in replay mode.", 2 )
end
local action = self:get_last_action()
for _, label in ipairs{ ... } do
action:add_label( label )
end
return self -- for chaining
end
function Controller:mock ()
if not self.is_recording then
error( "New mock during replay.", 2 )
end
local m = object( Mock.record )
mock_controller_map[m] = self
return m
end
function Controller:new ()
local mc = object( self )
mc.actionlist = {}
mc.is_recording = true
return mc
end
function Controller:replay ()
if not self.is_recording then
error( "Replay called twice.", 2 )
end
self.is_recording = false
for m, mc in pairs( mock_controller_map ) do
if mc == self then
setmetatable( m, Mock.replay )
end
end
self:update_dependencies()
self:assert_no_dependency_cycles()
end
function Controller:returns (...)
if not self.is_recording then
error( "Returns called during replay.", 2 )
end
local action = self:get_last_action()
assert( not action.is_callable, "lemock internal error" )
if not action.can_return then
error( "Previous action can not return anything.", 2 )
end
if action.has_returnvalue or action.throws_error then
error( "Returns and/or Error called twice for same action.", 2 )
end
action:set_returnvalue(...)
return self -- for chaining
end
function Controller:times (min, max)
if not self.is_recording then
error( "Can not set times in replay mode.", 0 )
end
self:get_last_action():set_times( min, max )
return self -- for chaining
end
-- convenience functions
function Controller:anytimes() return self:times( 0, math.huge ) end
function Controller:atleastonce() return self:times( 1, math.huge ) end
function Controller:verify ()
if self.is_recording then
error( "Verify called during record.", 2 )
end
for a in self:actions() do
a:assert_satisfied()
end
end
-- Protected methods
function Controller:actions (q)
local l = self.actionlist
local i = 0
return function ()
i = i + 1
return l[i]
end
end
function Controller:add_action (a)
assert( a ~= nil, "lemock internal error" ) -- breaks array property
table.insert( self.actionlist, a )
end
function Controller:assert_no_dependency_cycles ()
local function is_in_path (label, path)
if not path then return false end -- is root
for _, l in ipairs( path ) do
if l == label then return true end
end
if path.prev then return is_in_path( label, path.prev ) end
return false
end
local function can_block (action, node)
for _, label in ipairs( node ) do
if action:has_label( label ) then return true end
end
return false
end
local function step (action, path)
local new_head
for label in action:depends() do
if is_in_path( label, path ) then
error( "Detected dependency cycle", 0 )
end
-- only create table if needed to reduce garbage
if not new_head then new_head = { prev=path } end
new_head[#new_head+1] = label
end
return new_head
end
local function search_depth_first (path)
for action in self:actions() do
if can_block( action, path ) then
local new_head = step( action, path )
if new_head then
search_depth_first( new_head )
end
end
end
end
for action in self:actions() do
local root = step( action, nil )
if root then search_depth_first( root ) end
end
end
function Controller:close_actions( ... ) -- takes iterator
for label in ... do
for candidate in self:actions() do
if candidate:has_label( label ) then
if not candidate:is_satisfied() then
error( "Closes unsatisfied action: "..candidate:tostring(), 0 )
end
candidate.is_closed = true
end
end
end
end
function Controller:get_last_action ()
local l = self.actionlist
if #l == 0 then
error( "No action is recorded yet.", 0 )
end
return l[#l]
end
function Controller:lookup (actual)
for action in self:actions() do
if action:match( actual ) then
return action
end
end
local expected = {}
for _, a in ipairs( self.actionlist ) do
if a:is_expected() and not a.is_callable then
expected[#expected+1] = a:tostring()
end
end
table.sort( expected )
if #expected == 0 then
expected[1] = "(Nothing)"
end
error( sfmt( "Unexpected action %s, expected:\n%s\n"
, actual:tostring()
, table.concat(expected,'\n')
)
, 0
)
end
function Controller:make_callable (action)
if action.has_returnvalue then
error( "Can not call "..action.key..". It has a returnvalue.", 0 )
end
action.is_callable = true
action.min_replays = 0
action.max_replays = math.huge
end
function Controller:new ()
local mc = object( self )
mc.actionlist = {}
mc.is_recording = true
return mc
end
function Controller:replay_action ( action )
assert( action:is_expected(), "lemock internal error" )
assert( action.replay_count < action.max_replays, "lemock internal error" )
local was_satisfied = action:is_satisfied()
action.replay_count = action.replay_count + 1
if not was_satisfied and action.labellist and action:is_satisfied() then
self:update_dependencies()
end
if action.closelist then
self:close_actions( action:closes() )
end
end
function Controller:update_dependencies ()
local blocked = {}
for action in self:actions() do
for label in action:blocks() do
blocked[label] = true
end
end
local function is_blocked (action)
for label in action:depends() do
if blocked[label] then return true end
end
return false
end
for action in self:actions() do
action.is_blocked = is_blocked( action )
end
end
Mock = { record={}, replay={} } -- no self-referencing __index!
function Mock.record:__index (key)
local mc = mock_controller_map[self]
local action = Action.index:new( self, key )
mc:add_action( action )
return Callable.record:new( action )
end
function Mock.record:__newindex (key, val)
local mc = mock_controller_map[self]
mc:add_action( Action.newindex:new( self, key, val ))
end
function Mock.record:__call (...)
local mc = mock_controller_map[self]
mc:add_action( Action.selfcall:new( self, ... ))
end
function Mock.replay:__index (key)
local mc = mock_controller_map[self]
local index_action = mc:lookup( Action.index:new( self, key ))
mc:replay_action( index_action )
if index_action.throws_error then
error( index_action.errorvalue, 2 )
end
if index_action.is_callable then
return Callable.replay:new( index_action )
else
return index_action:get_returnvalue()
end
end
function Mock.replay:__newindex (key, val)
local mc = mock_controller_map[self]
local newindex_action = mc:lookup( Action.newindex:new( self, key, val ))
mc:replay_action( newindex_action )
if newindex_action.throws_error then
error( newindex_action.errorvalue, 2 )
end
end
function Mock.replay:__call (...)
local mc = mock_controller_map[self]
local selfcall_action = mc:lookup( Action.selfcall:new( self, ... ))
mc:replay_action( selfcall_action )
if selfcall_action.throws_error then
error( selfcall_action.errorvalue, 2 )
end
return selfcall_action:get_returnvalue()
end
function controller ()
local exported_methods = {
'anytimes',
'atleastonce',
'close',
'depend',
'error',
'label',
'mock',
'new',
'replay',
'returns',
'times',
'verify',
}
local mc = Controller:new()
local wrapper = {}
for _, method in ipairs( exported_methods ) do
wrapper[ method ] = function (self, ...)
return mc[ method ]( mc, ... )
end
end
wrapper.ANYARG = Argv.ANYARG
wrapper.ANYARGS = Argv.ANYARGS
return wrapper
end
return _M

@ -1,759 +0,0 @@
--[[
luaunit.lua
Description: A unit testing framework
Homepage: https://github.com/bluebird75/luaunit
Initial author: Ryu, Gwang (http://www.gpgstudy.com/gpgiki/LuaUnit)
Lot of improvements by Philippe Fremy <phil@freehackers.org>
License: BSD License, see LICENSE.txt
]]--
argv = arg
--[[ Some people like assertEquals( actual, expected ) and some people prefer
assertEquals( expected, actual ).
]]--
USE_EXPECTED_ACTUAL_IN_ASSERT_EQUALS = true
DEFAULT_VERBOSITY = 1
function assertError(f, ...)
-- assert that calling f with the arguments will raise an error
-- example: assertError( f, 1, 2 ) => f(1,2) should generate an error
local has_error, error_msg = not pcall( f, ... )
if has_error then return end
error( "Expected an error but no error generated", 2 )
end
function mytostring( v )
if type(v) == 'string' then
return '"'..v..'"'
end
if type(v) == 'table' then
if v.__class__ then
return string.gsub( tostring(v), 'table', v.__class__ )
end
return tostring(v)
end
return tostring(v)
end
function errormsg(actual, expected)
local errorMsg
if not USE_EXPECTED_ACTUAL_IN_ASSERT_EQUALS then
expected, actual = actual, expected
end
if type(expected) == 'string' then
errorMsg = "\nexpected: "..mytostring(expected).."\n"..
"actual : "..mytostring(actual).."\n"
else
errorMsg = "expected: "..mytostring(expected)..", actual: "..mytostring(actual)
end
return errorMsg
end
function _table_contains(t, element)
local _, value, v
if t then
for _, value in pairs(t) do
if type(value) == type(element) then
if type(element) == 'table' then
if _is_table_items_equals(v, expected) then
return true
end
else
if value == element then
return true
end
end
end
end
end
return false
end
function _is_table_items_equals(actual, expected, parent_key, items)
if (type(actual) == 'table') and (type(expected) == 'table') then
local k,v
for k,v in pairs(actual) do
if not _table_contains(expected, v) then
return false
end
end
return true
elseif type(actual) ~= type(expected) then
return false
elseif actual == expected then
return true
end
return false
end
function _is_table_equals(actual, expected)
if (type(actual) == 'table') and (type(expected) == 'table') then
local k,v
for k,v in ipairs(actual) do
if not _is_table_equals(v, expected[k]) then
return false
end
end
for k,v in pairs(actual) do
if (type(k) ~= 'number') and (not _is_table_equals(v, expected[k])) then
return false
end
end
return true
elseif type(actual) ~= type(expected) then
return false
elseif actual == expected then
return true
end
return false
end
function assertEquals(actual, expected)
if type(actual) == 'table' and type(expected) == 'table' then
if not _is_table_equals(actual, expected) then
error( errormsg(actual, expected), 2 )
end
elseif type(actual) ~= type(expected) then
error( errormsg(actual, expected), 2 )
elseif actual ~= expected then
error( errormsg(actual, expected), 2 )
end
end
function assertTrue(value)
if not value then
error("expected: true, actual: " ..mytostring(value), 2)
end
end
function assertFalse(value)
if value then
error("expected: false, actual: " ..mytostring(value), 2)
end
end
function assertNotEquals(actual, expected)
if type(actual) == 'table' and type(expected) == 'table' then
if _is_table_equals(actual, expected) then
error( errormsg(actual, expected), 2 )
end
elseif type(actual) == type(expected) and actual == expected then
error( errormsg(actual, expected), 2 )
end
end
function assertItemsEquals(actual, expected)
if not _is_table_items_equals(actual, expected, true) then
error( errormsg(actual, expected), 2 )
end
end
function assertIsNumber(value)
if type(value) ~= 'number' then
error("expected: a number value, actual:" .. type(value))
end
end
function assertIsString(value)
if type(value) ~= "string" then
error("expected: a string value, actual:" .. type(value))
end
end
function assertIsTable(value)
if type(value) ~= 'table' then
error("expected: a table value, actual:" .. type(value))
end
end
function assertIsBoolean(value)
if type(value) ~= 'boolean' then
error("expected: a boolean value, actual:" .. type(value))
end
end
function assertIsNil(value)
if type(value) ~= "nil" then
error("expected: a nil value, actual:" .. type(value))
end
end
function assertIsFunction(value)
if type(value) ~= 'function' then
error("expected: a function value, actual:" .. type(value))
end
end
function assertIs(actual, expected)
if actual ~= expected then
error( errormsg(actual, expected), 2 )
end
end
function assertNotIs(actual, expected)
if actual == expected then
error( errormsg(actual, expected), 2 )
end
end
assert_equals = assertEquals
assert_not_equals = assertNotEquals
assert_error = assertError
assert_true = assertTrue
assert_false = assertFalse
assert_is_number = assertIsNumber
assert_is_string = assertIsString
assert_is_table = assertIsTable
assert_is_boolean = assertIsBoolean
assert_is_nil = assertIsNil
assert_is_function = assertIsFunction
assert_is = assertIs
assert_not_is = assertNotIs
function __genOrderedIndex( t )
local orderedIndex = {}
for key,_ in pairs(t) do
table.insert( orderedIndex, key )
end
table.sort( orderedIndex )
return orderedIndex
end
function orderedNext(t, state)
-- Equivalent of the next() function of table iteration, but returns the
-- keys in the alphabetic order. We use a temporary ordered key table that
-- is stored in the table being iterated.
--print("orderedNext: state = "..tostring(state) )
local key
if state == nil then
-- the first time, generate the index
t.__orderedIndex = nil
t.__orderedIndex = __genOrderedIndex( t )
key = t.__orderedIndex[1]
return key, t[key]
end
-- fetch the next value
key = nil
for i = 1,#t.__orderedIndex do
if t.__orderedIndex[i] == state then
key = t.__orderedIndex[i+1]
end
end
if key then
return key, t[key]
end
-- no more value to return, cleanup
t.__orderedIndex = nil
return
end
function orderedPairs(t)
-- Equivalent of the pairs() function on tables. Allows to iterate
-- in order
return orderedNext, t, nil
end
function strsplit(delimiter, text)
-- Split text into a list consisting of the strings in text,
-- separated by strings matching delimiter (which may be a pattern).
-- example: strsplit(",%s*", "Anna, Bob, Charlie,Dolores")
local list = {}
local pos = 1
if string.find("", delimiter, 1) then -- this would result in endless loops
error("delimiter matches empty string!")
end
while 1 do
local first, last = string.find(text, delimiter, pos)
if first then -- found?
table.insert(list, string.sub(text, pos, first-1))
pos = last+1
else
table.insert(list, string.sub(text, pos))
break
end
end
return list
end
function prefixString( prefix, s )
local t, s2
t = strsplit('\n', s)
s2 = prefix..table.concat(t, '\n'..prefix)
return s2
end
----------------------------------------------------------------
-- class TapOutput
----------------------------------------------------------------
TapOutput = { -- class
__class__ = 'TapOutput',
runner = nil,
result = nil,
}
TapOutput_MT = { __index = TapOutput }
function TapOutput:new()
local t = {}
t.verbosity = 0
setmetatable( t, TapOutput_MT )
return t
end
function TapOutput:startSuite() end
function TapOutput:startClass(className) end
function TapOutput:startTest(testName) end
function TapOutput:addFailure( errorMsg, stackTrace )
print(string.format("not ok %d\t%s", self.result.testCount, self.result.currentTestName ))
if self.verbosity > 0 then
print( prefixString( ' ', errorMsg ) )
end
if self.verbosity > 1 then
print( prefixString( ' ', stackTrace ) )
end
end
function TapOutput:endTest(testHasFailure)
if not self.result.currentTestHasFailure then
print(string.format("ok %d\t%s", self.result.testCount, self.result.currentTestName ))
end
end
function TapOutput:endClass() end
function TapOutput:endSuite()
print("1.."..self.result.testCount)
return self.result.failureCount
end
-- class TapOutput end
----------------------------------------------------------------
-- class TextOutput
----------------------------------------------------------------
TextOutput = { __class__ = 'TextOutput' }
TextOutput_MT = { -- class
__index = TextOutput
}
function TextOutput:new()
local t = {}
t.runner = nil
t.result = nil
t.errorList ={}
t.verbosity = 1
setmetatable( t, TextOutput_MT )
return t
end
function TextOutput:startSuite()
end
function TextOutput:startClass(className)
if self.verbosity > 0 then
print( '>>>>>>>>> '.. self.result.currentClassName )
end
end
function TextOutput:startTest(testName)
if self.verbosity > 0 then
print( ">>> ".. self.result.currentTestName )
end
end
function TextOutput:addFailure( errorMsg, stackTrace )
table.insert( self.errorList, { self.result.currentTestName, errorMsg, stackTrace } )
if self.verbosity == 0 then
io.stdout:write("F")
end
if self.verbosity > 0 then
print( errorMsg )
print( 'Failed' )
end
end
function TextOutput:endTest(testHasFailure)
if not testHasFailure then
if self.verbosity > 0 then
--print ("Ok" )
else
io.stdout:write(".")
end
end
end
function TextOutput:endClass()
if self.verbosity > 0 then
print()
end
end
function TextOutput:displayOneFailedTest( failure )
testName, errorMsg, stackTrace = unpack( failure )
print(">>> "..testName.." failed")
print( errorMsg )
if self.verbosity > 1 then
print( stackTrace )
end
end
function TextOutput:displayFailedTests()
if #self.errorList == 0 then return end
print("Failed tests:")
print("-------------")
for i,v in ipairs(self.errorList) do
self:displayOneFailedTest( v )
end
print()
end
function TextOutput:endSuite()
if self.verbosity == 0 then
print()
else
print("=========================================================")
end
self:displayFailedTests()
local successPercent, successCount
successCount = self.result.testCount - self.result.failureCount
if self.result.testCount == 0 then
successPercent = 100
else
successPercent = math.ceil( 100 * successCount / self.result.testCount )
end
print( string.format("Success : %d%% - %d / %d",
successPercent, successCount, self.result.testCount) )
end
-- class TextOutput end
----------------------------------------------------------------
-- class NilOutput
----------------------------------------------------------------
function nopCallable()
--print(42)
return nopCallable
end
NilOutput = {
__class__ = 'NilOuptut',
}
NilOutput_MT = {
__index = nopCallable,
}
function NilOutput:new()
local t = {}
t.__class__ = 'NilOutput'
setmetatable( t, NilOutput_MT )
return t
end
----------------------------------------------------------------
-- class LuaUnit
----------------------------------------------------------------
LuaUnit = {
outputType = TextOutput,
verbosity = DEFAULT_VERBOSITY,
__class__ = 'LuaUnit'
}
LuaUnit_MT = { __index = LuaUnit }
function LuaUnit:new()
local t = {}
setmetatable( t, LuaUnit_MT )
return t
end
-----------------[[ Utility methods ]]---------------------
function LuaUnit.isFunction(aObject)
return 'function' == type(aObject)
end
--------------[[ Output methods ]]-------------------------
function LuaUnit:ensureSuiteStarted( )
if self.result and self.result.suiteStarted then
return
end
self:startSuite()
end
function LuaUnit:startSuite()
self.result = {}
self.result.failureCount = 0
self.result.testCount = 0
self.result.currentTestName = ""
self.result.currentClassName = ""
self.result.currentTestHasFailure = false
self.result.suiteStarted = true
self.outputType = self.outputType or TextOutput
self.output = self.outputType:new()
self.output.runner = self
self.output.result = self.result
self.output.verbosity = self.verbosity
self.output:startSuite()
end
function LuaUnit:startClass( className )
self.result.currentClassName = className
self.output:startClass( className )
end
function LuaUnit:startTest( testName )
self.result.currentTestName = testName
self.result.testCount = self.result.testCount + 1
self.result.currentTestHasFailure = false
self.output:startTest( testName )
end
function LuaUnit:addFailure( errorMsg, stackTrace )
if not self.result.currentTestHasFailure then
self.result.failureCount = self.result.failureCount + 1
self.result.currentTestHasFailure = true
end
self.output:addFailure( errorMsg, stackTrace )
end
function LuaUnit:endTest()
self.output:endTest( self.result.currentTestHasFailure )
self.result.currentTestName = ""
self.result.currentTestHasFailure = false
end
function LuaUnit:endClass()
self.output:endClass()
end
function LuaUnit:endSuite()
self.result.suiteStarted = false
self.output:endSuite()
end
function LuaUnit:setOutputType(outputType)
-- default to text
-- tap produces results according to TAP format
if outputType:upper() == "NIL" then
self.outputType = NilOutput
return
end
if outputType:upper() == "TAP" then
self.outputType = TapOutput
return
end
if outputType:upper() == "TEXT" then
self.outputType = TextOutput
return
end
error( 'No such format: '..outputType)
end
function LuaUnit:setVerbosity( verbosity )
self.verbosity = verbosity
end
--------------[[ Runner ]]-----------------
SPLITTER = '\n>----------<\n'
function LuaUnit:protectedCall( classInstance , methodInstance)
-- if classInstance is nil, this is just a function run
local function err_handler(e)
return debug.traceback(e..SPLITTER, 4)
end
local ok=true, errorMsg, stackTrace
if classInstance then
-- stupid Lua < 5.2 does not allow xpcall with arguments so let's live with that
ok, errorMsg = xpcall( function () methodInstance(classInstance) end, err_handler )
else
ok, errorMsg = xpcall( function () methodInstance() end, err_handler )
end
if not ok then
t = strsplit( SPLITTER, errorMsg )
stackTrace = string.sub(t[2],2)
self:addFailure( t[1], stackTrace )
end
return ok
end
function LuaUnit:_runTestMethod(className, methodName, classInstance, methodInstance)
-- When executing a class method, all parameters are set
-- When executing a test function, className and classInstance are nil
if type(methodInstance) ~= 'function' then
error( tostring(methodName)..'must be a function, not '..type(methodInstance))
end
if className == nil then
className = '<TestFunction>'
end
if self.lastClassName ~= className then
if self.lastClassName ~= nil then
self:endClass()
end
self:startClass( className )
self.lastClassName = className
end
self:startTest(className..':'..methodName)
-- run setUp first(if any)
if classInstance and self.isFunction( classInstance.setUp ) then
self:protectedCall( classInstance, classInstance.setUp)
end
-- run testMethod()
if not self.result.currentTestHasFailure then
self:protectedCall( classInstance, methodInstance)
end
-- lastly, run tearDown(if any)
if classInstance and self.isFunction(classInstance.tearDown) then
self:protectedCall( classInstance, classInstance.tearDown)
end
self:endTest()
end
function LuaUnit:runSomeTest( someName, someInstance )
-- name is mandatory
-- if instance is not given, it's looked up in the global namespace
-- name can be a test class, a test function, or a test class + test method
-- instance can be a test class or a test function
-- example: runSomeTest( 'TestToto' )
-- example: runSomeTest( 'TestToto', TestToto )
-- example: runSomeTest( 'TestToto:testTiti' )
-- example: runSomeTest( 'TestToto:testTiti', TestToto )
-- example: runSomeTest( 'testFunction' )
-- example: runSomeTest( 'testFunction' , testFunction )
self:ensureSuiteStarted()
local hasMethod, methodName, methodInstance, className, classInstance
if someName == nil or someName == '' then
error( 'Name is required!')
end
hasMethod = string.find(someName, ':' )
-- name is class + method
if hasMethod then
methodName = string.sub(someName, hasMethod+1)
className = string.sub(someName,1,hasMethod-1)
classInstance = someInstance
classInstance = classInstance or _G[className]
if classInstance == nil then
error( "No such class: "..className )
end
if type(classInstance) ~= 'table' then
error( 'Instance must be a table')
end
methodInstance = classInstance[methodName]
if methodInstance == nil then
error( "Could not find method in class "..tostring(className).." for method "..tostring(methodName) )
end
self:_runTestMethod( className, methodName, classInstance, methodInstance )
return
end
if someInstance == nil then
someInstance = _G[someName]
if not someInstance then
error( "No such variable: "..someName )
end
end
if (type(someInstance) ~= 'table' and type(someInstance) ~= 'function') then
error( 'Instance must be function or table')
end
-- name is either a function or a class
if type(someInstance) == 'table' then
-- run all test methods of the class
className = someName
classInstance = someInstance
for methodName, methodInstance in orderedPairs(classInstance) do
if LuaUnit.isFunction(methodInstance) and string.sub(methodName, 1, 4) == "test" then
self:_runTestMethod( className, methodName, classInstance, methodInstance )
end
end
return
end
if type(someInstance) == 'function' then
self:_runTestMethod( nil, someName, nil, someInstance )
return
end
error( 'Should never be reached...')
end
function LuaUnit:run(...)
-- Run some specific test classes.
-- If no arguments are passed, run the class names specified on the
-- command line. If no class name is specified on the command line
-- run all classes whose name starts with 'Test'
--
-- If arguments are passed, they must be strings of the class names
-- that you want to run
local runner = self:new()
return runner:runSuite(...)
end
function LuaUnit:runSuite(...)
self:startSuite()
args={...};
if #args == 0 then
args = argv
end
if #args == 0 then
-- create the list if classes to run now ! If not, you can
-- not iterate over _G while modifying it.
args = {}
for key, val in pairs(_G) do
if string.sub(key,1,4):lower() == 'test' then
table.insert( args, key )
end
end
table.sort( args )
end
for i,testName in ipairs( args ) do
self:runSomeTest( testName )
end
if self.lastClassName ~= nil then
self:endClass()
end
self:endSuite()
return self.result.failureCount
end
-- class LuaUnit
Loading…
Cancel
Save