Files
XCEngine/tests/UI/Editor/unit/test_hierarchy_scene_binding.cpp

205 lines
6.6 KiB
C++
Raw Normal View History

#include "Features/Hierarchy/HierarchyModel.h"
#include "Scene/EditorSceneBridge.h"
#include <XCEngine/Components/GameObject.h>
#include <XCEngine/Core/Asset/ResourceManager.h>
#include <XCEngine/Scene/Scene.h>
#include <XCEngine/Scene/SceneManager.h>
#include <gtest/gtest.h>
#include <chrono>
#include <filesystem>
namespace XCEngine::UI::Editor::App {
namespace {
using ::XCEngine::Components::GameObject;
using ::XCEngine::Components::Scene;
using ::XCEngine::Components::SceneManager;
class ScopedSceneManagerReset final {
public:
ScopedSceneManagerReset() {
Reset();
}
~ScopedSceneManagerReset() {
Reset();
}
private:
static void Reset() {
SceneManager& manager = SceneManager::Get();
const auto scenes = manager.GetAllScenes();
for (Scene* scene : scenes) {
manager.UnloadScene(scene);
}
}
};
class TemporaryProjectRoot final {
public:
TemporaryProjectRoot() {
const auto uniqueSuffix =
std::chrono::steady_clock::now().time_since_epoch().count();
m_root =
std::filesystem::temp_directory_path() /
("xcui_hierarchy_scene_bridge_" + std::to_string(uniqueSuffix));
}
~TemporaryProjectRoot() {
std::error_code errorCode = {};
std::filesystem::remove_all(m_root, errorCode);
}
const std::filesystem::path& Root() const {
return m_root;
}
private:
std::filesystem::path m_root = {};
};
TEST(HierarchySceneBindingTests, BuildFromSceneUsesRealGameObjectIds) {
ScopedSceneManagerReset reset = {};
Scene* scene = SceneManager::Get().CreateScene("Main");
ASSERT_NE(scene, nullptr);
SceneManager::Get().SetActiveScene(scene);
GameObject* root = scene->CreateGameObject("Root");
ASSERT_NE(root, nullptr);
GameObject* child = scene->CreateGameObject("Child", root);
ASSERT_NE(child, nullptr);
const HierarchyModel model = HierarchyModel::BuildFromScene(scene);
const HierarchyNode* rootNode =
model.FindNode(MakeEditorGameObjectItemId(root->GetID()));
ASSERT_NE(rootNode, nullptr);
EXPECT_EQ(rootNode->label, "Root");
ASSERT_EQ(rootNode->children.size(), 1u);
EXPECT_EQ(
rootNode->children.front().nodeId,
MakeEditorGameObjectItemId(child->GetID()));
EXPECT_EQ(rootNode->children.front().label, "Child");
}
TEST(HierarchySceneBindingTests, DuplicateGameObjectClonesHierarchyIntoScene) {
ScopedSceneManagerReset reset = {};
Scene* scene = SceneManager::Get().CreateScene("Main");
ASSERT_NE(scene, nullptr);
SceneManager::Get().SetActiveScene(scene);
GameObject* root = scene->CreateGameObject("Root");
ASSERT_NE(root, nullptr);
GameObject* child = scene->CreateGameObject("Child", root);
ASSERT_NE(child, nullptr);
const std::string duplicateId =
DuplicateEditorGameObject(MakeEditorGameObjectItemId(root->GetID()));
ASSERT_FALSE(duplicateId.empty());
const HierarchyModel model = HierarchyModel::BuildFromScene(scene);
const HierarchyNode* duplicateNode = model.FindNode(duplicateId);
ASSERT_NE(duplicateNode, nullptr);
EXPECT_EQ(duplicateNode->label, "Root");
ASSERT_EQ(duplicateNode->children.size(), 1u);
EXPECT_EQ(duplicateNode->children.front().label, "Child");
const auto roots = scene->GetRootGameObjects();
EXPECT_EQ(roots.size(), 2u);
}
TEST(HierarchySceneBindingTests, RenameGameObjectUpdatesRealSceneAndProjection) {
ScopedSceneManagerReset reset = {};
Scene* scene = SceneManager::Get().CreateScene("Main");
ASSERT_NE(scene, nullptr);
SceneManager::Get().SetActiveScene(scene);
GameObject* gameObject = scene->CreateGameObject("Camera");
ASSERT_NE(gameObject, nullptr);
const std::string itemId =
MakeEditorGameObjectItemId(gameObject->GetID());
ASSERT_TRUE(RenameEditorGameObject(itemId, "PlayerCamera"));
EXPECT_EQ(gameObject->GetName(), "PlayerCamera");
const HierarchyModel model = HierarchyModel::BuildFromScene(scene);
const HierarchyNode* node = model.FindNode(itemId);
ASSERT_NE(node, nullptr);
EXPECT_EQ(node->label, "PlayerCamera");
}
TEST(HierarchySceneBindingTests, ReparentAndMoveToRootOperateOnRealScene) {
ScopedSceneManagerReset reset = {};
Scene* scene = SceneManager::Get().CreateScene("Main");
ASSERT_NE(scene, nullptr);
SceneManager::Get().SetActiveScene(scene);
GameObject* parentA = scene->CreateGameObject("ParentA");
ASSERT_NE(parentA, nullptr);
GameObject* parentB = scene->CreateGameObject("ParentB");
ASSERT_NE(parentB, nullptr);
GameObject* child = scene->CreateGameObject("Child", parentA);
ASSERT_NE(child, nullptr);
ASSERT_TRUE(ReparentEditorGameObject(
MakeEditorGameObjectItemId(child->GetID()),
MakeEditorGameObjectItemId(parentB->GetID())));
EXPECT_EQ(child->GetParent(), parentB);
HierarchyModel model = HierarchyModel::BuildFromScene(scene);
const HierarchyNode* parentBNode =
model.FindNode(MakeEditorGameObjectItemId(parentB->GetID()));
ASSERT_NE(parentBNode, nullptr);
ASSERT_EQ(parentBNode->children.size(), 1u);
EXPECT_EQ(parentBNode->children.front().label, "Child");
ASSERT_TRUE(MoveEditorGameObjectToRoot(
MakeEditorGameObjectItemId(child->GetID())));
EXPECT_EQ(child->GetParent(), nullptr);
model = HierarchyModel::BuildFromScene(scene);
const auto roots = scene->GetRootGameObjects();
EXPECT_EQ(roots.size(), 3u);
}
TEST(HierarchySceneBindingTests, EnsureStartupSceneLoadsMainSceneAndSetsActive) {
ScopedSceneManagerReset reset = {};
TemporaryProjectRoot projectRoot = {};
const std::filesystem::path scenePath =
projectRoot.Root() / "Assets" / "Scenes" / "Main.xc";
std::filesystem::create_directories(scenePath.parent_path());
{
Scene scene("Main");
scene.CreateGameObject("Camera");
scene.Save(scenePath.string());
}
const EditorStartupSceneResult result =
EnsureEditorStartupScene(projectRoot.Root());
EXPECT_TRUE(result.ready);
EXPECT_TRUE(result.loadedFromDisk);
ASSERT_NE(GetActiveEditorScene(), nullptr);
EXPECT_EQ(GetActiveEditorScene()->GetName(), "Main");
const HierarchyModel model =
HierarchyModel::BuildFromScene(GetActiveEditorScene());
EXPECT_FALSE(model.Empty());
SceneManager& sceneManager = SceneManager::Get();
const auto scenes = sceneManager.GetAllScenes();
for (Scene* scene : scenes) {
sceneManager.UnloadScene(scene);
}
::XCEngine::Resources::ResourceManager::Get().Shutdown();
}
} // namespace
} // namespace XCEngine::UI::Editor::App