Content deleted Content added
nowiki the patterns as well, and also nowiki the match in assertNotStringContains |
use require('strict') instead of require('Module:No globals') |
||
(6 intermediate revisions by 2 users not shown) | |||
Line 2:
-- Unit tests for Scribunto.
-------------------------------------------------------------------------------
require('strict')
local DebugHelper = {}
local ScribuntoUnit = {}
-- The cfg table contains all localisable strings and configuration, to make it
-- easier to port this module to another wiki.
local cfg = mw.loadData('Module:ScribuntoUnit/config')
-------------------------------------------------------------------------------
-- Concatenates keys and values, ideal for displaying a template or parser function argument table.
-- @param keySeparator glue between key and value (defaults to " = ")
-- @param separator glue between different key-value pairs (defaults to ", ")
Line 42 ⟶ 48:
local type1 = type(t1)
local type2 = type(t2)
if type1 ~= type2 then
return false
Line 49 ⟶ 55:
return t1 == t2
end
local metatable = getmetatable(t1)
if not ignoreMetatable and metatable and metatable.__eq then
return t1 == t2
end
for k1, v1 in pairs(t1) do
local v2 = t2[k1]
Line 66 ⟶ 72:
end
end
return true
end
Line 81 ⟶ 87:
level = (level or 1) + 1
details.trace = debug.traceback('', level)
details.source =
-- setmetatable(details, {
-- __tostring: function() return details.text end
-- })
error(details, level)
end
Line 94 ⟶ 98:
-------------------------------------------------------------------------------
-- when used in a test, that test gets ignored, and the skipped count increases by one.
--
function ScribuntoUnit:markTestSkipped()
DebugHelper.raise({ScribuntoUnit = true, skipped = true}, 3)
Line 140 ⟶ 144:
end
if not mw.ustring.find(s, pattern, nil, plain) then
DebugHelper.raise({
ScribuntoUnit = true,
text = mw.ustring.format('Failed to find %s "%s" in string "%s"', plain and "plain string" or "pattern",
message = message
}, 2)
Line 179 ⟶ 175:
if i then
local match = mw.ustring.sub(s, i, j)
DebugHelper.raise({
ScribuntoUnit = true,
text = mw.ustring.format('Found match "%s" for %s "%s"',
message = message
}, 2)
Line 199 ⟶ 187:
-- @param message optional description of the test
-- @example assertEquals(4, add(2,2), "2+2 should be 4")
--
function ScribuntoUnit:assertEquals(expected, actual, message)
Line 259 ⟶ 247:
function ScribuntoUnit:assertDeepEquals(expected, actual, message)
if not DebugHelper.deepCompare(expected, actual) then
if type(expected) == 'table' then
expected = mw.dumpObject(expected)
end
if type(actual) == 'table' then
actual = mw.dumpObject(actual)
end
DebugHelper.raise({
ScribuntoUnit = true,
Line 304 ⟶ 298:
expected = processed2,
expectedRaw = text2,
message = message,
}, 2)
end
end
-------------------------------------------------------------------------------
-- Checks that a parser function gives the expected output.
-- @param message optional description of the test
-- @example assertParserFunctionEquals("Hello world", "msg:concat", {"Hello", " world"})
function ScribuntoUnit:assertParserFunctionEquals(expected, pfname, args, message)
local frame = self.frame
local actual = frame:callParserFunction{ name = pfname, args = args}
if expected ~= actual then
DebugHelper.raise({
ScribuntoUnit = true,
text = string.format("Failed to assert that %s with args %s equals expected %s after preprocessing",
DebugHelper.concatWithKeys(args), pfname, expected),
actual = actual,
actualRaw = pfname,
expected = expected,
message = message,
}, 2)
Line 312 ⟶ 326:
-- Checks that a template gives the expected output.
-- @param message optional description of the test
-- @example assertTemplateEquals("Hello world", "concat", {"Hello", " world"})
function ScribuntoUnit:assertTemplateEquals(expected, template, args, message)
local frame = self.frame
local actual = frame:expandTemplate
if expected ~= actual then
DebugHelper.raise({
Line 325 ⟶ 339:
expected = expected,
message = message,
}, 2)
end
end
-------------------------------------------------------------------------------
-- Checks whether a function throws an error
-- @param fn the function to test
-- @param expectedMessage optional the expected error message
-- @param message optional description of the test
function ScribuntoUnit:assertThrows(fn, expectedMessage, message)
local succeeded, actualMessage = pcall(fn)
if succeeded then
DebugHelper.raise({
ScribuntoUnit = true,
text = 'Expected exception but none was thrown',
message = message,
}, 2)
end
-- For strings, strip the line number added to the error message
actualMessage = type(actualMessage) == 'string'
and string.match(actualMessage, 'Module:[^:]*:[0-9]*: (.*)')
or actualMessage
local messagesMatch = DebugHelper.deepCompare(expectedMessage, actualMessage)
if expectedMessage and not messagesMatch then
DebugHelper.raise({
ScribuntoUnit = true,
expected = expectedMessage,
actual = actualMessage,
text = string.format('Expected exception with message %s, but got message %s',
tostring(expectedMessage), tostring(actualMessage)
),
message = message
}, 2)
end
Line 335 ⟶ 381:
function ScribuntoUnit:new(o)
o = o or {}
o.run = function(frame) return self:run(o, frame) end
return o
Line 345 ⟶ 390:
--
function ScribuntoUnit:init(frame)
self.frame = frame or mw.getCurrentFrame()
self.successCount = 0
self.failureCount = 0
Line 358 ⟶ 403:
--
function ScribuntoUnit:runTest(suite, name, test)
local success, details = pcall(test, suite)
if success then
Line 376 ⟶ 421:
end
message = message .. details.text
table.insert(self.results, {name = name, error = true, message = message, expected = details.expected, actual = details.actual, testname = details.message})
end
end
Line 382 ⟶ 427:
-------------------------------------------------------------------------------
-- Runs all tests and displays the results.
--
function ScribuntoUnit:runSuite(suite, frame)
self:init(frame)
local names = {}
for name in pairs(suite) do
if name:find('^test') then
table.insert(names, name)
end
end
table.sort(names) -- Put tests in alphabetical order.
for i, name in ipairs(names) do
local func = suite[name]
self:runTest(suite, name, func)
end
return {
successCount = self.successCount,
Line 402 ⟶ 453:
-- Can be called without a frame, in which case it will use mw.log for output
-- @param displayMode see displayResults()
--
function ScribuntoUnit:run(suite, frame)
local testData = self:runSuite(suite, frame)
if frame and frame.args then
return self:displayResults(testData, frame.args.displayMode or 'table')
else
Line 443 ⟶ 493:
end
end
function ScribuntoUnit:displayResultsAsShort(testData)
local text = string.format(
if testData.failureCount > 0 then
text = '<span class="error">' .. text .. '</span>'
Line 455 ⟶ 503:
function ScribuntoUnit:displayResultsAsTable(testData)
local successIcon, failIcon = self.frame:preprocess(
local text = '
if testData.failureCount > 0 then
local msg = mw.message.newRawMessage(cfg.failureSummary, testData.failureCount):plain()
msg = self.frame:preprocess(msg)
if cfg.failureCategory then
msg = cfg.failureCategory .. msg
end
text = text .. failIcon .. ' ' .. msg .. '\n'
else
text = text .. successIcon .. ' ' .. cfg.successSummary .. '\n'
end
text = text .. '{| class="wikitable scribunto-test-table"\n'
text = text .. '!\n! ' .. cfg.nameString .. '\n! ' .. cfg.expectedString .. '\n! ' .. cfg.actualString .. '\n'
for _, result in ipairs(testData.results) do
text = text .. '|-\n'
if result.error then
text = text .. '| ' .. failIcon .. '
if (result.expected and result.actual) then
local
if result.testname then
name = name .. ' / ' .. result.testname
end
text = text .. name .. '\n| ' .. mw.text.nowiki(tostring(result.expected)) .. '\n| ' .. mw.text.nowiki(tostring(result.actual)) .. '\n'
else
text = text .. result.name .. '\n| ' .. ' colspan="2" | ' .. mw.text.nowiki(result.message) .. '\n'
end
else
text = text .. '| ' .. successIcon .. '
end
end
|