Module:List/testcases

-- Unit tests for Module:List. Click talk page to run tests.

local mList = require('Module:List/sandbox') local ScribuntoUnit = require('Module:ScribuntoUnit') local suite = ScribuntoUnit:new

-- Default values

local d = {}

-- Function names d.bulletedFunc = 'bulleted' d.unbulletedFunc = 'unbulleted' d.horizontalFunc = 'horizontal' d.orderedFunc = 'ordered' d.horizontalOrderedFunc = 'horizontal_ordered'

-- List items d.item1 = 'Foo' d.item2 = 'Bar' d.itemNested = '\n*Subitem 1\n*Subitem 2' -- The leading LF must not be trimmed from such item

-- Styles and classes d.arbitraryStyle = 'text-align: right' d.arbitraryValue = 'some value' d.arbitraryClass = 'someclass' d.arbitraryClass2 = 'someclass2' d.hlist = 'hlist hlist-separated' d.plainlist = 'plainlist'

-- Parameter names d.itemStyleParam1 = 'item1_style' d.itemValueParam1 = 'item1_value'

-- Attributes d.arbitraryStart = '5'

-- Tracking categories d.trackingCategory = ''

-- Helper functions

function suite:assertArrayContainsString(expected, t) -- This only works on arrays that only contain strings. local sep = '|SEPARATOR|' local concatenated = sep .. table.concat(t, sep) .. sep self:assertStringContains(sep .. expected .. sep, concatenated, true) end

-- Test makeListData

function suite:testDataBlank local data = mList.makeListData(d.bulletedFunc, {}) self:assertEquals('table', type(data)) end

function suite:testDataOneItem local data = mList.makeListData(d.bulletedFunc, {d.item1}) self:assertEquals(d.item1, data.items[1].content) end

function suite:testDataTwoItems local data = mList.makeListData(d.bulletedFunc, {d.item1, d.item2}) self:assertEquals(d.item1, data.items[1].content) self:assertEquals(d.item2, data.items[2].content) end

function suite:testDataItemStyle1 local data = mList.makeListData(d.bulletedFunc, {d.item1, [d.itemStyleParam1] = d.arbitraryStyle}) self:assertEquals(d.arbitraryStyle, data.items[1].style) end

function suite:testDataItemStyle1NoContent local data = mList.makeListData(d.bulletedFunc, {[d.itemStyleParam1] = d.arbitraryStyle}) self:assertEquals(nil, data.items[1]) end

function suite:testDataItemValue1 local data = mList.makeListData(d.bulletedFunc, {d.item1, [d.itemValueParam1] = d.arbitraryValue}) self:assertEquals(d.arbitraryValue, data.items[1].value) end

function suite:testDataItemValue1NoContent local data = mList.makeListData(d.bulletedFunc, {[d.itemValueParam1] = d.arbitraryValue}) self:assertEquals(nil, data.items[1]) end

function suite:testDataItemStyle local data = mList.makeListData(d.bulletedFunc, {item_style = d.arbitraryStyle}) self:assertEquals(d.arbitraryStyle, data.itemStyle) end

function suite:testDataListStyle local data = mList.makeListData(d.bulletedFunc, {list_style = d.arbitraryStyle}) self:assertEquals(d.arbitraryStyle, data.listStyle) end

function suite:testDataStart local data = mList.makeListData(d.bulletedFunc, {start = d.arbitraryStart}) self:assertEquals(d.arbitraryStart, data.start) end

function suite:testDataHorizontalNumberingFix local data = mList.makeListData(d.horizontalOrderedFunc, {start = '5'}) self:assertEquals('5', data.start) self:assertEquals('listitem 4', data.counterReset) end

function suite:testDataHorizontalNumberingFixBadInput local data = mList.makeListData(d.horizontalOrderedFunc, {start = 'foo'}) self:assertEquals('foo', data.start) self:assertEquals(nil, data.counterReset) end

function suite:testDataHorizontalNumberingFixNumberInput local data = mList.makeListData(d.horizontalOrderedFunc, {start = 6}) self:assertEquals(6, data.start) self:assertEquals('listitem 5', data.counterReset) end

function suite:testDataListTag self:assertEquals('ul', mList.makeListData(d.bulletedFunc, {}).listTag) self:assertEquals('ul', mList.makeListData(d.horizontalFunc, {}).listTag) self:assertEquals('ul', mList.makeListData(d.unbulletedFunc, {}).listTag) self:assertEquals('ol', mList.makeListData(d.orderedFunc, {}).listTag) self:assertEquals('ol', mList.makeListData(d.horizontalOrderedFunc, {}).listTag) end

function suite:testDataListStyleType self:assertEquals('foo', mList.makeListData(d.orderedFunc, {list_style_type = 'foo'}).listStyleType) self:assertEquals('foo', mList.makeListData(d.horizontalOrderedFunc, {list_style_type = 'foo'}).listStyleType) self:assertEquals(nil, mList.makeListData(d.bulletedFunc, {list_style_type = 'foo'}).listStyleType) end

function suite:testDataListStyleTypeAltSyntax self:assertEquals('foo', mList.makeListData(d.orderedFunc, {['list-style-type'] = 'foo'}).listStyleType) self:assertEquals('foo', mList.makeListData(d.horizontalOrderedFunc, {['list-style-type'] = 'foo'}).listStyleType) self:assertEquals(nil, mList.makeListData(d.bulletedFunc, {['list-style-type'] = 'foo'}).listStyleType) end

function suite:testDataValidType self:assertEquals('1', mList.makeListData(d.orderedFunc, {type = '1'}).type) self:assertEquals('A', mList.makeListData(d.orderedFunc, {type = 'A'}).type) self:assertEquals('a', mList.makeListData(d.orderedFunc, {type = 'a'}).type) self:assertEquals('I', mList.makeListData(d.orderedFunc, {type = 'I'}).type) self:assertEquals('i', mList.makeListData(d.orderedFunc, {type = 'i'}).type) end

function suite:testDataInvalidType local data = mList.makeListData(d.orderedFunc, {type = 'foo'}) self:assertEquals(nil, data.type) self:assertEquals('foo', data.listStyleType) end

function suite:testDataTypeByListType self:assertEquals('1', mList.makeListData(d.orderedFunc, {type = '1'}).type) self:assertEquals('1', mList.makeListData(d.horizontalOrderedFunc, {type = '1'}).type) self:assertEquals(nil, mList.makeListData(d.bulletedFunc, {type = '1'}).type) end

function suite:testDataIndent self:assertEquals('1.6em', mList.makeListData(d.horizontalFunc, {indent = 1}).marginLeft) self:assertEquals('3.2em', mList.makeListData(d.horizontalFunc, {indent = 2}).marginLeft) self:assertEquals('1.6em', mList.makeListData(d.horizontalFunc, {indent = '1'}).marginLeft) self:assertEquals(nil, mList.makeListData(d.horizontalFunc, {}).marginLeft) end

function suite:testDataIndentByListType self:assertEquals('1.6em', mList.makeListData(d.horizontalFunc, {indent = 1}).marginLeft) self:assertEquals('1.6em', mList.makeListData(d.horizontalOrderedFunc, {indent = 1}).marginLeft) self:assertEquals(nil, mList.makeListData(d.bulletedFunc, {indent = 1}).marginLeft) self:assertEquals(nil, mList.makeListData(d.unbulletedFunc, {indent = 1}).marginLeft) self:assertEquals(nil, mList.makeListData(d.orderedFunc, {indent = 1}).marginLeft) end

function suite:testDataStyle self:assertEquals(d.arbitraryStyle, mList.makeListData(d.horizontalFunc, {style = d.arbitraryStyle}).style) end

function suite:testDataClass self:assertArrayContainsString(d.arbitraryClass, mList.makeListData(d.bulletedFunc, {class = d.arbitraryClass}).classes) end

function suite:testDataListTypeClasses self:assertArrayContainsString(d.hlist, mList.makeListData(d.horizontalFunc, {}).classes) self:assertArrayContainsString(d.hlist, mList.makeListData(d.horizontalOrderedFunc, {}).classes) self:assertArrayContainsString(d.plainlist, mList.makeListData(d.unbulletedFunc, {}).classes) end

-- Test deprecated parameters

function suite:testDeprecatedItemStyle1 local data = mList.makeListData(d.bulletedFunc, {d.item1, item_style1 = d.arbitraryStyle}) self:assertEquals(d.arbitraryStyle, data.items[1].style) end

function suite:testDeprecatedItemStyle1NoContent local data = mList.makeListData(d.bulletedFunc, {item_style1 = d.arbitraryStyle}) self:assertEquals(nil, data.items[1]) end

function suite:testDeprecatedValueStyle1 local data = mList.makeListData(d.bulletedFunc, {d.item1, item_value1 = d.arbitraryStyle}) self:assertEquals(d.arbitraryStyle, data.items[1].value) end

function suite:testDeprecatedValueStyle1NoContent local data = mList.makeListData(d.bulletedFunc, {item_value1 = d.arbitraryStyle}) self:assertEquals(nil, data.items[1]) end

-- Test tracking categories

function suite:testTrackingCategoriesItem1Style local result = mList.renderTrackingCategories{item1_style = d.arbitraryStyle} self:assertEquals('', result) end

function suite:testTrackingCategoriesItemStyle1 local result = mList.renderTrackingCategories{item_style1 = d.arbitraryStyle} self:assertEquals(d.trackingCategory, result) end

function suite:testTrackingCategoriesItemStyle4 local result = mList.renderTrackingCategories{item_style4 = d.arbitraryStyle} self:assertEquals(d.trackingCategory, result) end

function suite:testTrackingCategoriesItemValue1 local result = mList.renderTrackingCategories{item_value1 = d.arbitraryValue} self:assertEquals(d.trackingCategory, result) end

-- Test renderList

function suite.makeDataWithOneItem(args) local data = {} data.classes = {} data.items = {} data.items[1] = {content = d.item1} for k, v in pairs(args or {}) do		data[k] = v	end return data end

function suite.cleanPattern(s) -- Cleans a pattern so that the magic characters %.[]*+-?^$ are interpreted literally. s = s:gsub('([%(%)%%%.%[%]%*%+%-%?%^%$])', '%%%1') return s end

function suite.makePattern(tag, attr, s1, s2) -- For making a pattern to use with assertStringContains inside a specific attribute and HTML tag. s1 = suite.cleanPattern(s1) if s2 then s2 = suite.cleanPattern(s2) end local ssep = '' if s2 then ssep = '%s*:%s*' end s2 = s2 or '' return string.format(		'&#x3c;%s[^&#x3e;]-%s="[^"&#x3e;]-%s%s%s[^"&#x3e;]-"[^&#x3e;]-&#x3e;',		tag,		attr,		s1,		ssep,		s2	) end

function suite:testRenderNoItems self:assertEquals('', mList.renderList{}) self:assertEquals('', mList.renderList{items = {}}) end

function suite:testRenderOneItem local data = self.makeDataWithOneItem self:assertStringContains('^&#x3c;div&#x3e;%s*&#x3c;ul&#x3e;%s*&#x3c;li&#x3e;%s*' .. self.cleanPattern(d.item1) .. '%s*&#x3c;/li&#x3e;%s*&#x3c;/ul&#x3e;%s*&#x3c;/div&#x3e;$', mList.renderList(data)) end

function suite:testRenderTwoItems local data = self.makeDataWithOneItem data.items[2] = {content = d.item2} self:assertStringContains('^&#x3c;div&#x3e;%s*&#x3c;ul&#x3e;%s*&#x3c;li&#x3e;%s*' .. self.cleanPattern(d.item1) .. '%s*&#x3c;/li&#x3e;%s*&#x3c;li&#x3e;%s*' .. self.cleanPattern(d.item2) .. '%s*&#x3c;/li&#x3e;%s*&#x3c;/ul&#x3e;%s*&#x3c;/div&#x3e;$', mList.renderList(data)) end

function suite:testRenderOneClass local data = self.makeDataWithOneItem data.classes[1] = d.arbitraryClass self:assertStringContains('&#x3c;div class="' .. d.arbitraryClass .. '"&#x3e;', mList.renderList(data), true) end

function suite:testRenderTwoClasses local data = self.makeDataWithOneItem data.classes[1] = d.arbitraryClass data.classes[2] = d.arbitraryClass2 local pattern = self.makePattern('div', 'class', d.arbitraryClass .. ' ' .. d.arbitraryClass2) self:assertStringContains(pattern, mList.renderList(data), false) end

function suite:testRenderMarginLeft local data = self.makeDataWithOneItem{marginLeft = '5px'} local pattern = self.makePattern('div', 'style', 'margin-left', '5px') self:assertStringContains(pattern, mList.renderList(data), false) end

function suite:testRenderStyle local data = self.makeDataWithOneItem{style = 'foo:bar'} local pattern = self.makePattern('div', 'style', 'foo:bar') self:assertStringContains(pattern, mList.renderList(data), false) end

function suite:testRenderListTag local data = self.makeDataWithOneItem{listTag = 'ol'} self:assertEquals('&#x3c;div&#x3e;&#x3c;ol&#x3e;&#x3c;li&#x3e;' .. d.item1 .. '&#x3c;/li&#x3e;&#x3c;/ol&#x3e;&#x3c;/div&#x3e;', mList.renderList(data)) end

function suite:testRenderStart local data = self.makeDataWithOneItem{start = '7'} local pattern = self.makePattern('ul', 'start', '7') self:assertStringContains(pattern, mList.renderList(data), false) end

function suite:testRenderStartNumber local data = self.makeDataWithOneItem{start = 7} local pattern = self.makePattern('ul', 'start', '7') self:assertStringContains(pattern, mList.renderList(data), false) end

function suite:testRenderType local data = self.makeDataWithOneItem{type = 'i'} local pattern = self.makePattern('ul', 'type', 'i') self:assertStringContains(pattern, mList.renderList(data), false) end

function suite:testRenderCounterReset local data = self.makeDataWithOneItem{counterReset = 'item 3'} local pattern = self.makePattern('ul', 'style', 'counter-reset', 'item 3') self:assertStringContains(pattern, mList.renderList(data), false) end

function suite:testRenderListStyleType local data = self.makeDataWithOneItem{listStyleType = 'roman'} local pattern = self.makePattern('ul', 'style', 'list-style-type', 'roman') self:assertStringContains(pattern, mList.renderList(data), false) end

function suite:testRenderListStyle local data = self.makeDataWithOneItem{listStyle = 'bar:baz'} local pattern = self.makePattern('ul', 'style', 'bar:baz') self:assertStringContains(pattern, mList.renderList(data), false) end

function suite:testRenderItemStyle local data = self.makeDataWithOneItem{itemStyle = 'qux:foo'} local pattern = self.makePattern('li', 'style', 'qux:foo') self:assertStringContains(pattern, mList.renderList(data), false) end

function suite:testRenderItemStyleTwoItems local data = self.makeDataWithOneItem{itemStyle = 'bar:foo'} data.items[2] = {content = d.item2} local tagPattern = self.makePattern('li', 'style', 'bar:foo') local pattern = tagPattern .. d.item1 .. '&#x3c;/li&#x3e;' .. tagPattern .. d.item2 self:assertStringContains(pattern, mList.renderList(data), false) end

function suite:testRenderItem1Style local data = self.makeDataWithOneItem data.items[1].style = 'baz:foo' local pattern = self.makePattern('li', 'style', 'baz:foo') self:assertStringContains(pattern, mList.renderList(data), false) end

function suite:testRenderItem1Value local data = self.makeDataWithOneItem data.items[1].value = d.arbitraryValue local pattern = self.makePattern('li', 'value', d.arbitraryValue) self:assertStringContains(pattern, mList.renderList(data), false) end

-- Whole-module tests

function suite:testBulleted local actual = mList[d.bulletedFunc]{d.item1} local pattern = '^&#x3c;div&#x3e;%s*&#x3c;ul&#x3e;%s*&#x3c;li&#x3e;%s*' .. self.cleanPattern(d.item1) .. '%s*&#x3c;/li&#x3e;%s*&#x3c;/ul&#x3e;%s*&#x3c;/div&#x3e;$' self:assertStringContains(pattern, actual, false) end

function suite:testUnbulleted local actual = mList[d.unbulletedFunc]{d.item1} local pattern = '^' .. self.makePattern('div', 'class', 'plainlist') .. '%s*&#x3c;ul&#x3e;%s*&#x3c;li&#x3e;%s*' .. self.cleanPattern(d.item1) .. '%s*&#x3c;/li&#x3e;%s*&#x3c;/ul&#x3e;%s*&#x3c;/div&#x3e;$' self:assertStringContains(pattern, actual, false) end

function suite:testHorizontal local actual = mList[d.horizontalFunc]{d.item1} local pattern = '^' .. self.makePattern('div', 'class', 'hlist') .. '%s*&#x3c;ul&#x3e;%s*&#x3c;li&#x3e;%s*' .. self.cleanPattern(d.item1) .. '%s*&#x3c;/li&#x3e;%s*&#x3c;/ul&#x3e;%s*&#x3c;/div&#x3e;$' self:assertStringContains(pattern, actual, false) end

function suite:testOrdered local actual = mList[d.orderedFunc]{d.item1} local pattern = '^&#x3c;div&#x3e;%s*&#x3c;ol&#x3e;%s*&#x3c;li&#x3e;%s*' .. self.cleanPattern(d.item1) .. '%s*&#x3c;/li&#x3e;%s*&#x3c;/ol&#x3e;%s*&#x3c;/div&#x3e;$' self:assertStringContains(pattern, actual, false) end

function suite:testHorizontalOrdered local actual = mList[d.horizontalOrderedFunc]{d.item1} local pattern = '^' .. self.makePattern('div', 'class', 'hlist') .. '%s*&#x3c;ol&#x3e;%s*&#x3c;li&#x3e;%s*' .. self.cleanPattern(d.item1) .. '%s*&#x3c;/li&#x3e;%s*&#x3c;/ol&#x3e;%s*&#x3c;/div&#x3e;$' self:assertStringContains(pattern, actual, false) end

function suite:testTrimming local actual = mList[d.orderedFunc]{'\n Foo \n'} -- Now many templates expect the arguments to be trimmed local pattern = '^&#x3c;div&#x3e;%s*&#x3c;ol&#x3e;%s*&#x3c;li&#x3e;' .. self.cleanPattern('Foo') .. '&#x3c;/li&#x3e;%s*&#x3c;/ol&#x3e;%s*&#x3c;/div&#x3e;$' self:assertStringContains(pattern, actual, false) end

function suite:testNested local actual = mList[d.orderedFunc]{d.itemNested} local pattern = '^&#x3c;div&#x3e;%s*&#x3c;ol&#x3e;%s*&#x3c;li&#x3e;%s*' .. self.cleanPattern(d.itemNested) .. '%s*&#x3c;/li&#x3e;%s*&#x3c;/ol&#x3e;%s*&#x3c;/div&#x3e;$' self:assertStringContains(pattern, actual, false) end

return suite