yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
zscustomoverworld_test_suite.h
Go to the documentation of this file.
1#ifndef YAZE_APP_TEST_ZSCUSTOMOVERWORLD_TEST_SUITE_H
2#define YAZE_APP_TEST_ZSCUSTOMOVERWORLD_TEST_SUITE_H
3
4#include <chrono>
5#include <map>
6
7#include "absl/strings/str_format.h"
9#include "rom/rom.h"
11
12namespace yaze {
13namespace test {
14
26 public:
28 ~ZSCustomOverworldTestSuite() override = default;
29
30 std::string GetName() const override {
31 return "ZSCustomOverworld Upgrade Tests";
32 }
33 TestCategory GetCategory() const override {
35 }
36
37 absl::Status RunTests(TestResults& results) override {
38 Rom* current_rom = TestManager::Get().GetCurrentRom();
39
40 // Check ROM availability
41 if (!current_rom || !current_rom->is_loaded()) {
42 AddSkippedTest(results, "ROM_Availability_Check", "No ROM loaded");
43 return absl::OkStatus();
44 }
45
46 // Initialize version data
48
49 // Run ZSCustomOverworld tests
51 RunVanillaBaselineTest(results, current_rom);
52 }
53
54 if (test_v2_upgrade_) {
55 RunV2UpgradeTest(results, current_rom);
56 }
57
58 if (test_v3_upgrade_) {
59 RunV3UpgradeTest(results, current_rom);
60 }
61
63 RunAddressValidationTest(results, current_rom);
64 }
65
67 RunFeatureToggleTest(results, current_rom);
68 }
69
71 RunDataIntegrityTest(results, current_rom);
72 }
73
74 return absl::OkStatus();
75 }
76
77 void DrawConfiguration() override {
78 Rom* current_rom = TestManager::Get().GetCurrentRom();
79
80 ImGui::Text("%s ZSCustomOverworld Test Configuration", ICON_MD_UPGRADE);
81
82 if (current_rom && current_rom->is_loaded()) {
83 ImGui::TextColored(ImVec4(0.0F, 1.0F, 0.0F, 1.0F), "%s Current ROM: %s",
84 ICON_MD_CHECK_CIRCLE, current_rom->title().c_str());
85
86 // Check current version
87 auto version_byte = current_rom->ReadByte(0x140145);
88 if (version_byte.ok()) {
89 std::string version_name = "Unknown";
90 if (*version_byte == 0xFF)
91 version_name = "Vanilla";
92 else if (*version_byte == 0x02)
93 version_name = "v2";
94 else if (*version_byte == 0x03)
95 version_name = "v3";
96
97 ImGui::Text("Current ZSCustomOverworld version: %s (0x%02X)",
98 version_name.c_str(), *version_byte);
99 }
100 } else {
101 ImGui::TextColored(ImVec4(1.0F, 0.5F, 0.0F, 1.0F),
102 "%s No ROM currently loaded", ICON_MD_WARNING);
103 }
104
105 ImGui::Separator();
106 ImGui::Checkbox("Test vanilla baseline", &test_vanilla_baseline_);
107 ImGui::Checkbox("Test v2 upgrade", &test_v2_upgrade_);
108 ImGui::Checkbox("Test v3 upgrade", &test_v3_upgrade_);
109 ImGui::Checkbox("Test address validation", &test_address_validation_);
110 ImGui::Checkbox("Test feature toggle", &test_feature_toggle_);
111 ImGui::Checkbox("Test data integrity", &test_data_integrity_);
112
113 if (ImGui::CollapsingHeader("Version Settings")) {
114 ImGui::Text("Version-specific addresses and features:");
115 ImGui::Text("Vanilla: 0x140145 = 0xFF");
116 ImGui::Text("v2: 0x140145 = 0x02, main palettes enabled");
117 ImGui::Text("v3: 0x140145 = 0x03, all features enabled");
118 }
119 }
120
121 private:
123 // Vanilla ROM addresses and values
124 vanilla_data_ = {
125 {"version_flag", {0x140145, 0xFF}}, // OverworldCustomASMHasBeenApplied
126 {"message_ids", {0x3F51D, 0x00}}, // Message ID table start
127 {"area_graphics", {0x7C9C, 0x00}}, // Area graphics table
128 {"area_palettes", {0x7D1C, 0x00}}, // Area palettes table
129 };
130
131 // v2 ROM addresses and values
132 v2_data_ = {
133 {"version_flag", {0x140145, 0x02}}, // v2 version
134 {"message_ids", {0x1417F8, 0x00}}, // Expanded message ID table
135 {"area_graphics", {0x7C9C, 0x00}}, // Same as vanilla
136 {"area_palettes", {0x7D1C, 0x00}}, // Same as vanilla
137 {"main_palettes", {0x140160, 0x00}}, // New v2 feature
138 };
139
140 // v3 ROM addresses and values
141 v3_data_ = {
142 {"version_flag", {0x140145, 0x03}}, // v3 version
143 {"message_ids", {0x1417F8, 0x00}}, // Same as v2
144 {"area_graphics", {0x7C9C, 0x00}}, // Same as vanilla
145 {"area_palettes", {0x7D1C, 0x00}}, // Same as vanilla
146 {"main_palettes", {0x140160, 0x00}}, // Same as v2
147 {"bg_colors", {0x140000, 0x00}}, // New v3 feature
148 {"subscreen_overlays", {0x140340, 0x00}}, // New v3 feature
149 {"animated_gfx", {0x1402A0, 0x00}}, // New v3 feature
150 {"custom_tiles", {0x140480, 0x00}}, // New v3 feature
151 };
152 }
153
154 void AddSkippedTest(TestResults& results, const std::string& test_name,
155 const std::string& reason) {
156 TestResult result;
157 result.name = test_name;
158 result.suite_name = GetName();
159 result.category = GetCategory();
161 result.error_message = reason;
162 result.duration = std::chrono::milliseconds{0};
163 result.timestamp = std::chrono::steady_clock::now();
164 results.AddResult(result);
165 }
166
167 absl::Status ApplyVersionPatch(Rom& rom, const std::string& version) {
168 const auto* data = &vanilla_data_;
169 if (version == "v2") {
170 data = &v2_data_;
171 } else if (version == "v3") {
172 data = &v3_data_;
173 }
174
175 // Apply version-specific data
176 for (const auto& [key, value] : *data) {
177 RETURN_IF_ERROR(rom.WriteByte(value.first, value.second));
178 }
179
180 // Apply version-specific features
181 if (version == "v2") {
182 // Enable v2 features
183 RETURN_IF_ERROR(rom.WriteByte(0x140146, 0x01)); // Enable main palettes
184 } else if (version == "v3") {
185 // Enable v3 features
186 RETURN_IF_ERROR(rom.WriteByte(0x140146, 0x01)); // Enable main palettes
188 rom.WriteByte(0x140147, 0x01)); // Enable area-specific BG
190 rom.WriteByte(0x140148, 0x01)); // Enable subscreen overlay
191 RETURN_IF_ERROR(rom.WriteByte(0x140149, 0x01)); // Enable animated GFX
193 rom.WriteByte(0x14014A, 0x01)); // Enable custom tile GFX groups
194 RETURN_IF_ERROR(rom.WriteByte(0x14014B, 0x01)); // Enable mosaic
195 }
196
197 return absl::OkStatus();
198 }
199
200 bool ValidateVersionAddresses(Rom& rom, const std::string& version) {
201 const auto* data = &vanilla_data_;
202 if (version == "v2") {
203 data = &v2_data_;
204 } else if (version == "v3") {
205 data = &v3_data_;
206 }
207
208 for (const auto& [key, value] : *data) {
209 auto byte_value = rom.ReadByte(value.first);
210 if (!byte_value.ok() || *byte_value != value.second) {
211 return false;
212 }
213 }
214
215 return true;
216 }
217
219 auto start_time = std::chrono::steady_clock::now();
220
221 TestResult result;
222 result.name = "Vanilla_Baseline_Test";
223 result.suite_name = GetName();
224 result.category = GetCategory();
225 result.timestamp = start_time;
226
227 try {
228 auto& test_manager = TestManager::Get();
229
230 auto test_status =
231 test_manager.TestRomWithCopy(rom, [&](Rom* test_rom) -> absl::Status {
232 // Validate vanilla addresses
233 if (!ValidateVersionAddresses(*test_rom, "vanilla")) {
234 return absl::InternalError("Vanilla address validation failed");
235 }
236
237 // Verify version flag
238 auto version_byte = test_rom->ReadByte(0x140145);
239 if (!version_byte.ok()) {
240 return absl::InternalError("Failed to read version flag");
241 }
242
243 if (*version_byte != 0xFF) {
244 return absl::InternalError(absl::StrFormat(
245 "Expected vanilla version flag (0xFF), got 0x%02X",
246 *version_byte));
247 }
248
249 return absl::OkStatus();
250 });
251
252 if (test_status.ok()) {
254 result.error_message =
255 "Vanilla baseline test passed - ROM is in vanilla state";
256 } else {
258 result.error_message =
259 "Vanilla baseline test failed: " + test_status.ToString();
260 }
261
262 } catch (const std::exception& e) {
264 result.error_message =
265 "Vanilla baseline test exception: " + std::string(e.what());
266 }
267
268 auto end_time = std::chrono::steady_clock::now();
269 result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
270 end_time - start_time);
271
272 results.AddResult(result);
273 }
274
275 void RunV2UpgradeTest(TestResults& results, Rom* rom) {
276 auto start_time = std::chrono::steady_clock::now();
277
278 TestResult result;
279 result.name = "V2_Upgrade_Test";
280 result.suite_name = GetName();
281 result.category = GetCategory();
282 result.timestamp = start_time;
283
284 try {
285 auto& test_manager = TestManager::Get();
286
287 auto test_status =
288 test_manager.TestRomWithCopy(rom, [&](Rom* test_rom) -> absl::Status {
289 // Apply v2 patch
290 RETURN_IF_ERROR(ApplyVersionPatch(*test_rom, "v2"));
291
292 // Validate v2 addresses
293 if (!ValidateVersionAddresses(*test_rom, "v2")) {
294 return absl::InternalError("v2 address validation failed");
295 }
296
297 // Verify version flag
298 auto version_byte = test_rom->ReadByte(0x140145);
299 if (!version_byte.ok()) {
300 return absl::InternalError("Failed to read version flag");
301 }
302
303 if (*version_byte != 0x02) {
304 return absl::InternalError(
305 absl::StrFormat("Expected v2 version flag (0x02), got 0x%02X",
306 *version_byte));
307 }
308
309 return absl::OkStatus();
310 });
311
312 if (test_status.ok()) {
314 result.error_message =
315 "v2 upgrade test passed - ROM successfully upgraded to v2";
316 } else {
318 result.error_message =
319 "v2 upgrade test failed: " + test_status.ToString();
320 }
321
322 } catch (const std::exception& e) {
324 result.error_message =
325 "v2 upgrade test exception: " + std::string(e.what());
326 }
327
328 auto end_time = std::chrono::steady_clock::now();
329 result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
330 end_time - start_time);
331
332 results.AddResult(result);
333 }
334
335 void RunV3UpgradeTest(TestResults& results, Rom* rom) {
336 auto start_time = std::chrono::steady_clock::now();
337
338 TestResult result;
339 result.name = "V3_Upgrade_Test";
340 result.suite_name = GetName();
341 result.category = GetCategory();
342 result.timestamp = start_time;
343
344 try {
345 auto& test_manager = TestManager::Get();
346
347 auto test_status =
348 test_manager.TestRomWithCopy(rom, [&](Rom* test_rom) -> absl::Status {
349 // Apply v3 patch
350 RETURN_IF_ERROR(ApplyVersionPatch(*test_rom, "v3"));
351
352 // Validate v3 addresses
353 if (!ValidateVersionAddresses(*test_rom, "v3")) {
354 return absl::InternalError("v3 address validation failed");
355 }
356
357 // Verify version flag
358 auto version_byte = test_rom->ReadByte(0x140145);
359 if (!version_byte.ok()) {
360 return absl::InternalError("Failed to read version flag");
361 }
362
363 if (*version_byte != 0x03) {
364 return absl::InternalError(
365 absl::StrFormat("Expected v3 version flag (0x03), got 0x%02X",
366 *version_byte));
367 }
368
369 return absl::OkStatus();
370 });
371
372 if (test_status.ok()) {
374 result.error_message =
375 "v3 upgrade test passed - ROM successfully upgraded to v3";
376 } else {
378 result.error_message =
379 "v3 upgrade test failed: " + test_status.ToString();
380 }
381
382 } catch (const std::exception& e) {
384 result.error_message =
385 "v3 upgrade test exception: " + std::string(e.what());
386 }
387
388 auto end_time = std::chrono::steady_clock::now();
389 result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
390 end_time - start_time);
391
392 results.AddResult(result);
393 }
394
396 auto start_time = std::chrono::steady_clock::now();
397
398 TestResult result;
399 result.name = "Address_Validation_Test";
400 result.suite_name = GetName();
401 result.category = GetCategory();
402 result.timestamp = start_time;
403
404 try {
405 auto& test_manager = TestManager::Get();
406
407 auto test_status =
408 test_manager.TestRomWithCopy(rom, [&](Rom* test_rom) -> absl::Status {
409 // Test vanilla addresses
410 if (!ValidateVersionAddresses(*test_rom, "vanilla")) {
411 return absl::InternalError("Vanilla address validation failed");
412 }
413
414 // Test v2 addresses
415 RETURN_IF_ERROR(ApplyVersionPatch(*test_rom, "v2"));
416 if (!ValidateVersionAddresses(*test_rom, "v2")) {
417 return absl::InternalError("v2 address validation failed");
418 }
419
420 // Test v3 addresses
421 RETURN_IF_ERROR(ApplyVersionPatch(*test_rom, "v3"));
422 if (!ValidateVersionAddresses(*test_rom, "v3")) {
423 return absl::InternalError("v3 address validation failed");
424 }
425
426 return absl::OkStatus();
427 });
428
429 if (test_status.ok()) {
431 result.error_message =
432 "Address validation test passed - all version addresses valid";
433 } else {
435 result.error_message =
436 "Address validation test failed: " + test_status.ToString();
437 }
438
439 } catch (const std::exception& e) {
441 result.error_message =
442 "Address validation test exception: " + std::string(e.what());
443 }
444
445 auto end_time = std::chrono::steady_clock::now();
446 result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
447 end_time - start_time);
448
449 results.AddResult(result);
450 }
451
452 void RunFeatureToggleTest(TestResults& results, Rom* rom) {
453 auto start_time = std::chrono::steady_clock::now();
454
455 TestResult result;
456 result.name = "Feature_Toggle_Test";
457 result.suite_name = GetName();
458 result.category = GetCategory();
459 result.timestamp = start_time;
460
461 try {
462 auto& test_manager = TestManager::Get();
463
464 auto test_status =
465 test_manager.TestRomWithCopy(rom, [&](Rom* test_rom) -> absl::Status {
466 // Apply v3 patch
467 RETURN_IF_ERROR(ApplyVersionPatch(*test_rom, "v3"));
468
469 // Test feature flags
470 auto main_palettes = test_rom->ReadByte(0x140146);
471 auto area_bg = test_rom->ReadByte(0x140147);
472 auto subscreen_overlay = test_rom->ReadByte(0x140148);
473 auto animated_gfx = test_rom->ReadByte(0x140149);
474 auto custom_tiles = test_rom->ReadByte(0x14014A);
475 auto mosaic = test_rom->ReadByte(0x14014B);
476
477 if (!main_palettes.ok() || !area_bg.ok() ||
478 !subscreen_overlay.ok() || !animated_gfx.ok() ||
479 !custom_tiles.ok() || !mosaic.ok()) {
480 return absl::InternalError("Failed to read feature flags");
481 }
482
483 if (*main_palettes != 0x01 || *area_bg != 0x01 ||
484 *subscreen_overlay != 0x01 || *animated_gfx != 0x01 ||
485 *custom_tiles != 0x01 || *mosaic != 0x01) {
486 return absl::InternalError("Feature flags not properly enabled");
487 }
488
489 // Disable some features
490 RETURN_IF_ERROR(test_rom->WriteByte(
491 0x140147, 0x00)); // Disable area-specific BG
493 test_rom->WriteByte(0x140149, 0x00)); // Disable animated GFX
494
495 // Verify features are disabled
496 auto disabled_area_bg = test_rom->ReadByte(0x140147);
497 auto disabled_animated_gfx = test_rom->ReadByte(0x140149);
498
499 if (!disabled_area_bg.ok() || !disabled_animated_gfx.ok()) {
500 return absl::InternalError(
501 "Failed to read disabled feature flags");
502 }
503
504 if (*disabled_area_bg != 0x00 || *disabled_animated_gfx != 0x00) {
505 return absl::InternalError("Feature flags not properly disabled");
506 }
507
508 return absl::OkStatus();
509 });
510
511 if (test_status.ok()) {
513 result.error_message =
514 "Feature toggle test passed - features can be enabled/disabled";
515 } else {
517 result.error_message =
518 "Feature toggle test failed: " + test_status.ToString();
519 }
520
521 } catch (const std::exception& e) {
523 result.error_message =
524 "Feature toggle test exception: " + std::string(e.what());
525 }
526
527 auto end_time = std::chrono::steady_clock::now();
528 result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
529 end_time - start_time);
530
531 results.AddResult(result);
532 }
533
534 void RunDataIntegrityTest(TestResults& results, Rom* rom) {
535 auto start_time = std::chrono::steady_clock::now();
536
537 TestResult result;
538 result.name = "Data_Integrity_Test";
539 result.suite_name = GetName();
540 result.category = GetCategory();
541 result.timestamp = start_time;
542
543 try {
544 auto& test_manager = TestManager::Get();
545
546 auto test_status =
547 test_manager.TestRomWithCopy(rom, [&](Rom* test_rom) -> absl::Status {
548 // Store some original data
549 auto original_graphics = test_rom->ReadByte(0x7C9C);
550 auto original_palette = test_rom->ReadByte(0x7D1C);
551 auto original_sprite_set = test_rom->ReadByte(0x7A41);
552
553 if (!original_graphics.ok() || !original_palette.ok() ||
554 !original_sprite_set.ok()) {
555 return absl::InternalError("Failed to read original data");
556 }
557
558 // Upgrade to v3
559 RETURN_IF_ERROR(ApplyVersionPatch(*test_rom, "v3"));
560
561 // Verify original data is preserved
562 auto preserved_graphics = test_rom->ReadByte(0x7C9C);
563 auto preserved_palette = test_rom->ReadByte(0x7D1C);
564 auto preserved_sprite_set = test_rom->ReadByte(0x7A41);
565
566 if (!preserved_graphics.ok() || !preserved_palette.ok() ||
567 !preserved_sprite_set.ok()) {
568 return absl::InternalError("Failed to read preserved data");
569 }
570
571 if (*preserved_graphics != *original_graphics ||
572 *preserved_palette != *original_palette ||
573 *preserved_sprite_set != *original_sprite_set) {
574 return absl::InternalError(
575 "Original data not preserved during upgrade");
576 }
577
578 // Verify new v3 data is initialized
579 auto bg_colors = test_rom->ReadByte(0x140000);
580 auto subscreen_overlays = test_rom->ReadByte(0x140340);
581 auto animated_gfx = test_rom->ReadByte(0x1402A0);
582 auto custom_tiles = test_rom->ReadByte(0x140480);
583
584 if (!bg_colors.ok() || !subscreen_overlays.ok() ||
585 !animated_gfx.ok() || !custom_tiles.ok()) {
586 return absl::InternalError("Failed to read new v3 data");
587 }
588
589 if (*bg_colors != 0x00 || *subscreen_overlays != 0x00 ||
590 *animated_gfx != 0x00 || *custom_tiles != 0x00) {
591 return absl::InternalError(
592 "New v3 data not properly initialized");
593 }
594
595 return absl::OkStatus();
596 });
597
598 if (test_status.ok()) {
600 result.error_message =
601 "Data integrity test passed - original data preserved, new data "
602 "initialized";
603 } else {
605 result.error_message =
606 "Data integrity test failed: " + test_status.ToString();
607 }
608
609 } catch (const std::exception& e) {
611 result.error_message =
612 "Data integrity test exception: " + std::string(e.what());
613 }
614
615 auto end_time = std::chrono::steady_clock::now();
616 result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
617 end_time - start_time);
618
619 results.AddResult(result);
620 }
621
622 // Configuration
624 bool test_v2_upgrade_ = true;
625 bool test_v3_upgrade_ = true;
629
630 // Version data
631 std::map<std::string, std::pair<uint32_t, uint8_t>> vanilla_data_;
632 std::map<std::string, std::pair<uint32_t, uint8_t>> v2_data_;
633 std::map<std::string, std::pair<uint32_t, uint8_t>> v3_data_;
634};
635
636} // namespace test
637} // namespace yaze
638
639#endif // YAZE_APP_TEST_ZSCUSTOMOVERWORLD_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:24
absl::Status WriteByte(int addr, uint8_t value)
Definition rom.cc:286
absl::StatusOr< uint8_t > ReadByte(int offset)
Definition rom.cc:221
bool is_loaded() const
Definition rom.h:128
auto title() const
Definition rom.h:133
Rom * GetCurrentRom() const
static TestManager & Get()
ZSCustomOverworld upgrade testing suite.
void RunDataIntegrityTest(TestResults &results, Rom *rom)
void RunAddressValidationTest(TestResults &results, Rom *rom)
void RunV2UpgradeTest(TestResults &results, Rom *rom)
void RunVanillaBaselineTest(TestResults &results, Rom *rom)
absl::Status ApplyVersionPatch(Rom &rom, const std::string &version)
std::map< std::string, std::pair< uint32_t, uint8_t > > v3_data_
std::map< std::string, std::pair< uint32_t, uint8_t > > v2_data_
void RunFeatureToggleTest(TestResults &results, Rom *rom)
bool ValidateVersionAddresses(Rom &rom, const std::string &version)
void RunV3UpgradeTest(TestResults &results, Rom *rom)
std::map< std::string, std::pair< uint32_t, uint8_t > > vanilla_data_
void AddSkippedTest(TestResults &results, const std::string &test_name, const std::string &reason)
absl::Status RunTests(TestResults &results) override
~ZSCustomOverworldTestSuite() override=default
#define ICON_MD_WARNING
Definition icons.h:2123
#define ICON_MD_UPGRADE
Definition icons.h:2047
#define ICON_MD_CHECK_CIRCLE
Definition icons.h:400
#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)