Module:Sandbox/Vergir: Difference between revisions

Vergir (talk | contribs)
Testing reworked HeroData: module body (with help from vergir-bot LLM)
Vergir (talk | contribs)
Testing reworked HeroData: parity harness (with help from vergir-bot LLM)
Line 447: Line 447:
     return table.concat(output, "\n")
     return table.concat(output, "\n")
end
end
--------------------------------------------------------------------------------
-- TEMPORARY parity harness - NOT part of the live module.
-- {{#invoke:Sandbox/Vergir|test|SUITE}} where SUITE is one of:
--  stats | list | scalars | scalings | has_stat | keys | tags
--------------------------------------------------------------------------------
local old_module = require('Module:HeroData')
local function repr(v, depth)
depth = depth or 0
if type(v) ~= 'table' then return tostring(v) end
if depth > 3 then return '<deep>' end
local entries = {}
for k, val in pairs(v) do
table.insert(entries, { k = tostring(k), v = val })
end
table.sort(entries, function(a, b) return a.k < b.k end)
local parts = {}
for _, e in ipairs(entries) do
table.insert(parts, e.k .. '=' .. repr(e.v, depth + 1))
end
return '{' .. table.concat(parts, ',') .. '}'
end
-- Calls fn(...) and returns a normalised string, so that a raised error on one
-- side compares equal to the same error on the other (line numbers stripped).
local function attempt(fn, ...)
local ok, result = pcall(fn, ...)
if ok then return repr(result) end
return 'ERR:' .. tostring(result):gsub("^.-:%d+: ", "")
end
local function sorted_hero_keys()
local list = {}
for hero_key in pairs(heroes_data) do table.insert(list, hero_key) end
table.sort(list)
return list
end
-- Every key appearing anywhere in the hero data, so sweeps are exhaustive.
local function all_stat_keys()
local seen = {}
for _, hero in pairs(heroes_data) do
local sources = {
hero,
hero.Weapon or {},
(hero.Weapon and hero.Weapon.AltFire) or {},
hero.LevelScaling or {},
hero.SpiritScaling or {},
}
for _, source in ipairs(sources) do
for stat in pairs(source) do
if type(stat) == 'string' then seen[stat] = true end
end
end
end
local list = {}
for stat in pairs(seen) do table.insert(list, stat) end
table.sort(list)
return list
end
local MAX_ROWS = 50
local function report(title, checked, mismatches)
local out = {
"'''" .. title .. "'''",
'',
'Comparisons: ' .. checked,
'Mismatches: ' .. #mismatches,
'',
}
if #mismatches == 0 then
table.insert(out, ':<span style="color:#13f278">No differences.</span>')
return table.concat(out, '\n')
end
table.insert(out, '{| class="wikitable"')
table.insert(out, '! Case !! old !! new')
for i, row in ipairs(mismatches) do
if i > MAX_ROWS then
table.insert(out, '|-\n| colspan="3" | ... and ' .. (#mismatches - MAX_ROWS) .. ' more')
break
end
table.insert(out, '|-\n| <code>' .. row[1] .. '</code> || <code>' ..
mw.text.nowiki(row[2]) .. '</code> || <code>' .. mw.text.nowiki(row[3]) .. '</code>')
end
table.insert(out, '|}')
return table.concat(out, '\n')
end
local suites = {}
-- p.get_stat, via get_hero_var
suites.stats = function()
local checked, mismatches = 0, {}
local stat_keys = all_stat_keys()
for _, hero_key in ipairs(sorted_hero_keys()) do
for _, stat in ipairs(stat_keys) do
local frame = { args = { hero_key, stat } }
local a = attempt(old_module.get_hero_var, frame)
local b = attempt(p.get_hero_var, frame)
checked = checked + 1
if a ~= b then
table.insert(mismatches, { hero_key .. ' / ' .. stat, a, b })
end
end
end
return report('get_hero_var (p.get_stat)', checked, mismatches)
end
-- p.get_stat, via get_list_elem
suites.list = function()
local checked, mismatches = 0, {}
local stat_keys = all_stat_keys()
for _, hero_key in ipairs(sorted_hero_keys()) do
for _, stat in ipairs(stat_keys) do
for index = 1, 2 do
local frame = { args = { hero_key, stat, tostring(index) } }
local a = attempt(old_module.get_list_elem, frame)
local b = attempt(p.get_list_elem, frame)
checked = checked + 1
if a ~= b then
table.insert(mismatches, { hero_key .. ' / ' .. stat .. ' [' .. index .. ']', a, b })
end
end
end
end
return report('get_list_elem (p.get_stat)', checked, mismatches)
end
-- raw_scaling, via get_hero_scalar (both template and no_template modes)
suites.scalars = function()
local checked, mismatches = 0, {}
local stat_keys = all_stat_keys()
for _, hero_key in ipairs(sorted_hero_keys()) do
for _, stat in ipairs(stat_keys) do
for _, scaling_type in ipairs({ 'Level', 'Spirit' }) do
for _, no_template in ipairs({ 'true', '' }) do
local frame = { args = { hero_key, scaling_type, stat, no_template = no_template } }
local a = attempt(old_module.get_hero_scalar, frame)
local b = attempt(p.get_hero_scalar, frame)
checked = checked + 1
if a ~= b then
table.insert(mismatches, {
hero_key .. ' / ' .. scaling_type .. ' / ' .. stat ..
(no_template == 'true' and ' (raw)' or ''), a, b })
end
end
end
end
end
return report('get_hero_scalar (raw_scaling)', checked, mismatches)
end
-- The deprecated shim must stay byte-identical for Module:HeroComparisonTable
suites.scalings = function()
local checked, mismatches = 0, {}
local stat_keys = all_stat_keys()
for _, hero_key in ipairs(sorted_hero_keys()) do
local hero_data = heroes_data[hero_key]
for _, stat in ipairs(stat_keys) do
local a = attempt(old_module.get_hero_scaling_data, hero_data, stat)
local b = attempt(p.get_hero_scaling_data, hero_data, stat)
checked = checked + 1
if a ~= b then
table.insert(mismatches, { hero_key .. ' / ' .. stat, a, b })
end
end
end
return report('get_hero_scaling_data (deprecated shim)', checked, mismatches)
end
-- EXPECTED to differ: new version is Weapon/AltFire aware
suites.has_stat = function()
local checked, mismatches = 0, {}
local stat_keys = all_stat_keys()
for _, hero_key in ipairs(sorted_hero_keys()) do
for _, stat in ipairs(stat_keys) do
local frame = { args = { hero_key, stat } }
local a = attempt(old_module.hero_has_stat, frame)
local b = attempt(p.hero_has_stat, frame)
checked = checked + 1
if a ~= b then
table.insert(mismatches, { hero_key .. ' / ' .. stat, a, b })
end
end
end
return report('hero_has_stat (EXPECTED to widen)', checked, mismatches)
end
-- EXPECTED to differ: new version also accepts a hero_* key
suites.keys = function()
local checked, mismatches = 0, {}
local inputs = {}
for _, hero_key in ipairs(sorted_hero_keys()) do
table.insert(inputs, hero_key)
local name = heroes_data[hero_key]['Name']
if name then
table.insert(inputs, name)
table.insert(inputs, mw.ustring.upper(name))
table.insert(inputs, mw.ustring.lower(name))
end
end
for _, extra in ipairs({ '', ' ', 'Not A Hero', 'hero_nope' }) do
table.insert(inputs, extra)
end
for _, input in ipairs(inputs) do
local frame = { args = { input } }
local a = attempt(old_module.get_hero_key, frame)
local b = attempt(p.get_hero_key, frame)
checked = checked + 1
if a ~= b then
table.insert(mismatches, { input, a, b })
end
end
return report('get_hero_key (EXPECTED to widen)', checked, mismatches)
end
-- get_hero_tag must be unchanged; the has_tags predicate may narrow
suites.tags = function()
local checked, mismatches = 0, {}
local names = {}
for _, hero_key in ipairs(sorted_hero_keys()) do
local name = heroes_data[hero_key]['Name']
if name then table.insert(names, name) end
end
for _, extra in ipairs({ 'Not A Hero', '' }) do table.insert(names, extra) end
for _, name in ipairs(names) do
for _, index in ipairs({ '0', '1', '2', '3', '4', 'x' }) do
local frame = { args = { name, index } }
local a = attempt(old_module.get_hero_tag, frame)
local b = attempt(p.get_hero_tag, frame)
checked = checked + 1
if a ~= b then
table.insert(mismatches, { name .. ' [' .. index .. ']', a, b })
end
end
-- Predicate: old Infobox_hero.hero_has_tags vs new p.has_tags
local old_tag = old_module.get_hero_tag({ args = { name, '1' } })
local old_pred = tostring(string.find(old_tag, 'Error:') == nil)
local new_pred = tostring(p.has_tags({ args = { name } }) == 'true')
checked = checked + 1
if old_pred ~= new_pred then
table.insert(mismatches, { 'PREDICATE ' .. name, old_pred, new_pred })
end
end
return report('get_hero_tag + has_tags predicate', checked, mismatches)
end
function p.test(frame)
local suite = frame.args[1]
if suite == nil or suites[suite] == nil then
local names = {}
for name in pairs(suites) do table.insert(names, name) end
table.sort(names)
return 'Pick a suite: ' .. table.concat(names, ', ')
end
return suites[suite]()
end
return p