#include "zelda3/dungeon/object_parser.h" #include #include #include #include "mocks/mock_rom.h" namespace yaze { namespace test { class ObjectParserTest : public ::testing::Test { protected: void SetUp() override { mock_rom_ = std::make_unique(); SetupMockData(); parser_ = std::make_unique(mock_rom_.get()); } void SetupMockData() { std::vector mock_data(0x100000, 0x00); // Set up object subtype tables SetupSubtypeTable(mock_data, 0x8000, 0x100); // Subtype 1 table SetupSubtypeTable(mock_data, 0x83F0, 0x80); // Subtype 2 table SetupSubtypeTable(mock_data, 0x84F0, 0x100); // Subtype 3 table // Set up tile data SetupTileData(mock_data, 0x1B52, 0x1000); static_cast(mock_rom_.get())->SetTestData(mock_data); } void SetupSubtypeTable(std::vector& data, int base_addr, int count) { for (int i = 0; i < count; i++) { int addr = base_addr + (i * 2); if (addr + 1 < (int)data.size()) { // Point to tile data at 0x1B52 + (i * 8) int tile_offset = (i * 8) & 0xFFFF; data[addr] = tile_offset & 0xFF; data[addr + 1] = (tile_offset >> 8) & 0xFF; } } } void SetupTileData(std::vector& data, int base_addr, int size) { for (int i = 0; i < size; i += 8) { int addr = base_addr + i; if (addr + 7 < (int)data.size()) { // Create simple tile data (4 words per tile) for (int j = 0; j < 8; j++) { data[addr + j] = (i + j) & 0xFF; } } } } std::unique_ptr mock_rom_; std::unique_ptr parser_; }; TEST_F(ObjectParserTest, ParseSubtype1Object) { auto result = parser_->ParseObject(0x01); ASSERT_TRUE(result.ok()); const auto& tiles = result.value(); EXPECT_EQ(tiles.size(), 8); // Verify tile data was parsed correctly for (const auto& tile : tiles) { EXPECT_NE(tile.id_, 0); } } TEST_F(ObjectParserTest, ParseSubtype2Object) { auto result = parser_->ParseObject(0x101); ASSERT_TRUE(result.ok()); const auto& tiles = result.value(); EXPECT_EQ(tiles.size(), 8); } TEST_F(ObjectParserTest, ParseSubtype3Object) { auto result = parser_->ParseObject(0x201); ASSERT_TRUE(result.ok()); const auto& tiles = result.value(); EXPECT_EQ(tiles.size(), 8); } TEST_F(ObjectParserTest, GetObjectSubtype) { // Subtype 1: Object IDs 0x00-0xFF auto result1 = parser_->GetObjectSubtype(0x01); ASSERT_TRUE(result1.ok()); EXPECT_EQ(result1->subtype, 1); // Subtype 2: Object IDs 0x100-0x1FF auto result2 = parser_->GetObjectSubtype(0x101); ASSERT_TRUE(result2.ok()); EXPECT_EQ(result2->subtype, 2); // Subtype 3: Object IDs 0xF80-0xFFF (decoded from b3 >= 0xF8) // These map to table indices 0-127 via (id - 0xF80) & 0x7F auto result3 = parser_->GetObjectSubtype(0xF81); ASSERT_TRUE(result3.ok()); EXPECT_EQ(result3->subtype, 3); } TEST_F(ObjectParserTest, ParseObjectSize) { // size_byte 0x09 = 0b00001001: size_x = 1 (bits 0-1), size_y = 2 (bits 2-3) auto result = parser_->ParseObjectSize(0x01, 0x09); ASSERT_TRUE(result.ok()); const auto& size_info = result.value(); EXPECT_EQ(size_info.width_tiles, 4); // (1 + 1) * 2 EXPECT_EQ(size_info.height_tiles, 6); // (2 + 1) * 2 EXPECT_TRUE(size_info.is_horizontal); EXPECT_TRUE(size_info.is_repeatable); EXPECT_EQ(size_info.repeat_count, 0x09); } TEST_F(ObjectParserTest, ParseObjectRoutine) { auto result = parser_->ParseObjectRoutine(0x01); ASSERT_TRUE(result.ok()); const auto& routine_info = result.value(); EXPECT_NE(routine_info.routine_ptr, 0); EXPECT_NE(routine_info.tile_ptr, 0); EXPECT_EQ(routine_info.tile_count, 8); EXPECT_TRUE(routine_info.is_repeatable); EXPECT_TRUE(routine_info.is_orientation_dependent); } TEST_F(ObjectParserTest, InvalidObjectId) { auto result = parser_->ParseObject(-1); EXPECT_FALSE(result.ok()); EXPECT_EQ(result.status().code(), absl::StatusCode::kInvalidArgument); } TEST_F(ObjectParserTest, NullRom) { zelda3::ObjectParser null_parser(nullptr); auto result = null_parser.ParseObject(0x01); EXPECT_FALSE(result.ok()); EXPECT_EQ(result.status().code(), absl::StatusCode::kInvalidArgument); } } // namespace test } // namespace yaze