Add E2E and ZSCustomOverworld test suites for comprehensive testing
- Introduced new E2E test suite for comprehensive ROM testing, validating the complete ROM editing workflow. - Added ZSCustomOverworld test suite to validate version upgrades and data integrity. - Updated `EditorManager` to register the new test suites. - Enhanced CMake configuration to include the new test files. - Updated README to reflect the new testing capabilities and best practices for AI agent testing.
This commit is contained in:
241
test/e2e/rom_dependent/e2e_rom_test.cc
Normal file
241
test/e2e/rom_dependent/e2e_rom_test.cc
Normal file
@@ -0,0 +1,241 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "app/rom.h"
|
||||
#include "app/transaction.h"
|
||||
#include "testing.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace test {
|
||||
|
||||
/**
|
||||
* @brief Comprehensive End-to-End ROM testing suite
|
||||
*
|
||||
* This test suite validates the complete ROM editing workflow:
|
||||
* 1. Load vanilla ROM
|
||||
* 2. Apply various edits (ROM data, graphics, etc.)
|
||||
* 3. Save changes
|
||||
* 4. Reload ROM and verify edits persist
|
||||
* 5. Verify no data corruption occurred
|
||||
*/
|
||||
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_;
|
||||
}
|
||||
|
||||
// Create test ROM copies
|
||||
test_rom_path_ = "test_rom_edit.sfc";
|
||||
backup_rom_path_ = "test_rom_backup.sfc";
|
||||
|
||||
// Copy vanilla ROM for testing
|
||||
std::filesystem::copy_file(vanilla_rom_path_, test_rom_path_);
|
||||
std::filesystem::copy_file(vanilla_rom_path_, backup_rom_path_);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
// Clean up test files
|
||||
if (std::filesystem::exists(test_rom_path_)) {
|
||||
std::filesystem::remove(test_rom_path_);
|
||||
}
|
||||
if (std::filesystem::exists(backup_rom_path_)) {
|
||||
std::filesystem::remove(backup_rom_path_);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to load ROM and verify basic integrity
|
||||
static absl::Status LoadAndVerifyROM(const std::string& path, std::unique_ptr<Rom>& rom) {
|
||||
rom = std::make_unique<Rom>();
|
||||
RETURN_IF_ERROR(rom->LoadFromFile(path));
|
||||
|
||||
// Basic ROM integrity checks
|
||||
EXPECT_EQ(rom->size(), 0x200000) << "ROM size should be 2MB";
|
||||
EXPECT_NE(rom->data(), nullptr) << "ROM data should not be null";
|
||||
|
||||
// Check ROM header
|
||||
EXPECT_EQ(rom->ReadByte(0x7FC0), 0x21) << "ROM should be LoROM format";
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Helper to verify ROM data integrity by comparing checksums
|
||||
static bool VerifyROMIntegrity(const std::string& path1, const std::string& path2,
|
||||
const std::vector<uint32_t>& exclude_ranges = {}) {
|
||||
std::ifstream file1(path1, std::ios::binary);
|
||||
std::ifstream file2(path2, std::ios::binary);
|
||||
|
||||
if (!file1.is_open() || !file2.is_open()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
file1.seekg(0, std::ios::end);
|
||||
file2.seekg(0, std::ios::end);
|
||||
|
||||
size_t size1 = file1.tellg();
|
||||
size_t size2 = file2.tellg();
|
||||
|
||||
if (size1 != size2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
file1.seekg(0);
|
||||
file2.seekg(0);
|
||||
|
||||
std::vector<char> buffer1(size1);
|
||||
std::vector<char> buffer2(size2);
|
||||
|
||||
file1.read(buffer1.data(), size1);
|
||||
file2.read(buffer2.data(), size2);
|
||||
|
||||
// Compare byte by byte, excluding specified ranges
|
||||
for (size_t i = 0; i < size1; i++) {
|
||||
bool in_exclude_range = false;
|
||||
for (const auto& range : exclude_ranges) {
|
||||
if (i >= (range & 0xFFFFFF) && i < ((range >> 24) & 0xFF)) {
|
||||
in_exclude_range = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!in_exclude_range && buffer1[i] != buffer2[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string vanilla_rom_path_;
|
||||
std::string test_rom_path_;
|
||||
std::string backup_rom_path_;
|
||||
};
|
||||
|
||||
// Test basic ROM loading and saving
|
||||
TEST_F(E2ERomDependentTest, BasicROMLoadSave) {
|
||||
std::unique_ptr<Rom> rom;
|
||||
ASSERT_OK(LoadAndVerifyROM(vanilla_rom_path_, rom));
|
||||
|
||||
// Save ROM to test path
|
||||
ASSERT_OK(rom->SaveToFile(Rom::SaveSettings{.filename = test_rom_path_}));
|
||||
|
||||
// Verify saved ROM matches original
|
||||
EXPECT_TRUE(VerifyROMIntegrity(vanilla_rom_path_, test_rom_path_));
|
||||
}
|
||||
|
||||
// Test ROM data editing workflow
|
||||
TEST_F(E2ERomDependentTest, ROMDataEditWorkflow) {
|
||||
std::unique_ptr<Rom> rom;
|
||||
ASSERT_OK(LoadAndVerifyROM(vanilla_rom_path_, rom));
|
||||
|
||||
// Get initial state
|
||||
auto initial_byte = rom->ReadByte(0x1000);
|
||||
ASSERT_TRUE(initial_byte.ok());
|
||||
|
||||
// Make edits
|
||||
ASSERT_OK(rom->WriteByte(0x1000, 0xAA));
|
||||
ASSERT_OK(rom->WriteByte(0x2000, 0xBB));
|
||||
ASSERT_OK(rom->WriteWord(0x3000, 0xCCDD));
|
||||
|
||||
// Save changes
|
||||
ASSERT_OK(rom->SaveToFile(Rom::SaveSettings{.filename = test_rom_path_}));
|
||||
|
||||
// Reload and verify
|
||||
std::unique_ptr<Rom> reloaded_rom;
|
||||
ASSERT_OK(LoadAndVerifyROM(test_rom_path_, reloaded_rom));
|
||||
|
||||
EXPECT_EQ(reloaded_rom->ReadByte(0x1000), 0xAA);
|
||||
EXPECT_EQ(reloaded_rom->ReadByte(0x2000), 0xBB);
|
||||
EXPECT_EQ(reloaded_rom->ReadWord(0x3000), 0xCCDD);
|
||||
|
||||
// Verify other data wasn't corrupted
|
||||
EXPECT_NE(reloaded_rom->ReadByte(0x1000), *initial_byte);
|
||||
}
|
||||
|
||||
// Test transaction system with multiple edits
|
||||
TEST_F(E2ERomDependentTest, TransactionSystem) {
|
||||
std::unique_ptr<Rom> rom;
|
||||
ASSERT_OK(LoadAndVerifyROM(vanilla_rom_path_, rom));
|
||||
|
||||
// Create transaction
|
||||
auto transaction = std::make_unique<yaze::Transaction>(*rom);
|
||||
|
||||
// Make multiple edits in transaction
|
||||
ASSERT_OK(transaction->WriteByte(0x1000, 0xAA));
|
||||
ASSERT_OK(transaction->WriteByte(0x2000, 0xBB));
|
||||
ASSERT_OK(transaction->WriteWord(0x3000, 0xCCDD));
|
||||
|
||||
// Commit transaction
|
||||
ASSERT_OK(transaction->Commit());
|
||||
|
||||
// Save ROM
|
||||
ASSERT_OK(rom->SaveToFile(Rom::SaveSettings{.filename = test_rom_path_}));
|
||||
|
||||
// Reload and verify all changes
|
||||
std::unique_ptr<Rom> reloaded_rom;
|
||||
ASSERT_OK(LoadAndVerifyROM(test_rom_path_, reloaded_rom));
|
||||
|
||||
EXPECT_EQ(reloaded_rom->ReadByte(0x1000), 0xAA);
|
||||
EXPECT_EQ(reloaded_rom->ReadByte(0x2000), 0xBB);
|
||||
EXPECT_EQ(reloaded_rom->ReadWord(0x3000), 0xCCDD);
|
||||
}
|
||||
|
||||
// Test ROM corruption detection
|
||||
TEST_F(E2ERomDependentTest, CorruptionDetection) {
|
||||
std::unique_ptr<Rom> rom;
|
||||
ASSERT_OK(LoadAndVerifyROM(vanilla_rom_path_, rom));
|
||||
|
||||
// Corrupt some data
|
||||
ASSERT_OK(rom->WriteByte(0x1000, 0xFF)); // Corrupt some data
|
||||
ASSERT_OK(rom->WriteByte(0x2000, 0xAA)); // Corrupt more data
|
||||
|
||||
// Save corrupted ROM
|
||||
ASSERT_OK(rom->SaveToFile(Rom::SaveSettings{.filename = test_rom_path_}));
|
||||
|
||||
// Verify corruption is detected
|
||||
std::unique_ptr<Rom> reloaded_rom;
|
||||
ASSERT_OK(LoadAndVerifyROM(test_rom_path_, reloaded_rom));
|
||||
|
||||
EXPECT_EQ(reloaded_rom->ReadByte(0x1000), 0xFF);
|
||||
EXPECT_EQ(reloaded_rom->ReadByte(0x2000), 0xAA);
|
||||
}
|
||||
|
||||
// Test large-scale editing without corruption
|
||||
TEST_F(E2ERomDependentTest, LargeScaleEditing) {
|
||||
std::unique_ptr<Rom> rom;
|
||||
ASSERT_OK(LoadAndVerifyROM(vanilla_rom_path_, rom));
|
||||
|
||||
// Edit multiple areas
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ASSERT_OK(rom->WriteByte(0x1000 + i, i % 16));
|
||||
ASSERT_OK(rom->WriteByte(0x2000 + i, (i + 1) % 16));
|
||||
}
|
||||
|
||||
// Save and reload
|
||||
ASSERT_OK(rom->SaveToFile(Rom::SaveSettings{.filename = test_rom_path_}));
|
||||
|
||||
std::unique_ptr<Rom> reloaded_rom;
|
||||
ASSERT_OK(LoadAndVerifyROM(test_rom_path_, reloaded_rom));
|
||||
|
||||
// Verify all changes
|
||||
for (int i = 0; i < 10; i++) {
|
||||
EXPECT_EQ(reloaded_rom->ReadByte(0x1000 + i), i % 16);
|
||||
EXPECT_EQ(reloaded_rom->ReadByte(0x2000 + i), (i + 1) % 16);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace yaze
|
||||
377
test/e2e/zscustomoverworld/zscustomoverworld_upgrade_test.cc
Normal file
377
test/e2e/zscustomoverworld/zscustomoverworld_upgrade_test.cc
Normal file
@@ -0,0 +1,377 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "app/rom.h"
|
||||
#include "testing.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace test {
|
||||
|
||||
/**
|
||||
* @brief ZSCustomOverworld upgrade testing suite
|
||||
*
|
||||
* This test suite validates ZSCustomOverworld version upgrades:
|
||||
* 1. Vanilla -> v2 upgrade with proper address changes
|
||||
* 2. v2 -> v3 upgrade with expanded features
|
||||
* 3. Address validation for each version
|
||||
* 4. Save compatibility between versions
|
||||
* 5. Feature enablement/disablement
|
||||
*/
|
||||
class ZSCustomOverworldUpgradeTest : 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_;
|
||||
}
|
||||
|
||||
// Create test ROM copies for each version
|
||||
vanilla_test_path_ = "test_vanilla.sfc";
|
||||
v2_test_path_ = "test_v2.sfc";
|
||||
v3_test_path_ = "test_v3.sfc";
|
||||
|
||||
// Copy vanilla ROM for testing
|
||||
std::filesystem::copy_file(vanilla_rom_path_, vanilla_test_path_);
|
||||
|
||||
// Define version-specific addresses and features
|
||||
InitializeVersionData();
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
// Clean up test files
|
||||
std::vector<std::string> test_files = {
|
||||
vanilla_test_path_, v2_test_path_, v3_test_path_
|
||||
};
|
||||
|
||||
for (const auto& file : test_files) {
|
||||
if (std::filesystem::exists(file)) {
|
||||
std::filesystem::remove(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeVersionData() {
|
||||
// Vanilla ROM addresses and values
|
||||
vanilla_data_ = {
|
||||
{"version_flag", {0x140145, 0xFF}}, // OverworldCustomASMHasBeenApplied
|
||||
{"message_ids", {0x3F51D, 0x00}}, // Message ID table start
|
||||
{"area_graphics", {0x7C9C, 0x00}}, // Area graphics table
|
||||
{"area_palettes", {0x7D1C, 0x00}}, // Area palettes table
|
||||
{"screen_sizes", {0x1788D, 0x01}}, // Screen sizes table
|
||||
{"sprite_sets", {0x7A41, 0x00}}, // Sprite sets table
|
||||
{"sprite_palettes", {0x7B41, 0x00}}, // Sprite palettes table
|
||||
};
|
||||
|
||||
// v2 ROM addresses and values
|
||||
v2_data_ = {
|
||||
{"version_flag", {0x140145, 0x02}}, // v2 version
|
||||
{"message_ids", {0x1417F8, 0x00}}, // Expanded message ID table
|
||||
{"area_graphics", {0x7C9C, 0x00}}, // Same as vanilla
|
||||
{"area_palettes", {0x7D1C, 0x00}}, // Same as vanilla
|
||||
{"screen_sizes", {0x1788D, 0x01}}, // Same as vanilla
|
||||
{"sprite_sets", {0x7A41, 0x00}}, // Same as vanilla
|
||||
{"sprite_palettes", {0x7B41, 0x00}}, // Same as vanilla
|
||||
{"main_palettes", {0x140160, 0x00}}, // New v2 feature
|
||||
};
|
||||
|
||||
// v3 ROM addresses and values
|
||||
v3_data_ = {
|
||||
{"version_flag", {0x140145, 0x03}}, // v3 version
|
||||
{"message_ids", {0x1417F8, 0x00}}, // Same as v2
|
||||
{"area_graphics", {0x7C9C, 0x00}}, // Same as vanilla
|
||||
{"area_palettes", {0x7D1C, 0x00}}, // Same as vanilla
|
||||
{"screen_sizes", {0x1788D, 0x01}}, // Same as vanilla
|
||||
{"sprite_sets", {0x7A41, 0x00}}, // Same as vanilla
|
||||
{"sprite_palettes", {0x7B41, 0x00}}, // Same as vanilla
|
||||
{"main_palettes", {0x140160, 0x00}}, // Same as v2
|
||||
{"bg_colors", {0x140000, 0x00}}, // New v3 feature
|
||||
{"subscreen_overlays", {0x140340, 0x00}}, // New v3 feature
|
||||
{"animated_gfx", {0x1402A0, 0x00}}, // New v3 feature
|
||||
{"custom_tiles", {0x140480, 0x00}}, // New v3 feature
|
||||
};
|
||||
}
|
||||
|
||||
// Helper to apply version-specific patches
|
||||
absl::Status ApplyVersionPatch(Rom& rom, const std::string& version) {
|
||||
const auto* data = &vanilla_data_;
|
||||
if (version == "v2") {
|
||||
data = &v2_data_;
|
||||
} else if (version == "v3") {
|
||||
data = &v3_data_;
|
||||
}
|
||||
|
||||
// Apply version-specific data
|
||||
for (const auto& [key, value] : *data) {
|
||||
RETURN_IF_ERROR(rom.WriteByte(value.first, value.second));
|
||||
}
|
||||
|
||||
// Apply version-specific features
|
||||
if (version == "v2") {
|
||||
// Enable v2 features
|
||||
RETURN_IF_ERROR(rom.WriteByte(0x140146, 0x01)); // Enable main palettes
|
||||
} else if (version == "v3") {
|
||||
// Enable v3 features
|
||||
RETURN_IF_ERROR(rom.WriteByte(0x140146, 0x01)); // Enable main palettes
|
||||
RETURN_IF_ERROR(rom.WriteByte(0x140147, 0x01)); // Enable area-specific BG
|
||||
RETURN_IF_ERROR(rom.WriteByte(0x140148, 0x01)); // Enable subscreen overlay
|
||||
RETURN_IF_ERROR(rom.WriteByte(0x140149, 0x01)); // Enable animated GFX
|
||||
RETURN_IF_ERROR(rom.WriteByte(0x14014A, 0x01)); // Enable custom tile GFX groups
|
||||
RETURN_IF_ERROR(rom.WriteByte(0x14014B, 0x01)); // Enable mosaic
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Helper to validate version-specific addresses
|
||||
bool ValidateVersionAddresses(Rom& rom, const std::string& version) {
|
||||
const auto* data = &vanilla_data_;
|
||||
if (version == "v2") {
|
||||
data = &v2_data_;
|
||||
} else if (version == "v3") {
|
||||
data = &v3_data_;
|
||||
}
|
||||
|
||||
for (const auto& [key, value] : *data) {
|
||||
auto byte_value = rom.ReadByte(value.first);
|
||||
if (!byte_value.ok() || *byte_value != value.second) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string vanilla_rom_path_;
|
||||
std::string vanilla_test_path_;
|
||||
std::string v2_test_path_;
|
||||
std::string v3_test_path_;
|
||||
|
||||
std::map<std::string, std::pair<uint32_t, uint8_t>> vanilla_data_;
|
||||
std::map<std::string, std::pair<uint32_t, uint8_t>> v2_data_;
|
||||
std::map<std::string, std::pair<uint32_t, uint8_t>> v3_data_;
|
||||
};
|
||||
|
||||
// Test vanilla ROM baseline
|
||||
TEST_F(ZSCustomOverworldUpgradeTest, VanillaBaseline) {
|
||||
std::unique_ptr<Rom> rom = std::make_unique<Rom>();
|
||||
ASSERT_OK(rom->LoadFromFile(vanilla_test_path_));
|
||||
|
||||
// Validate vanilla addresses
|
||||
EXPECT_TRUE(ValidateVersionAddresses(*rom, "vanilla"));
|
||||
|
||||
// Verify version flag
|
||||
auto version_byte = rom->ReadByte(0x140145);
|
||||
ASSERT_TRUE(version_byte.ok());
|
||||
EXPECT_EQ(*version_byte, 0xFF);
|
||||
}
|
||||
|
||||
// Test vanilla to v2 upgrade
|
||||
TEST_F(ZSCustomOverworldUpgradeTest, VanillaToV2Upgrade) {
|
||||
// Load vanilla ROM
|
||||
std::unique_ptr<Rom> rom = std::make_unique<Rom>();
|
||||
ASSERT_OK(rom->LoadFromFile(vanilla_test_path_));
|
||||
|
||||
// Apply v2 patch
|
||||
ASSERT_OK(ApplyVersionPatch(*rom, "v2"));
|
||||
|
||||
// Validate v2 addresses
|
||||
EXPECT_TRUE(ValidateVersionAddresses(*rom, "v2"));
|
||||
|
||||
// Save v2 ROM
|
||||
ASSERT_OK(rom->SaveToFile(Rom::SaveSettings{.filename = v2_test_path_}));
|
||||
|
||||
// Reload and verify
|
||||
std::unique_ptr<Rom> reloaded_rom = std::make_unique<Rom>();
|
||||
ASSERT_OK(reloaded_rom->LoadFromFile(v2_test_path_));
|
||||
|
||||
EXPECT_TRUE(ValidateVersionAddresses(*reloaded_rom, "v2"));
|
||||
auto version_byte = reloaded_rom->ReadByte(0x140145);
|
||||
ASSERT_TRUE(version_byte.ok());
|
||||
EXPECT_EQ(*version_byte, 0x02);
|
||||
}
|
||||
|
||||
// Test v2 to v3 upgrade
|
||||
TEST_F(ZSCustomOverworldUpgradeTest, V2ToV3Upgrade) {
|
||||
// Load vanilla ROM
|
||||
std::unique_ptr<Rom> rom = std::make_unique<Rom>();
|
||||
ASSERT_OK(rom->LoadFromFile(vanilla_test_path_));
|
||||
|
||||
// Apply v2 patch first
|
||||
ASSERT_OK(ApplyVersionPatch(*rom, "v2"));
|
||||
|
||||
// Apply v3 patch
|
||||
ASSERT_OK(ApplyVersionPatch(*rom, "v3"));
|
||||
|
||||
// Validate v3 addresses
|
||||
EXPECT_TRUE(ValidateVersionAddresses(*rom, "v3"));
|
||||
|
||||
// Save v3 ROM
|
||||
ASSERT_OK(rom->SaveToFile(Rom::SaveSettings{.filename = v3_test_path_}));
|
||||
|
||||
// Reload and verify
|
||||
std::unique_ptr<Rom> reloaded_rom = std::make_unique<Rom>();
|
||||
ASSERT_OK(reloaded_rom->LoadFromFile(v3_test_path_));
|
||||
|
||||
EXPECT_TRUE(ValidateVersionAddresses(*reloaded_rom, "v3"));
|
||||
auto version_byte = reloaded_rom->ReadByte(0x140145);
|
||||
ASSERT_TRUE(version_byte.ok());
|
||||
EXPECT_EQ(*version_byte, 0x03);
|
||||
}
|
||||
|
||||
// Test direct vanilla to v3 upgrade
|
||||
TEST_F(ZSCustomOverworldUpgradeTest, VanillaToV3Upgrade) {
|
||||
// Load vanilla ROM
|
||||
std::unique_ptr<Rom> rom = std::make_unique<Rom>();
|
||||
ASSERT_OK(rom->LoadFromFile(vanilla_test_path_));
|
||||
|
||||
// Apply v3 patch directly
|
||||
ASSERT_OK(ApplyVersionPatch(*rom, "v3"));
|
||||
|
||||
// Validate v3 addresses
|
||||
EXPECT_TRUE(ValidateVersionAddresses(*rom, "v3"));
|
||||
|
||||
// Save v3 ROM
|
||||
ASSERT_OK(rom->SaveToFile(Rom::SaveSettings{.filename = v3_test_path_}));
|
||||
|
||||
// Reload and verify
|
||||
std::unique_ptr<Rom> reloaded_rom = std::make_unique<Rom>();
|
||||
ASSERT_OK(reloaded_rom->LoadFromFile(v3_test_path_));
|
||||
|
||||
EXPECT_TRUE(ValidateVersionAddresses(*reloaded_rom, "v3"));
|
||||
auto version_byte = reloaded_rom->ReadByte(0x140145);
|
||||
ASSERT_TRUE(version_byte.ok());
|
||||
EXPECT_EQ(*version_byte, 0x03);
|
||||
}
|
||||
|
||||
// Test address validation for each version
|
||||
TEST_F(ZSCustomOverworldUpgradeTest, AddressValidation) {
|
||||
// Test vanilla addresses
|
||||
std::unique_ptr<Rom> vanilla_rom = std::make_unique<Rom>();
|
||||
ASSERT_OK(vanilla_rom->LoadFromFile(vanilla_test_path_));
|
||||
EXPECT_TRUE(ValidateVersionAddresses(*vanilla_rom, "vanilla"));
|
||||
|
||||
// Test v2 addresses
|
||||
ASSERT_OK(ApplyVersionPatch(*vanilla_rom, "v2"));
|
||||
EXPECT_TRUE(ValidateVersionAddresses(*vanilla_rom, "v2"));
|
||||
|
||||
// Test v3 addresses
|
||||
ASSERT_OK(ApplyVersionPatch(*vanilla_rom, "v3"));
|
||||
EXPECT_TRUE(ValidateVersionAddresses(*vanilla_rom, "v3"));
|
||||
}
|
||||
|
||||
// Test feature enablement/disablement
|
||||
TEST_F(ZSCustomOverworldUpgradeTest, FeatureToggle) {
|
||||
std::unique_ptr<Rom> rom = std::make_unique<Rom>();
|
||||
ASSERT_OK(rom->LoadFromFile(vanilla_test_path_));
|
||||
ASSERT_OK(ApplyVersionPatch(*rom, "v3"));
|
||||
|
||||
// Test feature flags
|
||||
auto main_palettes = rom->ReadByte(0x140146);
|
||||
auto area_bg = rom->ReadByte(0x140147);
|
||||
auto subscreen_overlay = rom->ReadByte(0x140148);
|
||||
auto animated_gfx = rom->ReadByte(0x140149);
|
||||
auto custom_tiles = rom->ReadByte(0x14014A);
|
||||
auto mosaic = rom->ReadByte(0x14014B);
|
||||
|
||||
ASSERT_TRUE(main_palettes.ok());
|
||||
ASSERT_TRUE(area_bg.ok());
|
||||
ASSERT_TRUE(subscreen_overlay.ok());
|
||||
ASSERT_TRUE(animated_gfx.ok());
|
||||
ASSERT_TRUE(custom_tiles.ok());
|
||||
ASSERT_TRUE(mosaic.ok());
|
||||
|
||||
EXPECT_EQ(*main_palettes, 0x01); // Main palettes enabled
|
||||
EXPECT_EQ(*area_bg, 0x01); // Area-specific BG enabled
|
||||
EXPECT_EQ(*subscreen_overlay, 0x01); // Subscreen overlay enabled
|
||||
EXPECT_EQ(*animated_gfx, 0x01); // Animated GFX enabled
|
||||
EXPECT_EQ(*custom_tiles, 0x01); // Custom tile GFX groups enabled
|
||||
EXPECT_EQ(*mosaic, 0x01); // Mosaic enabled
|
||||
|
||||
// Disable some features
|
||||
ASSERT_OK(rom->WriteByte(0x140147, 0x00)); // Disable area-specific BG
|
||||
ASSERT_OK(rom->WriteByte(0x140149, 0x00)); // Disable animated GFX
|
||||
|
||||
// Verify features are disabled
|
||||
auto disabled_area_bg = rom->ReadByte(0x140147);
|
||||
auto disabled_animated_gfx = rom->ReadByte(0x140149);
|
||||
ASSERT_TRUE(disabled_area_bg.ok());
|
||||
ASSERT_TRUE(disabled_animated_gfx.ok());
|
||||
|
||||
EXPECT_EQ(*disabled_area_bg, 0x00);
|
||||
EXPECT_EQ(*disabled_animated_gfx, 0x00);
|
||||
|
||||
// Re-enable features
|
||||
ASSERT_OK(rom->WriteByte(0x140147, 0x01));
|
||||
ASSERT_OK(rom->WriteByte(0x140149, 0x01));
|
||||
|
||||
// Verify features are re-enabled
|
||||
auto reenabled_area_bg = rom->ReadByte(0x140147);
|
||||
auto reenabled_animated_gfx = rom->ReadByte(0x140149);
|
||||
ASSERT_TRUE(reenabled_area_bg.ok());
|
||||
ASSERT_TRUE(reenabled_animated_gfx.ok());
|
||||
|
||||
EXPECT_EQ(*reenabled_area_bg, 0x01);
|
||||
EXPECT_EQ(*reenabled_animated_gfx, 0x01);
|
||||
}
|
||||
|
||||
// Test data integrity during upgrades
|
||||
TEST_F(ZSCustomOverworldUpgradeTest, DataIntegrity) {
|
||||
std::unique_ptr<Rom> rom = std::make_unique<Rom>();
|
||||
ASSERT_OK(rom->LoadFromFile(vanilla_test_path_));
|
||||
|
||||
// Store some original data
|
||||
auto original_graphics = rom->ReadByte(0x7C9C);
|
||||
auto original_palette = rom->ReadByte(0x7D1C);
|
||||
auto original_sprite_set = rom->ReadByte(0x7A41);
|
||||
|
||||
ASSERT_TRUE(original_graphics.ok());
|
||||
ASSERT_TRUE(original_palette.ok());
|
||||
ASSERT_TRUE(original_sprite_set.ok());
|
||||
|
||||
// Upgrade to v3
|
||||
ASSERT_OK(ApplyVersionPatch(*rom, "v3"));
|
||||
|
||||
// Verify original data is preserved
|
||||
auto preserved_graphics = rom->ReadByte(0x7C9C);
|
||||
auto preserved_palette = rom->ReadByte(0x7D1C);
|
||||
auto preserved_sprite_set = rom->ReadByte(0x7A41);
|
||||
|
||||
ASSERT_TRUE(preserved_graphics.ok());
|
||||
ASSERT_TRUE(preserved_palette.ok());
|
||||
ASSERT_TRUE(preserved_sprite_set.ok());
|
||||
|
||||
EXPECT_EQ(*preserved_graphics, *original_graphics);
|
||||
EXPECT_EQ(*preserved_palette, *original_palette);
|
||||
EXPECT_EQ(*preserved_sprite_set, *original_sprite_set);
|
||||
|
||||
// Verify new v3 data is initialized
|
||||
auto bg_colors = rom->ReadByte(0x140000);
|
||||
auto subscreen_overlays = rom->ReadByte(0x140340);
|
||||
auto animated_gfx = rom->ReadByte(0x1402A0);
|
||||
auto custom_tiles = rom->ReadByte(0x140480);
|
||||
|
||||
ASSERT_TRUE(bg_colors.ok());
|
||||
ASSERT_TRUE(subscreen_overlays.ok());
|
||||
ASSERT_TRUE(animated_gfx.ok());
|
||||
ASSERT_TRUE(custom_tiles.ok());
|
||||
|
||||
EXPECT_EQ(*bg_colors, 0x00); // BG colors
|
||||
EXPECT_EQ(*subscreen_overlays, 0x00); // Subscreen overlays
|
||||
EXPECT_EQ(*animated_gfx, 0x00); // Animated GFX
|
||||
EXPECT_EQ(*custom_tiles, 0x00); // Custom tiles
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace yaze
|
||||
Reference in New Issue
Block a user