From e101bfa16200550ff14edb608709421b3a880321 Mon Sep 17 00:00:00 2001 From: hjpalpha Date: Sun, 14 Jun 2026 13:03:09 +0200 Subject: [PATCH 1/4] fix(TeamCard/Legacy): Changed behaviour in input processing --- lua/wikis/commons/TeamCard/Legacy.lua | 29 +++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/lua/wikis/commons/TeamCard/Legacy.lua b/lua/wikis/commons/TeamCard/Legacy.lua index 321de22cbdf..cb0987a6994 100644 --- a/lua/wikis/commons/TeamCard/Legacy.lua +++ b/lua/wikis/commons/TeamCard/Legacy.lua @@ -12,7 +12,9 @@ local Array = Lua.import('Module:Array') local Json = Lua.import('Module:Json') local Logic = Lua.import('Module:Logic') local Namespace = Lua.import('Module:Namespace') +local Page = Lua.import('Module:Page') local PageVariableNamespace = Lua.import('Module:PageVariableNamespace') +local PlayerExt = Lua.import('Module:Player/Ext') local String = Lua.import('Module:StringUtils') local RoleUtil = Lua.import('Module:Role/Util') local Table = Lua.import('Module:Table') @@ -21,6 +23,11 @@ local Tournament = Lua.import('Module:Tournament') local TeamParticipantsController = Lua.import('Module:TeamParticipants/Controller') +local Condition = Lua.import('Module:Condition') +local ConditionNode = Condition.Node +local Comparator = Condition.Comparator +local ColumnName = Condition.ColumnName + local HtmlWidgets = Lua.import('Module:Widget/Html/All') local WidgetUtil = Lua.import('Module:Widget/Util') @@ -243,10 +250,28 @@ function LegacyTeamCard.mapPlayer(tcArgs, prefix, sourceGroup) end end + -- can't rely on PlayerExt.syncPlayer because the old TC did not read from wiki vars + -- hence you would get unexpectedly different data compared to the old stuff with syncPlayer + ---@param player string + ---@return string? + local function getNationality(player) + local playerLink = Page.pageifyLink(player) + + local results = mw.ext.LiquipediaDB.lpdb('player', { + limit = 1, + conditions = tostring(ConditionNode(ColumnName('pagename'), Comparator.eq, playerLink)), + query = 'nationality', + })[1] or {} + + return results.nationality + end + + local pageName = tcArgs[prefix .. 'link'] or tcArgs[prefix] + return { [1] = tcArgs[prefix], - link = tcArgs[prefix .. 'link'], - flag = tcArgs[prefix .. 'flag_o'] or tcArgs[prefix .. 'flag'], + link = pageName, + flag = tcArgs[prefix .. 'flag_o'] or tcArgs[prefix .. 'flag'] or getNationality(pageName), team = tcArgs[prefix .. 'team'], id = tcArgs[prefix .. 'id'], number = tcArgs[prefix .. 'number'], From 6bedc75fead917fe8ec73a7e4d1dc6889cbd936a Mon Sep 17 00:00:00 2001 From: hjpalpha Date: Sun, 14 Jun 2026 13:09:11 +0200 Subject: [PATCH 2/4] kick unsued import --- lua/wikis/commons/TeamCard/Legacy.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/wikis/commons/TeamCard/Legacy.lua b/lua/wikis/commons/TeamCard/Legacy.lua index cb0987a6994..ca5df495edb 100644 --- a/lua/wikis/commons/TeamCard/Legacy.lua +++ b/lua/wikis/commons/TeamCard/Legacy.lua @@ -14,7 +14,6 @@ local Logic = Lua.import('Module:Logic') local Namespace = Lua.import('Module:Namespace') local Page = Lua.import('Module:Page') local PageVariableNamespace = Lua.import('Module:PageVariableNamespace') -local PlayerExt = Lua.import('Module:Player/Ext') local String = Lua.import('Module:StringUtils') local RoleUtil = Lua.import('Module:Role/Util') local Table = Lua.import('Module:Table') From d8f401ca31e16153e8b585e191a34d6d46fbe91c Mon Sep 17 00:00:00 2001 From: hjpalpha Date: Sun, 14 Jun 2026 13:15:19 +0200 Subject: [PATCH 3/4] spaces to tabs and shut up some anno warnings in tests --- lua/spec/teamcard_legacy_spec.lua | 1060 ++++++++++++++--------------- 1 file changed, 530 insertions(+), 530 deletions(-) diff --git a/lua/spec/teamcard_legacy_spec.lua b/lua/spec/teamcard_legacy_spec.lua index feaf66638fb..15ee240b993 100644 --- a/lua/spec/teamcard_legacy_spec.lua +++ b/lua/spec/teamcard_legacy_spec.lua @@ -18,7 +18,7 @@ describe('TeamCard Legacy', function() end) it('detects "invite" case-insensitively', function() - local q = LegacyTeamCard.parseQualifier('invite via league') + local q = LegacyTeamCard.parseQualifier('invite via league') or {} assert.are_equal('invite', q.method) assert.are_equal('other', q.type) assert.are_equal('invite via league', q.text) @@ -58,7 +58,7 @@ describe('TeamCard Legacy', function() it('handles relative internal link', function() local stubTournament = stub(require('Module:Tournament'), 'getTournament', function() return nil end) - local q = LegacyTeamCard.parseQualifier('[[/Qualifier|Qual]]') + local q = LegacyTeamCard.parseQualifier('[[/Qualifier|Qual]]') or {} assert.are_equal('internal', q.type) -- exact page resolved relative to current page; check it begins with the current page name assert.is_truthy(q.page) @@ -66,532 +66,532 @@ describe('TeamCard Legacy', function() end) end) - describe('mapPlayer basic mapping', function() - local LegacyTeamCard = require('Module:TeamCard/Legacy') - - it('reads display from positional', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'Faker'}, 'p1', nil) - assert.are_equal('Faker', p[1]) - end) - - it('reads link', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'Faker', p1link = 'Lee Sang-hyeok'}, 'p1', nil) - assert.are_equal('Lee Sang-hyeok', p.link) - end) - - it('reads flag', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'Faker', p1flag = 'kr'}, 'p1', nil) - assert.are_equal('kr', p.flag) - end) - - it('prefers flag_o over flag', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'Faker', p1flag = 'kr', p1flag_o = 'us'}, 'p1', nil) - assert.are_equal('us', p.flag) - end) - - it('reads team override', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1team = 'oldTeam'}, 'p1', nil) - assert.are_equal('oldTeam', p.team) - end) - - it('reads id', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1id = 'faker-id'}, 'p1', nil) - assert.are_equal('faker-id', p.id) - end) - - it('passes number through', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1number = '3'}, 'p1', nil) - assert.are_equal('3', p.number) - end) - - it('number nil when unset', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'X'}, 'p1', nil) - assert.is_nil(p.number) - end) - - it('reads faction', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1faction = 'p'}, 'p1', nil) - assert.are_equal('p', p.faction) - end) - - it('reads race as faction fallback', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1race = 'z'}, 'p1', nil) - assert.are_equal('z', p.faction) - end) - - it('reads pos as role', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1pos = 'top'}, 'p1', nil) - assert.are_equal('top', p.role) - end) - end) - - describe('mapPlayer status & trophies', function() - local LegacyTeamCard = require('Module:TeamCard/Legacy') - - it('sums wins and winsc into trophies', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1wins = '2', p1winsc = '1'}, 'p1', nil) - assert.are_equal(3, p.trophies) - end) - - it('trophies nil when neither set', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'X'}, 'p1', nil) - assert.is_nil(p.trophies) - end) - - it('passes joindate/leavedate through', function() - local p = LegacyTeamCard.mapPlayer( - {p1 = 'X', p1joindate = '2025-01-01', p1leavedate = '2025-12-01'}, 'p1', nil) - assert.are_equal('2025-01-01', p.joindate) - assert.are_equal('2025-12-01', p.leavedate) - end) - - it('reads played true', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1played = 'true'}, 'p1', nil) - assert.is_true(p.played) - end) - - it('reads result as played fallback', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1result = 'true'}, 'p1', nil) - assert.is_true(p.played) - end) - - it('dnp forces played=false even if result=true', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1result = 'true', p1dnp = 'true'}, 'p1', nil) - assert.is_false(p.played) - end) - - it('pNsub sets status=sub', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1sub = 'true'}, 'p1', nil) - assert.are_equal('sub', p.status) - end) - - it('pNleave sets status=former', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1leave = 'true'}, 'p1', nil) - assert.are_equal('former', p.status) - end) - - it('pNleave overrides pNsub', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1sub = 'true', p1leave = 'true'}, 'p1', nil) - assert.are_equal('former', p.status) - end) - - it('pNsub=true + pNdnp=true: status=sub and played=false', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1sub = 'true', p1dnp = 'true'}, 'p1', nil) - assert.are_equal('sub', p.status) - assert.is_false(p.played) - end) - - it('pNleave=true + pNdnp=true: status=former and played=false', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1leave = 'true', p1dnp = 'true'}, 'p1', nil) - assert.are_equal('former', p.status) - assert.is_false(p.played) - end) - end) - - describe('mapPlayer source groups', function() - local LegacyTeamCard = require('Module:TeamCard/Legacy') - - it('source group s sets status=sub', function() - local p = LegacyTeamCard.mapPlayer({s1 = 'X'}, 's1', 's') - assert.are_equal('sub', p.status) - end) - - it('source group f sets status=former', function() - local p = LegacyTeamCard.mapPlayer({f1 = 'X'}, 'f1', 'f') - assert.are_equal('former', p.status) - end) - - it('source group s + subdnpdefault sets played=false when no result', function() - local p = LegacyTeamCard.mapPlayer( - {s1 = 'X', subdnpdefault = 'true'}, 's1', 's') - assert.is_false(p.played) - assert.are_equal('sub', p.status) - end) - - it('source group s + subdnpdefault + explicit result keeps played=true', function() - local p = LegacyTeamCard.mapPlayer( - {s1 = 'X', s1result = 'true', subdnpdefault = 'true'}, 's1', 's') - assert.is_true(p.played) - end) - - it('main group with noVarDefault leaves played untouched', function() - local p = LegacyTeamCard.mapPlayer({p1 = 'X', noVarDefault = 'true'}, 'p1', nil) - assert.is_nil(p.played) - end) - - it('source group s with noVarDefault and no result sets played=false', function() - local p = LegacyTeamCard.mapPlayer({s1 = 'X', noVarDefault = 'true'}, 's1', 's') - assert.is_false(p.played) - end) - - it('source group f with noVarDefault leaves played untouched', function() - local p = LegacyTeamCard.mapPlayer({f1 = 'X', noVarDefault = 'true'}, 'f1', 'f') - assert.is_nil(p.played) - end) - - it('source group s + pNsub=true: status=sub (redundant, no conflict)', function() - local p = LegacyTeamCard.mapPlayer({s1 = 'X', s1sub = 'true'}, 's1', 's') - assert.are_equal('sub', p.status) - end) - end) - - describe('mapCoach', function() - local LegacyTeamCard = require('Module:TeamCard/Legacy') - - it('coach defaults role to coach', function() - local c = LegacyTeamCard.mapCoach({c1 = 'Score'}, 'c1', nil) - assert.are_equal('coach', c.role) - assert.are_equal('staff', c.type) - end) - - it('coach with cNpos overrides role', function() - local c = LegacyTeamCard.mapCoach({c1 = 'Score', c1pos = 'head coach'}, 'c1', nil) - assert.are_equal('head coach', c.role) - end) - - it('scN source group sets status=sub', function() - local c = LegacyTeamCard.mapCoach({sc1 = 'Mata'}, 'sc1', 'sc') - assert.are_equal('coach', c.role) - assert.are_equal('sub', c.status) - end) - - it('fcN source group sets status=former', function() - local c = LegacyTeamCard.mapCoach({fc1 = 'kkOma'}, 'fc1', 'fc') - assert.are_equal('coach', c.role) - assert.are_equal('former', c.status) - end) - - it('cNsub sets status=sub', function() - local c = LegacyTeamCard.mapCoach({c1 = 'X', c1sub = 'true'}, 'c1', nil) - assert.are_equal('sub', c.status) - end) - - it('wins+winsc sum to trophies', function() - local c = LegacyTeamCard.mapCoach({c1 = 'X', c1wins = '1', c1winsc = '2'}, 'c1', nil) - assert.are_equal(3, c.trophies) - end) - - it('flag_o wins over flag', function() - local c = LegacyTeamCard.mapCoach({c1 = 'X', c1flag = 'kr', c1flag_o = 'us'}, 'c1', nil) - assert.are_equal('us', c.flag) - end) - end) - - describe('mapPlayers enumeration', function() - local LegacyTeamCard = require('Module:TeamCard/Legacy') - - it('enumerates main players', function() - local players = LegacyTeamCard.mapPlayers({p1 = 'A', p2 = 'B', p3 = 'C'}) - assert.are_equal(3, #players) - assert.are_equal('A', players[1][1]) - assert.are_equal('B', players[2][1]) - end) - - it('appends sN players with status=sub', function() - local players = LegacyTeamCard.mapPlayers({p1 = 'A', s1 = 'B'}) - assert.are_equal(2, #players) - assert.is_nil(players[1].status) - assert.are_equal('sub', players[2].status) - end) - - it('appends fN players with status=former', function() - local players = LegacyTeamCard.mapPlayers({p1 = 'A', f1 = 'B'}) - assert.are_equal('former', players[2].status) - end) - - it('reads t2p* bucketed by t2type', function() - local players = LegacyTeamCard.mapPlayers({p1 = 'A', t2p1 = 'B', t2type = 'sub'}) - assert.are_equal('sub', players[2].status) - end) - - it('t2type=staff promotes t2p* to type=staff', function() - local players = LegacyTeamCard.mapPlayers({p1 = 'A', t2p1 = 'B', t2type = 'staff'}) - assert.are_equal('staff', players[2].type) - end) - - it('dedups t2p* against s* by pageName, t2p* wins', function() - local players = LegacyTeamCard.mapPlayers({ - p1 = 'Faker', - s1 = 'Pawn', s1link = 'Pawn (Korean)', - t2p1 = 'Pawn (player)', t2p1link = 'Pawn (Korean)', t2type = 'sub', - }) - local pawnCount = 0 - for _, p in ipairs(players) do - if p.link == 'Pawn (Korean)' then pawnCount = pawnCount + 1 end - end - assert.are_equal(1, pawnCount) - end) - - it('keeps both player and staff entries for the same person (staff tab)', function() - local players = LegacyTeamCard.mapPlayers({ - p1 = 'Dhokla', - t3p1 = 'Dhokla', t3p1pos = 'Positional Coach', t3title = 'Staff', - }) - assert.are_equal(2, #players) - assert.is_nil(players[1].type) - assert.is_nil(players[1].role) - assert.are_equal('staff', players[2].type) - assert.are_equal('Positional Coach', players[2].role) - end) - - it('keeps both entries when a staff role sits in a default former tab', function() - local players = LegacyTeamCard.mapPlayers({ - p1 = 'Dhokla', - t3p1 = 'Dhokla', t3p1pos = 'Positional Coach', - }) - assert.are_equal(2, #players) - assert.is_nil(players[1].role) - assert.are_equal('Positional Coach', players[2].role) - end) - - it('staff tab entry still dedups against an earlier staff tab entry', function() - local players = LegacyTeamCard.mapPlayers({ - t2p1 = 'Goldenglue', t2p1pos = 'Head Coach', t2title = 'Staff', - t3p1 = 'Goldenglue', t3p1pos = 'Strategic Coach', t3title = 'Staff', - }) - assert.are_equal(1, #players) - assert.are_equal('Strategic Coach', players[1].role) - end) - end) - - describe('mapCoaches enumeration', function() - local LegacyTeamCard = require('Module:TeamCard/Legacy') - - it('enumerates main coaches', function() - local coaches = LegacyTeamCard.mapCoaches({c1 = 'A', c2 = 'B'}) - assert.are_equal(2, #coaches) - assert.are_equal('coach', coaches[1].role) - assert.are_equal('coach', coaches[2].role) - end) - - it('appends scN as sub coaches', function() - local coaches = LegacyTeamCard.mapCoaches({c1 = 'A', sc1 = 'B'}) - assert.are_equal('sub', coaches[2].status) - end) - - it('reads t2c* with t2type', function() - local coaches = LegacyTeamCard.mapCoaches({c1 = 'A', t2c1 = 'B', t2type = 'former'}) - assert.are_equal('former', coaches[2].status) - end) - end) - - describe('mapCard', function() - local LegacyTeamCard = require('Module:TeamCard/Legacy') - - it('uses link over team for template', function() - local card = LegacyTeamCard.mapCard({team = 'Display', link = 'Real Team'}) - assert.are_equal('Real Team', card[1]) - end) - - it('falls back to team if no link', function() - local card = LegacyTeamCard.mapCard({team = 'Solo Team'}) - assert.are_equal('Solo Team', card[1]) - end) - - it('team2/team3 populate contenders with all three teams', function() - local card = LegacyTeamCard.mapCard({ - team = 'A', team2 = 'B', team3 = 'C', - }) - assert.is_nil(card[1]) - assert.are_same({'A', 'B', 'C'}, card.contenders) - end) - - it('contender uses link if present', function() - local card = LegacyTeamCard.mapCard({ - team = 'A', link = 'AReal', - team2 = 'B', link2 = 'BReal', - }) - assert.are_same({'AReal', 'BReal'}, card.contenders) - end) - - it('qualification built from qualifier', function() - local card = LegacyTeamCard.mapCard({team = 'A', qualifier = 'Invited'}) - assert.are_equal('invite', card.qualification.method) - end) - - it('notes and inotes both populate notes list', function() - local card = LegacyTeamCard.mapCard({team = 'A', notes = 'note A', inotes = 'note B'}) - assert.are_equal(2, #card.notes) - assert.are_equal('note A', card.notes[1][1]) - assert.are_equal('note B', card.notes[2][1]) - end) - - it('aliases reads alsoknownas first then aliases', function() - assert.are_equal('foo;bar', - LegacyTeamCard.mapCard({team = 'A', alsoknownas = 'foo;bar', aliases = 'wrong'}).aliases) - assert.are_equal('only-aliases', - LegacyTeamCard.mapCard({team = 'A', aliases = 'only-aliases'}).aliases) - end) - - it('combines players and coaches into one list', function() - local card = LegacyTeamCard.mapCard({team = 'A', p1 = 'P', c1 = 'C'}) - assert.are_equal('P', card.players[1][1]) - assert.are_equal('C', card.players[2][1]) - assert.are_equal('staff', card.players[2].type) - end) - - it('sets import=false unconditionally', function() - local card = LegacyTeamCard.mapCard({team = 'A', import = 'true'}) - assert.is_false(card.import) - end) - end) - - describe('toggle folding', function() - local LegacyTeamCard = require('Module:TeamCard/Legacy') - - it('folds zero toggles to defaults', function() - local f = LegacyTeamCard._foldToggles({}) - assert.is_false(f.showPlayerInfo) - assert.are_equal(0, f.extraPlayers) - assert.are_same({}, f.notes) - end) - - it('playerinfo=true sets showPlayerInfo', function() - local f = LegacyTeamCard._foldToggles({{playerinfo = 'true'}}) - assert.is_true(f.showPlayerInfo) - end) - - it('sums p_extra', function() - local f = LegacyTeamCard._foldToggles({{p_extra = '2'}, {p_extra = '3'}}) - assert.are_equal(5, f.extraPlayers) - end) - - it('collects notes in order, skipping empty', function() - local f = LegacyTeamCard._foldToggles({{note = 'first'}, {note = ''}, {note = 'second'}}) - assert.are_same({'first', 'second'}, f.notes) - end) - end) - - describe('run — partition and malformed', function() - local Template = require('Module:Template') - local LegacyTeamCard = require('Module:TeamCard/Legacy') - - local function stashAll(entries) - for _, e in ipairs(entries) do - Template.stashReturnValue(e, 'LegacyTeamCard') - end - end - - it('with no stash, returns empty render without error', function() - local out = LegacyTeamCard.run() - assert.is_truthy(out) - end) - - it('with malformed structure (no header, just cards), adds tracking category and renders', function() - local TPParser = require('Module:TeamParticipants/Parse/Wiki') - local stubParseMalformed = stub(TPParser, 'parseWikiInput', function() - return {participants = {}} - end) - local addCategory = stub(mw.ext.TeamLiquidIntegration, 'add_category', function() end) - stashAll({ - {team = 'A', __source = 'card'}, - {team = 'B', __source = 'card'}, - }) - local out = LegacyTeamCard.run() - assert.is_truthy(out) - assert.stub(addCategory).was.called_with('Pages with malformed Legacy TeamCard structure') - addCategory:revert() - stubParseMalformed:revert() - end) - end) - - describe('run — render and post-render side effects', function() - local Template = require('Module:Template') - local LegacyTeamCard = require('Module:TeamCard/Legacy') - - it('passes minimumplayers = defaultRowNumber + extraRows + sum(p_extra)', function() - local TPParser = require('Module:TeamParticipants/Parse/Wiki') - local captured - local stubParse = stub(TPParser, 'parseWikiInput', function(args) - captured = args - return {participants = {}, expectedPlayerCount = tonumber(args.minimumplayers)} - end) - - Template.stashReturnValue({__source = 'header'}, 'LegacyTeamCard') - Template.stashReturnValue({__source = 'toggle', p_extra = '2'}, 'LegacyTeamCard') - Template.stashReturnValue( - {__source = 'card', team = 'A', defaultRowNumber = '5', extraRows = '1'}, 'LegacyTeamCard') - - LegacyTeamCard.run() - assert.are_equal('8', tostring(captured.minimumplayers)) - - stubParse:revert() - end) - - end) - - describe('run — preprocessCard hook', function() - local Template = require('Module:Template') - local LegacyTeamCard = require('Module:TeamCard/Legacy') - - it('applies preprocessCard to each card before mapping', function() - local TPParser = require('Module:TeamParticipants/Parse/Wiki') - local captured - local stubParse = stub(TPParser, 'parseWikiInput', function(args) - captured = args - return {participants = {}, expectedPlayerCount = 0} - end) - - Template.stashReturnValue({__source = 'header'}, 'LegacyTeamCard') - Template.stashReturnValue({__source = 'card', sub1 = 'X'}, 'LegacyTeamCard') - - LegacyTeamCard.run({ - preprocessCard = function(card) - if card.sub1 then card.p1 = card.sub1; card.p1sub = 'true'; card.sub1 = nil end - return card - end, - }) - - -- The first opponent in captured should now have p1='X' as a sub-status player. - assert.are_equal('X', captured[1].players[1][1]) - assert.are_equal('sub', captured[1].players[1].status) - - stubParse:revert() - end) - - end) - - describe('integration', function() - it('renders a representative legacy block via Module:Template stash', function() - local TeamTemplateMock = require('wikis.commons.Mock.TeamTemplate') - TeamTemplateMock.setUp() - local LpdbQuery = stub(mw.ext.LiquipediaDB, 'lpdb', function() return {} end) - local LpdbPlacementStore = stub(mw.ext.LiquipediaDB, 'lpdb_placement', function() end) - - local Template = require('Module:Template') - local LegacyTeamCard = require('Module:TeamCard/Legacy') - - Template.stashReturnValue({__source = 'toggle', playerinfo = 'true', p_extra = '1'}, 'LegacyTeamCard') - Template.stashReturnValue({__source = 'header', cols = '4'}, 'LegacyTeamCard') - Template.stashReturnValue({ - __source = 'card', - team = 'Team Liquid', - defaultRowNumber = '5', - subdnpdefault = 'true', - p1 = 'alexis', - p2 = 'dodonut', - p3 = 'meL', - p4 = 'Noia', - p5 = 'sarah', - s1 = 'sub-player', s1result = 'true', - c1 = 'Coach Name', - qualifier = 'Invited', - }, 'LegacyTeamCard') - Template.stashReturnValue({ - __source = 'card', - team = 'mouz', - team2 = 'TBD', - team3 = 'bds', - defaultRowNumber = '5', - qualifier = '[[Qualifier/2025|Qualifier]]', - }, 'LegacyTeamCard') - - GoldenTest('teamcard_legacy', tostring(LegacyTeamCard.run()), - [[]]) - - LpdbQuery:revert() - LpdbPlacementStore:revert() - TeamTemplateMock.tearDown() - end) - end) + describe('mapPlayer basic mapping', function() + local LegacyTeamCard = require('Module:TeamCard/Legacy') + + it('reads display from positional', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'Faker'}, 'p1', nil) + assert.are_equal('Faker', p[1]) + end) + + it('reads link', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'Faker', p1link = 'Lee Sang-hyeok'}, 'p1', nil) + assert.are_equal('Lee Sang-hyeok', p.link) + end) + + it('reads flag', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'Faker', p1flag = 'kr'}, 'p1', nil) + assert.are_equal('kr', p.flag) + end) + + it('prefers flag_o over flag', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'Faker', p1flag = 'kr', p1flag_o = 'us'}, 'p1', nil) + assert.are_equal('us', p.flag) + end) + + it('reads team override', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1team = 'oldTeam'}, 'p1', nil) + assert.are_equal('oldTeam', p.team) + end) + + it('reads id', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1id = 'faker-id'}, 'p1', nil) + assert.are_equal('faker-id', p.id) + end) + + it('passes number through', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1number = '3'}, 'p1', nil) + assert.are_equal('3', p.number) + end) + + it('number nil when unset', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'X'}, 'p1', nil) + assert.is_nil(p.number) + end) + + it('reads faction', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1faction = 'p'}, 'p1', nil) + assert.are_equal('p', p.faction) + end) + + it('reads race as faction fallback', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1race = 'z'}, 'p1', nil) + assert.are_equal('z', p.faction) + end) + + it('reads pos as role', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1pos = 'top'}, 'p1', nil) + assert.are_equal('top', p.role) + end) + end) + + describe('mapPlayer status & trophies', function() + local LegacyTeamCard = require('Module:TeamCard/Legacy') + + it('sums wins and winsc into trophies', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1wins = '2', p1winsc = '1'}, 'p1', nil) + assert.are_equal(3, p.trophies) + end) + + it('trophies nil when neither set', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'X'}, 'p1', nil) + assert.is_nil(p.trophies) + end) + + it('passes joindate/leavedate through', function() + local p = LegacyTeamCard.mapPlayer( + {p1 = 'X', p1joindate = '2025-01-01', p1leavedate = '2025-12-01'}, 'p1', nil) + assert.are_equal('2025-01-01', p.joindate) + assert.are_equal('2025-12-01', p.leavedate) + end) + + it('reads played true', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1played = 'true'}, 'p1', nil) + assert.is_true(p.played) + end) + + it('reads result as played fallback', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1result = 'true'}, 'p1', nil) + assert.is_true(p.played) + end) + + it('dnp forces played=false even if result=true', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1result = 'true', p1dnp = 'true'}, 'p1', nil) + assert.is_false(p.played) + end) + + it('pNsub sets status=sub', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1sub = 'true'}, 'p1', nil) + assert.are_equal('sub', p.status) + end) + + it('pNleave sets status=former', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1leave = 'true'}, 'p1', nil) + assert.are_equal('former', p.status) + end) + + it('pNleave overrides pNsub', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1sub = 'true', p1leave = 'true'}, 'p1', nil) + assert.are_equal('former', p.status) + end) + + it('pNsub=true + pNdnp=true: status=sub and played=false', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1sub = 'true', p1dnp = 'true'}, 'p1', nil) + assert.are_equal('sub', p.status) + assert.is_false(p.played) + end) + + it('pNleave=true + pNdnp=true: status=former and played=false', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'X', p1leave = 'true', p1dnp = 'true'}, 'p1', nil) + assert.are_equal('former', p.status) + assert.is_false(p.played) + end) + end) + + describe('mapPlayer source groups', function() + local LegacyTeamCard = require('Module:TeamCard/Legacy') + + it('source group s sets status=sub', function() + local p = LegacyTeamCard.mapPlayer({s1 = 'X'}, 's1', 's') + assert.are_equal('sub', p.status) + end) + + it('source group f sets status=former', function() + local p = LegacyTeamCard.mapPlayer({f1 = 'X'}, 'f1', 'f') + assert.are_equal('former', p.status) + end) + + it('source group s + subdnpdefault sets played=false when no result', function() + local p = LegacyTeamCard.mapPlayer( + {s1 = 'X', subdnpdefault = 'true'}, 's1', 's') + assert.is_false(p.played) + assert.are_equal('sub', p.status) + end) + + it('source group s + subdnpdefault + explicit result keeps played=true', function() + local p = LegacyTeamCard.mapPlayer( + {s1 = 'X', s1result = 'true', subdnpdefault = 'true'}, 's1', 's') + assert.is_true(p.played) + end) + + it('main group with noVarDefault leaves played untouched', function() + local p = LegacyTeamCard.mapPlayer({p1 = 'X', noVarDefault = 'true'}, 'p1', nil) + assert.is_nil(p.played) + end) + + it('source group s with noVarDefault and no result sets played=false', function() + local p = LegacyTeamCard.mapPlayer({s1 = 'X', noVarDefault = 'true'}, 's1', 's') + assert.is_false(p.played) + end) + + it('source group f with noVarDefault leaves played untouched', function() + local p = LegacyTeamCard.mapPlayer({f1 = 'X', noVarDefault = 'true'}, 'f1', 'f') + assert.is_nil(p.played) + end) + + it('source group s + pNsub=true: status=sub (redundant, no conflict)', function() + local p = LegacyTeamCard.mapPlayer({s1 = 'X', s1sub = 'true'}, 's1', 's') + assert.are_equal('sub', p.status) + end) + end) + + describe('mapCoach', function() + local LegacyTeamCard = require('Module:TeamCard/Legacy') + + it('coach defaults role to coach', function() + local c = LegacyTeamCard.mapCoach({c1 = 'Score'}, 'c1', nil) + assert.are_equal('coach', c.role) + assert.are_equal('staff', c.type) + end) + + it('coach with cNpos overrides role', function() + local c = LegacyTeamCard.mapCoach({c1 = 'Score', c1pos = 'head coach'}, 'c1', nil) + assert.are_equal('head coach', c.role) + end) + + it('scN source group sets status=sub', function() + local c = LegacyTeamCard.mapCoach({sc1 = 'Mata'}, 'sc1', 'sc') + assert.are_equal('coach', c.role) + assert.are_equal('sub', c.status) + end) + + it('fcN source group sets status=former', function() + local c = LegacyTeamCard.mapCoach({fc1 = 'kkOma'}, 'fc1', 'fc') + assert.are_equal('coach', c.role) + assert.are_equal('former', c.status) + end) + + it('cNsub sets status=sub', function() + local c = LegacyTeamCard.mapCoach({c1 = 'X', c1sub = 'true'}, 'c1', nil) + assert.are_equal('sub', c.status) + end) + + it('wins+winsc sum to trophies', function() + local c = LegacyTeamCard.mapCoach({c1 = 'X', c1wins = '1', c1winsc = '2'}, 'c1', nil) + assert.are_equal(3, c.trophies) + end) + + it('flag_o wins over flag', function() + local c = LegacyTeamCard.mapCoach({c1 = 'X', c1flag = 'kr', c1flag_o = 'us'}, 'c1', nil) + assert.are_equal('us', c.flag) + end) + end) + + describe('mapPlayers enumeration', function() + local LegacyTeamCard = require('Module:TeamCard/Legacy') + + it('enumerates main players', function() + local players = LegacyTeamCard.mapPlayers({p1 = 'A', p2 = 'B', p3 = 'C'}) + assert.are_equal(3, #players) + assert.are_equal('A', players[1][1]) + assert.are_equal('B', players[2][1]) + end) + + it('appends sN players with status=sub', function() + local players = LegacyTeamCard.mapPlayers({p1 = 'A', s1 = 'B'}) + assert.are_equal(2, #players) + assert.is_nil(players[1].status) + assert.are_equal('sub', players[2].status) + end) + + it('appends fN players with status=former', function() + local players = LegacyTeamCard.mapPlayers({p1 = 'A', f1 = 'B'}) + assert.are_equal('former', players[2].status) + end) + + it('reads t2p* bucketed by t2type', function() + local players = LegacyTeamCard.mapPlayers({p1 = 'A', t2p1 = 'B', t2type = 'sub'}) + assert.are_equal('sub', players[2].status) + end) + + it('t2type=staff promotes t2p* to type=staff', function() + local players = LegacyTeamCard.mapPlayers({p1 = 'A', t2p1 = 'B', t2type = 'staff'}) + assert.are_equal('staff', players[2].type) + end) + + it('dedups t2p* against s* by pageName, t2p* wins', function() + local players = LegacyTeamCard.mapPlayers({ + p1 = 'Faker', + s1 = 'Pawn', s1link = 'Pawn (Korean)', + t2p1 = 'Pawn (player)', t2p1link = 'Pawn (Korean)', t2type = 'sub', + }) + local pawnCount = 0 + for _, p in ipairs(players) do + if p.link == 'Pawn (Korean)' then pawnCount = pawnCount + 1 end + end + assert.are_equal(1, pawnCount) + end) + + it('keeps both player and staff entries for the same person (staff tab)', function() + local players = LegacyTeamCard.mapPlayers({ + p1 = 'Dhokla', + t3p1 = 'Dhokla', t3p1pos = 'Positional Coach', t3title = 'Staff', + }) + assert.are_equal(2, #players) + assert.is_nil(players[1].type) + assert.is_nil(players[1].role) + assert.are_equal('staff', players[2].type) + assert.are_equal('Positional Coach', players[2].role) + end) + + it('keeps both entries when a staff role sits in a default former tab', function() + local players = LegacyTeamCard.mapPlayers({ + p1 = 'Dhokla', + t3p1 = 'Dhokla', t3p1pos = 'Positional Coach', + }) + assert.are_equal(2, #players) + assert.is_nil(players[1].role) + assert.are_equal('Positional Coach', players[2].role) + end) + + it('staff tab entry still dedups against an earlier staff tab entry', function() + local players = LegacyTeamCard.mapPlayers({ + t2p1 = 'Goldenglue', t2p1pos = 'Head Coach', t2title = 'Staff', + t3p1 = 'Goldenglue', t3p1pos = 'Strategic Coach', t3title = 'Staff', + }) + assert.are_equal(1, #players) + assert.are_equal('Strategic Coach', players[1].role) + end) + end) + + describe('mapCoaches enumeration', function() + local LegacyTeamCard = require('Module:TeamCard/Legacy') + + it('enumerates main coaches', function() + local coaches = LegacyTeamCard.mapCoaches({c1 = 'A', c2 = 'B'}) + assert.are_equal(2, #coaches) + assert.are_equal('coach', coaches[1].role) + assert.are_equal('coach', coaches[2].role) + end) + + it('appends scN as sub coaches', function() + local coaches = LegacyTeamCard.mapCoaches({c1 = 'A', sc1 = 'B'}) + assert.are_equal('sub', coaches[2].status) + end) + + it('reads t2c* with t2type', function() + local coaches = LegacyTeamCard.mapCoaches({c1 = 'A', t2c1 = 'B', t2type = 'former'}) + assert.are_equal('former', coaches[2].status) + end) + end) + + describe('mapCard', function() + local LegacyTeamCard = require('Module:TeamCard/Legacy') + + it('uses link over team for template', function() + local card = LegacyTeamCard.mapCard({team = 'Display', link = 'Real Team'}) + assert.are_equal('Real Team', card[1]) + end) + + it('falls back to team if no link', function() + local card = LegacyTeamCard.mapCard({team = 'Solo Team'}) + assert.are_equal('Solo Team', card[1]) + end) + + it('team2/team3 populate contenders with all three teams', function() + local card = LegacyTeamCard.mapCard({ + team = 'A', team2 = 'B', team3 = 'C', + }) + assert.is_nil(card[1]) + assert.are_same({'A', 'B', 'C'}, card.contenders) + end) + + it('contender uses link if present', function() + local card = LegacyTeamCard.mapCard({ + team = 'A', link = 'AReal', + team2 = 'B', link2 = 'BReal', + }) + assert.are_same({'AReal', 'BReal'}, card.contenders) + end) + + it('qualification built from qualifier', function() + local card = LegacyTeamCard.mapCard({team = 'A', qualifier = 'Invited'}) + assert.are_equal('invite', card.qualification.method) + end) + + it('notes and inotes both populate notes list', function() + local card = LegacyTeamCard.mapCard({team = 'A', notes = 'note A', inotes = 'note B'}) + assert.are_equal(2, #card.notes) + assert.are_equal('note A', card.notes[1][1]) + assert.are_equal('note B', card.notes[2][1]) + end) + + it('aliases reads alsoknownas first then aliases', function() + assert.are_equal('foo;bar', + LegacyTeamCard.mapCard({team = 'A', alsoknownas = 'foo;bar', aliases = 'wrong'}).aliases) + assert.are_equal('only-aliases', + LegacyTeamCard.mapCard({team = 'A', aliases = 'only-aliases'}).aliases) + end) + + it('combines players and coaches into one list', function() + local card = LegacyTeamCard.mapCard({team = 'A', p1 = 'P', c1 = 'C'}) + assert.are_equal('P', card.players[1][1]) + assert.are_equal('C', card.players[2][1]) + assert.are_equal('staff', card.players[2].type) + end) + + it('sets import=false unconditionally', function() + local card = LegacyTeamCard.mapCard({team = 'A', import = 'true'}) + assert.is_false(card.import) + end) + end) + + describe('toggle folding', function() + local LegacyTeamCard = require('Module:TeamCard/Legacy') + + it('folds zero toggles to defaults', function() + local f = LegacyTeamCard._foldToggles({}) + assert.is_false(f.showPlayerInfo) + assert.are_equal(0, f.extraPlayers) + assert.are_same({}, f.notes) + end) + + it('playerinfo=true sets showPlayerInfo', function() + local f = LegacyTeamCard._foldToggles({{playerinfo = 'true'}}) + assert.is_true(f.showPlayerInfo) + end) + + it('sums p_extra', function() + local f = LegacyTeamCard._foldToggles({{p_extra = '2'}, {p_extra = '3'}}) + assert.are_equal(5, f.extraPlayers) + end) + + it('collects notes in order, skipping empty', function() + local f = LegacyTeamCard._foldToggles({{note = 'first'}, {note = ''}, {note = 'second'}}) + assert.are_same({'first', 'second'}, f.notes) + end) + end) + + describe('run — partition and malformed', function() + local Template = require('Module:Template') + local LegacyTeamCard = require('Module:TeamCard/Legacy') + + local function stashAll(entries) + for _, e in ipairs(entries) do + Template.stashReturnValue(e, 'LegacyTeamCard') + end + end + + it('with no stash, returns empty render without error', function() + local out = LegacyTeamCard.run() + assert.is_truthy(out) + end) + + it('with malformed structure (no header, just cards), adds tracking category and renders', function() + local TPParser = require('Module:TeamParticipants/Parse/Wiki') + local stubParseMalformed = stub(TPParser, 'parseWikiInput', function() + return {participants = {}} + end) + local addCategory = stub(mw.ext.TeamLiquidIntegration, 'add_category', function() end) + stashAll({ + {team = 'A', __source = 'card'}, + {team = 'B', __source = 'card'}, + }) + local out = LegacyTeamCard.run() + assert.is_truthy(out) + assert.stub(addCategory).was.called_with('Pages with malformed Legacy TeamCard structure') + addCategory:revert() + stubParseMalformed:revert() + end) + end) + + describe('run — render and post-render side effects', function() + local Template = require('Module:Template') + local LegacyTeamCard = require('Module:TeamCard/Legacy') + + it('passes minimumplayers = defaultRowNumber + extraRows + sum(p_extra)', function() + local TPParser = require('Module:TeamParticipants/Parse/Wiki') + local captured + local stubParse = stub(TPParser, 'parseWikiInput', function(args) + captured = args + return {participants = {}, expectedPlayerCount = tonumber(args.minimumplayers)} + end) + + Template.stashReturnValue({__source = 'header'}, 'LegacyTeamCard') + Template.stashReturnValue({__source = 'toggle', p_extra = '2'}, 'LegacyTeamCard') + Template.stashReturnValue( + {__source = 'card', team = 'A', defaultRowNumber = '5', extraRows = '1'}, 'LegacyTeamCard') + + LegacyTeamCard.run() + assert.are_equal('8', tostring(captured.minimumplayers)) + + stubParse:revert() + end) + + end) + + describe('run — preprocessCard hook', function() + local Template = require('Module:Template') + local LegacyTeamCard = require('Module:TeamCard/Legacy') + + it('applies preprocessCard to each card before mapping', function() + local TPParser = require('Module:TeamParticipants/Parse/Wiki') + local captured + local stubParse = stub(TPParser, 'parseWikiInput', function(args) + captured = args + return {participants = {}, expectedPlayerCount = 0} + end) + + Template.stashReturnValue({__source = 'header'}, 'LegacyTeamCard') + Template.stashReturnValue({__source = 'card', sub1 = 'X'}, 'LegacyTeamCard') + + LegacyTeamCard.run({ + preprocessCard = function(card) + if card.sub1 then card.p1 = card.sub1; card.p1sub = 'true'; card.sub1 = nil end + return card + end, + }) + + -- The first opponent in captured should now have p1='X' as a sub-status player. + assert.are_equal('X', captured[1].players[1][1]) + assert.are_equal('sub', captured[1].players[1].status) + + stubParse:revert() + end) + + end) + + describe('integration', function() + it('renders a representative legacy block via Module:Template stash', function() + local TeamTemplateMock = require('wikis.commons.Mock.TeamTemplate') + TeamTemplateMock.setUp() + local LpdbQuery = stub(mw.ext.LiquipediaDB, 'lpdb', function() return {} end) + local LpdbPlacementStore = stub(mw.ext.LiquipediaDB, 'lpdb_placement', function() end) + + local Template = require('Module:Template') + local LegacyTeamCard = require('Module:TeamCard/Legacy') + + Template.stashReturnValue({__source = 'toggle', playerinfo = 'true', p_extra = '1'}, 'LegacyTeamCard') + Template.stashReturnValue({__source = 'header', cols = '4'}, 'LegacyTeamCard') + Template.stashReturnValue({ + __source = 'card', + team = 'Team Liquid', + defaultRowNumber = '5', + subdnpdefault = 'true', + p1 = 'alexis', + p2 = 'dodonut', + p3 = 'meL', + p4 = 'Noia', + p5 = 'sarah', + s1 = 'sub-player', s1result = 'true', + c1 = 'Coach Name', + qualifier = 'Invited', + }, 'LegacyTeamCard') + Template.stashReturnValue({ + __source = 'card', + team = 'mouz', + team2 = 'TBD', + team3 = 'bds', + defaultRowNumber = '5', + qualifier = '[[Qualifier/2025|Qualifier]]', + }, 'LegacyTeamCard') + + GoldenTest('teamcard_legacy', tostring(LegacyTeamCard.run()), + [[]]) + + LpdbQuery:revert() + LpdbPlacementStore:revert() + TeamTemplateMock.tearDown() + end) + end) end) From 3b3f788e736138c5768fb4f73b1bb9c4154d5919 Mon Sep 17 00:00:00 2001 From: hjpalpha Date: Sun, 14 Jun 2026 13:29:26 +0200 Subject: [PATCH 4/4] set up lpdb fake for the test not to error --- lua/spec/teamcard_legacy_spec.lua | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lua/spec/teamcard_legacy_spec.lua b/lua/spec/teamcard_legacy_spec.lua index 15ee240b993..3f21843666f 100644 --- a/lua/spec/teamcard_legacy_spec.lua +++ b/lua/spec/teamcard_legacy_spec.lua @@ -1,5 +1,14 @@ --- Triple Comment to Enable our LLS Plugin describe('TeamCard Legacy', function() + before_each(function() + stub(mw.ext.LiquipediaDB, "lpdb", {}) + end) + + after_each(function () + ---@diagnostic disable-next-line: undefined-field + mw.ext.LiquipediaDB.lpdb:revert() + end) + describe('parseQualifier', function() local LegacyTeamCard = require('Module:TeamCard/Legacy')