Files
yaze/test/integration/object_selection_integration_test.cc

229 lines
8.0 KiB
C++

/**
* @file object_selection_integration_test.cc
* @brief Integration tests for ObjectSelection + DungeonObjectInteraction
*
* These tests verify the unified selection system works correctly when
* integrated with the dungeon editor interaction layer.
*/
#include <gtest/gtest.h>
#include "app/editor/dungeon/dungeon_object_interaction.h"
#include "app/editor/dungeon/object_selection.h"
#include "app/gui/canvas/canvas.h"
#include "zelda3/dungeon/room.h"
#include "zelda3/dungeon/room_object.h"
namespace yaze {
namespace editor {
namespace {
class ObjectSelectionIntegrationTest : public ::testing::Test {
protected:
void SetUp() override {
// Initialize rooms with some test objects
auto& room = rooms_[0];
room.AddTileObject(zelda3::RoomObject{0x01, 10, 10, 0x12, 0});
room.AddTileObject(zelda3::RoomObject{0x02, 20, 10, 0x14, 0});
room.AddTileObject(zelda3::RoomObject{0x03, 10, 20, 0x16, 1});
room.AddTileObject(zelda3::RoomObject{0x04, 30, 30, 0x18, 2});
// Set up interaction with the room
interaction_.SetCurrentRoom(&rooms_, 0);
}
std::array<zelda3::Room, 0x128> rooms_;
gui::Canvas canvas_{"TestCanvas", ImVec2(512, 512)};
DungeonObjectInteraction interaction_{&canvas_};
};
// =============================================================================
// Basic Selection Tests
// =============================================================================
TEST_F(ObjectSelectionIntegrationTest, InitialStateHasNoSelection) {
EXPECT_TRUE(interaction_.GetSelectedObjectIndices().empty());
EXPECT_EQ(interaction_.GetSelectionCount(), 0);
EXPECT_FALSE(interaction_.IsObjectSelectActive());
}
TEST_F(ObjectSelectionIntegrationTest, SetSelectedObjectsUpdatesSelection) {
std::vector<size_t> indices = {0, 2};
interaction_.SetSelectedObjects(indices);
auto selected = interaction_.GetSelectedObjectIndices();
EXPECT_EQ(selected.size(), 2);
EXPECT_TRUE(interaction_.IsObjectSelected(0));
EXPECT_FALSE(interaction_.IsObjectSelected(1));
EXPECT_TRUE(interaction_.IsObjectSelected(2));
EXPECT_FALSE(interaction_.IsObjectSelected(3));
}
TEST_F(ObjectSelectionIntegrationTest, ClearSelectionRemovesAllSelections) {
interaction_.SetSelectedObjects({0, 1, 2});
EXPECT_EQ(interaction_.GetSelectionCount(), 3);
interaction_.ClearSelection();
EXPECT_EQ(interaction_.GetSelectionCount(), 0);
EXPECT_TRUE(interaction_.GetSelectedObjectIndices().empty());
}
TEST_F(ObjectSelectionIntegrationTest, IsObjectSelectedReturnsCorrectValue) {
interaction_.SetSelectedObjects({1, 3});
EXPECT_FALSE(interaction_.IsObjectSelected(0));
EXPECT_TRUE(interaction_.IsObjectSelected(1));
EXPECT_FALSE(interaction_.IsObjectSelected(2));
EXPECT_TRUE(interaction_.IsObjectSelected(3));
}
// =============================================================================
// Selection Callback Tests
// =============================================================================
TEST_F(ObjectSelectionIntegrationTest, SelectionCallbackFires) {
int callback_count = 0;
interaction_.SetSelectionChangeCallback([&callback_count]() {
callback_count++;
});
// Setting selection should trigger callback
interaction_.SetSelectedObjects({0});
EXPECT_GE(callback_count, 1);
int count_after_first = callback_count;
// Clearing selection should also trigger callback
interaction_.ClearSelection();
EXPECT_GT(callback_count, count_after_first);
}
TEST_F(ObjectSelectionIntegrationTest, MultipleSelectionChangesFireMultipleCallbacks) {
std::vector<std::vector<size_t>> callback_selections;
interaction_.SetSelectionChangeCallback([this, &callback_selections]() {
callback_selections.push_back(interaction_.GetSelectedObjectIndices());
});
interaction_.SetSelectedObjects({0});
interaction_.SetSelectedObjects({0, 1});
interaction_.SetSelectedObjects({2});
interaction_.ClearSelection();
// Should have received multiple callbacks
EXPECT_GE(callback_selections.size(), 2);
}
// =============================================================================
// Selection Count Tests
// =============================================================================
TEST_F(ObjectSelectionIntegrationTest, GetSelectionCountReturnsCorrectCount) {
EXPECT_EQ(interaction_.GetSelectionCount(), 0);
interaction_.SetSelectedObjects({0});
EXPECT_EQ(interaction_.GetSelectionCount(), 1);
interaction_.SetSelectedObjects({0, 1, 2});
EXPECT_EQ(interaction_.GetSelectionCount(), 3);
interaction_.SetSelectedObjects({0, 1, 2, 3});
EXPECT_EQ(interaction_.GetSelectionCount(), 4);
}
// =============================================================================
// Selection Mode Tests (via SetSelectedObjects behavior)
// =============================================================================
TEST_F(ObjectSelectionIntegrationTest, SetSelectedObjectsReplacesPreviousSelection) {
interaction_.SetSelectedObjects({0, 1});
EXPECT_EQ(interaction_.GetSelectionCount(), 2);
EXPECT_TRUE(interaction_.IsObjectSelected(0));
EXPECT_TRUE(interaction_.IsObjectSelected(1));
// Setting new selection should replace, not add
interaction_.SetSelectedObjects({2, 3});
EXPECT_EQ(interaction_.GetSelectionCount(), 2);
EXPECT_FALSE(interaction_.IsObjectSelected(0));
EXPECT_FALSE(interaction_.IsObjectSelected(1));
EXPECT_TRUE(interaction_.IsObjectSelected(2));
EXPECT_TRUE(interaction_.IsObjectSelected(3));
}
TEST_F(ObjectSelectionIntegrationTest, DuplicateIndicesAreHandled) {
// Setting the same index twice should only count once (using set internally)
interaction_.SetSelectedObjects({0, 0, 0, 1, 1});
// Should have 2 unique selections, not 5
EXPECT_EQ(interaction_.GetSelectionCount(), 2);
}
// =============================================================================
// Integration with Room Data
// =============================================================================
TEST_F(ObjectSelectionIntegrationTest, SelectionPersistsAcrossRoomAccess) {
interaction_.SetSelectedObjects({0, 2});
// Access room data (simulating what ObjectEditorPanel would do)
auto& room = rooms_[0];
const auto& objects = room.GetTileObjects();
EXPECT_EQ(objects.size(), 4);
// Selection should still be valid
EXPECT_EQ(interaction_.GetSelectionCount(), 2);
EXPECT_TRUE(interaction_.IsObjectSelected(0));
EXPECT_TRUE(interaction_.IsObjectSelected(2));
}
TEST_F(ObjectSelectionIntegrationTest, OutOfBoundsIndicesAreAccepted) {
// The selection system accepts indices without validating against room size
// This is intentional - the room might not be loaded yet
interaction_.SetSelectedObjects({100, 200});
EXPECT_EQ(interaction_.GetSelectionCount(), 2);
EXPECT_TRUE(interaction_.IsObjectSelected(100));
}
// =============================================================================
// IsObjectSelectActive Tests
// =============================================================================
TEST_F(ObjectSelectionIntegrationTest, IsObjectSelectActiveWhenHasSelection) {
EXPECT_FALSE(interaction_.IsObjectSelectActive());
interaction_.SetSelectedObjects({0});
EXPECT_TRUE(interaction_.IsObjectSelectActive());
interaction_.ClearSelection();
EXPECT_FALSE(interaction_.IsObjectSelectActive());
}
// =============================================================================
// Empty Selection Tests
// =============================================================================
TEST_F(ObjectSelectionIntegrationTest, EmptyVectorClearsSelection) {
interaction_.SetSelectedObjects({0, 1, 2});
EXPECT_EQ(interaction_.GetSelectionCount(), 3);
interaction_.SetSelectedObjects({});
EXPECT_EQ(interaction_.GetSelectionCount(), 0);
}
TEST_F(ObjectSelectionIntegrationTest, ClearSelectionIsIdempotent) {
interaction_.ClearSelection();
EXPECT_EQ(interaction_.GetSelectionCount(), 0);
interaction_.ClearSelection();
EXPECT_EQ(interaction_.GetSelectionCount(), 0);
interaction_.SetSelectedObjects({0});
interaction_.ClearSelection();
interaction_.ClearSelection();
EXPECT_EQ(interaction_.GetSelectionCount(), 0);
}
} // namespace
} // namespace editor
} // namespace yaze