Difference between revisions of "Module:Math/testcases"
Jump to navigation
Jump to search
blackwiki>Mr. Stradivarius (preprocess the invoke args and fix rand10_20) |
m (25 revisions imported) |
||
| (19 intermediate revisions by 2 users not shown) | |||
| Line 1: | Line 1: | ||
| − | -- Unit tests for [[Module:Math]]. Click talk page to run tests. | + | -- Unit tests for [[Module:Math/sandbox]]. Click talk page to run tests. |
| − | local mm = require('Module: | + | 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 ScribuntoUnit = require('Module:ScribuntoUnit') | ||
local suite = ScribuntoUnit:new() | local suite = ScribuntoUnit:new() | ||
| − | + | ------------------------------------------------------------------------------- | |
| − | + | -- Helper functions | |
| − | local | + | ------------------------------------------------------------------------------- |
| − | + | ||
| + | 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 | end | ||
| − | + | function suite.buildInvocation(funcName, args) | |
| − | for | + | 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 | end | ||
| + | for k, v in pairs(argsClone) do | ||
| + | k = tostring(k) | ||
| + | v = tostring(v) | ||
| + | ret = ret .. '|' .. k .. '=' .. v | ||
| + | end | ||
| + | return ret .. '}}' | ||
end | 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. | |
| − | return | + | 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 | 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() | 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 | end | ||
| + | |||
| + | ------------------------------------------------------------------------------- | ||
| + | -- Test max | ||
| + | ------------------------------------------------------------------------------- | ||
function suite:test_max() | function suite:test_max() | ||
local tests = { | local tests = { | ||
| − | { | + | {9, {5, 6, 9}}, |
| − | + | {-5, {-5, -6, -9}}, | |
| − | { | ||
} | } | ||
| − | + | self:assertLuaAndInvokeEqualMany('max', tests) | |
| + | self:assertLuaEquals(nil, 'max', {}) | ||
| + | self:assertInvokeEquals('', 'max', {}) | ||
end | end | ||
| − | + | ||
| + | ------------------------------------------------------------------------------- | ||
| + | -- Test average | ||
| + | ------------------------------------------------------------------------------- | ||
| + | |||
function suite:test_average() | function suite:test_average() | ||
local tests = { | local tests = { | ||
| − | { | + | {6, {5, 6, 7}}, |
| − | { | + | {-7, {-7}}, |
| − | { | + | {10000000002, {10000000001, 10000000002, 10000000003}}, |
} | } | ||
| − | + | self:assertLuaAndInvokeEqualMany('average', tests) | |
end | end | ||
| + | ------------------------------------------------------------------------------- | ||
| + | -- Test min | ||
| + | ------------------------------------------------------------------------------- | ||
| + | |||
function suite:test_min() | function suite:test_min() | ||
local tests = { | 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 | end | ||
| − | + | ||
| + | ------------------------------------------------------------------------------- | ||
| + | -- Test order | ||
| + | ------------------------------------------------------------------------------- | ||
| + | |||
function suite:test_order() | function suite:test_order() | ||
local tests = { | 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 | end | ||
| − | + | ||
| + | ------------------------------------------------------------------------------- | ||
| + | -- Test precision | ||
| + | ------------------------------------------------------------------------------- | ||
| + | |||
function suite:test_precison() | function suite:test_precison() | ||
local tests = { | 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 | end | ||
| − | + | ||
| + | ------------------------------------------------------------------------------- | ||
| + | -- Test round | ||
| + | ------------------------------------------------------------------------------- | ||
| + | |||
function suite:test_round() | function suite:test_round() | ||
local tests = { | 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 | 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() | function suite:test_precison_format() | ||
local tests = { | local tests = { | ||
| − | {'10.00', | + | {'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 | end | ||
return suite | return suite | ||
Latest revision as of 07:55, 27 September 2020
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