yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
overworld_editor_test_suite.h
Go to the documentation of this file.
1#ifndef YAZE_APP_TEST_OVERWORLD_EDITOR_TEST_SUITE_H
2#define YAZE_APP_TEST_OVERWORLD_EDITOR_TEST_SUITE_H
3
4#include <chrono>
5#include <vector>
6
7#include "absl/strings/str_format.h"
11#include "rom/rom.h"
12#include "zelda3/game_data.h"
13
14namespace yaze {
15namespace test {
16
18 public:
20 ~OverworldEditorTestSuite() override = default;
21
22 std::string GetName() const override { return "Overworld Editor Tests"; }
23 TestCategory GetCategory() const override {
25 }
26
27 absl::Status RunTests(TestResults& results) override {
28 Rom* current_rom = TestManager::Get().GetCurrentRom();
29
30 if (!current_rom || !current_rom->is_loaded()) {
31 AddSkippedTest(results, "Overworld_Editor_Check", "No ROM loaded");
32 return absl::OkStatus();
33 }
34
36 RunTilePlacementTest(results, current_rom);
37 }
38
40 RunEntityManipulationTest(results, current_rom);
41 }
42
43 return absl::OkStatus();
44 }
45
46 void DrawConfiguration() override {
47 ImGui::Text("%s Overworld Editor Test Configuration", ICON_MD_MAP);
48 ImGui::Separator();
49 ImGui::Checkbox("Test Tile Placement", &test_tile_placement_);
50 ImGui::Checkbox("Test Entity Manipulation", &test_entity_manipulation_);
51 }
52
53 private:
54 void AddSkippedTest(TestResults& results, const std::string& test_name,
55 const std::string& reason) {
56 TestResult result;
57 result.name = test_name;
58 result.suite_name = GetName();
59 result.category = GetCategory();
61 result.error_message = reason;
62 result.duration = std::chrono::milliseconds{0};
63 result.timestamp = std::chrono::steady_clock::now();
64 results.AddResult(result);
65 }
66
67 void RunTilePlacementTest(TestResults& results, Rom* rom) {
68 auto start_time = std::chrono::steady_clock::now();
69
70 TestResult result;
71 result.name = "Overworld_Tile_Placement";
72 result.suite_name = GetName();
73 result.category = GetCategory();
74 result.timestamp = start_time;
75
76 try {
77 auto& test_manager = TestManager::Get();
78 auto test_status =
79 test_manager.TestRomWithCopy(rom, [&](Rom* test_rom) -> absl::Status {
80 zelda3::GameData game_data;
81 RETURN_IF_ERROR(zelda3::LoadGameData(*test_rom, game_data));
82
83 editor::OverworldEditor editor(test_rom);
84 editor.SetGameData(&game_data);
85
86 // Initialize and Load to populate internal structures
87 editor.Initialize();
88 RETURN_IF_ERROR(editor.Load());
89
90 // Test placing a tile on Map 0 (Light World Link's House area)
91 int map_id = 0;
92 editor.set_current_map(map_id);
93
94 // Use Automation API for tile placement (x,y in 16x16 tile coordinates)
95 int test_tile_x = 10;
96 int test_tile_y = 10;
97 int new_tile_id = 0x0123; // Some arbitrary valid tile ID
98
99 // Note: AutomationSetTile internally handles the coordinates
100 // based on the current map and world.
101 bool success = editor.AutomationSetTile(test_tile_x, test_tile_y, new_tile_id);
102 if (!success) {
103 return absl::InternalError("AutomationSetTile failed");
104 }
105
106 // Verify the tile was set in the data layer
107 int actual_tile = editor.AutomationGetTile(test_tile_x, test_tile_y);
108 if (actual_tile != new_tile_id) {
109 return absl::InternalError(absl::StrFormat(
110 "Tile mismatch: expected 0x%04X, got 0x%04X", new_tile_id, actual_tile));
111 }
112
113 return absl::OkStatus();
114 });
115
116 if (test_status.ok()) {
118 result.error_message = "Overworld tile placement verified";
119 } else {
121 result.error_message = test_status.ToString();
122 }
123
124 } catch (const std::exception& e) {
126 result.error_message = std::string(e.what());
127 }
128
129 auto end_time = std::chrono::steady_clock::now();
130 result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
131 end_time - start_time);
132
133 results.AddResult(result);
134 }
135
137 auto start_time = std::chrono::steady_clock::now();
138
139 TestResult result;
140 result.name = "Overworld_Entity_Manipulation";
141 result.suite_name = GetName();
142 result.category = GetCategory();
143 result.timestamp = start_time;
144
145 try {
146 auto& test_manager = TestManager::Get();
147 auto test_status =
148 test_manager.TestRomWithCopy(rom, [&](Rom* test_rom) -> absl::Status {
149 zelda3::GameData game_data;
150 RETURN_IF_ERROR(zelda3::LoadGameData(*test_rom, game_data));
151
152 editor::OverworldEditor editor(test_rom);
153 editor.SetGameData(&game_data);
154 editor.Initialize();
155 RETURN_IF_ERROR(editor.Load());
156
157 // Test Map 0
158 editor.set_current_map(0);
159
160 auto* current_map_data = editor.overworld().current_map_data();
161 if (!current_map_data) {
162 return absl::InternalError("Failed to get current map data");
163 }
164
165 size_t initial_sprite_count = current_map_data->sprites().size();
166
167 // Simulate sprite insertion
168 // Note: HandleEntityInsertion usually relies on mouse pos for placement
169 // and opens a popup. For testing, we might need to use internal operations.
170 // Let's check if we can add a sprite directly to verify the data integrity.
171
172 zelda3::Sprite new_sprite;
173 new_sprite.set_id(0x01); // Green Soldier
174 new_sprite.set_x(100);
175 new_sprite.set_y(100);
176
177 current_map_data->mutable_sprites()->push_back(new_sprite);
178
179 if (current_map_data->sprites().size() != initial_sprite_count + 1) {
180 return absl::InternalError("Failed to add sprite to overworld map");
181 }
182
183 return absl::OkStatus();
184 });
185
186 if (test_status.ok()) {
188 result.error_message = "Overworld entity manipulation verified";
189 } else {
191 result.error_message = test_status.ToString();
192 }
193
194 } catch (const std::exception& e) {
196 result.error_message = std::string(e.what());
197 }
198
199 auto end_time = std::chrono::steady_clock::now();
200 result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
201 end_time - start_time);
202
203 results.AddResult(result);
204 }
205
208};
209
210} // namespace test
211} // namespace yaze
212
213#endif // YAZE_APP_TEST_OVERWORLD_EDITOR_TEST_SUITE_H
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:28
bool is_loaded() const
Definition rom.h:132
Main UI class for editing overworld maps in A Link to the Past.
void SetGameData(zelda3::GameData *game_data) override
void set_current_map(int map_id)
Set the current map for editing (also updates world)
bool AutomationSetTile(int x, int y, int tile_id)
Definition automation.cc:29
zelda3::Overworld & overworld()
Access the underlying Overworld data.
absl::Status Load() override
int AutomationGetTile(int x, int y)
Definition automation.cc:58
absl::Status RunTests(TestResults &results) override
void RunEntityManipulationTest(TestResults &results, Rom *rom)
void RunTilePlacementTest(TestResults &results, Rom *rom)
~OverworldEditorTestSuite() override=default
void AddSkippedTest(TestResults &results, const std::string &test_name, const std::string &reason)
Rom * GetCurrentRom() const
static TestManager & Get()
auto set_x(int x)
Definition common.h:62
auto set_y(int y)
Definition common.h:63
A class for managing sprites in the overworld and underworld.
Definition sprite.h:35
auto set_id(uint8_t id)
Definition sprite.h:96
#define ICON_MD_MAP
Definition icons.h:1173
absl::Status LoadGameData(Rom &rom, GameData &data, const LoadOptions &options)
Loads all Zelda3-specific game data from a generic ROM.
Definition game_data.cc:123
#define RETURN_IF_ERROR(expr)
Definition snes.cc:22
std::chrono::milliseconds duration
std::string error_message
std::chrono::time_point< std::chrono::steady_clock > timestamp
void AddResult(const TestResult &result)