246 lines
8.3 KiB
C++
246 lines
8.3 KiB
C++
#include "Features/Project/ProjectPanel.h"
|
|
#include "Rendering/Assets/BuiltInIcons.h"
|
|
|
|
#include <XCEditor/App/EditorPanelIds.h>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <chrono>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <string>
|
|
|
|
namespace XCEngine::UI::Editor::App {
|
|
namespace {
|
|
|
|
class TemporaryRepo final {
|
|
public:
|
|
TemporaryRepo() {
|
|
const auto uniqueSuffix =
|
|
std::chrono::steady_clock::now().time_since_epoch().count();
|
|
m_root =
|
|
std::filesystem::temp_directory_path() /
|
|
("xcengine_project_panel_" + std::to_string(uniqueSuffix));
|
|
}
|
|
|
|
~TemporaryRepo() {
|
|
std::error_code errorCode = {};
|
|
std::filesystem::remove_all(m_root, errorCode);
|
|
}
|
|
|
|
const std::filesystem::path& Root() const {
|
|
return m_root;
|
|
}
|
|
|
|
bool CreateDirectory(const std::filesystem::path& relativePath) const {
|
|
std::error_code errorCode = {};
|
|
std::filesystem::create_directories(m_root / relativePath, errorCode);
|
|
return !errorCode;
|
|
}
|
|
|
|
bool WriteFile(
|
|
const std::filesystem::path& relativePath,
|
|
std::string_view contents = "test") const {
|
|
const std::filesystem::path absolutePath = m_root / relativePath;
|
|
std::error_code errorCode = {};
|
|
std::filesystem::create_directories(absolutePath.parent_path(), errorCode);
|
|
if (errorCode) {
|
|
return false;
|
|
}
|
|
|
|
std::ofstream stream(absolutePath, std::ios::binary);
|
|
if (!stream.is_open()) {
|
|
return false;
|
|
}
|
|
|
|
stream << contents;
|
|
return stream.good();
|
|
}
|
|
|
|
private:
|
|
std::filesystem::path m_root = {};
|
|
};
|
|
|
|
UIEditorPanelContentHostFrame MakeProjectHostFrame() {
|
|
UIEditorPanelContentHostFrame frame = {};
|
|
UIEditorPanelContentHostPanelState panelState = {};
|
|
panelState.panelId = std::string(kProjectPanelId);
|
|
panelState.kind = UIEditorPanelPresentationKind::HostedContent;
|
|
panelState.mounted = true;
|
|
panelState.bounds = ::XCEngine::UI::UIRect(0.0f, 0.0f, 640.0f, 360.0f);
|
|
frame.panelStates.push_back(std::move(panelState));
|
|
return frame;
|
|
}
|
|
|
|
::XCEngine::UI::UIInputEvent MakePointerButtonDown(
|
|
float x,
|
|
float y,
|
|
::XCEngine::UI::UIPointerButton button) {
|
|
::XCEngine::UI::UIInputEvent event = {};
|
|
event.type = ::XCEngine::UI::UIInputEventType::PointerButtonDown;
|
|
event.position = ::XCEngine::UI::UIPoint(x, y);
|
|
event.pointerButton = button;
|
|
return event;
|
|
}
|
|
|
|
TEST(ProjectPanelTests, CreateFolderCommandCreatesDirectoryAndQueuesRename) {
|
|
TemporaryRepo repo = {};
|
|
|
|
ProjectPanel panel = {};
|
|
panel.Initialize(repo.Root());
|
|
|
|
const UIEditorHostCommandEvaluationResult evaluation =
|
|
panel.EvaluateAssetCommand("assets.create_folder");
|
|
EXPECT_TRUE(evaluation.executable);
|
|
|
|
const UIEditorHostCommandDispatchResult dispatch =
|
|
panel.DispatchAssetCommand("assets.create_folder");
|
|
EXPECT_TRUE(dispatch.commandExecuted);
|
|
EXPECT_TRUE(std::filesystem::exists(repo.Root() / "project/Assets/New Folder"));
|
|
|
|
const auto& events = panel.GetFrameEvents();
|
|
ASSERT_EQ(events.size(), 2u);
|
|
EXPECT_EQ(events[0].kind, ProjectPanel::EventKind::AssetSelected);
|
|
EXPECT_EQ(events[0].source, ProjectPanel::EventSource::Command);
|
|
EXPECT_EQ(events[0].itemId, "Assets/New Folder");
|
|
EXPECT_EQ(events[1].kind, ProjectPanel::EventKind::RenameRequested);
|
|
EXPECT_EQ(events[1].source, ProjectPanel::EventSource::Command);
|
|
EXPECT_EQ(events[1].itemId, "Assets/New Folder");
|
|
}
|
|
|
|
TEST(ProjectPanelTests, CreateMaterialCommandCreatesFileAndQueuesRename) {
|
|
TemporaryRepo repo = {};
|
|
|
|
ProjectPanel panel = {};
|
|
panel.Initialize(repo.Root());
|
|
|
|
const UIEditorHostCommandEvaluationResult evaluation =
|
|
panel.EvaluateAssetCommand("assets.create_material");
|
|
EXPECT_TRUE(evaluation.executable);
|
|
|
|
const UIEditorHostCommandDispatchResult dispatch =
|
|
panel.DispatchAssetCommand("assets.create_material");
|
|
EXPECT_TRUE(dispatch.commandExecuted);
|
|
EXPECT_TRUE(std::filesystem::exists(repo.Root() / "project/Assets/New Material.mat"));
|
|
|
|
const auto& events = panel.GetFrameEvents();
|
|
ASSERT_EQ(events.size(), 2u);
|
|
EXPECT_EQ(events[0].kind, ProjectPanel::EventKind::AssetSelected);
|
|
EXPECT_EQ(events[0].itemId, "Assets/New Material.mat");
|
|
EXPECT_EQ(events[1].kind, ProjectPanel::EventKind::RenameRequested);
|
|
EXPECT_EQ(events[1].itemId, "Assets/New Material.mat");
|
|
}
|
|
|
|
TEST(ProjectPanelTests, BackgroundContextMenuCreateFolderUsesCurrentFolder) {
|
|
TemporaryRepo repo = {};
|
|
|
|
ProjectPanel panel = {};
|
|
panel.Initialize(repo.Root());
|
|
|
|
const UIEditorPanelContentHostFrame hostFrame = MakeProjectHostFrame();
|
|
panel.Update(
|
|
hostFrame,
|
|
{ MakePointerButtonDown(520.0f, 180.0f, ::XCEngine::UI::UIPointerButton::Right) },
|
|
true,
|
|
true);
|
|
panel.Update(
|
|
hostFrame,
|
|
{ MakePointerButtonDown(520.0f, 194.0f, ::XCEngine::UI::UIPointerButton::Left) },
|
|
true,
|
|
true);
|
|
|
|
EXPECT_TRUE(std::filesystem::exists(repo.Root() / "project/Assets/New Folder"));
|
|
const UIEditorHostCommandEvaluationResult renameEvaluation =
|
|
panel.EvaluateEditCommand("edit.rename");
|
|
EXPECT_TRUE(renameEvaluation.executable);
|
|
EXPECT_EQ(renameEvaluation.message, "Rename project item 'New Folder'.");
|
|
|
|
const auto& events = panel.GetFrameEvents();
|
|
ASSERT_FALSE(events.empty());
|
|
EXPECT_EQ(events.back().kind, ProjectPanel::EventKind::RenameRequested);
|
|
EXPECT_EQ(events.back().itemId, "Assets/New Folder");
|
|
}
|
|
|
|
TEST(ProjectPanelTests, FolderContextMenuCreateFolderUsesFolderTarget) {
|
|
TemporaryRepo repo = {};
|
|
ASSERT_TRUE(std::filesystem::create_directories(repo.Root() / "project/Assets/FolderA"));
|
|
|
|
ProjectPanel panel = {};
|
|
panel.Initialize(repo.Root());
|
|
|
|
const UIEditorPanelContentHostFrame hostFrame = MakeProjectHostFrame();
|
|
panel.Update(
|
|
hostFrame,
|
|
{ MakePointerButtonDown(300.0f, 80.0f, ::XCEngine::UI::UIPointerButton::Right) },
|
|
true,
|
|
true);
|
|
panel.Update(
|
|
hostFrame,
|
|
{ MakePointerButtonDown(320.0f, 120.0f, ::XCEngine::UI::UIPointerButton::Left) },
|
|
true,
|
|
true);
|
|
|
|
EXPECT_TRUE(std::filesystem::exists(repo.Root() / "project/Assets/FolderA/New Folder"));
|
|
}
|
|
|
|
TEST(ProjectPanelTests, InjectedRuntimeSelectionDrivesRenameWithoutPanelSelectionSync) {
|
|
TemporaryRepo repo = {};
|
|
ASSERT_TRUE(repo.CreateDirectory("project/Assets/Scripts"));
|
|
ASSERT_TRUE(repo.WriteFile("project/Assets/Scripts/Player.cs"));
|
|
ASSERT_TRUE(repo.WriteFile("project/Assets/Scripts/Player.cs.meta"));
|
|
|
|
EditorProjectRuntime runtime = {};
|
|
ASSERT_TRUE(runtime.Initialize(repo.Root()));
|
|
|
|
ProjectPanel panel = {};
|
|
panel.SetProjectRuntime(&runtime);
|
|
|
|
ASSERT_TRUE(runtime.NavigateToFolder("Assets/Scripts"));
|
|
ASSERT_TRUE(runtime.SetSelection("Assets/Scripts/Player.cs"));
|
|
|
|
const UIEditorHostCommandDispatchResult dispatch =
|
|
panel.DispatchEditCommand("edit.rename");
|
|
EXPECT_TRUE(dispatch.commandExecuted);
|
|
|
|
const auto& events = panel.GetFrameEvents();
|
|
ASSERT_EQ(events.size(), 1u);
|
|
EXPECT_EQ(events[0].kind, ProjectPanel::EventKind::RenameRequested);
|
|
EXPECT_EQ(events[0].source, ProjectPanel::EventSource::GridPrimary);
|
|
EXPECT_EQ(events[0].itemId, "Assets/Scripts/Player.cs");
|
|
}
|
|
|
|
TEST(ProjectPanelTests, InjectedRuntimeCurrentFolderDrivesRenameFallbackWithoutTreeSync) {
|
|
TemporaryRepo repo = {};
|
|
ASSERT_TRUE(repo.CreateDirectory("project/Assets/FolderA"));
|
|
|
|
EditorProjectRuntime runtime = {};
|
|
ASSERT_TRUE(runtime.Initialize(repo.Root()));
|
|
|
|
ProjectPanel panel = {};
|
|
panel.SetProjectRuntime(&runtime);
|
|
|
|
ASSERT_TRUE(runtime.NavigateToFolder("Assets/FolderA"));
|
|
|
|
const UIEditorHostCommandEvaluationResult evaluation =
|
|
panel.EvaluateEditCommand("edit.rename");
|
|
EXPECT_TRUE(evaluation.executable);
|
|
EXPECT_EQ(evaluation.message, "Rename project item 'FolderA'.");
|
|
}
|
|
|
|
TEST(ProjectPanelTests, BuiltInIconsCanBeConfiguredBeforeRuntimeInitialization) {
|
|
TemporaryRepo repo = {};
|
|
|
|
ProjectPanel panel = {};
|
|
BuiltInIcons icons = {};
|
|
|
|
panel.SetBuiltInIcons(&icons);
|
|
panel.Initialize(repo.Root());
|
|
|
|
const UIEditorHostCommandEvaluationResult evaluation =
|
|
panel.EvaluateAssetCommand("assets.create_folder");
|
|
EXPECT_TRUE(evaluation.executable);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace XCEngine::UI::Editor::App
|