Difference between revisions of "Module:Protection banner/testcases"
Jump to navigation
Jump to search
blackwiki>Mr. Stradivarius (override Module:Effective protection level) |
m (92 revisions imported) |
||
| (13 intermediate revisions by 2 users not shown) | |||
| Line 52: | Line 52: | ||
end | end | ||
| − | local function makeTitleObject(page | + | local function makeTitleObject(options) |
| + | local title = mw.title.new(options.page) | ||
| + | |||
| + | -- Set protection levels | ||
local levels = { | local levels = { | ||
edit = {}, | edit = {}, | ||
| Line 58: | Line 61: | ||
autoreview = {} | autoreview = {} | ||
} | } | ||
| − | levels[action][1] = level | + | for _, action in ipairs{'edit', 'move', 'autoreview'} 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 title | ||
end | end | ||
local function makeDefaultTitleObject() | local function makeDefaultTitleObject() | ||
| − | return makeTitleObject | + | return makeTitleObject{page = d.page, [d.action] = d.level} |
end | end | ||
| Line 82: | Line 94: | ||
pagetypes = {}, | pagetypes = {}, | ||
indefStrings = {}, | indefStrings = {}, | ||
| + | hierarchy = { | ||
| + | sysop = {}, | ||
| + | reviewer = {'sysop'}, | ||
| + | filemover = {'sysop'}, | ||
| + | templateeditor = {'sysop'}, | ||
| + | extendedconfirmed = {'sysop'}, | ||
| + | autoconfirmed = {'reviewer', 'filemover', 'templateeditor', 'extendedconfirmed'}, | ||
| + | user = {'autoconfirmed'}, | ||
| + | ['*'] = {'user'} | ||
| + | }, | ||
wrappers = {}, | wrappers = {}, | ||
msg = {} | msg = {} | ||
| Line 197: | Line 219: | ||
function suite:assertIsPadlock(s, msg) | function suite:assertIsPadlock(s, msg) | ||
self:assertStringContains( | self:assertStringContains( | ||
| − | '^% | + | '\127[^\127]*UNIQ%-%-indicator%-%x+%-QINU[^\127]*\127', |
s, | s, | ||
false, | false, | ||
| Line 268: | Line 290: | ||
Protection.new, | Protection.new, | ||
{{action = 'foo'}, makeConfig()}, | {{action = 'foo'}, makeConfig()}, | ||
| − | 'invalid action | + | 'invalid action: foo' |
) | ) | ||
end | end | ||
| Line 285: | Line 307: | ||
local obj = Protection.new({action = 'autoreview'}, makeConfig()) | local obj = Protection.new({action = 'autoreview'}, makeConfig()) | ||
suite:assertEquals('autoreview', obj.action) | suite:assertEquals('autoreview', obj.action) | ||
| + | end | ||
| + | |||
| + | function suite:testProtectionActionUpload() | ||
| + | local obj = Protection.new({action = 'upload'}, makeConfig()) | ||
| + | suite:assertEquals('upload', obj.action) | ||
end | end | ||
| Line 298: | Line 325: | ||
{action = 'edit'}, | {action = 'edit'}, | ||
makeConfig(), | makeConfig(), | ||
| − | makeTitleObject | + | makeTitleObject{page = 'Foo', edit = 'autoconfirmed'} |
) | ) | ||
self:assertEquals('autoconfirmed', obj.level) | self:assertEquals('autoconfirmed', obj.level) | ||
| Line 307: | Line 334: | ||
{action = 'edit'}, | {action = 'edit'}, | ||
makeConfig(), | makeConfig(), | ||
| − | makeTitleObject | + | makeTitleObject{page = 'Foo', edit = 'sysop'} |
) | ) | ||
self:assertEquals('sysop', obj.level) | self:assertEquals('sysop', obj.level) | ||
| Line 316: | Line 343: | ||
{action = 'edit'}, | {action = 'edit'}, | ||
makeConfig(), | makeConfig(), | ||
| − | makeTitleObject | + | makeTitleObject{page = 'Foo', edit = nil} |
) | ) | ||
self:assertEquals('*', obj.level) | self:assertEquals('*', obj.level) | ||
| Line 325: | Line 352: | ||
{action = 'move'}, | {action = 'move'}, | ||
makeConfig(), | makeConfig(), | ||
| − | makeTitleObject | + | makeTitleObject{page = 'Foo', move = 'autoconfirmed'} |
) | ) | ||
self:assertEquals('*', obj.level) | self:assertEquals('*', obj.level) | ||
| Line 334: | Line 361: | ||
{action = 'edit'}, | {action = 'edit'}, | ||
makeConfig(), | makeConfig(), | ||
| − | makeTitleObject | + | makeTitleObject{page = 'Template:Foo', edit = 'templateeditor'} |
) | ) | ||
self:assertEquals('templateeditor', obj.level) | self:assertEquals('templateeditor', obj.level) | ||
| Line 343: | Line 370: | ||
{action = 'edit'}, | {action = 'edit'}, | ||
makeConfig(), | makeConfig(), | ||
| − | makeTitleObject | + | makeTitleObject{page = 'Template:Editnotices/Page/Foo', edit = nil} |
) | ) | ||
self:assertEquals('templateeditor', obj.level) | self:assertEquals('templateeditor', obj.level) | ||
end | end | ||
| − | -- | + | -- Reason |
| − | function suite: | + | function suite:testProtectionReason() |
local obj = Protection.new( | local obj = Protection.new( | ||
| − | { | + | {'foo'}, |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
makeConfig() | makeConfig() | ||
) | ) | ||
| − | self:assertEquals( | + | self:assertEquals('foo', obj.reason) |
end | end | ||
| − | function suite: | + | function suite:testProtectionReasonLowerCase() |
local obj = Protection.new( | local obj = Protection.new( | ||
| − | { | + | {'fOO'}, |
makeConfig() | makeConfig() | ||
) | ) | ||
| − | self:assertEquals( | + | self:assertEquals('foo', obj.reason) |
end | end | ||
| − | function suite: | + | function suite:testProtectionBadReason() |
self:assertError( | self:assertError( | ||
Protection.new, | Protection.new, | ||
| − | {{ | + | {{'foo|bar'}, makeConfig()}, |
| − | ' | + | 'reasons cannot contain the pipe character ("|")' |
) | ) | ||
end | end | ||
| − | function suite: | + | function suite:testProtectionNoReason() |
local obj = Protection.new( | local obj = Protection.new( | ||
| − | { | + | {}, |
makeConfig() | makeConfig() | ||
) | ) | ||
| − | self:assertEquals( | + | self:assertEquals(nil, obj.reason) |
end | end | ||
| − | -- | + | -- Protection date |
| − | function suite: | + | function suite:testProtectionProtectionDateIndef() |
| + | self:assertError( | ||
| + | Protection.new, | ||
| + | { | ||
| + | {date = 'indefinite'}, | ||
| + | makeConfig{indefStrings = {indefinite = true}} | ||
| + | }, | ||
| + | 'invalid protection date: indefinite' | ||
| + | ) | ||
| + | end | ||
| + | |||
| + | function suite:testProtectionProtectionDateTemp() | ||
local obj = Protection.new( | local obj = Protection.new( | ||
| − | { | + | {date = d.protectionDate}, |
makeConfig() | makeConfig() | ||
) | ) | ||
| − | self:assertEquals( | + | self:assertEquals(d.protectionDateU, obj.protectionDate) |
end | end | ||
| − | function suite: | + | function suite:testProtectionNoProtectionDate() |
local obj = Protection.new( | local obj = Protection.new( | ||
| − | { | + | {}, |
makeConfig() | makeConfig() | ||
) | ) | ||
| − | self:assertEquals( | + | self:assertEquals(nil, obj.protectionDate) |
end | end | ||
| − | function suite: | + | function suite:testProtectionBadProtectionDate() |
self:assertError( | self:assertError( | ||
Protection.new, | Protection.new, | ||
| − | {{' | + | { |
| − | ' | + | {date = 'foobar'}, |
| + | makeConfig{indefStrings = {indefinite = true}} | ||
| + | }, | ||
| + | 'invalid protection date: foobar' | ||
) | ) | ||
end | end | ||
| − | function suite: | + | -- bannerConfig |
| − | local | + | |
| − | + | function suite:testProtectionMasterBannerConfigPrecedence1() | |
| − | + | local masterBanner = {text = 'master banner text'} | |
| − | + | local obj = makeDefaultProtectionObject{masterBanner = masterBanner} | |
| − | self:assertEquals( | + | self:assertEquals('master banner text', obj.bannerConfig.text) |
end | end | ||
| − | + | function suite:testProtectionMasterBannerConfigPrecedence2() | |
| − | + | local masterBanner = {text = 'master banner text'} | |
| − | function suite: | + | local defaultBanners = {[d.action] = {default = {text = 'defaultBanners default text'}}} |
| − | + | local obj = makeDefaultProtectionObject(makeConfig{ | |
| − | + | masterBanner = masterBanner, | |
| − | + | defaultBanners = defaultBanners | |
| − | + | }) | |
| − | + | self:assertEquals('defaultBanners default text', obj.bannerConfig.text) | |
| − | |||
| − | |||
| − | ) | ||
end | end | ||
| − | function suite: | + | function suite:testProtectionMasterBannerConfigPrecedence3() |
| − | local | + | local defaultBanners = {[d.action] = { |
| − | { | + | [d.level] = {text = 'defaultBanners level text'}, |
| − | + | default = {text = 'defaultBanners default text'} | |
| − | ) | + | }} |
| − | self:assertEquals( | + | local obj = makeDefaultProtectionObject(makeConfig{defaultBanners = defaultBanners}) |
| + | self:assertEquals('defaultBanners level text', obj.bannerConfig.text) | ||
end | end | ||
| − | function suite: | + | function suite:testProtectionMasterBannerConfigPrecedence4() |
| − | local | + | local defaultBanners = {[d.action] = { |
| − | {}, | + | [d.level] = {text = 'defaultBanners level text'} |
| − | + | }} | |
| − | ) | + | local banners = {[d.action] ={ |
| − | self:assertEquals( | + | [d.reason] = {text = 'banners text'} |
| + | }} | ||
| + | local obj = makeDefaultProtectionObject(makeConfig{ | ||
| + | defaultBanners = defaultBanners, | ||
| + | banners = banners | ||
| + | }) | ||
| + | self:assertEquals('banners text', obj.bannerConfig.text) | ||
end | end | ||
| − | function suite: | + | function suite:testProtectionMasterBannerConfigFields() |
| − | + | local masterBanner = { | |
| − | + | text = 'master banner text', | |
| − | + | explanation = 'master banner explanation', | |
| − | + | tooltip = 'master banner tooltip', | |
| − | + | alt = 'master banner alt', | |
| − | + | link = 'master banner link', | |
| − | + | image = 'master banner image' | |
| − | ) | + | } |
| + | local obj = makeDefaultProtectionObject{masterBanner = masterBanner} | ||
| + | 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 | end | ||
| − | -- | + | -- isUserScript |
| − | function suite: | + | function suite:testProtectionIsUserScriptWithUserCSS() |
| − | local | + | local protection = Protection.new( |
| − | + | {}, | |
| − | self: | + | makeConfig(), |
| + | mw.title.new('User:Example/common.css') | ||
| + | ) | ||
| + | self:assertTrue(protection:isUserScript()) | ||
end | end | ||
| − | function suite: | + | function suite:testProtectionIsUserScriptWithUserJS() |
| − | local | + | local protection = Protection.new( |
| − | + | {}, | |
| − | local | + | makeConfig(), |
| − | + | mw.title.new('User:Example/common.js') | |
| − | + | ) | |
| − | + | self:assertTrue(protection:isUserScript()) | |
| − | self: | + | end |
| + | |||
| + | function suite:testProtectionIsUserScriptWithUserPage() | ||
| + | local protection = Protection.new( | ||
| + | {}, | ||
| + | makeConfig(), | ||
| + | mw.title.new('User:Example') | ||
| + | ) | ||
| + | self:assertFalse(protection:isUserScript()) | ||
end | end | ||
| − | function suite: | + | function suite:testProtectionIsUserScriptWithNormalSubpage() |
| − | local | + | local protection = Protection.new( |
| − | + | {}, | |
| − | + | makeConfig(), | |
| − | + | mw.title.new('User:Example/common') | |
| − | + | ) | |
| − | self: | + | self:assertFalse(protection:isUserScript()) |
end | end | ||
| − | function suite: | + | function suite:testProtectionIsUserScriptWithUsernameEndingInCSS() |
| − | local | + | local protection = Protection.new( |
| − | + | {}, | |
| − | + | makeConfig(), | |
| − | + | mw.title.new('User:My username ends in .css') | |
| − | + | ) | |
| − | + | self:assertFalse(protection:isUserScript()) | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | self: | ||
end | end | ||
| − | function suite: | + | |
| − | + | function suite:testProtectionIsUserScriptWithUsernameEndingInJS() | |
| − | + | self:assertFalse( | |
| − | + | Protection.new( | |
| − | + | {}, | |
| − | + | makeConfig(), | |
| − | + | mw.title.new('User:My username ends in .js') | |
| − | + | ):isUserScript() | |
| − | + | ) | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
end | end | ||
| − | + | function suite:testProtectionIsUserScriptWithSubpageContainingCSS() | |
| + | self:assertFalse( | ||
| + | Protection.new( | ||
| + | {}, | ||
| + | makeConfig(), | ||
| + | mw.title.new('User:Example/common.css.txt') | ||
| + | ):isUserScript() | ||
| + | ) | ||
| + | end | ||
| − | function suite: | + | function suite:testProtectionIsUserScriptWithNoSubpagePrefix() |
| − | + | self:assertTrue( | |
| − | + | Protection.new( | |
| − | + | {}, | |
| + | makeConfig(), | ||
| + | mw.title.new('User:Example/.css') | ||
| + | ):isUserScript() | ||
| + | ) | ||
end | end | ||
| − | function suite: | + | function suite:testProtectionIsUserScriptWithBlankUsernameAndNoSubpagePrefix() |
| − | + | self:assertTrue( | |
| − | + | Protection.new( | |
| − | + | {}, | |
| + | makeConfig(), | ||
| + | mw.title.new('User:/.css') | ||
| + | ):isUserScript() | ||
| + | ) | ||
end | end | ||
| − | + | function suite:testProtectionIsUserScriptWhenUsernameIsOnlyCSS() | |
| − | + | self:assertFalse( | |
| − | function suite: | + | Protection.new( |
| − | + | {}, | |
| − | + | makeConfig(), | |
| − | + | mw.title.new('User:.css') | |
| + | ):isUserScript() | ||
| + | ) | ||
end | end | ||
| − | function suite: | + | function suite:testProtectionIsUserScriptWithNonstandardCSSContentModel() |
| − | + | self:assertTrue( | |
| − | + | Protection.new( | |
| − | + | {}, | |
| + | makeConfig(), | ||
| + | makeTitleObject{page='User:Example/foo', contentModel='css'} | ||
| + | ):isUserScript() | ||
| + | ) | ||
end | end | ||
| − | function suite: | + | function suite:testProtectionIsUserScriptWithNonstandardJSContentModel() |
| − | + | self:assertTrue( | |
| − | + | Protection.new( | |
| − | + | {}, | |
| + | makeConfig(), | ||
| + | makeTitleObject{page='User:Example/foo', contentModel='javascript'} | ||
| + | ):isUserScript() | ||
| + | ) | ||
end | end | ||
| − | + | function suite:testProtectionIsUserScriptWithNonstandardWikitextContentModel() | |
| + | self:assertFalse( | ||
| + | Protection.new( | ||
| + | {}, | ||
| + | makeConfig(), | ||
| + | makeTitleObject{page='User:Example/foo.css', contentModel='wikitext'} | ||
| + | ):isUserScript() | ||
| + | ) | ||
| + | end | ||
| − | function suite: | + | function suite:testProtectionIsUserScriptWithNonUserspacePage() |
| − | + | self:assertFalse( | |
| − | + | Protection.new( | |
| − | + | {}, | |
| − | + | makeConfig(), | |
| − | + | makeTitleObject{page='Wikipedia:Example.css', contentModel='css'} | |
| − | + | ):isUserScript() | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
) | ) | ||
end | end | ||
| − | function suite: | + | -- isProtected |
| − | + | ||
| − | local | + | function suite:testProtectionIsProtectedTrue() |
| − | + | local obj = makeDefaultProtectionObject() | |
| − | + | obj.level = 'autoconfirmed' | |
| − | + | self:assertTrue(obj:isProtected()) | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | self: | ||
| − | |||
| − | |||
| − | |||
| − | |||
end | end | ||
| − | function suite: | + | function suite:testProtectionIsProtectedFalse() |
| − | + | local obj = makeDefaultProtectionObject() | |
| − | -- | + | obj.level = '*' |
| − | local | + | self:assertFalse(obj:isProtected()) |
| − | + | end | |
| − | + | ||
| − | + | -- shouldShowLock | |
| − | + | ||
| − | + | function suite:testProtectionShouldShowLockWithProtectedPage() | |
| − | + | local obj = Protection.new( | |
| − | + | {}, | |
| − | + | makeConfig(), | |
| − | + | makeTitleObject{page='Foo', edit='sysop'} | |
| − | + | ) | |
| − | + | self:assertTrue(obj:shouldShowLock()) | |
| − | + | end | |
| − | + | ||
| − | + | function suite:testProtectionShouldShowLockWithProtectedUserScript() | |
| + | local obj = Protection.new( | ||
| + | {}, | ||
| + | makeConfig(), | ||
| + | makeTitleObject{page='User:Example/common.css', contentModel='css', edit='sysop'} | ||
) | ) | ||
| + | self:assertFalse(obj:shouldShowLock()) | ||
end | end | ||
| − | function suite: | + | function suite:testProtectionShouldShowLockWithUnprotectedPage() |
| − | + | local obj = Protection.new( | |
| − | local | + | {}, |
| − | + | makeConfig(), | |
| − | + | makeTitleObject{page='Foo'} | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
) | ) | ||
| + | self:assertFalse(obj:shouldShowLock()) | ||
end | end | ||
| − | function suite: | + | -- shouldHaveProtectionCategory |
| − | + | ||
| − | local | + | function suite:testProtectionShouldHaveProtectionCategoryWithProtectedPage() |
| − | + | local obj = Protection.new( | |
| − | + | {}, | |
| − | + | makeConfig(), | |
| − | + | makeTitleObject{page='Foo', edit='sysop'} | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
) | ) | ||
| + | self:assertTrue(obj:shouldHaveProtectionCategory()) | ||
end | end | ||
| − | function suite: | + | function suite:testProtectionShouldHaveProtectionCategoryWithProtectedUserScript() |
| − | + | local obj = Protection.new( | |
| − | + | {}, | |
| − | + | makeConfig(), | |
| − | + | makeTitleObject{page='User:Example/common.css', contentModel='css', edit='sysop'} | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
) | ) | ||
| + | self:assertFalse(obj:shouldHaveProtectionCategory()) | ||
end | end | ||
| − | function suite: | + | function suite:testProtectionShouldHaveProtectionCategoryWithUnprotectedPage() |
| − | + | local obj = Protection.new( | |
| − | local | + | {}, |
| − | + | makeConfig(), | |
| − | + | makeTitleObject{page='Foo'} | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
) | ) | ||
| + | self:assertFalse(obj:shouldHaveProtectionCategory()) | ||
end | end | ||
| − | function suite: | + | -- isTemporary |
| − | + | ||
| − | local | + | function suite:testProtectionIsProtectedTrue() |
| − | + | local obj = makeDefaultProtectionObject() | |
| − | + | obj.expiry = 123456789012 | |
| − | + | self:assertTrue(obj:isTemporary()) | |
| − | local obj = makeDefaultProtectionObject | + | end |
| − | + | ||
| − | + | function suite:testProtectionIsProtectedFalse1() | |
| − | self: | + | local obj = makeDefaultProtectionObject() |
| − | + | obj.expiry = 'indef' | |
| − | + | self:assertFalse(obj:isTemporary()) | |
| − | |||
| − | |||
end | end | ||
| − | function suite: | + | function suite:testProtectionIsProtectedFalse2() |
| − | -- Test that | + | local obj = makeDefaultProtectionObject() |
| − | local protectionCategories = { | + | obj.expiry = nil |
| − | [ | + | self:assertFalse(obj:isTemporary()) |
| − | [ | + | end |
| + | |||
| + | -- makeProtectionCategory | ||
| + | -- | ||
| + | function suite:testProtectionCategoryWithUnprotectedPage() | ||
| + | local obj = Protection.new( | ||
| + | {}, | ||
| + | makeConfig(), | ||
| + | makeTitleObject{page='Foo'} | ||
| + | ) | ||
| + | self:assertEquals(obj:makeProtectionCategory(), '') | ||
| + | end | ||
| + | |||
| + | function suite:testProtectionCategoryPrecedence1() | ||
| + | -- Test that expiry has the lowest priority. | ||
| + | local protectionCategories = { | ||
| + | [makeDefaultProtectionCategoryKey{expiry = 'all'}] = 'all expiries allowed', | ||
| + | [makeDefaultProtectionCategoryKey{namespace = 'all'}] = 'all namespaces allowed', | ||
| + | [makeDefaultProtectionCategoryKey{reason = 'all'}] = 'all reasons allowed', | ||
| + | [makeDefaultProtectionCategoryKey{level = 'all'}] = 'all levels allowed', | ||
| + | [makeDefaultProtectionCategoryKey{action = 'all'}] = 'all actions allowed' | ||
} | } | ||
local obj = makeDefaultProtectionObject{ | local obj = makeDefaultProtectionObject{ | ||
| Line 708: | Line 762: | ||
} | } | ||
self:assertStringContains( | self:assertStringContains( | ||
| − | ' | + | 'all expiries allowed', |
obj:makeProtectionCategory(), | obj:makeProtectionCategory(), | ||
true | true | ||
| Line 714: | Line 768: | ||
end | end | ||
| − | function suite: | + | function suite:testProtectionCategoryPrecedence2() |
| − | -- Test that | + | -- Test that reason has the highest priority. |
local protectionCategories = { | local protectionCategories = { | ||
| − | [makeProtectionCategoryKey{ | + | [makeProtectionCategoryKey{expiry = d.expiryFragment}] = 'expiry only', |
| − | [makeProtectionCategoryKey | + | [makeProtectionCategoryKey{namespace = d.namespaceFragment}] = 'namespace only', |
| + | [makeProtectionCategoryKey{reason = d.reason}] = 'reason only', | ||
| + | [makeProtectionCategoryKey{level = d.level}] = 'level only', | ||
| + | [makeProtectionCategoryKey{action = d.action}] = 'action only' | ||
} | } | ||
local obj = makeDefaultProtectionObject{ | local obj = makeDefaultProtectionObject{ | ||
| Line 724: | Line 781: | ||
} | } | ||
self:assertStringContains( | self:assertStringContains( | ||
| − | ' | + | 'reason only', |
obj:makeProtectionCategory(), | obj:makeProtectionCategory(), | ||
true | true | ||
| Line 730: | Line 787: | ||
end | end | ||
| − | function suite: | + | function suite:testProtectionCategoryPrecedence3() |
| − | -- Test that | + | -- Test that namespace has the highest priority if the reason is set in |
| + | -- cfg.reasonsWithNamespacePriority. | ||
local protectionCategories = { | local protectionCategories = { | ||
| − | [makeProtectionCategoryKey | + | [makeProtectionCategoryKey{expiry = d.expiryFragment}] = 'expiry only', |
| + | [makeProtectionCategoryKey{namespace = d.namespaceFragment}] = 'namespace only', | ||
| + | [makeProtectionCategoryKey{reason = d.reason}] = 'reason only', | ||
| + | [makeProtectionCategoryKey{level = d.level}] = 'level only', | ||
| + | [makeProtectionCategoryKey{action = d.action}] = 'action only' | ||
} | } | ||
local obj = makeDefaultProtectionObject{ | local obj = makeDefaultProtectionObject{ | ||
protectionCategories = protectionCategories, | protectionCategories = protectionCategories, | ||
| + | reasonsWithNamespacePriority = {[d.reason] = true} | ||
} | } | ||
self:assertStringContains( | self:assertStringContains( | ||
| − | ' | + | 'namespace only', |
obj:makeProtectionCategory(), | obj:makeProtectionCategory(), | ||
true | true | ||
| Line 745: | Line 808: | ||
end | end | ||
| − | function suite: | + | function suite:testProtectionCategoryPrecedence4() |
| − | -- Test that | + | -- Test that level has a higher priority than namespace. |
local protectionCategories = { | local protectionCategories = { | ||
| − | [ | + | [makeDefaultProtectionCategoryKey{namespace = 'all'}] = 'all namespaces allowed', |
| − | + | [makeDefaultProtectionCategoryKey{level = 'all'}] = 'all levels allowed', | |
| − | [ | + | } |
| − | |||
| − | |||
| − | |||
| − | } | ||
local obj = makeDefaultProtectionObject{ | local obj = makeDefaultProtectionObject{ | ||
protectionCategories = protectionCategories, | protectionCategories = protectionCategories, | ||
} | } | ||
self:assertStringContains( | self:assertStringContains( | ||
| − | ' | + | 'all namespaces allowed', |
obj:makeProtectionCategory(), | obj:makeProtectionCategory(), | ||
true | true | ||
| Line 765: | Line 824: | ||
end | end | ||
| − | function suite: | + | function suite:testProtectionCategoryPrecedence5() |
| − | -- Test that | + | -- Test that action has a higher priority than level. |
local protectionCategories = { | local protectionCategories = { | ||
| − | [ | + | [makeDefaultProtectionCategoryKey{level = 'all'}] = 'all levels allowed', |
| + | [makeDefaultProtectionCategoryKey{action = 'all'}] = 'all actions allowed', | ||
} | } | ||
local obj = makeDefaultProtectionObject{ | local obj = makeDefaultProtectionObject{ | ||
| Line 774: | Line 834: | ||
} | } | ||
self:assertStringContains( | self:assertStringContains( | ||
| − | ' | + | 'all levels allowed', |
| − | obj:makeProtectionCategory() | + | obj:makeProtectionCategory(), |
| + | true | ||
) | ) | ||
end | end | ||
| − | function suite: | + | function suite:testProtectionCategoryPrecedence6() |
| − | -- Test that | + | -- Test that an exact match will be first. |
local protectionCategories = { | local protectionCategories = { | ||
| − | [ | + | [makeDefaultProtectionCategoryKey()] = 'exact match', |
| + | [makeDefaultProtectionCategoryKey{action = 'all'}] = 'all actions allowed', | ||
| + | } | ||
| + | local obj = makeDefaultProtectionObject{ | ||
| + | protectionCategories = protectionCategories, | ||
} | } | ||
| − | + | self:assertStringContains( | |
| − | + | 'exact match', | |
| − | + | obj:makeProtectionCategory(), | |
| − | + | true | |
) | ) | ||
| − | |||
end | end | ||
| − | function suite: | + | function suite:testProtectionCategoryPrecedence7() |
| − | -- Test that | + | -- Test that matching 4 keys will come before matching 3 keys |
| − | + | local protectionCategories = { | |
| − | local obj = makeDefaultProtectionObject | + | [makeDefaultProtectionCategoryKey{action = 'all'}] = 'four keys', |
| − | self: | + | [makeDefaultProtectionCategoryKey{action = 'all', level = 'all'}] = 'three keys', |
| + | } | ||
| + | local obj = makeDefaultProtectionObject{ | ||
| + | protectionCategories = protectionCategories, | ||
| + | } | ||
| + | self:assertStringContains( | ||
| + | 'four keys', | ||
| + | obj:makeProtectionCategory(), | ||
| + | true | ||
| + | ) | ||
end | end | ||
| − | function suite: | + | function suite:testProtectionCategoryPrecedence8() |
| − | -- Test that | + | -- Test that matching 3 keys will come before matching 2 keys |
local protectionCategories = { | local protectionCategories = { | ||
| − | [makeProtectionCategoryKey{ | + | [makeProtectionCategoryKey{reason = d.reason, action = d.action, level = d.level}] = 'three keys', |
| + | [makeProtectionCategoryKey{reason = d.reason, action = d.action}] = 'two keys', | ||
| + | } | ||
| + | local obj = makeDefaultProtectionObject{ | ||
| + | protectionCategories = protectionCategories, | ||
} | } | ||
| − | + | self:assertStringContains( | |
| − | + | 'three keys', | |
| − | + | obj:makeProtectionCategory(), | |
| − | + | true | |
| − | |||
| − | |||
| − | |||
) | ) | ||
| − | |||
| − | |||
end | end | ||
| − | function suite: | + | function suite:testProtectionCategoryPrecedence9() |
| − | -- Test that | + | -- Test that matching 2 keys will come before matching 1 key |
local protectionCategories = { | local protectionCategories = { | ||
| − | [makeProtectionCategoryKey{ | + | [makeProtectionCategoryKey{action = d.action, level = d.level}] = 'two keys', |
| + | [makeProtectionCategoryKey{action = d.action}] = 'one key', | ||
| + | } | ||
| + | local obj = makeDefaultProtectionObject{ | ||
| + | protectionCategories = protectionCategories, | ||
} | } | ||
| − | + | self:assertStringContains( | |
| − | + | 'two keys', | |
| − | + | obj:makeProtectionCategory(), | |
| − | + | true | |
| − | |||
| − | |||
) | ) | ||
| − | |||
| − | |||
end | end | ||
| − | function suite: | + | function suite:testProtectionCategoryPrecedence10() |
| − | -- Test that | + | -- Test that matching 1 keys will come before matching 0 keys |
local protectionCategories = { | local protectionCategories = { | ||
| − | [makeProtectionCategoryKey{ | + | [makeProtectionCategoryKey{action = d.action}] = 'one key', |
| − | [makeProtectionCategoryKey | + | [makeProtectionCategoryKey()] = 'no keys', |
| − | + | } | |
| + | local obj = makeDefaultProtectionObject{ | ||
| + | protectionCategories = protectionCategories, | ||
} | } | ||
| − | + | self:assertStringContains( | |
| − | + | 'one key', | |
| − | + | obj:makeProtectionCategory(), | |
| − | + | true | |
) | ) | ||
| − | |||
end | end | ||
| − | function suite: | + | function suite:testProtectionCategoryAllAlls() |
| − | -- Test that | + | -- Test that 'all|all|all|all|all' works |
local protectionCategories = { | local protectionCategories = { | ||
| − | [makeProtectionCategoryKey | + | [makeProtectionCategoryKey()] = 'no keys', |
| + | } | ||
| + | local obj = makeDefaultProtectionObject{ | ||
| + | protectionCategories = protectionCategories, | ||
} | } | ||
| − | + | self:assertStringContains( | |
| − | + | 'no keys', | |
| − | + | obj:makeProtectionCategory(), | |
| − | + | true | |
| − | |||
| − | |||
| − | |||
) | ) | ||
| − | |||
end | end | ||
| − | function suite: | + | function suite:testProtectionCategoryNoFalseMatches() |
| − | -- Test that | + | -- Test that we don't match things that we aren't supposed to. |
local protectionCategories = { | local protectionCategories = { | ||
| − | [makeProtectionCategoryKey{namespace = ' | + | [makeProtectionCategoryKey{expiry = 'foo'}] = 'expiry foo', |
| + | [makeProtectionCategoryKey{namespace = 'foo'}] = 'namespace foo', | ||
| + | [makeProtectionCategoryKey{reason = 'foo'}] = 'reason foo', | ||
| + | [makeProtectionCategoryKey{level = 'foo'}] = 'level foo', | ||
| + | [makeProtectionCategoryKey{action = 'foo'}] = 'action foo', | ||
| + | [makeProtectionCategoryKey()] = 'no keys', | ||
} | } | ||
| − | local obj = | + | local obj = makeDefaultProtectionObject{ |
| − | + | protectionCategories = protectionCategories, | |
| − | + | } | |
| − | + | self:assertStringContains( | |
| + | 'no keys', | ||
| + | obj:makeProtectionCategory(), | ||
| + | true | ||
) | ) | ||
| − | |||
end | end | ||
| − | + | function suite:testProtectionCategoryProtected() | |
| − | + | -- Test that protected pages produce some kind of category link. | |
| − | function suite: | + | local protectionCategories = { |
| − | local | + | [makeProtectionCategoryKey()] = 'no keys', |
| − | obj | + | } |
| − | self: | + | local obj = makeDefaultProtectionObject{ |
| − | obj: | + | protectionCategories = protectionCategories, |
| − | + | } | |
| + | self:assertStringContains( | ||
| + | '^%[%[Category:.*%]%]$', | ||
| + | obj:makeProtectionCategory() | ||
) | ) | ||
end | end | ||
| − | function suite: | + | function suite:testProtectionCategoryNotProtected() |
| − | local | + | -- Test that unprotected pages produce the blank string. |
| − | + | local protectionCategories = { | |
| − | obj | + | [makeProtectionCategoryKey()] = 'no keys', |
| − | + | } | |
| − | + | local obj = Protection.new( | |
| − | + | {}, | |
| − | ' | + | makeConfig{protectionCategories = protectionCategories}, |
| + | makeTitleObject{page = d.page, 'edit', nil} | ||
) | ) | ||
| + | self:assertEquals('', obj:makeProtectionCategory()) | ||
end | end | ||
| − | function suite: | + | function suite:testProtectionCategoryNoMatch() |
| + | -- Test that protected pages that don't match any categories | ||
| + | -- produce the blank string. | ||
local obj = makeDefaultProtectionObject() | local obj = makeDefaultProtectionObject() | ||
| − | + | self:assertEquals('', obj:makeProtectionCategory()) | |
| − | |||
| − | |||
| − | |||
| − | self: | ||
| − | |||
| − | |||
| − | |||
end | end | ||
| − | function suite: | + | function suite:testProtectionCategoryExpiryIndef() |
| + | -- Test that indefinite protection matches the "indef" expiry fragment. | ||
local obj = makeDefaultProtectionObject() | local obj = makeDefaultProtectionObject() | ||
| − | obj.expiry = | + | obj._cfg.protectionCategories = { |
| − | + | [makeProtectionCategoryKey{expiry = 'indef', action = 'autoreview'}] = 'indef expiry', | |
| − | obj. | + | } |
| − | obj. | + | obj.action = 'autoreview' |
| − | obj. | + | obj.level = 'autoconfirmed' |
| − | self: | + | obj.expiry = 'indef' |
| − | + | self:assertStringContains('indef expiry', obj:makeProtectionCategory(), true) | |
| − | |||
| − | |||
end | end | ||
| − | function suite: | + | function suite:testProtectionCategoryExpiryTemp() |
| + | -- Test that temporary protection matches the "temp" expiry fragment. | ||
local obj = makeDefaultProtectionObject() | local obj = makeDefaultProtectionObject() | ||
| − | obj.expiry = | + | obj._cfg.protectionCategories = { |
| − | obj.action = ' | + | [makeProtectionCategoryKey{expiry = 'temp', action = 'autoreview'}] = 'temporary expiry', |
| − | obj. | + | } |
| − | self: | + | obj.action = 'autoreview' |
| − | + | obj.level = 'autoconfirmed' | |
| − | + | obj.expiry = d.expiryU | |
| − | + | self:assertStringContains('temporary expiry', obj:makeProtectionCategory(), true) | |
end | end | ||
| − | function suite: | + | function suite:testProtectionCategoryNoExpiry() |
| − | local | + | -- Test that pages with no expiry set don't match "indef" or "temp". |
| − | + | local protectionCategories = { | |
| − | + | [makeProtectionCategoryKey{expiry = 'temp', action = 'autoreview' }] = 'temporary expiry', | |
| − | + | [makeProtectionCategoryKey{expiry = 'indef', action = 'autoreview' }] = 'indefinite expiry', | |
| − | + | [makeProtectionCategoryKey()] = 'no matches' | |
| − | obj. | + | } |
| − | + | local obj = Protection.new( | |
| − | + | {}, | |
| − | + | makeConfig{protectionCategories = protectionCategories}, | |
| − | + | makeProtectedTitleObject() | |
) | ) | ||
| + | self:assertStringContains('no matches', obj:makeProtectionCategory(), true) | ||
end | end | ||
| − | -- isIncorrect | + | function suite:testProtectionCategoryNamespaceFragment() |
| − | + | -- Test that values in cfg.categoryNamespaceKeys will work. | |
| − | function suite:testProtectionIsIncorrectTrue1() | + | local protectionCategories = { |
| + | [makeProtectionCategoryKey{namespace = 'foobar'}] = 'we found a match', | ||
| + | } | ||
| + | local obj = Protection.new( | ||
| + | {}, | ||
| + | makeConfig{ | ||
| + | protectionCategories = protectionCategories, | ||
| + | categoryNamespaceKeys = {[10] = 'foobar'} -- Template namespace | ||
| + | }, | ||
| + | makeTitleObject{page = 'Template:Foo', edit = 'autoconfirmed'} | ||
| + | ) | ||
| + | self:assertStringContains('we found a match', obj:makeProtectionCategory(), true) | ||
| + | end | ||
| + | |||
| + | function suite:testProtectionCategoryTalk() | ||
| + | -- Test that talk pages match the "talk" namespace fragment. | ||
| + | local protectionCategories = { | ||
| + | [makeProtectionCategoryKey{namespace = 'talk'}] = 'talk namespace', | ||
| + | } | ||
| + | local obj = Protection.new( | ||
| + | {}, | ||
| + | makeConfig{protectionCategories = protectionCategories}, | ||
| + | makeTitleObject{page = 'Template talk:Example', edit = 'autoconfirmed'} | ||
| + | ) | ||
| + | self:assertStringContains('talk namespace', obj:makeProtectionCategory(), true) | ||
| + | end | ||
| + | |||
| + | -- isIncorrect | ||
| + | |||
| + | function suite:testProtectionIsIncorrectTrue1() | ||
local obj = makeDefaultProtectionObject() | local obj = makeDefaultProtectionObject() | ||
function obj:isProtected() | function obj:isProtected() | ||
| Line 1,044: | Line 1,153: | ||
local obj = makeDefaultProtectionObject() | local obj = makeDefaultProtectionObject() | ||
obj._cfg.msg = { | obj._cfg.msg = { | ||
| − | |||
['tracking-category-incorrect'] = 'Incorrect category', | ['tracking-category-incorrect'] = 'Incorrect category', | ||
['tracking-category-template'] = 'Template category' | ['tracking-category-template'] = 'Template category' | ||
| Line 1,051: | Line 1,159: | ||
return '[[Category:Protection category|' .. d.baseText .. ']]' | return '[[Category:Protection category|' .. d.baseText .. ']]' | ||
end | end | ||
| − | for _, field in ipairs{ | + | for _, field in ipairs{'isIncorrect', 'isTemplateProtectedNonTemplate'} do |
obj[field] = function () return true end | obj[field] = function () return true end | ||
end | end | ||
self:assertEquals( | self:assertEquals( | ||
'[[Category:Protection category|' .. d.baseText .. ']]' .. | '[[Category:Protection category|' .. d.baseText .. ']]' .. | ||
| − | |||
'[[Category:Incorrect category|' .. d.baseText .. ']]' .. | '[[Category:Incorrect category|' .. d.baseText .. ']]' .. | ||
'[[Category:Template category|' .. d.baseText .. ']]', | '[[Category:Template category|' .. d.baseText .. ']]', | ||
| Line 1,860: | Line 1,967: | ||
end | end | ||
| − | -- | + | -- renderImage |
| − | + | function suite:testBannerTemplateRenderImageFilename() | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | function suite:testBannerTemplateRenderImageFilename() | ||
local obj = makeDefaultBannerTemplateObject() | local obj = makeDefaultBannerTemplateObject() | ||
obj._imageFilename = 'ImageFilename.png' | obj._imageFilename = 'ImageFilename.png' | ||
| Line 1,904: | Line 1,993: | ||
function suite:testBannerTemplateRenderImageCustomWidth() | function suite:testBannerTemplateRenderImageCustomWidth() | ||
local obj = makeDefaultBannerTemplateObject() | local obj = makeDefaultBannerTemplateObject() | ||
| − | obj. | + | obj.imageWidth = 50 |
self:assertStringContains('50px', obj:renderImage(), true) | self:assertStringContains('50px', obj:renderImage(), true) | ||
end | end | ||
| Line 1,922: | Line 2,011: | ||
function suite:testBannerTemplateRenderImageCaption() | function suite:testBannerTemplateRenderImageCaption() | ||
local obj = makeDefaultBannerTemplateObject() | local obj = makeDefaultBannerTemplateObject() | ||
| − | obj. | + | obj.imageCaption = 'the caption text' |
self:assertStringContains('the caption text', obj:renderImage(), true) | self:assertStringContains('the caption text', obj:renderImage(), true) | ||
end | end | ||
| Line 1,947: | Line 2,036: | ||
local obj = Banner.new(protectionObj, blurbObj, cfg) | local obj = Banner.new(protectionObj, blurbObj, cfg) | ||
| − | self:assertEquals(40, obj. | + | self:assertEquals(40, obj.imageWidth) |
| − | self:assertEquals('the alt text', obj. | + | self:assertEquals('the alt text', obj.imageCaption) |
self:assertEquals('the main text', obj._reasonText) | self:assertEquals('the main text', obj._reasonText) | ||
self:assertEquals('the explanation text', obj._explanationText) | self:assertEquals('the explanation text', obj._explanationText) | ||
| Line 2,003: | Line 2,092: | ||
local obj = Padlock.new(protectionObj, blurbObj, cfg) | local obj = Padlock.new(protectionObj, blurbObj, cfg) | ||
| − | self:assertEquals(20, obj. | + | self:assertEquals(20, obj.imageWidth) |
| − | self:assertEquals('the tooltip text', obj. | + | self:assertEquals('the tooltip text', obj.imageCaption) |
self:assertEquals('the alt text', obj._imageAlt) | self:assertEquals('the alt text', obj._imageAlt) | ||
self:assertEquals('the link text', obj._imageLink) | self:assertEquals('the link text', obj._imageLink) | ||
| Line 2,045: | Line 2,134: | ||
function suite:test_mainError() | function suite:test_mainError() | ||
| − | local args = { | + | local args = {action = 'foobar'} |
local cfg = makeConfig() | local cfg = makeConfig() | ||
| − | local title | + | local title = makeDefaultTitleObject() |
local success, result = pcall(mProtectionBanner._main, args, cfg, title) | local success, result = pcall(mProtectionBanner._main, args, cfg, title) | ||
self:assertFalse(success) | self:assertFalse(success) | ||
self:assertEquals( | self:assertEquals( | ||
| − | 'invalid | + | 'invalid action: foobar', |
result, | result, | ||
false | false | ||
| Line 2,078: | Line 2,167: | ||
end | end | ||
| − | function suite:test_mainLarge1() | + | function suite:test_mainLarge1() |
| − | local args = {} | + | local args = {} |
| − | local cfg = makeConfig() | + | local cfg = makeConfig() |
| − | local title = makeDefaultTitleObject() | + | local title = makeDefaultTitleObject() |
| − | self:assertIsBanner(mProtectionBanner._main(args, cfg, title)) | + | self:assertIsBanner(mProtectionBanner._main(args, cfg, title)) |
| − | end | + | end |
| − | + | ||
| − | function suite:test_mainLarge2() | + | function suite:test_mainLarge2() |
| − | local args = {small = 'no'} | + | local args = {small = 'no'} |
| − | local cfg = makeConfig() | + | local cfg = makeConfig() |
| − | local title = makeDefaultTitleObject() | + | local title = makeDefaultTitleObject() |
| − | self:assertIsBanner(mProtectionBanner._main(args, cfg, title)) | + | self:assertIsBanner(mProtectionBanner._main(args, cfg, title)) |
| − | end | + | end |
| − | + | ||
| − | function suite:test_mainLarge3() | + | function suite:test_mainLarge3() |
| − | local args = {small = 'No'} | + | local args = {small = 'No'} |
| − | local cfg = makeConfig() | + | local cfg = makeConfig() |
| − | local title = makeDefaultTitleObject() | + | local title = makeDefaultTitleObject() |
| − | self:assertIsBanner(mProtectionBanner._main(args, cfg, title)) | + | self:assertIsBanner(mProtectionBanner._main(args, cfg, title)) |
| − | end | + | end |
| − | + | ||
| − | function suite:test_mainLarge4() | + | function suite:test_mainLarge4() |
| − | local args = {small = 'false'} | + | local args = {small = 'false'} |
| − | local cfg = makeConfig() | + | local cfg = makeConfig() |
| − | local title = makeDefaultTitleObject() | + | local title = makeDefaultTitleObject() |
| − | self:assertIsBanner(mProtectionBanner._main(args, cfg, title)) | + | self:assertIsBanner(mProtectionBanner._main(args, cfg, title)) |
| − | end | + | end |
| − | + | ||
| − | function suite:test_mainNoBanner() | + | function suite:test_mainNoBanner() |
| + | local args = {} | ||
| + | local cfg = makeConfig() | ||
| + | local title = makeTitleObject{page = d.page, edit = nil} | ||
| + | self:assertNoBanner(mProtectionBanner._main(args, cfg, title), 'page unprotected') | ||
| + | end | ||
| + | |||
| + | function suite:test_mainNoBannerForUserScripts() | ||
local args = {} | local args = {} | ||
local cfg = makeConfig() | local cfg = makeConfig() | ||
| − | local title = makeTitleObject | + | local title = makeTitleObject{page = 'User:Example/common.css', contentType = 'css'} |
| − | self:assertNoBanner(mProtectionBanner._main(args, cfg, title), 'page | + | self:assertNoBanner(mProtectionBanner._main(args, cfg, title), 'page is a user script') |
end | end | ||
| Line 2,116: | Line 2,212: | ||
local args = {} | local args = {} | ||
local cfg -- Use main config module | local cfg -- Use main config module | ||
| − | local title = makeTitleObject | + | local title = makeTitleObject{page = d.page, 'edit', nil} |
self:assertStringContains( | self:assertStringContains( | ||
'%[%[Category:.-%]%]', | '%[%[Category:.-%]%]', | ||
Latest revision as of 08:29, 27 September 2020
Documentation for this module may be created at Module:Protection banner/testcases/doc
-- Load necessary modules
local mProtectionBanner = require('Module:Protection banner/sandbox')
local ScribuntoUnit = require('Module:ScribuntoUnit')
-- Get the classes
local Protection = mProtectionBanner._exportClasses().Protection
local Blurb = mProtectionBanner._exportClasses().Blurb
local BannerTemplate = mProtectionBanner._exportClasses().BannerTemplate
local Banner = mProtectionBanner._exportClasses().Banner
local Padlock = mProtectionBanner._exportClasses().Padlock
-- Initialise test suite
local 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.page
d.namespaceFragment = 'user' -- namespace fragment of d.page for makeProtectionCategory
d.categoryNamespaceKeys = {[d.namespace] = d.namespaceFragment} -- namespace key config table
d.expiry = '1 January 9999'
d.expiryU = 253370764800 -- d.expiry in Unix time
d.expiryFragment = 'temp' -- expiry fragment of d.expiry for makeProtectionCategory
d.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
end
end
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 = {
edit = {},
move = {},
autoreview = {}
}
for _, action in ipairs{'edit', 'move', 'autoreview'} 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 title
end
local function makeDefaultTitleObject()
return makeTitleObject{page = d.page, [d.action] = d.level}
end
-- Make an alias, to be clear the object is for a protected page.
local makeProtectedTitleObject = makeDefaultTitleObject
local function makeConfig(t)
local cfg = {
masterBanner = {},
padlockIndicatorNames = {},
indefImageReasons = {},
reasonsWithNamespacePriority = {},
categoryNamespaceKeys = {},
protectionCategories = {},
reasonsWithoutExpiryCheck = {},
expiryCheckActions = {},
pagetypes = {},
indefStrings = {},
hierarchy = {
sysop = {},
reviewer = {'sysop'},
filemover = {'sysop'},
templateeditor = {'sysop'},
extendedconfirmed = {'sysop'},
autoconfirmed = {'reviewer', 'filemover', 'templateeditor', 'extendedconfirmed'},
user = {'autoconfirmed'},
['*'] = {'user'}
},
wrappers = {},
msg = {}
}
local protLevelFields = {
'defaultBanners',
'banners',
'protectionBlurbs',
'explanationBlurbs',
'protectionLevels',
'images',
'imageLinks'
}
for _, field in ipairs(protLevelFields) do
cfg[field] = {
edit = {},
move = {},
autoreview = {}
}
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 cfg
end
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(
{d.reason, action = d.action, expiry = d.expiry},
cfg,
makeDefaultTitleObject()
)
obj.expiry = d.expiryU -- Hack to override [[Module:Effective protection expiry]]
return obj
end
local function makeProtectionCategoryKey(testFragments, defaults)
local fragments = {
expiry = 'all',
namespace = 'all',
reason = 'all',
level = 'all',
action = 'all'
}
for i, t in ipairs{defaults or {}, testFragments} do
for k, v in pairs(t) do
fragments[k] = v
end
end
local key = {
fragments.expiry,
fragments.namespace,
fragments.reason,
fragments.level,
fragments.action
}
return table.concat(key, '|')
end
local function makeDefaultProtectionCategoryKey(testFragments)
local defaults = {
expiry = d.expiryFragment,
namespace = d.namespaceFragment,
reason = d.reason,
level = d.level,
action = d.action
}
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
function suite:assertIsPadlock(s, msg)
self:assertStringContains(
'\127[^\127]*UNIQ%-%-indicator%-%x+%-QINU[^\127]*\127',
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,
{{action = 'foo'}, makeConfig()},
'invalid action: foo'
)
end
function suite:testProtectionActionEdit()
local obj = Protection.new({action = 'edit'}, makeConfig())
suite:assertEquals('edit', obj.action)
end
function suite:testProtectionActionMove()
local obj = Protection.new({action = 'move'}, makeConfig())
suite:assertEquals('move', obj.action)
end
function suite:testProtectionActionAutoreview()
local obj = Protection.new({action = 'autoreview'}, makeConfig())
suite:assertEquals('autoreview', obj.action)
end
function suite:testProtectionActionUpload()
local obj = Protection.new({action = 'upload'}, 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(
{action = 'edit'},
makeConfig(),
makeTitleObject{page = 'Foo', edit = 'autoconfirmed'}
)
self:assertEquals('autoconfirmed', obj.level)
end
function suite:testProtectionFull()
local obj = Protection.new(
{action = 'edit'},
makeConfig(),
makeTitleObject{page = 'Foo', edit = 'sysop'}
)
self:assertEquals('sysop', obj.level)
end
function suite:testProtectionUnprotected()
local obj = Protection.new(
{action = 'edit'},
makeConfig(),
makeTitleObject{page = 'Foo', edit = nil}
)
self:assertEquals('*', obj.level)
end
function suite:testProtectionSemiMove()
local obj = Protection.new(
{action = 'move'},
makeConfig(),
makeTitleObject{page = 'Foo', move = 'autoconfirmed'}
)
self:assertEquals('*', obj.level)
end
function suite:testProtectionTemplate()
local obj = Protection.new(
{action = 'edit'},
makeConfig(),
makeTitleObject{page = 'Template:Foo', edit = 'templateeditor'}
)
self:assertEquals('templateeditor', obj.level)
end
function suite:testProtectionTitleBlacklist()
local obj = Protection.new(
{action = 'edit'},
makeConfig(),
makeTitleObject{page = 'Template:Editnotices/Page/Foo', edit = nil}
)
self:assertEquals('templateeditor', obj.level)
end
-- Reason
function suite:testProtectionReason()
local obj = Protection.new(
{'foo'},
makeConfig()
)
self:assertEquals('foo', obj.reason)
end
function suite:testProtectionReasonLowerCase()
local obj = Protection.new(
{'fOO'},
makeConfig()
)
self:assertEquals('foo', obj.reason)
end
function suite:testProtectionBadReason()
self:assertError(
Protection.new,
{{'foo|bar'}, makeConfig()},
'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,
{
{date = 'indefinite'},
makeConfig{indefStrings = {indefinite = true}}
},
'invalid protection date: indefinite'
)
end
function suite:testProtectionProtectionDateTemp()
local obj = Protection.new(
{date = d.protectionDate},
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,
{
{date = 'foobar'},
makeConfig{indefStrings = {indefinite = true}}
},
'invalid protection date: foobar'
)
end
-- bannerConfig
function suite:testProtectionMasterBannerConfigPrecedence1()
local masterBanner = {text = 'master banner text'}
local obj = makeDefaultProtectionObject{masterBanner = masterBanner}
self:assertEquals('master banner text', obj.bannerConfig.text)
end
function suite:testProtectionMasterBannerConfigPrecedence2()
local masterBanner = {text = 'master banner text'}
local defaultBanners = {[d.action] = {default = {text = 'defaultBanners default text'}}}
local obj = makeDefaultProtectionObject(makeConfig{
masterBanner = masterBanner,
defaultBanners = defaultBanners
})
self:assertEquals('defaultBanners default text', obj.bannerConfig.text)
end
function suite:testProtectionMasterBannerConfigPrecedence3()
local defaultBanners = {[d.action] = {
[d.level] = {text = 'defaultBanners level text'},
default = {text = 'defaultBanners default text'}
}}
local obj = makeDefaultProtectionObject(makeConfig{defaultBanners = defaultBanners})
self:assertEquals('defaultBanners level text', obj.bannerConfig.text)
end
function suite:testProtectionMasterBannerConfigPrecedence4()
local defaultBanners = {[d.action] = {
[d.level] = {text = 'defaultBanners level text'}
}}
local banners = {[d.action] ={
[d.reason] = {text = 'banners text'}
}}
local obj = makeDefaultProtectionObject(makeConfig{
defaultBanners = defaultBanners,
banners = banners
})
self:assertEquals('banners text', obj.bannerConfig.text)
end
function suite:testProtectionMasterBannerConfigFields()
local masterBanner = {
text = 'master banner text',
explanation = 'master banner explanation',
tooltip = 'master banner tooltip',
alt = 'master banner alt',
link = 'master banner link',
image = 'master banner image'
}
local obj = makeDefaultProtectionObject{masterBanner = masterBanner}
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{page='User:Example/foo', contentModel='css'}
):isUserScript()
)
end
function suite:testProtectionIsUserScriptWithNonstandardJSContentModel()
self:assertTrue(
Protection.new(
{},
makeConfig(),
makeTitleObject{page='User:Example/foo', contentModel='javascript'}
):isUserScript()
)
end
function suite:testProtectionIsUserScriptWithNonstandardWikitextContentModel()
self:assertFalse(
Protection.new(
{},
makeConfig(),
makeTitleObject{page='User:Example/foo.css', contentModel='wikitext'}
):isUserScript()
)
end
function suite:testProtectionIsUserScriptWithNonUserspacePage()
self:assertFalse(
Protection.new(
{},
makeConfig(),
makeTitleObject{page='Wikipedia:Example.css', contentModel='css'}
):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{page='Foo', edit='sysop'}
)
self:assertTrue(obj:shouldShowLock())
end
function suite:testProtectionShouldShowLockWithProtectedUserScript()
local obj = Protection.new(
{},
makeConfig(),
makeTitleObject{page='User:Example/common.css', contentModel='css', edit='sysop'}
)
self:assertFalse(obj:shouldShowLock())
end
function suite:testProtectionShouldShowLockWithUnprotectedPage()
local obj = Protection.new(
{},
makeConfig(),
makeTitleObject{page='Foo'}
)
self:assertFalse(obj:shouldShowLock())
end
-- shouldHaveProtectionCategory
function suite:testProtectionShouldHaveProtectionCategoryWithProtectedPage()
local obj = Protection.new(
{},
makeConfig(),
makeTitleObject{page='Foo', edit='sysop'}
)
self:assertTrue(obj:shouldHaveProtectionCategory())
end
function suite:testProtectionShouldHaveProtectionCategoryWithProtectedUserScript()
local obj = Protection.new(
{},
makeConfig(),
makeTitleObject{page='User:Example/common.css', contentModel='css', edit='sysop'}
)
self:assertFalse(obj:shouldHaveProtectionCategory())
end
function suite:testProtectionShouldHaveProtectionCategoryWithUnprotectedPage()
local obj = Protection.new(
{},
makeConfig(),
makeTitleObject{page='Foo'}
)
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{page='Foo'}
)
self:assertEquals(obj:makeProtectionCategory(), '')
end
function suite:testProtectionCategoryPrecedence1()
-- Test that expiry has the lowest priority.
local protectionCategories = {
[makeDefaultProtectionCategoryKey{expiry = 'all'}] = 'all expiries allowed',
[makeDefaultProtectionCategoryKey{namespace = 'all'}] = 'all namespaces allowed',
[makeDefaultProtectionCategoryKey{reason = 'all'}] = 'all reasons allowed',
[makeDefaultProtectionCategoryKey{level = 'all'}] = 'all levels allowed',
[makeDefaultProtectionCategoryKey{action = 'all'}] = 'all actions allowed'
}
local obj = makeDefaultProtectionObject{
protectionCategories = protectionCategories,
}
self:assertStringContains(
'all expiries allowed',
obj:makeProtectionCategory(),
true
)
end
function suite:testProtectionCategoryPrecedence2()
-- Test that reason has the highest priority.
local protectionCategories = {
[makeProtectionCategoryKey{expiry = d.expiryFragment}] = 'expiry only',
[makeProtectionCategoryKey{namespace = d.namespaceFragment}] = 'namespace only',
[makeProtectionCategoryKey{reason = d.reason}] = 'reason only',
[makeProtectionCategoryKey{level = d.level}] = 'level only',
[makeProtectionCategoryKey{action = d.action}] = 'action only'
}
local obj = makeDefaultProtectionObject{
protectionCategories = protectionCategories,
}
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 = {
[makeProtectionCategoryKey{expiry = d.expiryFragment}] = 'expiry only',
[makeProtectionCategoryKey{namespace = d.namespaceFragment}] = 'namespace only',
[makeProtectionCategoryKey{reason = d.reason}] = 'reason only',
[makeProtectionCategoryKey{level = d.level}] = 'level only',
[makeProtectionCategoryKey{action = d.action}] = 'action only'
}
local obj = makeDefaultProtectionObject{
protectionCategories = protectionCategories,
reasonsWithNamespacePriority = {[d.reason] = true}
}
self:assertStringContains(
'namespace only',
obj:makeProtectionCategory(),
true
)
end
function suite:testProtectionCategoryPrecedence4()
-- Test that level has a higher priority than namespace.
local protectionCategories = {
[makeDefaultProtectionCategoryKey{namespace = 'all'}] = 'all namespaces allowed',
[makeDefaultProtectionCategoryKey{level = 'all'}] = 'all levels allowed',
}
local obj = makeDefaultProtectionObject{
protectionCategories = protectionCategories,
}
self:assertStringContains(
'all namespaces allowed',
obj:makeProtectionCategory(),
true
)
end
function suite:testProtectionCategoryPrecedence5()
-- Test that action has a higher priority than level.
local protectionCategories = {
[makeDefaultProtectionCategoryKey{level = 'all'}] = 'all levels allowed',
[makeDefaultProtectionCategoryKey{action = 'all'}] = 'all actions allowed',
}
local obj = makeDefaultProtectionObject{
protectionCategories = protectionCategories,
}
self:assertStringContains(
'all levels allowed',
obj:makeProtectionCategory(),
true
)
end
function suite:testProtectionCategoryPrecedence6()
-- Test that an exact match will be first.
local protectionCategories = {
[makeDefaultProtectionCategoryKey()] = 'exact match',
[makeDefaultProtectionCategoryKey{action = 'all'}] = 'all actions allowed',
}
local obj = makeDefaultProtectionObject{
protectionCategories = protectionCategories,
}
self:assertStringContains(
'exact match',
obj:makeProtectionCategory(),
true
)
end
function suite:testProtectionCategoryPrecedence7()
-- Test that matching 4 keys will come before matching 3 keys
local protectionCategories = {
[makeDefaultProtectionCategoryKey{action = 'all'}] = 'four keys',
[makeDefaultProtectionCategoryKey{action = 'all', level = 'all'}] = 'three keys',
}
local obj = makeDefaultProtectionObject{
protectionCategories = protectionCategories,
}
self:assertStringContains(
'four keys',
obj:makeProtectionCategory(),
true
)
end
function suite:testProtectionCategoryPrecedence8()
-- Test that matching 3 keys will come before matching 2 keys
local protectionCategories = {
[makeProtectionCategoryKey{reason = d.reason, action = d.action, level = d.level}] = 'three keys',
[makeProtectionCategoryKey{reason = d.reason, action = d.action}] = 'two keys',
}
local obj = makeDefaultProtectionObject{
protectionCategories = protectionCategories,
}
self:assertStringContains(
'three keys',
obj:makeProtectionCategory(),
true
)
end
function suite:testProtectionCategoryPrecedence9()
-- Test that matching 2 keys will come before matching 1 key
local protectionCategories = {
[makeProtectionCategoryKey{action = d.action, level = d.level}] = 'two keys',
[makeProtectionCategoryKey{action = d.action}] = 'one key',
}
local obj = makeDefaultProtectionObject{
protectionCategories = protectionCategories,
}
self:assertStringContains(
'two keys',
obj:makeProtectionCategory(),
true
)
end
function suite:testProtectionCategoryPrecedence10()
-- Test that matching 1 keys will come before matching 0 keys
local protectionCategories = {
[makeProtectionCategoryKey{action = d.action}] = 'one key',
[makeProtectionCategoryKey()] = 'no keys',
}
local obj = makeDefaultProtectionObject{
protectionCategories = protectionCategories,
}
self:assertStringContains(
'one key',
obj:makeProtectionCategory(),
true
)
end
function suite:testProtectionCategoryAllAlls()
-- Test that 'all|all|all|all|all' works
local protectionCategories = {
[makeProtectionCategoryKey()] = 'no keys',
}
local obj = makeDefaultProtectionObject{
protectionCategories = protectionCategories,
}
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 = {
[makeProtectionCategoryKey{expiry = 'foo'}] = 'expiry foo',
[makeProtectionCategoryKey{namespace = 'foo'}] = 'namespace foo',
[makeProtectionCategoryKey{reason = 'foo'}] = 'reason foo',
[makeProtectionCategoryKey{level = 'foo'}] = 'level foo',
[makeProtectionCategoryKey{action = 'foo'}] = 'action foo',
[makeProtectionCategoryKey()] = 'no keys',
}
local obj = makeDefaultProtectionObject{
protectionCategories = protectionCategories,
}
self:assertStringContains(
'no keys',
obj:makeProtectionCategory(),
true
)
end
function suite:testProtectionCategoryProtected()
-- Test that protected pages produce some kind of category link.
local protectionCategories = {
[makeProtectionCategoryKey()] = 'no keys',
}
local obj = makeDefaultProtectionObject{
protectionCategories = protectionCategories,
}
self:assertStringContains(
'^%[%[Category:.*%]%]$',
obj:makeProtectionCategory()
)
end
function suite:testProtectionCategoryNotProtected()
-- Test that unprotected pages produce the blank string.
local protectionCategories = {
[makeProtectionCategoryKey()] = 'no keys',
}
local obj = Protection.new(
{},
makeConfig{protectionCategories = protectionCategories},
makeTitleObject{page = d.page, 'edit', nil}
)
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 = {
[makeProtectionCategoryKey{expiry = 'indef', action = 'autoreview'}] = 'indef expiry',
}
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 = {
[makeProtectionCategoryKey{expiry = 'temp', action = 'autoreview'}] = 'temporary expiry',
}
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 = {
[makeProtectionCategoryKey{expiry = 'temp', action = 'autoreview' }] = 'temporary expiry',
[makeProtectionCategoryKey{expiry = 'indef', action = 'autoreview' }] = 'indefinite expiry',
[makeProtectionCategoryKey()] = 'no matches'
}
local obj = Protection.new(
{},
makeConfig{protectionCategories = protectionCategories},
makeProtectedTitleObject()
)
self:assertStringContains('no matches', obj:makeProtectionCategory(), true)
end
function suite:testProtectionCategoryNamespaceFragment()
-- Test that values in cfg.categoryNamespaceKeys will work.
local protectionCategories = {
[makeProtectionCategoryKey{namespace = 'foobar'}] = 'we found a match',
}
local obj = Protection.new(
{},
makeConfig{
protectionCategories = protectionCategories,
categoryNamespaceKeys = {[10] = 'foobar'} -- Template namespace
},
makeTitleObject{page = 'Template:Foo', edit = 'autoconfirmed'}
)
self:assertStringContains('we found a match', obj:makeProtectionCategory(), true)
end
function suite:testProtectionCategoryTalk()
-- Test that talk pages match the "talk" namespace fragment.
local protectionCategories = {
[makeProtectionCategoryKey{namespace = 'talk'}] = 'talk namespace',
}
local obj = Protection.new(
{},
makeConfig{protectionCategories = protectionCategories},
makeTitleObject{page = 'Template talk:Example', edit = 'autoconfirmed'}
)
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 = 'templatemoveor'
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 = 'templatemoveor'
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 = {
['tracking-category-incorrect'] = 'Incorrect category',
['tracking-category-template'] = 'Template category'
}
function obj:makeProtectionCategory()
return '[[Category:Protection category|' .. d.baseText .. ']]'
end
for _, field in ipairs{'isIncorrect', 'isTemplateProtectedNonTemplate'} do
obj[field] = function () return true end
end
self:assertEquals(
'[[Category:Protection category|' .. d.baseText .. ']]' ..
'[[Category:Incorrect category|' .. d.baseText .. ']]' ..
'[[Category:Template category|' .. d.baseText .. ']]',
obj:makeCategoryLinks()
)
end
function suite:testProtectionMakeCategoryLinksAllAbsent()
local obj = makeDefaultProtectionObject()
obj._cfg.msg = {
['tracking-category-expiry'] = 'Expiry category',
['tracking-category-incorrect'] = 'Incorrect category',
['tracking-category-template'] = 'Template category'
}
function obj:makeProtectionCategory()
return ''
end
for _, field in ipairs{'needsExpiry', 'isIncorrect', 'isTemplateProtectedNonTemplate'} do
obj[field] = function () return false end
end
self:assertEquals('', obj:makeCategoryLinks())
end
--------------------------------------------------------------------------------
-- Blurb class tests
--------------------------------------------------------------------------------
-- initialize
function suite:testBlurbNew()
local obj = Blurb.new({'foo'}, {'bar'}, {'baz'})
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{msg = {['expiry-date-format'] = 'Y Y F F j'}}
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 = {['test-key'] = 'test message'}
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 = '${CURRENTVERSION}-' ..
'${EDITREQUEST}-' ..
'${EXPIRY}-' ..
'${EXPLANATIONBLURB}-' ..
'${IMAGELINK}-' ..
'${INTROBLURB}-' ..
'${INTROFRAGMENT}-' ..
'${PAGETYPE}-' ..
'${PROTECTIONBLURB}-' ..
'${PROTECTIONDATE}-' ..
'${PROTECTIONLEVEL}-' ..
'${PROTECTIONLOG}-' ..
'${TALKPAGE}-' ..
'${TOOLTIPBLURB}-' ..
'${TOOLTIPFRAGMENT}-' ..
'${VANDAL}'
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
-- [[Module:Submit an edit request]], 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 [[Module:Submit an edit request]]
-- 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 = {
edit = {
autoconfirmed = {
talk = 'edit-autoconfirmed-talk',
default = 'edit-autoconfirmed-default'
},
default = {
talk = 'edit-default-talk',
default = 'edit-default-default'
}
}
}
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,
{obj},
'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 = {
edit = {
sysop = 'edit-sysop',
default = 'edit-default'
},
move = {
sysop = 'move-sysop',
default = 'move-default'
}
}
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 = {
[3] = 'user talk page',
default = 'default page'
}
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,
{obj},
'no default pagetype defined'
)
end
-- _makeProtectionBlurbParameter
function suite:testBlurbMakeProtectionBlurbParameter()
local obj = makeDefaultBlurbObject()
obj._protectionObj.action = 'move'
obj._protectionObj.level = 'sysop'
obj._cfg.protectionBlurbs = {
edit = {
sysop = 'edit-sysop',
default = 'edit-default'
},
move = {
sysop = 'move-sysop',
default = 'move-default'
}
}
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,
{obj},
'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 = {
edit = {
sysop = 'edit-sysop',
default = 'edit-default'
},
move = {
sysop = 'move-sysop',
default = 'move-default'
}
}
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,
{obj},
'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(
'[['
.. d.talkPage .. '#top|'
.. 'the key is talk-page-link-display'
.. ']]',
obj:_makeTalkPageParameter()
)
obj._args.section = 'talk section'
self:assertEquals(
'[['
.. d.talkPage .. '#talk section|'
.. '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,
{obj, 'foo'},
'"foo" is not a valid banner config field'
)
self:assertError(
obj.makeBannerText,
{obj, nil},
'"nil" is not a valid banner config field'
)
end
function suite:testBlurbMakeBannerTextGoodInput()
local obj = makeDefaultBlurbObject()
obj._protectionObj.bannerConfig = {
text = 'banner text',
explanation = 'banner explanation',
tooltip = 'banner tooltip',
alt = 'banner alt',
link = 'banner link'
}
self:assertNotError(obj.makeBannerText, {obj, 'text'})
self:assertNotError(obj.makeBannerText, {obj, 'explanation'})
self:assertNotError(obj.makeBannerText, {obj, 'tooltip'})
self:assertNotError(obj.makeBannerText, {obj, 'alt'})
self:assertNotError(obj.makeBannerText, {obj, 'link'})
end
function suite:testBlurbMakeBannerTextString()
local obj = makeDefaultBlurbObject()
function obj:_substituteParameters(msg)
return msg
end
obj._protectionObj.bannerConfig = {
text = 'banner text',
}
self:assertEquals('banner text', obj:makeBannerText('text'))
end
function suite:testBlurbMakeBannerTextBadFunction()
local obj = makeDefaultBlurbObject()
function obj:_substituteParameters(msg)
return msg
end
obj._protectionObj.bannerConfig = {
text = function () return 9 end,
}
self:assertError(
obj.makeBannerText,
{obj, 'text'},
'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 = {
text = function () return 'some text' end,
}
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{foo = 'bar'})
self:assertEquals('bar', obj._cfg.foo)
end
function suite:testBannerTemplateNewImageIndefTemplateOrModule()
local cfg = {
msg = {['image-filename-indef'] = 'red padlock'}
}
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 = {
indefImageReasons = {[d.reason] = true},
msg = {['image-filename-indef'] = 'red padlock'}
}
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 = {
move = {
sysop = 'foo',
default = 'bar'
}
}
local protectionObj = makeDefaultProtectionObject()
protectionObj.action = 'move'
protectionObj.level = 'sysop'
local obj = BannerTemplate.new(protectionObj, makeConfig{
images = images
})
self:assertEquals('foo', obj._imageFilename)
images.move.sysop = nil
obj = BannerTemplate.new(protectionObj, makeConfig{
images = images
})
self:assertEquals('bar', obj._imageFilename)
images.move.default = nil
obj = BannerTemplate.new(protectionObj, makeConfig{
images = images
})
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, {obj}, '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 '[[File:Example.png|30px]]'
end
self:assertStringContains('[[File:Example.png|30px]]', tostring(obj), true)
self:assertStringContains(
"'''the reason text'''<br />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{padlockIndicatorNames = {
move = 'move-indicator',
default = 'default-indicator'
}}
local obj = Padlock.new(protectionObj, blurbObj, cfg)
self:assertEquals(obj._indicatorName, 'move-indicator')
cfg.padlockIndicatorNames.move = nil
obj = Padlock.new(protectionObj, blurbObj, cfg)
self:assertEquals(obj._indicatorName, 'default-indicator')
cfg.padlockIndicatorNames.default = nil
obj = Padlock.new(protectionObj, blurbObj, cfg)
self:assertEquals(obj._indicatorName, 'pp-default')
end
-- __tostring
function suite:testPadlockToString()
local obj = makeDefaultPadlockObject()
self:assertIsPadlock(tostring(obj))
end
--------------------------------------------------------------------------------
-- Export tests
--------------------------------------------------------------------------------
-- _main
function suite:test_mainError()
local args = {action = 'foobar'}
local cfg = makeConfig()
local title = makeDefaultTitleObject()
local success, result = pcall(mProtectionBanner._main, args, cfg, title)
self:assertFalse(success)
self:assertEquals(
'invalid action: foobar',
result,
false
)
end
function suite:test_mainSmall1()
local args = {small = 'yes'}
local cfg = makeConfig()
local title = makeDefaultTitleObject()
self:assertIsPadlock(mProtectionBanner._main(args, cfg, title))
end
function suite:test_mainSmall2()
local args = {small = 'Yes'}
local cfg = makeConfig()
local title = makeDefaultTitleObject()
self:assertIsPadlock(mProtectionBanner._main(args, cfg, title))
end
function suite:test_mainSmall3()
local args = {small = 'true'}
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 = {small = 'no'}
local cfg = makeConfig()
local title = makeDefaultTitleObject()
self:assertIsBanner(mProtectionBanner._main(args, cfg, title))
end
function suite:test_mainLarge3()
local args = {small = 'No'}
local cfg = makeConfig()
local title = makeDefaultTitleObject()
self:assertIsBanner(mProtectionBanner._main(args, cfg, title))
end
function suite:test_mainLarge4()
local args = {small = 'false'}
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{page = d.page, edit = nil}
self:assertNoBanner(mProtectionBanner._main(args, cfg, title), 'page unprotected')
end
function suite:test_mainNoBannerForUserScripts()
local args = {}
local cfg = makeConfig()
local title = makeTitleObject{page = 'User:Example/common.css', contentType = 'css'}
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{page = d.page, 'edit', nil}
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{args = {}}
local child = parent:newChild{args = {}}
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{title = 'Template:Pp-example', args = {}}
local child = parent:newChild{args = {}}
local cfg = makeConfig{
msg = {['tracking-category-incorrect'] = 'Incorrect'},
wrappers = {['Template:Pp-example'] = {category = false}}
}
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{title = 'Template:Pp-example', args = {category = 'yes'}}
local child = parent:newChild{args = {}}
local cfg = makeConfig{
msg = {['tracking-category-incorrect'] = 'Incorrect'},
wrappers = {['Template:Pp-example'] = {category = false}}
}
self:assertStringContains(
'%[%[Category:.-%]%]',
mProtectionBanner.main(child, cfg),
false
)
end
function suite:testMainWrapperSandbox()
local frame = mw.getCurrentFrame()
local parent = frame:newChild{title = 'Template:Pp-example/sandbox', args = {}}
local child = parent:newChild{args = {}}
local cfg = makeConfig{
msg = {['tracking-category-incorrect'] = 'Incorrect'},
wrappers = {['Template:Pp-example'] = {category = false}}
}
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{title = 'Template:Some template', args = {}}
local child = parent:newChild{args = {}}
local cfg = makeConfig{
msg = {['tracking-category-incorrect'] = 'Incorrect'},
wrappers = {['Template:Pp-example'] = {category = false}}
}
self:assertStringContains(
'%[%[Category:.-%]%]',
mProtectionBanner.main(child, cfg),
false
)
self:assertStringContains(
'%[%[Category:.-%]%]',
mProtectionBanner.main(parent, cfg),
false
)
end
return suite