yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
e2e_rom_test.cc
Go to the documentation of this file.
1#include <gtest/gtest.h>
2#include <filesystem>
3#include <fstream>
4#include <memory>
5#include <vector>
6#include <string>
7
8#include "app/rom.h"
9#include "app/transaction.h"
10#include "testing.h"
11
12namespace yaze {
13namespace test {
14
25class E2ERomDependentTest : public ::testing::Test {
26 protected:
27 void SetUp() override {
28 // Skip tests if ROM is not available
29 if (getenv("YAZE_SKIP_ROM_TESTS")) {
30 GTEST_SKIP() << "ROM tests disabled";
31 }
32
33 // Get ROM path from environment or use default
34 const char* rom_path_env = getenv("YAZE_TEST_ROM_PATH");
35 vanilla_rom_path_ = rom_path_env ? rom_path_env : "zelda3.sfc";
36
37 if (!std::filesystem::exists(vanilla_rom_path_)) {
38 GTEST_SKIP() << "Test ROM not found: " << vanilla_rom_path_;
39 }
40
41 // Create test ROM copies
42 test_rom_path_ = "test_rom_edit.sfc";
43 backup_rom_path_ = "test_rom_backup.sfc";
44
45 // Copy vanilla ROM for testing
46 std::filesystem::copy_file(vanilla_rom_path_, test_rom_path_);
47 std::filesystem::copy_file(vanilla_rom_path_, backup_rom_path_);
48 }
49
50 void TearDown() override {
51 // Clean up test files
52 if (std::filesystem::exists(test_rom_path_)) {
53 std::filesystem::remove(test_rom_path_);
54 }
55 if (std::filesystem::exists(backup_rom_path_)) {
56 std::filesystem::remove(backup_rom_path_);
57 }
58 }
59
60 // Helper to load ROM and verify basic integrity
61 static absl::Status LoadAndVerifyROM(const std::string& path, std::unique_ptr<Rom>& rom) {
62 rom = std::make_unique<Rom>();
63 RETURN_IF_ERROR(rom->LoadFromFile(path));
64
65 // Basic ROM integrity checks
66 EXPECT_EQ(rom->size(), 0x200000) << "ROM size should be 2MB";
67 EXPECT_NE(rom->data(), nullptr) << "ROM data should not be null";
68
69 // Check ROM header
70 auto header_byte = rom->ReadByte(0x7FC0);
71 RETURN_IF_ERROR(header_byte.status());
72 EXPECT_EQ(*header_byte, 0x21) << "ROM should be LoROM format";
73
74 return absl::OkStatus();
75 }
76
77 // Helper to verify ROM data integrity by comparing checksums
78 static bool VerifyROMIntegrity(const std::string& path1, const std::string& path2,
79 const std::vector<uint32_t>& exclude_ranges = {}) {
80 std::ifstream file1(path1, std::ios::binary);
81 std::ifstream file2(path2, std::ios::binary);
82
83 if (!file1.is_open() || !file2.is_open()) {
84 return false;
85 }
86
87 file1.seekg(0, std::ios::end);
88 file2.seekg(0, std::ios::end);
89
90 size_t size1 = file1.tellg();
91 size_t size2 = file2.tellg();
92
93 if (size1 != size2) {
94 return false;
95 }
96
97 file1.seekg(0);
98 file2.seekg(0);
99
100 std::vector<char> buffer1(size1);
101 std::vector<char> buffer2(size2);
102
103 file1.read(buffer1.data(), size1);
104 file2.read(buffer2.data(), size2);
105
106 // Compare byte by byte, excluding specified ranges
107 for (size_t i = 0; i < size1; i++) {
108 bool in_exclude_range = false;
109 for (const auto& range : exclude_ranges) {
110 if (i >= (range & 0xFFFFFF) && i < ((range >> 24) & 0xFF)) {
111 in_exclude_range = true;
112 break;
113 }
114 }
115
116 if (!in_exclude_range && buffer1[i] != buffer2[i]) {
117 return false;
118 }
119 }
120
121 return true;
122 }
123
124 std::string vanilla_rom_path_;
125 std::string test_rom_path_;
126 std::string backup_rom_path_;
127};
128
129// Test basic ROM loading and saving
130TEST_F(E2ERomDependentTest, BasicROMLoadSave) {
131 std::unique_ptr<Rom> rom;
132 ASSERT_OK(LoadAndVerifyROM(vanilla_rom_path_, rom));
133
134 // Save ROM to test path
135 ASSERT_OK(rom->SaveToFile(Rom::SaveSettings{.filename = test_rom_path_}));
136
137 // Verify saved ROM matches original
138 EXPECT_TRUE(VerifyROMIntegrity(vanilla_rom_path_, test_rom_path_));
139}
140
141// Test ROM data editing workflow
142TEST_F(E2ERomDependentTest, ROMDataEditWorkflow) {
143 std::unique_ptr<Rom> rom;
144 ASSERT_OK(LoadAndVerifyROM(vanilla_rom_path_, rom));
145
146 // Get initial state
147 auto initial_byte = rom->ReadByte(0x1000);
148 ASSERT_TRUE(initial_byte.ok());
149
150 // Make edits
151 ASSERT_OK(rom->WriteByte(0x1000, 0xAA));
152 ASSERT_OK(rom->WriteByte(0x2000, 0xBB));
153 ASSERT_OK(rom->WriteWord(0x3000, 0xCCDD));
154
155 // Save changes
156 ASSERT_OK(rom->SaveToFile(Rom::SaveSettings{.filename = test_rom_path_}));
157
158 // Reload and verify
159 std::unique_ptr<Rom> reloaded_rom;
160 ASSERT_OK(LoadAndVerifyROM(test_rom_path_, reloaded_rom));
161
162 auto byte1 = reloaded_rom->ReadByte(0x1000);
163 ASSERT_OK(byte1.status());
164 EXPECT_EQ(*byte1, 0xAA);
165
166 auto byte2 = reloaded_rom->ReadByte(0x2000);
167 ASSERT_OK(byte2.status());
168 EXPECT_EQ(*byte2, 0xBB);
169
170 auto word1 = reloaded_rom->ReadWord(0x3000);
171 ASSERT_OK(word1.status());
172 EXPECT_EQ(*word1, 0xCCDD);
173
174 // Verify other data wasn't corrupted
175 EXPECT_NE(*byte1, *initial_byte);
176}
177
178// Test transaction system with multiple edits
179TEST_F(E2ERomDependentTest, TransactionSystem) {
180 std::unique_ptr<Rom> rom;
181 ASSERT_OK(LoadAndVerifyROM(vanilla_rom_path_, rom));
182
183 // Create transaction
184 auto transaction = std::make_unique<yaze::Transaction>(*rom);
185
186 // Make multiple edits in transaction
187 transaction->WriteByte(0x1000, 0xAA);
188 transaction->WriteByte(0x2000, 0xBB);
189 transaction->WriteWord(0x3000, 0xCCDD);
190
191 // Commit the transaction
192 ASSERT_OK(transaction->Commit());
193
194 // Commit transaction
195 ASSERT_OK(transaction->Commit());
196
197 // Save ROM
198 ASSERT_OK(rom->SaveToFile(Rom::SaveSettings{.filename = test_rom_path_}));
199
200 // Reload and verify all changes
201 std::unique_ptr<Rom> reloaded_rom;
202 ASSERT_OK(LoadAndVerifyROM(test_rom_path_, reloaded_rom));
203
204 auto byte1 = reloaded_rom->ReadByte(0x1000);
205 ASSERT_OK(byte1.status());
206 EXPECT_EQ(*byte1, 0xAA);
207
208 auto byte2 = reloaded_rom->ReadByte(0x2000);
209 ASSERT_OK(byte2.status());
210 EXPECT_EQ(*byte2, 0xBB);
211
212 auto word1 = reloaded_rom->ReadWord(0x3000);
213 ASSERT_OK(word1.status());
214 EXPECT_EQ(*word1, 0xCCDD);
215}
216
217// Test ROM corruption detection
218TEST_F(E2ERomDependentTest, CorruptionDetection) {
219 std::unique_ptr<Rom> rom;
220 ASSERT_OK(LoadAndVerifyROM(vanilla_rom_path_, rom));
221
222 // Corrupt some data
223 ASSERT_OK(rom->WriteByte(0x1000, 0xFF)); // Corrupt some data
224 ASSERT_OK(rom->WriteByte(0x2000, 0xAA)); // Corrupt more data
225
226 // Save corrupted ROM
227 ASSERT_OK(rom->SaveToFile(Rom::SaveSettings{.filename = test_rom_path_}));
228
229 // Verify corruption is detected
230 std::unique_ptr<Rom> reloaded_rom;
231 ASSERT_OK(LoadAndVerifyROM(test_rom_path_, reloaded_rom));
232
233 auto corrupt_byte1 = reloaded_rom->ReadByte(0x1000);
234 ASSERT_OK(corrupt_byte1.status());
235 EXPECT_EQ(*corrupt_byte1, 0xFF);
236
237 auto corrupt_byte2 = reloaded_rom->ReadByte(0x2000);
238 ASSERT_OK(corrupt_byte2.status());
239 EXPECT_EQ(*corrupt_byte2, 0xAA);
240}
241
242// Test large-scale editing without corruption
243TEST_F(E2ERomDependentTest, LargeScaleEditing) {
244 std::unique_ptr<Rom> rom;
245 ASSERT_OK(LoadAndVerifyROM(vanilla_rom_path_, rom));
246
247 // Edit multiple areas
248 for (int i = 0; i < 10; i++) {
249 ASSERT_OK(rom->WriteByte(0x1000 + i, i % 16));
250 ASSERT_OK(rom->WriteByte(0x2000 + i, (i + 1) % 16));
251 }
252
253 // Save and reload
254 ASSERT_OK(rom->SaveToFile(Rom::SaveSettings{.filename = test_rom_path_}));
255
256 std::unique_ptr<Rom> reloaded_rom;
257 ASSERT_OK(LoadAndVerifyROM(test_rom_path_, reloaded_rom));
258
259 // Verify all changes
260 for (int i = 0; i < 10; i++) {
261 auto byte1 = reloaded_rom->ReadByte(0x1000 + i);
262 ASSERT_OK(byte1.status());
263 EXPECT_EQ(*byte1, i % 16);
264
265 auto byte2 = reloaded_rom->ReadByte(0x2000 + i);
266 ASSERT_OK(byte2.status());
267 EXPECT_EQ(*byte2, (i + 1) % 16);
268 }
269}
270
271} // namespace test
272} // namespace yaze
Comprehensive End-to-End ROM testing suite.
static bool VerifyROMIntegrity(const std::string &path1, const std::string &path2, const std::vector< uint32_t > &exclude_ranges={})
static absl::Status LoadAndVerifyROM(const std::string &path, std::unique_ptr< Rom > &rom)
#define RETURN_IF_ERROR(expression)
Definition macro.h:53
TEST_F(DungeonObjectRenderingE2ETests, RunAllTests)
Main namespace for the application.
#define ASSERT_OK(expr)
Definition testing.h:12