From 81d68a43b8d89ea189e3fd792cd1c2247cfcb7b0 Mon Sep 17 00:00:00 2001
From: Tphamtranba <119475427+Bapham12@users.noreply.github.com>
Date: Sat, 14 Mar 2026 20:01:21 +0700
Subject: [PATCH 01/25] Create Anchor.lua
---
Testcases/Anchor.lua | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
create mode 100644 Testcases/Anchor.lua
diff --git a/Testcases/Anchor.lua b/Testcases/Anchor.lua
new file mode 100644
index 0000000..bbfcf9a
--- /dev/null
+++ b/Testcases/Anchor.lua
@@ -0,0 +1,26 @@
+-- Unit tests for [[Module:Anchor]]. Click talk page to run tests.
+
+local anchor = require('Module:Anchor') -- the module to be tested
+local ScribuntoUnit = require('Module:ScribuntoUnit')
+local suite = ScribuntoUnit:new()
+
+function suite:testmain()
+ self:assertResultEquals('', '{{#invoke:Anchor|main|foo}}')
+ self:assertResultEquals('', '{{#invoke:Anchor|main|foo|bar}}')
+ self:assertResultEquals('', '{{#invoke:Anchor|main|3=foo}}')
+ self:assertResultEquals('', '{{#invoke:Anchor|main| foo }}')
+ self:assertResultEquals('', '{{#invoke:Anchor|main|25=foo}}')
+end
+
+function suite:test_main()
+ self:assertResultEquals('', anchor._main('foo'))
+ self:assertResultEquals('', anchor._main('foo', 'bar'))
+end
+
+function suite:testAgainstTemplate()
+ self:assertSameResult('{{anchor|foo}}', '{{#invoke:Anchor|main|foo}}')
+ self:assertSameResult('{{anchor|foo|bar}}', '{{#invoke:Anchor|main|foo|bar}}')
+ self:assertSameResult('{{anchor|3=foo}}', '{{#invoke:Anchor|main|3=foo}}')
+end
+
+return suite
From e4bc744914ab6ad7c82adde41b49bd454e8e4d9f Mon Sep 17 00:00:00 2001
From: Tphamtranba <119475427+Bapham12@users.noreply.github.com>
Date: Sat, 14 Mar 2026 20:01:57 +0700
Subject: [PATCH 02/25] Create Ancient Greek.lua
---
Testcases/Ancient Greek.lua | 76 +++++++++++++++++++++++++++++++++++++
1 file changed, 76 insertions(+)
create mode 100644 Testcases/Ancient Greek.lua
diff --git a/Testcases/Ancient Greek.lua b/Testcases/Ancient Greek.lua
new file mode 100644
index 0000000..b9a07df
--- /dev/null
+++ b/Testcases/Ancient Greek.lua
@@ -0,0 +1,76 @@
+--[=[
+ Modified from [[wikt:Module:grc-translit/testcases]].
+]=]
+
+local tests = require('Module:UnitTests')
+local translit = require('Module:Ancient Greek')
+local decompose = mw.ustring.toNFC
+
+local function tag(text)
+ return '' .. text .. ''
+end
+
+function tests:check_output(term, Wiktionary, ALA_LC)
+ tests:equals(
+ tag(term),
+ decompose(translit.transliterate(term, "Wiktionary")),
+ decompose(Wiktionary)
+ )
+
+ tests:equals(
+ tag(term),
+ decompose(translit.transliterate(term, "ALA-LC")),
+ decompose(ALA_LC)
+ )
+end
+
+function tests:test_translit()
+ local examples = {
+ { 'λόγος', 'lógos', 'logos' },
+ { 'σφίγξ', 'sphínx', 'sphinx' },
+ { 'ϝάναξ', 'wánax', 'wanax' },
+ { 'οἷαι', 'hoîai', 'hoiai' },
+
+ -- test u/y
+ { 'ταῦρος', 'taûros', 'tauros' },
+ { 'νηῦς', 'nēûs', 'nēus' },
+ { 'σῦς', 'sûs', 'sys' },
+ { 'ὗς', 'hûs', 'hys' },
+ { 'γυῖον', 'guîon', 'guion' },
+ { 'ἀναῡ̈τέω', 'anaṻtéō', 'anayteō' },
+ { 'δαΐφρων', 'daḯphrōn', 'daiphrōn' },
+
+ -- test length
+ { 'τῶν', 'tôn', 'tōn' },
+ { 'τοὶ', 'toì', 'toi' },
+ { 'τῷ', 'tôi', 'tō' },
+ { 'τούτῳ', 'toútōi', 'toutō' },
+ { 'σοφίᾳ', 'sophíāi', 'sophia' },
+ { 'μᾱ̆νός', 'mānós', 'manos' }, -- should perhaps be mā̆nos
+
+ -- test h
+ { 'ὁ', 'ho', 'ho' },
+ { 'οἱ', 'hoi', 'hoi' },
+ { 'εὕρισκε', 'heúriske', 'heuriske' },
+ { 'ὑϊκός', 'huïkós', 'hyikos' },
+ { 'πυρρός', 'purrhós', 'pyrrhos' },
+ { 'ῥέω', 'rhéō', 'rheō' },
+ { 'σάἁμον', 'sáhamon', 'sahamon' },
+
+ -- test capitals
+ { 'Ὀδυσσεύς', 'Odusseús', 'Odysseus' },
+ { 'Εἵλως', 'Heílōs', 'Heilōs' },
+ { 'ᾍδης', 'Hā́idēs', 'Hadēs' },
+ { 'ἡ Ἑλήνη', 'hē Helḗnē', 'hē Helēnē' },
+
+ -- punctuation
+ { 'ἔχεις μοι εἰπεῖν, ὦ Σώκρατες, ἆρα διδακτὸν ἡ ἀρετή;', 'ékheis moi eipeîn, ô Sṓkrates, âra didaktòn hē aretḗ?', 'echeis moi eipein, ō Sōkrates, ara didakton hē aretē?'},
+ { 'τί τηνικάδε ἀφῖξαι, ὦ Κρίτων; ἢ οὐ πρῲ ἔτι ἐστίν;', 'tí tēnikáde aphîxai, ô Krítōn? ḕ ou prṑi éti estín?', 'ti tēnikade aphixai, ō Kritōn? ē ou prō eti estin?' },
+ -- This ought to be colon, but sadly that cannot be.
+ { 'τούτων φωνήεντα μέν ἐστιν ἑπτά· α ε η ι ο υ ω.', 'toútōn phōnḗenta mén estin heptá; a e ē i o u ō.', 'toutōn phōnēenta men estin hepta; a e ē i o y ō.' },
+ }
+
+ self:iterate(examples, 'check_output')
+end
+
+return tests
From 12daf03ee01e88596f020503de8b3d9c1d19c1da Mon Sep 17 00:00:00 2001
From: Tphamtranba <119475427+Bapham12@users.noreply.github.com>
Date: Sat, 14 Mar 2026 20:02:38 +0700
Subject: [PATCH 03/25] Create Arguments.lua
---
Testcases/Arguments.lua | 583 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 583 insertions(+)
create mode 100644 Testcases/Arguments.lua
diff --git a/Testcases/Arguments.lua b/Testcases/Arguments.lua
new file mode 100644
index 0000000..b3a3831
--- /dev/null
+++ b/Testcases/Arguments.lua
@@ -0,0 +1,583 @@
+local getArgs = require('Module:Arguments/sandbox').getArgs
+local ScribuntoUnit = require('Module:ScribuntoUnit')
+local suite = ScribuntoUnit:new()
+
+--------------------------------------------------------------------------
+-- Default values
+--------------------------------------------------------------------------
+
+local d = {}
+d.frameTitle = 'Frame title'
+d.parentTitle = 'Parent title'
+
+-- Precedence-testing values
+d.firstFrameArg = 'first frame argument'
+d.firstParentArg = 'first parent argument'
+d.secondParentArg = 'second parent argument'
+d.uniqueFrameArg = 'unique frame argument'
+d.uniqueFrameArgKey = 'uniqueFrameArgKey'
+d.uniqueParentArg = 'unique parent argument'
+d.uniqueParentArgKey = 'uniqueParentArgKey'
+
+-- Trimming and whitespace values.
+-- Whitespace gets trimmed from named parameters, so keys for these need
+-- to be numbers to make this a proper test.
+d.blankArg = ''
+d.blankArgKey = 100
+d.spacesArg = '\n '
+d.spacesArgKey = 101
+d.untrimmedArg = '\n foo bar '
+d.untrimmedArgKey = 102
+d.trimmedArg = 'foo bar'
+d.valueFuncValue = 'valueFuncValue'
+d.defaultValueFunc = function() return d.valueFuncValue end
+d.translate = {
+ foo = 'F00',
+ bar = '8@r',
+ baz = '8@z',
+ qux = 'qUx'
+}
+
+--------------------------------------------------------------------------
+-- Helper functions
+--------------------------------------------------------------------------
+
+function suite.getFrames(frameTitle, frameArgs, parentTitle, parentArgs)
+ frameTitle = frameTitle or d.frameTitle
+ frameArgs = frameArgs or {
+ d.firstFrameArg,
+ [d.uniqueFrameArgKey] = d.uniqueFrameArg,
+ [d.blankArgKey] = d.blankArg,
+ [d.spacesArgKey] = d.spacesArg,
+ [d.untrimmedArgKey] = d.untrimmedArg
+ }
+ parentTitle = parentTitle or d.parentTitle
+ parentArgs = parentArgs or {
+ d.firstParentArg,
+ d.secondParentArg,
+ [d.uniqueParentArgKey] = d.uniqueParentArg
+ }
+ local currentFrame = mw.getCurrentFrame()
+ local parent = currentFrame:newChild{title = parentTitle, args = parentArgs}
+ local frame = parent:newChild{title = frameTitle, args = frameArgs}
+ return frame, parent
+end
+
+function suite.getDefaultArgs(options, frameTitle, frameArgs, parentTitle, parentArgs)
+ local frame, parent = suite.getFrames(frameTitle, frameArgs, parentTitle, parentArgs)
+ local args = getArgs(frame, options)
+ return args
+end
+
+function suite:assertError(func, ...)
+ -- Asserts that executing the function func results in an error.
+ -- Parameters after func are func's arguments.
+ local success, msg = pcall(func, ...)
+ self:assertFalse(success)
+end
+
+function suite:assertNumberOfIterations(expected, iterator, t)
+ local noIterations = 0
+ for k, v in iterator(t) do
+ noIterations = noIterations + 1
+ end
+ self:assertEquals(expected, noIterations)
+end
+
+--------------------------------------------------------------------------
+-- Test precedence
+--------------------------------------------------------------------------
+
+function suite:assertDefaultPrecedence(args)
+ self:assertEquals(d.firstFrameArg, args[1])
+ self:assertEquals(d.secondParentArg, args[2])
+ self:assertEquals(d.uniqueFrameArg, args[d.uniqueFrameArgKey])
+ self:assertEquals(d.uniqueParentArg, args[d.uniqueParentArgKey])
+end
+
+function suite:testDefaultPrecedence()
+ self:assertDefaultPrecedence(suite.getDefaultArgs())
+end
+
+function suite:testDefaultPrecedenceThroughWrapper()
+ self:assertDefaultPrecedence(suite.getDefaultArgs{wrappers = {d.parentTitle}, parentOnly = false})
+end
+
+function suite:testDefaultPrecedenceThroughNonWrapper()
+ self:assertDefaultPrecedence(suite.getDefaultArgs({wrappers = d.parentTitle, frameOnly = false}, nil, nil, 'Not the parent title'))
+end
+
+function suite:assertParentFirst(args)
+ self:assertEquals(d.firstParentArg, args[1])
+ self:assertEquals(d.secondParentArg, args[2])
+ self:assertEquals(d.uniqueFrameArg, args[d.uniqueFrameArgKey])
+ self:assertEquals(d.uniqueParentArg, args[d.uniqueParentArgKey])
+end
+
+function suite:testParentFirst()
+ self:assertParentFirst(suite.getDefaultArgs{parentFirst = true})
+end
+
+function suite:testParentFirstThroughWrapper()
+ self:assertParentFirst(suite.getDefaultArgs{wrappers = {d.parentTitle}, parentOnly = false, parentFirst = true})
+end
+
+function suite:testParentFirstThroughNonWrapper()
+ self:assertParentFirst(suite.getDefaultArgs({wrappers = d.parentTitle, frameOnly = false, parentFirst = true}, nil, nil, 'Not the parent title'))
+end
+
+function suite:assertParentOnly(args)
+ self:assertEquals(d.firstParentArg, args[1])
+ self:assertEquals(d.secondParentArg, args[2])
+ self:assertEquals(nil, args[d.uniqueFrameArgKey])
+ self:assertEquals(d.uniqueParentArg, args[d.uniqueParentArgKey])
+end
+
+function suite:testParentOnly()
+ self:assertParentOnly(suite.getDefaultArgs{parentOnly = true})
+end
+
+function suite:testParentOnlyThroughWrapper()
+ self:assertParentOnly(suite.getDefaultArgs{wrappers = {d.parentTitle}})
+end
+
+function suite:testParentOnlyThroughSandboxWrapper()
+ self:assertParentOnly(suite.getDefaultArgs({wrappers = d.parentTitle}, nil, nil, d.parentTitle .. '/sandbox'))
+end
+
+function suite:assertFrameOnly(args)
+ self:assertEquals(d.firstFrameArg, args[1])
+ self:assertEquals(nil, args[2])
+ self:assertEquals(d.uniqueFrameArg, args[d.uniqueFrameArgKey])
+ self:assertEquals(nil, args[d.uniqueParentArgKey])
+end
+
+function suite:testFrameOnly()
+ self:assertFrameOnly(suite.getDefaultArgs{frameOnly = true})
+end
+
+function suite:testFrameOnlyThroughNonWrapper()
+ self:assertFrameOnly(suite.getDefaultArgs({wrappers = d.parentTitle}, nil, nil, 'Not the parent title'))
+end
+
+function suite:testDefaultPrecedenceWithWhitespace()
+ local frame, parent = suite.getFrames(
+ d.frameTitle,
+ {' '},
+ d.parentTitle,
+ {d.firstParentArg}
+ )
+ local args = getArgs(frame)
+ self:assertEquals(d.firstParentArg, args[1])
+end
+
+--------------------------------------------------------------------------
+-- Test trimming and blank removal
+--------------------------------------------------------------------------
+
+function suite:testDefaultTrimmingAndBlankRemoval()
+ local args = suite.getDefaultArgs()
+ self:assertEquals(nil, args[d.blankArgKey])
+ self:assertEquals(nil, args[d.spacesArgKey])
+ self:assertEquals(d.trimmedArg, args[d.untrimmedArgKey])
+end
+
+function suite:testRemoveBlanksButNoTrimming()
+ local args = suite.getDefaultArgs{trim = false}
+ self:assertEquals(nil, args[d.blankArgKey])
+ self:assertEquals(nil, args[d.spacesArgKey])
+ self:assertEquals(d.untrimmedArg, args[d.untrimmedArgKey])
+end
+
+function suite:testTrimButNoBlankRemoval()
+ local args = suite.getDefaultArgs{removeBlanks = false}
+ self:assertEquals(d.blankArg, args[d.blankArgKey])
+ self:assertEquals('', args[d.spacesArgKey])
+ self:assertEquals(d.trimmedArg, args[d.untrimmedArgKey])
+end
+
+function suite:testNoTrimOrBlankRemoval()
+ local args = suite.getDefaultArgs{trim = false, removeBlanks = false}
+ self:assertEquals(d.blankArg, args[d.blankArgKey])
+ self:assertEquals(d.spacesArg, args[d.spacesArgKey])
+ self:assertEquals(d.untrimmedArg, args[d.untrimmedArgKey])
+end
+
+--------------------------------------------------------------------------
+-- Test valueFunc
+--------------------------------------------------------------------------
+
+function suite:testValueFunc()
+ local args = suite.getDefaultArgs{valueFunc = d.defaultValueFunc}
+ self:assertEquals(d.valueFuncValue, args['some random key: sdfaliwyda'])
+end
+
+function suite:testValueFuncPrecedence()
+ local args = suite.getDefaultArgs{
+ trim = false,
+ removeBlanks = false,
+ valueFunc = d.defaultValueFunc
+ }
+ self:assertEquals(d.valueFuncValue, args[1])
+ self:assertEquals(d.valueFuncValue, args['some random key: gekjabawyvy'])
+end
+
+function suite:testValueFuncKey()
+ local args = suite.getDefaultArgs{valueFunc = function(key, value)
+ return 'valueFunc key: '.. key
+ end}
+ self:assertEquals('valueFunc key: foo', args.foo)
+end
+
+function suite:testValueFuncValue()
+ local args = suite.getDefaultArgs{valueFunc = function(key, value)
+ return 'valueFunc value: '.. value
+ end}
+ self:assertEquals(
+ 'valueFunc value: ' .. d.uniqueFrameArg,
+ args[d.uniqueFrameArgKey]
+ )
+end
+
+--------------------------------------------------------------------------
+-- Test adding new arguments
+--------------------------------------------------------------------------
+
+function suite:testAddingNewArgs()
+ local args = suite.getDefaultArgs()
+ self:assertEquals(nil, args.newKey)
+ args.newKey = 'some new key'
+ self:assertEquals('some new key', args.newKey)
+end
+
+function suite:testAddingNewBlankArgs()
+ local args = suite.getDefaultArgs()
+ self:assertEquals(nil, args.newKey)
+ args.newKey = ''
+ self:assertEquals('', args.newKey)
+end
+
+function suite:testAddingNewSpacesArgs()
+ local args = suite.getDefaultArgs()
+ self:assertEquals(nil, args.newKey)
+ args.newKey = ' '
+ self:assertEquals(' ', args.newKey)
+end
+
+function suite:testOverwriting()
+ local args = suite.getDefaultArgs()
+ self:assertEquals(d.firstFrameArg, args[1])
+ args[1] = 'a new first frame argument'
+ self:assertEquals('a new first frame argument', args[1])
+end
+
+function suite:testOverwritingWithNil()
+ local args = suite.getDefaultArgs()
+ self:assertEquals(d.firstFrameArg, args[1])
+ args[1] = nil
+ self:assertEquals(nil, args[1])
+end
+
+function suite:testOverwritingWithBlank()
+ local args = suite.getDefaultArgs()
+ self:assertEquals(d.firstFrameArg, args[1])
+ args[1] = ''
+ self:assertEquals('', args[1])
+end
+
+function suite:testOverwritingWithSpaces()
+ local args = suite.getDefaultArgs()
+ self:assertEquals(d.firstFrameArg, args[1])
+ args[1] = ' '
+ self:assertEquals(' ', args[1])
+end
+
+function suite:testReadOnly()
+ local args = suite.getDefaultArgs{readOnly = true}
+ local function testFunc()
+ args.newKey = 'some new value'
+ end
+ self:assertError(testFunc)
+end
+
+function suite:testNoOverwriteExistingKey()
+ local args = suite.getDefaultArgs{noOverwrite = true}
+ self:assertEquals(d.firstFrameArg, args[1])
+ local function testFunc()
+ args[1] = 'a new first frame argument'
+ end
+ self:assertError(testFunc)
+end
+
+function suite:testNoOverwriteNewKey()
+ local args = suite.getDefaultArgs{noOverwrite = true}
+ self:assertEquals(nil, args.newKey)
+ args.newKey = 'some new value'
+ self:assertEquals('some new value', args.newKey)
+end
+
+--------------------------------------------------------------------------
+-- Test bad input
+--------------------------------------------------------------------------
+
+function suite:testBadFrameInput()
+ self:assertError(getArgs, 'foo')
+ self:assertError(getArgs, 9)
+ self:assertError(getArgs, true)
+ self:assertError(getArgs, function() return true end)
+end
+
+function suite:testBadOptionsInput()
+ self:assertError(getArgs, {}, 'foo')
+ self:assertError(getArgs, {}, 9)
+ self:assertError(getArgs, {}, true)
+ self:assertError(getArgs, {}, function() return true end)
+end
+
+function suite:testBadValueFuncInput()
+ self:assertError(getArgs, {}, {valueFunc = 'foo'})
+ self:assertError(getArgs, {}, {valueFunc = 9})
+ self:assertError(getArgs, {}, {valueFunc = true})
+ self:assertError(getArgs, {}, {valueFunc = {}})
+end
+
+--------------------------------------------------------------------------
+-- Test iterator metamethods
+--------------------------------------------------------------------------
+
+function suite:testPairs()
+ local args = getArgs{'foo', 'bar', baz = 'qux'}
+ self:assertNumberOfIterations(3, pairs, args)
+end
+
+function suite:testIpairs()
+ local args = getArgs{'foo', 'bar', baz = 'qux'}
+ self:assertNumberOfIterations(2, ipairs, args)
+end
+
+function suite:testNoNilsinPairs()
+ -- Test that when we use pairs, we don't iterate over any nil values
+ -- that have been memoized.
+ local args = getArgs{''}
+ local temp = args[1] -- Memoizes the nil
+ self:assertNumberOfIterations(0, pairs, args)
+end
+
+function suite:testNoNilsinIpairs()
+ -- Test that when we use ipairs, we don't iterate over any nil values
+ -- that have been memoized.
+ local args = getArgs{''}
+ local temp = args[1] -- Memoizes the nil
+ self:assertNumberOfIterations(0, ipairs, args)
+end
+
+function suite:testDeletedArgsInPairs()
+ -- Test that when we use pairs, we don't iterate over any values that have
+ -- been explicitly set to nil.
+ local args = getArgs{'foo'}
+ args[1] = nil
+ self:assertNumberOfIterations(0, pairs, args)
+end
+
+function suite:testDeletedArgsInIpairs()
+ -- Test that when we use ipairs, we don't iterate over any values that have
+ -- been explicitly set to nil.
+ local args = getArgs{'foo'}
+ args[1] = nil
+ self:assertNumberOfIterations(0, ipairs, args)
+end
+
+function suite:testNoNilsInPairsAfterIndex()
+ -- Test that when we use pairs, we don't iterate over any nils that
+ -- might have been memoized after a value that is not present in the
+ -- original args table is indexed.
+ local args = getArgs{}
+ local temp = args.someRandomValue -- Memoizes the nil
+ self:assertNumberOfIterations(0, pairs, args)
+end
+
+function suite:testNoNilsInPairsAfterNewindex()
+ -- Test that when we use pairs, we don't iterate over any nils that
+ -- might have been memoized after a value that is not present in the
+ -- original args table is added to the args table.
+ local args = getArgs{}
+ args.newKey = nil -- The nil is memoized
+ self:assertNumberOfIterations(0, pairs, args)
+end
+
+function suite:testNoTableLengthChangeWhileIterating()
+ -- Test that the number of arguments doesn't change if we index the
+ -- args table while iterating.
+ -- (Note that the equivalent test is not needed for new arg table
+ -- indexes, as that would be a user error - doing so produces
+ -- undetermined behaviour in Lua's next() function.)
+ local args = getArgs{'foo', 'bar', baz = 'qux'}
+ self:assertNumberOfIterations(3, pairs, args)
+ for k, v in pairs(args) do
+ local temp = args[k .. 'foo']
+ end
+ self:assertNumberOfIterations(3, pairs, args)
+end
+
+function suite:testPairsPrecedenceWithWhitespace()
+ local frame, parent = suite.getFrames(
+ d.frameTitle,
+ {' '},
+ d.parentTitle,
+ {d.firstParentArg}
+ )
+ local args = getArgs(frame)
+ local actual
+ for k, v in pairs(args) do
+ actual = v
+ end
+ self:assertEquals(d.firstParentArg, actual)
+ -- Check that we have actually iterated.
+ self:assertNumberOfIterations(1, pairs, args)
+end
+
+function suite:testPairsPrecedenceWithNil()
+ local frame, parent = suite.getFrames(
+ d.frameTitle,
+ {},
+ d.parentTitle,
+ {d.firstParentArg}
+ )
+ local args = getArgs(frame)
+ local actual
+ for k, v in pairs(args) do
+ actual = v
+ end
+ self:assertEquals(d.firstParentArg, actual)
+ -- Check that we have actually iterated.
+ self:assertNumberOfIterations(1, pairs, args)
+end
+
+function suite:testIpairsEarlyExit()
+ local mt = {}
+ function mt.__index(t, k)
+ if k == 1 then
+ return 'foo'
+ elseif k == 2 then
+ return 'bar'
+ elseif k == 3 then
+ error('Expanded argument 3 unnecessarily')
+ end
+ end
+ function mt.__pairs(t)
+ error('Called pairs unnecessarily')
+ end
+ function mt.__ipairs(t)
+ -- Works just like the default ipairs, except respecting __index
+ return function(t, i)
+ local v = t[i + 1]
+ if v ~= nil then
+ return i + 1, v
+ end
+ end, t, 0
+ end
+ local args = getArgs(setmetatable({}, mt))
+ for k,v in ipairs(args) do
+ if v == 'bar' then
+ break
+ end
+ end
+end
+
+--------------------------------------------------------------------------
+-- Test argument translation
+--------------------------------------------------------------------------
+
+function suite:testTranslationIndex()
+ local args = getArgs({F00 = 'one', ['8@r'] = 'two', ['8@z'] = 'three', qUx = 'four', foo = 'nope', untranslated = 'yep'}, {translate = d.translate})
+ self:assertEquals('one', args.foo)
+ self:assertEquals('two', args.bar)
+ self:assertEquals('three', args.baz)
+ self:assertEquals('four', args.qux)
+ self:assertEquals('yep', args.untranslated)
+end
+
+function suite:testTranslationPairsWithAutoBacktranslate()
+ local args = getArgs({F00 = 'one', ['8@r'] = 'two', ['8@z'] = 'three', qUx = 'four', foo = 'nope', untranslated = 'yep'}, {translate = d.translate})
+ local cleanArgs = {}
+ for k,v in pairs(args) do
+ cleanArgs[k] = v
+ end
+ self:assertDeepEquals(
+ {
+ foo = 'one',
+ bar = 'two',
+ baz = 'three',
+ qux = 'four',
+ untranslated = 'yep'
+ },
+ cleanArgs
+ )
+end
+
+function suite:testTranslationPairsWithBacktranslate()
+ local args = getArgs({F00 = 'one', ['8@r'] = 'two', ['8@z'] = 'three', qUx = 'four', foo = 'nope', untranslated = 'yep'}, {translate = d.translate, backtranslate = {F00 = 'foo'}})
+ local cleanArgs = {}
+ for k,v in pairs(args) do
+ cleanArgs[k] = v
+ end
+ self:assertDeepEquals(
+ {
+ foo = 'one',
+ ['8@r'] = 'two',
+ ['8@z'] = 'three',
+ qUx = 'four',
+ untranslated = 'yep'
+ },
+ cleanArgs
+ )
+end
+
+function suite:testTranslationPairsWithoutBacktranslate()
+ local args = getArgs({F00 = 'one', ['8@r'] = 'two', ['8@z'] = 'three', qUx = 'four', foo = 'nope', untranslated = 'yep'}, {translate = d.translate, backtranslate = false})
+ local cleanArgs = {}
+ for k,v in pairs(args) do
+ cleanArgs[k] = v
+ end
+ self:assertDeepEquals(
+ {
+ F00 = 'one',
+ ['8@r'] = 'two',
+ ['8@z'] = 'three',
+ qUx = 'four',
+ foo = 'nope',
+ untranslated = 'yep'
+ },
+ cleanArgs
+ )
+end
+
+function suite:testTranslationNewindex()
+ local args = getArgs({F00 = 'one', ['8@r'] = 'two', ['8@z'] = 'three', qUx = 'four', foo = 'nope', untranslated = 'yep'}, {translate = d.translate, backtranslate = false})
+ args.foo = 'changed1'
+ args.untranslated = 'changed2'
+ local cleanArgs = {}
+ for k,v in pairs(args) do
+ cleanArgs[k] = v
+ end
+ self:assertDeepEquals(
+ {
+ F00 = 'changed1',
+ ['8@r'] = 'two',
+ ['8@z'] = 'three',
+ qUx = 'four',
+ foo = 'nope',
+ untranslated = 'changed2'
+ },
+ cleanArgs
+ )
+end
+
+function suite:test_argument()
+ local currentFrame = mw.getCurrentFrame()
+ currentFrame.args[5] = 555;
+ local args = getArgs(currentFrame)
+ self:assertEquals('nil', type(args.foo))
+end
+
+return suite
From 0c1883ca532832def9ddfdb75f024717950f7669 Mon Sep 17 00:00:00 2001
From: Tphamtranba <119475427+Bapham12@users.noreply.github.com>
Date: Sat, 14 Mar 2026 20:03:14 +0700
Subject: [PATCH 04/25] Create Cat main.lua
---
Testcases/Cat main.lua | 104 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 104 insertions(+)
create mode 100644 Testcases/Cat main.lua
diff --git a/Testcases/Cat main.lua b/Testcases/Cat main.lua
new file mode 100644
index 0000000..f19c475
--- /dev/null
+++ b/Testcases/Cat main.lua
@@ -0,0 +1,104 @@
+local mCatMain = require('Module:Cat main/sandbox') -- the module to be tested
+local ScribuntoUnit = require('Module:ScribuntoUnit')
+local suite = ScribuntoUnit:new()
+
+--------------------------------------------------------------------------------
+-- Helper functions
+--------------------------------------------------------------------------------
+
+local function patchCurrentTitle(newTitle, func)
+ local oldGetCurrentTitle = mw.title.getCurrentTitle
+ mw.title.getCurrentTitle = function ()
+ return mw.title.new("Category:Example")
+ end
+ func()
+ mw.title.getCurrentTitle = oldGetCurrentTitle
+end
+
+--------------------------------------------------------------------------------
+-- Custom assert methods
+--------------------------------------------------------------------------------
+
+function suite:assertHasClass(expectedClass, result)
+ result = mw.text.killMarkers(result) -- remove TemplateStyles marker
+ local classes = result:match('^
]*class="([^"]*)"')
+ classes = mw.text.split(classes, ' ')
+ local hasClass = false
+ for _, actualClass in ipairs(classes) do
+ if actualClass == expectedClass then
+ hasClass = true
+ break
+ end
+ end
+ self:assertTrue(
+ hasClass,
+ string.format(
+ 'Class "%s" %s in result "%s"',
+ expectedClass,
+ hasClass and "found" or "not found",
+ result
+ )
+ )
+end
+
+--------------------------------------------------------------------------------
+-- Tests
+--------------------------------------------------------------------------------
+
+function suite:testWholeOutput()
+ self:assertEquals(
+ [=[
bài viết chính của [[Help:Thể loại|thể loại]] này là '''[[:Foo]]'''.
]=],
+ mw.text.killMarkers(mCatMain._catMain(nil, 'Foo'))
+ )
+end
+
+function suite:testOneArticle()
+ self:assertStringContains(
+ "bài viết chính của [[Help:Thể loại|thể loại]] này là '''[[:Foo]]'''.",
+ mCatMain._catMain(nil, 'Foo'),
+ true
+ )
+end
+
+function suite:testTwoArticles()
+ self:assertStringContains(
+ "bài viết chính của [[Help:Thể loại|thể loại]] này là '''[[:Foo]]''' '''[[:Foo]]''' and '''[[:Bar]]'''.",
+ mCatMain._catMain(nil, 'Foo', 'Bar'),
+ true
+ )
+end
+
+function suite:testThreeArticles()
+ self:assertStringContains(
+ "bài viết chính của [[Help:Thể loại|thể loại]] này là '''[[:Foo]]''' '''[[:Foo]]''', '''[[:Bar]]''' and '''[[:Baz]]'''.",
+ mCatMain._catMain(nil, 'Foo', 'Bar', 'Baz'),
+ true
+ )
+end
+
+function suite:testNonArticle()
+ self:assertStringContains(
+ "bài viết chính của [[Help:Thể loại|thể loại]] này là '''[[:Foo]]'''",
+ mCatMain._catMain({article = false}, 'Foo'),
+ true
+ )
+end
+
+function suite:testSelfReference()
+ self:assertHasClass("selfref", mCatMain._catMain({selfref = true}, 'Foo'))
+end
+
+function suite:testNoArticles()
+ patchCurrentTitle(
+ "Category:Example",
+ function ()
+ self:assertStringContains(
+ "bài viết chính của [[Help:Thể loại|thể loại]] này là '''[[Example]]'''",
+ mCatMain._catMain(),
+ true
+ )
+ end
+ )
+end
+
+return suite
From f0d5e7d21cbb5cc4113837c950cf234ecf7591a0 Mon Sep 17 00:00:00 2001
From: Tphamtranba <119475427+Bapham12@users.noreply.github.com>
Date: Sat, 14 Mar 2026 20:03:55 +0700
Subject: [PATCH 05/25] Create Category handler.lua
---
Testcases/Category handler.lua | 552 +++++++++++++++++++++++++++++++++
1 file changed, 552 insertions(+)
create mode 100644 Testcases/Category handler.lua
diff --git a/Testcases/Category handler.lua b/Testcases/Category handler.lua
new file mode 100644
index 0000000..bb527d8
--- /dev/null
+++ b/Testcases/Category handler.lua
@@ -0,0 +1,552 @@
+-- Unit tests for [[Module:Category handler]]. Click talk page to run tests.
+local m_category_handler = require('Module:Category handler/sandbox')
+local chmain = m_category_handler._main
+local ScribuntoUnit = require('Module:ScribuntoUnit')
+local suite = ScribuntoUnit:new()
+
+-- Define table of defaults
+local d = {}
+
+-- Values
+d.absent = nil
+d.blank = ''
+d.negation = '¬'
+d.yes = 'yes'
+d.no = 'no'
+d.subpageOnly = 'only'
+d.subpageNo = 'no'
+
+-- Categories
+d.category = 'Category:Somecat'
+d.category1 = 'Category:Somecat1'
+d.category2 = 'Category:Somecat2'
+
+-- Pages
+d.article = 'Somearticle'
+d.file = 'File:Example.png'
+d.talk = 'Talk:Foo'
+d.archive = 'User talk:Example/Archive 5'
+d.subpage = 'User:Example/test'
+d.basepage = 'User:Example'
+
+-- Params
+d.archiveParam = 'talk'
+
+--------------------------------------------------------------------------------
+-- Test nil
+--------------------------------------------------------------------------------
+
+function suite:test_nil()
+ self:assertEquals(d.absent, chmain{nil})
+end
+
+--------------------------------------------------------------------------------
+-- Test defaults
+--------------------------------------------------------------------------------
+
+function suite:test_default_current_page()
+ -- Will test either module or module talk space, neither of which are categorised by default.
+ self:assertEquals(d.absent, chmain{d.category})
+end
+
+function suite:test_default_main()
+ self:assertEquals(d.category, chmain{d.category, page = d.article})
+end
+
+function suite:test_default_file()
+ self:assertEquals(d.category, chmain{d.category, page = d.file})
+end
+
+--------------------------------------------------------------------------------
+-- Test numbered parameters
+--------------------------------------------------------------------------------
+
+function suite:test_numbered_main()
+ self:assertEquals(d.category, chmain{
+ [1] = d.category,
+ main = 1,
+ page = d.article
+ })
+end
+
+function suite:test_numbered_two_params()
+ self:assertEquals(d.category2, chmain{
+ [1] = d.category1,
+ [2] = d.category2,
+ main = 1,
+ file = 2,
+ page = d.file
+ })
+end
+
+--------------------------------------------------------------------------------
+-- Test overriding defaults
+--------------------------------------------------------------------------------
+
+function suite:test_numbered_main()
+ self:assertEquals(d.absent, chmain{
+ main = d.category,
+ page = d.file
+ })
+end
+
+--------------------------------------------------------------------------------
+-- Test blank namespace parameters
+--------------------------------------------------------------------------------
+
+function suite:test_blank_namespace_talk()
+ self:assertEquals(d.blank, chmain{
+ talk = d.blank,
+ other = d.category,
+ page = d.talk
+ })
+end
+
+--------------------------------------------------------------------------------
+-- Test other parameter
+--------------------------------------------------------------------------------
+
+function suite:test_other_only()
+ self:assertEquals(d.category, chmain{
+ other = d.category,
+ })
+end
+
+--------------------------------------------------------------------------------
+-- Test nocat parameter
+--------------------------------------------------------------------------------
+
+function suite:test_nocat_true()
+ self:assertEquals(d.absent, chmain{d.category, page = d.file, nocat = true})
+end
+
+function suite:test_nocat_blank()
+ self:assertEquals(d.category, chmain{d.category, page = d.file, nocat = ''})
+end
+
+function suite:test_nocat_yes()
+ self:assertEquals(d.absent, chmain{d.category, page = d.file, nocat = d.yes})
+end
+
+function suite:test_nocat_false()
+ self:assertEquals(d.category, chmain{
+ [d.archiveParam] = d.category,
+ page = d.archive,
+ nocat = false
+ })
+end
+
+function suite:test_nocat_no()
+ self:assertEquals(d.category, chmain{
+ [d.archiveParam] = d.category,
+ page = d.archive,
+ nocat = d.no
+ })
+end
+
+--------------------------------------------------------------------------------
+-- Test categories parameter
+--------------------------------------------------------------------------------
+
+function suite:test_categories_true()
+ self:assertEquals(d.category, chmain{
+ [d.archiveParam] = d.category,
+ page = d.archive,
+ categories = true
+ })
+end
+
+function suite:test_categories_blank()
+ self:assertEquals(d.category, chmain{d.category, page = d.file, categories = ''})
+end
+
+function suite:test_categories_yes()
+ self:assertEquals(d.category, chmain{
+ [d.archiveParam] = d.category,
+ page = d.archive,
+ categories = d.yes
+ })
+end
+
+function suite:test_categories_false()
+ self:assertEquals(d.absent, chmain{
+ file = d.category,
+ page = d.file,
+ categories = false
+ })
+end
+
+function suite:test_categories_no()
+ self:assertEquals(d.absent, chmain{
+ file = d.category,
+ page = d.file,
+ categories = d.no
+ })
+end
+
+--------------------------------------------------------------------------------
+-- Test category2 parameter
+--------------------------------------------------------------------------------
+
+function suite:test_category2_no()
+ self:assertEquals(d.absent, chmain{
+ other = d.category,
+ category2 = d.no
+ })
+end
+
+function suite:test_category2_blank()
+ self:assertEquals(d.absent, chmain{
+ other = d.category,
+ category2 = d.blank
+ })
+end
+
+function suite:test_category2_negation()
+ self:assertEquals(d.category, chmain{
+ other = d.category,
+ category2 = d.negation
+ })
+end
+
+function suite:test_category2_blacklist()
+ self:assertEquals(d.category, chmain{
+ other = d.category,
+ page = d.archive,
+ categories = d.yes
+ })
+end
+
+--------------------------------------------------------------------------------
+-- Test subpage parameter
+--------------------------------------------------------------------------------
+
+function suite:test_subpage_no_basepage()
+ self:assertEquals(d.category, chmain{
+ other = d.category,
+ page = d.basepage,
+ subpage = d.subpageNo
+ })
+end
+
+function suite:test_subpage_no_subpage()
+ self:assertEquals(d.absent, chmain{
+ other = d.category,
+ page = d.subpage,
+ subpage = d.subpageNo
+ })
+end
+
+function suite:test_subpage_only_basepage()
+ self:assertEquals(d.absent, chmain{
+ other = d.category,
+ page = d.basepage,
+ subpage = d.subpageOnly
+ })
+end
+
+function suite:test_subpage_only_subpage()
+ self:assertEquals(d.category, chmain{
+ other = d.category,
+ page = d.subpage,
+ subpage = d.subpageOnly
+ })
+end
+
+--------------------------------------------------------------------------------
+-- Test blacklist
+--------------------------------------------------------------------------------
+
+function suite:test_blacklist_archives()
+ self:assertEquals(d.absent, chmain{
+ other = d.category,
+ page = 'User talk:Example/Archive 5',
+ })
+end
+
+function suite:test_blacklist_archives_lowercase()
+ self:assertEquals(d.absent, chmain{
+ other = d.category,
+ page = 'User talk:Example/archive 5',
+ })
+end
+
+function suite:test_blacklist_archives_notarchive()
+ self:assertEquals(d.category, chmain{
+ other = d.category,
+ page = 'User talk:Example/Archove 5',
+ })
+end
+
+function suite:test_blacklist_archives_incident_archive()
+ self:assertEquals(d.category, chmain{
+ other = d.category,
+ page = "BKDatabase:Administrators' noticeboard/IncidentArchive 5",
+ })
+end
+
+function suite:test_blacklist_main_page()
+ self:assertEquals(d.absent, chmain{
+ other = d.category,
+ page = 'Main Page',
+ })
+end
+
+function suite:test_blacklist_main_page_talk()
+ self:assertEquals(d.category, chmain{
+ other = d.category,
+ page = 'Talk:Main Page',
+ })
+end
+
+function suite:test_blacklist_cascade()
+ self:assertEquals(d.absent, chmain{
+ other = d.category,
+ page = 'BKDatabase:Cascade-protected items',
+ })
+end
+
+function suite:test_blacklist_cascade_slash()
+ self:assertEquals(d.absent, chmain{
+ other = d.category,
+ page = 'BKDatabase:Cascade-protected items/',
+ })
+end
+
+function suite:test_blacklist_cascade_subpage()
+ self:assertEquals(d.absent, chmain{
+ other = d.category,
+ page = 'BKDatabase:Cascade-protected items/Foo',
+ })
+end
+
+function suite:test_blacklist_cascade_not_subpage()
+ self:assertEquals(d.category, chmain{
+ other = d.category,
+ page = 'BKDatabase:Cascade-protected itemsFoo',
+ })
+end
+
+function suite:test_blacklist_cascade_talk()
+ self:assertEquals(d.category, chmain{
+ other = d.category,
+ page = 'BKDatabase talk:Cascade-protected items',
+ })
+end
+
+function suite:test_blacklist_ubx()
+ self:assertEquals(d.absent, chmain{
+ other = d.category,
+ page = 'User:UBX',
+ })
+end
+
+function suite:test_blacklist_ubx_talk()
+ self:assertEquals(d.absent, chmain{
+ other = d.category,
+ page = 'User talk:UBX',
+ })
+end
+
+function suite:test_blacklist_ubx_subpage()
+ self:assertEquals(d.absent, chmain{
+ other = d.category,
+ page = 'User:UBX/Userboxes',
+ })
+end
+
+function suite:test_blacklist_ubx_talk_subpage()
+ self:assertEquals(d.absent, chmain{
+ other = d.category,
+ page = 'User talk:UBX/Userboxes',
+ })
+end
+
+function suite:test_blacklist_template_index_basepage()
+ self:assertEquals(d.category, chmain{
+ other = d.category,
+ page = 'BKDatabase:Template index',
+ })
+end
+
+function suite:test_blacklist_template_index_slash()
+ self:assertEquals(d.absent, chmain{
+ other = d.category,
+ page = 'BKDatabase:Template index/',
+ })
+end
+
+function suite:test_blacklist_template_index_not_subpage()
+ self:assertEquals(d.category, chmain{
+ other = d.category,
+ page = 'BKDatabase:Template indexFoo',
+ })
+end
+
+function suite:test_blacklist_template_index_subpage()
+ self:assertEquals(d.absent, chmain{
+ other = d.category,
+ page = 'BKDatabase:Template index/Cleanup',
+ })
+end
+
+--------------------------------------------------------------------------------
+-- Test namespace params
+--------------------------------------------------------------------------------
+
+function suite:test_main()
+ self:assertEquals(d.category, chmain{
+ main = d.category,
+ page = 'Some article',
+ })
+end
+
+function suite:test_talk()
+ self:assertEquals(d.category, chmain{
+ talk = d.category,
+ page = 'Talk:Some article',
+ })
+end
+
+function suite:test_user()
+ self:assertEquals(d.category, chmain{
+ user = d.category,
+ page = 'User:Example',
+ })
+end
+
+function suite:test_user_talk()
+ self:assertEquals(d.category, chmain{
+ talk = d.category,
+ page = 'User talk:Example',
+ })
+ self:assertEquals(d.absent, chmain{
+ ['user talk'] = d.category,
+ page = 'User talk:Example',
+ })
+ self:assertEquals(d.absent, chmain{
+ ['user_talk'] = d.category,
+ page = 'User talk:Example',
+ })
+end
+
+function suite:test_BKDatabase()
+ self:assertEquals(d.category, chmain{
+ BKDatabase = d.category,
+ page = 'BKDatabase:Example',
+ })
+end
+
+function suite:test_BKDatabase()
+ self:assertEquals(d.category, chmain{
+ BKDatabase = d.category,
+ page = 'BKDatabase:Example',
+ })
+end
+
+function suite:test_project()
+ self:assertEquals(d.category, chmain{
+ project = d.category,
+ page = 'BKDatabase:Example',
+ })
+end
+
+function suite:test_wp()
+ self:assertEquals(d.category, chmain{
+ wp = d.category,
+ page = 'BKDatabase:Example',
+ })
+end
+
+function suite:test_file()
+ self:assertEquals(d.category, chmain{
+ file = d.category,
+ page = 'File:Example.png',
+ })
+end
+
+function suite:test_image()
+ self:assertEquals(d.category, chmain{
+ image = d.category,
+ page = 'File:Example.png',
+ })
+end
+
+function suite:test_mediawiki()
+ self:assertEquals(d.category, chmain{
+ mediawiki = d.category,
+ page = 'MediaWiki:Protectedpagetext',
+ })
+end
+
+function suite:test_template()
+ self:assertEquals(d.category, chmain{
+ template = d.category,
+ page = 'Template:Example',
+ })
+end
+
+function suite:test_help()
+ self:assertEquals(d.category, chmain{
+ help = d.category,
+ page = 'Help:Editing',
+ })
+end
+
+function suite:test_category()
+ self:assertEquals(d.category, chmain{
+ category = d.category,
+ page = 'Category:BKDatabasens',
+ })
+end
+
+function suite:test_category()
+ self:assertEquals(d.category, chmain{
+ category = d.category,
+ page = 'Category:BKDatabasens',
+ })
+end
+
+function suite:test_portal()
+ self:assertEquals(d.category, chmain{
+ portal = d.category,
+ page = 'Portal:France',
+ })
+end
+
+function suite:test_draft()
+ self:assertEquals(d.category, chmain{
+ draft = d.category,
+ page = 'Draft:Example',
+ })
+end
+
+function suite:test_timedtext()
+ self:assertEquals(d.category, chmain{
+ timedtext = d.category,
+ page = 'TimedText:Example',
+ })
+end
+
+function suite:test_module()
+ self:assertEquals(d.category, chmain{
+ module = d.category,
+ page = 'Module:Sandbox',
+ })
+end
+
+function suite:test_special()
+ self:assertEquals(d.category, chmain{
+ special = d.category,
+ page = 'Special:WhatLinksHere',
+ })
+end
+
+function suite:test_media()
+ self:assertEquals(d.category, chmain{
+ media = d.category,
+ page = 'Media:Example.png',
+ })
+end
+
+return suite
From 5f7c8c2cfed26e29a18333740c6b0c501224e109 Mon Sep 17 00:00:00 2001
From: Tphamtranba <119475427+Bapham12@users.noreply.github.com>
Date: Sat, 14 Mar 2026 20:04:59 +0700
Subject: [PATCH 06/25] Create Check for deprecated parameters.lua
---
Testcases/Check for deprecated parameters.lua | 48 +++++++++++++++++++
1 file changed, 48 insertions(+)
create mode 100644 Testcases/Check for deprecated parameters.lua
diff --git a/Testcases/Check for deprecated parameters.lua b/Testcases/Check for deprecated parameters.lua
new file mode 100644
index 0000000..0f8debd
--- /dev/null
+++ b/Testcases/Check for deprecated parameters.lua
@@ -0,0 +1,48 @@
+-- Unit tests for [[Module:{{ROOTPAGENAME}}]]. Click talk page to run tests.
+local p = require('Module:UnitTests')
+local warning = require('Module:If preview')._warning
+local main = require('Module:Check for deprecated parameters')._check
+local sandbox = require('Module:Check for deprecated parameters/sandbox')._check
+
+-- Remember to run the tests in preview mode! The test code, below, checks for preview correctness also
+
+local function test(tester,fcn)
+ tester:equals('Nothing deprecated',fcn({A1='B1',A2='B2',_category='C',preview='W'},
+ {A0='val'},'caller'),
+ '',{nowiki=1,stripmarkers=1})
+ tester:equals('Simple',fcn({A1='B1',A2='B2',_category='C',preview='W'},
+ {A2='val'},'caller'),
+ 'C'..warning({'W'}),{nowiki=1,stripmarkers=1})
+ tester:equals('Simple with _VALUE_',fcn({A1='B1',A2='B2',_category='C _VALUE_',preview='W _VALUE_'},
+ {A2='val'},'caller'),
+ 'C A2'..warning({'W "A2". Replace with "B2".'}),{nowiki=1,stripmarkers=1})
+ tester:equals('Remove',fcn({A1='B1',A2='B2',_category='C',preview='W',_remove='XX; A3; A4'},
+ {A3='val'},'caller'),
+ 'C'..warning({'W'}),{nowiki=1,stripmarkers=1})
+ tester:equals('Remove with _VALUE_',fcn({A1='B1',A2='B2',_category='C _VALUE_',preview='W _VALUE_',_remove='XX; A3; A4'},
+ {A3='val'},'caller'),
+ 'C A3'..warning({'W "A3". It should be removed.'}),{nowiki=1,stripmarkers=1})
+ tester:equals('No preview',fcn({A1='B1',A2='B2',_category='C _VALUE_'},
+ {A2='val'},'caller'),
+ 'C A2'..warning({'Page using [[caller]] with deprecated parameter "A2". Replace with "B2".'}),{nowiki=1,stripmarkers=1})
+ tester:equals('Blank value',fcn({A1='B1',A2='B2',_category='C _VALUE_',preview='W'},
+ {A2=' '},'caller'),
+ 'C A2'..warning({'W'}),{nowiki=1,stripmarkers=1})
+ tester:equals('Blank value with ignoreblank',fcn({A1='B1',A2='B2',_category='C _VALUE_',preview='W',ignoreblank=1},
+ {A2=' '},'caller'),
+ '',{nowiki=1,stripmarkers=1})
+end
+
+function p:test_main()
+ if main then
+ test(p,main)
+ end
+end
+
+function p:test_sandbox()
+ if sandbox then
+ test(p,sandbox)
+ end
+end
+
+return p
From a1c64351a9326e15e4404f007308232dce581015 Mon Sep 17 00:00:00 2001
From: Tphamtranba <119475427+Bapham12@users.noreply.github.com>
Date: Sat, 14 Mar 2026 20:05:52 +0700
Subject: [PATCH 07/25] Create Check for unknown parameters.lua
---
Testcases/Check for unknown parameters.lua | 10 ++++++++++
1 file changed, 10 insertions(+)
create mode 100644 Testcases/Check for unknown parameters.lua
diff --git a/Testcases/Check for unknown parameters.lua b/Testcases/Check for unknown parameters.lua
new file mode 100644
index 0000000..0622a61
--- /dev/null
+++ b/Testcases/Check for unknown parameters.lua
@@ -0,0 +1,10 @@
+-- Unit tests for [[Module:Check for unknown parameters]]. Click talk page to run tests.
+local p = require('Module:UnitTests')
+
+function p:test_01_1_check()
+ self:preprocess_equals_sandbox_many('{{Module:Check for unknown parameters/testcases/template call', '', {
+ {"arg1=arg1| arg2=arg2 | name=name | height=height | weight=weight | website=website", "Unknown name,Unknown height,Unknown website,Unknown weight,"},
+ }, {nowiki=1})
+end
+
+return p
From 3d6539660ebf5d71523dff0e806e2005385b9ad4 Mon Sep 17 00:00:00 2001
From: Tphamtranba <119475427+Bapham12@users.noreply.github.com>
Date: Sat, 14 Mar 2026 20:06:48 +0700
Subject: [PATCH 08/25] Create CS1.lua
---
Testcases/Citation/CS1.lua | 1121 ++++++++++++++++++++++++++++++++++++
1 file changed, 1121 insertions(+)
create mode 100644 Testcases/Citation/CS1.lua
diff --git a/Testcases/Citation/CS1.lua b/Testcases/Citation/CS1.lua
new file mode 100644
index 0000000..20ca1da
--- /dev/null
+++ b/Testcases/Citation/CS1.lua
@@ -0,0 +1,1121 @@
+-- Unit tests for [[Module:Citation/CS1]]. Click talk page to run tests.
+local p = require('Module:UnitTests')
+
+function p:test_encyclopedia()
+ self:preprocess_equals_preprocess_many('{{cite encyclopedia/new|', '}}', '{{cite encyclopedia|', '}}', {
+ {
+[==[
+last= LAST
+|first= FIRST
+|author-link= author-link
+|editor-first= EDITOR-FIRST
+|editor-last= EDITOR-LAST
+|editor-link= EDITOR-LINK
+|encyclopedia= ENCYCLOPEDIA
+|title= TITLE
+|trans-title= TRANS-TITLE
+|url=https://en.wikipedia.org/Main_Page
+|access-date= access-date
+|language= LANGUAGE
+|edition= EDITION
+|date= DATE
+|year= YEAR
+|publisher= PUBLISHER
+|volume= VOLUME
+|location= LOCATION
+|id= ID
+|isbn= ISBN
+|oclc= OCLC
+|doi= 10.DOI
+|pages= PAGES
+|quote= QUOTE
+|ref= REF
+]==]
+},{
+[==[
+ last =Golden
+ |first = Peter B.
+ |author-link =Peter Benjamin Golden
+ |editor1-last = Golden
+ |editor1-first = Peter B.
+ |editor1-link = Peter Benjamin Golden
+ |editor2-last = Ben-Shammai,
+ |editor2-first = Haggai
+ |editor3-last = Róna-Tas
+ |editor3-first = András
+ |editor3-link = András Róna-Tas
+ |encyclopedia = The World of the Khazars: New Perspectives
+ |title = Khazar Studies: Achievements and Perspectives
+ |series = Handbook of Oriental Studies
+ |volume = 17
+ |publisher = BRILL
+ |year = 2007a
+ |pages = 7–57
+ |isbn = 978-9-004-16042-2
+ |url = http://books.google.com/books?id=3ZzXjdyK-CEC&pg=PR2#v=onepage&p=123
+ |access-date = February 13, 2013
+]==]
+}, {
+[==[
+title=Idaho – MSN Encarta |url=http://encarta.msn.com/encyclopedia_761565515/Idaho.html | archive-url=https://www.webcitation.org/5kwpoRl6A?url=http://encarta.msn.com/encyclopedia_761565515/Idaho.html | archive-date=2009-11-01|url-status=dead
+]==]
+}, {
+[==[
+ url= http://encarta.msn.com/encyclopedia_761594679/martina_hingis.html | title=Martina Hingis | publisher=[[Encarta]] | access-date=31 October 2008 | archive-url=https://www.webcitation.org/5kx7RAO3G?url=http://encarta.msn.com/encyclopedia_761594679/martina_hingis.html | archive-date=1 November 2009|url-status=dead
+]==]
+}, {
+[==[
+archive-url=https://www.webcitation.org/5kwbxqnne?url=http://encarta.msn.com/encyclopedia_761570768/Europe.html | url-status=dead | archive-date=31 October 2009 | title=Europe | last=Microsoft Encarta Online Encyclopaedia 2007 | url=http://encarta.msn.com/encyclopaedia_761570768/Europe.html | access-date=27 December 2007
+]==]
+}, {
+[==[
+last=Seberg |first=Ole |year=2007 |editor-last=Heywood |editor-first=Vernon H. |editor2-last=Brummitt |editor2-first=Richard K. |editor3-last=Culham |editor3-first=Alastair |contribution=Alliaceae |title=Flowering Plant Families of the World |pages=340–341 |publication-place=Richmond Hill, Ontario |publisher=Firefly Books |isbn=978-1-55407-206-4 |name-list-style=amp
+]==]
+}, {
+[==[
+chapter=Lewinsky scandal |title=The Columbia Encyclopedia, Sixth Edition |publisher=Columbia University Press |year=2008 |url=http://www.encyclopedia.com/topic/Lewinsky_scandal.aspx |access-date=February 9, 2010
+]==]
+}, {
+[==[
+last = Gerish | first = Deborah | title = Aimery of Lusignan | editor = Alan V. Murray | encyclopedia = The Crusades: An Encyclopedia | volume = 1 | pages = 24 | publisher = [[ABC-CLIO]] | location = [[Santa Barbara, California|Santa Barbara]] | year = 2006 | url = http://books.google.com/books?id=6cSXSgAACAAJ | oclc = 70122512
+]==]
+}, {
+[==[
+author=Skousen, Royal | author-link=Royal Skousen | title=Book of Mormon Editions (1830-1981) | encyclopedia=[[Encyclopedia of Mormonism]] | year=1992 | volume=1 | pages=175–6 | publisher=[[Macmillan Publishers (United States)|Macmillan]] | url=http://eom.byu.edu/index.php/Book_of_Mormon_Editions_(1830-1981) | access-date=2009-02-12
+]==]
+}, {
+[==[
+ last = Morère
+ | first = J. E.
+ | title = Aguilon, François d'
+ | encyclopedia = [[Dictionary of Scientific Biography]]
+ | volume = 1
+ | pages = 81
+ | publisher = Charles Scribner's Sons
+ | location = New York
+ | year = 1970
+ | isbn = 0-684-10114-9
+]==]
+}, {
+[==[
+ title = Clipper
+ | encyclopedia = New International Encyclopaedia
+ | volume = 5
+ | pages = 39
+ | publisher = Dodd Mead and Company
+ | year = 1909
+ | quote = Clipper ... probably connected with Dutch ''klepper'', fast horse
+ | url = http://books.google.com/?id=qycVAAAAYAAJ&dq=%22clipper%20ship%22&pg=PA39#v=onepage
+ | access-date =6 Mar. 2010
+]==]
+}, {
+[==[
+last= Smith |first= Peter |encyclopedia= A concise encyclopedia of the Bahá'í Faith |title= satan |year= 2000 |publisher=Oneworld Publications |location= Oxford |isbn= 1-85168-184-1 |pages= 304
+]==]
+}, {
+[==[
+chapter=Ethanol|title=[[#Encyc Chem|Encyclopedia of chemical technology]]|year=1991|page=813|volume=9
+]==]
+}, {
+[==[
+ first = William A.
+| last = Wallace
+| title = Albertus Magnus, Saint
+| url = http://www.u.arizona.edu/~aversa/scholastic/Dictionary of%20Scientific%20Biography/Albertus%20Magnus%20(Wallace).pdf
+| publisher = Scribner & American Council of Learned Societies
+| isbn = 978-0-684-10114-9
+| editor-last = Gillispie
+| editor-first = Charles
+| encyclopedia = [[Dictionary of Scientific Biography]]
+| volume=1
+| pages=99-103
+| location = New York
+| year = 1970
+]==]
+}, {
+[==[
+last=Kukathas |first=Chandran |author-link=Chandran Kukathas |year=1998 |title=Rand, Ayn (1905–82) |editor-last=Craig |editor-first=Edward (ed) |encyclopedia=[[Routledge Encyclopedia of Philosophy]] |location=New York |publisher=Routledge |volume=8 |pages=55–56 |isbn=0-415-07310-3 |oclc=318280731
+]==]
+}, {
+[==[
+last=Morse |first=Stephen J. |encyclopedia=Law Library - American Law and Legal Information |title=Psychopathy - What Is Psychopathy? |url=http://law.jrank.org/pages/1884/Psychopathy-What-psychopathy.html |access-date=2008-09-25 |volume=Crime and Justice Vol 3|archive-url=https://www.webcitation.org/5b5vnGYP0?url=http://law.jrank.org/pages/1884/Psychopathy-What-psychopathy.html |archive-date=2008-09-25
+]==]
+}, {
+[==[
+last= Smith|first= Peter |encyclopedia= A concise encyclopedia of the Bahá'í Faith|title= burial, "death and afterlife", evil, evil spirits, sin |year= 2000|publisher=Oneworld Publications|location= Oxford |isbn= 1-85168-184-1|pages= 96–97, 118–119, 135–136, 322–323
+]==]
+}, {
+[==[
+last=Hodges |first=Andrew |editor=Edward N. Zalta |encyclopedia=[[Stanford Encyclopedia of Philosophy]] |title=Alan Turing |url=http://plato.stanford.edu/entries/turing/ |access-date=10 January 2011 |edition=Winter 2009 |date=27 August 2007 |publisher=[[Stanford University]]
+]==]
+}, {
+[==[
+editor=[[Pete Palmer]] and Gary Gillette|encyclopedia=The 2005 ESPN Baseball Encyclopedia|title=Introduction|edition=1st Edition|year=2005|publisher=Sterling|location=New York|isbn=1-4027-2568-X
+]==]
+}, {
+[==[
+ first = Ernan
+| last = McMullin
+| title = Robert Bellarmine
+| url = http://www.encyclopedia.com/topic/Robert_Bellarmine.aspx#1
+| publisher = Scribner & American Council of Learned Societies
+| editor-last = Gillispie
+| editor-first = Charles
+| encyclopedia = [[Dictionary of Scientific Biography]]
+| year = 2008
+]==]
+}, {
+[==[
+last= |first= | author-link= | title=Islam |year=2007| encyclopedia=Encyclopædia Britannica Online | access-date=2007-11-27|location=|publisher=|url=http://www.britannica.com/eb/article-69190/Islam
+]==]
+}, {
+[==[
+author=Bliss, Michael |year=2002 |title=Macleod, John James Rickard |url=http://www.thecanadianencyclopedia.com/articles/john-james-rickard-macleod |encyclopedia=Canadian Encyclopedia
+]==]
+}, {
+[==[
+title=Penderecki, Krzysztof|last=Thomas|first=Adrian|editor-last=Sadie|editor-first=Stanley|location=London, England|year=1992|encyclopedia=[[New Grove Dictionary of Opera]]|ISBN=0-333-73432-7
+]==]
+}, {
+[==[
+encyclopedia=[[Encyclopedia of Arkansas History & Culture]]|title=Louisiana Purchase|first=Lea Flowers|last=Baker|access-date=2010-09-18|url=http://encyclopediaofarkansas.net/encyclopedia/entry-detail.aspx?entryID=2383
+]==]
+}, {
+[==[
+title=Cervantes, Miguel de|encyclopedia=The Encyclopedia Americana|year=1994
+]==]
+}, {
+[==[
+editor=Robert M. Besançon | encyclopedia=The Encyclopedia of Physics | edition=3rd | year=1990 | publisher=Van Nostrand Reinhold, New York | isbn = 0-442-00522-9 | pages = 1278–1284 | article=Vacuum Techniques
+]==]
+}, {
+[==[
+last = McFarlane | first = Ian | author-link = Ian McFarlane | encyclopedia = [[Encyclopedia of Australian Rock and Pop]] | title = Whammo Homepage | url = http://web.archive.org/web/20040405231007/http://www.whammo.com.au/index.asp | access-date =4 December 2010 | year = 1999 | publisher=[[Allen & Unwin]] | location = [[St Leonards, New South Wales|St Leonards, NSW]] | isbn = 1-86508-072-1
+]==]
+}, {
+[==[
+ last = Campbell
+ | first = J.
+ | author-link =
+ | title = Rædwald
+ | url = http://www.oxforddnb.com/view/article/23265?docPos=1
+ | encyclopedia = [[Dictionary of National Biography]]
+ | year = 2004
+ | editor-last =
+ | editor-first =
+ | editor-link =
+ | volume =
+ | location =
+ | doi = 10.1093/ref:odnb/23265
+ | publisher = Oxford University Press
+]==]
+}, {
+[==[
+title=Avicenna | encyclopedia=Encyclopaedia of Islam Online
+]==]
+}, {
+[==[
+title=Islam|encyclopedia=Encyclopaedia of Islam Online|author=L. Gardet|author2=J. Jomier
+]==]
+}, {
+[==[
+first=Ted |last=Honderich |author-link=Ted Honderich |year=2005 |title=theodicy |encyclopedia=The Oxford Companion to Philosophy |isbn=0-19-926479-1 |quote=[[John Hick]], for example, proposes a theodicy, while [[Alvin Plantinga]] formulates a defence. The idea of human free will often appears in a both of these strategies, but in different ways.
+]==]
+}, {
+[==[
+title=AskOxford Search Results – terrorist |encyclopedia=AskOxford |publisher=AskOxford |access-date=2008-07-11 | no-tracking=true
+]==]
+}, {
+[==[
+title = Virus.VBS.Redlof.a | encyclopedia = Virus Encyclopedia | publisher = Viruslist.com | date = January 15, 2004 | url = http://www.viruslist.com/viruses/encyclopedia?virusid=25409 | access-date =August 26, 2007
+]==]
+}, {
+[==[
+title=Matthew, Tobie (1544?–1628)
+|last=Sheils
+|first=William Joseph
+|encyclopedia=Oxford Dictionary of National Biography
+|publisher=Oxford University Press
+|year=2004
+]==]
+}, {
+[==[
+editor = Thomas Hockey et al. | last = Dalen | first = Benno van | title=Ulugh Beg: Muḥammad Ṭaraghāy ibn Shāhrukh ibn Tīmūr | encyclopedia = The Biographical Encyclopedia of Astronomers | publisher=Springer | year = 2007 | location = New York | pages = 1157–9 | url=http://islamsci.mcgill.ca/RASI/BEA/Ulugh_Beg_BEA.htm | isbn=978-0-387-31022-0
+]==]
+}, {
+[==[
+author=Lawson, M. K. |encyclopedia= The Medieval State: Essays Presented to James Campbell |title=Observations Upon a Scene in the Bayeux Tapestry |publisher=Hambledon Press |location=London |pages=73–92 |year=2000
+]==]
+}, {
+[==[
+last=Waugh|first=Scott L.|title=Thomas, 1st Earl of Norfolk (1300–1338)|encyclopedia=Oxford Dictionary of National Biography|publisher=Oxford University Press|location=Oxford|year=2004|doi=10.1093/ref:odnb/27196
+]==]
+}, {
+[==[
+author=Yorke, Philip Chesney|encyclopedia=Encyclopædia Britannica|title=Anne (1665–1714)|publisher=University Press|location=Cambridge|edition=11th|year=1911
+]==]
+}, {
+[==[
+editor-last = Lewis| editor-first = M. Paul| encyclopedia = Ethnologue: Languages of the World| edition = 16 | publisher = SIL International | location = Dallas, Texas| year = 2009| url = http://www.ethnologue.com/show_language.asp?code=deu
+]==]
+}
+ }, {nowiki=false, templatestyles=true})
+end
+
+function p:test_news()
+ self:preprocess_equals_preprocess_many('{{cite news/new|', '}}', '{{cite news|', '}}', {
+ {
+[==[
+ title = TITLE
+ | author = AUTHOR
+ | first = FIRST
+ | last = LAST
+ | author-link = author-link
+ | author-link2 = author-link2
+ | author2 = AUTHOR2
+ | author3 = AUTHOR3
+ | author4 = AUTHOR4
+ | author5 = AUTHOR5
+ | author6 = AUTHOR6
+ | author7 = AUTHOR7
+ | url = https://en.wikipedia.org/Main_Page
+ | format = FORMAT
+ | agency = AGENCY
+ | newspaper = NEWSPAPER
+ | publisher = PUBLISHER
+ | location = LOCATION
+ | isbn = ISBN
+ | issn = ISSN
+ | oclc = OCLC
+ | pmid = PMID
+ | pmc = PMC
+ | bibcode = BIBCODE
+ | doi = 10.DOI
+ | id = ID
+ | date = DATE
+ | page = PAGE
+ | pages = PAGES
+ | at = AT
+ | access-date = access-date
+ | language = LANGUAGE
+ | trans-title = TRANS-TITLE
+ | quote = QUOTE
+ | archive-url = https://web.archive.org/web/20190310131346/https://en.wikipedia.org/wiki/Main_Page
+ | archive-date = archive-date
+ | url-status = URLSTATUS
+ | ref = REF
+ | no-tracking=true
+]==] }, {
+
+[==[ postscript= | title=Auction Record for an Original 'Alice' | url=http://www.nytimes.com/1998/12/11/nyregion/auction-record-for-an-original-alice.html | date=11 December 1998 | periodical=The New York Times | page=B30
+]==] }, {
+
+[==[ last=Rabil | title=New York Times Starts Selling Ad Space on Front Page | url=http://www.bloomberg.com/apps/news?pid=20601103&sid=amsJuEA115pI&refer=us | date=January 5, 2009 | first=Sarah | work=Bloomberg L.P.
+]==] }, {
+
+[==[
+title=Drugs: Chips trader gets 15 years, 10 strokes
+|url=http://www.dailyexpress.com.my/news.cfm?NewsID=48660
+|work=Daily Express |location=Kota Kinabalu, Malaysia
+|date=29 March 2007 |agency=Bernama
+]==] }, {
+
+[==[title=Ученый: тунгусская катастрофа связана с водородным взрывом ядра кометы (Scientist: The Tunguska Catastrophe connected to the hydrogen explosion of a comet nucleus)|url=http://ria.ru/science/20090330/166427555.html|access-date=14 October 2010|newspaper=[[RIA Novosti]]|date=30 March 2009|language=Russian
+]==] }, {
+
+[==[ publisher=Apple Inc. | title=Statement by Apple's Board of Directors | url=http://www.apple.com/pr/library/2011/10/05Statement-by-Apples-Board-of-Directors.html | access-date=October 6, 2011
+]==] }, {
+
+[==[ last=Stella | date=14 March 2013 | first=Gian Antonio | title=Tango e battesimo, fidanzata e vangelo l'alfabeto misto di Papa Francesco | newspaper=Corriere della Sera | quote=Mio padre era di Portacomaro (Asti, ndr) e mia madre di Buenos Aires, con sangue piemontese e genovese | url=http://www.corriere.it/esteri/speciali/2013/conclave/notizie/14-mar-papa-tango-fidanzata_1069e952-8c70-11e2-ab2c-711cc67f5f67.shtml | language=Italian | access-date=14 March 2013
+]==] }, {
+
+[==[ archive-url=http://web.archive.org/web/20051001062114/http://www.cnn.com/2005/WORLD/europe/09/23/ | date=23 September 2005 | publisher=CNN | title=Cardinal breaks conclave vow of secrecy | archive-date=1 October 2005 | agency=Associated Press | url=http://www.cnn.com/2005/WORLD/europe/09/23/conclave.diary.ap/index.html | access-date=13 March 2013
+]==] }, {
+
+[==[ date=17 March 2013 | author=Miroff, Nick | page=27 | title=Pope's activity in Dirty War Draws Scrutiny | location=Sec. 1 | agency=Washington Post | work=Chicago Tribune | access-date=17 March 2013|
+no-tracking=true ]==] }, {
+
+[==[ date=916 | title=Mahdia founded |last=El Fatimi]==] }, {
+
+[==[ author=[[Benedict Anderson]]|title=In the World-Shadow of Bismarck and Nobel|publisher=[[New Left Review]]|date=July–August 2004|url=http://newleftreview.org/II/28/benedict-anderson-in-the-world-shadow-of-bismarck-and-nobel]==] }, {
+
+[==[ url=http://findarticles.com/p/articles/mi_qa3884/is_200603/ai_n17181949/pg_1?tag=artBody;col1|title=City infrastructures and city dwellers: Accommodating the automobile in twentieth-century Paris|access-date=3 August 2008|author=Mathieu Flonneau|publisher=The Journal of Transport History | year=2006]==] }, {
+
+[==[ url=http://news.bbc.co.uk/1/hi/in_depth/4417096.stm|title=Special Report: Riots in France|date=9 November 2005|access-date=17 November 2007|publisher=BBC News ]==] }, {
+
+[==[ url=http://hn.wenweipo.com/news/zhuanti/2012-11-16/23713.html | title=本报独家探访河南邓州习营村 | date=2012-11-16 | publisher=[[Wen Wei Po]] |access-date=2012-11-156]==] }, {
+
+[==[ url=http://www.nytimes.com/2012/11/16/world/asia/new-chinese-leader-offers-few-hints-of-a-shift-in-direction.html|title=New Chinese Leader Offers Few Hints of a Shift in Direction|first=Ian|last=Johnson|date=2012-11-15|work=The New York Times|access-date=2012-11-15]==] }, {
+
+[==[ first=Jonathan | last=Watts | url=http://www.guardian.co.uk/world/2007/oct/26/china.uknews4 |title=Most corrupt officials are from poor families but Chinese royals have a spirit that is not dominated by money | access-date=11 June 2008 |work=The Guardian |location=London |date= 26 October 2007]==] }, {
+
+[==[ last=Bazar|first=Emily|title=Immigrants Make Pilgrimage to Pope | work=USA Today | date=16 April 2008 | url=http://www.usatoday.com/news/religion/2008-04-15-popeimmigrants_N.htm | access-date=3 May 2008]==] }, {
+
+[==[ author=David Willey |url=http://www.bbc.co.uk/news/world-europe-10645748 |title=Vatican 'speeds up' abuse cases |work=BBC News |date=15 July 2010 |access-date=28 October 2010]==] }, {
+
+[==[ title=The economy of heat |publisher=The Economist |date=2007-04-12 |url=http://www.economist.com/node/8952496?story_id=8952496 |access-date=2008-06-06]==] }, {
+
+[==[ last=Alves |first=Fabio |last2=Caminada |first2=Carlos |title=Brazilian Debt Raised to Investment Grade by S&P |publisher=Reuters |date=2008-04-30 |url=http://www.bloomberg.com/apps/news?pid=newsarchive&sid=a86v4f6_W2Jg |access-date=2008-06-09]==] }, {
+
+[==[ author= | title=Gwynne Shotwell: Executive Profile & Biography | url=http://investing.businessweek.com/research/stocks/private/person.asp?personId=39083380& privcapId=7702894& previousCapId=7702894& previousTitle=Space%20Exploration%20Technologies%20Corp | newspaper=Business Week| publisher=Bloomburg | location=New York | date=2011-12-01| access-date=2011-12-01 | archive-url=https://www.webcitation.org/63bzdtgbl?url=http://investing.businessweek.com/research/stocks/private/person.asp?personId=39083380&privcapId=7702894&previousCapId=7702894&previousTitle=Space%20Exploration%20Technologies%20Corp | url-status=live | archive-date=2011-12-01]==] }, {
+
+[==[ first= Irene | last= Klotz | title= SpaceX's Dragon Capsule Returns Safely To Earth|newspaper=Discovery News|publisher=Discovery Communications | location= Silver Spring, Maryland | date=2010-12-08 | url=http://news.discovery.com/space/spacexs-dragon-capsule-returns-safely-to-earth.html |access-date=2010-12-08|archive-url=https://www.webcitation.org/63c6KAVeX?url=http://news.discovery.com/space/spacexs-dragon-capsule-returns-safely-to-earth.html| archive-date=2011-12-01]==] }, {
+
+[==[ last=Engel|first=Max |title=Launch Market on Cusp of Change |url=http://www.satellitetoday.com/via/satellitegetspersonal/Launch-Market-on-Cusp-of-Change_40648.html |access-date=2013-02-15 |newspaper=Satellite Today |date=2013-03-01 |quote=''SpaceX is not the first private company to try to break through the commercial space launch market. The company, however, appears to be the real thing. Privately funded, it had a vehicle before it got money from NASA, and while NASA’s space station resupply funds are a tremendous boost, SpaceX would have existed without it.'' ]==] }, {
+
+[==[title=Bird flu has jumped to baby seals, scientists discover|url=http://edition.cnn.com/2012/07/31/health/baby-seals-avian-flu/index.html?hpt=hp_c4|access-date=31 July 2012|newspaper=[[CNN]]|date=31 July 2012]==] }, {
+
+[==[url=http://www.guardian.co.uk/film/2010/mar/10/oscars-farrah-fawcett|title=Farrah Fawcett:Oscars director apologises for 'In Memoriam' omission|work=The Guardian |access-date=March 8, 2010 | location=London | first=Ben | last=Child | date=March 10, 2010| archive-url= http://web.archive.org/web/20100414020632/http://www.guardian.co.uk/film/2010/mar/10/oscars-farrah-fawcett| archive-date= April 14, 2010 | url-status=live]==] }, {
+
+[==[url=http://latimesblogs.latimes.com/files/2009/02/being-a-member.html |title=Being an Oscar voter *doesn't* mean never having to say you're sorry |access-date=October 4, 2009 | work=The Los Angeles Times |url-status=dead]==] }, {
+
+[==[author=[[Donald G. McNeil, Jr.]] |title=Precursor to H.I.V. Was in Monkeys for Millennia |url=http://www.nytimes.com/2010/09/17/health/17aids.html?_r=1&src=me&ref=general |quote=Dr. Marx believes that the crucial event was the introduction into Africa of millions of inexpensive, mass-produced syringes in the 1950s. ... suspect that the growth of colonial cities is to blame. Before 1910, no Central African town had more than 10,000 people. But urban migration rose, increasing sexual contacts and leading to red-light districts.|work=[[New York Times]] |date=September 16, 2010 |access-date=2010-09-17 ]==] }, {
+
+[==[ url=http://news.bbc.co.uk/2/hi/technology/7091190.stm|title=BBC News: History of Technology|date=November 15, 2007]==] }, {
+
+[==[ url = http://findarticles.com/p/articles/mi_hb197/is_200401/ai_n5556112| title = The Story Behind Apple's '1984' TV commercial: Big Brother at 20| access-date =May 9, 2008| last = Cellini| first = Adelia | date=January 2004| work = [[Macworld]] 21.1, page 18| archive-url = http://web.archive.org/web/20080626112220/| archive-date = June 26, 2008]==] }, {
+
+[==[ last = Spector| first = G| title = Apple's Jobs Starts New Firm, Targets Education Market| work = [[PC Week]]| page = 109| date = September 24, 1985]==] }, {
+
+[==[ url=http://www.cnn.com/2010/TECH/mobile/06/07/apple.wwdc.preview/index.html | title=Apple unveils iPhone 4, 'biggest leap we've taken' since first model | work=CNN | first1=Brandon |last1=Griggs | first2=John D. |last2= Sutter | date=June 8, 2010 | access-date=July 5, 2010| archive-url= http://web.archive.org/web/20100708063056/| archive-date= July 8, 2010 | url-status=live]==] }, {
+
+[==[ last=Nichols | date=26 March 2010 | first=Vincent | title=The Church is not trying to cover anything up | url=http://www.timesonline.co.uk/tol/comment/columnists/guest_contributors/article7076344.ece | work=The Times | location=London | access-date=22 May 2010 ]==] }
+ }, {nowiki=false, templatestyles=true})
+end
+
+function p:test_journal()
+ self:preprocess_equals_preprocess_many('{{cite journal/new|', '}}', '{{cite journal|', '}}', {
+ {
+[==[
+ last1 = LAST1
+ | first1 = FIRST1
+ | author-link1 = author-link1
+ | last2 = LAST2
+ | first2 = FIRST2
+ | author-link2 = author-link2
+ | editor-last = EDITOR-LAST
+ | editor-first = EDITOR-FIRST
+ | editor-link = EDITOR-LINK
+ | date = DATE
+ | year = YEAR
+ | title = TITLE
+ | trans-title = TRANS-TITLE
+ | journal = JOURNAL
+ | volume = VOLUME
+ | issue = ISSUE
+ | series = SERIES
+ | pages = PAGES
+ | location = LOCATION
+ | publisher = PUBLISHER
+ | language = LANGUAGE
+ | format = FORMAT
+ | type = TYPE
+ | arxiv = ARXIV
+ | id = ID
+ | isbn = ISBN
+ | issn = ISSN
+ | oclc = OCLC
+ | pmid = PMID
+ | pmc = PMC
+ | bibcode = BIBCODE
+ | doi = 10.DOI
+ | access-date = access-date
+ | url = https://en.wikipedia.org/Main_Page
+ | archive-url = https://web.archive.org/web/20190310131346/https://en.wikipedia.org/wiki/Main_Page
+ | archive-date = 1 January 2010
+ | lay-source = LAYSOURCE
+ | lay-url = https://en.wikipedia.org/Wikipedia
+ | lay-date = 2010-01-01
+ | quote = QUOTE
+ | ref = REF
+ | postscript = POSTSCRIPT
+|no-tracking = true
+]==] }, {
+
+[==[
+type=Type | title=Article | format=Format | author=Author | journal=Journal | no-tracking=true
+]==] }, {
+
+[==[
+department=Bryan on Scouting | last=Wendell | title=Calendar of New Merit Badges | url=http://blog.scoutingmagazine.org/merit-badge-calendar/ | journal=Scouting | first=Bryan ]==] },{
+
+[==[
+archive-url=http://wikiwix.com/cache/?url=http%3A%2F%2Fphysics.aps.org%2Farticles%2Fv3%2F98 | date=November 22, 2010 | doi=10.1103/Physics.3.98 | first1=Paul | volume=3 | editor-first=Gene D. | editor-last=Sprouse | url=http://physics.aps.org/articles/v3/98 | issue=98 | journal=Physics | title=Meet a superpartner at the LHC | issn=1943-2879 | publisher=American Physical Society | archive-date=2011-02-22 | oclc=233971234 | location=New York | bibcode=2010PhyOJ...3...98L | last1=Langacker | access-date=21 February 2011
+]==] }, {
+
+[==[
+archive-url=http://wikiwix.com/cache/?url=http%3A%2F%2Fphysics.aps.org%2Farticles%2Fv3%2F98 | date=November 22, 2010 | doi=10.1103/Physics.3.98 | doi-access=free | first1=Paul | volume=3 | editor-first=Gene D. | editor-last=Sprouse | url=http://physics.aps.org/articles/v3/98 | issue=98 | journal=Physics | title=Meet a superpartner at the LHC | issn=1943-2879 | publisher=American Physical Society | archive-date=2011-02-22 | oclc=233971234 | location=New York | bibcode=2010PhyOJ...3...98L | last1=Langacker | access-date=21 February 2011
+]==] }, {
+
+[==[ author=Sammy De Grave, N. Dean Pentcheff, Shane T. Ahyong ''et al.'' |year=2009 |title=A classification of living and fossil genera of decapod crustaceans |journal=[[Raffles Bulletin of Zoology]] |volume=Suppl. 21 |pages=1–109 |url=http://rmbr.nus.edu.sg/rbz/biblio/s21/s21rbz1-109.pdf |format=[[Portable Document Format|PDF]]
+
+]==] }, {
+
+[==[ author=Tin-Yam Chan |year=2010 |chapter=Annotated checklist of the world's marine lobsters (Crustacea: Decapoda: Astacidea, Glypheidea, Achelata, Polychelida) |editor=Martyn E. Y. Low and S. H. Tan |title=Annotated checklist of anomuran decapod crustaceans of the world (exclusive of the Kiwaoidea and families Chirostylidae and Galatheidae of the Galatheoidea) and marine lobsters of the world |journal=[[Zootaxa]] |volume=Suppl. 23 |pages=153–181 |url=http://rmbr.nus.edu.sg/rbz/biblio/s23/s23rbz153-181.pdf |format=[[Portable Document Format|PDF]]
+
+]==] }, {
+
+[==[ last=Frątczak|first=Sławomir Z.|language=Polish | url=http://www.glos.com.pl/Archiwum_nowe/Rok+2005/032/strona/Cud.html | archive-url=http://web.archive.org/web/20070708173639/ | archive-date=2007-07-08 | journal=[[Głos (1991)|Głos]]|issue=32/2005 | year=2005 | title=Cud nad Wisłą|access-date=June 18, 2006
+
+]==] }, {
+
+[==[ author= |title=The fourth report on the diagnosis, evaluation, and treatment of high blood pressure in children and adolescents |journal=Pediatrics |volume=114 |issue=2 Suppl 4th Report |pages=555–76 |date=August 2004|pmid=15286277 |doi= 10.1542/peds.114.2.S2.555|url= |author1= National High Blood Pressure Education Program Working Group on High Blood Pressure in Children and Adolescents
+
+]==] }, {
+
+[==[ author= |title=The fourth report on the diagnosis, evaluation, and treatment of high blood pressure in children and adolescents |journal=Pediatrics |volume=114 |issue=2 Suppl 4th Report |pages=555–76 |date=August 2004|pmid=15286277 |doi= 10.1542/peds.114.2.S2.555|hdl=2027/uc1.c095473177|hdl-access=free|url= |author1= National High Blood Pressure Education Program Working Group on High Blood Pressure in Children and Adolescents
+
+]==] }, {
+
+[==[ author=Milazzo S, Ernst E, Lejeune S, Schmidt K |title=Laetrile treatment for cancer |journal=Cochrane Database Syst Rev |issue=2 |pages=CD005476 |year=2006 |pmid=16625640 |doi=10.1002/14651858.CD005476.pub2 |editor1-last=Milazzo |editor1-first=Stefania
+
+]==] }, {
+
+[==[ author=M. F. Land |title=Superposition images are formed by reflection in the eyes of some oceanic decapod Crustacea |journal=[[Nature (journal)|Nature]] |year=1976 |volume=263 |pages=764–765 |doi=10.1038/263764a0 |pmid=995187 |issue=5580
+]==] }, {
+
+[==[ author=Dale Tshudy & Loren E. Babcock |year=1997 |title=Morphology-based phylogenetic analysis of the clawed lobsters (family Nephropidae and the new family Chilenophoberidae) |journal=[[Journal of Crustacean Biology]] |volume=17 |issue=2 |pages=253–263 |jstor=1549275
+]==] }, {
+
+[==[ author=M. Kottek|author2=J. Grieser|author3=C. Beck|author4=B. Rudolf|author5=F. Rubel|title=World Map of the Köppen-Geiger climate classification updated|journal=Meteorol. Z.|volume=15|pages=259–263|url=http://koeppen-geiger.vu-wien.ac.at/pics/kottek_et_al_2006.gif|doi=10.1127/0941-2948/2006/0130|access-date=April 22, 2009|year=2006
+]==] }, {
+
+[==[ last = Boddington | first = Ann | title = Sejanus. Whose Conspiracy? | journal = The American Journal of Philology | volume = 84 | issue = 1 | pages = 1–16 | date = January 1963 | doi = 10.2307/293155 | jstor = 293155
+]==] }, {
+
+[==[ vauthors=Zubcevic J, Waki H, Raizada MK, Paton JF |title=Autonomic-immune-vascular interaction: an emerging concept for neurogenic hypertension |journal=Hypertension |volume=57 |issue=6 |pages=1026–33 |date=June 2011 |pmid=21536990 |pmc=3105900 |doi=10.1161/HYPERTENSIONAHA.111.169748 |url=http://hyper.ahajournals.org/content/57/6/1026.long
+]==] }, {
+
+[==[ author = Whelton PK |name-list-style=vanc | year = 2002 |title = Primary prevention of hypertension:Clinical and public health advisory from The National High Blood Pressure Education Program | url = | journal = JAMA | volume = 288 | issue = 15| pages = 1882–8 |doi = 10.1001/jama.288.15.1882 | pmid = 12377087 | author2 = He J | author3 = Appel LJ | author4 = Cutler JA | author5 = Havas S | author6 = Kotchen TA | display-authors = 6 | last7 = Roccella | first7 = EJ | last8 = Stout | first8 = R | last9 = Vallbona | first9 = C
+|no-tracking=true ]==] }, {
+
+[==[ vauthors=Alcocer L, Cueto L |title=Hypertension, a health economics perspective |journal=Therapeutic Advances in Cardiovascular Disease |volume=2 |issue=3 |pages=147–55 |date=June 2008 |pmid=19124418 |doi=10.1177/1753944708090572 |url=http://tak.sagepub.com/cgi/pmidlookup?view=long&pmid=19124418 |access-date=2009-06-20
+]==] }, {
+
+[==[ title = Are EU Trade Sanctions On Burma Compatible With WTO Law? | journal=Are EU Trade Sanctions on Burma Compatible with WTO Law? | first = Robert | last = Howse | author2 = Jared M. Genser | pages = 166+| id = | url = http://students.law.umich.edu/mjil/article-pdfs/v29n2-howse-genser.pdf | access-date =7 November 2010 | quote = repressive and abusive military regime
+]==] }, {
+
+[==[ journal = [[Science (journal)|Science]] | last1 = Wodinsky | first1 = Jerome | title = Hormonal Inhibition of Feeding and Death in Octopus: Control by Optic Gland Secretion | date = 2 December 1977 | volume = 198 | issue = 4320| pages = 948–951 | url = http://www.sciencemag.org/content/198/4320/948.abstract | access-date= 27 November 2011 | doi = 10.1126/science.198.4320.948
+]==] }, {
+
+[==[ vauthors=Karakurt F |title=Comparison of the clinical efficacy of flutamide and spironolactone plus ethinyloestradiol/cyproterone acetate in the treatment of hirsutism: a randomised controlled study |journal=Adv Ther |volume=25 |issue=4 |pages=321–8 |date=April 2008 |isbn=1232500800395
+]==] }, {
+
+[==[ title = Mr. Mackintosh's New God | first = George Jacob | last = Holyoake | author-link = George Holyoake | magazine = [[w:The Oracle of Reason|The Oracle of Reason, Or, Philosophy Vindicated]] | volume = 1 | issue = 23 | year = 1842 | page = 186 | url = http://books.google.com/books?id=BFY9AAAAYAAJ&pg=PA186 | quote = On the contrary, I, as an Atheist, simply profess that I do not see sufficient reason to ''believe'' that there is a god. I do not pretend to ''know'' that there is no god. The whole question of god's existence, ''belief'' or ''disbelief'', a question of probability or of improbability, not knowledge.
+]==] }, {
+
+[==[ last1 = Arenillas | first1 = Miguel | last2 = Castillo | first2 = Juan C. | title = Dams from the Roman Era in Spain. Analysis of Design Forms (with Appendix) | journal = 1st International Congress on Construction History [20th–24th January] | publication-place = Madrid | year = 2003 | url = http://www.traianvs.net/textos/presas_in.htm#_ednref4
+]==] }, {
+
+[==[ author=International Union of Crystallography |year=1992 |title=Report of the Executive Committee for 1991 |journal=Acta Crystallogr. A |volume=48 |issue= 6|pages=922 |doi=10.1107/S0108767392008328
+]==] }, {
+
+[==[ author=International Union of Crystallography |year=1992 |title=Report of the Executive Committee for 1991 |journal=Acta Crystallogr. A |volume=48 |issue= 6|pages=922 |doi=10.1107/S0108767392008328|pmc=1438678
+]==] }, {
+
+[==[ url = http://www.minsocam.org/ammin/AM66/AM66_885.pdf|journal = American Mineralogist|volume = 66|page=885|year= 1981|title= The largest crystals|author = Rickwood, P. C.
+]==] }, {
+
+[==[ last=Watling|first=H. R.|title=The bioleaching of sulphide minerals with emphasis on copper sulphides — A review | journal=Hydrometallurgy | year=2006 | volume=84 | issue=1, 2 | pages=81–108 | url=http://infolib.hua.edu.vn/Fulltext/ChuyenDe/ChuyenDe07/CDe53/59.pdf | format=PDF | doi=10.1016/j.hydromet.2006.05.001
+]==] }, {
+
+[==[ vauthors=Richmond SJ, Brown SR, Campion PD, Porter AJ, Moffett JA, Jackson DA, Featherstone VA, Taylor AJ |title=Therapeutic effects of magnetic and copper bracelets in osteoarthritis: a randomised placebo-controlled crossover trial|journal=Complement Ther Med.|year=2009|volume=17|issue=5-6|pages=249–256|pmid=19942103|doi=10.1016/j.ctim.2009.07.002
+]==] }, {
+
+[==[ author=Kivelson G. M., Russell, C. T. |title=Introduction to Space Physics |publisher=Cambridge University Press |year=1995|isbn=0-521-45714-9
+]==] }, {
+
+[==[ last=Quigg| first=Catherine T.| title=Tritium Warning| journal=Bulletin of the Atomic Scientists| volume=40|issue=3| pages=56–57|date=March 1984
+]==] }, {
+
+[==[ last1 = Ralston | first1 = NVC | last2 = Raymond | first2 = LJ | year = 2010 | title = Dietary selenium's protective effects against methylmercury toxicity | url = | journal = Toxicology | volume = 278 | issue = | pages = 112–123
+]==] }, {
+
+[==[ author=Aller TA, Wildsoet C |title=Bifocal soft contact lenses as a possible myopia control treatment: a case report involving identical twins |journal=Clin Exp Optom |volume=91 |issue=4 |pages=394–9 |date=July 2008 |pmid=18601670 |doi=10.1111/j.1444-0938.2007.00230.x |url=
+]==] }, {
+
+[==[ pmid=17742735|year=1969|last1=Gorman|first1=CF|title=Hoabinhian: A pebble-tool complex with early plant associations in southeast Asia|volume=163|issue=3868|pages=671–3|doi=10.1126/science.163.3868.671|journal=Science
+]==] }, {
+
+[==[ last1 = Tormmsdof | first1 = V. | year = 1966 | title = Progressive metamorphose kieseliger karbonatgesteine in den Zentralalpen zwischen Bernina und Simplon | url = | journal = Schweizerische Mineralogische und Petrographische Mitteilungen = Bulletin Suisse de Mineralogie et Petrographie | volume = 46 | issue = | pages = 431–460
+]==] }, {
+
+[==[ author=Kivelson G. M., Russell, C. T. |title=Introduction to Space Physics |publisher=Cambridge University Press |year=1995|isbn=0-521-45714-9
+]==] }, {
+
+[==[ author=Ellenberger, C. Leroy|date=Winter 1984 |author-link=C. Leroy Ellenberger |title=Worlds in Collision in Macmillan's Catalogues |journal=Kronos | volume=9 | issue=2 | url=http://www.catastrophism.com/cdrom/pubs/journals/kronos/vol0902/index.htm |access-date=2009-05-16
+]==] }, {
+
+[==[ author = Zapolski TC, Cyders MA, Smith GT | title = Positive urgency predicts illegal drug use and risky sexual behavior | journal = Psychol Addict Behav | volume = 23 | issue = 2 | pages = 348–54 | date = June 2009 | pmid = 19586152 | pmc = 2709762 | doi = 10.1037/a0014684
+]==] }, {
+
+[==[ first=J. | last=Blackwell | author2 =M.R. Nagarajan |author3= T.B. Hoitink | title=The Structure of the Hard Segments in MDI/diol/PTMA Polyurethane Elastomers | publisher=American Chemical Society | location=Washington, D.C. | year=1981 | issn=0097-6156/81/0172-0179
+]==] }, {
+
+[==[ author=Ehret GB |name-list-style=vanc |title=Genetic variants in novel pathways influence blood pressure and cardiovascular disease risk |journal=Nature |volume=478 |issue=7367 |pages=103–9 |date=October 2011 |pmid=21909115 |doi=10.1038/nature10405 |author2=Munroe PB |author3=Rice KM|display-authors=3 |last4=Bochud |first4=Murielle |last5=Johnson |first5=Andrew D. |last6=Chasman|first6=Daniel I. |last7=Smith |first7=Albert V. |last8=Tobin |first8=Martin D. |last9=Verwoert|first9=Germaine C. |pmc=3340926
+]==] }, {
+
+[==[ author=Lewington S, Clarke R, Qizilbash N, Peto R, Collins R |title=Age-specific relevance of usual blood pressure to vascular mortality: a meta-analysis of individual data for one million adults in 61 prospective studies |journal=Lancet |volume=360 |issue=9349 |pages=1903–13 |date=December 2002 |pmid=12493255 |doi= 10.1016/S0140-6736(02)11911-8|url=
+]==] }, {
+
+[==[ author = Steiner DF, Oyer PE | title = The biosynthesis of insulin and a probable precursor of insulin by a human islet cell adenoma | journal = Proc. Natl. Acad. Sci. U.S.A. | volume = 57 | issue = 2 | pages = 473–480 | date = February 1967 | pmid = 16591494 | pmc = 335530 | doi = 10.1073/pnas.57.2.473| url =
+]==] }, {
+
+[==[ author = Menting JG, Whittaker J, Margetts MB, Whittaker LJ, Kong GK-W, Smith BJ, Watson CJ, Žáková L, Kletvíková E, JJ, Chan SJ, Steiner DF, Dodson GG, Brzozowski AM, Weiss MA, Ward CW, Lawrence MC | title = How insulin engages its primary binding site on the insulin receptor | journal = Nature | year = 2013 | volume = 493 | issue = 7431 | pages = 241–245 | doi = 10.1038/nature11781 | lay-url = http://www.abc.net.au/news/2013-01-10/australian-researchers-crack-insulin-mechanism/4458974 | lay-source = Australian Broadcasting Commission
+]==] }, {
+
+[==[ author=J Clemens, PG Jones, NH Gilbert|date=|year=1977 |title=Effect of seed treatments on germination in Acacia|journal=Australian Journal of Botany |volume=25 |issue=3 |pages=269–267 |pmid=|doi=10.1071/BT9770269|url=http://www.publish.csiro.au/nid/65/paper/BT9770269.htm
+]==] }, {
+
+[==[ title=Martinez Beavers |author=Aleta George |url=http://baynature.org/articles/jan-mar-2008/ear-to-the-ground/martinez-beavers |year=2008 |magazine=Bay Nature |publisher=Bay Nature Institute |access-date=November 6, 2009
+]==] }, {
+
+[==[ author = Weissman KJ, Müller R |title = Protein-protein interactions in multienzyme megasynthetases |journal = ChemBioChem |volume = 9 |issue = 6 |pages = 826–48 |year = 2008 |pmid = 18357594 |doi = 10.1002/cbic.200700751
+]==] }, {
+
+[==[ last1 = Coyne | first1 = Jerry A. | author2 = Barton, Turelli | title = Perspective: A Critique of Sewall Wright's Shifting Balance Theory of Evolution | journal = Evolution | year = 1997 | volume = 51 | issue = 3 | series = 3 | pages = 643–671 | doi = 10.2307/2411143
+]==] }, {
+
+[==[ doi = 10.1086/377226 |title = First-Year Wilkinson Microwave Anisotropy Probe (WMAP) Observations: Determination of Cosmological Parameters |first = D. N. |last = Spergel |journal = The Astrophysical Journal Supplement Series |volume = 148 |year = 2003 |issue = 1 |pages = 175–94 |last2 = Verde |first2 = L. |last3 = Peiris |first3 = H. V. |last4 = Komatsu |first4 = E. |last5 = Nolta |first5 = M. R. |last6 = Bennett |first6 = C. L. |last7 = Halpern |first7 = M. |last8 = Hinshaw |first8 = G. |last9 = Jarosik |first9 = N. |bibcode = 2003ApJS..148..175S |arxiv = astro-ph/0302209
+| no-tracking = true
+]==] }
+}, {nowiki=false, templatestyles=true})
+end
+
+function p:test_book()
+ self:preprocess_equals_preprocess_many('{{cite book/new|', '}}', '{{cite book|', '}}', {
+ {
+[==[
+ last = LAST
+| first = FIRST
+| author-link = author-link
+| last2 = LAST2
+| first2 = FIRST2
+| author-link2 = author-link2
+| editor-last = EDITOR-LAST
+| editor-first = EDITOR-FIRST
+| editor-link = EDITOR-LINK
+| editor2-last = EDITOR2-LAST
+| editor2-first = EDITOR2-FIRST
+| editor2-link = EDITOR2-LINK
+| others = OTHERS
+| title = TITLE
+| trans-title = TRANS-TITLE
+| url = https://en.wikipedia.org/Main_Page
+| archive-url = https://web.archive.org/web/20190310131346/https://en.wikipedia.org/wiki/Main_Page
+| archive-date = January 1, 2010
+| format = FORMAT
+| access-date = 1 January, 2010
+| type = TYPE
+| edition = EDITION
+| series = SERIES
+| volume = VOLUME
+| date = DATE
+| origyear = ORIGYEAR
+| year = YEAR
+| publisher = PUBLISHER
+| location = LOCATION
+| language = LANGUAGE
+| isbn = ISBN
+| oclc = OCLC
+| lccn = LCCN
+| doi = 10.DOI
+| bibcode = BIBCODE
+| id = ID
+| page = PAGE
+| pages = PAGES
+| nopp = NOPP
+| at = AT
+| chapter = CHAPTER
+| trans-chapter = TRANS-CHAPTER
+| chapterurl = https://en.wikipedia.org/Main_Page#top
+| quote = QUOTE
+| ref = REF
+| lay-url = https://en.wikipedia.org/Wikipedia
+| lay-date = 2010-01-01
+| author-mask = AUTHOR-MASK
+| display-authors = 10
+| postscript = POSTSCRIPT
+| no-tracking = true
+]==] }, {
+
+[==[ last=Rabinovich|first=Viktor Abramovich |author2=Vasserman, A. A.|author3=Nedostup, V. I. |author4=Veksler, L. S.|title=Thermophysical properties of neon, argon, krypton, and xenon|year=1988|edition=English-language |publisher=Hemisphere Publishing Corp. |location=Washington, DC|isbn=0-89116-675-0 |url=http://adsabs.harvard.edu/abs/1988wdch...10.....R |access-date=2009-04-02
+]==] }, {
+
+[==[ author=Anonymous|editor=Daniel Coit Gilman |editor2=Harry Thurston Peck |editor3=Frank Moore Colby |year=1904|title=The New International Encyclopædia |publisher=Dodd, Mead and Company|page=906
+]==] }, {
+
+[==[ pages=1328–1334|title=Linus Pauling: Selected Scientific Papers|volume=2|editor=Pauling, Linus |editor2=Kamb, Barclay |place=River Edge, New Jersey|publisher=World Scientific |year=2001|isbn=981-02-2940-2|url=http://books.google.com/?id=2QduA19d_X8C&pg=PA1329
+]==] }, {
+
+[==[ title=Soedirman: Bapak Tentara Indonesia |trans-title=Soedirman: Father of the Indonesian Military |language=Indonesian |last=Adi |first=A. Kresna |publisher=Mata Padi Pressindo |isbn=978-602-95337-1-2 |location=Yogyakarta |year=2011
+]==] }, {
+
+[==[ url=http://books.google.ca/books?id=WrkzPcxBnLMC |title=Takhta untuk Rakyat: Celah-celah Kehidupan Sultan Hamengku Buwono IX |trans-title=Serving the People: The Life Story of Sultan Hamengku Buwono IX |language=Indonesian |isbn=978-979-22-6767-9 |editor1-first=Mohamad |editor1-last=Roem |editor1-link=Mohamad Roem |editor2-first=Mochtar |editor2-last=Lubis |editor2-link=Mochtar Lubis |editor3-first=Kustiniyati |editor3-last=Mochtar |editor4-first=Maimoen |editor4-last=S. |last=Nasution |first=A. H. |author-link=Abdul Haris Nasution |publisher=Gramedia Pustaka Utama |location=Jakarta |year=2011 |origyear=1982 |edition=Revised
+|no-tracking=true ]==] }, {
+
+[==[ author=Luhmann J. G., Russell C. T. |editor=J. H. Shirley and R. W. Fainbridge |title=Venus: Magnetic Field and Magnetosphere |work=Encyclopedia of Planetary Sciences |publisher=Chapman and Hall, New York|year=1997 |url=http://www-spc.igpp.ucla.edu/personnel/russell/papers/venus_mag/ |access-date=2009-06-28|isbn=978-1-4020-4520-2
+]==] }, {
+
+[==[ author=Feldman, M. S.; Ferrara, L. A.; Havenstein, P. L.; Volonte, J. E.; Whipple, P. H. |title=Manned Venus Flyby, February 1, 1967 |publisher=Bellcomm, Inc |url=http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19790072165_1979072165.pdf |format=PDF|year=1967
+]==] }, {
+
+[==[ last=Rose |first=Herbert Jennings |author-link=H.J. Rose |title=A Handbook of Greek Mythology |edition=1st |year=1959 |publisher=E.P. Dutton & Co. |location=New York |language= |isbn=0-525-47041-7 |pages=173
+]==] }, {
+
+[==[ url=http://www.ethnologue.com/show_country.asp?name=AR|title=Languages of Argentina|work=Ethnologue: Languages of the World|edition=16th|editor=Lewis, M. Paul|publisher=SIL International|place=Dallas|year=2009
+]==] }, {
+
+[==[ editor=Jean Chrétien Ferdinand Hoefer |contribution=Labarraque, Antoine-Germain |title=Nouvelle biographie universelle |volume=28 |pages=323–324 |ol=24229911M
+]==] }, {
+
+[==[ last=Crepeau |first=Bob |title=Niels Bohr: The Atomic Model |journal=Great Scientific Minds |publisher=Great Neck Publishing |date=2006-01-01 |isbn=1-4298-0723-7
+]==] }, {
+
+[==[ last=Holderness |first=Mary |title=Journey from Riga to the Crimea, with some account of the manners and customs of the colonists of new Russia. |year=1823 |publisher=Sherwood, Jones and co. |location=London |oclc=5073195 |page=316 |lccn=04024846
+]==] }, {
+
+[==[ author=Herbst, T. M.; Rix, H.-W.|year=1999 |editor=Guenther, Eike; Stecklum, Bringfried; Klose, Sylvio|title=Star Formation and Extrasolar Planet Studies with Near-Infrared Interferometry on the LBT |book-title=Optical and Infrared Spectroscopy of Circumstellar Matter, ASP Conference Series, Vol. 188. |isbn=1-58381-014-5|pages=341–350 |bibcode=1999ASPC..188..341H |publisher=Astronomical Society of the Pacific |location=San Francisco, Calif.
+]==] }, {
+
+[==[ author = Marius Turda| title = The idea of national superiority in Central Europe, 1880-1918| year = 2004| publisher = Edwin Mellen Press| isbn = 978-0-7734-6180-2 ]==] }, {
+
+[==[ author=Bhagavan NV|title=Medical Biochemistry |publisher=Harcourt/Academic Press |location=San Diego |year=2002 |isbn=0-12-095440-0|url=http://books.google.com/?id=vT9YttFTPi0C&printsec=frontcover]==] }, {
+
+[==[ author=Edgar Thorpe|title=The Pearson CSAT Manual 2012|url=http://books.google.com/books?id=1cruroSVFoUC&pg=RA3-PA38|access-date=18 November 2012|year=2012|publisher=Pearson Education India|isbn=978-81-317-6734-4|page=3]==] }, {
+
+[==[ author=Iyengar PTS |year=2001 |title=History Of The Tamils: From the Earliest Times to 600 A.D. |publisher=Asian Educational Services |isbn=81-206-0145-9 |url=http://books.google.com/books?id=ERq-OCn2cloC |pages=192–195 |access-date=29 December 2008 ]==] }, {
+
+[==[ author=Motilal (UK) Books of India|title=Tourist Guide Kerala|url=http://books.google.com/books?id=ZYfRBcLdTNYC&pg=PA11|access-date=18 November 2012|date=1 February 2008|publisher=Sura Books|isbn=978-81-7478-164-2|page=11]==] }, {
+
+[==[ author=S. N. Sadasivan|title=River Disputes in India: Kerala Rivers Under Siege|url=http://books.google.com/books?id=hhrRboi5kOcC&pg=PA223|access-date=18 November 2012|year=2003|publisher=Mittal Publications|isbn=978-81-7099-913-3|page=223]==] }, {
+
+[==[ author1=Joseph Needham|author2=Gwei-Djen Lu|author3=Ling Wang|title=Science and civilisation in China, Volume 5, Part 7|year=1987|publisher=Cambridge University Press|isbn=978-0-521-30358-3|pages=48–50]==] }, {
+
+[==[ editor=Mark W. Denny |editor2=Steven Dean Gaines |year=2007 |title=Encyclopedia of tidepools and rocky shores |publisher=[[University of California Press]] |isbn=978-0-520-25118-2 |author=Carlos Robles |chapter=Lobsters |pages=333–335 |url=http://books.google.co.uk/books?id=uufQnE7MzMkC&pg=PA333]==] }, {
+
+[==[ first=Elena|last=Aprile|author2=Bolotnikov, Aleksey E. |author3=Doke, Tadayoshi |title=Noble Gas Detectors|publisher=Wiley-VCH|year=2006 |isbn=3-527-60963-6|url=http://books.google.com/?id=tsnHM8x6cHAC&pg=PT1|pages=8–9]==] }, {
+
+[==[ first=Sidney F. |last=Ray |title=Applied Photographic Optics: Lenses and Optical Systems for Photography, Film, Video, Electronic and Digital Imaging |location= |publisher=Focal Press |year=2002 |isbn=0-240-51540-4 |page=40 |url=http://www.google.com/books?id=cuzYl4hx-B8C&printsec=frontcover#PPA40,M1 ]==] }, {
+
+[==[ last = Koch | first = John | title = Tartessian: Celtic from the Southwest at the Dawn of History in Acta Palaeohispanica X Palaeohispanica 9 (2009)| publisher=Palaeohispanica | year = 2009 | pages = 339–351 | url = http://ifc.dpz.es/recursos/publicaciones/29/54/26koch.pdf | id = | issn = 1578-5386 | access-date =17 May 2010 ]==] }, {
+
+[==[ last = Rhodes |first = Richard |year = 1986 |title = The Making of the Atomic Bomb |isbn = 0-671-65719-4 |pages = 659–660 |publisher = Simon & Schuster |location = New York]==] }, {
+
+[==[ last = Watt | first = William Montgomery |author-link = William Montgomery Watt| title = [[Muhammad at Mecca (book)|Muhammad at Mecca]]| publisher=Oxford University Press | year = 1953 | id =]==] }, {
+
+[==[ last=Cooper |first=J.C. |title=Symbolic and Mythological Animals |pages=25–26 |year=1992 |publisher=Aquarian Press |location=London |isbn=1-85538-118-4]==] }, {
+
+[==[ last=Finnegan |first=Dana G. |author2 = Emily B. McNally |title=Counseling Lesbian, Gay, Bisexual, and Transgender Substance Abusers: Dual Identities |publisher=Haworth Press |date=2002|isbn= 1-56023-925-5 |url =http://books.google.com/books?id=I32nHF_gaTsC ]==] }, {
+
+[==[ title=[[Ellipsis|Dots...]] |author=Doe, Dotty D. | publisher=[[McGraw-Hill|Dot Corp.]] |series=Dot Books Etc. |pages=23 ''[[ff.]]'' |id=Std. ]==] }, {
+
+[==[ last=Hume |first=David |author-link=David Hume |title=[[s:An Enquiry Concerning Human Understanding|An Enquiry Concerning Human Understanding]] |year=1748 |location=London]==] }, {
+
+[==[ last=Köse|first=Yavuz|editor-last=Atabaki|editor-first=Touraj|editor2-last=Brockett|editor2-first=Gavin|chapter=Vertical Bazaars of Modernity: Western Department Stores and Their Staff in Istanbul (1889–1921)|title=Ottoman and Republican Turkish Labour History|publisher=Cambridge University Press|location=Cambridge, Eng.|year=2009|isbn=978-0-521-12805-6|pages=91–114]==] }, {
+
+[==[ last=Roebuck|first=Carl|title=Ionian Trade and Colonization|year=1959|series=Monographs on Archaeology and Fine Arts|publisher=Archaeological Institute of America|location=New York|isbn=978-0-89005-528-1]==] }, {
+
+[==[ last=Wiberg|first= Egon|author2= Wiberg, Nils |author3=Holleman, Arnold Frederick |title=Inorganic Chemistry |publisher=Academic Press|year=2001|isbn=0-12-352651-5]==] }, {
+
+[==[ last1=Masters|first1=Bruce Alan|last2=Ágoston|first2=Gábor|year=2009|title=Encyclopedia of the Ottoman Empire|publisher=Infobase Publishing|location=New York|isbn=978-1-4381-1025-7]==] }, {
+
+[==[ url=http://books.google.ca/books?id=LjzZ_rVv_2MC&pg=PA30 |title=Villes et organisation de l'espace en Afrique |pages=30–31 |first1=Jérôme |last1=Aloko-N'Guessan |first2=Amadou |last2=Diallo |first3=Kokou Henri |last3=Motcho |publisher=KARTHALA Editions |year=2010 |ISBN=2-8111-0339-2]==] }, {
+
+[==[ title = Statics: Analysis and Design of Systems in Equilibrium | last = Sheppard and Tongue | publisher = Wiley and Sons | year = 2005 | page = 618 | quote = In general, for given contacting surfaces, ''μ''
k < ''μ''
s | isbn = 0-471-37299-4]==] }, {
+
+[==[ title=A Concise History of Modern India |first1=Barbara D. |last1=Metcalf |first2=Thomas R. |last2=Metcalf |author-link1=Barbara D. Metcalf |author-link2=Thomas R. Metcalf |edition=Second |location=Cambridge |publisher=Cambridge University Press |year=2006 |pages=20–21 |isbn=978-0-521-86362-9]==] }, {
+
+[==[ title=Geochemical processes in soil and groundwater: measurement—modelling—upscaling |first1=Horst D. |last1=Schulz |first2=Astrid |last2=Hadeler |author3=Deutsche Forschungsgemeinschaft |publisher=Wiley-VCH |year=2003 |isbn=3-527-27766-8 |page=67 |url=http://books.google.com/books?id=Fo1PjKW9GpUC]==] }, {
+
+[==[ title=Normans: The History of a Dynasty|last=Crouch|first=David|year=2006|publisher=Hambledon Continuum|isbn=978-1-85285-595-6Z]==] }, {
+
+[==[ title=Southeastern Ceremonial Complex : Chronology, Content, Context|editor=King, Adam|author1=Kelly, John E.|author2=Brown, James A.|author3=Hamlin, Jenn M.|author4=Kelly, Lucretia S.|author5=Kozuch, Laura|author6=Parker, Kathryn|author7=Van Nest, Julieann|chapter=Mound 34 : The Context for the Early Evidence of the Southeastern Ceremonial Complex at Cahokia|pages=57–87|isbn=978-0-8173-5409-1|publisher=University of Alabama Press]==] }, {
+
+[==[ url = http://books.google.ca/books?id=0M4Pl_VCExgC | title = Forgotten Wars: Freedom and Revolution in Southeast Asia | isbn = 978-0-674-02153-2 | last1 = Bayly | first1 = Christopher Alan | last2 = Harper | first2 = Timothy Norman | year = 2007 | location = Cambridge | publisher = Belknap Press ]==] }, {
+
+[==[ url = http://books.google.de/books?id=iX194mHFAcYC&pg=PA11 | page = 11 | title = The Correspondence of Michael Faraday | isbn = 978-0-86341-251-6 | author1 = Faraday, Michael | author2 = James, Frank A. J. L | year = 1999]==] }, {
+
+[==[ url=http://books.google.com/?id=COcVgAtqeKkC&pg=PA473|page=473|title=Handbook of semiconductor silicon technology|first1=William C.|last1=O'Mara|first2=Robert B.|last2 =Herring| first3=Lee Philip|last3=Hunt|publisher=William Andrew|year=1990|isbn=978-0-8155-1237-0]==] }, {
+
+[==[ last=Sedgwick |first=John |title=Popular Filmgoing In 1930s Britain: A Choice of Pleasures |publisher=[[University of Exeter Press]] |year=2000 |isbn=9780859896603 |pages=[http://books.google.com/books?id=YsUfc8Ijb-wC&pg=PA146 146]–148 ]==] }, {
+
+[==[ chapter=Naturalism and Physicalism | last=Fales | postscript=, | first=Evan ]==] }, {
+
+[==[ trans-title=My Book in English | last=Pan | location=Neverland | date=1965 | first=Peter | publisher=Foreign Books
+|no-tracking = true ]==] }, {
+
+[==[ trans-title=My Book in English | last=Pan | location=Neverland | date=1965 | first=Peter | publisher=Foreign Books | url = http://www.foo.com/
+|no-tracking = true ]==] }, {
+
+[==[ first5=FifthFirst | last1=FirstLast | last3=ThirdLast | last2=SecondLast | first2=SecondFirst | first4=FourthFirst | author-mask=with | last4=FourthLast | first1=FirstFirst | title=Title | last5=FifthLast | first3=ThirdFirst ]==] }
+
+}, {nowiki=false, templatestyles=true})
+end
+
+function p:test_web()
+ self:preprocess_equals_preprocess_many('{{cite web/new|', '}}', '{{cite web|', '}}', {
+ {
+[==[
+ url = URL
+ |title = TITLE
+ |last1 = LAST1
+ |first1 = FIRST1
+ |author-link1 = author-link1
+ |last2 = LAST2
+ |first2 = FIRST2
+ |author-link2 = author-link2
+ |date = DATE
+ |year = YEAR
+ |editor-last = EDITOR-LAST
+ |editor-first = EDITOR-FIRST
+ |editor = EDITOR
+ |editor-link = EDITOR-LINK
+ |editor1-last = EDITOR1-LAST
+ |editor1-first= EDITOR1-FIRST
+ |editor1-link = EDITOR1-LINK
+ |editor2-last = EDITOR2-LAST
+ |editor2-first= EDITOR2-FIRST
+ |editor2-link = EDITOR2-LINK
+ |work = WORK
+ |series = SERIES
+ |publisher = PUBLISHER
+ |location = LOCATION
+ |page = PAGE
+ |pages = PAGES
+ |at = AT
+ |language = LANGUAGE
+ |trans-title = TRANS-TITLE
+ |type = TYPE
+ |format = FORMAT
+ |arxiv = ARXIV
+ |asin = ASIN
+ |bibcode = BIBCODE
+ |doi = 10.DOI
+ |doi-broken-date = 10 June 2015
+ |isbn = ISBN
+ |issn = ISSN
+ |jfm = JFM
+ |jstor = JSTOR
+ |lccn = LCCN
+ |mr = MR
+ |oclc = OCLC
+ |ol = OL
+ |osti = OSTI
+ |pmc = PMC
+ |pmid = PMID
+ |rfc = RFC
+ |ssrn = SSRN
+ |zbl = ZBL
+ |id = ID
+ |archive-url = https://web.archive.org/web/20190310131346/https://en.wikipedia.org/wiki/Main_Page
+ |archive-date = archive-date
+ |url-status = URLSTATUS
+ |access-date = access-date
+ |quote = QUOTE
+ |ref = REF
+ |postscript = POSTSCRIPT
+|no-tracking = true
+]==] }, {
+
+[==[ url= http://www.indec.mecon.ar/nuevaweb/cuadros/2/proyecciones_provinciales_vol31.pdf |title= Proyecciones provinciales de población por sexo y grupos de edad 2001–2015 |work=Gustavo Pérez |format= PDF |publisher=[[INDEC]] |page= 16 |language= español
+]==] }, {
+
+[==[ url=http://www.gamesbids.com/eng/index.php?news=1177787226 |title= Delhi To Bid For 2020 Summer Games|access-date=5 August 2007 |date=28 April 2007 |work= gamesbids.com|publisher= Menscerto Inc.
+]==] }, {
+
+[==[ author=Staff|year=2007 |url=http://www.infoplease.com/ce6/sci/A0852881.html |title=Xenon|work=Columbia Electronic Encyclopedia |edition=6th|publisher=Columbia University Press |access-date=2007-10-23
+]==] }, {
+
+[==[ url=http://shook.pragmatism.org/skepticismaboutthesupernatural.pdf | title=Skepticism about the Supernatural | author=Shook, John R. | access-date=2012-10-02
+]==] }, {
+
+[==[ title=Bintang Mahaputera Adipurna |language=Indonesian |url=http://www.setneg.go.id/index.php?option=com_tandajasa&Itemid=43&cat=2&id=6 |work=Awards of the Republic of Indonesia |publisher=Indonesian State Secretariat |access-date=17 May 2012
+]==] }, {
+
+[==[ url=http://www.fs.fed.us/r9/publications/success_story_updates/2003-05.pdf |format=PDF|title=Success Stories |access-date=2008-04-20 |author=US Forest Service |date=May 2003 |chapter=Mules Key in Accomplishing Trail Work |publisher=US Department of Agriculture |page=4
+]==] }, {
+
+[==[ url=http://www.ommbid.com/ |title= Galactosemia |chapter=72 |author=Fridovich-Keil JL, Walter JH |format= |work=The Online Metabolic and Molecular Bases of Inherited Disease |access-date=
+]==] }, {
+
+[==[ author=Vijverberg et al. | title=Similar mode of action of pyrethroids and DDT on sodium channel gating in myelinated nerves | url=http://www.nature.com/nature/journal/v295/n5850/abs/295601a0.html | journal=Nature | volume=42 | issue=295 | year=1982 | access-date=2012-04-28
+]==] }, {
+
+[==[ url= http://www.ign.gob.ar/AreaProfesional/Geografia/DatosArgentina|title= Datos de la República Argentina|language = Spanish|trans-title = Data of the Argentine Republic|author= Rubén Albanese|year= 2009|publisher= Instituto Geográfico Nacional
+]==] }, {
+
+[==[ url=http://www.cornellpress.cornell.edu/book/?GCOI=80140100965480|author=Bamber, G.J., Gittell, J.H., Kochan, T.A. & von Nordenflytch, A. |year=2009 |title=Up in the Air: How Airlines Can Improve Performance by Engaging their Employees|publisher=Cornell University Press, Ithaca |chapter=Chapter 5
+]==] }, {
+
+[==[ access-date=2007-07-21|url=http://www.roman-emperors.org/assobd.htm#t-inx|title=De Imperatoribus Romanis|work=An Online Encyclopedia of Roman Emperors|quote= Battle of Sarmizegetusa (Sarmizegetuza), A.D. 105. During Trajan's reign one of the most important Roman successes was the victory over the Dacians. The first important confrontation between the Romans and [[Dacia|the Dacians]] had taken place in the year 87 and was initiated by Domitian. The [[praetorian prefect]] Cornelius Fuscus led five or six legions across the Danube on a bridge of ships and advanced towards [[Banat]] (in [[Romania]]). The Romans were surprised by a Dacian attack at Tapae (near the village of [[Bucova]], in Romania). [[Legion V Alaude]] was crushed and Cornelius Fuscus was killed. The victorious [[Dacia]]n general was originally known as [[Diurpaneus]] (see Manea, p.109), but after this victory he was called [[Decebalus]] (the brave one). ]==] }, {
+
+[==[ author = Fermilab | year = 2006 | title = Jobs at Fermilab: Employer Awards | url = http://lss.fnal.gov/employ/employer_awards.html | access-date = 2006-01-06 |archive-url = http://web.archive.org/web/20070110184255/http://lss.fnal.gov/employ/employer_awards.html |archive-date = January 10, 2007]==] }, {
+
+[==[ author=Posted 8 April 2000 by admin |url=http://www.foodfirst.org/media/opeds/2000/4-greenrev.html |title=Food First/Institute for Food and Development Policy |publisher=Foodfirst.org |date=8 April 2000 |access-date=25 August 2010]==] }, {
+
+[==[ first=Ray P.|last=Norris|pages=1–4 |title=Searching for the Astronomy of Aboriginal Australians |work=Conference Proceedings | year=2004 |publisher=Australia Telescope National Facility | url=http://www.atnf.csiro.au/research/AboriginalAstronomy/literature/Norris2007b.pdf |format=PDF | access-date=2009-05-16]==] }, {
+
+[==[ title =The National Revolution, 1945–50 | work =Country Studies, Indonesia | publisher =U.S. Library of Congress | date = | url =http://countrystudies.us/indonesia/16.htm | doi = | access-date = ]==] }, {
+
+[==[ last= Smith |first= Joseph Jr |author-link= Joseph Smith Jr |title= Pearl Of Great Price |url= http://lds.org/library/display/0,4945,106-1-2-1,FF.html |postscript= ]==] }, {
+
+[==[ last=Cooler | first=Richard M. | title=The Art and Culture of Burma | year=2002 | url=http://www.seasite.niu.edu/burmese/cooler/BurmaArt_TOC.htm | publisher=Northern Illinois University | location=DeKalb ]==] }, {
+
+[==[ last=Food|first=BBC|title=Tapenade | url=http://www.bbc.co.uk/food/tapenade | work=BBC Food | publisher=British Broadcasting Corporation | access-date=4 July 2011]==] }, {
+
+[==[ last=Nave| first=C. R.|title=Deuterium-Tritium Fusion| work=HyperPhysics| publisher=Georgia State University| year=2006| url=http://hyperphysics.phy-astr.gsu.edu/Hbase/nucene/fusion.html| access-date=2008-03-08]==] }, {
+
+[==[ last=Stern|first=David P.|date=2005-02-13| url=http://www-spof.gsfc.nasa.gov/stargaze/Q7.htm| title=Wave Mechanics| publisher=NASA Goddard Space Flight Center| access-date=2008-04-16]==] }, {
+
+[==[ publisher=[http://www.metalfromfinland.com/ MetalFromFinland.com] | title=Nightwish's 'Amaranth' Single Available As Flower-Fragrance-Shaped Picture Disc | url=http://www.metalfromfinland.com/news/2010-01-29_11:19/nightwishs_amaranth_single_available_as_flowerfragranceshaped_picture_disc | date= 2010-01-29 | access-date=2010-01-13]==] }, {
+
+[==[ title = How Wildfires Work|author= Bonsor, Kevin| publisher = [[HowStuffWorks]]| url = http://science.howstuffworks.com/wildfire.htm|access-date=2007-07-23| archive-url= http://web.archive.org/web/20070714174036/http://science.howstuffworks.com/wildfire.htm| archive-date= 14 July 2007 | url-status=live]==] }, {
+
+[==[ title = The real Chubby Checker, 71, was born with the name Ernest Evans. He trademarked his stage name in 1997|url = http://www.guardian.co.uk/music/2013/feb/14/chubby-checker-sues-hewlett-packard|access-date = February 14, 2013]==] }, {
+
+[==[ title=A Long Lipid, a Long Name: Docosahexaenoic Acid|url=http://www.samuelfurse.com/2011/12/a-long-name-a-long-lipid-docosahexaenoic-acid/|work=The Lipid Chronicles|access-date=2011-12-31]==] }, {
+
+[==[ title=California Symbols |publisher=California State Capitol Museum |url=http://www.capitolmuseum.ca.gov/VirtualTour.aspx?content1=1278&Content2=1374&Content3=1294 |access-date=2007-09-14| archive-url= http://web.archive.org/web/20071012123245/http://capitolmuseum.ca.gov/VirtualTour.aspx?content1=1278&Content2=1374&Content3=1294| archive-date= 12 October 2007 | url-status=live]==] }, {
+
+[==[ title=Maternal and Neonatal Tetanus Elimination by 2005 | date = November 2000 | publisher = UNICEF | url=http://www.unicef.org/immunization/files/MNTE_strategy_paper.pdf | access-date=2007-01-26 ]==] }, {
+
+[==[ title=Population Estimates|url=http://www.census.gov/popest/data/cities/totals/2011/files/SUB-EST2011-IP.csv|publisher={{URL|1=http://en.wikipedia.org/wiki/United_States_Census_Bureau|2=United States Census Bureau}} ]==] }, {
+
+[==[ title=The Structure of a Membrane|url=http://www.samuelfurse.com/2011/11/the-structure-of-a-membrane/|work=The Lipid Chronicles|access-date=2011-12-31]==] }, {
+
+[==[ title=Unit of thermodynamic temperature (kelvin) |work=SI Brochure, 8th edition |pages=Section 2.1.1.5 |url=http://www1.bipm.org/en/si/si_brochure/chapter2/2-1/2-1-1/kelvin.html |publisher=Bureau International des Poids et Mesures |year=1967 |access-date=2008-02-06]==] }, {
+
+[==[ url = http://pogoda.ru.net/climate/33345.htm | title = Weather and Climate - The Climate of Kiev | publisher = Weather and Climate (Погода и климат) | access-date = March 1, 2013 | language = Russian]==] }, {
+
+[==[ url = http://www.lanl.gov/history/people/R_Schreiber.shtml |title = Raemer Schreiber |work = Staff Biographies |publisher = Los Alamos National Laboratory |location = Los Alamos (NM) |author = LANL contributors |access-date = November 16, 2008 ]==] }, {
+
+[==[ url= http://berkleycenter.georgetown.edu/resources/countries/argentina |title=Argentina |publisher=[[Berkley Center for Religion, Peace, and World Affairs]]]==] }, {
+
+[==[ url=http://213.253.134.43/oecd/pdfs/browseit/0406041E.PDF|format=PDF|title=Competitive Cities in the Global Economy|author=OECD|access-date=30 April 2009|author-link=Organisation for Economic Co-operation and Development]==] }, {
+
+[==[ url=http://factfinder2.census.gov/bkmk/table/1.0/en/ACS/11_1YR/DP03/1600000US1714000| title=Selected Economic Characteristics: 2011 American Community Survey 1-Year Estimates (DP03): Chicago city, Illinois| publisher=U.S. Census Bureau, American Factfinder| access-date=February 8, 2013]==] }, {
+
+[==[ url=http://liftoff.msfc.nasa.gov/academy/astronauts/training.html | archive-url=http://web.archive.org/web/20070910124735/http://liftoff.msfc.nasa.gov/academy/astronauts/training.html | archive-date=2007-09-10 | title=Selection and Training of Astronauts|access-date=October 4, 2007 |publisher=NASA|year=1995|author=NASA]==] }, {
+
+[==[ url=http://quod.lib.umich.edu/cgi/t/text/text-idx?c=jii;view=text;rgn=main;idno=4750978.0016.105 |title =Environmental and Structural Inequalities in Greater Accra |access-date =22 July 2010|publisher =The Journal of the International Institute]==] }, {
+
+[==[ url=http://users.rcn.com/jkimball.ma.ultranet/BiologyPages/T/Telomeres.html |author=John W. Kimball |date=November 25, 2008 |title=Telomeres]==] }, {
+
+[==[ url=http://worldaerodata.com/wad.cgi?id=GH02526&sch=DGAA | title=Kotoka International Airport|publisher=World Aero Data|year=2009|access-date=29 October 2009]==] }, {
+
+[==[ url=http://www.bbc.co.uk/wales/music/sites/big_weekend/ | title=BBC Wales – Big Weekend|access-date=23 February 2008]==] }, {
+
+[==[ url=http://www.chem.umn.edu/class/2301/barany03f/fun/beautiful1.pdf |title=Chemistry at its Most Beautiful |access-date=2007-09-13|last=Freemantel|first=Michael |date=August 25, 2003|format=PDF |publisher=Chemical & Engineering News]==] }, {
+
+[==[ url=http://www.dublincity.ie/RecreationandCulture/DublinCityParks/Pages/Facts%20About%20Our%20Parks.aspx |title=Dublin City Council – ''Facts About Our Parks'' |publisher=Dublincity.ie |date= |access-date=14 January 2012]==] }, {
+
+[==[ url=http://www.fws.gov/news/NewsReleases/showNews.cfm?newsId=9191BAAD-F8E8-0097-B3670BDF3849EBF2|title=Fish and Wildlife Service Awards $800,000 in Grants to Explore Cause, Control of White-Nose Syndrome in Bats|date=2009-10-26|publisher=[[United States Fish and Wildlife Service]]|access-date=2009-10-30]==] }, {
+
+[==[ url=http://www.guinnessworldrecords.com/content_pages/record.asp?recordid=51451 |publisher=[[Guinness World Records]] |title=Heaviest marine crustacean |access-date=August 3, 2006 |archive-url=http://web.archive.org/web/20060528192250/ |archive-date=May 28, 2006]==] }, {
+
+[==[ url=http://www.hurriyetdailynews.com/default.aspx?pageid=438&n=new-card-alternative-to-akbil-raises-questions-2010-07-16|last=Songün|first=Sevim|work=Hürriyet Daily News|title=Istanbul Commuters Skeptical of Transit Change|date=16 July 2010|access-date=5 July 2012]==] }, {
+
+[==[ url=http://www.lboro.ac.uk/gawc/world2008t.html |title=The World According to GaWC 2008 |work=Globalization and World Cities Research Network|publisher=GaWC Loughborough University |access-date=April 29, 2009]==] }, {
+
+[==[ url=http://www.medicinenet.com/yaws/page4.htm|title=Yaws|access-date=5 August 2012|authors=Davis, Charles Patrick; Stoppler, Melissa Conrad|publisher=MedicineNet.com]==] }, {
+
+[==[ url=http://www.autoblog.com/2010/03/29/hennessey-venom-gt-a-600k-mid-engine-cobra-for-the-21st-centur/ |title=Hennessey Venom GT: A $600k mid-engine Cobra for the 21st Century |access-date=2010-03-29 |last=Lavrinc |first=Damon |date=2010-03-29 |work=[[Autoblog.com|Autoblog]] |publisher=[[Weblogs, Inc.]] ]==] }
+
+}, {nowiki=false, templatestyles=true})
+end
+
+function p:test_citation()
+ self:preprocess_equals_preprocess_many('{{citation/new|', '}}', '{{citation|', '}}', { {
+[==[
+author = AUTHOR
+| last = LAST
+| first = FIRST
+| author2 = AUTHOR2
+| last2 = LAST2
+| first2 = FIRST2
+| author-link = AUTHOR-LINK
+| author2-link = AUTHOR-LINK2
+| author-mask = AUTHOR-MASK
+| display-authors = et al
+| editor = EDITOR
+| editor-last = EDITOR-LAST
+| editor-first = EDITOR-FIRST
+| editor2 = EDITOR2
+| editor2-last = EDITOR2-LAST
+| editor2-first = EDITOR2-FIRST
+| editor-link = EDITOR-LINK
+| editor2-link = EDITOR2-LINK
+| others = OTHERS
+| publication-date = PUBLICATION-DATE
+| date = DATE
+| year = YEAR
+| origyear = ORIGYEAR
+| title = TITLE
+| chapter = CHAPTER
+| chapter-url = https://en.wikipedia.org/Main_Page#top
+| contribution = CONTRIBUTION
+| contribution-url = CONTRIBUTON-URL
+| type = TYPE
+| journal = JOURNAL
+| periodical = PERIODICAL
+| newspaper = NEWSPAPER
+| magazine = MAGAZINE
+| work = WORK
+| edition = EDITION
+| series = SERIES
+| volume = VOLUME
+| issue = ISSUE
+| publisher = PUBLISHER
+| publication-place = PUBLICATION-PLACE
+| place = PLACE
+| language = LANGUAGE
+| page = PAGE
+| pages = PAGES
+| nopp = NOPP
+| at = AT
+| id = ID
+| isbn = ISBN
+| issn = ISSN
+| oclc = OCLC
+| pmid = PMID
+| pmc = PMC
+| bibcode = BIBCODE
+| doi = 10.DOI
+| doi-inactive-date = 10 June 2015
+| url = https://en.wikipedia.org/Main_Page
+| access-date = access-date
+| format = FORMAT
+| archive-url = https://web.archive.org/web/20190310131346/https://en.wikipedia.org/wiki/Main_Page
+| archive-date = January 1, 2010
+| quote = QUOTE
+| lay-url = https://en.wikipedia.org/Wikipedia
+| lay-source = LAYSOURCE
+| lay-date = 2010-01-01
+| postscript =
+| ref = REF
+| no-tracking = true
+]==] }, {
+
+[==[ author=Anonymous|editor=Daniel Coit Gilman, Harry Thurston Peck, Frank Moore Colby |year=1904|title=The New International Encyclopædia |publisher=Dodd, Mead and Company|page=906
+]==] }, {
+
+[==[ pages=1328–1334|title=Linus Pauling: Selected Scientific Papers|volume=2|editor=Pauling, Linus; Kamb, Barclay |place=River Edge, New Jersey|publisher=World Scientific |year=2001|isbn=981-02-2940-2|url=http://books.google.com/?id=2QduA19d_X8C&pg=PA1329
+]==] }, {
+
+[==[ title=Soedirman: Bapak Tentara Indonesia |trans-title=Soedirman: Father of the Indonesian Military |language=Indonesian |last=Adi |first=A. Kresna |publisher=Mata Padi Pressindo |isbn=978-602-95337-1-2 |location=Yogyakarta |year=2011
+]==] }, {
+
+[==[ url=http://books.google.ca/books?id=WrkzPcxBnLMC |title=Takhta untuk Rakyat: Celah-celah Kehidupan Sultan Hamengku Buwono IX |trans-title=Serving the People: The Life Story of Sultan Hamengku Buwono IX |language=Indonesian |isbn=978-979-22-6767-9 |editor1-first=Mohamad |editor1-last=Roem |editor1-link=Mohamad Roem |editor2-first=Mochtar |editor2-last=Lubis |editor2-link=Mochtar Lubis |editor3-first=Kustiniyati |editor3-last=Mochtar |editor4-first=Maimoen |editor4-last=S. |last=Nasution |first=A. H. |author-link=Abdul Haris Nasution |publisher=Gramedia Pustaka Utama |location=Jakarta |year=2011 |origyear=1982 |edition=Revised
+| no-tracking=true]==] }, {
+
+[==[ author=Luhmann J. G., Russell C. T. |editor=J. H. Shirley and R. W. Fainbridge |title=Venus: Magnetic Field and Magnetosphere |work=Encyclopedia of Planetary Sciences |publisher=Chapman and Hall, New York|year=1997 |url=http://www-spc.igpp.ucla.edu/personnel/russell/papers/venus_mag/ |access-date=2009-06-28|isbn=978-1-4020-4520-2
+]==] }, {
+
+[==[ author=Feldman, M. S.; Ferrara, L. A.; Havenstein, P. L.; Volonte, J. E.; Whipple, P. H. |title=Manned Venus Flyby, February 1, 1967 |publisher=Bellcomm, Inc |url=http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19790072165_1979072165.pdf |format=PDF|year=1967
+]==] }, {
+
+[==[ last=Rose |first=Herbert Jennings |author-link=H.J. Rose |title=A Handbook of Greek Mythology |edition=1st |year=1959 |publisher=E.P. Dutton & Co. |location=New York |language= |isbn=0-525-47041-7 |pages=173
+]==] }, {
+
+[==[ url=http://www.ethnologue.com/show_country.asp?name=AR|title=Languages of Argentina|work=Ethnologue: Languages of the World|edition=16th|editor=Lewis, M. Paul|publisher=SIL International|place=Dallas|year=2009
+]==] }, {
+
+[==[ editor=Jean Chrétien Ferdinand Hoefer |contribution=Labarraque, Antoine-Germain |title=Nouvelle biographie universelle |volume=28 |pages=323–324 |ol=24229911M
+]==] }, {
+
+[==[ author=Herbst, T. M.; Rix, H.-W.|year=1999 |editor=Guenther, Eike; Stecklum, Bringfried; Klose, Sylvio|title=Star Formation and Extrasolar Planet Studies with Near-Infrared Interferometry on the LBT |book-title=Optical and Infrared Spectroscopy of Circumstellar Matter, ASP Conference Series, Vol. 188. |isbn=1-58381-014-5|pages=341–350 |bibcode=1999ASPC..188..341H |publisher=Astronomical Society of the Pacific |location=San Francisco, Calif.
+]==] }, {
+
+[==[ date=4 June 2007|title=The List of Wetlands of International Importance | publisher=The Secretariat of the Convention on Wetlands | page=18 | url=http://www.ramsar.org/sitelist.pdf | access-date=20 June 2007 | format=PDF | archive-url=http://web.archive.org/web/20070621011113/http://www.ramsar.org/sitelist.pdf | archive-date=21 June 2007
+]==] }, {
+
+[==[ last=Schmidt|first=Hans-Peter|chapter=Mithra i: Mithra in Old Indian and Mithra in Old Iranian|year=2006|title=Encyclopædia Iranica|volume=OT 10|location=New York|publisher=iranica.com|url=http://www.iranicaonline.org/articles/mithra-i|format=
+]==] }, {
+
+[==[ last1=Canard |first1=M. |editor1-first=P. |editor1-last=Bearman |editor2-first=Th. |editor2-last=Bianquis |editor3-first=C.E. |editor3-last=Bosworth |editor4-first=E. |editor4-last=van Donzel |editor5-first=W.P. |editor5-last=Heinrichs |editor3-link=Clifford Edmund Bosworth |title=Encyclopaedia of Islam, Second Edition |year=2011 |publisher=Brill Online |location=Leiden |chapter=al-ḎJazīra, Ḏjazīrat Aḳūr or Iḳlīm Aḳūr |oclc=624382576
+]==] }, {
+
+[==[ last=Block|first=Steven M.|title=The growing threat of biological weapons|url=http://www.americanscientist.org/issues/feature/the-growing-threat-of-biological-weapons|access-date=2009-05-22|volume=89:1|year=2001|publisher=American Scientist|doi=10.1511/2001.1.28|journal=American Scientist|page=28]==] }, {
+
+[==[ year=2011|title=Human Development Report 2011|chapter=Table 1: Human Development Index and its Components|publisher=[[United Nations]]|chapter-url=http://hdr.undp.org/en/media/HDR_2011_EN_Table1.pdf|format=PDF|ref=]==] }, {
+
+[==[ author=Bhagavan NV|title=Medical Biochemistry |publisher=Harcourt/Academic Press |location=San Diego |year=2002 |isbn=0-12-095440-0|url=http://books.google.com/?id=vT9YttFTPi0C&printsec=frontcover]==] }, {
+
+[==[ author=Motilal (UK) Books of India|title=Tourist Guide Kerala|url=http://books.google.com/books?id=ZYfRBcLdTNYC&pg=PA11|access-date=18 November 2012|date=1 February 2008|publisher=Sura Books|isbn=978-81-7478-164-2|page=11]==] }, {
+
+[==[ author1=Joseph Needham|author2=Gwei-Djen Lu|author3=Ling Wang|title=Science and civilisation in China, Volume 5, Part 7|year=1987|publisher=Cambridge University Press|isbn=978-0-521-30358-3|pages=48–50]==] }, {
+
+[==[ chapter=Naturalism and Physicalism | last=Fales | postscript=, | first=Evan ]==] }, {
+
+[==[ date=5 October 2009|title=India, Russia Review Defence Ties|publisher=[[The Hindu]]|url=http://www.thehindu.com/news/national/article2514142.ece|access-date=8 October 2011]==] }, {
+
+[==[ first=Elena|last=Aprile|author2=Bolotnikov, Aleksey E. |author3=Doke, Tadayoshi |title=Noble Gas Detectors|publisher=Wiley-VCH|year=2006 |isbn=3-527-60963-6|url=http://books.google.com/?id=tsnHM8x6cHAC&pg=PT1|pages=8–9]==] }, {
+
+[==[ first=Maurice | last=Loir | title=L'escadre de l'amiral Courbet | location=Paris | publisher=Berger-Levrault | year=1886 | postscript=. ]==] }, {
+
+[==[ last = Bennett | first = Ralph | title = Behind the Battle: Intelligence in the War with Germany | place = London | publisher = Random House | origyear = 1994 | year = 1999 | edition = Pimlico: New and Enlarged | isbn = 0-7126-6521-8 ]==] }, {
+
+[==[ last = Hunt | first = David | author-link = David Hunt (diplomat) | title = The raid on Coventry | newspaper = The Times | pages = 11 | date = 28 August 1976 ]==] }, {
+
+[==[ last = Rhodes |first = Richard |year = 1986 |title = The Making of the Atomic Bomb |isbn = 0-671-65719-4 |pages = 659–660 |publisher = Simon & Schuster |location = New York]==] }, {
+
+[==[ last = Watt | first = William Montgomery |author-link = William Montgomery Watt| title = [[Muhammad at Mecca (book)|Muhammad at Mecca]]| publisher=Oxford University Press | year = 1953 | id =]==] }, {
+
+[==[ last=Cooper |first=J.C. |title=Symbolic and Mythological Animals |pages=25–26 |year=1992 |publisher=Aquarian Press |location=London |isbn=1-85538-118-4]==] }, {
+
+[==[ last=Horton|first=Michael|author-link=Michael Horton (theologian)|title=For Calvinism|url=http://books.google.com/books?id=ezoDtwAACAAJ|access-date=17 January 2013|date=18 October 2011|publisher=Zondervan Books|isbn=978-0-310-32465-2|page=15]==] }, {
+
+[==[ last=Jacobs|first=Bruno|chapter=Mithra|title=Iconography of Deities and Demons in the Ancient Near East|series=(Electronic Pre-Publication)|location=Leiden|publisher=U Zürich/Brill| year=2006|url=http://www.religionswissenschaft.unizh.ch/idd/prepublications/e_idd_mithra.pdf Iconography of Mithra]==] }, {
+
+[==[ last=Malandra|first=William|year=1983|isbn=0-8166-1115-7|title=An Introduction to Ancient Iranian Religion|location=Minneapolis|publisher=University of Minnesota Press]==] }, {
+
+[==[ last=Metzner|first =Paul|year=1998|title=Crescendo of the Virtuoso: Spectacle, Skill, and Self-Promotion in Paris during the Age of Revolution|publisher=University of California Press]==] }, {
+
+[==[ last=Raichlen|first=S.|date=10 May 2011|title=A Tandoor Oven Brings India's Heat to the Backyard|publisher=The New York Times|url=http://www.nytimes.com/2011/05/11/dining/a-tandoor-oven-brings-indias-heat-to-the-backyard.html|access-date=14 June 2011]==] }, {
+
+[==[ last=Sripati|first=V.|year=1998|title=Toward Fifty Years of Constitutionalism and Fundamental Rights in India: Looking Back to See Ahead (1950–2000)|journal=American University International Law Review|volume=14|issue=2|pages=413–496]==] }, {
+
+[==[ last1=Ali|first1=J. R.|last2=Aitchison|first2=J. C.|year=2005|title=Greater India|journal=Earth-Science Reviews|volume=72|issue=3–4|pages=170–173|doi=10.1016/j.earscirev.2005.07.005]==] }, {
+
+[==[ last1=Eitzen|first1=E.|last2=Takafuji|first2=E.|title=Military Medicine: Medical Aspects of Chemical and Biological Warfare|url=|year=1997|publisher=Office of the Surgeon General, Department of the Army|chapter=Historical Overview of Biological Warfare]==] }, {
+
+[==[ last1=Heitzman|first1=J.|last2=Worden|first2=R. L.|date=August 1996|title=India: A Country Study|series=Area Handbook Series|publisher=[[Library of Congress]]|place=Washington, D.C.|isbn=978-0-8444-0833-0]==] }, {
+
+[==[ last1=Masters|first1=Bruce Alan|last2=Ágoston|first2=Gábor|year=2009|title=Encyclopedia of the Ottoman Empire|publisher=Infobase Publishing|location=New York|isbn=978-1-4381-1025-7]==] }, {
+
+[==[ url=http://books.google.ca/books?id=LjzZ_rVv_2MC&pg=PA30 |title=Villes et organisation de l'espace en Afrique |pages=30–31 |first1=Jérôme |last1=Aloko-N'Guessan |first2=Amadou |last2=Diallo |first3=Kokou Henri |last3=Motcho |publisher=KARTHALA Editions |year=2010 |ISBN=2-8111-0339-2]==] }, {
+
+[==[ title = Statics: Analysis and Design of Systems in Equilibrium | last = Sheppard and Tongue | publisher = Wiley and Sons | year = 2005 | page = 618 | quote = In general, for given contacting surfaces, ''μ''
k < ''μ''
s | isbn = 0-471-37299-4]==] }, {
+
+[==[ title=Ancient Egyptian Rhetoric in the Old and Middle Kingdoms|author=David Hutto|journal=[[Rhetorica]]|date=Summer 2002|volume=20|issue=3|publisher=[[University of California Press]]|pages=213–233|doi=10.1525/rh.2002.20.3.213]==] }, {
+
+[==[ title=Civilizations of ancient Iraq |last1=Foster |first1=Benjamin R. |last2=Polinger Foster |first2=Karen |year=2009 |publisher=Princeton University Press |location=Princeton |isbn=978-0-691-13722-3 ]==] }, {
+
+[==[ title=India | publisher=[[International Monetary Fund]] | url=http://www.imf.org/external/pubs/ft/weo/2011/02/weodata/weorept.aspx? | access-date=14 October 2011]==] }, {
+
+[==[ title=New Interstellar Boundary Explorer data show heliosphere's long-theorized bow shock does not exist | date=May 10, 2012 | work=Phys.org | url=http://phys.org/news/2012-05-interstellar-boundary-explorer-heliosphere-long-theorized.html | access-date=2012-02-11 ]==] }, {
+
+[==[ title=The European Flag|publisher=[[Europa (web portal)]]|url=http://europa.eu/abc/symbols/emblem/index_en.htm|access-date=4 August 2007]==] }, {
+
+[==[ url = http://english.president.go.kr/tours/place_buildings/main_office.php | title = Cheong Wa Dae / The Blue House | quote = The Main Building and its two annexes are covered with a total of 150,000 traditional Korean blue roof tiles (hence, the name "Blue House" is also commonly used when referring to Cheongwadae). ]==] }, {
+
+[==[ url=https://www.regione.sardegna.it/j/v/86?v=9&c=72&s=1&file=1997026 |title=Legge Regionale 15 ottobre 1997, n. 26 |year=1997 |publisher=Regione Sardegna |access-date=]==] }, {
+
+[==[ title = Studies on Archaic Chinese
+ | last = Li | first = Fang-Kuei | author-link = Li Fang-Kuei
+ | others = Gilbert L. Mattos (trans.)
+ | journal = Monumenta Serica | volume = 31 | year = 1974–75
+ | pages = 219–287
+ | postscript = .
+]==] }, { [==[
+ title = Studies on Archaic Chinese
+ | last = Li | first = Fang-Kuei | author-link = Li Fang-Kuei
+ | others = Gilbert L. Mattos (trans.)
+ | journal = Monumenta Serica | volume = 31 | year = 1974–1975
+ | pages = 219–287
+ | postscript = .
+]==] } }, {nowiki=false, templatestyles=true})
+end
+
+return p
From c61bf6901861f210aff4d89ffce8726e6f2d3866 Mon Sep 17 00:00:00 2001
From: Tphamtranba <119475427+Bapham12@users.noreply.github.com>
Date: Sat, 14 Mar 2026 20:07:30 +0700
Subject: [PATCH 09/25] Create CitationAnchor.lua
---
Testcases/Citation/CitationAnchor.lua | 203 ++++++++++++++++++++++++++
1 file changed, 203 insertions(+)
create mode 100644 Testcases/Citation/CitationAnchor.lua
diff --git a/Testcases/Citation/CitationAnchor.lua b/Testcases/Citation/CitationAnchor.lua
new file mode 100644
index 0000000..44e0a49
--- /dev/null
+++ b/Testcases/Citation/CitationAnchor.lua
@@ -0,0 +1,203 @@
+-- we never call cs1 directly because it doesn't have a nice implementation
+-- as a module, so comment out below line
+-- local myModule = require('Module:Citation/CS1') -- the module to be tested
+local ScribuntoUnit = require('Module:ScribuntoUnit')
+local suite = ScribuntoUnit:new()
+
+-- merge keys and values into one table
+local function merge(t1, t2)
+ local t3 = {}
+ for k, v in pairs(t1) do
+ t3[k] = v
+ end
+ for k, v in pairs(t2) do
+ t3[k] = v
+ end
+ return t3
+end
+
+-- Finds the citeref in an expanded CS1/2 template. Takes a test_parameters
+-- table and a specific template invoke's args. The test_parameters table has
+-- the following fields:
+-- * base_args, a table representing the template args common to the test case.
+-- * pattern, a string to find in the expanded template
+-- * frame, usually from mw.getCurrentFrame()
+-- * template, a string which is the name of the template to test.
+-- targs is a table of the template arguments unique to the specific assertion.
+local function citeref(test_parameters, targs)
+
+ local merged_args = merge(test_parameters.base_args, targs)
+ local expansion = test_parameters.frame:expandTemplate{
+ title = test_parameters.template, args = merged_args
+ }
+
+ local _, _, citeref_value = mw.ustring.find(expansion, test_parameters.pattern)
+ if not citeref_value then
+ citeref_value = ''
+ end
+ return citeref_value
+end
+
+-- Tests to ensure author masks don't corrupt the CITEREF
+function suite:testAuthorMask()
+ local env = {
+ frame = mw.getCurrentFrame(),
+ pattern = 'id=\"(CITEREF%S-)\"',
+ template = 'cite book/new',
+ base_args = { title = 'T', author = '_A1_', year = '2020' }
+ }
+ self:assertEquals( 'CITEREF_A1_2020', citeref(env, {chapter = 'CH'}))
+ self:assertEquals( 'CITEREF_A1_2020', citeref(env, {['author-mask'] = 'A1'}))
+ self:assertEquals( 'CITEREF_A1_2020', citeref(env, {['author-mask1'] = '2'}))
+end
+
+-- Tests what happens with various counts of contributors, authors, and editors
+function suite:testCounts()
+ local env = {
+ frame = mw.getCurrentFrame(),
+ pattern = 'id=\"(CITEREF%S-)\"',
+ template = 'cite book/new',
+ base_args = { title = 'T', year = '2020' }
+ }
+ self:assertEquals( '', citeref(env, {chapter = 'CH'}))
+ self:assertEquals( 'CITEREF_A1_2020', citeref(env, {author = '_A1_'}))
+ self:assertEquals( '', citeref(env, {contributor = 'C1'}))
+ self:assertEquals( '', citeref(env, {contributor = 'C1', contribution = 'CON'}))
+ self:assertEquals( 'CITEREF_E1_2020', citeref(env, {editor = '_E1_'}))
+ self:assertEquals( 'CITEREF_A1_2020', citeref(env, {author = '_A1_', contributor = '_C1_'}))
+ self:assertEquals( 'CITEREF_C1_2020', citeref(env, {author = '_A1_', contributor = '_C1_', contribution = 'CON'}))
+ self:assertEquals( 'CITEREF_A1_2020', citeref(env, {author = '_A1_', editor = '_E1_'}))
+ self:assertEquals( 'CITEREF_E1_2020', citeref(env, {editor = '_E1_', contributor = '_C1_'}))
+ self:assertEquals( 'CITEREF_E1_2020', citeref(env, {editor = '_E1_', contributor = '_C1_', contribution = 'CON'}))
+ self:assertEquals( 'CITEREF_A1_2020', citeref(env, {author = '_A1_', contributor = '_C1_', editor = '_E1_'}))
+ self:assertEquals( 'CITEREF_C1_2020', citeref(env, {author = '_A1_', contributor = '_C1_', editor = '_E1_', contribution = 'CON'}))
+ self:assertEquals( 'CITEREF_A1_A2_A3_A4_2020', citeref(env, {author = '_A1_', author2 = 'A2_', author3 = 'A3_', author4 = 'A4_'}))
+ self:assertEquals( 'CITEREF_A1_A2_A3_A4_2020', citeref(env, {author = '_A1_', author2 = 'A2_', author3 = 'A3_', author4 = 'A4_', author5 = 'A5_'}))
+ self:assertEquals( 'CITEREF_C1_C2_C3_2020', citeref(env, {author = '_A1_', contributor = '_C1_', contributor2 = 'C2_', contributor3 = 'C3_', contribution = 'CON'}))
+ self:assertEquals( 'CITEREF_E1_E2_2020', citeref(env, {editor = '_E1_', editor2 = 'E2_'}))
+end
+
+-- Tests date resolution code, including anchor years.
+function suite:testDates()
+ local env = {
+ frame = mw.getCurrentFrame(),
+ pattern = 'id=\"(CITEREF%S-)\"',
+ template = 'cite book/new',
+ base_args = { title = 'T', author = '_A1_' }
+ }
+ self:assertEquals( 'CITEREF_A1_2020', citeref(env, {year='2020'}))
+ self:assertEquals( 'CITEREF_A1_c\._2020', citeref(env, {date='c. 2020'}))
+ self:assertEquals( 'CITEREF_A1_2020', citeref(env, {date='1 January 2020'}))
+ self:assertEquals( 'CITEREF_A1_2020a', citeref(env, {date='1 January 2020a'}))
+ self:assertEquals( 'CITEREF_A1_2020', citeref(env, {date='1 January 2020', year='2020'}))
+ self:assertEquals( 'CITEREF_A1_2020a', citeref(env, {date='1 January 2020', year='2020a'}))
+ self:assertEquals( 'CITEREF_A1_2020', citeref(env, {date='2020-01-01', year='2020'}))
+ self:assertEquals( 'CITEREF_A1_2020a', citeref(env, {date='2020-01-01', year='2020a'}))
+end
+
+function suite:testDatesMaint()
+ local frame = mw.getCurrentFrame()
+ local base_args = {title = 'T', author = '_A1_', year = '2020'}
+ local template = 'cite book/new'
+ local maint = 'CS1 maint: date and year'
+
+ self:assertStringContains(maint, frame:expandTemplate{
+ title = template, args = merge(base_args, { date = '1 January 2020'})
+ })
+ self:assertStringContains(maint, frame:expandTemplate{
+ title = template, args = merge(base_args, { date = '2020-01-01'})
+ })
+end
+
+-- should fail: extra unexpected nd in the anchor, plus trailingauthordash below
+-- TODO: Should that change? I've seen workarounds in the wild.
+function suite:testDatesExtraNd()
+ local env = {
+ frame = mw.getCurrentFrame(),
+ pattern = 'id=\"(CITEREF%S-)\"',
+ template = 'cite book/new',
+ base_args = { title = 'T', author = '_A1_' }
+ }
+
+ self:assertEquals( 'CITEREF_A1_', citeref(env, {date='nd'}))
+end
+
+-- should fail: extra unexpected n.d. in the anchor
+-- TODO: Should that change? I've seen workarounds in the wild.
+function suite:testDatesExtraNdPunct()
+ local env = {
+ frame = mw.getCurrentFrame(),
+ pattern = 'id=\"(CITEREF%S-)\"',
+ template = 'cite book/new',
+ base_args = { title = 'T', author = '_A1_' }
+ }
+ self:assertEquals( 'CITEREF_A1_', citeref(env, {date='n.d.'}))
+end
+
+-- Tests to ensure display name settings don't corrupt the CITEREF
+function suite:testDisplayNames()
+ local env = {
+ frame = mw.getCurrentFrame(),
+ pattern = 'id=\"(CITEREF%S-)\"',
+ template = 'cite book/new',
+ base_args = { title = 'T', author = '_A1_', author2 = 'A2_', date = '2020' }
+ }
+ self:assertEquals( 'CITEREF_A1_A2_2020', citeref(env, {chapter = 'CH'}))
+ self:assertEquals( 'CITEREF_A1_A2_2020', citeref(env, {['display-authors'] = '0'}))
+ self:assertEquals( 'CITEREF_A1_A2_2020', citeref(env, {['display-authors'] = '1'}))
+ self:assertEquals( 'CITEREF_A1_A2_2020', citeref(env, {['display-authors'] = 'etal'}))
+end
+
+-- Tests what happens for certain values of ref
+function suite:testRef()
+ local env = {
+ frame = mw.getCurrentFrame(),
+ pattern = '(id=\"CITEREF%S-\")',
+ template = 'cite book/new',
+ base_args = { title = 'T', author = '_A1_', year = '2020' }
+ }
+ -- TODO test citation for equivalent value
+ self:assertEquals( 'id=\"CITEREF_A1_2020\"', citeref(env, {chapter = 'CH'}))
+ self:assertEquals( '', citeref(env, {ref = 'none'}))
+ self:assertEquals( 'id=\"CITEREF_A1_2020\"', citeref(env, {ref = 'CITEREF_A1_2020'}))
+
+end
+
+-- slightly different setup; we want to test that the input ID is the output ID
+function suite:testRefREF()
+ local env = {
+ frame = mw.getCurrentFrame(),
+ pattern = '(id=\"REF\")',
+ template = 'cite book/new',
+ base_args = { title = 'T', author = '_A1_', year = '2020' }
+ }
+ self:assertEquals( 'id=\"REF\"', citeref(env, {ref = 'REF'}))
+end
+
+-- tests for expected presence of maintenance messages in ref
+function suite:testRefMaint()
+ local frame = mw.getCurrentFrame()
+ local base_args = {title = 'T', author = '_A1_', date = '2020'}
+
+ self:assertStringContains('CS1 maint: ref duplicates default', frame:expandTemplate{
+ title = 'cite book/new', args = merge(base_args, { ref = 'CITEREF_A1_2020'})
+ })
+ self:assertStringContains('Invalid
|ref=harv', frame:expandTemplate{
+ title = 'cite book/new', args = merge(base_args, { ref = 'harv'})
+ })
+end
+
+-- should fail: missing trailing underscore in anchor; not sure if that's desirable
+-- or if that can change
+-- TODO: Ask someone.
+function suite:testTrailingAuthorDash()
+ local env = {
+ frame = mw.getCurrentFrame(),
+ pattern = 'id=\"(CITEREF%S-)\"',
+ template = 'cite book/new',
+ base_args = { title = 'T', author = '_A1_' }
+ }
+ self:assertEquals( 'CITEREF_A1_', citeref(env, {chapter='CH'}))
+end
+
+return suite
From 9bd4d19c79ebeedf49c064e291cce5fc3cde3b5f Mon Sep 17 00:00:00 2001
From: Tphamtranba <119475427+Bapham12@users.noreply.github.com>
Date: Sat, 14 Mar 2026 20:08:02 +0700
Subject: [PATCH 10/25] Create CitationMode1.lua
---
Testcases/Citation/CitationMode1.lua | 10 ++++++++++
1 file changed, 10 insertions(+)
create mode 100644 Testcases/Citation/CitationMode1.lua
diff --git a/Testcases/Citation/CitationMode1.lua b/Testcases/Citation/CitationMode1.lua
new file mode 100644
index 0000000..ac9dbf6
--- /dev/null
+++ b/Testcases/Citation/CitationMode1.lua
@@ -0,0 +1,10 @@
+-- Unit tests for [[Module:{{ROOTPAGENAME}}]]. Click talk page to run tests.
+local p = require('Module:UnitTests')
+
+-- Example unit test.
+function p:test_CS1config_not_used()
+ self:preprocess_equals('{{#invoke:Citation mode | main | cs2}}', ' cs2')
+ self:preprocess_equals('{{#invoke:Citation mode/sandbox | main | cs2}}', ' cs2')
+end
+
+return p
From de03f30e530e52e524b2c78a9c168900ca0c6517 Mon Sep 17 00:00:00 2001
From: Tphamtranba <119475427+Bapham12@users.noreply.github.com>
Date: Sat, 14 Mar 2026 20:08:47 +0700
Subject: [PATCH 11/25] Create CitationMode2.lua
---
Testcases/Citation/CitationMode2.lua | 9 +++++++++
1 file changed, 9 insertions(+)
create mode 100644 Testcases/Citation/CitationMode2.lua
diff --git a/Testcases/Citation/CitationMode2.lua b/Testcases/Citation/CitationMode2.lua
new file mode 100644
index 0000000..e1bd76c
--- /dev/null
+++ b/Testcases/Citation/CitationMode2.lua
@@ -0,0 +1,9 @@
+-- Unit tests for [[Module:{{ROOTPAGENAME}}]]. Click talk page to run tests.
+local p = require('Module:UnitTests')
+
+function p:test_CS1config_used()
+ self:preprocess_equals('{{#invoke:Citation mode | main | cs2}}', '')
+ self:preprocess_equals('{{#invoke:Citation mode/sandbox | main | cs2}}', '')
+end
+
+return p
From dc4a3f12c293113cf70b3cb3b1a58bcf371de991 Mon Sep 17 00:00:00 2001
From: Tphamtranba <119475427+Bapham12@users.noreply.github.com>
Date: Sat, 14 Mar 2026 20:09:38 +0700
Subject: [PATCH 12/25] Create Coord.lua
---
Testcases/Coord.lua | 137 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 137 insertions(+)
create mode 100644 Testcases/Coord.lua
diff --git a/Testcases/Coord.lua b/Testcases/Coord.lua
new file mode 100644
index 0000000..d6b1e79
--- /dev/null
+++ b/Testcases/Coord.lua
@@ -0,0 +1,137 @@
+-- Các trường hợp kiểm thử đơn vị cho [[Mô đun:Coordinates]]. Bấm vào trang thảo luận để chạy các trường hợp kiểm thử.
+local p = require('Mô đun:UnitTests')
+
+function p:test_coord()
+ self:preprocess_equals_preprocess_many('{{#gọi:Coordinates/sandbox|coord|', '}}',
+ '{{#gọi:Coordinates|coord|', '}}', {
+
+ -- First - the broken test cases
+ {'-20.4|N|-20.4|E|name=Test case SW-1b: -20.4d N -20.4d E (-20.4, -20.4)', '-20.4|N|-20.4|E|name=Test case SW-1b: -20.4d N -20.4d E (-20.4, -20.4)'},
+ {'-20|20|N|-20|20|E|name=Test case SW-2b: -20d 20m N -20d 20m E (-20.3333, -20.3333)', '-20|20|N|-20|20|E|name=Test case SW-2b: -20d 20m N -20d 20m E (-20.3333, -20.3333)'},
+ {'-20||N|-20||E|name=Test case SW-2c: -20d N -20d E (-20, -20)', '-20||N|-20||E|name=Test case SW-2c: -20d N -20d E (-20, -20)'},
+ {'-20|20|20|N|-20|20|20|E|name=Test case SW-3b: -20d 20m 20s N -20d 20m 20s E (-20.33889, -20.33889)', '-20|20|20|N|-20|20|20|E|name=Test case SW-3b: -20d 20m 20s N -20d 20m 20s E (-20.33889, -20.33889)'},
+ {'-20||20|N|-20||20|E|name=Test case SW-3c: -20d 20s N -20d 20s E', '-20||20|N|-20||20|E|name=Test case SW-3c: -20d 20s N -20d 20s E'},
+ {'-20|20||N|-20|20||E|name=Test case SW-3d: -20d 20m N -20d 20m E', '-20|20||N|-20|20||E|name=Test case SW-3d: -20d 20m N -20d 20m E'},
+ {'-20|||N|-20|||E|name=Test case SW-3e: -20d N -20d E (-20, -20)', '-20|||N|-20|||E|name=Test case SW-3e: -20d N -20d E (-20, -20)'},
+ {'-20.4|S|-20.4|W|name=Test case NE-1b: -20.4d S 20.4d W (20.4, 20.4) (rev.1)', '-20.4|S|-20.4|W|name=Test case NE-1b: -20.4d S 20.4d W (20.4, 20.4) (rev.1)'},
+ {'-20|20|S|-20|20|W|name=Test case NE-2b: -20d 20m S -20d 20m W (20.3333, 20.3333)', '-20|20|S|-20|20|W|name=Test case NE-2b: -20d 20m S -20d 20m W (20.3333, 20.3333)'},
+ {'-20|20|20|S|-20|20|20|W|name=Test case NE-3b: -20d 20m 20s S -20d 20m 20s W (20.33889, 20.33889)(rev.1)', '-20|20|20|S|-20|20|20|W|name=Test case NE-3b: -20d 20m 20s S -20d 20m 20s W (20.33889, 20.33889)(rev.1)'},
+ {'20.4|S|180.4|W|name=Test case W>180: 20.4d S 180.4d W (-20.4, -180.4)', '20.4|S|180.4|W|name=Test case W>180: 20.4d S 180.4d W (-20.4, -180.4)'},
+ {'20.4|N|180.4|E|name=Test case E>180: 20.4d N 180.4d E ( 20.4, 180.4)', '20.4|N|180.4|E|name=Test case E>180: 20.4d N 180.4d E ( 20.4, 180.4)'},
+ {'90.1|1|name=Test case N>+90 dec', '90.1|1|name=Test case N>+90 dec'},
+ {'-90.1|1|name=Test case N<-90 dec', '-90.1|1|name=Test case N<-90 dec'},
+ {'1|360|name=Test case E>=+360 dec', '1|360|name=Test case E>=+360 dec'},
+ {'1|-360|name=Test case E<=-360 dec', '1|-360|name=Test case E<=-360 dec'},
+ {'90.1|S|1|W|name=Test case S>+90 d', '90.1|S|1|W|name=Test case S>+90 d'},
+ {'90.1|N|1|E|name=Test case N>+90 d', '90.1|N|1|E|name=Test case N>+90 d'},
+ {'-90.1|N|1|W|name=Test case N<-90 d', '-90.1|N|1|W|name=Test case N<-90 d'},
+ {'1|N|360|W|name=Test case W>=+360 d', '1|N|360|W|name=Test case W>=+360 d'},
+ {'1|N|-360|E|name=Test case E<=-360 d', '1|N|-360|E|name=Test case E<=-360 d'},
+ {'91|0|N|1|2|E|name=Test case dN>+90 dm', '91|0|N|1|2|E|name=Test case dN>+90 dm'},
+ {'-91|0|N|1|2|E|name=Test case dN<-90 dm', '-91|0|N|1|2|E|name=Test case dN<-90 dm'},
+ {'1|2|S|360|0|E|name=Test case dE>=+360 dm', '1|2|S|360|0|E|name=Test case dE>=+360 dm'},
+ {'1|2|S|-360|0|E|name=Test case dE<=-360 dm', '1|2|S|-360|0|E|name=Test case dE<=-360 dm'},
+ {'1|60|S|2|3|W|name=Test case mS>=60 dm', '1|60|S|2|3|W|name=Test case mS>=60 dm'},
+ {'1|-1|S|2|3|W|name=Test case mS<0 dm', '1|-1|S|2|3|W|name=Test case mS<0 dm'},
+ {'1|2|S|3|60|W|name=Test case mW>=60 dm', '1|2|S|3|60|W|name=Test case mW>=60 dm'},
+ {'1|2|S|3|-1|W|name=Test case mW<0 dm', '1|2|S|3|-1|W|name=Test case mW<0 dm'},
+ {'91|0|0|N|1|2|3|E|name=Test case dN>+90 dms', '91|0|0|N|1|2|3|E|name=Test case dN>+90 dms'},
+ {'-91|0|0|N|1|2|3|E|name=Test case dN<-90 dms', '-91|0|0|N|1|2|3|E|name=Test case dN<-90 dms'},
+ {'1|2|3|S|360|0|0|E|name=Test case dE>=+360 dms', '1|2|3|S|360|0|0|E|name=Test case dE>=+360 dms'},
+ {'1|2|3|S|-360|0|0|E|name=Test case dE<=-360 dms', '1|2|3|S|-360|0|0|E|name=Test case dE<=-360 dms'},
+ {'1|60|0|S|2|3|4|W|name=Test case mS>=60 dms', '1|60|0|S|2|3|4|W|name=Test case mS>=60 dms'},
+ {'1|-1|2|S|3|4|5|W|name=Test case mS<0 dms', '1|-1|2|S|3|4|5|W|name=Test case mS<0 dms'},
+ {'1|2|3|S|4|60|0|W|name=Test case mW>=60 dms', '1|2|3|S|4|60|0|W|name=Test case mW>=60 dms'},
+ {'1|2|3|S|4|-1|5|W|name=Test case mW<0 dms', '1|2|3|S|4|-1|5|W|name=Test case mW<0 dms'},
+ {'1|2|60|S|3|4|5|W|name=Test case sS>=60 dms', '1|2|60|S|3|4|5|W|name=Test case sS>=60 dms'},
+ {'1|2|-1|S|3|4|5|W|name=Test case sS<0 dms', '1|2|-1|S|3|4|5|W|name=Test case sS<0 dms'},
+ {'1|2|3|S|3|4|60|W|name=Test case sW>=60 dms', '1|2|3|S|3|4|60|W|name=Test case sW>=60 dms'},
+ {'1|2|3|S|3|4|-1|W|name=Test case sW<0 dms', '1|2|3|S|3|4|-1|W|name=Test case sW<0 dms'},
+ {'', ''},
+ {'|-2', '|-2'},
+ {'1|', '1|'},
+ {'1|N||W', '1|N||W'},
+ {'1|2|N||4|W', '1|2|N||4|W'},
+ {'1|2|3|N||5|6|W', '1|2|3|N||5|6|W'},
+
+ -- Good test cases
+ {'57|18|22|N|4|27|32|W', '57|18|22|N|4|27|32|W'},
+ {'44.112|N|87.913|W', '44.112|N|87.913|W'},
+ {'44.112|-87.913', '44.112|-87.913'},
+ {'44.117|-87.913|dim:30_region:US-WI_type:landmark|name=Klann Road', '44.117|-87.913|dim:30_region:US-WI_type:landmark|name=Klann Road'},
+ {'10.2|-20.3|display=inline', '10.2|-20.3|display=inline'},
+ {'10.2|-20.3', '10.2|-20.3'},
+ {'44.4|-111.1|type:city_region:US', '44.4|-111.1|type:city_region:US'},
+ {'51.01234|-1.56789|type:landmark_region:GB', '51.01234|-1.56789|type:landmark_region:GB'},
+ {'-35.5|150.1|type:landmark_region:AU', '-35.5|150.1|type:landmark_region:AU'},
+ {'12|34|12|N|45|33|45|W', '12|34|12|N|45|33|45|W'},
+ {'43.651234|-79.383333', '43.651234|-79.383333'},
+ {'43.65|-79.38', '43.65|-79.38'},
+ {'43.6500|-79.3800', '43.6500|-79.3800'},
+ {'43.651234|N|79.383333|W', '43.651234|N|79.383333|W'},
+ {'43|29|N|79|23|W', '43|29|N|79|23|W'},
+ {'43|29|4|N|79|23|0|W', '43|29|4|N|79|23|0|W'},
+ {'43|29|4.5|N|79|23|0.5|W', '43|29|4.5|N|79|23|0.5|W'},
+ {'55.752222|N|37.615556|E', '55.752222|N|37.615556|E'},
+ {'55.752222|N|37.615556|E|format=dms', '55.752222|N|37.615556|E|format=dms'},
+ {'39.098095|-94.587307|format=dms', '39.098095|-94.587307|format=dms'},
+ {'55.752222|N|37.615556|E|format=dec|name=Moskva', '55.752222|N|37.615556|E|format=dec|name=Moskva'},
+ {'33|55|S|18|25|E', '33|55|S|18|25|E'},
+ {'35|00|N|105|00|E', '35|00|N|105|00|E'},
+ {'22|54|30|S|43|14|37|W', '22|54|30|S|43|14|37|W'},
+ {'22|S|43|W', '22|S|43|W'},
+ {'52|28|59|N|1|53|37|W|display=inline,title|region:GB_type:city', '52|28|59|N|1|53|37|W|display=inline,title|region:GB_type:city'},
+ {'46|43|N|7|58|E|type:mountain', '46|43|N|7|58|E|type:mountain'},
+ {'51.500611|N|0.124611|W|scale:1000', '51.500611|N|0.124611|W|scale:1000'},
+ {'51.500611|N|0.124611|W|scale:10000', '51.500611|N|0.124611|W|scale:10000'},
+ {'51.500611|N|0.124611|W|scale:100000', '51.500611|N|0.124611|W|scale:100000'},
+ {'51.500611|N|0.124611|W|scale:1000000', '51.500611|N|0.124611|W|scale:1000000'},
+ {'0|N|90|W|dim:10000000', '0|N|90|W|dim:10000000'},
+ {'40.5|-82.5|dim:400000', '40.5|-82.5|dim:400000'},
+ {'51.033|13.73|dim:20000', '51.033|13.73|dim:20000'},
+ {'40.6892|-74.0445|dim:100', '40.6892|-74.0445|dim:100'},
+ {'45.516194|-122.673226|dim:0.6', '45.516194|-122.673226|dim:0.6'},
+ {'46.9524|N|7.4396|E|region:CH', '46.9524|N|7.4396|E|region:CH'},
+ {'52.5164|N|13.3775|E|region:DE-BE', '52.5164|N|13.3775|E|region:DE-BE'},
+ {'0|40|26.69|N|23|28|22.69|E|globe:moon', '0|40|26.69|N|23|28|22.69|E|globe:moon'},
+ {'48.269|N|225.990|W|globe:mars', '48.269|N|225.990|W|globe:mars'},
+ {'7.5|S|303|E|globe:venus', '7.5|S|303|E|globe:venus'},
+ {'8|N|190.5|W|globe:mercury', '8|N|190.5|W|globe:mercury'},
+ {'52.5164|N|13.3775|E|region:DE-BE', '52.5164|N|13.3775|E|region:DE-BE'},
+ {'20.4|S|20.4|W|name=Test case SW-1a: 20.4d S 20.4d W (-20.4, -20.4)', '20.4|S|20.4|W|name=Test case SW-1a: 20.4d S 20.4d W (-20.4, -20.4)'},
+ {'-20.4|-20.4|name=Test case SW-1c: -20.4d -20.4d (-20.4, -20.4)', '-20.4|-20.4|name=Test case SW-1c: -20.4d -20.4d (-20.4, -20.4)'},
+ {'20|20|S|20|20|W|name=Test case SW-2a: 20d 20m S 20d 20m W (-20.3333, -20.3333)', '20|20|S|20|20|W|name=Test case SW-2a: 20d 20m S 20d 20m W (-20.3333, -20.3333)'},
+ {'20|20|20|S|20|20|20|W|name=Test case SW-3a: 20d 20m 20s S 20d 20m 20s W (-20.33889, -20.33889)', '20|20|20|S|20|20|20|W|name=Test case SW-3a: 20d 20m 20s S 20d 20m 20s W (-20.33889, -20.33889)'},
+ {'20.4|N|20.4|E|name=Test case NE-1a: 20.4d N 20.4d E (20.4, 20.4)', '20.4|N|20.4|E|name=Test case NE-1a: 20.4d N 20.4d E (20.4, 20.4)'},
+ {'20.4|20.4|name=Test case NE-1c: 20.4d 20.4d (20.4, 20.4) (rev.1)', '20.4|20.4|name=Test case NE-1c: 20.4d 20.4d (20.4, 20.4) (rev.1)'},
+ {'20|20|N|20|20|E|name=Test case NE-2a: 20d 20m N 20d 20m E (20.3333, 20.3333)', '20|20|N|20|20|E|name=Test case NE-2a: 20d 20m N 20d 20m E (20.3333, 20.3333)'},
+ {'20|20|20|N|20|20|20|E|name=Test case NE-3a: 20d 20m 20s N 20d 20m 20s E (20.33889, 20.33889) (rev.1)', '20|20|20|N|20|20|20|E|name=Test case NE-3a: 20d 20m 20s N 20d 20m 20s E (20.33889, 20.33889) (rev.1)'},
+ {'1|2|dim=10000|name=Test case dim= dec', '1|2|dim=10000|name=Test case dim= dec'},
+ {'1|2|globe=moon|name=Test case globe= dec', '1|2|globe=moon|name=Test case globe= dec'},
+ {'1|2|region=CA-QC|name=Test case region= dec', '1|2|region=CA-QC|name=Test case region= dec'},
+ {'1|2|scale=100000|name=Test case scale= dec', '1|2|scale=100000|name=Test case scale= dec'},
+ {'1|2|source=gnis|name=Test case source= dec', '1|2|source=gnis|name=Test case source= dec'},
+ {'1|2|type=city|name=Test case type= dec', '1|2|type=city|name=Test case type= dec'},
+ {'1|S|2|W|type:city|region:XZ|name=Test case extra d', '1|S|2|W|type:city|region:XZ|name=Test case extra d'},
+ {'1|2|S|3|4|W|type:city|region:XZ|name=Test case extra dm', '1|2|S|3|4|W|type:city|region:XZ|name=Test case extra dm'},
+ {'1|2|3|S|3|4|5|W|type:city|region:XZ|name=Test case extra dms', '1|2|3|S|3|4|5|W|type:city|region:XZ|name=Test case extra dms'},
+ {'1|2|3|4', '1|2|3|4'},
+ {'1|2|3|E|4|5|6|N', '1|2|3|E|4|5|6|N'},
+ {'1|2|E|3|4|N', '1|2|E|3|4|N'},
+ {'1||N|3||E|name=Test case DM blank M', '1||N|3||E|name=Test case DM blank M'},
+ {'1|2||N|5|6||E|name=Test case DMS blank S', '1|2||N|5|6||E|name=Test case DMS blank S'},
+ {'1|||N|5|||E|name=Test case DMS blank M and S', '1|||N|5|||E|name=Test case DMS blank M and S'},
+ {'1|2|dispenser=|name=Test case DMS blank M and S', '1|2|dispenser=|name=Test case DMS blank M and S'},
+ {' 51 | 02 | 21 |N| 116 | 26 | 34 |W|name=Test case extra blanks', ' 51 | 02 | 21 |N| 116 | 26 | 34 |W|name=Test case extra blanks'},
+ {'0|0|N|0|0|E', '0|0|N|0|0|E'},
+ {'0|0|0|N|0|0|0|E', '0|0|0|N|0|0|0|E'},
+ {'0|0|N|180|0|E', '0|0|N|180|0|E'},
+ {'0|0|0|N|180|0|0|E', '0|0|0|N|180|0|0|E'},
+ {'0|59|N|179|59|W', '0|59|N|179|59|W'},
+ {'0|59|59|S|179|59|59|W', '0|59|59|S|179|59|59|W'},
+ {'44.112|N|.913|W', '44.112|N|.913|W'},
+
+ })
+end
+
+return p
From 480a76a4a75455f1d57f1eb7f28df0aece2b0eb6 Mon Sep 17 00:00:00 2001
From: Tphamtranba <119475427+Bapham12@users.noreply.github.com>
Date: Sat, 14 Mar 2026 20:10:13 +0700
Subject: [PATCH 13/25] Create Delink.lua
---
Testcases/Delink.lua | 326 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 326 insertions(+)
create mode 100644 Testcases/Delink.lua
diff --git a/Testcases/Delink.lua b/Testcases/Delink.lua
new file mode 100644
index 0000000..ef75bb2
--- /dev/null
+++ b/Testcases/Delink.lua
@@ -0,0 +1,326 @@
+local p = require('Module:UnitTests')
+
+function p:test01_basic()
+ self:preprocess_equals_many('{{delink/sandbox|', '}}', {
+ { '[[Apple]]', 'Apple'},
+ { '[[Orange]]s are dissimilar to [[Apple]]s', 'Oranges are dissimilar to Apples'},
+ { '[[Apple]]s and [[orange]]s and [[fruit salad|other kinds of fruit]]', 'Apples and oranges and other kinds of fruit'},
+ { 'All [[Gone]] [[wikt:to|]] [[Bed]] [[Now]]', 'All Gone to Bed Now'},
+ { '[[Survey]] of [http://books.google.com Google Books] on [[UK|Britain]]', 'Survey of Google Books on Britain'},
+ { '[[What If...?]]', 'What If...?' },
+ }, {nowiki='yes'})
+end
+
+function p:test02_cats_files_interwikis()
+ self:preprocess_equals_many('{{delink/sandbox|', '}}', {
+ { '[[Category:Foo]]', ''},
+ { '[[category:Foo]]', ''},
+ { '[[File:Foo]]', ''},
+ { '[[Image:Foo]]', ''},
+ { '[[es:Foo]]', ''},
+ { '[[wikt:Foo]]', 'wikt:Foo'},
+ { '[[es:Wikipedia:Políticas]]', ''},
+ { '[[abcd:efgh:ijkl]]', 'abcd:efgh:ijkl'},
+ { '[[cbk-zam:abcd:efgh]]', ''},
+ { '[[meatball:WikiPedia]]', 'meatball:WikiPedia' },
+ }, {nowiki='yes'})
+end
+
+function p:test03_colontrick()
+ self:preprocess_equals_many('{{delink/sandbox|', '}}', {
+ { '[[:Category:Foo]]', 'Category:Foo'},
+ { '[[:es:Foo]]', 'es:Foo'},
+ { '[[:wikt:Foo]]', 'wikt:Foo'},
+ { '[[:es:Wikipedia:Políticas]]', 'es:Wikipedia:Políticas'},
+ { '[[:abcd:efgh:ijkl]]', 'abcd:efgh:ijkl'},
+ { '[[:cbk-zam:abcd:efgh]]', 'cbk-zam:abcd:efgh'},
+ { '[[:meatball:WikiPedia]]', 'meatball:WikiPedia'},
+ }, {nowiki='yes'})
+end
+
+function p:test04_pipetrick()
+ self:preprocess_equals_many('{{delink/sandbox|', '}}', {
+ { '[[Pipe (computing)|]]', 'Pipe'},
+ { '[[Boston, Massachusetts|]]', 'Boston'},
+ { '[[Wikipedia:Verifiability|]]', 'Verifiability'},
+ { '[[User:Example|]]', 'Example'},
+ { '[[Template:Welcome|]]', 'Welcome'},
+ { '[[Yours, Mine and Ours (1968 film)|]]', 'Yours, Mine and Ours'},
+ { '[[:es:Wikipedia:Políticas|]]', 'Wikipedia:Políticas'},
+ { '[[Il Buono, il Brutto, il Cattivo|]]', 'Il Buono'},
+ { '[[Wikipedia:Manual of Style (Persian)|]]', 'Manual of Style'},
+ { '[[Wikipedia:Manual of Style(Persian)|]]', 'Manual of Style'},
+ { '[[foo|bar|]]', 'bar|'},
+ { '[[foo||]]', '|'},
+ { 'xx[[foo bar (baz)|]]xx', 'xxfoo bar xx'},
+ }, {nowiki='yes'})
+end
+
+function p:test05_reverse_pipetrick()
+ self:preprocess_equals_many('{{delink/sandbox|', '}}', {
+ { '[[|foo]]', 'foo'},
+ { '[[|multiple|pipes]]', '[[|multiple|pipes]]'},
+ { '[[|foo (bar)]]', 'foo (bar)'},
+ { '[[|foo, bar (baz)]]', 'foo, bar (baz)'},
+ { '[[|simultaneous pipe trick|]]', '[[|simultaneous pipe trick|]]'},
+ }, {nowiki='yes'})
+end
+
+function p:test06_badlinks()
+ self:preprocess_equals_many('{{delink/sandbox|', '}}', {
+ { '[[<]]', '[[<]]'},
+ { '[[Category:<]]', '[[Category:<]]'},
+ { '[[:Category:<]]', '[[:Category:<]]'},
+ { '[[:Category:<|Foo]]', '[[:Category:<|Foo]]'},
+ { '[[:Category:<|]]', '[[:Category:<|]]'},
+ { '[[:Category:Foo|<]]', '<'},
+ { '[[Category:Foo|<]]', ''},
+ { '[[Foo:Bar|<]]', '<'},
+ { '[[Foo:Bar:>]]', '[[Foo:Bar:>]]'},
+ { '[[es:Wikipedia:<]]', '[[es:Wikipedia:<]]'},
+ { '[[es:Wikipedia:Foo|<]]', ''},
+ { '[[:es:Wikipedia:<]]', '[[:es:Wikipedia:<]]'},
+ { '[[:es:Wikipedia:Foo|<]]', '<'},
+ { '[[Foo:Bar:Foo#>]]', 'Foo:Bar:Foo#>'},
+ { '[[Foo:Bar:Foo>#Baz]]', '[[Foo:Bar:Foo>#Baz]]'},
+ { '[[Foo#Bar>#Baz]]', 'Foo#Bar>#Baz'},
+ { '[[Foo>#Bar#Baz]]', '[[Foo>#Bar#Baz]]'},
+ { '[[wikt:es:asdf:Template:title#Fragment]]', '[[wikt:es:asdf:Template:title#Fragment]]'},
+ { '[[foo]]', '[[foo]]'}, -- ASCII delete character
+ }, {nowiki='yes'})
+end
+
+function p:test07_URI_slashes()
+ self:preprocess_equals_many('{{delink/sandbox|', '}}', {
+ { '[/foo]', '[/foo]'},
+ { '[/foo bar]', '[/foo bar]'},
+ { '[//foo]', ''},
+ { '[//foo bar]', 'bar'},
+ { '[///foo]', ''},
+ { '[///foo bar]', 'bar'},
+ { '[////foo]', ''},
+ { '[////foo bar]', 'bar'},
+ { '[///////////////////////////////////foo]', ''},
+ { '[///////////////////////////////////foo bar]', 'bar'},
+ }, {nowiki='yes'})
+end
+
+function p:test08_URI_prefixes()
+ self:preprocess_equals_many('{{delink/sandbox|', '}}', {
+ { '[://foo]', '[://foo]'},
+ { '[:://foo]', '[:://foo]'},
+ { '[abcd://]', '[abcd://]'},
+ { '[abcd://foo]', '[abcd://foo]'},
+ { '[http://]', '[http://]'},
+ { '[http://foo]', ''},
+ { '[https://]', '[https://]'},
+ { '[https://foo]', ''},
+ { '[ftp://]', '[ftp://]'},
+ { '[ftp://foo]', ''},
+ { '[gopher://]', '[gopher://]'},
+ { '[gopher://foo]', ''},
+ { '[mailto:]', '[mailto:]'},
+ { '[mailto:foo]', ''},
+ { '[news]', '[news]'},
+ { '[news at ten]', '[news at ten]'},
+ { '[news:]', '[news:]'},
+ { '[news: at ten]', '[news: at ten]'},
+ { '[news:/]', ''},
+ { '[news:/ at ten]', 'at ten'},
+ { '[news://]', ''},
+ { '[news://foo]', ''},
+ { '[news://foo at ten]', 'at ten'},
+ { '[irc://]', '[irc://]'},
+ { '[irc://foo]', ''},
+ }, {nowiki='yes'})
+end
+
+function p:test09_URI_special_characters()
+ self:preprocess_equals_many('{{delink/sandbox|', '}}', {
+ { '[:http://foo]', '[:http://foo]'},
+ { '[http://
foo]', '>foo'},
+ { '[http://foo
bar]', '>bar'},
+ { '[http:// foo]', '[http:// foo]'},
+ }, {nowiki='yes'})
+end
+
+function p:test10_nesting()
+ self:preprocess_equals_many('{{delink/sandbox|', '}}', {
+ { 'text[[strickenmore text]]', 'text[[strickenmore text]]'},
+ { 'text[[strickenmore text]]', 'text[[strickenmore text]]'},
+ { '[[outer[[inner]]outer]]', '[[outerinnerouter]]'},
+ { '[http://outer outer [[inner]] outer]', 'outer inner outer'},
+ { '[[outer[http://inner inner]outer]]', '[[outerinnerouter]]'},
+ { '[[outer[http://inner]outer]]]', '[[outerouter]]]'},
+ }, {nowiki='yes'})
+end
+
+function p:test11_multiple_pipes()
+ self:preprocess_equals_many('{{delink/sandbox|', '}}', {
+ { '[[foo|bar|baz]]', 'bar|baz'},
+ { '[[foo|bar|baz|]]', 'bar|baz|'},
+ { '[[|foo|bar|baz]]', '[[|foo|bar|baz]]'},
+ { '[[|foo|bar|baz|]]', '[[|foo|bar|baz|]]'},
+ { '[[foo|bar|baz||]]', 'bar|baz||'},
+ { '[[||foobarbaz]]', '[[||foobarbaz]]'},
+ { '[[foobarbaz||]]', '|'},
+ }, {nowiki='yes'})
+end
+
+function p:test12_http_links()
+ self:preprocess_equals_many('{{delink/sandbox|', '}}', {
+ { '[http]', '[http]'},
+ { '[http:foo]', '[http:foo]'},
+ { '[http:]', '[http:]'},
+ { '[http:foo]', '[http:foo]'},
+ { '[http:/]', '[http:/]'},
+ { '[http:/foo]', '[http:/foo]'},
+ { '[http://]', '[http://]'},
+ { '[http://foo]', ''},
+ }, {nowiki='yes'})
+end
+
+function p:test13_whitespace()
+ self:preprocess_equals_many('{{delink/sandbox|', '}}', {
+ { 'xx[[ fruit salad | many kinds of fruit ]]xx', 'xx many kinds of fruit xx'},
+ { '[http://www.example.com example]', 'example'},
+ { [=[[[link with
+ a line break in]]]=], '[[link with a line break in]]'},
+ { [=[[[link with
+
+ two line breaks in]]]=], [=[[[link with
+
+ two line breaks in]]]=] },
+ { [=[an [http://www.example.com
+ example].]=], 'an [http://www.example.com example].'},
+ { [=[an [http://www.example.com
+
+ example].]=], [=[an [http://www.example.com
+
+ example].]=] },
+ { '[http://www.example.com HTML line breaks] between
two [http://www.example.com links]', 'HTML line breaks between two links'},
+ { '[http://www.example.com HTML line break
within
a link]', 'HTML line break within a link'},
+ { '[http://www.example.com Double HTML line break
within a link]', [=[Double HTML line break
+
+within a link]=]},
+ { '[http://www.example.com non-breaking spaces]', 'non-breaking spaces'},
+ { '[http://www.example.com tab characters]', 'tab characters'},
+ { '[http://www.example.com multiple non-breaking spaces]', 'multiple non-breaking spaces'},
+ { '[http://www.example.com multiple tab characters]', 'multiple tab characters'},
+ }, {nowiki='yes'})
+end
+
+function p:test14_full_paragraphs()
+ self:preprocess_equals_many('{{delink/sandbox|', '}}', {
+ {
+ [==[He then studied at [[Saint Patrick Seminary, Menlo Park|St. Patrick's Seminary]] in [[Menlo Park, California|Menlo Park]]. He was [[Holy Orders|ordained]] to the [[Priesthood (Catholic Church)|priesthood]] on June 10, 1933.[{{cite news|work=Catholic-Hierarchy.org|title=Bishop Merlin Joseph Guilfoyle|url=http://www.catholic-hierarchy.org/bishop/bguimj.html}}] In 1937, he earned a [[Doctor of Canon Law]] from the [[The Catholic University of America|Catholic University of America]] in [[Washington, D.C.]][ He became a [[Monsignor|Domestic Prelate]] in 1949, and was co-founder and [[chaplain]] of [http://www.stthomasmore-sf.org/ St. Thomas More Society].]==],
+ [==[He then studied at St. Patrick's Seminary in Menlo Park. He was ordained to the priesthood on June 10, 1933. In 1937, he earned a Doctor of Canon Law from the Catholic University of America in Washington, D.C. He became a Domestic Prelate in 1949, and was co-founder and chaplain of St. Thomas More Society.]==],
+ },
+ })
+end
+
+function p:test15_full_paragraphs_removing_ref_strip_markers()
+ self:preprocess_equals_many('{{delink/sandbox|refs=yes|', '}}', {
+ {
+ [==[He then studied at [[Saint Patrick Seminary, Menlo Park|St. Patrick's Seminary]] in [[Menlo Park, California|Menlo Park]]. He was [[Holy Orders|ordained]] to the [[Priesthood (Catholic Church)|priesthood]] on June 10, 1933.][{{cite news|work=Catholic-Hierarchy.org|title=Bishop Merlin Joseph Guilfoyle|url=http://www.catholic-hierarchy.org/bishop/bguimj.html}}] In 1937, he earned a [[Doctor of Canon Law]] from the [[The Catholic University of America|Catholic University of America]] in [[Washington, D.C.]][ He became a [[Monsignor|Domestic Prelate]] in 1949, and was co-founder and [[chaplain]] of [http://www.stthomasmore-sf.org/ St. Thomas More Society].]==],
+ [==[He then studied at St. Patrick's Seminary in Menlo Park. He was ordained to the priesthood on June 10, 1933. In 1937, he earned a Doctor of Canon Law from the Catholic University of America in Washington, D.C. He became a Domestic Prelate in 1949, and was co-founder and chaplain of St. Thomas More Society.]==],
+ },
+ })
+end
+
+function p:test16_html_comments()
+ self:preprocess_equals_many('{{delink/sandbox|', '}}', {
+ { '[[foobaz]]', 'foobaz'},
+ { 'foobaz', 'foobaz'},
+ { 'foobat-->bam', 'foobat-->bam'},
+ { 'foo[http://abcdefgh]baz', 'foobaz'},
+ { 'foo[http://abcdbat', 'foo[http://abcdbat'},
+ { 'foo[http://ab[[cd]]bat', 'foo[http://abcdbat'},
+ { 'foo[http://ab{{!((}}cdbat', 'foo[http://ab[[cdbat'},
+ { 'foo[[bar]]bam', 'foobarbam'},
+ }, {nowiki='yes'})
+end
+
+function p:test17_nowiki()
+ self:preprocess_equals_many('{{delink/sandbox|', '}}', {
+ { '[[foo]]', '[[foo]]'},
+ { '[[foo]][[bar]][[baz]]', 'foo[[bar]]baz'},
+ { '[http://www.example.com foo]', '[http://www.example.com foo]'},
+ { '{{!((}}foobar]]', '[[foobar]]'},
+ { '[[foobar]]', '[[foobar]]'},
+ { '[http://www.example.com foo]', '[http://www.example.com foo]'},
+ }, {nowiki='yes'})
+end
+
+function p:test18_decoding()
+ self:preprocess_equals_many('{{delink/sandbox|', '}}', {
+ { '[[foo%25 bar]]', 'foo% bar'},
+ { '[[foo%25bar]]', '[[foo%25bar]]'},
+ { '[[foo%24bar]]', 'foo$bar'},
+ { '[[foo%88bar]]', '[[foo%88bar]]'},
+ { '[[foo%6Abar]]', 'foojbar'},
+ { '[[foo%11bar]]', '[[foo%11bar]]'},
+ { '[[foo&bar]]', 'foo&bar'},
+ { '[[foo%25bar]]', '[[foo%25bar]]'},
+ { '[[foo&a%6Amp;bar]]', '[[foo&a%6Amp;bar]]'},
+ { '[[foo&%61mp;bar]]', 'foo&bar'},
+ { '[[foo&%62mp;bar]]', '[[foo&%62mp;bar]]'},
+ { '[[foo%bar]]', '[[foo%bar]]'},
+ { '[[foo%62bar]]', '[[foo%62bar]]'},
+ { '[[foobar]]', '[[foobar]]'},
+ { '[[foobar]]', '[[foobar]]'},
+ { '[[foo"bar]]', 'foo"bar'},
+ { '[[foo"bar]]', 'foo"bar'},
+ { '[[foo&bar]]', '[[foo&bar]]'},
+ }, {nowiki='yes'})
+end
+
+function p:test19_URL_decoding()
+ self:preprocess_equals_many('{{delink/sandbox|', '}}', {
+ { '[http://www.example.com foo%25 bar]', 'foo%25 bar'},
+ { '[http://www.example.com foo%25bar]', 'foo%25bar'},
+ { '[http://www.example.com foo%24bar]', 'foo%24bar'},
+ { '[http://www.example.com foo%88bar]', 'foo%88bar'},
+ { '[http://www.example.com foo%6Abar]', 'foo%6Abar'},
+ { '[http://www.example.com foo%11bar]', 'foo%11bar'},
+ { '[http://www.example.com foo&bar]', 'foo&bar'},
+ { '[http://www.example.com foo%25bar]', 'foo%25bar'},
+ { '[http://www.example.com foo&a%6Amp;bar]', 'foo&a%6Amp;bar'},
+ { '[http://www.example.com foo&%61mp;bar]', 'foo&%61mp;bar'},
+ { '[http://www.example.com foo&%62mp;bar]', 'foo&%62mp;bar'},
+ { '[http://www.example.com foo%bar]', 'foo%bar'},
+ { '[http://www.example.com foo%62bar]', 'foo%62bar'},
+ { '[http://www.example.com foobar]', 'foobar'},
+ { '[http://www.example.com foobar]', 'foobar'},
+ { '[http://www.example.com foo"bar]', 'foo"bar'},
+ { '[http://www.example.com foo"bar]', 'foo"bar'},
+ }, {nowiki='yes'})
+end
+
+function p:test20_no_link()
+ self:preprocess_equals_many('{{delink/sandbox|', '}}', {
+ { '#Foo', '#Foo' },
+ { 'Foo#Bar', 'Foo#Bar' },
+ }, {nowiki='yes'})
+end
+
+function p:test21_exotic()
+ self:preprocess_equals_many('{{delink/sandbox|', '}}', {
+ { 'some text [[Apple| apples and [[Pear|pears]]]]', 'some text apples and pears' },
+ { 'some text [[Apple|[[Pear|pears]]]]', 'some text pears' },
+ { 'some text [[Apple| [[Pear|pears]]]]', 'some text pears' },
+ { 'some text [[Apple| apples and [[:Pear|pears]]]]', 'some text apples and pears' },
+ { 'some text [[Category:fred]][[Apple| apples]][[:Pear|pears]]', 'some text applespears' },
+ { 'some text [[Category:fred]] [[Apple| apples]][[:Pear|pears]]', 'some text applespears' },
+ {
+ [==[He then studied at St. Patrick's Seminary in Menlo Park. He was ordained to the priesthood on June 10, 1933. In 1937, he earned a Doctor of Canon Law from the Catholic University of America in Washington, D.C. He became a Domestic Prelate in 1949, and was co-founder and chaplain of St. Thomas More Society.]==],
+ [==[He then studied at St. Patrick's Seminary in Menlo Park. He was ordained to the priesthood on June 10, 1933. In 1937, he earned a Doctor of Canon Law from the Catholic University of America in Washington, D.C. He became a Domestic Prelate in 1949, and was co-founder and chaplain of St. Thomas More Society.]==],
+ },
+ }, {nowiki='yes'})
+end
+
+return p
From c3a8876fd13539d7e0e0815ee987018fa6c9e3a0 Mon Sep 17 00:00:00 2001
From: Tphamtranba <119475427+Bapham12@users.noreply.github.com>
Date: Sat, 14 Mar 2026 20:10:59 +0700
Subject: [PATCH 14/25] Create Doc.lua
---
Testcases/Doc.lua | 672 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 672 insertions(+)
create mode 100644 Testcases/Doc.lua
diff --git a/Testcases/Doc.lua b/Testcases/Doc.lua
new file mode 100644
index 0000000..787f861
--- /dev/null
+++ b/Testcases/Doc.lua
@@ -0,0 +1,672 @@
+-- Test cases page for [[Mô đun:Documentation]]. See talk page to run tests.
+
+local doc = require('Mô đun:Documentation/sandbox')
+local ScribuntoUnit = require('Mô đun:ScribuntoUnit')
+local suite = ScribuntoUnit:new()
+
+--------------------------------------------------------------------------------------------
+-- Test case helper functions
+--------------------------------------------------------------------------------------------
+
+local function getEnv(page)
+ -- Gets an env table using the specified page.
+ return doc.getEnvironment{page = page}
+end
+
+--------------------------------------------------------------------------------------------
+-- Test helper functions
+--------------------------------------------------------------------------------------------
+
+function suite:testMessage()
+ self:assertEquals('sandbox', doc.message('sandbox-subpage'))
+ self:assertEquals('Các trang con của foobar này', doc.message('subpages-link-display', {'foobar'}))
+ self:assertEquals(true, doc.message('display-strange-usage-category', nil, 'boolean'))
+end
+
+function suite:testMakeToolbar()
+ self:assertEquals(nil, doc.makeToolbar())
+ self:assertEquals('(Foo)', doc.makeToolbar('Foo'))
+ self:assertEquals('(Foo | Bar)', doc.makeToolbar('Foo', 'Bar'))
+end
+
+function suite:testMakeWikilink()
+ self:assertEquals('[[Foo]]', doc.makeWikilink('Foo'))
+ self:assertEquals('[[Foo|Bar]]', doc.makeWikilink('Foo', 'Bar'))
+end
+
+function suite:testMakeCategoryLink()
+ self:assertEquals('[[Thể loại:Foo]]', doc.makeCategoryLink('Foo'))
+ self:assertEquals('[[Thể loại:Foo|Bar]]', doc.makeCategoryLink('Foo', 'Bar'))
+end
+
+function suite:testMakeUrlLink()
+ self:assertEquals('[Foo Bar]', doc.makeUrlLink('Foo', 'Bar'))
+end
+
+--------------------------------------------------------------------------------------------
+-- Test env table
+--------------------------------------------------------------------------------------------
+
+function suite:assertEnvFieldEquals(expected, page, field)
+ local env = getEnv(page)
+ self:assertEquals(expected, env[field])
+end
+
+function suite:assertEnvTitleEquals(expected, page, titleField)
+ local env = getEnv(page)
+ local title = env[titleField]
+ self:assertEquals(expected, title.prefixedText)
+end
+
+function suite:testEnvTitle()
+ self:assertEnvTitleEquals('Wikipedia:Sandbox', 'Wikipedia:Sandbox', 'title')
+ self:assertEnvTitleEquals('Bản mẫu:Example/sandbox', 'Bản mẫu:Example/sandbox', 'title')
+end
+
+function suite:testEnvBadTitle()
+ local env = doc.getEnvironment{page = 'Bad[]Title'}
+ local title = env.title
+ self:assertEquals(nil, title)
+end
+
+function suite:testEnvTemplateTitle()
+ self:assertEnvTitleEquals('Bản mẫu:Example', 'Bản mẫu:Example', 'templateTitle')
+ self:assertEnvTitleEquals('Bản mẫu:Example', 'Thảo luận Bản mẫu:Example', 'templateTitle')
+ self:assertEnvTitleEquals('Bản mẫu:Example', 'Bản mẫu:Example/sandbox', 'templateTitle')
+ self:assertEnvTitleEquals('Bản mẫu:Example', 'Thảo luận Bản mẫu:Example/sandbox', 'templateTitle')
+ self:assertEnvTitleEquals('Bản mẫu:Example', 'Bản mẫu:Example/testcases', 'templateTitle')
+ self:assertEnvTitleEquals('Bản mẫu:Example/foo', 'Bản mẫu:Example/foo', 'templateTitle')
+ self:assertEnvTitleEquals('Tập tin:Example', 'Thảo luận Tập tin:Example', 'templateTitle')
+ self:assertEnvTitleEquals('Tập tin:Example', 'Thảo luận Tập tin:Example/sandbox', 'templateTitle')
+end
+
+function suite:testEnvDocTitle()
+ self:assertEnvTitleEquals('Bản mẫu:Example/doc', 'Bản mẫu:Example', 'docTitle')
+ self:assertEnvTitleEquals('Bản mẫu:Example/doc', 'Thảo luận Bản mẫu:Example', 'docTitle')
+ self:assertEnvTitleEquals('Bản mẫu:Example/doc', 'Bản mẫu:Example/sandbox', 'docTitle')
+ self:assertEnvTitleEquals('Thảo luận:Example/doc', 'Example', 'docTitle')
+ self:assertEnvTitleEquals('Thảo luận Tập tin:Example.png/doc', 'Tập tin:Example.png', 'docTitle')
+ self:assertEnvTitleEquals('Thảo luận Tập tin:Example.png/doc', 'Thảo luận Tập tin:Example.png/sandbox', 'docTitle')
+end
+
+function suite:testEnvSandboxTitle()
+ self:assertEnvTitleEquals('Bản mẫu:Example/sandbox', 'Bản mẫu:Example', 'sandboxTitle')
+ self:assertEnvTitleEquals('Bản mẫu:Example/sandbox', 'Thảo luận Bản mẫu:Example', 'sandboxTitle')
+ self:assertEnvTitleEquals('Bản mẫu:Example/sandbox', 'Bản mẫu:Example/sandbox', 'sandboxTitle')
+ self:assertEnvTitleEquals('Thảo luận:Example/sandbox', 'Example', 'sandboxTitle')
+ self:assertEnvTitleEquals('Thảo luận Tập tin:Example.png/sandbox', 'Tập tin:Example.png', 'sandboxTitle')
+end
+
+function suite:testEnvTestcasesTitle()
+ self:assertEnvTitleEquals('Bản mẫu:Example/testcases', 'Bản mẫu:Example', 'testcasesTitle')
+ self:assertEnvTitleEquals('Bản mẫu:Example/testcases', 'Thảo luận Bản mẫu:Example', 'testcasesTitle')
+ self:assertEnvTitleEquals('Bản mẫu:Example/testcases', 'Bản mẫu:Example/testcases', 'testcasesTitle')
+ self:assertEnvTitleEquals('Thảo luận:Example/testcases', 'Example', 'testcasesTitle')
+ self:assertEnvTitleEquals('Thảo luận Tập tin:Example.png/testcases', 'Tập tin:Example.png', 'testcasesTitle')
+end
+
+function suite:testEnvProtectionLevels()
+ local pipeEnv = getEnv('Bản mẫu:?')
+ self:assertEquals('autoconfirmed', pipeEnv.protectionLevels.edit[1])
+ local sandboxEnv = getEnv('Wikipedia:Sandbox')
+ local sandboxEditLevels = sandboxEnv.protectionLevels.edit
+ if sandboxEditLevels then -- sandboxEditLevels may also be nil if the page is unprotected
+ self:assertEquals(nil, sandboxEditLevels[1])
+ else
+ self:assertEquals(nil, sandboxEditLevels)
+ end
+end
+
+function suite:testEnvSubjectSpace()
+ self:assertEnvFieldEquals(10, 'Bản mẫu:Sandbox', 'subjectSpace')
+ self:assertEnvFieldEquals(10, 'Thảo luận Bản mẫu:Sandbox', 'subjectSpace')
+ self:assertEnvFieldEquals(0, 'Foo', 'subjectSpace')
+ self:assertEnvFieldEquals(0, 'Thảo luận:Foo', 'subjectSpace')
+end
+
+function suite:testEnvDocSpace()
+ self:assertEnvFieldEquals(10, 'Bản mẫu:Sandbox', 'docSpace')
+ self:assertEnvFieldEquals(828, 'Mô đun:Sandbox', 'docSpace')
+ self:assertEnvFieldEquals(1, 'Foo', 'docSpace')
+ self:assertEnvFieldEquals(7, 'Tập tin:Example.png', 'docSpace')
+ self:assertEnvFieldEquals(9, 'MediaWiki:Watchlist-details', 'docSpace')
+ self:assertEnvFieldEquals(15, 'Thể loại:Wikipedians', 'docSpace')
+end
+
+function suite:testEnvDocpageBase()
+ self:assertEnvFieldEquals('Bản mẫu:Example', 'Bản mẫu:Example', 'docpageBase')
+ self:assertEnvFieldEquals('Bản mẫu:Example', 'Bản mẫu:Example/sandbox', 'docpageBase')
+ self:assertEnvFieldEquals('Bản mẫu:Example', 'Thảo luận Bản mẫu:Example', 'docpageBase')
+ self:assertEnvFieldEquals('Thảo luận Tập tin:Example.png', 'Tập tin:Example.png', 'docpageBase')
+ self:assertEnvFieldEquals('Thảo luận Tập tin:Example.png', 'Thảo luận Tập tin:Example.png', 'docpageBase')
+ self:assertEnvFieldEquals('Thảo luận Tập tin:Example.png', 'Thảo luận Tập tin:Example.png/sandbox', 'docpageBase')
+end
+
+function suite:testEnvCompareUrl()
+ -- We use "Bản mẫu:Edit protected" rather than "Bản mẫu:Example" here as it has a space in the title.
+ local expected = 'https://vi.wikipedia.org/w/index.php?title=Đặc_biệt%3ASo_sánh_trang&page1=Template%3AEdit+protected&page2=Template%3AEdit+protected%2Fsandbox'
+ self:assertEnvFieldEquals(expected, 'Bản mẫu:Edit protected', 'compareUrl')
+ self:assertEnvFieldEquals(expected, 'Bản mẫu:Edit protected/sandbox', 'compareUrl')
+ self:assertEnvFieldEquals(nil, 'Bản mẫu:Non-existent template adsfasdg', 'compareUrl')
+ self:assertEnvFieldEquals(nil, 'Bản mẫu:Fact', 'compareUrl') -- Exists but doesn't have a sandbox.
+end
+
+--------------------------------------------------------------------------------------------
+-- Test sandbox notice
+--------------------------------------------------------------------------------------------
+
+function suite.getSandboxNoticeTestData(page)
+ local env = getEnv(page)
+ local templatePage = page:match('^(.*)/sandbox$')
+ local image = '[[Tập tin:Sandbox.svg|50px|alt=|link=]]'
+ local templateBlurb = 'This is the [[Wikipedia:Template test cases|template sandbox]] page for [[' .. templatePage .. ']]'
+ local moduleBlurb = 'This is the [[Wikipedia:Template test cases|module sandbox]] page for [[' .. templatePage .. ']]'
+ local otherBlurb = 'This is the sandbox page for [[' .. templatePage .. ']]'
+ local diff = '[https://vi.wikipedia.org/w/index.php?title=Đặc_biệt%3ASo_sánh_trang&page1=' .. mw.uri.encode(templatePage) .. '&page2=' .. mw.uri.encode(page) .. ' diff]'
+ local testcasesBlurb = 'See also the companion subpage for [[' .. templatePage .. '/testcases|test cases]].'
+ local category = '[[Thể loại:Template sandboxes]]'
+ local clear = ''
+ return env, image, templateBlurb, moduleBlurb, otherBlurb, diff, testcasesBlurb, category, clear
+end
+
+function suite:testSandboxNoticeNotSandbox()
+ local env = getEnv('Bản mẫu:Example')
+ local notice = doc.sandboxNotice({}, env)
+ self:assertEquals(nil, notice)
+end
+
+function suite:testSandboxNoticeStaticVals()
+ local env, image, templateBlurb, moduleBlurb, otherBlurb, diff, testcasesBlurb, category, clear = suite.getSandboxNoticeTestData('Bản mẫu:Example/sandbox')
+ local notice = doc.sandboxNotice({}, env)
+
+ -- Escape metacharacters (mainly '-')
+ clear = clear:gsub( '%p', '%%%0' )
+
+ self:assertStringContains('^' .. clear, notice, false)
+ self:assertStringContains(image, notice, true)
+ self:assertStringContains(category, notice, true)
+end
+
+function suite:testSandboxNoticeTemplateBlurb()
+ local env, image, templateBlurb, moduleBlurb, otherBlurb, diff, testcasesBlurb, category = suite.getSandboxNoticeTestData('Bản mẫu:Example/sandbox')
+ local notice = doc.sandboxNotice({}, env)
+ self:assertStringContains(templateBlurb, notice, true)
+end
+
+function suite:testSandboxNoticeModuleBlurb()
+ local env, image, templateBlurb, moduleBlurb, otherBlurb, diff, testcasesBlurb, category = suite.getSandboxNoticeTestData('Mô đun:Math/sandbox')
+ local notice = doc.sandboxNotice({}, env)
+ self:assertStringContains(moduleBlurb, notice, true)
+end
+
+function suite:testSandboxNoticeOtherBlurb()
+ local env, image, templateBlurb, moduleBlurb, otherBlurb, diff, testcasesBlurb, category = suite.getSandboxNoticeTestData('User:Mr. Stradivarius/sandbox')
+ local notice = doc.sandboxNotice({}, env)
+ self:assertStringContains(otherBlurb, notice, true)
+end
+
+function suite:testSandboxNoticeBlurbDiff()
+ local env, image, templateBlurb, moduleBlurb, otherBlurb, diff, testcasesBlurb, category = suite.getSandboxNoticeTestData('Bản mẫu:Example/sandbox')
+ local notice = doc.sandboxNotice({}, env)
+ if mw.title.getCurrentTitle().isTalk then
+ -- This test doesn't work in the debug console due to the use of frame:preprocess({{REVISIONID}}).
+ -- The frame test doesn't seem to be working for now, so adding a namespace hack.
+ self:assertStringContains(diff, notice, true)
+ end
+end
+
+function suite:testSandboxNoticeBlurbDiffNoBasePage()
+ local env, image, templateBlurb, moduleBlurb, otherBlurb, diff, testcasesBlurb, category = suite.getSandboxNoticeTestData('Mô đun:User:Mr. Stradivarius/sandbox')
+ local notice = doc.sandboxNotice({}, env)
+ if mw.title.getCurrentTitle().isTalk then
+ -- This test doesn't work in the debug console due to the use of frame:preprocess({{REVISIONID}}).
+ -- The frame test doesn't seem to be working for now, so adding a namespace hack.
+ self:assertNotStringContains(diff, notice, true)
+ end
+end
+
+function suite:testSandboxNoticeTestcases()
+ local env, image, templateBlurb, moduleBlurb, otherBlurb, diff, testcasesBlurb, category = suite.getSandboxNoticeTestData('Bản mẫu:Edit protected/sandbox')
+ local notice = doc.sandboxNotice({}, env)
+ self:assertStringContains(testcasesBlurb, notice, true)
+end
+
+function suite:testSandboxNoticeNoTestcases()
+ local env, image, templateBlurb, moduleBlurb, otherBlurb, diff, testcasesBlurb, category = suite.getSandboxNoticeTestData('Bản mẫu:Example/sandbox')
+ local notice = doc.sandboxNotice({}, env)
+ self:assertNotStringContains(testcasesBlurb, notice, true)
+end
+
+--------------------------------------------------------------------------------------------
+-- Test protection template
+--
+-- There's not much we can do with this until {{pp-meta}} gets rewritten in Lua. At the
+-- moment the protection detection only works for the current page, and the testcases pages
+-- will be unprotected.
+--------------------------------------------------------------------------------------------
+
+function suite:testProtectionTemplateUnprotectedTemplate()
+ local env = getEnv('Bản mẫu:Example')
+ self:assertEquals(nil, doc.protectionTemplate(env))
+end
+
+function suite:testProtectionTemplateProtectedTemplate()
+ local env = getEnv('Bản mẫu:Navbox')
+ -- Test whether there is some content. We don't care what the content is, as the protection level
+ -- detected will be for the current page, not the template.
+ self:assertTrue(doc.protectionTemplate(env))
+end
+
+function suite:testProtectionTemplateUnprotectedModule()
+ local env = getEnv('Mô đun:Example')
+ self:assertEquals(nil, doc.protectionTemplate(env))
+end
+
+function suite:testProtectionTemplateProtectedModule()
+ local env = getEnv('Mô đun:Yesno')
+ -- Test whether there is some content. We don't care what the content is, as the protection level
+ -- detected will be for the current page, not the template.
+ self:assertTrue(doc.protectionTemplate(env))
+end
+
+--------------------------------------------------------------------------------------------
+-- Test _startBox
+--------------------------------------------------------------------------------------------
+
+function suite:testStartBoxContentArg()
+ local pattern = ']\n.-
'
+ local startBox = doc._startBox({content = 'some documentation'}, getEnv('Bản mẫu:Example'))
+ self:assertStringContains(pattern, startBox)
+end
+
+function suite:testStartBoxHtml()
+ self:assertStringContains(
+ '\n.-.-
',
+ doc._startBox({}, getEnv('Bản mẫu:Example'))
+ )
+end
+
+--------------------------------------------------------------------------------------------
+-- Test makeStartBoxLinksData
+--------------------------------------------------------------------------------------------
+
+function suite:testMakeStartBoxLinksData()
+ local env = getEnv('Bản mẫu:Example')
+ local data = doc.makeStartBoxLinksData({}, env)
+ self:assertEquals('Bản mẫu:Example', data.title.prefixedText)
+ self:assertEquals('Bản mẫu:Example/doc', data.docTitle.prefixedText)
+ self:assertEquals('xem', data.viewLinkDisplay)
+ self:assertEquals('sửa', data.editLinkDisplay)
+ self:assertEquals('lịch sử', data.historyLinkDisplay)
+ self:assertEquals('làm mới', data.purgeLinkDisplay)
+ self:assertEquals('tạo', data.createLinkDisplay)
+end
+
+function suite:testMakeStartBoxLinksDataTemplatePreload()
+ local env = getEnv('Bản mẫu:Example')
+ local data = doc.makeStartBoxLinksData({}, env)
+ self:assertEquals('Bản mẫu:Tài liệu/preload', data.preload)
+end
+
+function suite:testMakeStartBoxLinksDataArgsPreload()
+ local env = getEnv('Bản mẫu:Example')
+ local data = doc.makeStartBoxLinksData({preload = 'My custom preload'}, env)
+ self:assertEquals('My custom preload', data.preload)
+end
+
+--------------------------------------------------------------------------------------------
+-- Test renderStartBoxLinks
+--------------------------------------------------------------------------------------------
+
+function suite.makeExampleStartBoxLinksData(exists)
+ -- Makes a data table to be used with testRenderStartBoxLinksExists and testRenderStartBoxLinksDoesntExist.
+ local data = {}
+ if exists then
+ data.title = mw.title.new('Bản mẫu:Example')
+ data.docTitle = mw.title.new('Bản mẫu:Example/doc')
+ else
+ data.title = mw.title.new('Bản mẫu:NonExistentTemplate')
+ data.docTitle = mw.title.new('Bản mẫu:NonExistentTemplate/doc')
+ end
+ data.viewLinkDisplay = 'xem'
+ data.editLinkDisplay = 'sửa'
+ data.historyLinkDisplay = 'lịch sử'
+ data.purgeLinkDisplay = 'làm mới'
+ data.createLinkDisplay = 'tạo'
+ data.preload = 'Bản mẫu:MyPreload'
+ return data
+end
+
+function suite:testRenderStartBoxLinksExists()
+ local data = suite.makeExampleStartBoxLinksData(true)
+ local expected = '[[[Bản mẫu:Example/doc|xem]]] [[[Đặc_biệt:EditPage/Bản mẫu:Example/doc|sửa]]] [[[Đặc_biệt:PageHistory/Bản mẫu:Example/doc|lịch sử]]] [[[Đặc_biệt:Purge/Bản mẫu:Example|làm mới]]]'
+ self:assertEquals(expected, doc.renderStartBoxLinks(data))
+end
+
+function suite:testRenderStartBoxLinksDoesntExist()
+ local data = suite.makeExampleStartBoxLinksData(false)
+ local expected = '[[https://vi.wikipedia.org/w/index.php?title=B%E1%BA%A3n_m%E1%BA%ABu:NonExistentTemplate/doc&action=edit&preload=B%E1%BA%A3n+m%E1%BA%ABu%3AMyPreload tạo]] [[[Đặc_biệt:Purge/Bản mẫu:NonExistentTemplate|làm mới]]]'
+ self:assertEquals(expected, doc.renderStartBoxLinks(data))
+end
+
+--------------------------------------------------------------------------------------------
+-- Test makeStartBoxData
+--------------------------------------------------------------------------------------------
+
+function suite:testStartBoxDataBlankHeading()
+ local data = doc.makeStartBoxData({heading = ''}, {})
+ self:assertEquals(nil, data)
+end
+
+function suite:testStartBoxDataHeadingTemplate()
+ local env = getEnv('Bản mẫu:Example')
+ local data = doc.makeStartBoxData({}, env)
+ local expected = '[[Tập tin:Test Template Info-Icon - Version (2).svg|50px|link=|alt=]] Tài liệu bản mẫu'
+ self:assertEquals(expected, data.heading)
+end
+
+function suite:testStartBoxDataHeadingModule()
+ local env = getEnv('Mô đun:Example')
+ local data = doc.makeStartBoxData({}, env)
+ local expected = '[[Tập tin:Test Template Info-Icon - Version (2).svg|50px|link=|alt=]] Tài liệu mô đun'
+ self:assertEquals(expected, data.heading)
+end
+
+function suite:testStartBoxDataHeadingFile()
+ local env = getEnv('Tập tin:Example.png')
+ local data = doc.makeStartBoxData({}, env)
+ local expected = 'Tóm lược'
+ self:assertEquals(expected, data.heading)
+end
+
+function suite:testStartBoxDataHeadingOther()
+ local env = getEnv('User:Example')
+ local data = doc.makeStartBoxData({}, env)
+ local expected = 'Tài liệu'
+ self:assertEquals(expected, data.heading)
+end
+
+function suite:testStartBoxDataHeadingStyle()
+ local data = doc.makeStartBoxData({['heading-style'] = 'foo:bar'}, {})
+ self:assertEquals('foo:bar', data.headingStyleText)
+end
+
+function suite:testStartBoxDataHeadingStyleTemplate()
+ local env = getEnv('Bản mẫu:Example')
+ local data = doc.makeStartBoxData({}, env)
+ self:assertEquals(nil, data.headingStyleText)
+end
+
+function suite:testStartBoxDataHeadingStyleOther()
+ local env = getEnv('User:Example')
+ local data = doc.makeStartBoxData({}, env)
+ self:assertEquals(nil, data.headingStyleText)
+end
+
+function suite:testStartBoxDataLinks()
+ local env = getEnv('Bản mẫu:Example')
+ local data = doc.makeStartBoxData({}, env, 'some links')
+ self:assertEquals('some links', data.links)
+ self:assertEquals('mw-editsection-like plainlinks', data.linksClass)
+end
+
+function suite:testStartBoxDataNoLinks()
+ local env = getEnv('Bản mẫu:Example')
+ local data = doc.makeStartBoxData({}, env)
+ self:assertEquals(nil, data.links)
+ self:assertEquals(nil, data.linksClass)
+ self:assertEquals(nil, data.linksId)
+end
+
+--------------------------------------------------------------------------------------------
+-- Test renderStartBox
+--------------------------------------------------------------------------------------------
+
+function suite:testRenderStartBox()
+ local expected = '\n
'
+ self:assertEquals(expected, doc.renderStartBox{})
+end
+
+function suite:testRenderStartBoxHeadingStyleText()
+ self:assertStringContains('\n', doc.renderStartBox{headingStyleText = 'foo:bar'}, true)
+end
+
+function suite:testRenderStartBoxHeading()
+ self:assertStringContains('\nFoobar', doc.renderStartBox{heading = 'Foobar'}, true)
+end
+
+function suite:testRenderStartBoxLinks()
+ self:assertStringContains('list of links', doc.renderStartBox{links = 'list of links'}, true)
+end
+
+function suite:testRenderStartBoxLinksClass()
+ self:assertStringContains('list of links', doc.renderStartBox{linksClass = 'linksclass', links = 'list of links'}, true)
+ self:assertNotStringContains('linksclass', doc.renderStartBox{linksClass = 'linksclass'}, true)
+end
+
+function suite:testRenderStartBoxLinksId()
+ self:assertStringContains('list of links', doc.renderStartBox{linksId = 'linksid', links = 'list of links'}, true)
+ self:assertNotStringContains('linksid', doc.renderStartBox{linksId = 'linksid'}, true)
+end
+
+--------------------------------------------------------------------------------------------
+-- Test _content
+--------------------------------------------------------------------------------------------
+
+function suite:testContentArg()
+ self:assertEquals('\nsome documentation\n', doc._content({content = 'some documentation'}, {}))
+end
+
+function suite:testContentNoContent()
+ local env = getEnv('Bản mẫu:This is a non-existent template agauchvaiu')
+ self:assertEquals('\n\n', doc._content({}, env))
+end
+
+function suite:testContentExists()
+ local env = doc.getEnvironment{'Bản mẫu:Documentation/testcases/test3'}
+ local docs = mw.getCurrentFrame():preprocess('{{Bản mẫu:Documentation/testcases/test3}}')
+ local expected = '\n' .. docs .. '\n'
+ self:assertEquals(expected, doc._content({}, env))
+end
+
+--------------------------------------------------------------------------------------------
+-- Test _endBox
+--------------------------------------------------------------------------------------------
+
+function suite:testEndBoxLinkBoxOff()
+ local env = getEnv()
+ self:assertEquals(nil, doc._endBox({['link box'] = 'off'}, env))
+end
+
+function suite:testEndBoxNoDocsOtherNs()
+ local env = {
+ subjectSpace = 4,
+ docTitle = {
+ exists = false
+ }
+ }
+ self:assertEquals(nil, doc._endBox({}, env))
+end
+
+function suite:testEndBoxAlwaysShowNs()
+ self:assertTrue(doc._endBox({}, getEnv('Bản mẫu:Non-existent template asdfalsdhaw')))
+ self:assertTrue(doc._endBox({}, getEnv('Mô đun:Non-existent module asdhewbydcyg')))
+ self:assertTrue(doc._endBox({}, getEnv('User:Non-existent user ahfliwebalisyday')))
+end
+
+function suite:testEndBoxStyles()
+ local env = getEnv('Bản mẫu:Example')
+ local endBox = doc._endBox({}, env)
+ self:assertStringContains('class="documentation-metadata plainlinks"', endBox, true)
+end
+
+function suite:testEndBoxLinkBoxArg()
+ local env = getEnv()
+ self:assertStringContains('Custom link box', doc._endBox({['link box'] = 'Custom link box'}, env))
+end
+
+function suite:testEndBoxExperimentBlurbValidNs()
+ local expected = 'Editors can experiment in this.-
'
+ self:assertStringContains(expected, doc._endBox({}, getEnv('Bản mẫu:Example')))
+ self:assertStringContains(expected, doc._endBox({}, getEnv('Mô đun:Example')))
+ self:assertStringContains(expected, doc._endBox({}, getEnv('User:Example')))
+end
+
+function suite:testEndBoxExperimentBlurbInvalidNs()
+ local expected = 'Editors can experiment in this.-
'
+ self:assertNotStringContains(expected, doc._endBox({}, getEnv('Wikipedia:Twinkle'))) -- Wikipedia:Twinkle has an existing /doc subpage
+end
+
+function suite:testEndBoxCategoriesBlurb()
+ local expected = 'Add categories to the %[%[.-|/doc%]%] subpage%.'
+ self:assertStringContains(expected, doc._endBox({}, getEnv('Bản mẫu:Example')))
+ self:assertStringContains(expected, doc._endBox({}, getEnv('Mô đun:Example')))
+ self:assertStringContains(expected, doc._endBox({}, getEnv('User:Example')))
+ self:assertNotStringContains(expected, doc._endBox({[1] = 'Foo'}, getEnv('Bản mẫu:Example')))
+ self:assertNotStringContains(expected, doc._endBox({content = 'Bar'}, getEnv('Bản mẫu:Example')))
+ self:assertNotStringContains(expected, doc._endBox({}, getEnv('Wikipedia:Twinkle')))
+end
+
+--------------------------------------------------------------------------------------------
+-- Test makeDocPageBlurb
+--------------------------------------------------------------------------------------------
+
+function suite:testDocPageBlurbError()
+ self:assertEquals(nil, doc.makeDocPageBlurb({}, {}))
+end
+
+function suite:testDocPageBlurbTemplateDocExists()
+ local env = getEnv('Bản mẫu:Documentation')
+ local expected = '[[Wikipedia:Tài liệu bản mẫu|Tài liệu]] bên trên [[:en:Wikipedia:Transclusion|được truyền tải]] từ [[Bản mẫu:Documentation/doc]]. ([[Đặc_biệt:EditPage/Bản mẫu:Documentation/doc|sửa]] | [[Đặc_biệt:PageHistory/Bản mẫu:Documentation/doc|lịch sử]])
'
+ self:assertEquals(expected, doc.makeDocPageBlurb({}, env))
+end
+
+function suite:testDocPageBlurbTemplateDocDoesntExist()
+ local env = getEnv('Bản mẫu:Non-existent template ajlkfdsa')
+ self:assertEquals(nil, doc.makeDocPageBlurb({}, env))
+end
+
+function suite:testDocPageBlurbModuleDocExists()
+ local env = getEnv('Mô đun:Example')
+ local expected = '[[Wikipedia:Tài liệu bản mẫu|Tài liệu]] bên trên [[:en:Wikipedia:Transclusion|được truyền tải]] từ [[Mô đun:Example/doc]]. ([[Đặc_biệt:EditPage/Mô đun:Example/doc|sửa]] | [[Đặc_biệt:PageHistory/Mô đun:Example/doc|lịch sử]])
'
+ self:assertEquals(expected, doc.makeDocPageBlurb({}, env))
+end
+
+function suite:testDocPageBlurbModuleDocDoesntExist()
+ local env = getEnv('Mô đun:Non-existent module ajlkfdsa')
+ local expected = 'Bạn có thể muốn [https://vi.wikipedia.org/w/index.php?title=M%C3%B4_%C4%91un:Non-existent_module_ajlkfdsa/doc&action=edit&preload=B%E1%BA%A3n+m%E1%BA%ABu%3AT%C3%A0i+li%E1%BB%87u%2Fpreload-module-doc tạo] một trang tài liệu cho [[:en:Wikipedia:Lua|mô đun Scribunto]] này.
'
+ self:assertEquals(expected, doc.makeDocPageBlurb({}, env))
+end
+
+--------------------------------------------------------------------------------------------
+-- Test makeExperimentBlurb
+--------------------------------------------------------------------------------------------
+
+function suite:testExperimentBlurbTemplate()
+ local env = getEnv('Bản mẫu:Example')
+ self:assertStringContains("Editors can experiment in this template's .- and .- pages.", doc.makeExperimentBlurb({}, env), false)
+end
+
+function suite:testExperimentBlurbModule()
+ local env = getEnv('Mô đun:Example')
+ self:assertStringContains("Editors can experiment in this module's .- and .- pages.", doc.makeExperimentBlurb({}, env), false)
+end
+
+function suite:testExperimentBlurbSandboxExists()
+ local env = getEnv('Bản mẫu:Edit protected')
+ local pattern = '[[Bản mẫu:Edit protected/sandbox|sandbox]] ([[Đặc_biệt:EditPage/Bản mẫu:Edit protected/sandbox|edit]] | [https://vi.wikipedia.org/w/index.php?title=Đặc_biệt%3ASo_sánh_trang&page1=Template%3AEdit+protected&page2=Template%3AEdit+protected%2Fsandbox diff])'
+ self:assertStringContains(pattern, doc.makeExperimentBlurb({}, env), true)
+end
+
+function suite:testExperimentBlurbSandboxDoesntExist()
+ local env = getEnv('Bản mẫu:Non-existent template sajdfasd')
+ local pattern = 'sandbox ([https://vi.wikipedia.org/w/index.php?title=Bản_mẫu:Non-existent_template_sajdfasd/sandbox&action=edit&preload=Template%3ADocumentation%2Fpreload-sandbox create] | [https://vi.wikipedia.org/w/index.php?title=Bản_mẫu:Non-existent_template_sajdfasd/sandbox&preload=Template%3ADocumentation%2Fmirror&action=edit&summary=Create+sandbox+version+of+%5B%5BTemplate%3ANon-existent+template+sajdfasd%5D%5D mirror])'
+ self:assertStringContains(pattern, doc.makeExperimentBlurb({}, env), true)
+end
+
+function suite:testExperimentBlurbTestcasesExist()
+ local env = getEnv('Bản mẫu:Edit protected')
+ local pattern = '[[Bản mẫu:Edit protected/testcases|testcases]] ([[Đặc_biệt:EditPage/Bản mẫu:Edit protected/testcases|edit]])'
+ self:assertStringContains(pattern, doc.makeExperimentBlurb({}, env), true)
+end
+
+function suite:testExperimentBlurbTestcasesDontExist()
+ local env = getEnv('Bản mẫu:Non-existent template sajdfasd')
+ local pattern = 'testcases ([https://vi.wikipedia.org/w/index.php?title=Bản_mẫu:Non-existent_template_sajdfasd/testcases&action=edit&preload=Template%3ADocumentation%2Fpreload-testcases create])'
+ self:assertStringContains(pattern, doc.makeExperimentBlurb({}, env), true)
+end
+
+--------------------------------------------------------------------------------------------
+-- Test makeCategoriesBlurb
+--------------------------------------------------------------------------------------------
+
+function suite:testMakeCategoriesBlurb()
+ local env = getEnv('Bản mẫu:Example')
+ self:assertEquals('Xin hãy bổ sung các thể loại vào trang con [[Bản mẫu:Example/doc|/doc]].', doc.makeCategoriesBlurb({}, env))
+end
+
+--------------------------------------------------------------------------------------------
+-- Test makeSubpagesBlurb
+--------------------------------------------------------------------------------------------
+
+function suite:testMakeSubpagesBlurbTemplate()
+ local env = getEnv('Bản mẫu:Example')
+ self:assertEquals('[[Đặc_biệt:Tiền_tố/Bản mẫu:Example/|Các trang con của bản mẫu này]].', doc.makeSubpagesBlurb({}, env))
+end
+
+function suite:testMakeSubpagesBlurbModule()
+ local env = getEnv('Mô đun:Example')
+ self:assertEquals('[[Đặc_biệt:Tiền_tố/Mô đun:Example/|Các trang con của mô đun này]].', doc.makeSubpagesBlurb({}, env))
+end
+
+function suite:testMakeSubpagesBlurbOther()
+ local env = getEnv('Tập tin:Example.png')
+ self:assertEquals('[[Đặc_biệt:Tiền_tố/Tập tin:Example.png/|Các trang con của trang này]].', doc.makeSubpagesBlurb({}, env))
+end
+--------------------------------------------------------------------------------------------
+-- Test addTrackingCategories
+--------------------------------------------------------------------------------------------
+
+function suite.getStrangeUsageCat()
+ return '[[Thể loại:Các trang Wikipedia có cách sử dụng ((tài liệu)) lạ]]'
+end
+
+function suite:testAddTrackingCategoriesTemplatePage()
+ local env = getEnv('Bản mẫu:Example')
+ self:assertEquals('', doc.addTrackingCategories(env))
+end
+
+function suite:testAddTrackingCategoriesDocPage()
+ local env = getEnv('Bản mẫu:Example/doc')
+ self:assertEquals(self.getStrangeUsageCat(), doc.addTrackingCategories(env))
+end
+
+function suite:testAddTrackingCategoriesTestcasesPage()
+ local env = getEnv('Bản mẫu:Example/testcases')
+ self:assertEquals(self.getStrangeUsageCat(), doc.addTrackingCategories(env))
+end
+
+function suite:testAddTrackingCategoriesModuleDoc()
+ local env = getEnv('Mô đun:Math/doc')
+ self:assertEquals(self.getStrangeUsageCat(), doc.addTrackingCategories(env))
+end
+
+function suite:testAddTrackingCategoriesModuleTestcases()
+ local env = getEnv('Mô đun:Math/testcases')
+ self:assertEquals('', doc.addTrackingCategories(env))
+end
+
+function suite:testAddTrackingCategoriesInvalidTitle()
+ local env = getEnv('Bản mẫu:Foo[]Bar')
+ self:assertEquals(nil, doc.addTrackingCategories(env))
+end
+
+--------------------------------------------------------------------------------------------
+-- Whitespace tests
+--------------------------------------------------------------------------------------------
+
+function suite:testNoTrailingWhitespace()
+ self:assertStringContains('of this template%]%]. $', doc._main{page = 'Bản mẫu:Example'})
+end
+
+return suite
From a8385c56e7aff815cd02e08c3b7b8d0c8482245c Mon Sep 17 00:00:00 2001
From: Tphamtranba <119475427+Bapham12@users.noreply.github.com>
Date: Sat, 14 Mar 2026 20:11:33 +0700
Subject: [PATCH 15/25] Create Error.lua
---
Testcases/Error.lua | 60 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
create mode 100644 Testcases/Error.lua
diff --git a/Testcases/Error.lua b/Testcases/Error.lua
new file mode 100644
index 0000000..c2e049f
--- /dev/null
+++ b/Testcases/Error.lua
@@ -0,0 +1,60 @@
+-- Unit tests for [[Module:Error]]. Click talk page to run tests.
+local p = require('Module:UnitTests')
+
+function p:test_error()
+ self:preprocess_equals_sandbox_many('{{#invoke:Error', 'error', {
+ -- Minimal parameter input
+ {'', '