From 44c0fcea45b748fd6e7f459b4594a206ade9fd50 Mon Sep 17 00:00:00 2001 From: lex Date: Fri, 10 Jul 2026 22:54:39 +0300 Subject: [PATCH] Fix debug test suite for Factorio 2.0 Two long-standing failures in the in-game test runner: - The Gui top-button toggle test counted all children of the gui roots, but GUIs like the production hud hide their screen frame on close to preserve its position rather than destroying it. Count only visible elements so hide-on-close toggles pass. - Helper.modify_lua_object rawset fields on LuaObjects, which worked in Factorio 1.1 where they were tables but errors since 2.0 where they are userdata. Add Helper.fake_lua_object (a table that reads and writes through to the wrapped object except for overridden fields) and Helper.modify_global (replaces e.g. the game global until teardown), and migrate the death corpse tags, restart command and landfill remover tests to them. Co-Authored-By: Claude Fable 5 --- features/death_corpse_tags_tests.lua | 18 ++++++++------ features/landfill_remover_tests.lua | 36 +++++++++++++++++----------- features/restart_command_tests.lua | 30 +++++++++++++---------- utils/gui_tests.lua | 16 ++++++++++--- utils/test/helper.lua | 28 ++++++++++++++++++++++ 5 files changed, 92 insertions(+), 36 deletions(-) diff --git a/features/death_corpse_tags_tests.lua b/features/death_corpse_tags_tests.lua index 0ce7f81fa..d2f830182 100644 --- a/features/death_corpse_tags_tests.lua +++ b/features/death_corpse_tags_tests.lua @@ -69,13 +69,17 @@ Declare.module({'features', 'death_corpse_tags'}, function() local actual_text - Helper.modify_lua_object(context, player, 'print', function(text) - actual_text = text - end) - - Helper.modify_lua_object(context, game, 'get_player', function() - return player - end) + local fake_player = Helper.fake_lua_object(player, { + print = function(text) + actual_text = text + end + }) + + Helper.modify_global(context, 'game', Helper.fake_lua_object(game, { + get_player = function() + return fake_player + end + })) local event = fake_death(player, false) diff --git a/features/landfill_remover_tests.lua b/features/landfill_remover_tests.lua index 45716c23c..14286085e 100644 --- a/features/landfill_remover_tests.lua +++ b/features/landfill_remover_tests.lua @@ -727,13 +727,17 @@ Declare.module( local messages = {} - Helper.modify_lua_object(context, player, 'print', function(text) - messages[#messages+1] = text - end) - - Helper.modify_lua_object(context, game, 'get_player', function() - return player - end) + local fake_player = Helper.fake_lua_object(player, { + print = function(text) + messages[#messages+1] = text + end + }) + + Helper.modify_global(context, 'game', Helper.fake_lua_object(game, { + get_player = function() + return fake_player + end + })) -- Act EventFactory.do_player_deconstruct_area(cursor, player, area) @@ -765,13 +769,17 @@ Declare.module( local messages = {} - Helper.modify_lua_object(context, player, 'print', function(text) - messages[#messages+1] = text - end) - - Helper.modify_lua_object(context, game, 'get_player', function() - return player - end) + local fake_player = Helper.fake_lua_object(player, { + print = function(text) + messages[#messages+1] = text + end + }) + + Helper.modify_global(context, 'game', Helper.fake_lua_object(game, { + get_player = function() + return fake_player + end + })) -- Act EventFactory.do_player_deconstruct_area(cursor, player, area) diff --git a/features/restart_command_tests.lua b/features/restart_command_tests.lua index b3150d12c..9958fbf0a 100644 --- a/features/restart_command_tests.lua +++ b/features/restart_command_tests.lua @@ -137,10 +137,12 @@ Declare.module({'features', 'restart_command'}, function() declare_test('Requires admin to run command.', function(context) -- Arrange. local player = context.player - Helper.modify_lua_object(context, player, 'admin', false) - Helper.modify_lua_object(context, game, 'get_player', function() - return player - end) + local fake_player = Helper.fake_lua_object(player, { admin = false }) + Helper.modify_global(context, 'game', Helper.fake_lua_object(game, { + get_player = function() + return fake_player + end + })) -- Act. run_config_command(player) @@ -155,12 +157,16 @@ Declare.module({'features', 'restart_command'}, function() -- Arrange. local player = context.player local actual = nil - Helper.modify_lua_object(context, player, 'print', function(str) - actual = str - end) - Helper.modify_lua_object(context, game, 'get_player', function() - return player - end) + local fake_player = Helper.fake_lua_object(player, { + print = function(str) + actual = str + end + }) + Helper.modify_global(context, 'game', Helper.fake_lua_object(game, { + get_player = function() + return fake_player + end + })) local start_game_data = { type = RestartCommand.game_types.scenario, @@ -345,7 +351,7 @@ Mod Pack: some_mod_pack]] output[#output + 1] = str end - Helper.modify_lua_object(context, game, 'print', game_print) + Helper.modify_global(context, 'game', Helper.fake_lua_object(game, { print = game_print })) -- Act. run_restart_command(player) @@ -376,7 +382,7 @@ Mod Pack: some_mod_pack]] output[#output + 1] = str end - Helper.modify_lua_object(context, game, 'print', game_print) + Helper.modify_global(context, 'game', Helper.fake_lua_object(game, { print = game_print })) -- Act. run_restart_command(player, argument) diff --git a/utils/gui_tests.lua b/utils/gui_tests.lua index bc0577b11..5854d83c7 100644 --- a/utils/gui_tests.lua +++ b/utils/gui_tests.lua @@ -6,9 +6,19 @@ local Helper = require 'utils.test.helper' Declare.module({'utils', 'Gui'}, function() Declare.module('can toggle top buttons', function() local function count_gui_elements(player) - -- local gui = player.gui - -- return #gui.top.children + #gui.left.children + #gui.center.children + #gui.screen.children - return #Gui.get_top_flow(player).children + #Gui.get_left_flow(player).children + #player.gui.center.children + #player.gui.screen.children + local roots = {Gui.get_top_flow(player), Gui.get_left_flow(player), player.gui.center, player.gui.screen} + local count = 0 + for _, root in pairs(roots) do + for _, child in pairs(root.children) do + -- Only visible elements count as open: some GUIs, such as the + -- production hud, hide their frame on close instead of + -- destroying it, to preserve its screen position. + if child.visible then + count = count + 1 + end + end + end + return count end local function is_ignored_element(element) diff --git a/utils/test/helper.lua b/utils/test/helper.lua index 5edaf6056..eec1ed06b 100644 --- a/utils/test/helper.lua +++ b/utils/test/helper.lua @@ -91,6 +91,10 @@ function Public.wait_for_chunk_to_be_charted(context, force, surface, chunk_posi end function Public.modify_lua_object(context, object, key, value) + if type(object) ~= 'table' then + error('LuaObjects are userdata since Factorio 2.0 and cannot be modified; use Helper.fake_lua_object and Helper.modify_global instead.', 2) + end + local old_value = object[key] rawset(object, key, value) @@ -99,6 +103,30 @@ function Public.modify_lua_object(context, object, key, value) end) end +-- LuaObjects are userdata since Factorio 2.0, so their fields cannot be +-- replaced. Returns a table that reads and writes through to the given object, +-- except for the overridden fields. +function Public.fake_lua_object(object, overrides) + return setmetatable(overrides or {}, { + __index = function(_, key) + return object[key] + end, + __newindex = function(_, key, value) + object[key] = value + end + }) +end + +-- Replaces a global variable, e.g. the 'game' object, until test teardown. +function Public.modify_global(context, name, value) + local old_value = _G[name] + rawset(_G, name, value) + + context:add_teardown(function() + rawset(_G, name, old_value) + end) +end + local function get_gui_element_by_name(parent, name) if parent.name == name then return parent