Editing Module:Template test case

Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. Read the Privacy Policy to learn what information we collect about you and how we use it.

If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.

Latest revision Your text
Line 1: Line 1:
--[[
-- This module provides several methods to generate test cases.
  A module for generating test case templates.
 
  This module incorporates code from the English Wikipedia's "Testcase table"
  module,[1] written by Frietjes [2] with contributions by Mr. Stradivarius [3]
  and Jackmcbarn,[4] and the English Wikipedia's "Testcase rows" module,[5]
  written by Mr. Stradivarius.
 
  The "Testcase table" and "Testcase rows" modules are released under the
  CC BY-SA 3.0 License [6] and the GFDL.[7]


  License: CC BY-SA 3.0 and the GFDL
local mTableTools = require('Module:TableTools')
  Author: Mr. Stradivarius
local libraryUtil = require('libraryUtil')
local checkType = libraryUtil.checkType


  [1] https://en.wikipedia.org/wiki/Module:Testcase_table
local TEMPLATE_NAME_MAGIC_WORD = '<TEMPLATE_NAME>'
  [2] https://en.wikipedia.org/wiki/User:Frietjes
local TEMPLATE_NAME_MAGIC_WORD_ESCAPED = TEMPLATE_NAME_MAGIC_WORD:gsub('%p', '%%%0')
  [3] https://en.wikipedia.org/wiki/User:Mr._Stradivarius
  [4] https://en.wikipedia.org/wiki/User:Jackmcbarn
  [5] https://en.wikipedia.org/wiki/Module:Testcase_rows
  [6] https://en.wikipedia.org/wiki/Wikipedia:Text_of_Creative_Commons_Attribution-ShareAlike_3.0_Unported_License
  [7] https://en.wikipedia.org/wiki/Wikipedia:Text_of_the_GNU_Free_Documentation_License
]]
 
-- Load required modules
local yesno = require('Module:Yesno')
 
-- Set constants
local DATA_MODULE = 'Module:Template test case/data'


-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-- Shared methods
-- Helper functions
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------


local function message(self, key, ...)
--[[
-- This method is added to classes that need to deal with messages from the
local function validateTemplateOptions()
-- config module.
-- Add the template names for the first two templates if they weren't
local msg = self.cfg.msg[key]
-- specified.
if select(1, ...) then
do
return mw.message.newRawMessage(msg, ...):plain()
local title = mw.title.getCurrentTitle().basePageTitle
else
local template
return msg
if title.namespace == 10 then
end
template = title.text
end
elseif title.namespace == 0 then
 
template = ':' .. title.prefixedText
-------------------------------------------------------------------------------
else
-- Template class
template = title.prefixedText
-------------------------------------------------------------------------------
 
local Template = {}
 
Template.memoizedMethods = {
-- Names of methods to be memoized in each object. This table should only
-- hold methods with no parameters.
getFullPage = true,
getName = true,
makeHeader = true,
getOutput = true
}
 
function Template.new(invocationObj, options)
local obj = {}
 
-- Set input
for k, v in pairs(options or {}) do
if not Template[k] then
obj[k] = v
end
end
end
local templatePage = title.prefixedText
obj._invocation = invocationObj
templateOptions[1] = templateOptions[1] or {}
 
templateOptions[1].templatePage = templateOptions[1].template or templatePage
-- Validate input
templateOptions[1].template = templateOptions[1].template or template
if not obj.template and not obj.title then
templateOptions[2] = templateOptions[2] or {}
error('no template or title specified', 2)
templateOptions[2].templatePage = templateOptions[2].template or templatePage .. '/sandbox'
templateOptions[2].template = templateOptions[2].template or template .. '/sandbox'
end
end


-- Memoize expensive method calls
-- Validate options for three or more templates.
local memoFuncs = {}
if #templateOptions >= 3 then
return setmetatable(obj, {
for i = 3, #templateOptions do
__index = function (t, key)
local template = templateOptions[i].template
if Template.memoizedMethods[key] then
if not template then
local func = memoFuncs[key]
error('arguments for a third or subsequent ' ..
if not func then
'template were found, but no template name ' ..
local val = Template[key](t)
'was specified', 3)
func = function () return val end
memoFuncs[key] = func
end
return func
else
return Template[key]
end
end
end
end
})
end
function Template:getFullPage()
if not self.template then
return self.title.prefixedText
elseif self.template:sub(1, 7) == '#invoke' then
return 'Module' .. self.template:sub(8):gsub('|.*', '')
else
local strippedTemplate, hasColon = self.template:gsub('^:', '', 1)
hasColon = hasColon > 0
local ns = strippedTemplate:match('^(.-):')
ns = ns and mw.site.namespaces[ns]
if ns then
return strippedTemplate
elseif hasColon then
return strippedTemplate -- Main namespace
else
return mw.site.namespaces[10].name .. ':' .. strippedTemplate
end
end
end
function Template:getName()
if self.template then
return self.template
else
return require('Module:Template invocation').name(self.title)
end
end
end
end
--]]


function Template:makeLink(display)
local function parseTemplateOptions(origOptions)
if display then
-- Given a table of raw options, returns a table of general options
return string.format('[[:%s|%s]]', self:getFullPage(), display)
-- and template options.
else
local templateOptions = mTableTools.numData(origOptions, true)
return string.format('[[:%s]]', self:getFullPage())
local options = templateOptions.other
end
templateOptions.other = nil
end
return options, templateOptions
 
function Template:makeBraceLink(display)
display = display or self:getName()
local link = self:makeLink(display)
return mw.text.nowiki('{{') .. link .. mw.text.nowiki('}}')
end
 
function Template:makeHeader()
return self.heading or self:makeBraceLink()
end
 
function Template:getInvocation(format)
local invocation = self._invocation:getInvocation{
template = self:getName(),
requireMagicWord = self.requireMagicWord,
}
if format == 'code' then
invocation = '<code>' .. mw.text.nowiki(invocation) .. '</code>'
elseif format == 'kbd' then
invocation = '<kbd>' .. mw.text.nowiki(invocation) .. '</kbd>'
elseif format == 'plain' then
invocation = mw.text.nowiki(invocation)
else
-- Default is pre tags
invocation = mw.text.encode(invocation, '&')
invocation = '<pre style="white-space: pre-wrap;">' .. invocation .. '</pre>'
invocation = mw.getCurrentFrame():preprocess(invocation)
end
return invocation
end
 
function Template:getOutput()
local protect = require('Module:Protect')
-- calling self._invocation:getOutput{...}
return protect(self._invocation.getOutput)(self._invocation, {
template = self:getName(),
requireMagicWord = self.requireMagicWord,
})
end
end


-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-- TestCase class
-- Invocation class
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------


local TestCase = {}
local Invocation = {}
TestCase.__index = TestCase
Invocation.__index = Invocation
TestCase.message = message -- add the message method
 
TestCase.renderMethods = {
-- Keys in this table are values of the "format" option, values are the
-- method for rendering that format.
columns = 'renderColumns',
rows = 'renderRows',
tablerows = 'renderRows',
inline = 'renderInline',
cells = 'renderCells',
default = 'renderDefault'
}
 
function TestCase.new(invocationObj, options, cfg)
local obj = setmetatable({}, TestCase)
obj.cfg = cfg
 
-- Separate general options from template options. Template options are
-- numbered, whereas general options are not.
local generalOptions, templateOptions = {}, {}
for k, v in pairs(options) do
local prefix, num
if type(k) == 'string' then
prefix, num = k:match('^(.-)([1-9][0-9]*)$')
end
if prefix then
num = tonumber(num)
templateOptions[num] = templateOptions[num] or {}
templateOptions[num][prefix] = v
else
generalOptions[k] = v
end
end
 
-- Set general options
generalOptions.showcode = yesno(generalOptions.showcode)
generalOptions.showheader = yesno(generalOptions.showheader) ~= false
generalOptions.showcaption = yesno(generalOptions.showcaption) ~= false
generalOptions.collapsible = yesno(generalOptions.collapsible)
generalOptions.notcollapsed = yesno(generalOptions.notcollapsed)
generalOptions.wantdiff = yesno(generalOptions.wantdiff)
obj.options = generalOptions
 
-- Preprocess template args
for num, t in pairs(templateOptions) do
if t.showtemplate ~= nil then
t.showtemplate = yesno(t.showtemplate)
end
end
 
-- Set up first two template options tables, so that if only the
-- "template3" is specified it isn't made the first template when the
-- the table options array is compressed.
templateOptions[1] = templateOptions[1] or {}
templateOptions[2] = templateOptions[2] or {}
 
-- Allow the "template" option to override the "template1" option for
-- backwards compatibility with [[Module:Testcase table]].
if generalOptions.template then
templateOptions[1].template = generalOptions.template
end
 
-- Add default template options
if templateOptions[1].template and not templateOptions[2].template then
templateOptions[2].template = templateOptions[1].template ..
'/' .. obj.cfg.sandboxSubpage
end
if not templateOptions[1].template then
templateOptions[1].title = mw.title.getCurrentTitle().basePageTitle
end
if not templateOptions[2].template then
templateOptions[2].title = templateOptions[1].title:subPageTitle(
obj.cfg.sandboxSubpage
)
end
 
-- Remove template options for any templates where the showtemplate
-- argument is false. This prevents any output for that template.
for num, t in pairs(templateOptions) do
if t.showtemplate == false then
templateOptions[num] = nil
end
end
 
-- Check for missing template names.
for num, t in pairs(templateOptions) do
if not t.template and not t.title then
error(obj:message(
'missing-template-option-error',
num, num
), 2)
end
end
 
-- Compress templateOptions table so we can iterate over it with ipairs.
templateOptions = (function (t)
local nums = {}
for num in pairs(t) do
nums[#nums + 1] = num
end
table.sort(nums)
local ret = {}
for i, num in ipairs(nums) do
ret[i] = t[num]
end
return ret
end)(templateOptions)
 
-- Don't require the __TEMPLATENAME__ magic word for nowiki invocations if
-- there is only one template being output.
if #templateOptions <= 1 then
templateOptions[1].requireMagicWord = false
end
 
mw.logObject(templateOptions)
 
-- Make the template objects
obj.templates = {}
for i, options in ipairs(templateOptions) do
table.insert(obj.templates, Template.new(invocationObj, options))
end
 
-- Add tracking categories. At the moment we are only tracking templates
-- that use any "heading" parameters or an "output" parameter.
obj.categories = {}
for k, v in pairs(options) do
if type(k) == 'string' and k:find('heading') then
obj.categories['Test cases using heading parameters'] = true
elseif k == 'output' then
obj.categories['Test cases using output parameter'] = true
end
end


function Invocation.new()
local obj = setmetatable({}, TableInvocation)
return obj
return obj
end
end


function TestCase:getTemplateOutput(templateObj)
function Invocation:setOptions(t)
local output = templateObj:getOutput()
self._options = t
if self.options.resetRefs then
mw.getCurrentFrame():extensionTag('references')
end
return output
end
 
function TestCase:templateOutputIsEqual()
-- Returns a boolean showing whether all of the template outputs are equal.
-- The random parts of strip markers (see [[Help:Strip markers]]) are
-- removed before comparison. This means a strip marker can contain anything
-- and still be treated as equal, but it solves the problem of otherwise
-- identical wikitext not returning as exactly equal.
local function normaliseOutput(obj)
local out = obj:getOutput()
-- Remove the random parts from strip markers.
out = out:gsub('(\127\'"`UNIQ.-)%-%x+%-(QINU`"\'\127)', '%1%2')
return out
end
local firstOutput = normaliseOutput(self.templates[1])
for i = 2, #self.templates do
local output = normaliseOutput(self.templates[i])
if output ~= firstOutput then
return false
end
end
return true
end
 
function TestCase:makeCollapsible(s)
local title = self.options.title or self.templates[1]:makeHeader()
if self.options.titlecode then
title = self.templates[1]:getInvocation('kbd')
end
local isEqual = self:templateOutputIsEqual()
local root = mw.html.create('table')
if self.options.wantdiff then
root
:addClass('mw-collapsible')
if self.options.notcollapsed == false then
root
:addClass('mw-collapsed')
end
root
:css('background-color', 'transparent')
:css('width', '100%')
:css('border', 'solid silver 1px')
:tag('tr')
:tag('th')
:css('background-color', isEqual and 'yellow' or '#90a8ee')
:wikitext(title)
:done()
:done()
:tag('tr')
:tag('td')
:newline()
:wikitext(s)
:newline()
else
root
:addClass('mw-collapsible')
if self.options.notcollapsed == false then
root
:addClass('mw-collapsed')
end
if self.options.notcollapsed ~= true or false then
root
:addClass(isEqual and 'mw-collapsed' or nil)
end
root
:css('background-color', 'transparent')
:css('width', '100%')
:css('border', 'solid silver 1px')
:tag('tr')
:tag('th')
:css('background-color', isEqual and 'lightgreen' or 'yellow')
:wikitext(title)
:done()
:done()
:tag('tr')
:tag('td')
:newline()
:wikitext(s)
:newline()
end
return tostring(root)
end
 
function TestCase:renderColumns()
local root = mw.html.create()
if self.options.showcode then
root
:wikitext(self.templates[1]:getInvocation())
:newline()
end
 
local tableroot = root:tag('table')
 
if self.options.showheader then
-- Caption
if self.options.showcaption then
tableroot
:addClass(self.options.class)
:cssText(self.options.style)
:tag('caption')
:wikitext(self.options.caption or self:message('columns-header'))
end
 
-- Headers
local headerRow = tableroot:tag('tr')
if self.options.rowheader then
-- rowheader is correct here. We need to add another th cell if
-- rowheader is set further down, even if heading0 is missing.
headerRow:tag('th'):wikitext(self.options.heading0)
end
local width
if #self.templates > 0 then
width = tostring(math.floor(100 / #self.templates)) .. '%'
else
width = '100%'
end
for i, obj in ipairs(self.templates) do
headerRow
:tag('th')
:css('width', width)
:wikitext(obj:makeHeader())
end
end
 
-- Row header
local dataRow = tableroot:tag('tr'):css('vertical-align', 'top')
if self.options.rowheader then
dataRow:tag('th')
:attr('scope', 'row')
:wikitext(self.options.rowheader)
end
-- Template output
for i, obj in ipairs(self.templates) do
if self.options.output == 'nowiki+' then
dataRow:tag('td')
:newline()
:wikitext(self.options.before)
:wikitext(self:getTemplateOutput(obj))
:wikitext(self.options.after)
:wikitext('<pre style="white-space: pre-wrap;">')
:wikitext(mw.text.nowiki(self.options.before or ""))
:wikitext(mw.text.nowiki(self:getTemplateOutput(obj)))
:wikitext(mw.text.nowiki(self.options.after or ""))
:wikitext('</pre>')
elseif self.options.output == 'nowiki' then
dataRow:tag('td')
:newline()
:wikitext(mw.text.nowiki(self.options.before or ""))
:wikitext(mw.text.nowiki(self:getTemplateOutput(obj)))
:wikitext(mw.text.nowiki(self.options.after or ""))
else
dataRow:tag('td')
:newline()
:wikitext(self.options.before)
:wikitext(self:getTemplateOutput(obj))
:wikitext(self.options.after)
end
end
return tostring(root)
end
 
function TestCase:renderRows()
local root = mw.html.create()
if self.options.showcode then
root
:wikitext(self.templates[1]:getInvocation())
:newline()
end
 
local tableroot = root:tag('table')
tableroot
:addClass(self.options.class)
:cssText(self.options.style)
 
if self.options.caption then
tableroot
:tag('caption')
:wikitext(self.options.caption)
end
 
for _, obj in ipairs(self.templates) do
local dataRow = tableroot:tag('tr')
-- Header
if self.options.showheader then
if self.options.format == 'tablerows' then
dataRow:tag('th')
:attr('scope', 'row')
:css('vertical-align', 'top')
:css('text-align', 'left')
:wikitext(obj:makeHeader())
dataRow:tag('td')
:css('vertical-align', 'top')
:css('padding', '0 1em')
:wikitext('→')
else
dataRow:tag('td')
:css('text-align', 'center')
:css('font-weight', 'bold')
:wikitext(obj:makeHeader())
dataRow = tableroot:tag('tr')
end
end
-- Template output
if self.options.output == 'nowiki+' then
dataRow:tag('td')
:newline()
:wikitext(self:getTemplateOutput(obj))
:wikitext('<pre style="white-space: pre-wrap;">')
:wikitext(mw.text.nowiki(self:getTemplateOutput(obj)))
:wikitext('</pre>')
elseif self.options.output == 'nowiki' then
dataRow:tag('td')
:newline()
:wikitext(mw.text.nowiki(self:getTemplateOutput(obj)))
else
dataRow:tag('td')
:newline()
:wikitext(self:getTemplateOutput(obj))
end
end
 
return tostring(root)
end
end


function TestCase:renderInline()
function Invocation:getOptions()
local arrow = mw.language.getContentLanguage():getArrow('forwards')
return self._options
local ret = {}
for i, obj in ipairs(self.templates) do
local line = {}
line[#line + 1] = self.options.prefix or '* '
if self.options.showcode then
line[#line + 1] = obj:getInvocation('code')
line[#line + 1] = ' '
line[#line + 1] = arrow
line[#line + 1] = ' '
end
if self.options.output == 'nowiki+' then
line[#line + 1] = self:getTemplateOutput(obj)
line[#line + 1] = '<pre style="white-space: pre-wrap;">'
line[#line + 1] = mw.text.nowiki(self:getTemplateOutput(obj))
line[#line + 1] = '</pre>'
elseif self.options.output == 'nowiki' then
line[#line + 1] = mw.text.nowiki(self:getTemplateOutput(obj))
else
line[#line + 1] = self:getTemplateOutput(obj)
end
ret[#ret + 1] = table.concat(line)
end
if self.options.addline then
local line = {}
line[#line + 1] = self.options.prefix or '* '
line[#line + 1] = self.options.addline
ret[#ret + 1] = table.concat(line)
end
return table.concat(ret, '\n')
end
 
function TestCase:renderCells()
local root = mw.html.create()
local dataRow = root:tag('tr')
dataRow
:css('vertical-align', 'top')
:addClass(self.options.class)
:cssText(self.options.style)
 
-- Row header
if self.options.rowheader then
dataRow:tag('th')
:attr('scope', 'row')
:newline()
:wikitext(self.options.rowheader or self:message('row-header'))
end
-- Caption
if self.options.showcaption then
dataRow:tag('th')
:attr('scope', 'row')
:newline()
:wikitext(self.options.caption or self:message('columns-header'))
end
 
-- Show code
if self.options.showcode then
dataRow:tag('td')
:newline()
:wikitext(self:getInvocation('code'))
end
 
-- Template output
for i, obj in ipairs(self.templates) do
if self.options.output == 'nowiki+' then
dataRow:tag('td')
:newline()
:wikitext(self.options.before)
:wikitext(self:getTemplateOutput(obj))
:wikitext(self.options.after)
:wikitext('<pre style="white-space: pre-wrap;">')
:wikitext(mw.text.nowiki(self.options.before or ""))
:wikitext(mw.text.nowiki(self:getTemplateOutput(obj)))
:wikitext(mw.text.nowiki(self.options.after or ""))
:wikitext('</pre>')
elseif self.options.output == 'nowiki' then
dataRow:tag('td')
:newline()
:wikitext(mw.text.nowiki(self.options.before or ""))
:wikitext(mw.text.nowiki(self:getTemplateOutput(obj)))
:wikitext(mw.text.nowiki(self.options.after or ""))
else
dataRow:tag('td')
:newline()
:wikitext(self.options.before)
:wikitext(self:getTemplateOutput(obj))
:wikitext(self.options.after)
end
end
 
 
return tostring(root)
end
 
function TestCase:renderDefault()
local ret = {}
if self.options.showcode then
ret[#ret + 1] = self.templates[1]:getInvocation()
end
for i, obj in ipairs(self.templates) do
ret[#ret + 1] = '<div style="clear: both;"></div>'
if self.options.showheader then
ret[#ret + 1] = obj:makeHeader()
end
if self.options.output == 'nowiki+' then
ret[#ret + 1] = self:getTemplateOutput(obj) .. '<pre style="white-space: pre-wrap;">' .. mw.text.nowiki(self:getTemplateOutput(obj)) .. '</pre>'
elseif self.options.output == 'nowiki' then
ret[#ret + 1] = mw.text.nowiki(self:getTemplateOutput(obj))
else
ret[#ret + 1] = self:getTemplateOutput(obj)
end
end
return table.concat(ret, '\n\n')
end
 
function TestCase:__tostring()
local format = self.options.format
local method = format and TestCase.renderMethods[format] or 'renderDefault'
local ret = self[method](self)
if self.options.collapsible then
ret = self:makeCollapsible(ret)
end
for cat in pairs(self.categories) do
ret = ret .. string.format('[[Category:%s]]', cat)
end
return ret
end
end


Line 677: Line 82:
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------


local NowikiInvocation = {}
local NowikiInvocation = setmetatable({}, Invocation)
NowikiInvocation.__index = NowikiInvocation
NowikiInvocation.__index = NowikiInvocation
NowikiInvocation.message = message -- Add the message method


function NowikiInvocation.new(invocation, cfg)
function NowikiInvocation.new(args)
local obj = setmetatable({}, NowikiInvocation)
checkType('NowikiInvocation.new', 'args', args, 'table')
obj.cfg = cfg
local obj = Invocation.new()
invocation = mw.text.unstrip(invocation)
setmetatable(obj, NowikiInvocation)
-- Decode HTML entities for <, >, and ". This means that HTML entities in
 
-- the original code must be escaped as e.g. &amp;lt;, which is unfortunate,
obj.invocation = mw.text.unstrip(args.invocation)
-- but it is the best we can do as the distinction between <, >, " and &lt;,
args.invocation = nil
-- &gt;, &quot; is lost during the original nowiki operation.
local options = {}
invocation = invocation:gsub('&lt;', '<')
for k, v in pairs(args) do
invocation = invocation:gsub('&gt;', '>')
options[k] = v
invocation = invocation:gsub('&quot;', '"')
end
obj.invocation = invocation
obj.options = options
 
return obj
return obj
end
end


function NowikiInvocation:getInvocation(options)
function NowikiInvocation:getInvocation(template)
local template = options.template:gsub('%%', '%%%%') -- Escape "%" with "%%"
template = template:gsub('%%', '%%%%') -- Escape a % with %%
local invocation, count = self.invocation:gsub(
local invocation, count = self.invocation:gsub(
self.cfg.templateNameMagicWordPattern,
TEMPLATE_NAME_MAGIC_WORD_ESCAPED,
template
template
)
)
if options.requireMagicWord ~= false and count < 1 then
if count < 1 then
error(self:message(
error(string.format(
'nowiki-magic-word-error',
"the template invocation must include '%s' in place " ..
self.cfg.templateNameMagicWord
"of the template name",
TEMPLATE_NAME_MAGIC_WORD
))
))
end
end
Line 711: Line 117:
end
end


function NowikiInvocation:getOutput(options)
function NowikiInvocation:getOutput(template)
local invocation = self:getInvocation(options)
local invocation = self:getInvocation(template)
return mw.getCurrentFrame():preprocess(invocation)
return mw.getCurrentFrame():preprocess(invocation)
end
end
Line 722: Line 128:
local TableInvocation = {}
local TableInvocation = {}
TableInvocation.__index = TableInvocation
TableInvocation.__index = TableInvocation
TableInvocation.message = message -- Add the message method
function TableInvocation.new(invokeArgs, nowikiCode, cfg)
local obj = setmetatable({}, TableInvocation)
obj.cfg = cfg
obj.invokeArgs = invokeArgs
obj.code = nowikiCode
return obj
end
function TableInvocation:getInvocation(options)
if self.code then
local nowikiObj = NowikiInvocation.new(self.code, self.cfg)
return nowikiObj:getInvocation(options)
else
return require('Module:Template invocation').invocation(
options.template,
self.invokeArgs
)
end
end
function TableInvocation:getOutput(options)
if (options.template:sub(1, 7) == '#invoke') then
local moduleCall = mw.text.split(options.template, '|', true)
local args = mw.clone(self.invokeArgs)
table.insert(args, 1, moduleCall[2])
return mw.getCurrentFrame():callParserFunction(moduleCall[1], args)
end
return mw.getCurrentFrame():expandTemplate{
title = options.template,
args = self.invokeArgs
}
end


-------------------------------------------------------------------------------
function TableInvocation.new(args)
-- Bridge functions
checkType('TableInvocation.new', 'args', args, 'table')
--
local obj = Invocation.new()
-- These functions translate template arguments into forms that can be accepted
setmetatable(obj, TableInvocation)
-- by the different classes, and return the results.
-------------------------------------------------------------------------------


local bridge = {}
local rawOptions, invokeArgs = {}, {}
 
function bridge.table(args, cfg)
cfg = cfg or mw.loadData(DATA_MODULE)
 
local options, invokeArgs = {}, {}
for k, v in pairs(args) do
for k, v in pairs(args) do
local optionKey = type(k) == 'string' and k:match('^_(.*)$')
local optionKey = type(k) == 'string' and k:match('^_(.*)$')
if optionKey then
if optionKey then
if type(v) == 'string' then
if type(v) == 'string' then
v = v:match('^%s*(.-)%s*$') -- trim whitespace
v = mw.text.trim(v)
end
end
if v ~= '' then
if v ~= '' then
options[optionKey] = v
rawOptions[optionKey] = v
end
end
else
else
Line 783: Line 148:
end
end
end
end
obj.invokeArgs = invokeArgs
local options, templateOptions = parseTemplateOptions(rawOptions)
obj:setOptions(options)
obj:setTemplateOptions(templateOptions)


-- Allow passing a nowiki invocation as an option. While this means users
return obj
-- have to pass in the code twice, whitespace is preserved and &lt; etc.
end
-- will work as intended.
local nowikiCode = options.code
options.code = nil


local invocationObj = TableInvocation.new(invokeArgs, nowikiCode, cfg)
function TableInvocation:getInvocation(template)
local testCaseObj = TestCase.new(invocationObj, options, cfg)
return require('Module:Template invocation').invocation(
return tostring(testCaseObj)
template,
self.invokeArgs
)
end
end


function bridge.nowiki(args, cfg)
function TableInvocation:getOutput(template)
cfg = cfg or mw.loadData(DATA_MODULE)
return mw.getCurrentFrame():expandTemplate{
title = template,
args = self.invokeArgs
}
end
 
-------------------------------------------------------------------------------
-- TestCase class
-------------------------------------------------------------------------------


local code = args.code or args[1]
local TestCase = {}
local invocationObj = NowikiInvocation.new(code, cfg)
TestCase.__index = TestCase
args.code = nil
 
args[1] = nil
function TestCase.new(invocationObj)
-- Assume we want to see the code as we already passed it in.
checkType('TestCase.new', 'invocationObj', invocationObj, 'table')
args.showcode = args.showcode or true
local obj = setmetatable({}, TestCase)
local testCaseObj = TestCase.new(invocationObj, args, cfg)
return obj
return tostring(testCaseObj)
end
end
--------------------------------------------------------------------------------
-- Test case display functions
--
-- Test case display functions produce the wikitext to display the template
-- output for one test case. For example, one function might produce templates
-- aligned horizontally, and another function might produce templates aligned
-- one below the other.
--
-- They are named functions that accept the following parameters:
-- * templates - an array of subtables containing data about each template to be
--    displayed. These subtables can contain the following values:
--    * result - the expanded wikitext from the template.
--    * invocation - the original unexpanded wikitext that the output was
--        generated from. This may be nil if the invocation is not available.
--    * name - the name of the template.
--    * link - a normal wikilink to the template page (displays as
--        "Template:Foo").
--    * braceLink - a wikilink to the template page formatted like the {{tl}}
--        template, i.e. it displays as "{{Foo}}".
--    * heading - a heading to display above the template output.
--------------------------------------------------------------------------------


-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-- Exports
-- Exports
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-- Table-based exports
local function getTableArgs(frame, wrappers)
return require('Module:Arguments').getArgs(frame, {
wrappers = wrappers,
trim = false,
removeBlanks = false
})
end


local p = {}
local p = {}


function p.main(frame, cfg)
function p._table(args)
cfg = cfg or mw.loadData(DATA_MODULE)
local invocation = TableInvocation.new(args)
return invocation
end
 
function p.table(frame)
return p._table(getTableArgs(frame, 'Template:Test case from arguments'))
end
 
function p.columns(frame)
local args = getTableArgs(frame, 'Template:Testcase table')
args._format = 'columns'
return p._table(args)
end


-- Load the wrapper config, if any.
function p.rows(frame)
local wrapperConfig
local args = getTableArgs(frame, 'Template:Testcase rows')
if frame.getParent then
args._format = 'rows'
local title = frame:getParent():getTitle()
return p._table(args)
local template = title:gsub(cfg.sandboxSubpagePattern, '')
end
wrapperConfig = cfg.wrappers[template]
end


-- Work out the function we will call, use it to generate the config for
-- Nowiki-based exports
-- Module:Arguments, and use Module:Arguments to find the arguments passed
-- by the user.
local func = wrapperConfig and wrapperConfig.func or 'table'
local userArgs = require('Module:Arguments').getArgs(frame, {
parentOnly = wrapperConfig,
frameOnly = not wrapperConfig,
trim = func ~= 'table',
removeBlanks = func ~= 'table'
})


-- Get default args and build the args table. User-specified args overwrite
function p._nowiki(args)
-- default args.
local invocation = NowikiInvocation.new(args)
local defaultArgs = wrapperConfig and wrapperConfig.args or {}
return invocation
local args = {}
end
for k, v in pairs(defaultArgs) do
args[k] = v
end
for k, v in pairs(userArgs) do
args[k] = v
end


return bridge[func](args, cfg)
function p.nowiki(frame)
local args = require('Module:Arguments').getArgs(frame, {
wrappers = 'Template:Test case from invocation'
})
return p._nowiki(args)
end
end


function p._exportClasses() -- For testing
-- Exports for testing
 
function p._exportClasses()
return {
return {
Template = Template,
TestCase = TestCase,
TestCase = TestCase,
Invocation = Invocation,
NowikiInvocation = NowikiInvocation,
NowikiInvocation = NowikiInvocation,
TableInvocation = TableInvocation
TableInvocation = TableInvocation
Please note that all contributions to Nonbinary Wiki are considered to be released under the Creative Commons Attribution-ShareAlike (see Nonbinary Wiki:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!
Cancel Editing help (opens in new window)

Template used on this page: