From 42ae359abc2ee416fad56574af50cbde120be8a1 Mon Sep 17 00:00:00 2001 From: scawful Date: Mon, 22 Dec 2025 14:49:04 -0500 Subject: [PATCH] test(rom): add role-based ROM selection --- CMakeLists.txt | 7 +- src/cli/handlers/tools/test_cli_commands.cc | 27 +- test/CMakeLists.txt | 34 ++- test/e2e/ai_multimodal_test.cc | 6 +- test/e2e/canvas_selection_test.cc | 2 +- test/e2e/dungeon_canvas_interaction_test.cc | 8 +- test/e2e/dungeon_editor_smoke_test.cc | 2 +- test/e2e/dungeon_layer_rendering_test.cc | 2 +- test/e2e/dungeon_object_drawing_test.cc | 8 +- test/e2e/dungeon_object_drawing_test.h | 2 +- test/e2e/dungeon_visual_verification_test.cc | 8 +- test/e2e/emulator_stepping_test.cc | 10 +- test/e2e/framework_smoke_test.cc | 2 +- test/e2e/imgui_test_engine_demo.cc | 4 +- test/e2e/rom_dependent/e2e_rom_test.cc | 27 +- .../e2e/rom_dependent/editor_save_test_base.h | 108 ++------ test/gui_test_utils.cc | 19 +- .../dungeon_palette_inspection_test.cc | 9 +- test/integration/dungeon_editor_test.h | 15 +- test/integration/dungeon_editor_v2_test.h | 23 +- test/integration/editor/tile16_editor_test.cc | 9 +- test/integration/overworld_editor_test.h | 18 +- test/integration/zelda3/message_test.cc | 16 +- .../zelda3/music_integration_test.cc | 13 +- .../zelda3/sprite_position_test.cc | 21 +- test/test.cmake | 2 +- test/test_utils.h | 232 +++++++++++++++--- test/test_utils/rom_integrity_validator.h | 2 +- test/unit/rom/rom_test.cc | 30 ++- test/yaze_test.cc | 87 ++++++- 30 files changed, 488 insertions(+), 265 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 93db2091..b30b9dd9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,7 +72,12 @@ include(cmake/dependencies.cmake) # Additional configuration options option(YAZE_SUPPRESS_WARNINGS "Suppress compiler warnings (use -v preset suffix for verbose)" ON) -set(YAZE_TEST_ROM_PATH "${CMAKE_BINARY_DIR}/bin/zelda3.sfc" CACHE STRING "Path to test ROM file") +set(YAZE_TEST_ROM_VANILLA_PATH "" CACHE STRING "Path to vanilla test ROM file") +set(YAZE_TEST_ROM_US_PATH "" CACHE STRING "Path to US test ROM file") +set(YAZE_TEST_ROM_JP_PATH "" CACHE STRING "Path to JP test ROM file") +set(YAZE_TEST_ROM_EU_PATH "" CACHE STRING "Path to EU test ROM file") +set(YAZE_TEST_ROM_EXPANDED_PATH "" CACHE STRING "Path to expanded test ROM file") +set(YAZE_TEST_ROM_PATH "" CACHE STRING "Legacy path to test ROM file (vanilla)") # Export compile commands for clangd/LSP set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/src/cli/handlers/tools/test_cli_commands.cc b/src/cli/handlers/tools/test_cli_commands.cc index cbc5744c..9600e85d 100644 --- a/src/cli/handlers/tools/test_cli_commands.cc +++ b/src/cli/handlers/tools/test_cli_commands.cc @@ -256,11 +256,18 @@ absl::Status TestStatusCommandHandler::Execute( bool is_json = formatter.IsJson(); // Check environment variables - std::string rom_path = GetEnvOrDefault("YAZE_TEST_ROM_PATH", ""); + std::string rom_vanilla = GetEnvOrDefault("YAZE_TEST_ROM_VANILLA", ""); + std::string rom_expanded = GetEnvOrDefault("YAZE_TEST_ROM_EXPANDED", ""); + std::string rom_path_legacy = GetEnvOrDefault("YAZE_TEST_ROM_PATH", ""); + if (rom_vanilla.empty()) { + rom_vanilla = rom_path_legacy; + } std::string skip_rom = GetEnvOrDefault("YAZE_SKIP_ROM_TESTS", ""); std::string enable_ui = GetEnvOrDefault("YAZE_ENABLE_UI_TESTS", ""); - formatter.AddField("rom_path", rom_path.empty() ? "not set" : rom_path); + formatter.AddField("rom_vanilla", rom_vanilla.empty() ? "not set" : rom_vanilla); + formatter.AddField("rom_expanded", rom_expanded.empty() ? "not set" : rom_expanded); + formatter.AddField("rom_path", rom_path_legacy.empty() ? "not set" : rom_path_legacy); formatter.AddField("skip_rom_tests", !skip_rom.empty()); formatter.AddField("ui_tests_enabled", !enable_ui.empty()); @@ -291,7 +298,7 @@ absl::Status TestStatusCommandHandler::Execute( formatter.BeginArray("available_suites"); for (const auto& suite : kTestSuites) { bool available = true; - if (suite.requires_rom && rom_path.empty()) { + if (suite.requires_rom && rom_vanilla.empty()) { available = false; } if (available) { @@ -307,8 +314,11 @@ absl::Status TestStatusCommandHandler::Execute( std::cout << "║ TEST CONFIGURATION ║\n"; std::cout << "╠═══════════════════════════════════════════════════════════════╣\n"; std::cout << absl::StrFormat( - "║ ROM Path: %-50s ║\n", - rom_path.empty() ? "(not set)" : rom_path.substr(0, 50)); + "║ ROM Vanilla: %-47s ║\n", + rom_vanilla.empty() ? "(not set)" : rom_vanilla.substr(0, 47)); + std::cout << absl::StrFormat( + "║ ROM Expanded: %-46s ║\n", + rom_expanded.empty() ? "(not set)" : rom_expanded.substr(0, 46)); std::cout << absl::StrFormat("║ Skip ROM Tests: %-43s ║\n", skip_rom.empty() ? "NO" : "YES"); std::cout << absl::StrFormat("║ UI Tests Enabled: %-41s ║\n", @@ -326,7 +336,7 @@ absl::Status TestStatusCommandHandler::Execute( for (const auto& suite : kTestSuites) { bool available = true; std::string reason; - if (suite.requires_rom && rom_path.empty()) { + if (suite.requires_rom && rom_vanilla.empty()) { available = false; reason = " (needs ROM)"; } @@ -338,9 +348,9 @@ absl::Status TestStatusCommandHandler::Execute( } std::cout << "╚═══════════════════════════════════════════════════════════════╝\n"; - if (rom_path.empty()) { + if (rom_vanilla.empty()) { std::cout << "\nTo enable ROM-dependent tests:\n"; - std::cout << " export YAZE_TEST_ROM_PATH=/path/to/zelda3.sfc\n"; + std::cout << " export YAZE_TEST_ROM_VANILLA=/path/to/alttp_vanilla.sfc\n"; std::cout << " cmake ... -DYAZE_ENABLE_ROM_TESTS=ON\n"; } } @@ -349,4 +359,3 @@ absl::Status TestStatusCommandHandler::Execute( } } // namespace yaze::cli - diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 04cfb14d..6a5a06af 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -192,10 +192,42 @@ if(YAZE_BUILD_TESTS) e2e/zscustomoverworld/zscustomoverworld_upgrade_test.cc ) yaze_add_test_suite(yaze_test_rom_dependent "rom_dependent" OFF ${ROM_DEPENDENT_TEST_SOURCES}) + if(TARGET overworld_golden_data_extractor) + add_dependencies(yaze_test_rom_dependent overworld_golden_data_extractor) + endif() target_compile_definitions(yaze_test_rom_dependent PRIVATE YAZE_ENABLE_ROM_TESTS=1 - YAZE_TEST_ROM_PATH="${YAZE_TEST_ROM_PATH}" ) + if(YAZE_TEST_ROM_PATH) + target_compile_definitions(yaze_test_rom_dependent PRIVATE + YAZE_TEST_ROM_PATH="${YAZE_TEST_ROM_PATH}" + ) + endif() + if(YAZE_TEST_ROM_VANILLA_PATH) + target_compile_definitions(yaze_test_rom_dependent PRIVATE + YAZE_TEST_ROM_VANILLA_PATH="${YAZE_TEST_ROM_VANILLA_PATH}" + ) + endif() + if(YAZE_TEST_ROM_US_PATH) + target_compile_definitions(yaze_test_rom_dependent PRIVATE + YAZE_TEST_ROM_US_PATH="${YAZE_TEST_ROM_US_PATH}" + ) + endif() + if(YAZE_TEST_ROM_JP_PATH) + target_compile_definitions(yaze_test_rom_dependent PRIVATE + YAZE_TEST_ROM_JP_PATH="${YAZE_TEST_ROM_JP_PATH}" + ) + endif() + if(YAZE_TEST_ROM_EU_PATH) + target_compile_definitions(yaze_test_rom_dependent PRIVATE + YAZE_TEST_ROM_EU_PATH="${YAZE_TEST_ROM_EU_PATH}" + ) + endif() + if(YAZE_TEST_ROM_EXPANDED_PATH) + target_compile_definitions(yaze_test_rom_dependent PRIVATE + YAZE_TEST_ROM_EXPANDED_PATH="${YAZE_TEST_ROM_EXPANDED_PATH}" + ) + endif() endif() # Experimental & GUI Test Suites --- diff --git a/test/e2e/ai_multimodal_test.cc b/test/e2e/ai_multimodal_test.cc index a8360d12..91c148e7 100644 --- a/test/e2e/ai_multimodal_test.cc +++ b/test/e2e/ai_multimodal_test.cc @@ -21,7 +21,7 @@ namespace test { */ void E2ETest_AIVisionVerification(ImGuiTestContext* ctx) { // Load ROM first - gui::LoadRomInTest(ctx, "zelda3.sfc"); + gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); // Open the overworld editor gui::OpenEditorInTest(ctx, "Overworld"); @@ -80,7 +80,7 @@ void E2ETest_AIVisionVerification(ImGuiTestContext* ctx) { * using pixel-level comparison against reference images. */ void E2ETest_ScreenshotAssertion(ImGuiTestContext* ctx) { - gui::LoadRomInTest(ctx, "zelda3.sfc"); + gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); gui::OpenEditorInTest(ctx, "Graphics"); ctx->Yield(10); @@ -144,7 +144,7 @@ void E2ETest_ScreenshotAssertion(ImGuiTestContext* ctx) { * for comprehensive UI testing. */ void E2ETest_HybridAIScreenshotTest(ImGuiTestContext* ctx) { - gui::LoadRomInTest(ctx, "zelda3.sfc"); + gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); gui::OpenEditorInTest(ctx, "Dungeon"); ctx->Yield(10); diff --git a/test/e2e/canvas_selection_test.cc b/test/e2e/canvas_selection_test.cc index e6ebe805..c41413b9 100644 --- a/test/e2e/canvas_selection_test.cc +++ b/test/e2e/canvas_selection_test.cc @@ -5,7 +5,7 @@ #include "test_utils.h" void E2ETest_CanvasSelectionTest(ImGuiTestContext* ctx) { - yaze::test::gui::LoadRomInTest(ctx, "zelda3.sfc"); + yaze::test::gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); yaze::Controller* controller = (yaze::Controller*)ctx->Test->UserData; yaze::zelda3::Overworld* overworld = controller->overworld(); diff --git a/test/e2e/dungeon_canvas_interaction_test.cc b/test/e2e/dungeon_canvas_interaction_test.cc index f1504965..90a89d85 100644 --- a/test/e2e/dungeon_canvas_interaction_test.cc +++ b/test/e2e/dungeon_canvas_interaction_test.cc @@ -109,7 +109,7 @@ void E2ETest_DungeonCanvas_PanZoom(ImGuiTestContext* ctx) { // Load ROM ctx->LogInfo("Loading ROM..."); - yaze::test::gui::LoadRomInTest(ctx, "zelda3.sfc"); + yaze::test::gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); // Open dungeon editor and room ctx->LogInfo("Opening Dungeon Editor..."); @@ -219,7 +219,7 @@ void E2ETest_DungeonCanvas_ObjectSelection(ImGuiTestContext* ctx) { // Load ROM ctx->LogInfo("Loading ROM..."); - yaze::test::gui::LoadRomInTest(ctx, "zelda3.sfc"); + yaze::test::gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); // Open dungeon editor ctx->LogInfo("Opening Dungeon Editor..."); @@ -307,7 +307,7 @@ void E2ETest_DungeonCanvas_GridSnap(ImGuiTestContext* ctx) { // Load ROM ctx->LogInfo("Loading ROM..."); - yaze::test::gui::LoadRomInTest(ctx, "zelda3.sfc"); + yaze::test::gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); // Open dungeon editor ctx->LogInfo("Opening Dungeon Editor..."); @@ -414,7 +414,7 @@ void E2ETest_DungeonCanvas_MultiSelect(ImGuiTestContext* ctx) { // Load ROM ctx->LogInfo("Loading ROM..."); - yaze::test::gui::LoadRomInTest(ctx, "zelda3.sfc"); + yaze::test::gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); // Open dungeon editor ctx->LogInfo("Opening Dungeon Editor..."); diff --git a/test/e2e/dungeon_editor_smoke_test.cc b/test/e2e/dungeon_editor_smoke_test.cc index 1db92ce0..01041704 100644 --- a/test/e2e/dungeon_editor_smoke_test.cc +++ b/test/e2e/dungeon_editor_smoke_test.cc @@ -17,7 +17,7 @@ void E2ETest_DungeonEditorV2SmokeTest(ImGuiTestContext* ctx) { // Load ROM first ctx->LogInfo("Loading ROM..."); - yaze::test::gui::LoadRomInTest(ctx, "zelda3.sfc"); + yaze::test::gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); ctx->LogInfo("ROM loaded successfully"); // Open the Dungeon Editor diff --git a/test/e2e/dungeon_layer_rendering_test.cc b/test/e2e/dungeon_layer_rendering_test.cc index fb302275..b7e5fdbf 100644 --- a/test/e2e/dungeon_layer_rendering_test.cc +++ b/test/e2e/dungeon_layer_rendering_test.cc @@ -52,7 +52,7 @@ bool SetupDungeonEditorWithRoom(ImGuiTestContext* ctx, const char* room_hex = "0x00") { // Load ROM ctx->LogInfo("Loading ROM..."); - gui::LoadRomInTest(ctx, "zelda3.sfc"); + gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); // Open Dungeon Editor ctx->LogInfo("Opening Dungeon Editor..."); diff --git a/test/e2e/dungeon_object_drawing_test.cc b/test/e2e/dungeon_object_drawing_test.cc index 77aba59f..3f8df28e 100644 --- a/test/e2e/dungeon_object_drawing_test.cc +++ b/test/e2e/dungeon_object_drawing_test.cc @@ -141,7 +141,7 @@ void E2ETest_DungeonObjectDrawing_BasicPlacement(ImGuiTestContext* ctx) { // Step 1: Load ROM ctx->LogInfo("Step 1: Loading ROM..."); - gui::LoadRomInTest(ctx, "zelda3.sfc"); + gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); ctx->Yield(10); // Step 2: Open Dungeon Editor @@ -216,7 +216,7 @@ void E2ETest_DungeonObjectDrawing_MultiLayerObjects(ImGuiTestContext* ctx) { // Step 1: Load ROM and open editor ctx->LogInfo("Step 1: Loading ROM and opening editor..."); - gui::LoadRomInTest(ctx, "zelda3.sfc"); + gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); gui::OpenEditorInTest(ctx, "Dungeon"); ctx->Yield(20); @@ -287,7 +287,7 @@ void E2ETest_DungeonObjectDrawing_ObjectDeletion(ImGuiTestContext* ctx) { // Step 1: Load ROM and open editor ctx->LogInfo("Step 1: Loading ROM and opening editor..."); - gui::LoadRomInTest(ctx, "zelda3.sfc"); + gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); gui::OpenEditorInTest(ctx, "Dungeon"); ctx->Yield(20); @@ -357,7 +357,7 @@ void E2ETest_DungeonObjectDrawing_ObjectRepositioning(ImGuiTestContext* ctx) { // Step 1: Load ROM and open editor ctx->LogInfo("Step 1: Loading ROM and opening editor..."); - gui::LoadRomInTest(ctx, "zelda3.sfc"); + gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); gui::OpenEditorInTest(ctx, "Dungeon"); ctx->Yield(20); diff --git a/test/e2e/dungeon_object_drawing_test.h b/test/e2e/dungeon_object_drawing_test.h index 99b8aced..d405d8a6 100644 --- a/test/e2e/dungeon_object_drawing_test.h +++ b/test/e2e/dungeon_object_drawing_test.h @@ -14,7 +14,7 @@ * - Object repositioning via drag * * Requires: - * - ROM file for testing (zelda3.sfc) + * - ROM file for testing (alttp_vanilla.sfc) * - GUI test mode (--ui flag) */ diff --git a/test/e2e/dungeon_visual_verification_test.cc b/test/e2e/dungeon_visual_verification_test.cc index de94568c..7bd5ec3c 100644 --- a/test/e2e/dungeon_visual_verification_test.cc +++ b/test/e2e/dungeon_visual_verification_test.cc @@ -49,7 +49,7 @@ void E2ETest_VisualVerification_BasicRoomRendering(ImGuiTestContext* ctx) { // Load ROM ctx->LogInfo("Loading ROM..."); - gui::LoadRomInTest(ctx, "zelda3.sfc"); + gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); // Open Dungeon Editor ctx->LogInfo("Opening Dungeon Editor..."); @@ -102,7 +102,7 @@ void E2ETest_VisualVerification_LayerVisibility(ImGuiTestContext* ctx) { ctx->LogInfo("=== Visual Verification: Layer Visibility ==="); // Load ROM and open editor - gui::LoadRomInTest(ctx, "zelda3.sfc"); + gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); gui::OpenEditorInTest(ctx, "Dungeon"); ctx->Yield(20); @@ -157,7 +157,7 @@ void E2ETest_VisualVerification_LayerVisibility(ImGuiTestContext* ctx) { void E2ETest_VisualVerification_ObjectEditor(ImGuiTestContext* ctx) { ctx->LogInfo("=== Visual Verification: Object Editor ==="); - gui::LoadRomInTest(ctx, "zelda3.sfc"); + gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); gui::OpenEditorInTest(ctx, "Dungeon"); ctx->Yield(20); @@ -190,7 +190,7 @@ void E2ETest_VisualVerification_ObjectEditor(ImGuiTestContext* ctx) { void E2ETest_VisualVerification_MultiRoomNavigation(ImGuiTestContext* ctx) { ctx->LogInfo("=== Visual Verification: Multi-Room Navigation ==="); - gui::LoadRomInTest(ctx, "zelda3.sfc"); + gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); gui::OpenEditorInTest(ctx, "Dungeon"); ctx->Yield(20); diff --git a/test/e2e/emulator_stepping_test.cc b/test/e2e/emulator_stepping_test.cc index 00284fb9..cc38e53f 100644 --- a/test/e2e/emulator_stepping_test.cc +++ b/test/e2e/emulator_stepping_test.cc @@ -16,7 +16,7 @@ namespace test { * as single operations when the PC is at a JSR/JSL instruction. */ void E2ETest_EmulatorStepOver(ImGuiTestContext* ctx) { - gui::LoadRomInTest(ctx, "zelda3.sfc"); + gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); // Open emulator ctx->SetRef("Yaze"); @@ -61,7 +61,7 @@ void E2ETest_EmulatorStepOver(ImGuiTestContext* ctx) { * subroutine returns (RTS/RTL). */ void E2ETest_EmulatorStepOut(ImGuiTestContext* ctx) { - gui::LoadRomInTest(ctx, "zelda3.sfc"); + gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); ctx->SetRef("Yaze"); ctx->MenuClick("Emulation/Launch Emulator"); @@ -95,7 +95,7 @@ void E2ETest_EmulatorStepOut(ImGuiTestContext* ctx) { * across JSR/JSL calls and RTS/RTL returns. */ void E2ETest_EmulatorCallStackTracking(ImGuiTestContext* ctx) { - gui::LoadRomInTest(ctx, "zelda3.sfc"); + gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); ctx->SetRef("Yaze"); ctx->MenuClick("Emulation/Launch Emulator"); @@ -138,7 +138,7 @@ void E2ETest_EmulatorCallStackTracking(ImGuiTestContext* ctx) { * This test verifies running execution until a specific address is reached. */ void E2ETest_EmulatorRunToAddress(ImGuiTestContext* ctx) { - gui::LoadRomInTest(ctx, "zelda3.sfc"); + gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); ctx->SetRef("Yaze"); ctx->MenuClick("Emulation/Launch Emulator"); @@ -168,7 +168,7 @@ void E2ETest_EmulatorRunToAddress(ImGuiTestContext* ctx) { * for AI-driven analysis or automation. */ void E2ETest_EmulatorInstructionCallback(ImGuiTestContext* ctx) { - gui::LoadRomInTest(ctx, "zelda3.sfc"); + gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); ctx->SetRef("Yaze"); ctx->MenuClick("Emulation/Launch Emulator"); diff --git a/test/e2e/framework_smoke_test.cc b/test/e2e/framework_smoke_test.cc index 4d4778b7..5f1aec4c 100644 --- a/test/e2e/framework_smoke_test.cc +++ b/test/e2e/framework_smoke_test.cc @@ -9,7 +9,7 @@ // It opens a window, clicks a button, and verifies that the button was clicked. // The GUI for this test is rendered in `test/yaze_test.cc`. void E2ETest_FrameworkSmokeTest(ImGuiTestContext* ctx) { - yaze::test::gui::LoadRomInTest(ctx, "zelda3.sfc"); + yaze::test::gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); ctx->SetRef("Hello World Window"); ctx->ItemClick("Button"); ctx->ItemCheck("Clicked 1 times"); diff --git a/test/e2e/imgui_test_engine_demo.cc b/test/e2e/imgui_test_engine_demo.cc index 1f5fdbee..c204f5a4 100644 --- a/test/e2e/imgui_test_engine_demo.cc +++ b/test/e2e/imgui_test_engine_demo.cc @@ -102,7 +102,7 @@ void E2ETest_ImGuiMouseInteraction(ImGuiTestContext* ctx) { * - Arrow keys for navigation */ void E2ETest_ImGuiKeyboardShortcuts(ImGuiTestContext* ctx) { - gui::LoadRomInTest(ctx, "zelda3.sfc"); + gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); ctx->SetRef("Yaze"); ctx->WindowFocus("Overworld Editor"); @@ -169,7 +169,7 @@ void E2ETest_ImGuiWidgetState(ImGuiTestContext* ctx) { * the ImGui Test Engine for comprehensive visual verification. */ void E2ETest_ImGuiWithScreenshotAssertion(ImGuiTestContext* ctx) { - gui::LoadRomInTest(ctx, "zelda3.sfc"); + gui::LoadRomInTest(ctx, yaze::test::TestRomManager::GetTestRomPath()); ctx->SetRef("Yaze"); ctx->MenuClick("View/Graphics Editor"); diff --git a/test/e2e/rom_dependent/e2e_rom_test.cc b/test/e2e/rom_dependent/e2e_rom_test.cc index 94ef7d60..7d353bdc 100644 --- a/test/e2e/rom_dependent/e2e_rom_test.cc +++ b/test/e2e/rom_dependent/e2e_rom_test.cc @@ -8,6 +8,7 @@ #include "rom/rom.h" #include "rom/transaction.h" +#include "test/test_utils.h" #include "testing.h" #include "util/macro.h" @@ -27,18 +28,10 @@ namespace test { class E2ERomDependentTest : public ::testing::Test { protected: void SetUp() override { - // Skip tests if ROM is not available - if (getenv("YAZE_SKIP_ROM_TESTS")) { - GTEST_SKIP() << "ROM tests disabled"; - } - - // Get ROM path from environment or use default - const char* rom_path_env = getenv("YAZE_TEST_ROM_PATH"); - vanilla_rom_path_ = rom_path_env ? rom_path_env : "zelda3.sfc"; - - if (!std::filesystem::exists(vanilla_rom_path_)) { - GTEST_SKIP() << "Test ROM not found: " << vanilla_rom_path_; - } + yaze::test::TestRomManager::SkipIfRomMissing( + yaze::test::RomRole::kVanilla, "E2ERomDependentTest"); + vanilla_rom_path_ = + yaze::test::TestRomManager::GetRomPath(yaze::test::RomRole::kVanilla); // Create test ROM copies test_rom_path_ = "test_rom_edit.sfc"; @@ -69,10 +62,10 @@ class E2ERomDependentTest : public ::testing::Test { EXPECT_EQ(rom->size(), 0x200000) << "ROM size should be 2MB"; EXPECT_NE(rom->data(), nullptr) << "ROM data should not be null"; - // Check ROM header - auto header_byte = rom->ReadByte(0x7FC0); - RETURN_IF_ERROR(header_byte.status()); - EXPECT_EQ(*header_byte, 0x21) << "ROM should be LoROM format"; + // Check ROM mapping mode (LoROM expected) + auto map_mode = rom->ReadByte(0x7FD5); + RETURN_IF_ERROR(map_mode.status()); + EXPECT_EQ(*map_mode & 0x01, 0) << "ROM should be LoROM format"; return absl::OkStatus(); } @@ -273,4 +266,4 @@ TEST_F(E2ERomDependentTest, LargeScaleEditing) { } } // namespace test -} // namespace yaze \ No newline at end of file +} // namespace yaze diff --git a/test/e2e/rom_dependent/editor_save_test_base.h b/test/e2e/rom_dependent/editor_save_test_base.h index 30ba0081..4ee7a286 100644 --- a/test/e2e/rom_dependent/editor_save_test_base.h +++ b/test/e2e/rom_dependent/editor_save_test_base.h @@ -12,9 +12,11 @@ #include "absl/status/status.h" #include "rom/rom.h" #include "rom/snes.h" +#include "test/test_utils.h" #include "testing.h" #include "util/macro.h" #include "zelda.h" +#include "zelda3/overworld/overworld_version_helper.h" namespace yaze { namespace test { @@ -30,28 +32,6 @@ struct RomVersionInfo { uint8_t zscustom_version; // 0xFF = vanilla, 0x02 = v2, 0x03+ = v3+ }; -/** - * @brief Environment variable names for ROM paths - */ -struct RomEnvVars { - static constexpr const char* kDefaultRomPath = "YAZE_TEST_ROM_PATH"; - static constexpr const char* kSkipRomTests = "YAZE_SKIP_ROM_TESTS"; - static constexpr const char* kJpRomPath = "YAZE_TEST_ROM_JP_PATH"; - static constexpr const char* kUsRomPath = "YAZE_TEST_ROM_US_PATH"; - static constexpr const char* kEuRomPath = "YAZE_TEST_ROM_EU_PATH"; - static constexpr const char* kExpandedRomPath = "YAZE_TEST_ROM_EXPANDED_PATH"; -}; - -/** - * @brief Default ROM paths relative to workspace (roms/ directory) - */ -struct DefaultRomPaths { - static constexpr const char* kVanilla = "roms/alttp_vanilla.sfc"; - static constexpr const char* kUsRom = "roms/Legend of Zelda, The - A Link to the Past (USA).sfc"; - static constexpr const char* kExpanded = "roms/oos168.sfc"; - static constexpr const char* kFallback = "zelda3.sfc"; -}; - /** * @brief Base test fixture for E2E editor save tests * @@ -64,24 +44,8 @@ struct DefaultRomPaths { class EditorSaveTestBase : public ::testing::Test { protected: void SetUp() override { - // Skip tests if ROM tests are disabled - if (getenv(RomEnvVars::kSkipRomTests)) { - GTEST_SKIP() << "ROM tests disabled via YAZE_SKIP_ROM_TESTS"; - } - - // Determine ROM path - const char* rom_path_env = getenv(RomEnvVars::kDefaultRomPath); - if (rom_path_env && std::filesystem::exists(rom_path_env)) { - vanilla_rom_path_ = rom_path_env; - } else if (std::filesystem::exists(DefaultRomPaths::kVanilla)) { - vanilla_rom_path_ = DefaultRomPaths::kVanilla; - } else if (std::filesystem::exists(DefaultRomPaths::kUsRom)) { - vanilla_rom_path_ = DefaultRomPaths::kUsRom; - } else if (std::filesystem::exists(DefaultRomPaths::kFallback)) { - vanilla_rom_path_ = DefaultRomPaths::kFallback; - } else { - GTEST_SKIP() << "No test ROM found. Set YAZE_TEST_ROM_PATH or place ROM in roms/"; - } + TestRomManager::SkipIfRomMissing(RomRole::kVanilla, "EditorSaveTestBase"); + vanilla_rom_path_ = TestRomManager::GetRomPath(RomRole::kVanilla); // Create test file paths with unique names per test test_id_ = ::testing::UnitTest::GetInstance()->current_test_info()->name(); @@ -163,7 +127,7 @@ class EditorSaveTestBase : public ::testing::Test { Rom::SaveSettings settings; settings.filename = path; settings.backup = false; // We handle backups ourselves - settings.save_new = true; + settings.save_new = false; // Overwrite the test copy for persistence checks return rom->SaveToFile(settings); } @@ -183,9 +147,11 @@ class EditorSaveTestBase : public ::testing::Test { auto version_byte = rom.ReadByte(0x140145); info.zscustom_version = version_byte.ok() ? *version_byte : 0xFF; - // Detect expanded tile16 - auto tile16_check = rom.ReadByte(0x02FD28); - info.is_expanded_tile16 = tile16_check.ok() && *tile16_check != 0x0F; + // Detect expanded tile16 based on applied ASM version (v1+ uses expanded space) + const auto overworld_version = + zelda3::OverworldVersionHelper::GetVersion(rom); + info.is_expanded_tile16 = + zelda3::OverworldVersionHelper::SupportsExpandedSpace(overworld_version); // Detect expanded tile32 auto tile32_check = rom.ReadByte(0x01772E); @@ -347,24 +313,14 @@ class EditorSaveTestBase : public ::testing::Test { * @brief Get path to expanded ROM for v3 feature tests */ std::string GetExpandedRomPath() { - const char* expanded_path = getenv(RomEnvVars::kExpandedRomPath); - if (expanded_path && std::filesystem::exists(expanded_path)) { - return expanded_path; - } - if (std::filesystem::exists(DefaultRomPaths::kExpanded)) { - return DefaultRomPaths::kExpanded; - } - return ""; // Not available + return TestRomManager::GetRomPath(RomRole::kExpanded); } /** * @brief Skip test if expanded ROM is required but not available */ void RequireExpandedRom() { - std::string path = GetExpandedRomPath(); - if (path.empty()) { - GTEST_SKIP() << "Expanded ROM not available for v3 feature tests"; - } + TestRomManager::SkipIfRomMissing(RomRole::kExpanded, "ExpandedRomSaveTest"); } // =========================================================================== @@ -386,21 +342,9 @@ class MultiVersionEditorSaveTest : public EditorSaveTestBase { EditorSaveTestBase::SetUp(); // Check for additional ROM versions - const char* jp_path = getenv(RomEnvVars::kJpRomPath); - const char* us_path = getenv(RomEnvVars::kUsRomPath); - const char* eu_path = getenv(RomEnvVars::kEuRomPath); - - if (jp_path && std::filesystem::exists(jp_path)) { - jp_rom_path_ = jp_path; - } - if (us_path && std::filesystem::exists(us_path)) { - us_rom_path_ = us_path; - } else if (std::filesystem::exists(DefaultRomPaths::kUsRom)) { - us_rom_path_ = DefaultRomPaths::kUsRom; - } - if (eu_path && std::filesystem::exists(eu_path)) { - eu_rom_path_ = eu_path; - } + jp_rom_path_ = TestRomManager::GetRomPath(RomRole::kJp); + us_rom_path_ = TestRomManager::GetRomPath(RomRole::kUs); + eu_rom_path_ = TestRomManager::GetRomPath(RomRole::kEu); } bool HasJpRom() const { return !jp_rom_path_.empty(); } @@ -418,27 +362,11 @@ class MultiVersionEditorSaveTest : public EditorSaveTestBase { class ExpandedRomSaveTest : public EditorSaveTestBase { protected: void SetUp() override { - // Skip if ROM tests disabled - if (getenv(RomEnvVars::kSkipRomTests)) { - GTEST_SKIP() << "ROM tests disabled via YAZE_SKIP_ROM_TESTS"; - } - - // Get expanded ROM path - const char* expanded_path = getenv(RomEnvVars::kExpandedRomPath); - if (expanded_path && std::filesystem::exists(expanded_path)) { - expanded_rom_path_ = expanded_path; - } else if (std::filesystem::exists(DefaultRomPaths::kExpanded)) { - expanded_rom_path_ = DefaultRomPaths::kExpanded; - } else { - GTEST_SKIP() << "Expanded ROM not available. Set YAZE_TEST_ROM_EXPANDED_PATH"; - } + TestRomManager::SkipIfRomMissing(RomRole::kExpanded, "ExpandedRomSaveTest"); + expanded_rom_path_ = TestRomManager::GetRomPath(RomRole::kExpanded); // Use vanilla for baseline comparison - if (std::filesystem::exists(DefaultRomPaths::kVanilla)) { - vanilla_rom_path_ = DefaultRomPaths::kVanilla; - } else { - vanilla_rom_path_ = ""; - } + vanilla_rom_path_ = TestRomManager::GetRomPath(RomRole::kVanilla); // Create test file paths test_id_ = ::testing::UnitTest::GetInstance()->current_test_info()->name(); diff --git a/test/gui_test_utils.cc b/test/gui_test_utils.cc index d7194986..36791480 100644 --- a/test/gui_test_utils.cc +++ b/test/gui_test_utils.cc @@ -1,3 +1,6 @@ +#define IMGUI_DEFINE_MATH_OPERATORS + +#include "imgui_test_engine/imgui_te_context.h" #include "test_utils.h" #include "app/controller.h" @@ -15,6 +18,18 @@ void LoadRomInTest(ImGuiTestContext* ctx, const std::string& rom_path) { return; } + std::string resolved_rom_path = rom_path; + if (resolved_rom_path.empty() || resolved_rom_path == "zelda3.sfc" || + resolved_rom_path == "vanilla.sfc") { + resolved_rom_path = + TestRomManager::GetRomPath(RomRole::kVanilla); + } + if (resolved_rom_path.empty()) { + ctx->LogError( + "LoadRomInTest: No ROM path resolved. Set YAZE_TEST_ROM_VANILLA."); + return; + } + // Check if ROM is already loaded Rom* rom = controller->GetCurrentRom(); if (rom && rom->is_loaded()) { @@ -27,7 +42,7 @@ void LoadRomInTest(ImGuiTestContext* ctx, const std::string& rom_path) { // 2. ConfigureEditorDependencies() // 3. LoadAssets() - initializes all editors and loads graphics // 4. Updates UI state (hides welcome screen, etc.) - auto status = controller->LoadRomForTesting(rom_path); + auto status = controller->LoadRomForTesting(resolved_rom_path); if (!status.ok()) { ctx->LogError("LoadRomInTest: Failed to load ROM: %s", std::string(status.message()).c_str()); @@ -35,7 +50,7 @@ void LoadRomInTest(ImGuiTestContext* ctx, const std::string& rom_path) { } ctx->LogInfo("ROM loaded successfully with full initialization: %s", - rom_path.c_str()); + resolved_rom_path.c_str()); ctx->Yield(10); // Give more time for asset loading and UI updates } diff --git a/test/inspection/dungeon_palette_inspection_test.cc b/test/inspection/dungeon_palette_inspection_test.cc index e12202cd..98ce049b 100644 --- a/test/inspection/dungeon_palette_inspection_test.cc +++ b/test/inspection/dungeon_palette_inspection_test.cc @@ -1,6 +1,10 @@ #include + +#include + #include "rom/rom.h" #include "app/gfx/types/snes_palette.h" +#include "test/test_utils.h" #include "util/log.h" namespace yaze { @@ -10,7 +14,10 @@ namespace test { TEST(DungeonPaletteInspection, VerifyColors) { // Load ROM Rom rom; - auto load_result = rom.LoadFromFile("zelda3.sfc"); + TestRomManager::SkipIfRomMissing(RomRole::kVanilla, + "DungeonPaletteInspection"); + const std::string rom_path = TestRomManager::GetRomPath(RomRole::kVanilla); + auto load_result = rom.LoadFromFile(rom_path); if (!load_result.ok()) { GTEST_SKIP() << "ROM file not found, skipping palette inspection"; } diff --git a/test/integration/dungeon_editor_test.h b/test/integration/dungeon_editor_test.h index 29341d16..b356162b 100644 --- a/test/integration/dungeon_editor_test.h +++ b/test/integration/dungeon_editor_test.h @@ -7,6 +7,7 @@ #include "app/editor/dungeon/dungeon_editor_v2.h" #include "rom/rom.h" #include "gtest/gtest.h" +#include "test/test_utils.h" #include "zelda3/dungeon/room.h" #include "zelda3/game_data.h" @@ -21,16 +22,12 @@ namespace test { class DungeonEditorIntegrationTest : public ::testing::Test { protected: void SetUp() override { - // Use the real ROM (try multiple locations) + TestRomManager::SkipIfRomMissing(RomRole::kVanilla, + "DungeonEditorIntegrationTest"); rom_ = std::make_unique(); - auto status = rom_->LoadFromFile("assets/zelda3.sfc"); - if (!status.ok()) { - status = rom_->LoadFromFile("build/bin/zelda3.sfc"); - } - if (!status.ok()) { - status = rom_->LoadFromFile("zelda3.sfc"); - } - ASSERT_TRUE(status.ok()) << "Could not load zelda3.sfc from any location"; + const std::string rom_path = TestRomManager::GetRomPath(RomRole::kVanilla); + auto status = rom_->LoadFromFile(rom_path); + ASSERT_TRUE(status.ok()) << "Could not load ROM from " << rom_path; // Load Zelda3-specific game data game_data_ = std::make_unique(rom_.get()); diff --git a/test/integration/dungeon_editor_v2_test.h b/test/integration/dungeon_editor_v2_test.h index eb503a98..b9ddb10b 100644 --- a/test/integration/dungeon_editor_v2_test.h +++ b/test/integration/dungeon_editor_v2_test.h @@ -9,6 +9,7 @@ #include "rom/snes.h" #include "gtest/gtest.h" #include "imgui.h" +#include "test/test_utils.h" #include "zelda3/game_data.h" #include "zelda3/dungeon/dungeon_rom_addresses.h" #include "framework/headless_editor_test.h" @@ -26,22 +27,12 @@ class DungeonEditorV2IntegrationTest : public HeadlessEditorTest { void SetUp() override { HeadlessEditorTest::SetUp(); - // Use the real ROM (try multiple locations) - // We use the base class helper but need to handle the path logic - // TODO: Make LoadRom return status or boolean to allow fallbacks - // For now, we'll just try to load directly - - // Try loading from standard locations - const char* paths[] = {"assets/zelda3.sfc", "build/bin/zelda3.sfc", "zelda3.sfc"}; - bool loaded = false; - for (const char* path : paths) { - rom_ = std::make_unique(); - if (rom_->LoadFromFile(path).ok()) { - loaded = true; - break; - } - } - ASSERT_TRUE(loaded) << "Could not load zelda3.sfc from any location"; + TestRomManager::SkipIfRomMissing(RomRole::kVanilla, + "DungeonEditorV2IntegrationTest"); + const std::string rom_path = TestRomManager::GetRomPath(RomRole::kVanilla); + rom_ = std::make_unique(); + ASSERT_TRUE(rom_->LoadFromFile(rom_path).ok()) + << "Could not load ROM from " << rom_path; // Patch ROM to ensure Room 0 and Room 1 sprite pointers are sequential // This fixes "Cannot determine available sprite space" error if the loaded ROM is non-standard diff --git a/test/integration/editor/tile16_editor_test.cc b/test/integration/editor/tile16_editor_test.cc index 250efd37..e0b69677 100644 --- a/test/integration/editor/tile16_editor_test.cc +++ b/test/integration/editor/tile16_editor_test.cc @@ -4,6 +4,7 @@ #include #include +#include #include #include "app/gfx/backend/renderer_factory.h" @@ -12,6 +13,7 @@ #include "app/gfx/resource/arena.h" #include "app/platform/window.h" #include "rom/rom.h" +#include "test/test_utils.h" #include "zelda3/overworld/overworld.h" namespace yaze { @@ -42,7 +44,12 @@ class Tile16EditorIntegrationTest : public ::testing::Test { // Load the test ROM rom_ = std::make_unique(); - auto load_result = rom_->LoadFromFile(YAZE_TEST_ROM_PATH); + yaze::test::TestRomManager::SkipIfRomMissing( + yaze::test::RomRole::kVanilla, + "Tile16EditorIntegrationTest"); + const std::string rom_path = + yaze::test::TestRomManager::GetRomPath(yaze::test::RomRole::kVanilla); + auto load_result = rom_->LoadFromFile(rom_path); ASSERT_TRUE(load_result.ok()) << "Failed to load test ROM: " << load_result.message(); diff --git a/test/integration/overworld_editor_test.h b/test/integration/overworld_editor_test.h index 9a0a2619..673f7657 100644 --- a/test/integration/overworld_editor_test.h +++ b/test/integration/overworld_editor_test.h @@ -1,10 +1,13 @@ #pragma once +#include + #include "framework/headless_editor_test.h" #include "app/editor/overworld/overworld_editor.h" #include "rom/rom.h" #include "rom/snes.h" #include "gtest/gtest.h" +#include "test/test_utils.h" #include "zelda3/game_data.h" namespace yaze { @@ -16,16 +19,11 @@ class OverworldEditorTest : public HeadlessEditorTest { HeadlessEditorTest::SetUp(); // Load ROM - const char* paths[] = {"assets/zelda3.sfc", "build/bin/zelda3.sfc", "zelda3.sfc"}; - bool loaded = false; - for (const char* path : paths) { - rom_ = std::make_unique(); - if (rom_->LoadFromFile(path).ok()) { - loaded = true; - break; - } - } - ASSERT_TRUE(loaded) << "Could not load zelda3.sfc from any location"; + TestRomManager::SkipIfRomMissing(RomRole::kVanilla, "OverworldEditorTest"); + const std::string rom_path = TestRomManager::GetRomPath(RomRole::kVanilla); + rom_ = std::make_unique(); + ASSERT_TRUE(rom_->LoadFromFile(rom_path).ok()) + << "Could not load ROM from " << rom_path; // Load GameData game_data_ = std::make_unique(rom_.get()); diff --git a/test/integration/zelda3/message_test.cc b/test/integration/zelda3/message_test.cc index 3be8a41d..e409d6ee 100644 --- a/test/integration/zelda3/message_test.cc +++ b/test/integration/zelda3/message_test.cc @@ -1,9 +1,10 @@ #include -#include +#include #include "app/editor/message/message_data.h" #include "app/editor/message/message_editor.h" +#include "test/test_utils.h" #include "testing.h" namespace yaze { @@ -12,17 +13,8 @@ namespace test { class MessageRomTest : public ::testing::Test { protected: void SetUp() override { - // Skip tests if ROM is not available - if (getenv("YAZE_SKIP_ROM_TESTS")) { - GTEST_SKIP() << "ROM tests disabled"; - } - - // Check if ROM file exists - std::string rom_path = "zelda3.sfc"; - if (!std::filesystem::exists(rom_path)) { - GTEST_SKIP() << "Test ROM not found: " << rom_path; - } - + TestRomManager::SkipIfRomMissing(RomRole::kVanilla, "MessageRomTest"); + const std::string rom_path = TestRomManager::GetRomPath(RomRole::kVanilla); EXPECT_OK(rom_.LoadFromFile(rom_path)); dictionary_ = editor::BuildDictionaryEntries(&rom_); } diff --git a/test/integration/zelda3/music_integration_test.cc b/test/integration/zelda3/music_integration_test.cc index 54134e95..e81c7e7d 100644 --- a/test/integration/zelda3/music_integration_test.cc +++ b/test/integration/zelda3/music_integration_test.cc @@ -4,8 +4,11 @@ #include #include +#include + #include "app/emu/emulator.h" #include "rom/rom.h" +#include "test/test_utils.h" #include "zelda3/music/music_bank.h" #include "zelda3/music/song_data.h" #include "zelda3/music/spc_parser.h" @@ -25,12 +28,10 @@ class MusicIntegrationTest : public ::testing::Test { void SetUp() override { rom_ = std::make_unique(); - // Check if ROM file exists - const char* rom_path = std::getenv("YAZE_TEST_ROM_PATH"); - if (!rom_path) { - rom_path = "zelda3.sfc"; - } - + yaze::test::TestRomManager::SkipIfRomMissing( + yaze::test::RomRole::kVanilla, "MusicIntegrationTest"); + const std::string rom_path = + yaze::test::TestRomManager::GetRomPath(yaze::test::RomRole::kVanilla); auto status = rom_->LoadFromFile(rom_path); if (!status.ok()) { GTEST_SKIP() << "ROM file not available: " << status.message(); diff --git a/test/integration/zelda3/sprite_position_test.cc b/test/integration/zelda3/sprite_position_test.cc index e3feae48..729608db 100644 --- a/test/integration/zelda3/sprite_position_test.cc +++ b/test/integration/zelda3/sprite_position_test.cc @@ -1,11 +1,12 @@ #include -#include #include #include #include +#include #include "rom/rom.h" +#include "test/test_utils.h" #include "zelda3/overworld/overworld.h" #include "zelda3/overworld/overworld_map.h" @@ -15,19 +16,13 @@ namespace zelda3 { class SpritePositionTest : public ::testing::Test { protected: void SetUp() override { - // Try to load a vanilla ROM for testing rom_ = std::make_unique(); - std::string rom_path = "bin/zelda3.sfc"; - - // Check if ROM exists in build directory - std::ifstream rom_file(rom_path); - if (rom_file.good()) { - ASSERT_TRUE(rom_->LoadFromFile(rom_path).ok()) - << "Failed to load ROM from " << rom_path; - } else { - // Skip test if ROM not found - GTEST_SKIP() << "ROM file not found at " << rom_path; - } + yaze::test::TestRomManager::SkipIfRomMissing( + yaze::test::RomRole::kVanilla, "SpritePositionTest"); + const std::string rom_path = + yaze::test::TestRomManager::GetRomPath(yaze::test::RomRole::kVanilla); + ASSERT_TRUE(rom_->LoadFromFile(rom_path).ok()) + << "Failed to load ROM from " << rom_path; overworld_ = std::make_unique(rom_.get()); ASSERT_TRUE(overworld_->Load(rom_.get()).ok()) diff --git a/test/test.cmake b/test/test.cmake index 7fc15a2b..6a6e27dd 100644 --- a/test/test.cmake +++ b/test/test.cmake @@ -54,7 +54,7 @@ endif() # # For CI/CD, use the test runner with appropriate filters: # ./yaze_test --unit --verbose -# ./yaze_test --e2e --rom-path zelda3.sfc +# ./yaze_test --e2e --rom-vanilla roms/alttp_vanilla.sfc # ./yaze_test --zscustomoverworld --verbose # ============================================================================= diff --git a/test/test_utils.h b/test/test_utils.h index ae5e617f..edb186f4 100644 --- a/test/test_utils.h +++ b/test/test_utils.h @@ -1,26 +1,33 @@ #ifndef YAZE_TEST_TEST_UTILS_H #define YAZE_TEST_TEST_UTILS_H -#ifndef IMGUI_DEFINE_MATH_OPERATORS -#define IMGUI_DEFINE_MATH_OPERATORS -#endif - #include #include #include #include +#include #include +#include #include #include #include "absl/strings/str_format.h" #include "rom/rom.h" -#include "imgui_test_engine/imgui_te_context.h" + +struct ImGuiTestContext; namespace yaze { namespace test { +enum class RomRole { + kVanilla, + kUs, + kJp, + kEu, + kExpanded, +}; + /** * @brief Utility class for handling test ROM files */ @@ -32,15 +39,7 @@ class TestRomManager { * @brief Auto-discover a ROM file from common locations * @return Path to discovered ROM, or empty string if none found */ - static std::string AutoDiscoverRom() { - // Common ROM filenames to look for - static const std::vector kRomNames = { - "zelda3.sfc", - "alttp_vanilla.sfc", - "vanilla.sfc", - "Legend of Zelda, The - A Link to the Past (USA).sfc", - }; - + static std::string AutoDiscoverRom(const std::vector& rom_names) { // Common directories to search (relative to working directory) static const std::vector kSearchPaths = { ".", @@ -50,7 +49,7 @@ class TestRomManager { }; for (const auto& dir : kSearchPaths) { - for (const auto& name : kRomNames) { + for (const auto& name : rom_names) { std::filesystem::path path = std::filesystem::path(dir) / name; if (std::filesystem::exists(path)) { return path.string(); @@ -66,7 +65,10 @@ class TestRomManager { * @return True if ROM tests can be run */ static bool IsRomTestingEnabled() { - return !GetTestRomPath().empty() && std::filesystem::exists(GetTestRomPath()); + if (std::getenv("YAZE_SKIP_ROM_TESTS")) { + return false; + } + return HasRom(RomRole::kVanilla); } /** @@ -74,21 +76,131 @@ class TestRomManager { * @return Path to the test ROM */ static std::string GetTestRomPath() { - // Check environment variable first (set by --rom-path argument) - if (const char* env_path = std::getenv("YAZE_TEST_ROM_PATH")) { - if (std::filesystem::exists(env_path)) { - return env_path; + return GetRomPath(RomRole::kVanilla); + } + + /** + * @brief Get the path to a ROM role (vanilla/expanded/region) + * @return Path to the ROM, or empty if not found + */ + static std::string GetRomPath(RomRole role) { + switch (role) { + case RomRole::kVanilla: { + const auto env_path = GetEnvRomPath( + {"YAZE_TEST_ROM_VANILLA", "YAZE_TEST_ROM_VANILLA_PATH", + "YAZE_TEST_ROM_PATH"}); + if (!env_path.empty()) { + return env_path; + } + const auto compile_path = GetCompileRomPath(role); + if (!compile_path.empty()) { + return compile_path; + } + static const std::vector kVanillaNames = { + "alttp_vanilla.sfc", + "Legend of Zelda, The - A Link to the Past (USA).sfc", + }; + return AutoDiscoverRom(kVanillaNames); } + case RomRole::kUs: { + const auto env_path = GetEnvRomPath( + {"YAZE_TEST_ROM_US", "YAZE_TEST_ROM_US_PATH"}); + if (!env_path.empty()) { + return env_path; + } + return GetCompileRomPath(role); + } + case RomRole::kJp: { + const auto env_path = GetEnvRomPath( + {"YAZE_TEST_ROM_JP", "YAZE_TEST_ROM_JP_PATH"}); + if (!env_path.empty()) { + return env_path; + } + return GetCompileRomPath(role); + } + case RomRole::kEu: { + const auto env_path = GetEnvRomPath( + {"YAZE_TEST_ROM_EU", "YAZE_TEST_ROM_EU_PATH"}); + if (!env_path.empty()) { + return env_path; + } + return GetCompileRomPath(role); + } + case RomRole::kExpanded: { + const auto env_path = + GetEnvRomPath({"YAZE_TEST_ROM_EXPANDED", "YAZE_TEST_ROM_OOS", + "YAZE_TEST_ROM_EXPANDED_PATH"}); + if (!env_path.empty()) { + return env_path; + } + return GetCompileRomPath(role); + } + default: + return ""; } + } -#ifdef YAZE_TEST_ROM_PATH - if (std::filesystem::exists(YAZE_TEST_ROM_PATH)) { - return YAZE_TEST_ROM_PATH; + /** + * @brief Check if a ROM exists for the specified role + */ + static bool HasRom(RomRole role) { + const auto rom_path = GetRomPath(role); + return !rom_path.empty() && std::filesystem::exists(rom_path); + } + + /** + * @brief Skip test if the requested ROM role is not available + */ + static void SkipIfRomMissing(RomRole role, const std::string& test_name) { + if (std::getenv("YAZE_SKIP_ROM_TESTS")) { + GTEST_SKIP() << "ROM testing disabled via YAZE_SKIP_ROM_TESTS. Test: " + << test_name; } -#endif + if (!HasRom(role)) { + GTEST_SKIP() << "ROM not found for role " << GetRomRoleName(role) + << ". Test: " << test_name << ". " + << GetRomRoleHint(role); + } + } - // Auto-discover ROM from common locations - return AutoDiscoverRom(); + /** + * @brief Human-friendly role name for logging + */ + static const char* GetRomRoleName(RomRole role) { + switch (role) { + case RomRole::kVanilla: + return "vanilla"; + case RomRole::kUs: + return "us"; + case RomRole::kJp: + return "jp"; + case RomRole::kEu: + return "eu"; + case RomRole::kExpanded: + return "expanded"; + default: + return "unknown"; + } + } + + /** + * @brief Guidance for setting the correct ROM path env vars + */ + static std::string GetRomRoleHint(RomRole role) { + switch (role) { + case RomRole::kVanilla: + return "Set YAZE_TEST_ROM_VANILLA or YAZE_TEST_ROM_PATH."; + case RomRole::kUs: + return "Set YAZE_TEST_ROM_US."; + case RomRole::kJp: + return "Set YAZE_TEST_ROM_JP."; + case RomRole::kEu: + return "Set YAZE_TEST_ROM_EU."; + case RomRole::kExpanded: + return "Set YAZE_TEST_ROM_EXPANDED or YAZE_TEST_ROM_OOS."; + default: + return "Set the appropriate YAZE_TEST_ROM_* env var."; + } } /** @@ -168,10 +280,66 @@ class TestRomManager { * @param test_name Name of the test for logging */ static void SkipIfRomTestingDisabled(const std::string& test_name) { - if (!IsRomTestingEnabled()) { - GTEST_SKIP() << "ROM testing disabled or ROM file not found. " - << "Test: " << test_name - << " requires: " << GetTestRomPath(); + SkipIfRomMissing(RomRole::kVanilla, test_name); + } + + private: + static std::string GetEnvRomPath( + std::initializer_list env_vars) { + for (const char* env_var : env_vars) { + if (const char* env_path = std::getenv(env_var)) { + if (std::filesystem::exists(env_path)) { + return env_path; + } + } + } + return ""; + } + + static std::string GetCompileRomPath(RomRole role) { + switch (role) { + case RomRole::kVanilla: +#ifdef YAZE_TEST_ROM_VANILLA_PATH + if (std::filesystem::exists(YAZE_TEST_ROM_VANILLA_PATH)) { + return YAZE_TEST_ROM_VANILLA_PATH; + } +#endif +#ifdef YAZE_TEST_ROM_PATH + if (std::filesystem::exists(YAZE_TEST_ROM_PATH)) { + return YAZE_TEST_ROM_PATH; + } +#endif + return ""; + case RomRole::kUs: +#ifdef YAZE_TEST_ROM_US_PATH + if (std::filesystem::exists(YAZE_TEST_ROM_US_PATH)) { + return YAZE_TEST_ROM_US_PATH; + } +#endif + return ""; + case RomRole::kJp: +#ifdef YAZE_TEST_ROM_JP_PATH + if (std::filesystem::exists(YAZE_TEST_ROM_JP_PATH)) { + return YAZE_TEST_ROM_JP_PATH; + } +#endif + return ""; + case RomRole::kEu: +#ifdef YAZE_TEST_ROM_EU_PATH + if (std::filesystem::exists(YAZE_TEST_ROM_EU_PATH)) { + return YAZE_TEST_ROM_EU_PATH; + } +#endif + return ""; + case RomRole::kExpanded: +#ifdef YAZE_TEST_ROM_EXPANDED_PATH + if (std::filesystem::exists(YAZE_TEST_ROM_EXPANDED_PATH)) { + return YAZE_TEST_ROM_EXPANDED_PATH; + } +#endif + return ""; + default: + return ""; } } }; @@ -192,7 +360,7 @@ class TestRomManager::BoundRomTest : public ::testing::Test { const Rom* rom() const { return rom_instance_.get(); } std::string GetBoundRomPath() const { - return TestRomManager::GetTestRomPath(); + return TestRomManager::GetRomPath(RomRole::kVanilla); } private: @@ -203,7 +371,7 @@ class TestRomManager::BoundRomTest : public ::testing::Test { if (rom_loaded_) { return; } - const std::string rom_path = TestRomManager::GetTestRomPath(); + const std::string rom_path = TestRomManager::GetRomPath(RomRole::kVanilla); ASSERT_TRUE(rom_instance_->LoadFromFile(rom_path).ok()) << "Failed to load test ROM from " << rom_path; rom_loaded_ = true; diff --git a/test/test_utils/rom_integrity_validator.h b/test/test_utils/rom_integrity_validator.h index a6e04ecc..ff77d3af 100644 --- a/test/test_utils/rom_integrity_validator.h +++ b/test/test_utils/rom_integrity_validator.h @@ -60,7 +60,7 @@ struct ValidationResult { * Example usage: * @code * Rom rom; - * rom.LoadFromFile("zelda3.sfc"); + * rom.LoadFromFile("roms/alttp_vanilla.sfc"); * * // Make edits... * rom.WriteByte(0x1234, 0x42); diff --git a/test/unit/rom/rom_test.cc b/test/unit/rom/rom_test.cc index e3b72b70..24101e01 100644 --- a/test/unit/rom/rom_test.cc +++ b/test/unit/rom/rom_test.cc @@ -3,10 +3,15 @@ #include #include +#include +#include +#include + #include "absl/status/status.h" #include "absl/status/statusor.h" #include "rom/transaction.h" #include "mocks/mock_rom.h" +#include "test/test_utils.h" #include "testing.h" namespace yaze { @@ -35,7 +40,9 @@ TEST_F(RomTest, LoadFromFile) { #if defined(__linux__) GTEST_SKIP() << "ROM file loading skipped on Linux CI (no ROM available)"; #endif - EXPECT_OK(rom_.LoadFromFile("zelda3.sfc")); + TestRomManager::SkipIfRomMissing(RomRole::kVanilla, "RomTest.LoadFromFile"); + const std::string rom_path = TestRomManager::GetRomPath(RomRole::kVanilla); + EXPECT_OK(rom_.LoadFromFile(rom_path)); EXPECT_EQ(rom_.size(), 0x200000); EXPECT_NE(rom_.data(), nullptr); } @@ -64,7 +71,7 @@ TEST_F(RomTest, ReadByteOk) { TEST_F(RomTest, ReadByteInvalid) { EXPECT_THAT(rom_.ReadByte(0).status(), - StatusIs(absl::StatusCode::kFailedPrecondition)); + StatusIs(absl::StatusCode::kOutOfRange)); } TEST_F(RomTest, ReadWordOk) { @@ -80,7 +87,7 @@ TEST_F(RomTest, ReadWordOk) { TEST_F(RomTest, ReadWordInvalid) { EXPECT_THAT(rom_.ReadWord(0).status(), - StatusIs(absl::StatusCode::kFailedPrecondition)); + StatusIs(absl::StatusCode::kOutOfRange)); } TEST_F(RomTest, ReadLongOk) { @@ -188,8 +195,8 @@ TEST_F(RomTest, ReadTransactionFailure) { EXPECT_OK(mock_rom.LoadFromData(kMockRomData)); uint8_t byte_val; - EXPECT_EQ(mock_rom.ReadTransaction(byte_val, 0x1000), - absl::FailedPreconditionError("Offset out of range")); + EXPECT_THAT(mock_rom.ReadTransaction(byte_val, 0x1000), + StatusIs(absl::StatusCode::kOutOfRange)); } TEST_F(RomTest, SaveTruncatesExistingFile) { @@ -213,12 +220,13 @@ TEST_F(RomTest, SaveTruncatesExistingFile) { // Load the saved file and verify size equals original data size and first // byte matches - Rom verify; - EXPECT_OK(verify.LoadFromFile(tmp_name)); - EXPECT_EQ(verify.size(), kMockRomData.size()); - auto b0 = verify.ReadByte(0); - ASSERT_TRUE(b0.ok()); - EXPECT_EQ(*b0, 0xEE); + std::ifstream verify(tmp_name, std::ios::binary); + ASSERT_TRUE(verify.is_open()); + std::vector file_bytes((std::istreambuf_iterator(verify)), + std::istreambuf_iterator()); + EXPECT_EQ(file_bytes.size(), kMockRomData.size()); + ASSERT_FALSE(file_bytes.empty()); + EXPECT_EQ(file_bytes[0], 0xEE); } TEST_F(RomTest, TransactionRollbackRestoresOriginals) { diff --git a/test/yaze_test.cc b/test/yaze_test.cc index 2beaac19..f5c9aa46 100644 --- a/test/yaze_test.cc +++ b/test/yaze_test.cc @@ -51,7 +51,12 @@ enum class TestMode { struct TestConfig { TestMode mode = TestMode::kAll; std::string test_pattern; - std::string rom_path = "zelda3.sfc"; + std::string rom_path; + std::string rom_vanilla; + std::string rom_us; + std::string rom_jp; + std::string rom_eu; + std::string rom_expanded; bool verbose = false; bool skip_rom_tests = false; bool enable_ui_tests = false; @@ -69,7 +74,12 @@ TestConfig ParseArguments(int argc, char* argv[]) { << " --fast : Run tests at max speed (default)\n" << " --normal : Run tests at watchable speed\n" << " --cinematic : Run tests in slow-motion with pauses\n" - << " --rom= : Specify ROM file path\n" + << " --rom= : Legacy ROM path (vanilla)\n" + << " --rom-vanilla=\n" + << " --rom-us=\n" + << " --rom-jp=\n" + << " --rom-eu=\n" + << " --rom-expanded=\n" << " --pattern= : Run tests matching pattern\n" << std::endl; @@ -91,13 +101,18 @@ TestConfig ParseArguments(int argc, char* argv[]) { std::cout << " --deprecated Run deprecated tests\n\n"; std::cout << "Options:\n"; std::cout << " --rom-path PATH Specify ROM path for testing\n"; + std::cout << " --rom-vanilla PATH Specify vanilla ROM path\n"; + std::cout << " --rom-us PATH Specify US ROM path\n"; + std::cout << " --rom-jp PATH Specify JP ROM path\n"; + std::cout << " --rom-eu PATH Specify EU ROM path\n"; + std::cout << " --rom-expanded PATH Specify expanded ROM path (ZSCustom/OOS)\n"; std::cout << " --skip-rom-tests Skip tests requiring ROM files\n"; std::cout << " --enable-ui-tests Enable UI tests (requires display)\n"; std::cout << " --verbose Enable verbose output\n"; std::cout << " --help Show this help message\n\n"; std::cout << "Examples:\n"; std::cout << " yaze_test --unit --verbose\n"; - std::cout << " yaze_test --e2e --rom-path my_rom.sfc\n"; + std::cout << " yaze_test --e2e --rom-vanilla my_rom.sfc\n"; std::cout << " yaze_test --zscustomoverworld --verbose\n"; std::cout << " yaze_test RomTest.*\n"; exit(0); @@ -119,10 +134,46 @@ TestConfig ParseArguments(int argc, char* argv[]) { config.mode = TestMode::kEditor; } else if (arg == "--deprecated") { config.mode = TestMode::kDeprecated; - } else if (arg == "--rom-path") { + } else if (arg == "--rom-path" || arg == "--rom") { if (i + 1 < argc) { config.rom_path = argv[++i]; } + } else if (arg.rfind("--rom-path=", 0) == 0) { + config.rom_path = arg.substr(std::string("--rom-path=").size()); + } else if (arg.rfind("--rom=", 0) == 0) { + config.rom_path = arg.substr(std::string("--rom=").size()); + } else if (arg == "--rom-vanilla") { + if (i + 1 < argc) { + config.rom_vanilla = argv[++i]; + } + } else if (arg.rfind("--rom-vanilla=", 0) == 0) { + config.rom_vanilla = arg.substr(std::string("--rom-vanilla=").size()); + } else if (arg == "--rom-us") { + if (i + 1 < argc) { + config.rom_us = argv[++i]; + } + } else if (arg.rfind("--rom-us=", 0) == 0) { + config.rom_us = arg.substr(std::string("--rom-us=").size()); + } else if (arg == "--rom-jp") { + if (i + 1 < argc) { + config.rom_jp = argv[++i]; + } + } else if (arg.rfind("--rom-jp=", 0) == 0) { + config.rom_jp = arg.substr(std::string("--rom-jp=").size()); + } else if (arg == "--rom-eu") { + if (i + 1 < argc) { + config.rom_eu = argv[++i]; + } + } else if (arg.rfind("--rom-eu=", 0) == 0) { + config.rom_eu = arg.substr(std::string("--rom-eu=").size()); + } else if (arg == "--rom-expanded" || arg == "--rom-oos") { + if (i + 1 < argc) { + config.rom_expanded = argv[++i]; + } + } else if (arg.rfind("--rom-expanded=", 0) == 0) { + config.rom_expanded = arg.substr(std::string("--rom-expanded=").size()); + } else if (arg.rfind("--rom-oos=", 0) == 0) { + config.rom_expanded = arg.substr(std::string("--rom-oos=").size()); } else if (arg == "--skip-rom-tests") { config.skip_rom_tests = true; } else if (arg == "--enable-ui-tests") { @@ -154,6 +205,32 @@ void SetupTestEnvironment(const TestConfig& config) { // Set environment variables for tests using SDL's cross-platform function if (!config.rom_path.empty()) { SDL_setenv("YAZE_TEST_ROM_PATH", config.rom_path.c_str(), 1); + if (config.rom_vanilla.empty()) { + SDL_setenv("YAZE_TEST_ROM_VANILLA", config.rom_path.c_str(), 1); + } + } + if (!config.rom_vanilla.empty()) { + SDL_setenv("YAZE_TEST_ROM_VANILLA", config.rom_vanilla.c_str(), 1); + if (config.rom_path.empty()) { + SDL_setenv("YAZE_TEST_ROM_PATH", config.rom_vanilla.c_str(), 1); + } + } + if (!config.rom_us.empty()) { + SDL_setenv("YAZE_TEST_ROM_US", config.rom_us.c_str(), 1); + SDL_setenv("YAZE_TEST_ROM_US_PATH", config.rom_us.c_str(), 1); + } + if (!config.rom_jp.empty()) { + SDL_setenv("YAZE_TEST_ROM_JP", config.rom_jp.c_str(), 1); + SDL_setenv("YAZE_TEST_ROM_JP_PATH", config.rom_jp.c_str(), 1); + } + if (!config.rom_eu.empty()) { + SDL_setenv("YAZE_TEST_ROM_EU", config.rom_eu.c_str(), 1); + SDL_setenv("YAZE_TEST_ROM_EU_PATH", config.rom_eu.c_str(), 1); + } + if (!config.rom_expanded.empty()) { + SDL_setenv("YAZE_TEST_ROM_EXPANDED", config.rom_expanded.c_str(), 1); + SDL_setenv("YAZE_TEST_ROM_OOS", config.rom_expanded.c_str(), 1); + SDL_setenv("YAZE_TEST_ROM_EXPANDED_PATH", config.rom_expanded.c_str(), 1); } if (config.skip_rom_tests) { @@ -379,4 +456,4 @@ int main(int argc, char* argv[]) { return result; } -} \ No newline at end of file +}