yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
rom_dependent_test_suite.h
Go to the documentation of this file.
1#ifndef YAZE_APP_TEST_ROM_DEPENDENT_TEST_SUITE_H
2#define YAZE_APP_TEST_ROM_DEPENDENT_TEST_SUITE_H
3
4#include <chrono>
5#include <vector>
6
7#include "absl/strings/str_format.h"
9#include "app/rom.h"
12#include "app/gui/icons.h"
13
14namespace yaze {
15namespace test {
16
17// ROM-dependent test suite that works with the currently loaded ROM
19 public:
21 ~RomDependentTestSuite() override = default;
22
23 std::string GetName() const override { return "ROM-Dependent Tests"; }
25
26 absl::Status RunTests(TestResults& results) override {
27 Rom* current_rom = TestManager::Get().GetCurrentRom();
28
29 // Add detailed ROM availability check
30 TestResult rom_check_result;
31 rom_check_result.name = "ROM_Available_Check";
32 rom_check_result.suite_name = GetName();
33 rom_check_result.category = GetCategory();
34 rom_check_result.timestamp = std::chrono::steady_clock::now();
35
36 if (!current_rom) {
37 rom_check_result.status = TestStatus::kSkipped;
38 rom_check_result.error_message = "ROM pointer is null";
39 } else if (!current_rom->is_loaded()) {
40 rom_check_result.status = TestStatus::kSkipped;
41 rom_check_result.error_message = absl::StrFormat(
42 "ROM not loaded (ptr: %p, title: '%s', size: %zu)",
43 (void*)current_rom, current_rom->title().c_str(), current_rom->size());
44 } else {
45 rom_check_result.status = TestStatus::kPassed;
46 rom_check_result.error_message = absl::StrFormat(
47 "ROM loaded successfully (title: '%s', size: %.2f MB)",
48 current_rom->title().c_str(), current_rom->size() / 1048576.0f);
49 }
50
51 rom_check_result.duration = std::chrono::milliseconds{0};
52 results.AddResult(rom_check_result);
53
54 // If no ROM is available, skip other tests
55 if (!current_rom || !current_rom->is_loaded()) {
56 return absl::OkStatus();
57 }
58
59 // Run ROM-dependent tests (only if enabled)
60 auto& test_manager = TestManager::Get();
61
62 if (test_manager.IsTestEnabled("ROM_Header_Validation_Test")) {
63 RunRomHeaderValidationTest(results, current_rom);
64 } else {
65 AddSkippedTest(results, "ROM_Header_Validation_Test", "Test disabled by user");
66 }
67
68 if (test_manager.IsTestEnabled("ROM_Data_Access_Test")) {
69 RunRomDataAccessTest(results, current_rom);
70 } else {
71 AddSkippedTest(results, "ROM_Data_Access_Test", "Test disabled by user");
72 }
73
74 if (test_manager.IsTestEnabled("ROM_Graphics_Extraction_Test")) {
75 RunRomGraphicsExtractionTest(results, current_rom);
76 } else {
77 AddSkippedTest(results, "ROM_Graphics_Extraction_Test", "Test disabled by user");
78 }
79
80 if (test_manager.IsTestEnabled("ROM_Overworld_Loading_Test")) {
81 RunRomOverworldLoadingTest(results, current_rom);
82 } else {
83 AddSkippedTest(results, "ROM_Overworld_Loading_Test", "Test disabled by user");
84 }
85
86 if (test_manager.IsTestEnabled("Tile16_Editor_Test")) {
87 RunTile16EditorTest(results, current_rom);
88 } else {
89 AddSkippedTest(results, "Tile16_Editor_Test", "Test disabled by user");
90 }
91
92 if (test_manager.IsTestEnabled("Comprehensive_Save_Test")) {
93 RunComprehensiveSaveTest(results, current_rom);
94 } else {
95 AddSkippedTest(results, "Comprehensive_Save_Test", "Test disabled by user (known to crash)");
96 }
97
99 RunRomSpriteDataTest(results, current_rom);
100 RunRomMusicDataTest(results, current_rom);
101 }
102
103 return absl::OkStatus();
104 }
105
106 void DrawConfiguration() override {
107 Rom* current_rom = TestManager::Get().GetCurrentRom();
108
109 ImGui::Text("%s ROM-Dependent Test Configuration", ICON_MD_STORAGE);
110
111 if (current_rom && current_rom->is_loaded()) {
112 ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f),
113 "%s Current ROM: %s", ICON_MD_CHECK_CIRCLE, current_rom->title().c_str());
114 ImGui::Text("Size: %zu bytes", current_rom->size());
115 ImGui::Text("File: %s", current_rom->filename().c_str());
116 } else {
117 ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.0f, 1.0f),
118 "%s No ROM currently loaded", ICON_MD_WARNING);
119 ImGui::Text("Load a ROM in the editor to enable ROM-dependent tests");
120 }
121
122 ImGui::Separator();
123 ImGui::Checkbox("Test ROM header validation", &test_header_validation_);
124 ImGui::Checkbox("Test ROM data access", &test_data_access_);
125 ImGui::Checkbox("Test graphics extraction", &test_graphics_extraction_);
126 ImGui::Checkbox("Test overworld loading", &test_overworld_loading_);
127 ImGui::Checkbox("Test advanced features", &test_advanced_features_);
128
130 ImGui::Indent();
131 ImGui::Checkbox("Test sprite data", &test_sprite_data_);
132 ImGui::Checkbox("Test music data", &test_music_data_);
133 ImGui::Unindent();
134 }
135 }
136
137 private:
138 // Helper method to add skipped test results
139 void AddSkippedTest(TestResults& results, const std::string& test_name, const std::string& reason) {
140 TestResult result;
141 result.name = test_name;
142 result.suite_name = GetName();
143 result.category = GetCategory();
145 result.error_message = reason;
146 result.duration = std::chrono::milliseconds{0};
147 result.timestamp = std::chrono::steady_clock::now();
148 results.AddResult(result);
149 }
150
152 auto start_time = std::chrono::steady_clock::now();
153
154 TestResult result;
155 result.name = "ROM_Header_Validation_Test";
156 result.suite_name = GetName();
157 result.category = GetCategory();
158 result.timestamp = start_time;
159
162 result.error_message = "Header validation disabled in configuration";
163 } else {
164 try {
165 std::string title = rom->title();
166 size_t size = rom->size();
167
168 // Basic validation
169 bool valid_title = !title.empty() && title != "ZELDA3" && title.length() <= 21;
170 bool valid_size = size >= 1024*1024 && size <= 8*1024*1024; // 1MB to 8MB
171
172 if (valid_title && valid_size) {
174 result.error_message = absl::StrFormat(
175 "ROM header valid: '%s' (%zu bytes)", title.c_str(), size);
176 } else {
178 result.error_message = absl::StrFormat(
179 "ROM header validation failed: title='%s' size=%zu", title.c_str(), size);
180 }
181 } catch (const std::exception& e) {
183 result.error_message = "Header validation failed: " + std::string(e.what());
184 }
185 }
186
187 auto end_time = std::chrono::steady_clock::now();
188 result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
189 end_time - start_time);
190
191 results.AddResult(result);
192 }
193
194 void RunRomDataAccessTest(TestResults& results, Rom* rom) {
195 auto start_time = std::chrono::steady_clock::now();
196
197 TestResult result;
198 result.name = "ROM_Data_Access_Test";
199 result.suite_name = GetName();
200 result.category = GetCategory();
201 result.timestamp = start_time;
202
203 if (!test_data_access_) {
205 result.error_message = "Data access testing disabled in configuration";
206 } else {
207 try {
208 // Test basic ROM data access patterns
209 size_t bytes_tested = 0;
210 bool access_success = true;
211
212 // Test reading from various ROM regions
213 try {
214 [[maybe_unused]] auto header_byte = rom->ReadByte(0x7FC0);
215 bytes_tested++;
216 [[maybe_unused]] auto code_byte = rom->ReadByte(0x8000);
217 bytes_tested++;
218 [[maybe_unused]] auto data_word = rom->ReadWord(0x8002);
219 bytes_tested++;
220 } catch (...) {
221 access_success = false;
222 }
223
224 if (access_success && bytes_tested >= 3) {
226 result.error_message = absl::StrFormat(
227 "ROM data access verified: %zu operations", bytes_tested);
228 } else {
230 result.error_message = "ROM data access failed";
231 }
232 } catch (const std::exception& e) {
234 result.error_message = "Data access test failed: " + std::string(e.what());
235 }
236 }
237
238 auto end_time = std::chrono::steady_clock::now();
239 result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
240 end_time - start_time);
241
242 results.AddResult(result);
243 }
244
246 auto start_time = std::chrono::steady_clock::now();
247
248 TestResult result;
249 result.name = "ROM_Graphics_Extraction_Test";
250 result.suite_name = GetName();
251 result.category = GetCategory();
252 result.timestamp = start_time;
253
256 result.error_message = "Graphics extraction testing disabled in configuration";
257 } else {
258 try {
259 auto graphics_result = LoadAllGraphicsData(*rom);
260 if (graphics_result.ok()) {
261 auto& sheets = graphics_result.value();
262 size_t loaded_sheets = 0;
263 for (const auto& sheet : sheets) {
264 if (sheet.is_active()) {
265 loaded_sheets++;
266 }
267 }
268
270 result.error_message = absl::StrFormat(
271 "Graphics extraction successful: %zu/%zu sheets loaded",
272 loaded_sheets, sheets.size());
273 } else {
275 result.error_message = "Graphics extraction failed: " +
276 std::string(graphics_result.status().message());
277 }
278 } catch (const std::exception& e) {
280 result.error_message = "Graphics extraction test failed: " + std::string(e.what());
281 }
282 }
283
284 auto end_time = std::chrono::steady_clock::now();
285 result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
286 end_time - start_time);
287
288 results.AddResult(result);
289 }
290
292 auto start_time = std::chrono::steady_clock::now();
293
294 TestResult result;
295 result.name = "ROM_Overworld_Loading_Test";
296 result.suite_name = GetName();
297 result.category = GetCategory();
298 result.timestamp = start_time;
299
302 result.error_message = "Overworld loading testing disabled in configuration";
303 } else {
304 try {
305 zelda3::Overworld overworld(rom);
306 auto ow_status = overworld.Load(rom);
307
308 if (ow_status.ok()) {
310 result.error_message = "Overworld loading successful from current ROM";
311 } else {
313 result.error_message = "Overworld loading failed: " + std::string(ow_status.message());
314 }
315 } catch (const std::exception& e) {
317 result.error_message = "Overworld loading test failed: " + std::string(e.what());
318 }
319 }
320
321 auto end_time = std::chrono::steady_clock::now();
322 result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
323 end_time - start_time);
324
325 results.AddResult(result);
326 }
327
328 void RunRomSpriteDataTest(TestResults& results, Rom* rom) {
329 auto start_time = std::chrono::steady_clock::now();
330
331 TestResult result;
332 result.name = "ROM_Sprite_Data_Test";
333 result.suite_name = GetName();
334 result.category = GetCategory();
335 result.timestamp = start_time;
336
337 if (!test_sprite_data_) {
339 result.error_message = "Sprite data testing disabled in configuration";
340 } else {
341 try {
342 // Basic sprite data validation (simplified for now)
343 // In a full implementation, this would test sprite loading
345 result.error_message = "Sprite data testing not yet implemented";
346 } catch (const std::exception& e) {
348 result.error_message = "Sprite data test failed: " + std::string(e.what());
349 }
350 }
351
352 auto end_time = std::chrono::steady_clock::now();
353 result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
354 end_time - start_time);
355
356 results.AddResult(result);
357 }
358
359 void RunRomMusicDataTest(TestResults& results, Rom* rom) {
360 auto start_time = std::chrono::steady_clock::now();
361
362 TestResult result;
363 result.name = "ROM_Music_Data_Test";
364 result.suite_name = GetName();
365 result.category = GetCategory();
366 result.timestamp = start_time;
367
368 if (!test_music_data_) {
370 result.error_message = "Music data testing disabled in configuration";
371 } else {
372 try {
373 // Basic music data validation (simplified for now)
374 // In a full implementation, this would test music loading
376 result.error_message = "Music data testing not yet implemented";
377 } catch (const std::exception& e) {
379 result.error_message = "Music data test failed: " + std::string(e.what());
380 }
381 }
382
383 auto end_time = std::chrono::steady_clock::now();
384 result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
385 end_time - start_time);
386
387 results.AddResult(result);
388 }
389
390 void RunTile16EditorTest(TestResults& results, Rom* rom) {
391 auto start_time = std::chrono::steady_clock::now();
392
393 TestResult result;
394 result.name = "Tile16_Editor_Test";
395 result.suite_name = GetName();
396 result.category = GetCategory();
397 result.timestamp = start_time;
398
399 try {
400 // Verify ROM and palette data
401 if (rom->palette_group().overworld_main.size() > 0) {
402 // Test Tile16 editor functionality with real ROM data
403 editor::Tile16Editor tile16_editor(rom, nullptr);
404
405 // Create test bitmaps with realistic data
406 std::vector<uint8_t> test_blockset_data(256 * 8192, 1); // Tile16 blockset size
407 std::vector<uint8_t> test_gfx_data(256 * 256, 1); // Area graphics size
408
409 gfx::Bitmap test_blockset_bmp, test_gfx_bmp;
410 test_blockset_bmp.Create(256, 8192, 8, test_blockset_data);
411 test_gfx_bmp.Create(256, 256, 8, test_gfx_data);
412
413 // Set realistic palettes
414 if (rom->palette_group().overworld_main.size() > 0) {
415 test_blockset_bmp.SetPalette(rom->palette_group().overworld_main[0]);
416 test_gfx_bmp.SetPalette(rom->palette_group().overworld_main[0]);
417 }
418
419 std::array<uint8_t, 0x200> tile_types{};
420
421 // Test initialization
422 auto init_status = tile16_editor.Initialize(test_blockset_bmp, test_gfx_bmp, tile_types);
423 if (!init_status.ok()) {
425 result.error_message = "Tile16Editor initialization failed: " + init_status.ToString();
426 } else {
427 // Test setting a tile
428 auto set_tile_status = tile16_editor.SetCurrentTile(0);
429 if (!set_tile_status.ok()) {
431 result.error_message = "SetCurrentTile failed: " + set_tile_status.ToString();
432 } else {
434 result.error_message = absl::StrFormat(
435 "Tile16Editor working correctly (ROM: %s, Palette groups: %zu)",
436 rom->title().c_str(), rom->palette_group().overworld_main.size());
437 }
438 }
439 } else {
441 result.error_message = "ROM palette data not available";
442 }
443 } catch (const std::exception& e) {
445 result.error_message = "Tile16Editor test exception: " + std::string(e.what());
446 }
447
448 auto end_time = std::chrono::steady_clock::now();
449 result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
450 end_time - start_time);
451
452 results.AddResult(result);
453 }
454
456 auto start_time = std::chrono::steady_clock::now();
457
458 TestResult result;
459 result.name = "Comprehensive_Save_Test";
460 result.suite_name = GetName();
461 result.category = GetCategory();
462 result.timestamp = start_time;
463
464 try {
465 // Test comprehensive save functionality using ROM copy
466 auto& test_manager = TestManager::Get();
467
468 auto test_status = test_manager.TestRomWithCopy(rom, [&](Rom* test_rom) -> absl::Status {
469 // Test overworld modifications on the copy
470 zelda3::Overworld overworld(test_rom);
471 auto load_status = overworld.Load(test_rom);
472 if (!load_status.ok()) {
473 return load_status;
474 }
475
476 // Make modifications to the copy
477 auto* test_map = overworld.mutable_overworld_map(0);
478 uint8_t original_gfx = test_map->area_graphics();
479 test_map->set_area_graphics(0x01); // Change to a different graphics set
480
481 // Test save operations
482 auto save_maps_status = overworld.SaveOverworldMaps();
483 auto save_props_status = overworld.SaveMapProperties();
484
485 if (!save_maps_status.ok()) {
486 return save_maps_status;
487 }
488 if (!save_props_status.ok()) {
489 return save_props_status;
490 }
491
492 // Save the test ROM with timestamp
493 Rom::SaveSettings settings;
494 settings.backup = false;
495 settings.save_new = true;
496 settings.filename = test_manager.GenerateTestRomFilename(test_rom->title());
497
498 auto save_file_status = test_rom->SaveToFile(settings);
499 if (!save_file_status.ok()) {
500 return save_file_status;
501 }
502
503 // Offer to open test ROM in new session
504 test_manager.OfferTestSessionCreation(settings.filename);
505
506 return absl::OkStatus();
507 });
508
509 if (test_status.ok()) {
511 result.error_message = "Comprehensive save test completed successfully using ROM copy";
512 } else {
514 result.error_message = "Save test failed: " + test_status.ToString();
515 }
516
517 } catch (const std::exception& e) {
519 result.error_message = "Comprehensive save test exception: " + std::string(e.what());
520 }
521
522 auto end_time = std::chrono::steady_clock::now();
523 result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
524 end_time - start_time);
525
526 results.AddResult(result);
527 }
528
529 // Configuration
531 bool test_data_access_ = true;
537 bool test_sprite_data_ = false;
538 bool test_music_data_ = false;
539};
540
541} // namespace test
542} // namespace yaze
543
544#endif // YAZE_APP_TEST_ROM_DEPENDENT_TEST_SUITE_H
The Rom class is used to load, save, and modify Rom data.
Definition rom.h:71
auto palette_group() const
Definition rom.h:213
auto filename() const
Definition rom.h:208
absl::StatusOr< uint16_t > ReadWord(int offset)
Definition rom.cc:665
absl::Status SaveToFile(const SaveSettings &settings)
Definition rom.cc:536
auto size() const
Definition rom.h:202
absl::StatusOr< uint8_t > ReadByte(int offset)
Definition rom.cc:658
bool is_loaded() const
Definition rom.h:197
auto title() const
Definition rom.h:201
Popup window to edit Tile16 data.
absl::Status Initialize(const gfx::Bitmap &tile16_blockset_bmp, const gfx::Bitmap &current_gfx_bmp, std::array< uint8_t, 0x200 > &all_tiles_types)
absl::Status SetCurrentTile(int id)
Represents a bitmap image optimized for SNES ROM hacking.
Definition bitmap.h:66
void Create(int width, int height, int depth, std::span< uint8_t > data)
Create a bitmap with the given dimensions and data.
Definition bitmap.cc:162
void SetPalette(const SnesPalette &palette)
Set the palette for the bitmap.
Definition bitmap.cc:292
void RunTile16EditorTest(TestResults &results, Rom *rom)
void RunRomMusicDataTest(TestResults &results, Rom *rom)
void RunRomOverworldLoadingTest(TestResults &results, Rom *rom)
void RunComprehensiveSaveTest(TestResults &results, Rom *rom)
void RunRomGraphicsExtractionTest(TestResults &results, Rom *rom)
void RunRomHeaderValidationTest(TestResults &results, Rom *rom)
~RomDependentTestSuite() override=default
void AddSkippedTest(TestResults &results, const std::string &test_name, const std::string &reason)
void RunRomSpriteDataTest(TestResults &results, Rom *rom)
void RunRomDataAccessTest(TestResults &results, Rom *rom)
absl::Status RunTests(TestResults &results) override
TestCategory GetCategory() const override
Rom * GetCurrentRom() const
static TestManager & Get()
Represents the full Overworld data, light and dark world.
Definition overworld.h:135
absl::Status Load(Rom *rom)
Definition overworld.cc:27
absl::Status SaveMapProperties()
auto mutable_overworld_map(int i)
Definition overworld.h:259
absl::Status SaveOverworldMaps()
Definition overworld.cc:960
#define ICON_MD_STORAGE
Definition icons.h:1863
#define ICON_MD_WARNING
Definition icons.h:2121
#define ICON_MD_CHECK_CIRCLE
Definition icons.h:398
Main namespace for the application.
absl::StatusOr< std::array< gfx::Bitmap, kNumGfxSheets > > LoadAllGraphicsData(Rom &rom, bool defer_render)
This function iterates over all graphics sheets in the Rom and loads them into memory....
Definition rom.cc:172
std::string filename
Definition rom.h:77
std::chrono::milliseconds duration
std::string error_message
std::chrono::time_point< std::chrono::steady_clock > timestamp
void AddResult(const TestResult &result)