Module:Template test case: Difference between revisions

    From Nonbinary Wiki
    (add nowiki exports and finish the NowikiInvocation class)
    (move arg-trimming code to the TableInvocation class)
    Line 138: Line 138:
    local optionKey = type(k) == 'string' and k:match('^_(.*)$')
    local optionKey = type(k) == 'string' and k:match('^_(.*)$')
    if optionKey then
    if optionKey then
    rawOptions[optionKey] = v
    if type(v) == 'string' then
    v = mw.text.trim(v)
    end
    if v ~= '' then
    rawOptions[optionKey] = v
    end
    else
    else
    invokeArgs[k] = v
    invokeArgs[k] = v
    Line 209: Line 214:
    return require('Module:Arguments').getArgs(frame, {
    return require('Module:Arguments').getArgs(frame, {
    wrappers = wrappers,
    wrappers = wrappers,
    valueFunc = function (k, v)
    trim = false,
    if type(k) == 'string' and k:find('^_') then
    removeBlanks = false
    v = mw.text.trim(v)
    if v ~= '' then
    return v
    end
    else
    return v
    end
    end
    })
    })
    end
    end
    Line 230: Line 227:


    function p.table(frame)
    function p.table(frame)
    return p._table(getTableArgs(frame, 'Template:Test case'))
    return p._table(getTableArgs(frame, 'Template:Test case from arguments'))
    end
    end


    Line 254: Line 251:
    function p.nowiki(frame)
    function p.nowiki(frame)
    local args = require('Module:Arguments').getArgs(frame, {
    local args = require('Module:Arguments').getArgs(frame, {
    wrappers = 'Template:Test case'
    wrappers = 'Template:Test case from invocation'
    })
    })
    return p._nowiki(args)
    return p._nowiki(args)

    Revision as of 10:26, 24 November 2014

    Documentation for this module may be created at Module:Template test case/doc

    -- This module provides several methods to generate test cases.
    
    local mTableTools = require('Module:TableTools')
    local libraryUtil = require('libraryUtil')
    local checkType = libraryUtil.checkType
    
    local TEMPLATE_NAME_MAGIC_WORD = '<TEMPLATE_NAME>'
    local TEMPLATE_NAME_MAGIC_WORD_ESCAPED = TEMPLATE_NAME_MAGIC_WORD:gsub('%p', '%%%0')
    
    -------------------------------------------------------------------------------
    -- Helper functions
    -------------------------------------------------------------------------------
    
    --[[
    local function validateTemplateOptions()
    	-- Add the template names for the first two templates if they weren't
    	-- specified.
    	do
    		local title = mw.title.getCurrentTitle().basePageTitle
    		local template
    		if title.namespace == 10 then
    			template = title.text
    		elseif title.namespace == 0 then
    			template = ':' .. title.prefixedText
    		else
    			template = title.prefixedText
    		end
    		local templatePage = title.prefixedText
    		templateOptions[1] = templateOptions[1] or {}
    		templateOptions[1].templatePage = templateOptions[1].template or templatePage
    		templateOptions[1].template = templateOptions[1].template or template
    		templateOptions[2] = templateOptions[2] or {}
    		templateOptions[2].templatePage = templateOptions[2].template or templatePage .. '/sandbox'
    		templateOptions[2].template = templateOptions[2].template or template .. '/sandbox'
    	end
    
    	-- Validate options for three or more templates.
    	if #templateOptions >= 3 then
    		for i = 3, #templateOptions do
    			local template = templateOptions[i].template
    			if not template then
    				error('arguments for a third or subsequent ' ..
    				'template were found, but no template name ' ..
    				'was specified', 3)
    			end
    		end
    	end
    end
    --]]
    
    local function parseTemplateOptions(origOptions)
    	-- Given a table of raw options, returns a table of general options
    	-- and template options.
    	local templateOptions = mTableTools.numData(origOptions, true)
    	local options = templateOptions.other
    	templateOptions.other = nil
    	return options, templateOptions
    end
    
    -------------------------------------------------------------------------------
    -- Invocation class
    -------------------------------------------------------------------------------
    
    local Invocation = {}
    Invocation.__index = Invocation
    
    function Invocation.new()
    	local obj = setmetatable({}, TableInvocation)
    	return obj
    end
    
    function Invocation:setOptions(t)
    	self._options = t
    end
    
    function Invocation:getOptions()
    	return self._options
    end
    
    -------------------------------------------------------------------------------
    -- Nowiki invocation class
    -------------------------------------------------------------------------------
    
    local NowikiInvocation = setmetatable({}, Invocation)
    NowikiInvocation.__index = NowikiInvocation
    
    function NowikiInvocation.new(args)
    	checkType('NowikiInvocation.new', 'args', args, 'table')
    	local obj = Invocation.new()
    	setmetatable(obj, NowikiInvocation)
    
    	obj.invocation = mw.text.unstrip(args.invocation)
    	args.invocation = nil
    	local options = {}
    	for k, v in pairs(args) do
    		options[k] = v
    	end
    	obj.options = options
    
    	return obj
    end
    
    function NowikiInvocation:getInvocation(template)
    	template = template:gsub('%%', '%%%%') -- Escape a % with %%
    	local invocation, count = self.invocation:gsub(
    		TEMPLATE_NAME_MAGIC_WORD_ESCAPED,
    		template
    	)
    	if count < 1 then
    		error(string.format(
    			"the template invocation must include '%s' in place " ..
    			"of the template name",
    			TEMPLATE_NAME_MAGIC_WORD
    		))
    	end
    	return invocation
    end
    
    function NowikiInvocation:getOutput(template)
    	local invocation = self:getInvocation(template)
    	return mw.getCurrentFrame():preprocess(invocation)
    end
    
    -------------------------------------------------------------------------------
    -- Table invocation class
    -------------------------------------------------------------------------------
    
    local TableInvocation = {}
    TableInvocation.__index = TableInvocation
    
    function TableInvocation.new(args)
    	checkType('TableInvocation.new', 'args', args, 'table')
    	local obj = Invocation.new()
    	setmetatable(obj, TableInvocation)
    
    	local rawOptions, invokeArgs = {}, {}
    	for k, v in pairs(args) do
    		local optionKey = type(k) == 'string' and k:match('^_(.*)$')
    		if optionKey then
    			if type(v) == 'string' then
    				v = mw.text.trim(v)
    			end
    			if v ~= '' then
    				rawOptions[optionKey] = v
    			end
    		else
    			invokeArgs[k] = v
    		end
    	end
    	obj.invokeArgs = invokeArgs
    	local options, templateOptions = parseTemplateOptions(rawOptions)
    	obj:setOptions(options)
    	obj:setTemplateOptions(templateOptions)
    
    	return obj
    end
    
    function TableInvocation:getInvocation(template)
    	return require('Module:Template invocation').invocation(
    		template,
    		self.invokeArgs
    	)
    end
    
    function TableInvocation:getOutput(template)
    	return mw.getCurrentFrame():expandTemplate{
    		title = template,
    		args = self.invokeArgs
    	}
    end
    
    -------------------------------------------------------------------------------
    -- TestCase class
    -------------------------------------------------------------------------------
    
    local TestCase = {}
    TestCase.__index = TestCase
    
    function TestCase.new(invocationObj)
    	checkType('TestCase.new', 'invocationObj', invocationObj, 'table')
    	local obj = setmetatable({}, TestCase)
    	return obj
    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
    -------------------------------------------------------------------------------
    
    -- Table-based exports
    
    local function getTableArgs(frame, wrappers)
    	return require('Module:Arguments').getArgs(frame, {
    		wrappers = wrappers,
    		trim = false,
    		removeBlanks = false
    	})
    end
    
    local p = {}
    
    function p._table(args)
    	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
    
    function p.rows(frame)
    	local args = getTableArgs(frame, 'Template:Testcase rows')
    	args._format = 'rows'
    	return p._table(args)
    end
    
    -- Nowiki-based exports
    
    function p._nowiki(args)
    	local invocation = NowikiInvocation.new(args)
    	return invocation
    end
    
    function p.nowiki(frame)
    	local args = require('Module:Arguments').getArgs(frame, {
    		wrappers = 'Template:Test case from invocation'
    	})
    	return p._nowiki(args)
    end
    
    -- Exports for testing
    
    function p._exportClasses()
    	return {
    		TestCase = TestCase,
    		Invocation = Invocation,
    		NowikiInvocation = NowikiInvocation,
    		TableInvocation = TableInvocation
    	}
    end
    
    return p