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