From 8fe75f9300d8ae9b73c8a32610743ef6d0e77c3b Mon Sep 17 00:00:00 2001 From: Victor Seva Date: Fri, 10 May 2013 14:56:49 +0200 Subject: [PATCH] First Debian packaging attempt --- debian/changelog | 5 + debian/compat | 1 + debian/control | 18 + debian/copyright | 28 ++ debian/dh-lua.conf | 8 + debian/lua5.1.dh-lua.conf | 4 + debian/rules | 13 + debian/source/format | 1 + lemock.lua | 659 --------------------------------- luaunit.lua | 759 -------------------------------------- 10 files changed, 78 insertions(+), 1418 deletions(-) create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/dh-lua.conf create mode 100644 debian/lua5.1.dh-lua.conf create mode 100755 debian/rules create mode 100644 debian/source/format delete mode 100644 lemock.lua delete mode 100644 luaunit.lua diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..1d6f412 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +lua-ngcp (0.1.0) UNRELEASED; urgency=low + + * Initial Release. + + -- Victor Seva Fri, 10 May 2013 13:56:44 +0200 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..ec63514 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +9 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..9035669 --- /dev/null +++ b/debian/control @@ -0,0 +1,18 @@ +Source: lua-ngcp +Priority: extra +Maintainer: Victor Seva +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. + diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..1acbadb --- /dev/null +++ b/debian/copyright @@ -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 +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 . + . + On Debian systems, the complete text of the GNU General + Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". diff --git a/debian/dh-lua.conf b/debian/dh-lua.conf new file mode 100644 index 0000000..d3dd061 --- /dev/null +++ b/debian/dh-lua.conf @@ -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= diff --git a/debian/lua5.1.dh-lua.conf b/debian/lua5.1.dh-lua.conf new file mode 100644 index 0000000..48b39d2 --- /dev/null +++ b/debian/lua5.1.dh-lua.conf @@ -0,0 +1,4 @@ +PKG_NAME=ngcp + +LUA_SOURCES=$(wildcard ngcp/*.lua) +LUA_MODNAME=ngcp diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..e167251 --- /dev/null +++ b/debian/rules @@ -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 diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..89ae9db --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/lemock.lua b/lemock.lua deleted file mode 100644 index a25bc8c..0000000 --- a/lemock.lua +++ /dev/null @@ -1,659 +0,0 @@ ------- THIS FILE IS TANGLED FROM LITERATE SOURCE FILES ------ --- Copyright (C) 2009 Tommy Pettersson --- 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 " -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 diff --git a/luaunit.lua b/luaunit.lua deleted file mode 100644 index 84f6d18..0000000 --- a/luaunit.lua +++ /dev/null @@ -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 -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 = '' - 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 -