From Omniversalis

Documentation for this module may be created at Module:BDD/utils/doc

-- utility module for the Behavior Driven Development testing framework
-- @provenance ideas from Moses []
-- © John Erling Blad, Creative Commons by Attribution 3.0

-- @var table holding the modules exported members
local utils = {}

-- raw count of all the items in the provided table
-- @provenance reformatted exported version of 'local function count(t)' in Moses
-- @param t table that has its entries counted
-- @return count of raw entries
function utils.count( t )
	local i = 0
		for k,v in pairs( t ) do
			i = i + 1
	return i

-- size based on the raw count
-- @provenance reformatted exported version of 'function _.size(...)' in Moses
-- @param optional [table|any] count entries if table, count all args otherwise
-- @return count of entries
function utils.size(...)
	local args = {...}
	local arg1 = args[1]
	if arg1 == nil then
		return 0
	elseif type( arg1 ) == 'table' then
		return utils.count( args[1] )
	-- placement differs from Moses
	return utils.count( args )

-- deep equal of two objects
-- @provenance changed exported version of 'function UnitTester:equals_deep(name, actual, expected, options)' in [[w:no:Module:UnitTests]]
-- @provenance reformatted exported version of 'function _.isEqual(objA, objB, useMt)' in Moses
-- @param objA any type of object
-- @param objB any type of object
-- @param useMt boolean optional indicator for whether to include the meta table
-- @return boolean result of comparison
function utils.deepEqual( objA, objB, useMt )
	local typeObjA = type( objA )
	local typeObjB = type( objB )

	if typeObjA ~= typeObjB then
		return false end
	if typeObjA ~= 'table' then
		return objA == objB

	local mtA = getmetatable( objA )
	local mtB = getmetatable( objB )

	if useMt then
		if (mtA or mtB) and (mtA.__eq or mtB.__eq) then
			return mtA.__eq(objA, objB) or mtB.__eq(objB, objA) or (objA==objB)

	if utils.size( objA ) ~= utils.size( objB ) then
		return false

	for i,v1 in pairs( objA ) do
		local v2 = objB[i]
		-- test is partly inlined, differs from Moses
		if v2 == nil or not utils.deepEqual( v1, v2, useMt ) then
			return false

	for i,v1 in pairs(objB) do
		local v2 = objA[i]
		-- test is inlined, differs from Moses
		if v2 == nil then
			return false

	return true

-- checks if a table contains the arg
-- @provenance reformatted exported version of 'function _.contains(t, value)' in Moses
-- @param t table that is searched for the arg
-- @param arg any item to be searched for
-- @return boolean result of the operation
function utils.contains(t, arg)
	-- inlined code from '_.toBoolean' and '_.detect' from Moses
	local cmp = (type(arg)=='function') and arg or utils.deepEqual
	for k,v in pairs(t) do
		if cmp(v, arg) then
			return k
	return false

-- return the export table
return utils