yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
dungeon_editor_system_integration_test.cc
Go to the documentation of this file.
1#include <gtest/gtest.h>
2#include <memory>
3#include <vector>
4#include <map>
5#include <chrono>
6
7#include "app/rom.h"
11
12namespace yaze {
13namespace zelda3 {
14
15class DungeonEditorSystemIntegrationTest : public ::testing::Test {
16 protected:
17 void SetUp() override {
18 // Skip tests on Linux for automated github builds
19#if defined(__linux__)
20 GTEST_SKIP();
21#endif
22
23 // Use the real ROM from build directory
24 rom_path_ = "build/bin/zelda3.sfc";
25
26 // Load ROM
27 rom_ = std::make_unique<Rom>();
28 ASSERT_TRUE(rom_->LoadFromFile(rom_path_).ok());
29
30 // Initialize dungeon editor system
31 dungeon_editor_system_ = std::make_unique<DungeonEditorSystem>(rom_.get());
32 ASSERT_TRUE(dungeon_editor_system_->Initialize().ok());
33
34 // Load test room data
35 ASSERT_TRUE(LoadTestRoomData().ok());
36 }
37
38 void TearDown() override {
40 rom_.reset();
41 }
42
43 absl::Status LoadTestRoomData() {
44 // Load representative rooms for testing
45 test_rooms_ = {0x0000, 0x0001, 0x0002, 0x0010, 0x0012, 0x0020};
46
47 for (int room_id : test_rooms_) {
48 auto room_result = dungeon_editor_system_->GetRoom(room_id);
49 if (room_result.ok()) {
50 rooms_[room_id] = room_result.value();
51 std::cout << "Loaded room 0x" << std::hex << room_id << std::dec << std::endl;
52 }
53 }
54
55 return absl::OkStatus();
56 }
57
58 std::string rom_path_;
59 std::unique_ptr<Rom> rom_;
60 std::unique_ptr<DungeonEditorSystem> dungeon_editor_system_;
61
62 std::vector<int> test_rooms_;
63 std::map<int, Room> rooms_;
64};
65
66// Test basic dungeon editor system initialization
68 EXPECT_NE(dungeon_editor_system_, nullptr);
69 EXPECT_EQ(dungeon_editor_system_->GetROM(), rom_.get());
70 EXPECT_FALSE(dungeon_editor_system_->IsDirty());
71}
72
73// Test room loading and management
74TEST_F(DungeonEditorSystemIntegrationTest, RoomLoadingAndManagement) {
75 // Test loading a specific room
76 auto room_result = dungeon_editor_system_->GetRoom(0x0000);
77 ASSERT_TRUE(room_result.ok()) << "Failed to load room 0x0000: " << room_result.status().message();
78
79 const auto& room = room_result.value();
80 // Note: room_id_ is private, so we can't directly access it in tests
81
82 // Test setting current room
83 ASSERT_TRUE(dungeon_editor_system_->SetCurrentRoom(0x0000).ok());
84 EXPECT_EQ(dungeon_editor_system_->GetCurrentRoom(), 0x0000);
85
86 // Test loading another room
87 auto room2_result = dungeon_editor_system_->GetRoom(0x0001);
88 ASSERT_TRUE(room2_result.ok()) << "Failed to load room 0x0001: " << room2_result.status().message();
89
90 const auto& room2 = room2_result.value();
91 // Note: room_id_ is private, so we can't directly access it in tests
92}
93
94// Test object editor integration
95TEST_F(DungeonEditorSystemIntegrationTest, ObjectEditorIntegration) {
96 // Get object editor from system
97 auto object_editor = dungeon_editor_system_->GetObjectEditor();
98 ASSERT_NE(object_editor, nullptr);
99
100 // Set current room
101 ASSERT_TRUE(dungeon_editor_system_->SetCurrentRoom(0x0000).ok());
102
103 // Test object insertion
104 ASSERT_TRUE(object_editor->InsertObject(5, 5, 0x10, 0x12, 0).ok());
105 ASSERT_TRUE(object_editor->InsertObject(10, 10, 0x20, 0x22, 1).ok());
106
107 // Verify objects were added
108 EXPECT_EQ(object_editor->GetObjectCount(), 2);
109
110 // Test object selection
111 ASSERT_TRUE(object_editor->SelectObject(5 * 16, 5 * 16).ok());
112 auto selection = object_editor->GetSelection();
113 EXPECT_EQ(selection.selected_objects.size(), 1);
114
115 // Test object deletion
116 ASSERT_TRUE(object_editor->DeleteSelectedObjects().ok());
117 EXPECT_EQ(object_editor->GetObjectCount(), 1);
118}
119
120// Test sprite management
122 // Set current room
123 ASSERT_TRUE(dungeon_editor_system_->SetCurrentRoom(0x0000).ok());
124
125 // Create sprite data
127 sprite_data.sprite_id = 1;
128 sprite_data.name = "Test Sprite";
130 sprite_data.x = 100;
131 sprite_data.y = 100;
132 sprite_data.layer = 0;
133 sprite_data.is_active = true;
134
135 // Add sprite
136 ASSERT_TRUE(dungeon_editor_system_->AddSprite(sprite_data).ok());
137
138 // Get sprites for room
139 auto sprites_result = dungeon_editor_system_->GetSpritesByRoom(0x0000);
140 ASSERT_TRUE(sprites_result.ok()) << "Failed to get sprites: " << sprites_result.status().message();
141
142 const auto& sprites = sprites_result.value();
143 EXPECT_EQ(sprites.size(), 1);
144 EXPECT_EQ(sprites[0].sprite_id, 1);
145 EXPECT_EQ(sprites[0].name, "Test Sprite");
146
147 // Update sprite
148 sprite_data.x = 150;
149 ASSERT_TRUE(dungeon_editor_system_->UpdateSprite(1, sprite_data).ok());
150
151 // Get updated sprite
152 auto sprite_result = dungeon_editor_system_->GetSprite(1);
153 ASSERT_TRUE(sprite_result.ok());
154 EXPECT_EQ(sprite_result.value().x, 150);
155
156 // Remove sprite
157 ASSERT_TRUE(dungeon_editor_system_->RemoveSprite(1).ok());
158
159 // Verify sprite was removed
160 auto sprites_after = dungeon_editor_system_->GetSpritesByRoom(0x0000);
161 ASSERT_TRUE(sprites_after.ok());
162 EXPECT_EQ(sprites_after.value().size(), 0);
163}
164
165// Test item management
167 // Set current room
168 ASSERT_TRUE(dungeon_editor_system_->SetCurrentRoom(0x0000).ok());
169
170 // Create item data
172 item_data.item_id = 1;
174 item_data.name = "Small Key";
175 item_data.x = 200;
176 item_data.y = 200;
177 item_data.room_id = 0x0000;
178 item_data.is_hidden = false;
179
180 // Add item
181 ASSERT_TRUE(dungeon_editor_system_->AddItem(item_data).ok());
182
183 // Get items for room
184 auto items_result = dungeon_editor_system_->GetItemsByRoom(0x0000);
185 ASSERT_TRUE(items_result.ok()) << "Failed to get items: " << items_result.status().message();
186
187 const auto& items = items_result.value();
188 EXPECT_EQ(items.size(), 1);
189 EXPECT_EQ(items[0].item_id, 1);
190 EXPECT_EQ(items[0].name, "Small Key");
191
192 // Update item
193 item_data.is_hidden = true;
194 ASSERT_TRUE(dungeon_editor_system_->UpdateItem(1, item_data).ok());
195
196 // Get updated item
197 auto item_result = dungeon_editor_system_->GetItem(1);
198 ASSERT_TRUE(item_result.ok());
199 EXPECT_TRUE(item_result.value().is_hidden);
200
201 // Remove item
202 ASSERT_TRUE(dungeon_editor_system_->RemoveItem(1).ok());
203
204 // Verify item was removed
205 auto items_after = dungeon_editor_system_->GetItemsByRoom(0x0000);
206 ASSERT_TRUE(items_after.ok());
207 EXPECT_EQ(items_after.value().size(), 0);
208}
209
210// Test entrance management
212 // Create entrance data
214 entrance_data.entrance_id = 1;
216 entrance_data.name = "Test Entrance";
217 entrance_data.source_room_id = 0x0000;
218 entrance_data.target_room_id = 0x0001;
219 entrance_data.source_x = 100;
220 entrance_data.source_y = 100;
221 entrance_data.target_x = 200;
222 entrance_data.target_y = 200;
223 entrance_data.is_bidirectional = true;
224
225 // Add entrance
226 ASSERT_TRUE(dungeon_editor_system_->AddEntrance(entrance_data).ok());
227
228 // Get entrances for room
229 auto entrances_result = dungeon_editor_system_->GetEntrancesByRoom(0x0000);
230 ASSERT_TRUE(entrances_result.ok()) << "Failed to get entrances: " << entrances_result.status().message();
231
232 const auto& entrances = entrances_result.value();
233 EXPECT_EQ(entrances.size(), 1);
234 EXPECT_EQ(entrances[0].name, "Test Entrance");
235
236 // Store the entrance ID for later removal
237 int entrance_id = entrances[0].entrance_id;
238
239 // Test room connection
240 ASSERT_TRUE(dungeon_editor_system_->ConnectRooms(0x0000, 0x0001, 150, 150, 250, 250).ok());
241
242 // Get updated entrances
243 auto entrances_after = dungeon_editor_system_->GetEntrancesByRoom(0x0000);
244 ASSERT_TRUE(entrances_after.ok());
245 EXPECT_GE(entrances_after.value().size(), 1);
246
247 // Remove entrance using the correct ID
248 ASSERT_TRUE(dungeon_editor_system_->RemoveEntrance(entrance_id).ok());
249
250 // Verify entrance was removed
251 auto entrances_final = dungeon_editor_system_->GetEntrancesByRoom(0x0000);
252 ASSERT_TRUE(entrances_final.ok());
253 EXPECT_EQ(entrances_final.value().size(), 0);
254}
255
256// Test door management
258 // Create door data
260 door_data.door_id = 1;
261 door_data.name = "Test Door";
262 door_data.room_id = 0x0000;
263 door_data.x = 100;
264 door_data.y = 100;
265 door_data.direction = 0; // up
266 door_data.target_room_id = 0x0001;
267 door_data.target_x = 200;
268 door_data.target_y = 200;
269 door_data.requires_key = false;
270 door_data.key_type = 0;
271 door_data.is_locked = false;
272
273 // Add door
274 ASSERT_TRUE(dungeon_editor_system_->AddDoor(door_data).ok());
275
276 // Get doors for room
277 auto doors_result = dungeon_editor_system_->GetDoorsByRoom(0x0000);
278 ASSERT_TRUE(doors_result.ok()) << "Failed to get doors: " << doors_result.status().message();
279
280 const auto& doors = doors_result.value();
281 EXPECT_EQ(doors.size(), 1);
282 EXPECT_EQ(doors[0].door_id, 1);
283 EXPECT_EQ(doors[0].name, "Test Door");
284
285 // Update door
286 door_data.is_locked = true;
287 ASSERT_TRUE(dungeon_editor_system_->UpdateDoor(1, door_data).ok());
288
289 // Get updated door
290 auto door_result = dungeon_editor_system_->GetDoor(1);
291 ASSERT_TRUE(door_result.ok());
292 EXPECT_TRUE(door_result.value().is_locked);
293
294 // Set door key requirement
295 ASSERT_TRUE(dungeon_editor_system_->SetDoorKeyRequirement(1, true, 1).ok());
296
297 // Get door with key requirement
298 auto door_with_key = dungeon_editor_system_->GetDoor(1);
299 ASSERT_TRUE(door_with_key.ok());
300 EXPECT_TRUE(door_with_key.value().requires_key);
301 EXPECT_EQ(door_with_key.value().key_type, 1);
302
303 // Remove door
304 ASSERT_TRUE(dungeon_editor_system_->RemoveDoor(1).ok());
305
306 // Verify door was removed
307 auto doors_after = dungeon_editor_system_->GetDoorsByRoom(0x0000);
308 ASSERT_TRUE(doors_after.ok());
309 EXPECT_EQ(doors_after.value().size(), 0);
310}
311
312// Test chest management
314 // Create chest data
316 chest_data.chest_id = 1;
317 chest_data.room_id = 0x0000;
318 chest_data.x = 100;
319 chest_data.y = 100;
320 chest_data.is_big_chest = false;
321 chest_data.item_id = 10;
322 chest_data.item_quantity = 1;
323 chest_data.is_opened = false;
324
325 // Add chest
326 ASSERT_TRUE(dungeon_editor_system_->AddChest(chest_data).ok());
327
328 // Get chests for room
329 auto chests_result = dungeon_editor_system_->GetChestsByRoom(0x0000);
330 ASSERT_TRUE(chests_result.ok()) << "Failed to get chests: " << chests_result.status().message();
331
332 const auto& chests = chests_result.value();
333 EXPECT_EQ(chests.size(), 1);
334 EXPECT_EQ(chests[0].chest_id, 1);
335 EXPECT_EQ(chests[0].item_id, 10);
336
337 // Update chest item
338 ASSERT_TRUE(dungeon_editor_system_->SetChestItem(1, 20, 5).ok());
339
340 // Get updated chest
341 auto chest_result = dungeon_editor_system_->GetChest(1);
342 ASSERT_TRUE(chest_result.ok());
343 EXPECT_EQ(chest_result.value().item_id, 20);
344 EXPECT_EQ(chest_result.value().item_quantity, 5);
345
346 // Set chest as opened
347 ASSERT_TRUE(dungeon_editor_system_->SetChestOpened(1, true).ok());
348
349 // Get opened chest
350 auto opened_chest = dungeon_editor_system_->GetChest(1);
351 ASSERT_TRUE(opened_chest.ok());
352 EXPECT_TRUE(opened_chest.value().is_opened);
353
354 // Remove chest
355 ASSERT_TRUE(dungeon_editor_system_->RemoveChest(1).ok());
356
357 // Verify chest was removed
358 auto chests_after = dungeon_editor_system_->GetChestsByRoom(0x0000);
359 ASSERT_TRUE(chests_after.ok());
360 EXPECT_EQ(chests_after.value().size(), 0);
361}
362
363// Test room properties management
364TEST_F(DungeonEditorSystemIntegrationTest, RoomPropertiesManagement) {
365 // Create room properties
367 properties.room_id = 0x0000;
368 properties.name = "Test Room";
369 properties.description = "A test room for integration testing";
370 properties.dungeon_id = 1;
371 properties.floor_level = 0;
372 properties.is_boss_room = false;
373 properties.is_save_room = false;
374 properties.is_shop_room = false;
375 properties.music_id = 1;
376 properties.ambient_sound_id = 0;
377
378 // Set room properties
379 ASSERT_TRUE(dungeon_editor_system_->SetRoomProperties(0x0000, properties).ok());
380
381 // Get room properties
382 auto properties_result = dungeon_editor_system_->GetRoomProperties(0x0000);
383 ASSERT_TRUE(properties_result.ok()) << "Failed to get room properties: " << properties_result.status().message();
384
385 const auto& retrieved_properties = properties_result.value();
386 EXPECT_EQ(retrieved_properties.room_id, 0x0000);
387 EXPECT_EQ(retrieved_properties.name, "Test Room");
388 EXPECT_EQ(retrieved_properties.description, "A test room for integration testing");
389 EXPECT_EQ(retrieved_properties.dungeon_id, 1);
390
391 // Update properties
392 properties.name = "Updated Test Room";
393 properties.is_boss_room = true;
394 ASSERT_TRUE(dungeon_editor_system_->SetRoomProperties(0x0000, properties).ok());
395
396 // Verify update
397 auto updated_properties = dungeon_editor_system_->GetRoomProperties(0x0000);
398 ASSERT_TRUE(updated_properties.ok());
399 EXPECT_EQ(updated_properties.value().name, "Updated Test Room");
400 EXPECT_TRUE(updated_properties.value().is_boss_room);
401}
402
403// Test dungeon settings management
404TEST_F(DungeonEditorSystemIntegrationTest, DungeonSettingsManagement) {
405 // Create dungeon settings
407 settings.dungeon_id = 1;
408 settings.name = "Test Dungeon";
409 settings.description = "A test dungeon for integration testing";
410 settings.total_rooms = 10;
411 settings.starting_room_id = 0x0000;
412 settings.boss_room_id = 0x0001;
413 settings.music_theme_id = 1;
414 settings.color_palette_id = 0;
415 settings.has_map = true;
416 settings.has_compass = true;
417 settings.has_big_key = true;
418
419 // Set dungeon settings
420 ASSERT_TRUE(dungeon_editor_system_->SetDungeonSettings(settings).ok());
421
422 // Get dungeon settings
423 auto settings_result = dungeon_editor_system_->GetDungeonSettings();
424 ASSERT_TRUE(settings_result.ok()) << "Failed to get dungeon settings: " << settings_result.status().message();
425
426 const auto& retrieved_settings = settings_result.value();
427 EXPECT_EQ(retrieved_settings.dungeon_id, 1);
428 EXPECT_EQ(retrieved_settings.name, "Test Dungeon");
429 EXPECT_EQ(retrieved_settings.total_rooms, 10);
430 EXPECT_EQ(retrieved_settings.starting_room_id, 0x0000);
431 EXPECT_EQ(retrieved_settings.boss_room_id, 0x0001);
432 EXPECT_TRUE(retrieved_settings.has_map);
433 EXPECT_TRUE(retrieved_settings.has_compass);
434 EXPECT_TRUE(retrieved_settings.has_big_key);
435}
436
437// Test undo/redo functionality
439 // Set current room
440 ASSERT_TRUE(dungeon_editor_system_->SetCurrentRoom(0x0000).ok());
441
442 // Get object editor
443 auto object_editor = dungeon_editor_system_->GetObjectEditor();
444 ASSERT_NE(object_editor, nullptr);
445
446 // Add some objects
447 ASSERT_TRUE(object_editor->InsertObject(5, 5, 0x10, 0x12, 0).ok());
448 ASSERT_TRUE(object_editor->InsertObject(10, 10, 0x20, 0x22, 1).ok());
449
450 // Verify objects were added
451 EXPECT_EQ(object_editor->GetObjectCount(), 2);
452
453 // Test undo
454 ASSERT_TRUE(dungeon_editor_system_->Undo().ok());
455 EXPECT_EQ(object_editor->GetObjectCount(), 1);
456
457 // Test redo
458 ASSERT_TRUE(dungeon_editor_system_->Redo().ok());
459 EXPECT_EQ(object_editor->GetObjectCount(), 2);
460
461 // Test multiple undos
462 ASSERT_TRUE(dungeon_editor_system_->Undo().ok());
463 ASSERT_TRUE(dungeon_editor_system_->Undo().ok());
464 EXPECT_EQ(object_editor->GetObjectCount(), 0);
465
466 // Test multiple redos
467 ASSERT_TRUE(dungeon_editor_system_->Redo().ok());
468 ASSERT_TRUE(dungeon_editor_system_->Redo().ok());
469 EXPECT_EQ(object_editor->GetObjectCount(), 2);
470}
471
472// Test validation functionality
474 // Set current room
475 ASSERT_TRUE(dungeon_editor_system_->SetCurrentRoom(0x0000).ok());
476
477 // Validate room
478 auto room_validation = dungeon_editor_system_->ValidateRoom(0x0000);
479 ASSERT_TRUE(room_validation.ok()) << "Room validation failed: " << room_validation.message();
480
481 // Validate dungeon
482 auto dungeon_validation = dungeon_editor_system_->ValidateDungeon();
483 ASSERT_TRUE(dungeon_validation.ok()) << "Dungeon validation failed: " << dungeon_validation.message();
484}
485
486// Test save/load functionality
488 // Set current room and add some objects
489 ASSERT_TRUE(dungeon_editor_system_->SetCurrentRoom(0x0000).ok());
490
491 auto object_editor = dungeon_editor_system_->GetObjectEditor();
492 ASSERT_NE(object_editor, nullptr);
493
494 ASSERT_TRUE(object_editor->InsertObject(5, 5, 0x10, 0x12, 0).ok());
495 ASSERT_TRUE(object_editor->InsertObject(10, 10, 0x20, 0x22, 1).ok());
496
497 // Save room
498 ASSERT_TRUE(dungeon_editor_system_->SaveRoom(0x0000).ok());
499
500 // Reload room
501 ASSERT_TRUE(dungeon_editor_system_->ReloadRoom(0x0000).ok());
502
503 // Verify objects are still there
504 auto reloaded_objects = object_editor->GetObjects();
505 EXPECT_EQ(reloaded_objects.size(), 2);
506
507 // Save entire dungeon
508 ASSERT_TRUE(dungeon_editor_system_->SaveDungeon().ok());
509}
510
511// Test performance with multiple operations
513 auto start_time = std::chrono::high_resolution_clock::now();
514
515 // Perform many operations
516 for (int i = 0; i < 100; i++) {
517 // Add sprite
519 sprite_data.sprite_id = i;
521 sprite_data.x = i * 10;
522 sprite_data.y = i * 10;
523 sprite_data.layer = 0;
524
525 ASSERT_TRUE(dungeon_editor_system_->AddSprite(sprite_data).ok());
526
527 // Add item
529 item_data.item_id = i;
531 item_data.x = i * 15;
532 item_data.y = i * 15;
533 item_data.room_id = 0x0000;
534
535 ASSERT_TRUE(dungeon_editor_system_->AddItem(item_data).ok());
536 }
537
538 auto end_time = std::chrono::high_resolution_clock::now();
539 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
540
541 // Should complete in reasonable time (less than 5 seconds for 200 operations)
542 EXPECT_LT(duration.count(), 5000) << "Performance test too slow: " << duration.count() << "ms";
543
544 std::cout << "Performance test: 200 operations took " << duration.count() << "ms" << std::endl;
545}
546
547// Test error handling
549 // Test with invalid room ID
550 auto invalid_room = dungeon_editor_system_->GetRoom(-1);
551 EXPECT_FALSE(invalid_room.ok());
552
553 auto invalid_room_large = dungeon_editor_system_->GetRoom(10000);
554 EXPECT_FALSE(invalid_room_large.ok());
555
556 // Test with invalid sprite ID
557 auto invalid_sprite = dungeon_editor_system_->GetSprite(-1);
558 EXPECT_FALSE(invalid_sprite.ok());
559
560 // Test with invalid item ID
561 auto invalid_item = dungeon_editor_system_->GetItem(-1);
562 EXPECT_FALSE(invalid_item.ok());
563
564 // Test with invalid entrance ID
565 auto invalid_entrance = dungeon_editor_system_->GetEntrance(-1);
566 EXPECT_FALSE(invalid_entrance.ok());
567
568 // Test with invalid door ID
569 auto invalid_door = dungeon_editor_system_->GetDoor(-1);
570 EXPECT_FALSE(invalid_door.ok());
571
572 // Test with invalid chest ID
573 auto invalid_chest = dungeon_editor_system_->GetChest(-1);
574 EXPECT_FALSE(invalid_chest.ok());
575}
576
577} // namespace zelda3
578} // namespace yaze
TEST_F(DungeonEditorSystemIntegrationTest, BasicInitialization)
Main namespace for the application.
Legacy chest data structure.
Definition zelda.h:437