yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
rom_test.cc
Go to the documentation of this file.
1#include "app/rom.h"
2
3#include <gmock/gmock.h>
4#include <gtest/gtest.h>
5
6#include "absl/status/status.h"
7#include "absl/status/statusor.h"
8#include "mocks/mock_rom.h"
9#include "testing.h"
10#include "app/transaction.h"
11
12namespace yaze {
13namespace test {
14
15using ::testing::_;
16using ::testing::Return;
17
18const static std::vector<uint8_t> kMockRomData = {
19 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
20 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
21 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
22};
23
24class RomTest : public ::testing::Test {
25 protected:
27};
28
29TEST_F(RomTest, Uninitialized) {
30 EXPECT_EQ(rom_.size(), 0);
31 EXPECT_EQ(rom_.data(), nullptr);
32}
33
34TEST_F(RomTest, LoadFromFile) {
35#if defined(__linux__)
36 GTEST_SKIP();
37#endif
38 EXPECT_OK(rom_.LoadFromFile("zelda3.sfc"));
39 EXPECT_EQ(rom_.size(), 0x200000);
40 EXPECT_NE(rom_.data(), nullptr);
41}
42
43TEST_F(RomTest, LoadFromFileInvalid) {
44 EXPECT_THAT(rom_.LoadFromFile("invalid.sfc"),
45 StatusIs(absl::StatusCode::kNotFound));
46 EXPECT_EQ(rom_.size(), 0);
47 EXPECT_EQ(rom_.data(), nullptr);
48}
49
50TEST_F(RomTest, LoadFromFileEmpty) {
51 EXPECT_THAT(rom_.LoadFromFile(""),
52 StatusIs(absl::StatusCode::kInvalidArgument));
53}
54
55TEST_F(RomTest, ReadByteOk) {
56 EXPECT_OK(rom_.LoadFromData(kMockRomData, false));
57
58 for (size_t i = 0; i < kMockRomData.size(); ++i) {
59 uint8_t byte;
60 ASSERT_OK_AND_ASSIGN(byte, rom_.ReadByte(i));
61 EXPECT_EQ(byte, kMockRomData[i]);
62 }
63}
64
65TEST_F(RomTest, ReadByteInvalid) {
66 EXPECT_THAT(rom_.ReadByte(0).status(),
67 StatusIs(absl::StatusCode::kFailedPrecondition));
68}
69
70TEST_F(RomTest, ReadWordOk) {
71 EXPECT_OK(rom_.LoadFromData(kMockRomData, false));
72
73 for (size_t i = 0; i < kMockRomData.size(); i += 2) {
74 // Little endian
75 EXPECT_THAT(
76 rom_.ReadWord(i),
77 IsOkAndHolds<uint16_t>((kMockRomData[i]) | kMockRomData[i + 1] << 8));
78 }
79}
80
81TEST_F(RomTest, ReadWordInvalid) {
82 EXPECT_THAT(rom_.ReadWord(0).status(),
83 StatusIs(absl::StatusCode::kFailedPrecondition));
84}
85
86TEST_F(RomTest, ReadLongOk) {
87 EXPECT_OK(rom_.LoadFromData(kMockRomData, false));
88
89 for (size_t i = 0; i < kMockRomData.size(); i += 4) {
90 // Little endian
91 EXPECT_THAT(rom_.ReadLong(i),
92 IsOkAndHolds<uint32_t>((kMockRomData[i]) | kMockRomData[i] |
93 kMockRomData[i + 1] << 8 |
94 kMockRomData[i + 2] << 16));
95 }
96}
97
98TEST_F(RomTest, ReadBytesOk) {
99 EXPECT_OK(rom_.LoadFromData(kMockRomData, false));
100
101 std::vector<uint8_t> bytes;
102 ASSERT_OK_AND_ASSIGN(bytes, rom_.ReadByteVector(0, kMockRomData.size()));
103 EXPECT_THAT(bytes, ::testing::ContainerEq(kMockRomData));
104}
105
106TEST_F(RomTest, ReadBytesOutOfRange) {
107 EXPECT_OK(rom_.LoadFromData(kMockRomData, false));
108
109 std::vector<uint8_t> bytes;
110 EXPECT_THAT(rom_.ReadByteVector(kMockRomData.size() + 1, 1).status(),
111 StatusIs(absl::StatusCode::kOutOfRange));
112}
113
114TEST_F(RomTest, WriteByteOk) {
115 EXPECT_OK(rom_.LoadFromData(kMockRomData, false));
116
117 for (size_t i = 0; i < kMockRomData.size(); ++i) {
118 EXPECT_OK(rom_.WriteByte(i, 0xFF));
119 uint8_t byte;
120 ASSERT_OK_AND_ASSIGN(byte, rom_.ReadByte(i));
121 EXPECT_EQ(byte, 0xFF);
122 }
123}
124
125TEST_F(RomTest, WriteWordOk) {
126 EXPECT_OK(rom_.LoadFromData(kMockRomData, false));
127
128 for (size_t i = 0; i < kMockRomData.size(); i += 2) {
129 EXPECT_OK(rom_.WriteWord(i, 0xFFFF));
130 uint16_t word;
131 ASSERT_OK_AND_ASSIGN(word, rom_.ReadWord(i));
132 EXPECT_EQ(word, 0xFFFF);
133 }
134}
135
136TEST_F(RomTest, WriteLongOk) {
137 EXPECT_OK(rom_.LoadFromData(kMockRomData, false));
138
139 for (size_t i = 0; i < kMockRomData.size(); i += 4) {
140 EXPECT_OK(rom_.WriteLong(i, 0xFFFFFF));
141 uint32_t word;
142 ASSERT_OK_AND_ASSIGN(word, rom_.ReadLong(i));
143 EXPECT_EQ(word, 0xFFFFFF);
144 }
145}
146
147TEST_F(RomTest, WriteTransactionSuccess) {
148 MockRom mock_rom;
149 EXPECT_OK(mock_rom.LoadFromData(kMockRomData, false));
150
151 EXPECT_CALL(mock_rom, WriteHelper(_))
152 .WillRepeatedly(Return(absl::OkStatus()));
153
155 Rom::WriteAction{0x1000, uint8_t{0xFF}},
156 Rom::WriteAction{0x1001, uint16_t{0xABCD}},
157 Rom::WriteAction{0x1002, std::vector<uint8_t>{0x12, 0x34}}));
158}
159
160TEST_F(RomTest, WriteTransactionFailure) {
161 MockRom mock_rom;
162 EXPECT_OK(mock_rom.LoadFromData(kMockRomData, false));
163
164 EXPECT_CALL(mock_rom, WriteHelper(_))
165 .WillOnce(Return(absl::OkStatus()))
166 .WillOnce(Return(absl::InternalError("Write failed")));
167
168 EXPECT_EQ(
169 mock_rom.WriteTransaction(Rom::WriteAction{0x1000, uint8_t{0xFF}},
170 Rom::WriteAction{0x1001, uint16_t{0xABCD}}),
171 absl::InternalError("Write failed"));
172}
173
174TEST_F(RomTest, ReadTransactionSuccess) {
175 MockRom mock_rom;
176 EXPECT_OK(mock_rom.LoadFromData(kMockRomData, false));
177 uint8_t byte_val;
178 uint16_t word_val;
179
180 EXPECT_OK(mock_rom.ReadTransaction(byte_val, 0x0000, word_val, 0x0001));
181
182 EXPECT_EQ(byte_val, 0x00);
183 EXPECT_EQ(word_val, 0x0201);
184}
185
186TEST_F(RomTest, ReadTransactionFailure) {
187 MockRom mock_rom;
188 EXPECT_OK(mock_rom.LoadFromData(kMockRomData, false));
189 uint8_t byte_val;
190
191 EXPECT_EQ(mock_rom.ReadTransaction(byte_val, 0x1000),
192 absl::FailedPreconditionError("Offset out of range"));
193}
194
195TEST_F(RomTest, SaveTruncatesExistingFile) {
196#if defined(__linux__)
197 GTEST_SKIP();
198#endif
199 // Prepare ROM data and save to a temp file twice; second save should overwrite, not append
200 EXPECT_OK(rom_.LoadFromData(kMockRomData, /*z3_load=*/false));
201
202 const char* tmp_name = "test_temp_rom.sfc";
204 settings.filename = tmp_name;
205 settings.z3_save = false;
206
207 // First save
208 EXPECT_OK(rom_.SaveToFile(settings));
209
210 // Modify one byte and save again
211 EXPECT_OK(rom_.WriteByte(0, 0xEE));
212 EXPECT_OK(rom_.SaveToFile(settings));
213
214 // Load the saved file and verify size equals original data size and first byte matches
215 Rom verify;
216 EXPECT_OK(verify.LoadFromFile(tmp_name, /*z3_load=*/false));
217 EXPECT_EQ(verify.size(), kMockRomData.size());
218 auto b0 = verify.ReadByte(0);
219 ASSERT_TRUE(b0.ok());
220 EXPECT_EQ(*b0, 0xEE);
221}
222
223TEST_F(RomTest, TransactionRollbackRestoresOriginals) {
224 EXPECT_OK(rom_.LoadFromData(kMockRomData, /*z3_load=*/false));
225 // Force an out-of-range write to trigger failure after a successful write
226 yaze::Transaction tx{rom_};
227 auto status = tx.WriteByte(0x01, 0xAA) // valid
228 .WriteWord(0xFFFF, 0xBBBB) // invalid: should fail and rollback
229 .Commit();
230 EXPECT_FALSE(status.ok());
231 auto b1 = rom_.ReadByte(0x01);
232 ASSERT_TRUE(b1.ok());
233 // Should be restored to original 0x01 value (from kMockRomData)
234 EXPECT_EQ(*b1, kMockRomData[0x01]);
235}
236
237} // namespace test
238} // namespace yaze
The Rom class is used to load, save, and modify Rom data.
Definition rom.h:71
absl::Status LoadFromFile(const std::string &filename, bool z3_load=true)
Definition rom.cc:289
absl::Status ReadTransaction(T &var, int address, Args &&... args)
Definition rom.h:137
absl::Status LoadFromData(const std::vector< uint8_t > &data, bool z3_load=true)
Definition rom.cc:381
absl::Status WriteTransaction(Args... args)
Definition rom.h:129
auto size() const
Definition rom.h:202
absl::StatusOr< uint8_t > ReadByte(int offset)
Definition rom.cc:658
Transaction & WriteWord(int address, uint16_t value)
Definition transaction.h:39
absl::Status Commit()
Definition transaction.h:96
Transaction & WriteByte(int address, uint8_t value)
Definition transaction.h:25
Enhanced ROM for testing that behaves like a real ROM but with test data.
Definition mock_rom.h:21
TEST_F(DungeonObjectRenderingE2ETests, RunAllTests)
Main namespace for the application.
std::string filename
Definition rom.h:77
#define EXPECT_OK(expr)
Definition testing.h:10
#define ASSERT_OK_AND_ASSIGN(lhs, rexpr)
Definition testing.h:14