yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
asar_wrapper_test.cc
Go to the documentation of this file.
1#include "core/asar_wrapper.h"
2#include "test_utils.h"
3
4#include <gtest/gtest.h>
5#include <gmock/gmock.h>
6#include <fstream>
7#include <filesystem>
8
9namespace yaze {
10namespace core {
11namespace {
12
13class AsarWrapperTest : public ::testing::Test {
14 protected:
15 void SetUp() override {
16 wrapper_ = std::make_unique<AsarWrapper>();
17 CreateTestFiles();
18 }
19
20 void TearDown() override {
21 CleanupTestFiles();
22 }
23
25 // Create test directory
26 test_dir_ = std::filesystem::temp_directory_path() / "yaze_asar_test";
27 std::filesystem::create_directories(test_dir_);
28
29 // Create a simple test assembly file
30 test_asm_path_ = test_dir_ / "test_patch.asm";
31 std::ofstream asm_file(test_asm_path_);
32 asm_file << R"(
33; Test assembly patch for yaze
34org $008000
35testlabel:
36 LDA #$42
37 STA $7E0000
38 RTS
39
40anotherlabel:
41 LDA #$FF
42 STA $7E0001
43 RTL
44)";
45 asm_file.close();
46
47 // Create invalid assembly file for error testing
48 invalid_asm_path_ = test_dir_ / "invalid_patch.asm";
49 std::ofstream invalid_file(invalid_asm_path_);
50 invalid_file << R"(
51; Invalid assembly that should cause errors
52org $008000
53invalid_instruction_here
54LDA unknown_operand
55)";
56 invalid_file.close();
58 // Create test ROM data using utility
60 }
61
62 void CleanupTestFiles() {
63 try {
64 if (std::filesystem::exists(test_dir_)) {
65 std::filesystem::remove_all(test_dir_);
66 }
67 } catch (const std::exception& e) {
68 // Ignore cleanup errors in tests
69 }
70 }
71
72 std::unique_ptr<AsarWrapper> wrapper_;
73 std::filesystem::path test_dir_;
74 std::filesystem::path test_asm_path_;
75 std::filesystem::path invalid_asm_path_;
76 std::vector<uint8_t> test_rom_;
77};
78
79TEST_F(AsarWrapperTest, InitializationAndShutdown) {
80 // Test initialization
81 ASSERT_FALSE(wrapper_->IsInitialized());
82
83 auto status = wrapper_->Initialize();
84 EXPECT_TRUE(status.ok()) << status.message();
85 EXPECT_TRUE(wrapper_->IsInitialized());
86
87 // Test version info
88 std::string version = wrapper_->GetVersion();
89 EXPECT_FALSE(version.empty());
90 EXPECT_NE(version, "Not initialized");
91
92 int api_version = wrapper_->GetApiVersion();
93 EXPECT_GT(api_version, 0);
94
95 // Test shutdown
96 wrapper_->Shutdown();
97 EXPECT_FALSE(wrapper_->IsInitialized());
98}
99
100TEST_F(AsarWrapperTest, DoubleInitialization) {
101 auto status1 = wrapper_->Initialize();
102 EXPECT_TRUE(status1.ok());
103
104 auto status2 = wrapper_->Initialize();
105 EXPECT_TRUE(status2.ok()); // Should not fail on double init
106 EXPECT_TRUE(wrapper_->IsInitialized());
107}
108
109TEST_F(AsarWrapperTest, OperationsWithoutInitialization) {
110 // Operations should fail when not initialized
111 ASSERT_FALSE(wrapper_->IsInitialized());
112
113 std::vector<uint8_t> rom_copy = test_rom_;
114 auto patch_result = wrapper_->ApplyPatch(test_asm_path_.string(), rom_copy);
115 EXPECT_FALSE(patch_result.ok());
116 EXPECT_THAT(patch_result.status().message(),
117 testing::HasSubstr("not initialized"));
118
119 auto symbols_result = wrapper_->ExtractSymbols(test_asm_path_.string());
120 EXPECT_FALSE(symbols_result.ok());
121 EXPECT_THAT(symbols_result.status().message(),
122 testing::HasSubstr("not initialized"));
123}
124
125TEST_F(AsarWrapperTest, ValidPatchApplication) {
126 ASSERT_TRUE(wrapper_->Initialize().ok());
127
128 std::vector<uint8_t> rom_copy = test_rom_;
129 size_t original_size = rom_copy.size();
130
131 auto patch_result = wrapper_->ApplyPatch(test_asm_path_.string(), rom_copy);
132 ASSERT_TRUE(patch_result.ok()) << patch_result.status().message();
133
134 const auto& result = patch_result.value();
135 EXPECT_TRUE(result.success) << "Patch failed: "
136 << testing::PrintToString(result.errors);
137 EXPECT_GT(result.rom_size, 0);
138 EXPECT_EQ(rom_copy.size(), result.rom_size);
139
140 // Check that ROM was actually modified
141 EXPECT_NE(rom_copy, test_rom_); // Should be different after patching
142}
143
144TEST_F(AsarWrapperTest, InvalidPatchHandling) {
145 ASSERT_TRUE(wrapper_->Initialize().ok());
146
147 std::vector<uint8_t> rom_copy = test_rom_;
148
149 auto patch_result = wrapper_->ApplyPatch(invalid_asm_path_.string(), rom_copy);
150 EXPECT_FALSE(patch_result.ok());
151 EXPECT_THAT(patch_result.status().message(),
152 testing::HasSubstr("Patch failed"));
153}
154
155TEST_F(AsarWrapperTest, NonexistentPatchFile) {
156 ASSERT_TRUE(wrapper_->Initialize().ok());
157
158 std::vector<uint8_t> rom_copy = test_rom_;
159 std::string nonexistent_path = test_dir_.string() + "/nonexistent.asm";
160
161 auto patch_result = wrapper_->ApplyPatch(nonexistent_path, rom_copy);
162 EXPECT_FALSE(patch_result.ok());
163}
164
165TEST_F(AsarWrapperTest, SymbolExtraction) {
166 ASSERT_TRUE(wrapper_->Initialize().ok());
167
168 auto symbols_result = wrapper_->ExtractSymbols(test_asm_path_.string());
169 ASSERT_TRUE(symbols_result.ok()) << symbols_result.status().message();
170
171 const auto& symbols = symbols_result.value();
172 EXPECT_GT(symbols.size(), 0);
173
174 // Check for expected symbols from our test assembly
175 bool found_testlabel = false;
176 bool found_anotherlabel = false;
177
178 for (const auto& symbol : symbols) {
179 EXPECT_FALSE(symbol.name.empty());
180 EXPECT_GT(symbol.address, 0);
181
182 if (symbol.name == "testlabel") {
183 found_testlabel = true;
184 EXPECT_EQ(symbol.address, 0x008000); // Expected address from org directive
185 } else if (symbol.name == "anotherlabel") {
186 found_anotherlabel = true;
187 }
188 }
189
190 EXPECT_TRUE(found_testlabel) << "Expected 'testlabel' symbol not found";
191 EXPECT_TRUE(found_anotherlabel) << "Expected 'anotherlabel' symbol not found";
192}
193
194TEST_F(AsarWrapperTest, SymbolTableOperations) {
195 ASSERT_TRUE(wrapper_->Initialize().ok());
196
197 std::vector<uint8_t> rom_copy = test_rom_;
198 auto patch_result = wrapper_->ApplyPatch(test_asm_path_.string(), rom_copy);
199 ASSERT_TRUE(patch_result.ok());
200
201 // Test symbol table retrieval
202 auto symbol_table = wrapper_->GetSymbolTable();
203 EXPECT_GT(symbol_table.size(), 0);
204
205 // Test symbol lookup by name
206 auto testlabel_symbol = wrapper_->FindSymbol("testlabel");
207 EXPECT_TRUE(testlabel_symbol.has_value());
208 if (testlabel_symbol) {
209 EXPECT_EQ(testlabel_symbol->name, "testlabel");
210 EXPECT_GT(testlabel_symbol->address, 0);
211 }
212
213 // Test lookup of non-existent symbol
214 auto nonexistent_symbol = wrapper_->FindSymbol("nonexistent_symbol");
215 EXPECT_FALSE(nonexistent_symbol.has_value());
216
217 // Test symbols at address lookup
218 if (testlabel_symbol) {
219 auto symbols_at_addr = wrapper_->GetSymbolsAtAddress(testlabel_symbol->address);
220 EXPECT_GT(symbols_at_addr.size(), 0);
221
222 bool found = false;
223 for (const auto& symbol : symbols_at_addr) {
224 if (symbol.name == "testlabel") {
225 found = true;
226 break;
227 }
228 }
229 EXPECT_TRUE(found);
230 }
231}
232
233TEST_F(AsarWrapperTest, PatchFromString) {
234 ASSERT_TRUE(wrapper_->Initialize().ok());
235
236 std::string patch_content = R"(
237org $009000
238stringpatchlabel:
239 LDA #$55
240 STA $7E0002
241 RTS
242)";
243
244 std::vector<uint8_t> rom_copy = test_rom_;
245 auto patch_result = wrapper_->ApplyPatchFromString(
246 patch_content, rom_copy, test_dir_.string());
247
248 ASSERT_TRUE(patch_result.ok()) << patch_result.status().message();
249
250 const auto& result = patch_result.value();
251 EXPECT_TRUE(result.success);
252 EXPECT_GT(result.symbols.size(), 0);
253
254 // Check for the symbol we defined
255 bool found_symbol = false;
256 for (const auto& symbol : result.symbols) {
257 if (symbol.name == "stringpatchlabel") {
258 found_symbol = true;
259 EXPECT_EQ(symbol.address, 0x009000);
260 break;
261 }
262 }
263 EXPECT_TRUE(found_symbol);
264}
265
266TEST_F(AsarWrapperTest, AssemblyValidation) {
267 ASSERT_TRUE(wrapper_->Initialize().ok());
268
269 // Test valid assembly
270 auto valid_status = wrapper_->ValidateAssembly(test_asm_path_.string());
271 EXPECT_TRUE(valid_status.ok()) << valid_status.message();
272
273 // Test invalid assembly
274 auto invalid_status = wrapper_->ValidateAssembly(invalid_asm_path_.string());
275 EXPECT_FALSE(invalid_status.ok());
276 EXPECT_THAT(invalid_status.message(),
277 testing::AnyOf(testing::HasSubstr("validation failed"),
278 testing::HasSubstr("Patch failed"),
279 testing::HasSubstr("Unknown command"),
280 testing::HasSubstr("Label")));
281}
282
283TEST_F(AsarWrapperTest, ResetFunctionality) {
284 ASSERT_TRUE(wrapper_->Initialize().ok());
285
286 // Apply a patch to generate some state
287 std::vector<uint8_t> rom_copy = test_rom_;
288 auto patch_result = wrapper_->ApplyPatch(test_asm_path_.string(), rom_copy);
289 ASSERT_TRUE(patch_result.ok());
290
291 // Verify we have symbols and potentially warnings/errors
292 auto symbol_table_before = wrapper_->GetSymbolTable();
293 EXPECT_GT(symbol_table_before.size(), 0);
294
295 // Reset and verify state is cleared
296 wrapper_->Reset();
297
298 auto symbol_table_after = wrapper_->GetSymbolTable();
299 EXPECT_EQ(symbol_table_after.size(), 0);
300
301 auto errors = wrapper_->GetLastErrors();
302 auto warnings = wrapper_->GetLastWarnings();
303 EXPECT_EQ(errors.size(), 0);
304 EXPECT_EQ(warnings.size(), 0);
305}
306
307TEST_F(AsarWrapperTest, CreatePatchNotImplemented) {
308 ASSERT_TRUE(wrapper_->Initialize().ok());
309
310 std::vector<uint8_t> original_rom = test_rom_;
311 std::vector<uint8_t> modified_rom = test_rom_;
312 modified_rom[100] = 0x42; // Make a small change
313
314 std::string patch_path = test_dir_.string() + "/generated.asm";
315 auto status = wrapper_->CreatePatch(original_rom, modified_rom, patch_path);
316
317 EXPECT_FALSE(status.ok());
318 EXPECT_THAT(status.message(), testing::HasSubstr("not yet implemented"));
319}
320
321} // namespace
322} // namespace core
323} // namespace yaze
static std::vector< uint8_t > CreateMinimalTestRom(size_t size=1024 *1024)
Create a minimal test ROM for unit testing.
Definition test_utils.h:93
Main namespace for the application.
Definition controller.cc:20