From d6ddf23f976de5e37e2d0e3d0b2c2e4831a57eae Mon Sep 17 00:00:00 2001 From: thibautbus <310327033+thibautbus@users.noreply.github.com> Date: Sun, 16 Aug 2026 21:30:52 +0200 Subject: [PATCH] Add targeted coverage for the stat-rise message translation fix No existing test could tell a translated stat name apart from a raw stat:upper() that never went through Strings() at all: every rose! message assertion in the suite runs with no catalog loaded, where Strings() is an identity function either way. Loads a real catalog (Strings.load) that translates one stat name at a time and checks it actually reaches the X-item, vitamin, and AI-trainer X-item messages -- ROM-free, over tests/fixture_data. Confirmed this catches the regression: reverting src/inventory/ItemEffects.lua and src/battle/TrainerAI.lua to their pre-fix state fails 5 of 6 checks. --- .../stat_rise_message_translation_test.lua | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 tests/engine/stat_rise_message_translation_test.lua diff --git a/tests/engine/stat_rise_message_translation_test.lua b/tests/engine/stat_rise_message_translation_test.lua new file mode 100644 index 00000000..5b8ff08c --- /dev/null +++ b/tests/engine/stat_rise_message_translation_test.lua @@ -0,0 +1,73 @@ +-- The stat name substituted into X-item/vitamin "rose!" messages must +-- itself reach a translation catalog, not just the surrounding sentence +-- template (src/inventory/ItemEffects.lua, src/battle/TrainerAI.lua). +-- With no catalog loaded it stays English (the existing baseline); with +-- one loaded that translates e.g. "ATTACK", the substituted word must +-- change too -- that is the actual bug this suite guards against, which +-- passing/failing sentences alone (as other suites already check) +-- cannot tell apart from a raw stat:upper() that was never wrapped in +-- Strings() at all. +package.path = "./?.lua;./?/init.lua;" .. package.path + +local T = require("tests.modkit") +local Data = T.fixtures.fresh() +local Pokemon = require("src.pokemon.Pokemon") +local SaveData = require("src.core.SaveData") +local ItemEffects = require("src.inventory.ItemEffects") +local TrainerAI = require("src.battle.TrainerAI") +local Strings = require("src.core.Strings") + +local function withCatalog(catalog, fn) + Strings.load({ strings = catalog }) + local ok, err = pcall(fn) + Strings.load(nil) + if not ok then error(err, 0) end +end + +-- ------------------------------------------------------- player X-item + +local save = SaveData.newGame() +local player = { name = "FIXMON", stages = {} } +local xBattle = { player = player, kind = "wild" } + +local _, baseline = ItemEffects.use(Data, save, "X_ATTACK", nil, xBattle) +T.check(baseline[1]:find("ATTACK", 1, true) ~= nil, + "X ATTACK's rose! message names the stat in English with no catalog") + +withCatalog({ ATTACK = "ATTAQUE" }, function() + player.stages.attack = nil + local _, msgs = ItemEffects.use(Data, save, "X_ATTACK", nil, xBattle) + T.check(msgs[1]:find("ATTAQUE", 1, true) ~= nil, + "a catalog translating ATTACK reaches the X ATTACK rose! message") + T.check(msgs[1]:find("ATTACK", 1, true) == nil, + "...and the untranslated English stat name is gone") +end) + +-- --------------------------------------------------------- player vitamin + +local target = Pokemon.new(Data, "FIXMON_A", 10) +withCatalog({ DEFENSE = "DEFENSE_FR" }, function() + local _, msgs = ItemEffects.use(Data, save, "IRON", target) + T.check(msgs[1]:find("DEFENSE_FR", 1, true) ~= nil, + "a catalog translating DEFENSE reaches the IRON (vitamin) rose! message") +end) + +local hpTarget = Pokemon.new(Data, "FIXMON_A", 10) +withCatalog({ HP = "PV" }, function() + local _, msgs = ItemEffects.use(Data, save, "HP_UP", hpTarget) + T.check(msgs[1]:find("PV", 1, true) ~= nil, + "a catalog translating HP reaches the HP UP rose! message") +end) + +-- ------------------------------------------------------- AI trainer X-item + +local enemy = { name = "FOE", stages = {} } +local aiBattle = { enemy = enemy, trainer = { name = "TRAINER" }, data = Data } + +withCatalog({ SPEED = "VITESSE" }, function() + local msgs = TrainerAI.useItem(aiBattle, "X_SPEED") + T.check(msgs[2]:find("VITESSE", 1, true) ~= nil, + "a catalog translating SPEED reaches the AI trainer's X SPEED rose! message") +end) + +T.finish("stat rise message translation")