Module:Math/testcases

-- 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.err(msg) return mw.ustring.format('&#x3c;strong class="error"&#x3e;Formatting error: %s&#x3c;/strong&#x3e;', msg) end

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 = '' 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 &#x3e;= 0 and n &#x3c; 1 end, 'random') self:assertLuaAndInvokeTrue(function (n) return n == 1 or n == 2 end, 'random', {2}) self:assertLuaAndInvokeTrue(function (n) return n &#x3e;= 1 and n &#x3c;= 10 and math.floor(n) == n end, 'random', {10}) self:assertLuaAndInvokeTrue(function (n) return n &#x3e;= 10 and n &#x3c;= 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(suite.err('order of magnitude input appears non-numeric'), '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(suite.err('precision input appears non-numeric'), '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(suite.err('first argument to mod appears non-numeric'), 'mod', {}) self:assertInvokeEquals(suite.err('second argument to mod appears non-numeric'), '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 --- -- Test divide ---

function suite:test_divide self:assertInvokeEquals('1','divide',{1, 2, round = 'yes'}, false) self:assertInvokeEquals('0.5','divide',{1, 2, round = 'no'}, false) self:assertInvokeEquals('0','divide',{1, 3, round = 'yes', precision=2}, false) self:assertInvokeEquals('0.33','divide',{1, 3, precision=2}, false) self:assertInvokeEquals(suite.err('Empty dividend'),'divide',{'',2},false) self:assertInvokeEquals(suite.err('Empty divisor'),'divide',{1,''},false) self:assertInvokeEquals(suite.err('Empty divisor'),'divide',{},false) self:assertInvokeEquals(suite.err('Empty divisor'),'divide',{,},false) self:assertInvokeEquals(suite.err('Not a number: a'),'divide',{'a',2},false) self:assertInvokeEquals(suite.err('Not a number: b'),'divide',{1,'b'},false) self:assertInvokeEquals(suite.err('Not a number: b'),'divide',{'a','b'},false) self:assertInvokeEquals('&#x3c;big&#x3e;Bad&#x3c;/big&#x3e;','divide',{'&#x3c;big&#x3e;Bad&#x3c;/big&#x3e;',2},false) self:assertInvokeEquals('&#x3c;big&#x3e;Bad&#x3c;/big&#x3e;','divide',{1,'&#x3c;big&#x3e;Bad&#x3c;/big&#x3e;'},false) self:assertInvokeEquals('&#x3c;big&#x3e;Bad2&#x3c;/big&#x3e;','divide',{'&#x3c;big&#x3e;Bad1&#x3c;/big&#x3e;','&#x3c;big&#x3e;Bad2&#x3c;/big&#x3e;'},false) end return suite