elseif content1 == content2 then
label = message('same content', true)
else
label = message('different', false) .. ' (' .. diff_link(title1, title2) .. ')'
end
end
result:add(prefix .. link(title1) .. ' • ' .. link(title2) .. ' • ' .. label)
end
return result:join('\n')
end  
local function sections(text)
return {
first = 1, -- just after the newline at the end of the last heading
this_section = 1,
next_heading = function(self)
local first = self.first
while first <= #text do
local last, heading
first, last, heading = text:find('==+[\t ]*([^\n]-)[\t ]*==+[\t\r ]*\n', first)
if first then
if first == 1 or text:sub(first - 1, first - 1) == '\n' then
self.this_section = first
self.first = last + 1
return heading
end
first = last + 1
else
break
end
end
self.first = #text + 1
return nil
end,
current_section = function(self)
local first = self.this_section
local last = text:find('\n==[^\n]-==[\t\r ]*\n', first)
if not last then
last = -1
end
return text:sub(first, last)
end,
}
end  
local function get_tests(, tests)
local args = .args
local page_title, section_title = args.page, args.section
local show_all = (args.show == 'all')
if not empty(page_title) then
if not empty(tests) then
error('Invoke must not set "page=' .. page_title .. '" if also setting p.tests.', 0)
end
if page_title:sub(1, 2) == * and page_title:sub(-2) == * then
page_title = strip(page_title:sub(3, -3))
end
tests = get_page_content(page_title)
if not empty(section_title) then
local s = sections(tests)
while true do
local heading = s:next_heading
if heading then
if heading == section_title then
tests = s:current_section
break
end
else
error('Section "' .. section_title .. '" not found in page ' .. page_title .. '.', 0)
end
end
end
end
if type(tests) ~= 'string' then
if type(tests) == 'table' then
return tests
end
error('No tests were specified; see Module:Convert/tester/doc.', 0)
end
if tests:sub(-1) ~= '\n' then
tests = tests .. '\n'
end
local template_count = 0
local all_tests = Collection.new
for line in (tests):gmatch('([^\n]-)[\t\r ]*\n') do
local template, expected = line:match('^%s*(.-)%s*$')
if template then
template_count = template_count + 1
all_tests:add({ template, expected })
elseif show_all then
all_tests:add({ text = line })
end
end
if template_count == 0 then
error('No templates found; see Module:Convert/tester/doc.', 0)
end
return all_tests
end  
local function main(, p, worker)
local ok, result = pcall(get_tests, , p.tests)
if ok then
ok, result = pcall(worker, , result, .args)
if ok then
return result
end
end
return '<strong>Error</strong>\n\n' .. result
end  
local modules = {
-- For convenience, a key defined here can be used to refer to the
-- corresponding list of modules.
countries = { -- Commons
'Countries',
'Countries/Africa',
'Countries/Americas',
'Countries/Arab world',
'Countries/Asia',
'Countries/Caribbean',
'Countries/Central America',
'Countries/Europe',
'Countries/North America',
'Countries/North America (subcontinent)',
'Countries/Oceania',
'Countries/South America',
'Countries/United Kingdom',
},
convert = {
'Convert',
'Convert/data',
'Convert/text',
'Convert/extra',
'Convert/wikidata',
'Convert/wikidata/data',
},
cs1 = {
'Citation/CS1',
'Citation/CS1/Configuration',
},
cs1all = {
'Citation/CS1',
'Citation/CS1/Configuration',
'Citation/CS1/Whitelist',
'Citation/CS1/Date validation',
},
team = {
'Team appearances list',
'Team appearances list/data',
'Team appearances list/show',
},
val = {
'Val',
'Val/units',
},
}  
local p = {}  
function p.compare
local page_pairs = p.pairs
if not page_pairs then
local args = .args
if not args[2] then
local builtins = modules[args[1] or 'convert']
if builtins then
args = builtins
end
end
page_pairs = {}
for i, title in ipairs(args) do
if not title:find(':', 1, true) then
title = 'Module:' .. title
end
page_pairs[i] = { title, title .. '/sandbox' }
end
end
local ok, result = pcall(_compare, , page_pairs)
if ok then
return result
end
return '<strong>Error</strong>\n\n' .. result
end  
p.check_sandbox = p.compare  
function p.make_tests
return main(, p, _make_tests)
end  
function p.run_tests
return main(, p, _run_tests)
end  
return p