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  
return obj
end  
function TestCase:getTemplateOutput(templateObj)
local output = templateObj:getOutput
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 ) 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[^\127]*UNIQ%-%-%l+%-)%x+(%-%-?QINU[^\127]*\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('div')
root
:addClass('mw-collapsible')
:css('width', '100%')
:css('', 'solid silver ')
:css('padding', '0.2em')
:addClass(self.options.notcollapsed == false and 'mw-collapsed' or nil)
if self.options.wantdiff then
root
:tag('div')
:css('background-color', isEqual and 'yellow' or '#90a8ee')
:css('font-weight', 'bold')
:css('padding', '0.2em')
:wikitext(title)
:done
else
if self.options.notcollapsed ~= true or false then
root
:addClass(isEqual and 'mw-collapsed' or nil)
end
root
:tag('div')
:css('background-color', isEqual and 'lightgreen' or 'yellow')
:css('font-weight', 'bold')
:css('padding', '0.2em')
:wikitext(title)
:done
end
root
:tag('div')
:addClass('mw-collapsible-content')
:newline
:wikitext(s)
:newline
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
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>')
: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', '')
:wikitext(obj:makeHeader)
dataRow:tag('td')
:css('vertical-align', 'top')
:css('padding', '0 1em')
:wikitext('→')
else
dataRow:tag('td')
:css('text-align', '')
: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>')
: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  
function TestCase:renderInline
local arrow = mw.language.getContentLanguage:getArrow('forwards')
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>'
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>')
: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))