Module:Protection banner/testcases explained

-- Load necessary moduleslocal mProtectionBanner = require('Module:Protection banner/sandbox')local ScribuntoUnit = require('Module:ScribuntoUnit')

-- Get the classeslocal Protection = mProtectionBanner._exportClasses.Protectionlocal Blurb = mProtectionBanner._exportClasses.Blurblocal BannerTemplate = mProtectionBanner._exportClasses.BannerTemplatelocal Banner = mProtectionBanner._exportClasses.Bannerlocal Padlock = mProtectionBanner._exportClasses.Padlock

-- Initialise test suitelocal suite = ScribuntoUnit:new

---------------------------------------------------------------------------------- Default values--------------------------------------------------------------------------------

local d = d.reason = 'vandalism'd.action = 'edit'd.level = 'sysop'd.page = 'User:Example'd.talkPage = 'User talk:Example'd.baseText = 'Example'd.namespace = 2 -- Namespace of d.paged.namespaceFragment = 'user' -- namespace fragment of d.page for makeProtectionCategoryd.categoryNamespaceKeys = -- namespace key config tabled.expiry = '1 January 9999'd.expiryU = 253370764800 -- d.expiry in Unix timed.expiryFragment = 'temp' -- expiry fragment of d.expiry for makeProtectionCategoryd.protectionDate = '1 January 2000'd.protectionDateU = 946684800 -- d.protectionDate in Unix time

---------------------------------------------------------------------------------- Helper functions--------------------------------------------------------------------------------

function suite:assertError(func, args, msg) args = args or local success, result = pcall(func, unpack(args)) self:assertFalse(success) if msg then self:assertStringContains(msg, result, true) -- does a plain match endend

function suite:assertNotError(func, args) args = args or local success, result = pcall(func, unpack(args)) self:assertTrue(success)end

local function makeTitleObject(options) local title = mw.title.new(options.page)

-- Set protection levels local levels = for _, action in ipairs do local level = options[action] if level then levels[action][1] = level end end rawset(title, 'protectionLevels', levels)

-- Set content model rawset(title, 'contentModel', options.contentModel or 'wikitext')

return titleend

local function makeDefaultTitleObject return makeTitleObjectend

-- Make an alias, to be clear the object is for a protected page.local makeProtectedTitleObject = makeDefaultTitleObject

local function makeConfig(t) local cfg = local protLevelFields = for _, field in ipairs(protLevelFields) do cfg[field] = end

-- Add fields that cause errors if not present cfg.masterBanner.text = 'reason text'

-- Add custom fields for k, v in pairs(t or) do cfg[k] = v end return cfgend

local function makeDefaultProtectionObject(cfg) cfg = makeConfig(cfg) if next(cfg.categoryNamespaceKeys)

nil then -- cfg.categoryNamespaceKeys is empty cfg.categoryNamespaceKeys = d.categoryNamespaceKeys end local obj = Protection.new(cfg, makeDefaultTitleObject ) obj.expiry = d.expiryU -- Hack to override return objend

local function makeProtectionCategoryKey(testFragments, defaults) local fragments = for i, t in ipairs do for k, v in pairs(t) do fragments[k] = v end end local key = return table.concat(key, '|')end

local function makeDefaultProtectionCategoryKey(testFragments) local defaults = return makeProtectionCategoryKey(testFragments, defaults)end

local function makeDefaultBlurbObject(cfg) cfg = makeConfig(cfg) return Blurb.new(makeDefaultProtectionObject, , cfg )end

local function makeDefaultBannerTemplateObject(cfg) cfg = makeConfig(cfg) return BannerTemplate.new(makeDefaultProtectionObject, cfg )end

local function makeDefaultBannerObject(cfg) cfg = makeConfig(cfg) return Banner.new(makeDefaultProtectionObject, makeDefaultBlurbObject, cfg )end

local function makeDefaultPadlockObject(cfg) cfg = makeConfig(cfg) return Padlock.new(makeDefaultProtectionObject, makeDefaultBlurbObject, cfg )end

local padlockPattern = '\127[^\127]*UNIQ%-%-indicator%-%x+%-QINU[^\127]*\127'

function suite:assertIsPadlock(s, msg) self:assertStringContains(padlockPattern, s, false, msg )end

function suite:assertNoPadlock(s, msg) self:assertNotStringContains(padlockPattern, s, false, msg )end

function suite:assertIsBanner(s, msg) self:assertStringContains('class="[^"]*mbox[^"]*"', s, false, msg ) self:assertStringContains('role="presentation"', s, true, msg ) self:assertNotStringContains('id="protected-icon"', s, true, msg ) self:assertNotStringContains('topicon', s, true, msg )end

function suite:assertNoBanner(s, msg) self:assertNotStringContains('class="[^"]*mbox[^"]*"', s, false, msg ) self:assertNotStringContains('role="presentation"', s, true, msg ) self:assertNotStringContains('id="protected-icon"', s, true, msg ) self:assertNotStringContains('topicon', s, true, msg )end

---------------------------------------------------------------------------------- Protection object tests--------------------------------------------------------------------------------

-- Protection action

function suite:testProtectionActionError suite:assertError(Protection.new, , 'invalid action: foo' )end

function suite:testProtectionActionEdit local obj = Protection.new(makeConfig) suite:assertEquals('edit', obj.action)end

function suite:testProtectionActionMove local obj = Protection.new(makeConfig) suite:assertEquals('move', obj.action)end

function suite:testProtectionActionAutoreview local obj = Protection.new(makeConfig) suite:assertEquals('autoreview', obj.action)end

function suite:testProtectionActionUpload local obj = Protection.new(makeConfig) suite:assertEquals('upload', obj.action)end

function suite:testProtectionNoAction local obj = Protection.new(makeConfig) suite:assertEquals('edit', obj.action)end

-- Protection level

function suite:testProtectionSemi local obj = Protection.new(makeConfig, makeTitleObject ) self:assertEquals('autoconfirmed', obj.level)end

function suite:testProtectionFull local obj = Protection.new(makeConfig, makeTitleObject ) self:assertEquals('sysop', obj.level)end

function suite:testProtectionUnprotected local obj = Protection.new(makeConfig, makeTitleObject ) self:assertEquals('*', obj.level)end

function suite:testProtectionSemiMove local obj = Protection.new(makeConfig, makeTitleObject ) self:assertEquals('*', obj.level)end

function suite:testProtectionTemplate local obj = Protection.new(makeConfig, makeTitleObject ) self:assertEquals('templateeditor', obj.level)end

function suite:testProtectionTitleBlacklist local obj = Protection.new(makeConfig, makeTitleObject ) self:assertEquals('templateeditor', obj.level)end

-- Reason

function suite:testProtectionReason local obj = Protection.new(makeConfig ) self:assertEquals('foo', obj.reason)end

function suite:testProtectionReasonLowerCase local obj = Protection.new(makeConfig ) self:assertEquals('foo', obj.reason)end

function suite:testProtectionBadReason self:assertError(Protection.new, , 'reasons cannot contain the pipe character ("|")' )end

function suite:testProtectionNoReason local obj = Protection.new(makeConfig ) self:assertEquals(nil, obj.reason)end

-- Protection date

function suite:testProtectionProtectionDateIndef self:assertError(Protection.new, , 'invalid protection date: indefinite' )end

function suite:testProtectionProtectionDateTemp local obj = Protection.new(makeConfig ) self:assertEquals(d.protectionDateU, obj.protectionDate)end

function suite:testProtectionNoProtectionDate local obj = Protection.new(makeConfig ) self:assertEquals(nil, obj.protectionDate)end

function suite:testProtectionBadProtectionDate self:assertError(Protection.new, , 'invalid protection date: foobar' )end

-- bannerConfig

function suite:testProtectionMasterBannerConfigPrecedence1 local masterBanner = local obj = makeDefaultProtectionObject self:assertEquals('master banner text', obj.bannerConfig.text)end

function suite:testProtectionMasterBannerConfigPrecedence2 local masterBanner = local defaultBanners = local obj = makeDefaultProtectionObject(makeConfig) self:assertEquals('defaultBanners default text', obj.bannerConfig.text)end

function suite:testProtectionMasterBannerConfigPrecedence3 local defaultBanners = local obj = makeDefaultProtectionObject(makeConfig) self:assertEquals('defaultBanners level text', obj.bannerConfig.text)end

function suite:testProtectionMasterBannerConfigPrecedence4 local defaultBanners = local banners = local obj = makeDefaultProtectionObject(makeConfig) self:assertEquals('banners text', obj.bannerConfig.text)end

function suite:testProtectionMasterBannerConfigFields local masterBanner = local obj = makeDefaultProtectionObject self:assertEquals('master banner text', obj.bannerConfig.text) self:assertEquals('master banner explanation', obj.bannerConfig.explanation) self:assertEquals('master banner tooltip', obj.bannerConfig.tooltip) self:assertEquals('master banner alt', obj.bannerConfig.alt) self:assertEquals('master banner link', obj.bannerConfig.link) self:assertEquals('master banner image', obj.bannerConfig.image)end

-- isUserScript

function suite:testProtectionIsUserScriptWithUserCSS local protection = Protection.new(makeConfig, mw.title.new('User:Example/common.css') ) self:assertTrue(protection:isUserScript)end

function suite:testProtectionIsUserScriptWithUserJS local protection = Protection.new(makeConfig, mw.title.new('User:Example/common.js') ) self:assertTrue(protection:isUserScript)end

function suite:testProtectionIsUserScriptWithUserPage local protection = Protection.new(makeConfig, mw.title.new('User:Example') ) self:assertFalse(protection:isUserScript)end

function suite:testProtectionIsUserScriptWithNormalSubpage local protection = Protection.new(makeConfig, mw.title.new('User:Example/common') ) self:assertFalse(protection:isUserScript)end

function suite:testProtectionIsUserScriptWithUsernameEndingInCSS local protection = Protection.new(makeConfig, mw.title.new('User:My username ends in .css') ) self:assertFalse(protection:isUserScript)end

function suite:testProtectionIsUserScriptWithUsernameEndingInJS self:assertFalse(Protection.new(makeConfig, mw.title.new('User:My username ends in .js') ):isUserScript )end

function suite:testProtectionIsUserScriptWithSubpageContainingCSS self:assertFalse(Protection.new(makeConfig, mw.title.new('User:Example/common.css.txt') ):isUserScript )end

function suite:testProtectionIsUserScriptWithNoSubpagePrefix self:assertTrue(Protection.new(makeConfig, mw.title.new('User:Example/.css') ):isUserScript )end

function suite:testProtectionIsUserScriptWithBlankUsernameAndNoSubpagePrefix self:assertTrue(Protection.new(makeConfig, mw.title.new('User:/.css') ):isUserScript )end

function suite:testProtectionIsUserScriptWhenUsernameIsOnlyCSS self:assertFalse(Protection.new(makeConfig, mw.title.new('User:.css') ):isUserScript )end

function suite:testProtectionIsUserScriptWithNonstandardCSSContentModel self:assertTrue(Protection.new(makeConfig, makeTitleObject ):isUserScript )end

function suite:testProtectionIsUserScriptWithNonstandardJSContentModel self:assertTrue(Protection.new(makeConfig, makeTitleObject ):isUserScript )end

function suite:testProtectionIsUserScriptWithNonstandardWikitextContentModel self:assertFalse(Protection.new(makeConfig, makeTitleObject ):isUserScript )end

function suite:testProtectionIsUserScriptWithNonUserspacePage self:assertFalse(Protection.new(makeConfig, makeTitleObject ):isUserScript )end

-- isProtected

function suite:testProtectionIsProtectedTrue local obj = makeDefaultProtectionObject obj.level = 'autoconfirmed' self:assertTrue(obj:isProtected)end

function suite:testProtectionIsProtectedFalse local obj = makeDefaultProtectionObject obj.level = '*' self:assertFalse(obj:isProtected)end

-- shouldShowLock

function suite:testProtectionShouldShowLockWithProtectedPage local obj = Protection.new(makeConfig, makeTitleObject ) self:assertTrue(obj:shouldShowLock)end

function suite:testProtectionShouldShowLockWithProtectedUserScript local obj = Protection.new(makeConfig, makeTitleObject ) self:assertFalse(obj:shouldShowLock)end

function suite:testProtectionShouldShowLockWithUnprotectedPage local obj = Protection.new(makeConfig, makeTitleObject ) self:assertFalse(obj:shouldShowLock)end

-- shouldHaveProtectionCategory

function suite:testProtectionShouldHaveProtectionCategoryWithProtectedPage local obj = Protection.new(makeConfig, makeTitleObject ) self:assertTrue(obj:shouldHaveProtectionCategory)end

function suite:testProtectionShouldHaveProtectionCategoryWithProtectedUserScript local obj = Protection.new(makeConfig, makeTitleObject ) self:assertFalse(obj:shouldHaveProtectionCategory)end

function suite:testProtectionShouldHaveProtectionCategoryWithUnprotectedPage local obj = Protection.new(makeConfig, makeTitleObject ) self:assertFalse(obj:shouldHaveProtectionCategory)end

-- isTemporary

function suite:testProtectionIsProtectedTrue local obj = makeDefaultProtectionObject obj.expiry = 123456789012 self:assertTrue(obj:isTemporary)end

function suite:testProtectionIsProtectedFalse1 local obj = makeDefaultProtectionObject obj.expiry = 'indef' self:assertFalse(obj:isTemporary)end

function suite:testProtectionIsProtectedFalse2 local obj = makeDefaultProtectionObject obj.expiry = nil self:assertFalse(obj:isTemporary)end

-- makeProtectionCategory--function suite:testProtectionCategoryWithUnprotectedPage local obj = Protection.new(makeConfig, makeTitleObject ) self:assertEquals(obj:makeProtectionCategory, )end

function suite:testProtectionCategoryPrecedence1 -- Test that expiry has the lowest priority. local protectionCategories = local obj = makeDefaultProtectionObject self:assertStringContains('all expiries allowed', obj:makeProtectionCategory, true )end

function suite:testProtectionCategoryPrecedence2 -- Test that reason has the highest priority. local protectionCategories = local obj = makeDefaultProtectionObject self:assertStringContains('reason only', obj:makeProtectionCategory, true )end

function suite:testProtectionCategoryPrecedence3 -- Test that namespace has the highest priority if the reason is set in -- cfg.reasonsWithNamespacePriority. local protectionCategories = local obj = makeDefaultProtectionObject self:assertStringContains('namespace only', obj:makeProtectionCategory, true )end

function suite:testProtectionCategoryPrecedence4 -- Test that level has a higher priority than namespace. local protectionCategories = local obj = makeDefaultProtectionObject self:assertStringContains('all namespaces allowed', obj:makeProtectionCategory, true )end

function suite:testProtectionCategoryPrecedence5 -- Test that action has a higher priority than level. local protectionCategories = local obj = makeDefaultProtectionObject self:assertStringContains('all levels allowed', obj:makeProtectionCategory, true )end

function suite:testProtectionCategoryPrecedence6 -- Test that an exact match will be first. local protectionCategories = local obj = makeDefaultProtectionObject self:assertStringContains('exact match', obj:makeProtectionCategory, true )end

function suite:testProtectionCategoryPrecedence7 -- Test that matching 4 keys will come before matching 3 keys local protectionCategories = local obj = makeDefaultProtectionObject self:assertStringContains('four keys', obj:makeProtectionCategory, true )end

function suite:testProtectionCategoryPrecedence8 -- Test that matching 3 keys will come before matching 2 keys local protectionCategories = local obj = makeDefaultProtectionObject self:assertStringContains('three keys', obj:makeProtectionCategory, true )end

function suite:testProtectionCategoryPrecedence9 -- Test that matching 2 keys will come before matching 1 key local protectionCategories = local obj = makeDefaultProtectionObject self:assertStringContains('two keys', obj:makeProtectionCategory, true )end

function suite:testProtectionCategoryPrecedence10 -- Test that matching 1 keys will come before matching 0 keys local protectionCategories = local obj = makeDefaultProtectionObject self:assertStringContains('one key', obj:makeProtectionCategory, true )end

function suite:testProtectionCategoryAllAlls -- Test that 'all|all|all|all|all' works local protectionCategories = local obj = makeDefaultProtectionObject self:assertStringContains('no keys', obj:makeProtectionCategory, true )end

function suite:testProtectionCategoryNoFalseMatches -- Test that we don't match things that we aren't supposed to. local protectionCategories = local obj = makeDefaultProtectionObject self:assertStringContains('no keys', obj:makeProtectionCategory, true )end

function suite:testProtectionCategoryProtected -- Test that protected pages produce some kind of category link. local protectionCategories = local obj = makeDefaultProtectionObject self:assertStringContains('^%[%[Category:.*%]%]$', obj:makeProtectionCategory )end

function suite:testProtectionCategoryNotProtected -- Test that unprotected pages produce the blank string. local protectionCategories = local obj = Protection.new(makeConfig, makeTitleObject ) self:assertEquals(, obj:makeProtectionCategory)end

function suite:testProtectionCategoryNoMatch -- Test that protected pages that don't match any categories -- produce the blank string. local obj = makeDefaultProtectionObject self:assertEquals(, obj:makeProtectionCategory)end

function suite:testProtectionCategoryExpiryIndef -- Test that indefinite protection matches the "indef" expiry fragment. local obj = makeDefaultProtectionObject obj._cfg.protectionCategories = obj.action = 'autoreview' obj.level = 'autoconfirmed' obj.expiry = 'indef' self:assertStringContains('indef expiry', obj:makeProtectionCategory, true)end

function suite:testProtectionCategoryExpiryTemp -- Test that temporary protection matches the "temp" expiry fragment. local obj = makeDefaultProtectionObject obj._cfg.protectionCategories = obj.action = 'autoreview' obj.level = 'autoconfirmed' obj.expiry = d.expiryU self:assertStringContains('temporary expiry', obj:makeProtectionCategory, true)end

function suite:testProtectionCategoryNoExpiry -- Test that pages with no expiry set don't match "indef" or "temp". local protectionCategories = local obj = Protection.new(makeConfig, makeProtectedTitleObject ) self:assertStringContains('no matches', obj:makeProtectionCategory, true)end

function suite:testProtectionCategoryNamespaceFragment -- Test that values in cfg.categoryNamespaceKeys will work. local protectionCategories = local obj = Protection.new(makeConfig, makeTitleObject ) self:assertStringContains('we found a match', obj:makeProtectionCategory, true)end

function suite:testProtectionCategoryTalk -- Test that talk pages match the "talk" namespace fragment. local protectionCategories = local obj = Protection.new(makeConfig, makeTitleObject ) self:assertStringContains('talk namespace', obj:makeProtectionCategory, true)end

-- isIncorrect

function suite:testProtectionIsIncorrectTrue1 local obj = makeDefaultProtectionObject function obj:isProtected return false end self:assertTrue(obj:isIncorrect, 'Protection:isProtected returned false')end

function suite:testProtectionIsIncorrectTrue2 local obj = makeDefaultProtectionObject function obj:isProtected return true end obj.expiry = 0 self:assertTrue(obj:isIncorrect, 'the page is protected and expiry is in the past')end

function suite:testProtectionIsIncorrectFalse1 local obj = makeDefaultProtectionObject function obj:isProtected return true end obj.expiry = d.expiryU self:assertFalse(obj:isIncorrect, 'the page is protected and expiry is in the future')end

function suite:testProtectionIsIncorrectFalse2 local obj = makeDefaultProtectionObject obj.expiry = nil function obj:isProtected return true end self:assertFalse(obj:isIncorrect, 'the page is protected and no expiry is set')end

-- isTemplateProtectedNonTemplate

function suite:testProtectionIsTemplateProtectedNonTemplateFalse1 local obj = makeDefaultProtectionObject obj.level = 'autoconfirmed' self:assertFalse(obj:isTemplateProtectedNonTemplate, 'the page is semi-protected')end

function suite:testProtectionIsTemplateProtectedNonTemplateFalse2 local obj = makeDefaultProtectionObject obj.level = 'templateeditor' obj.action = 'edit' rawset(obj.title, 'namespace', 10) -- template space self:assertFalse(obj:isTemplateProtectedNonTemplate, 'template-protected template')end

function suite:testProtectionIsTemplateProtectedNonTemplateFalse3 local obj = makeDefaultProtectionObject obj.level = 'templateeditor' obj.action = 'edit' rawset(obj.title, 'namespace', 828) -- module space self:assertFalse(obj:isTemplateProtectedNonTemplate, 'template-protected module')end

function suite:testProtectionIsTemplateProtectedNonTemplateFalse4 local obj = makeDefaultProtectionObject obj.level = 'templateeditor' obj.action = 'move' rawset(obj.title, 'namespace', 10) -- template space self:assertFalse(obj:isTemplateProtectedNonTemplate, 'template-move-protected template')end

function suite:testProtectionIsTemplateProtectedNonTemplateFalse5 local obj = makeDefaultProtectionObject obj.level = 'templateeditor' obj.action = 'move' rawset(obj.title, 'namespace', 828) -- module space self:assertFalse(obj:isTemplateProtectedNonTemplate, 'template-move-protected module')end

function suite:testProtectionIsTemplateProtectedNonTemplateTrue1 local obj = makeDefaultProtectionObject obj.level = 'templateeditor' obj.action = 'autoreview' self:assertTrue(obj:isTemplateProtectedNonTemplate, 'the action is not edit or move')end

function suite:testProtectionIsTemplateProtectedNonTemplateTrue2 local obj = makeDefaultProtectionObject obj.level = 'templateeditor' rawset(obj.title, 'namespace', 2) -- user space self:assertTrue(obj:isTemplateProtectedNonTemplate, 'the action is not in template or module space')end

-- makeCategoryLinks

function suite:testProtectionMakeCategoryLinksAllPresent local obj = makeDefaultProtectionObject obj._cfg.msg = function obj:makeProtectionCategory return '' end for _, field in ipairs do obj[field] = function return true end end self:assertEquals('' .. '' .. '', obj:makeCategoryLinks )end

function suite:testProtectionMakeCategoryLinksAllAbsent local obj = makeDefaultProtectionObject obj._cfg.msg = function obj:makeProtectionCategory return end for _, field in ipairs do obj[field] = function return false end end self:assertEquals(, obj:makeCategoryLinks)end

---------------------------------------------------------------------------------- Blurb class tests--------------------------------------------------------------------------------

-- initialize

function suite:testBlurbNew local obj = Blurb.new self:assertEquals('foo', obj._protectionObj[1]) self:assertEquals('bar', obj._args[1]) self:assertEquals('baz', obj._cfg[1])end

-- _formatDate

function suite:testBlurbFormatDateStandard local obj = makeDefaultBlurbObject self:assertEquals('1 January 1970', obj:_formatDate(0))end

function suite:testBlurbFormatDateCustom local obj = makeDefaultBlurbObject self:assertEquals('1970 1970 January January 1', obj:_formatDate(0))end

function suite:testBlurbFormatDateError local obj = makeDefaultBlurbObject self:assertEquals(nil, obj:_formatDate('foo'))end

-- _getExpandedMessage

function suite:testBlurbGetExpandedMessage local obj = makeDefaultBlurbObject function obj:_substituteParameters(s) return 'testing ' .. s end obj._cfg.msg = self:assertEquals('testing test message', obj:_getExpandedMessage('test-key'))end

-- _substituteParameters

function suite:testBlurbSubstituteParameters local obj = makeDefaultBlurbObject

obj._makeCurrentVersionParameter = function return '1' end obj._makeEditRequestParameter = function return '2' end obj._makeExpiryParameter = function return '3' end obj._makeExplanationBlurbParameter = function return '4' end obj._makeImageLinkParameter = function return '5' end obj._makeIntroBlurbParameter = function return '6' end obj._makeIntroFragmentParameter = function return '7' end obj._makePagetypeParameter = function return '8' end obj._makeProtectionBlurbParameter = function return '9' end obj._makeProtectionDateParameter = function return '10' end obj._makeProtectionLevelParameter = function return '11' end obj._makeProtectionLogParameter = function return '12' end obj._makeTalkPageParameter = function return '13' end obj._makeTooltipBlurbParameter = function return '14' end obj._makeTooltipFragmentParameter = function return '15' end obj._makeVandalTemplateParameter = function return '16' end

local msg = '$-' .. '$-' .. '$-' .. '$-' .. '$-' .. '$-' .. '$-' .. '$-' .. '$-' .. '$-' .. '$-' .. '$-' .. '$-' .. '$-' .. '$-' .. '$'

local expected = '1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16'

self:assertEquals(expected, obj:_substituteParameters(msg))end -- makeCurrentVersionParameter

function suite:testBlurbMakeCurrentVersionParameterEdit local obj = makeDefaultBlurbObject obj._protectionObj.action = 'edit' obj._cfg.msg['current-version-edit-display'] = 'edit display' self:assertEquals('[//en.wikipedia.org/w/index.php?title=' .. mw.uri.encode(d.page) .. '&action=history edit display]', obj:_makeCurrentVersionParameter )end

function suite:testBlurbMakeCurrentVersionParameterMove local obj = makeDefaultBlurbObject obj._protectionObj.action = 'move' obj._cfg.msg['current-version-move-display'] = 'move display' self:assertEquals('[//en.wikipedia.org/w/index.php?title=' .. mw.uri.encode('Special:Log') .. '&page=' .. mw.uri.encode(d.page) .. '&type=move move display]', obj:_makeCurrentVersionParameter )end

-- _makeEditRequestParameter

function suite:testBlurbMakeEditRequestParameterLevels -- We can't test the edit requests directly as that is the responsibility of --, but we can check that we get different -- outputs for different protection levels. local function makeBlurbObjectWithLevels(action, level) local obj = makeDefaultBlurbObject obj._protectionObj.action = action obj._protectionObj.level = level obj._cfg.msg['edit-request-display'] = 'display' return obj end local obj1 = makeBlurbObjectWithLevels('edit', 'autoconfirmed') local obj2 = makeBlurbObjectWithLevels('edit', 'templateeditor') local obj3 = makeBlurbObjectWithLevels('edit', 'sysop') local obj4 = makeBlurbObjectWithLevels('move', 'templateeditor')

self:assertFalse(obj1:_makeEditRequestParameter

obj2:_makeEditRequestParameter) self:assertFalse(obj2:_makeEditRequestParameter

obj3:_makeEditRequestParameter) self:assertEquals(obj3:_makeEditRequestParameter, obj4:_makeEditRequestParameter)end

function suite:testBlurbMakeEditRequestParameterLink -- Check that the edit request links have features that we can always expect -- to be there. The rest is subject to be changed by -- at any time, so we won't test that here. local obj = makeDefaultBlurbObject obj._protectionObj.action = 'edit' obj._protectionObj.level = 'autoconfirmed' obj._cfg.msg['edit-request-display'] = 'the edit request display' self:assertStringContains('//en.wikipedia.org/w/index.php?', obj:_makeEditRequestParameter, true ) self:assertStringContains('action=edit', obj:_makeEditRequestParameter, true ) self:assertStringContains('title=[a-zA-Z0-9%%_]*[tT]alk', obj:_makeEditRequestParameter, false ) self:assertStringContains('the edit request display', obj:_makeEditRequestParameter, true )end

-- _makeExpiryParameter

function suite:testBlurbMakeExpiryParameterTemp local obj = makeDefaultBlurbObject obj._protectionObj.expiry = 0 function obj:_formatDate(num) return 'unix date is ' .. tostring(num) end self:assertEquals('unix date is 0', obj:_makeExpiryParameter)end

function suite:testBlurbMakeExpiryParameterOther local obj = makeDefaultBlurbObject obj._protectionObj.expiry = 'indef' function obj:_formatDate(num) return 'unix date is ' .. tostring(num) end self:assertEquals('indef', obj:_makeExpiryParameter)end

-- _makeExplanationBlurbParameter

function suite:testBlurbMakeExplanationBlurbParameter local obj = makeDefaultBlurbObject obj._protectionObj.action = 'edit' obj._protectionObj.level = 'autoconfirmed' rawset(obj._protectionObj.title, 'isTalkPage', true)

obj._cfg.explanationBlurbs =

function obj:_substituteParameters(msg) return msg end

self:assertEquals('edit-autoconfirmed-talk', obj:_makeExplanationBlurbParameter )

obj._cfg.explanationBlurbs.edit.autoconfirmed.talk = nil self:assertEquals('edit-autoconfirmed-default', obj:_makeExplanationBlurbParameter )

obj._cfg.explanationBlurbs.edit.autoconfirmed.default = nil self:assertEquals('edit-default-talk', obj:_makeExplanationBlurbParameter )

obj._cfg.explanationBlurbs.edit.default.talk = nil self:assertEquals('edit-default-default', obj:_makeExplanationBlurbParameter )

obj._cfg.explanationBlurbs.edit.default.default = nil self:assertError(obj._makeExplanationBlurbParameter, , 'could not find explanation blurb for action "edit",' .. ' level "autoconfirmed" and talk key "talk"' )end

function suite:testBlurbMakeExplanationBlurbParameterSpecialCases local obj = makeDefaultBlurbObject rawset(obj._protectionObj.title, 'namespace', 8) function obj:_getExpandedMessage(key) return 'the key is ' .. key end self:assertEquals('the key is explanation-blurb-nounprotect', obj:_makeExplanationBlurbParameter )end

-- _makeImageLinkParameter

function suite:testBlurbMakeImageLinkParameter local obj = makeDefaultBlurbObject obj._protectionObj.action = 'move' obj._protectionObj.level = 'sysop'

obj._cfg.imageLinks =

function obj:_substituteParameters(msg) return msg end

self:assertEquals('move-sysop', obj:_makeImageLinkParameter )

obj._cfg.imageLinks.move.sysop = nil self:assertEquals('move-default', obj:_makeImageLinkParameter )

obj._cfg.imageLinks.move.default = nil self:assertEquals('edit-default', obj:_makeImageLinkParameter )end

-- _makeIntroBlurbParameter

function suite:testBlurbMakeIntroBlurbParameter local obj = makeDefaultBlurbObject function obj._protectionObj:isTemporary return true end function obj:_getExpandedMessage(key) return 'the key is ' .. key end self:assertEquals('the key is intro-blurb-expiry', obj:_makeIntroBlurbParameter )

function obj._protectionObj:isTemporary return false end self:assertEquals('the key is intro-blurb-noexpiry', obj:_makeIntroBlurbParameter )end

-- _makeIntroFragmentParameter

function suite:testBlurbMakeIntroFragmentParameter local obj = makeDefaultBlurbObject function obj._protectionObj:isTemporary return true end function obj:_getExpandedMessage(key) return 'the key is ' .. key end self:assertEquals('the key is intro-fragment-expiry', obj:_makeIntroFragmentParameter )

function obj._protectionObj:isTemporary return false end self:assertEquals('the key is intro-fragment-noexpiry', obj:_makeIntroFragmentParameter )end

-- _makePagetypeParameter

function suite:testPagetypeParameter local obj = makeDefaultBlurbObject rawset(obj._protectionObj.title, 'namespace', 3)

obj._cfg.pagetypes =

self:assertEquals('user talk page', obj:_makePagetypeParameter )

obj._cfg.pagetypes[3] = nil self:assertEquals('default page', obj:_makePagetypeParameter )

obj._cfg.pagetypes.default = nil self:assertError(obj._makePagetypeParameter, , 'no default pagetype defined' )end

-- _makeProtectionBlurbParameter

function suite:testBlurbMakeProtectionBlurbParameter local obj = makeDefaultBlurbObject obj._protectionObj.action = 'move' obj._protectionObj.level = 'sysop'

obj._cfg.protectionBlurbs =

function obj:_substituteParameters(msg) return msg end

self:assertEquals('move-sysop', obj:_makeProtectionBlurbParameter )

obj._cfg.protectionBlurbs.move.sysop = nil self:assertEquals('move-default', obj:_makeProtectionBlurbParameter )

obj._cfg.protectionBlurbs.move.default = nil self:assertEquals('edit-default', obj:_makeProtectionBlurbParameter )

obj._cfg.protectionBlurbs.edit.default = nil self:assertError(obj._makeProtectionBlurbParameter, , 'no protection blurb defined for protectionBlurbs.edit.default' )end

-- _makeProtectionDateParameter

function suite:testBlurbMakeProtectionDateParameter local obj = makeDefaultBlurbObject obj._protectionObj.protectionDate = 0 function obj:_formatDate(num) return 'unix date is ' .. tostring(num) end self:assertEquals('unix date is 0', obj:_makeProtectionDateParameter)

obj._protectionObj.protectionDate = 'indef' self:assertEquals('indef', obj:_makeProtectionDateParameter)end

-- _makeProtectionLevelParameter

function suite:testBlurbMakeProtectionLevelParameter local obj = makeDefaultBlurbObject obj._protectionObj.action = 'move' obj._protectionObj.level = 'sysop'

obj._cfg.protectionLevels =

function obj:_substituteParameters(msg) return msg end

self:assertEquals('move-sysop', obj:_makeProtectionLevelParameter )

obj._cfg.protectionLevels.move.sysop = nil self:assertEquals('move-default', obj:_makeProtectionLevelParameter )

obj._cfg.protectionLevels.move.default = nil self:assertEquals('edit-default', obj:_makeProtectionLevelParameter )

obj._cfg.protectionLevels.edit.default = nil self:assertError(obj._makeProtectionLevelParameter, , 'no protection level defined for protectionLevels.edit.default' )end

-- _makeProtectionLogParameter

function suite:testBlurbMakeProtectionLogParameterPC local obj = makeDefaultBlurbObject obj._protectionObj.action = 'autoreview' function obj:_getExpandedMessage(key) return 'the key is ' .. key end self:assertStringContains('^%[//en%.wikipedia%.org/w/index%.php?', obj:_makeProtectionLogParameter, false ) self:assertStringContains('title=' .. mw.uri.encode('Special:Log'), obj:_makeProtectionLogParameter, true ) self:assertStringContains('type=stable', obj:_makeProtectionLogParameter, true ) self:assertStringContains('page=' .. mw.uri.encode(d.page), obj:_makeProtectionLogParameter, true ) self:assertStringContains('the key is pc%-log%-display%]$', obj:_makeProtectionLogParameter, false )end

function suite:testBlurbMakeProtectionLogParameterProtection local obj = makeDefaultBlurbObject obj._protectionObj.action = 'edit' function obj:_getExpandedMessage(key) return 'the key is ' .. key end self:assertStringContains('^%[//en%.wikipedia%.org/w/index%.php?', obj:_makeProtectionLogParameter, false ) self:assertStringContains('title=' .. mw.uri.encode('Special:Log'), obj:_makeProtectionLogParameter, true ) self:assertStringContains('type=protect', obj:_makeProtectionLogParameter, true ) self:assertStringContains('page=' .. mw.uri.encode(d.page), obj:_makeProtectionLogParameter, true ) self:assertStringContains('the key is protection%-log%-display%]$', obj:_makeProtectionLogParameter, false )end

-- _makeTalkPageParameter

function suite:testBlurbMakeTalkPageParameter local obj = makeDefaultBlurbObject function obj:_getExpandedMessage(key) return 'the key is ' .. key end self:assertEquals('' .. 'the key is talk-page-link-display' .. '', obj:_makeTalkPageParameter ) obj._args.section = 'talk section' self:assertEquals('' .. 'the key is talk-page-link-display' .. '', obj:_makeTalkPageParameter )end

-- _makeTooltipBlurbParameter

function suite:testBlurbMakeTooltipBlurbParameter local obj = makeDefaultBlurbObject function obj._protectionObj:isTemporary return true end function obj:_getExpandedMessage(key) return 'the key is ' .. key end self:assertEquals('the key is tooltip-blurb-expiry', obj:_makeTooltipBlurbParameter )

function obj._protectionObj:isTemporary return false end self:assertEquals('the key is tooltip-blurb-noexpiry', obj:_makeTooltipBlurbParameter )end

-- _makeTooltipFragmentParameter

function suite:testBlurbMakeTooltipFragmentParameter local obj = makeDefaultBlurbObject function obj._protectionObj:isTemporary return true end function obj:_getExpandedMessage(key) return 'the key is ' .. key end self:assertEquals('the key is tooltip-fragment-expiry', obj:_makeTooltipFragmentParameter )

function obj._protectionObj:isTemporary return false end self:assertEquals('the key is tooltip-fragment-noexpiry', obj:_makeTooltipFragmentParameter )end

-- _makeVandalTemplateParameter

function suite:testBlurbMakeVandalTemplateParameter local obj = makeDefaultBlurbObject self:assertStringContains(d.baseText, obj:_makeVandalTemplateParameter, true ) obj._args.user = 'Some user' self:assertStringContains('Some user', obj:_makeVandalTemplateParameter, true )end

-- makeBannerText

function suite:testBlurbMakeBannerTextBadInput local obj = makeDefaultBlurbObject self:assertError(obj.makeBannerText, , '"foo" is not a valid banner config field' ) self:assertError(obj.makeBannerText, , '"nil" is not a valid banner config field' )end

function suite:testBlurbMakeBannerTextGoodInput local obj = makeDefaultBlurbObject obj._protectionObj.bannerConfig = self:assertNotError(obj.makeBannerText,) self:assertNotError(obj.makeBannerText,) self:assertNotError(obj.makeBannerText,) self:assertNotError(obj.makeBannerText,) self:assertNotError(obj.makeBannerText,)end

function suite:testBlurbMakeBannerTextString local obj = makeDefaultBlurbObject function obj:_substituteParameters(msg) return msg end obj._protectionObj.bannerConfig = self:assertEquals('banner text', obj:makeBannerText('text'))end

function suite:testBlurbMakeBannerTextBadFunction local obj = makeDefaultBlurbObject function obj:_substituteParameters(msg) return msg end obj._protectionObj.bannerConfig = self:assertError(obj.makeBannerText, , 'bad output from banner config function with key "text"' .. ' (expected string, got number)' )end

function suite:testBlurbMakeBannerTextGoodFunction local obj = makeDefaultBlurbObject function obj:_substituteParameters(msg) return msg end obj._protectionObj.bannerConfig = self:assertEquals('some text', obj:makeBannerText('text'))end

---------------------------------------------------------------------------------- BannerTemplate class tests--------------------------------------------------------------------------------

-- BannerTemplate.new

function suite:testBannerTemplateNewCfg local protectionObj = makeDefaultProtectionObject local obj = BannerTemplate.new(protectionObj, makeConfig) self:assertEquals('bar', obj._cfg.foo)end

function suite:testBannerTemplateNewImageIndefTemplateOrModule local cfg = local protectionObj = makeDefaultProtectionObject protectionObj.action = 'edit' protectionObj.level = 'sysop' function protectionObj:isTemporary return false end

rawset(protectionObj.title, 'namespace', 10) local obj1 = BannerTemplate.new(protectionObj, makeConfig(cfg)) self:assertEquals('red padlock', obj1._imageFilename)

rawset(protectionObj.title, 'namespace', 828) local obj2 = BannerTemplate.new(protectionObj, makeConfig(cfg)) self:assertEquals('red padlock', obj2._imageFilename)end

function suite:testBannerTemplateNewImageUsesIndefReason local cfg = local protectionObj = makeDefaultProtectionObject protectionObj.action = 'edit' protectionObj.level = 'sysop' function protectionObj:isTemporary return false end rawset(protectionObj.title, 'namespace', 2) local obj = BannerTemplate.new(protectionObj, makeConfig(cfg)) self:assertEquals('red padlock', obj._imageFilename)end

function suite:testBannerTemplateNewImageDefault local images = local protectionObj = makeDefaultProtectionObject protectionObj.action = 'move' protectionObj.level = 'sysop' local obj = BannerTemplate.new(protectionObj, makeConfig)

self:assertEquals('foo', obj._imageFilename)

images.move.sysop = nil obj = BannerTemplate.new(protectionObj, makeConfig) self:assertEquals('bar', obj._imageFilename)

images.move.default = nil obj = BannerTemplate.new(protectionObj, makeConfig) self:assertEquals(nil, obj._imageFilename)end

-- renderImage

function suite:testBannerTemplateRenderImageFilename local obj = makeDefaultBannerTemplateObject obj._imageFilename = 'ImageFilename.png' self:assertStringContains('ImageFilename.png', obj:renderImage, true)end

function suite:testBannerTemplateRenderImageDefault local obj = makeDefaultBannerTemplateObject obj._cfg.msg['image-filename-default'] = 'Defaultfilename.png' self:assertStringContains('Defaultfilename.png', obj:renderImage, true)end

function suite:testBannerTemplateRenderImageDefaultNoConfig local obj = makeDefaultBannerTemplateObject self:assertStringContains('Transparent.gif', obj:renderImage, true)end

function suite:testBannerTemplateRenderImageDefaultWidth local obj = makeDefaultBannerTemplateObject self:assertStringContains('20px', obj:renderImage, true)end

function suite:testBannerTemplateRenderImageCustomWidth local obj = makeDefaultBannerTemplateObject obj.imageWidth = 50 self:assertStringContains('50px', obj:renderImage, true)end

function suite:testBannerTemplateRenderImageAlt local obj = makeDefaultBannerTemplateObject obj._imageAlt = 'the alt text' self:assertStringContains('alt%s*=%s*the alt text', obj:renderImage, false)end

function suite:testBannerTemplateRenderImageLink local obj = makeDefaultBannerTemplateObject obj._imageLink = 'the link text' self:assertStringContains('link%s*=%s*the link text', obj:renderImage, false)end

function suite:testBannerTemplateRenderImageCaption local obj = makeDefaultBannerTemplateObject obj.imageCaption = 'the caption text' self:assertStringContains('the caption text', obj:renderImage, true)end

---------------------------------------------------------------------------------- Banner class tests--------------------------------------------------------------------------------

function suite:testBannerNew local protectionObj = makeDefaultProtectionObject local blurbObj = makeDefaultBlurbObject local cfg = makeConfig

function blurbObj:makeBannerText(key) if key

'alt' then return 'the alt text' elseif key

'text' then return 'the main text' elseif key

'explanation' then return 'the explanation text' end end local obj = Banner.new(protectionObj, blurbObj, cfg)

self:assertEquals(40, obj.imageWidth) self:assertEquals('the alt text', obj.imageCaption) self:assertEquals('the main text', obj._reasonText) self:assertEquals('the explanation text', obj._explanationText) self:assertEquals(d.page, obj._page)end

-- __tostring

function suite:testBannerToStringError local obj = makeDefaultBannerObject obj._reasonText = nil self:assertError(obj.__tostring,, 'no reason text set')end

function suite:testBannerToString local obj = makeDefaultBannerObject obj._reasonText = 'the reason text' obj._explanationText = 'the explanation text' function obj:renderImage return '' end

self:assertStringContains('', tostring(obj), true) self:assertStringContains("the reason text
the explanation text", tostring(obj), true )

obj._explanationText = nil self:assertStringContains("the reason text", tostring(obj), true)end

---------------------------------------------------------------------------------- Padlock class tests--------------------------------------------------------------------------------

function suite:testPadlockNew local protectionObj = makeDefaultProtectionObject local blurbObj = makeDefaultBlurbObject local cfg = makeConfig

function blurbObj:makeBannerText(key) if key

'alt' then return 'the alt text' elseif key

'tooltip' then return 'the tooltip text' elseif key

'link' then return 'the link text' end end local obj = Padlock.new(protectionObj, blurbObj, cfg)

self:assertEquals(20, obj.imageWidth) self:assertEquals('the tooltip text', obj.imageCaption) self:assertEquals('the alt text', obj._imageAlt) self:assertEquals('the link text', obj._imageLink)end

function suite:testPadlockNewIndicators local protectionObj = makeDefaultProtectionObject protectionObj.action = 'move' protectionObj.level = 'sysop' local blurbObj = makeDefaultBlurbObject

local cfg = makeConfig local obj = Padlock.new(protectionObj, blurbObj, cfg) self:assertEquals('move-indicator', obj._indicatorName)

cfg.padlockIndicatorNames.move = nil obj = Padlock.new(protectionObj, blurbObj, cfg) self:assertEquals('default-indicator', obj._indicatorName)

cfg.padlockIndicatorNames.default = nil obj = Padlock.new(protectionObj, blurbObj, cfg) self:assertEquals('pp-default', obj._indicatorName)end

-- __tostring

function suite:testPadlockToString local obj = makeDefaultPadlockObject self:assertIsPadlock(tostring(obj))end

---------------------------------------------------------------------------------- Export tests--------------------------------------------------------------------------------

-- _main

function suite:test_mainError local args = local cfg = makeConfig local title = makeDefaultTitleObject local success, result = pcall(mProtectionBanner._main, args, cfg, title) self:assertFalse(success) self:assertEquals('invalid action: foobar', result )end

function suite:testCatOnlyHidesOutput local args1 = local args2 = local cfg = makeConfig local title = makeDefaultTitleObject self:assertNoBanner(mProtectionBanner._main(args1, cfg, title)) self:assertNoPadlock(mProtectionBanner._main(args2, cfg, title))end

function suite:testCatOnlyShowsCategory local args = local cfg = makeConfig cfg.protectionCategories = local title = makeDefaultTitleObject self:assertStringContains("Category:indef expiry", mProtectionBanner._main(args, cfg, title), true)end

function suite:testCatOnlyNoGivesOutput local args = local cfg = makeConfig local title = makeDefaultTitleObject self:assertIsBanner(mProtectionBanner._main(args, cfg, title))end

function suite:testCatOnlyNoShowsCategory local args = local cfg = makeConfig cfg.protectionCategories = local title = makeDefaultTitleObject self:assertStringContains("Category:indef expiry", mProtectionBanner._main(args, cfg, title), true)end

function suite:test_mainSmall1 local args = local cfg = makeConfig local title = makeDefaultTitleObject self:assertIsPadlock(mProtectionBanner._main(args, cfg, title))end

function suite:test_mainSmall2 local args = local cfg = makeConfig local title = makeDefaultTitleObject self:assertIsPadlock(mProtectionBanner._main(args, cfg, title))end

function suite:test_mainSmall3 local args = local cfg = makeConfig local title = makeDefaultTitleObject self:assertIsPadlock(mProtectionBanner._main(args, cfg, title))end

function suite:test_mainLarge1 local args = local cfg = makeConfig local title = makeDefaultTitleObject self:assertIsBanner(mProtectionBanner._main(args, cfg, title))end

function suite:test_mainLarge2 local args = local cfg = makeConfig local title = makeDefaultTitleObject self:assertIsBanner(mProtectionBanner._main(args, cfg, title))end

function suite:test_mainLarge3 local args = local cfg = makeConfig local title = makeDefaultTitleObject self:assertIsBanner(mProtectionBanner._main(args, cfg, title))end

function suite:test_mainLarge4 local args = local cfg = makeConfig local title = makeDefaultTitleObject self:assertIsBanner(mProtectionBanner._main(args, cfg, title))end

function suite:test_mainNoBanner local args = local cfg = makeConfig local title = makeTitleObject self:assertNoBanner(mProtectionBanner._main(args, cfg, title), 'page unprotected')end

function suite:test_mainNoBannerForUserScripts local args = local cfg = makeConfig local title = makeTitleObject self:assertNoBanner(mProtectionBanner._main(args, cfg, title), 'page is a user script')end

function suite:test_mainCategories local args = local cfg -- Use main config module local title = makeTitleObject self:assertStringContains('%[%[Category:.-%]%]', mProtectionBanner._main(args, cfg, title), false, 'page unprotected' )end

-- p.main

function suite:testMainHasOutput local frame = mw.getCurrentFrame local parent = frame:newChild local child = parent:newChild local cfg -- Use main config module self:assertStringContains('%S', mProtectionBanner.main(child, cfg), false)end

function suite:testMainWrapper local frame = mw.getCurrentFrame local parent = frame:newChild local child = parent:newChild local cfg = makeConfig self:assertNotStringContains('%[%[Category:.-%]%]', mProtectionBanner.main(child, cfg), false ) self:assertStringContains('%[%[Category:.-%]%]', mProtectionBanner.main(parent, cfg), false )end

function suite:testMainWrapperOverride local frame = mw.getCurrentFrame local parent = frame:newChild local child = parent:newChild local cfg = makeConfig self:assertStringContains('%[%[Category:.-%]%]', mProtectionBanner.main(child, cfg), false )end

function suite:testMainWrapperSandbox local frame = mw.getCurrentFrame local parent = frame:newChild local child = parent:newChild local cfg = makeConfig self:assertNotStringContains('%[%[Category:.-%]%]', mProtectionBanner.main(child, cfg), false ) self:assertStringContains('%[%[Category:.-%]%]', mProtectionBanner.main(parent, cfg), false )end

function suite:testMainNoWrapper local frame = mw.getCurrentFrame local parent = frame:newChild local child = parent:newChild local cfg = makeConfig self:assertStringContains('%[%[Category:.-%]%]', mProtectionBanner.main(child, cfg), false ) self:assertStringContains('%[%[Category:.-%]%]', mProtectionBanner.main(parent, cfg), false )end

return suite