Koha Test Wiki MW Canasta on Koha Portainer

Test major Koha Wiki changes or bug fixes here without fear of breaking the production wiki.

For the current Koha Wiki, visit https://wiki.koha-community.org .

Module:Math/testcases

From Koha Test Wiki MW Canasta on Koha Portainer
Jump to navigation Jump to search

Documentation for this module may be created at Module:Math/testcases/doc

-- Unit tests for [[Module:Math/sandbox]]. Click talk page to run tests.

local moduleName = 'Math/sandbox' -- assigning this to a variable as it is later used to generate an #invoke statement.
local mm = require('Module:' .. moduleName)
local ScribuntoUnit = require('Module:ScribuntoUnit')
local suite = ScribuntoUnit:new()

-------------------------------------------------------------------------------
-- Helper functions
-------------------------------------------------------------------------------

function suite.getLuaResult(funcName, args)
	args = args or {}
	local result = mm['_' .. funcName](unpack(args))
	return result
end

function suite:assertLuaEquals(expected, funcName, args)
	args = args or {}
	self:assertEquals(expected, self.getLuaResult(funcName, args))
end

function suite.buildInvocation(funcName, args)
	args = args or {}
	local argsClone = mw.clone(args)
	-- Build a module invocation equivalent to the args table. Taken from [[Module:Unsubst]].
	-- Numbered args first.
	local ret = '{{#invoke:' .. moduleName .. '|' .. funcName
	for k, v in ipairs(argsClone) do
		v = tostring(v)
		if string.find(v, '=', 1, true) then
			-- likely something like 1=foo=bar, we need to do it as a named arg
			break
		end
		ret = ret .. '|' .. v
		argsClone[k] = nil
	end
	for k, v in pairs(argsClone) do
		k = tostring(k)
		v = tostring(v)
		ret = ret .. '|' .. k .. '=' .. v
	end
	return ret .. '}}'
end

function suite:getInvokeResult(funcName, args, convertNumber) -- Unless convertNumber is false, the number is converted to a number, if possible, on re-entry to Lua.
	args = args or {}
	local invocation = self.buildInvocation(funcName, args)
	local result = self.frame:preprocess(invocation)
	if convertNumber ~= false and tonumber(result) then
		return tonumber(result)
	else
		return result
	end
end

function suite:assertInvokeEquals(expected, funcName, args, convertNumber)
	args = args or {}
	local invokeResult = self:getInvokeResult(funcName, args, convertNumber)
	self:assertEquals(expected, invokeResult)
end

function suite:assertLuaAndInvokeTrue(trueFunc, funcName, args, convertNumber)
	args = args or {}
	local invokeResult = self:getInvokeResult(funcName, args, convertNumber)
	local luaResult = self.getLuaResult(funcName, args)
	self:assertTrue(trueFunc(invokeResult))
	self:assertTrue(trueFunc(luaResult))
end

function suite:assertLuaAndInvokeEqual(funcName, testTable, convertNumber)
	local expected = testTable[1]
	local args = testTable[2] or {}
	self:assertLuaEquals(expected, funcName, args)
	self:assertInvokeEquals(expected, funcName, args, convertNumber)
end

function suite:assertLuaAndInvokeEqualMany(funcName, testTables, convertNumber)
	for i, testTable in ipairs(testTables) do
		self:assertLuaAndInvokeEqual(funcName, testTable, convertNumber)
	end
end

-------------------------------------------------------------------------------
-- Test random
-------------------------------------------------------------------------------

function suite:test_random()
	self:assertLuaAndInvokeTrue(function (n) return n >= 0 and n < 1 end, 'random')
	self:assertLuaAndInvokeTrue(function (n) return n == 1 or n == 2 end, 'random', {2})
	self:assertLuaAndInvokeTrue(function (n) return n >= 1 and n <= 10 and math.floor(n) == n end, 'random', {10})
	self:assertLuaAndInvokeTrue(function (n) return n >= 10 and n <= 20 and math.floor(n) == n end, 'random', {10, 20})
end

-------------------------------------------------------------------------------
-- Test max
-------------------------------------------------------------------------------
 
function suite:test_max()
	local tests = {
		{9, {5, 6, 9}},
		{-5, {-5, -6, -9}},
	}
	self:assertLuaAndInvokeEqualMany('max', tests)
	self:assertLuaEquals(nil, 'max', {})
	self:assertInvokeEquals('', 'max', {})
end

-------------------------------------------------------------------------------
-- Test average
-------------------------------------------------------------------------------

function suite:test_average()
	local tests = {
		{6, {5, 6, 7}},
		{-7, {-7}},
		{10000000002, {10000000001, 10000000002, 10000000003}},
	}
	self:assertLuaAndInvokeEqualMany('average', tests)
end
 
-------------------------------------------------------------------------------
-- Test min
-------------------------------------------------------------------------------

function suite:test_min()
	local tests = {
		{1, {1, 2, 3}},
		{-3, {-1, -2, -3}},
	}
	self:assertLuaAndInvokeEqualMany('min', tests)
	self:assertLuaEquals(nil, 'min', {})
	self:assertInvokeEquals('', 'min', {})
end

-------------------------------------------------------------------------------
-- Test gcd
-------------------------------------------------------------------------------

function suite:test_gcd()
	local tests = {
		{4, {12, 8}},
		{2, {12, 8, 6}},
		{4, {-12, -8}},
		{2, {-12, -8, -6}},
		{8, {0, 8}},
		{8, {0, -8}},
		{0, {0}},
		{0, {0, 0}},
		{4, {12, nil, 8}},
	}
	self:assertLuaAndInvokeEqualMany('gcd', tests)
end

-------------------------------------------------------------------------------
-- Test order
-------------------------------------------------------------------------------

function suite:test_order()
	local tests = {
		{0, {2}},
		{1, {20}},
		{2, {200}},
		{0, {5}},
	}
	self:assertLuaAndInvokeEqualMany('order', tests)
	self:assertInvokeEquals('<strong class="error">Formatting error: order of magnitude input appears non-numeric</strong>', 'order', {'string'})
	self:assertInvokeEquals(0, 'order', {x = 5})
end

-------------------------------------------------------------------------------
-- Test precision
-------------------------------------------------------------------------------

function suite:test_precison()
	local tests = {
		{4, {1.9856}},
		{1, {1.1}},
		{10, {1.9999999999}},
	}
	self:assertLuaAndInvokeEqualMany('precision', tests)
	self:assertInvokeEquals('<strong class="error">Formatting error: precision input appears non-numeric</strong>', 'precision', {'letra'})
	self:assertInvokeEquals(4, 'precision', {x = '1.9888'})
end

-------------------------------------------------------------------------------
-- Test round
-------------------------------------------------------------------------------

function suite:test_round()
	local tests = {
		{2, {1.99999}},
		{2, {1.99999, 0}},
		{1.9, {1.94, 1}},
		{20, {15, -1}},
	}
	self:assertLuaAndInvokeEqualMany('round', tests)
	self:assertInvokeEquals(3, 'round', {value = '2.99999', precision = '2'})
end

-------------------------------------------------------------------------------
-- Test mod
-------------------------------------------------------------------------------

function suite:test_mod()
	local tests = {
		{0, {10, 2}},
		{1, {11, 2}},
		{0, {525000000000000120000000000, 3}}, -- With the plain % operator this returns 68719476736 due to floating point error.
	}
	self:assertLuaAndInvokeEqualMany('mod', tests)
	self:assertInvokeEquals('<strong class="error">Formatting error: first argument to mod appears non-numeric</strong>', 'mod', {})
	self:assertInvokeEquals('<strong class="error">Formatting error: second argument to mod appears non-numeric</strong>', 'mod', {1})
	local successNoArgs = pcall(mm._mod)
	self:assertFalse(successNoArgs)
	local successOneArg = pcall(mm._mod, 1)
	self:assertFalse(successOneArg)
end

-------------------------------------------------------------------------------
-- Test precision format
-------------------------------------------------------------------------------

function suite:test_precison_format()
	local tests = {
		{'10.00', {10, 2}}
	}
	self:assertLuaAndInvokeEqualMany('precision_format', tests, false) -- the "false" stops string values being converted to numbers on re-entry from #invoke.
end

-------------------------------------------------------------------------------
-- Test cleanNumber
-------------------------------------------------------------------------------

function suite:assertCleanNumberEquals(expectedTable, inputString)
	local expectedNum, expectedNumString = expectedTable[1], expectedTable[2]
	local actualNum, actualNumString = mm._cleanNumber(inputString)
	self:assertEquals(expectedNum, actualNum)
	self:assertEquals(expectedNumString, actualNumString)
end

function suite:test_cleanNumber()
	self:assertCleanNumberEquals({0, '0'}, '0')
	self:assertCleanNumberEquals({1, '1'}, 1)
	self:assertCleanNumberEquals({2, '2'}, '  2  ')
	self:assertCleanNumberEquals({3, '3'}, '4-1')
	self:assertCleanNumberEquals({4, '4'}, '2 + 2')
	self:assertCleanNumberEquals({5, '5'}, '  2 + 3  ')
	self:assertCleanNumberEquals({6, '6'}, '+6')
	self:assertCleanNumberEquals({-7, '-7'}, '-7')
	self:assertCleanNumberEquals({88, '88'}, '0x58')
	self:assertCleanNumberEquals({1000000000, '1e+9'}, '1e+9')
	self:assertCleanNumberEquals({-88, '-88'}, '-0x58')
	self:assertCleanNumberEquals({0.16667, '0.16667'}, '1/6 round 5')
	self:assertCleanNumberEquals({nil, nil}, '1 foo 2') -- invalid expression
	self:assertCleanNumberEquals({nil, nil}, '1+') -- missing expr operand
	self:assertCleanNumberEquals({nil, nil}, '')
	self:assertCleanNumberEquals({nil, nil}, '  ')
	self:assertCleanNumberEquals({nil, nil}, 'string')
	self:assertCleanNumberEquals({nil, nil}, '  string with padding  ')
end

return suite