Add editor panel host lifecycle contract
This commit is contained in:
@@ -9,6 +9,7 @@ set(EDITOR_UI_UNIT_TEST_SOURCES
|
||||
test_ui_editor_menu_session.cpp
|
||||
test_ui_editor_menu_bar.cpp
|
||||
test_ui_editor_menu_popup.cpp
|
||||
test_ui_editor_panel_host_lifecycle.cpp
|
||||
test_ui_editor_panel_registry.cpp
|
||||
test_ui_editor_shell_compose.cpp
|
||||
test_ui_editor_shell_interaction.cpp
|
||||
|
||||
246
tests/UI/Editor/unit/test_ui_editor_panel_host_lifecycle.cpp
Normal file
246
tests/UI/Editor/unit/test_ui_editor_panel_host_lifecycle.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <XCEditor/Core/UIEditorPanelHostLifecycle.h>
|
||||
|
||||
namespace {
|
||||
|
||||
using XCEngine::UI::Editor::BuildDefaultUIEditorWorkspaceSession;
|
||||
using XCEngine::UI::Editor::BuildUIEditorWorkspacePanel;
|
||||
using XCEngine::UI::Editor::BuildUIEditorWorkspaceSplit;
|
||||
using XCEngine::UI::Editor::BuildUIEditorWorkspaceTabStack;
|
||||
using XCEngine::UI::Editor::FindUIEditorPanelHostState;
|
||||
using XCEngine::UI::Editor::GetUIEditorPanelHostLifecycleEventKindName;
|
||||
using XCEngine::UI::Editor::TryCloseUIEditorWorkspacePanel;
|
||||
using XCEngine::UI::Editor::TryHideUIEditorWorkspacePanel;
|
||||
using XCEngine::UI::Editor::TryOpenUIEditorWorkspacePanel;
|
||||
using XCEngine::UI::Editor::UIEditorPanelHostLifecycleRequest;
|
||||
using XCEngine::UI::Editor::UIEditorPanelHostLifecycleState;
|
||||
using XCEngine::UI::Editor::UIEditorPanelRegistry;
|
||||
using XCEngine::UI::Editor::UIEditorWorkspaceModel;
|
||||
using XCEngine::UI::Editor::UIEditorWorkspaceSession;
|
||||
using XCEngine::UI::Editor::UIEditorWorkspaceSplitAxis;
|
||||
using XCEngine::UI::Editor::UpdateUIEditorPanelHostLifecycle;
|
||||
|
||||
UIEditorPanelRegistry BuildPanelRegistry() {
|
||||
UIEditorPanelRegistry registry = {};
|
||||
registry.panels = {
|
||||
{ "doc-a", "Document A", {}, true, true, true },
|
||||
{ "doc-b", "Document B", {}, true, true, true },
|
||||
{ "details", "Details", {}, true, true, true }
|
||||
};
|
||||
return registry;
|
||||
}
|
||||
|
||||
UIEditorWorkspaceModel BuildWorkspace() {
|
||||
UIEditorWorkspaceModel workspace = {};
|
||||
workspace.root = BuildUIEditorWorkspaceSplit(
|
||||
"root-split",
|
||||
UIEditorWorkspaceSplitAxis::Horizontal,
|
||||
0.66f,
|
||||
BuildUIEditorWorkspaceTabStack(
|
||||
"document-tabs",
|
||||
{
|
||||
BuildUIEditorWorkspacePanel("doc-a-node", "doc-a", "Document A", true),
|
||||
BuildUIEditorWorkspacePanel("doc-b-node", "doc-b", "Document B", true)
|
||||
},
|
||||
0u),
|
||||
BuildUIEditorWorkspacePanel("details-node", "details", "Details", true));
|
||||
workspace.activePanelId = "doc-a";
|
||||
return workspace;
|
||||
}
|
||||
|
||||
std::vector<std::string> FormatEvents(
|
||||
const std::vector<XCEngine::UI::Editor::UIEditorPanelHostLifecycleEvent>& events) {
|
||||
std::vector<std::string> formatted = {};
|
||||
formatted.reserve(events.size());
|
||||
for (const auto& event : events) {
|
||||
formatted.push_back(
|
||||
std::string(GetUIEditorPanelHostLifecycleEventKindName(event.kind)) + ":" + event.panelId);
|
||||
}
|
||||
return formatted;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(UIEditorPanelHostLifecycleTest, InitialFrameResolvesAttachedVisibleActiveAndFocusedPanels) {
|
||||
const UIEditorPanelRegistry registry = BuildPanelRegistry();
|
||||
const UIEditorWorkspaceModel workspace = BuildWorkspace();
|
||||
const UIEditorWorkspaceSession session =
|
||||
BuildDefaultUIEditorWorkspaceSession(registry, workspace);
|
||||
|
||||
UIEditorPanelHostLifecycleState lifecycleState = {};
|
||||
const auto frame = UpdateUIEditorPanelHostLifecycle(
|
||||
lifecycleState,
|
||||
registry,
|
||||
workspace,
|
||||
session,
|
||||
UIEditorPanelHostLifecycleRequest{ "doc-a" });
|
||||
|
||||
ASSERT_EQ(frame.panelStates.size(), 3u);
|
||||
const auto* docA = FindUIEditorPanelHostState(frame, "doc-a");
|
||||
const auto* docB = FindUIEditorPanelHostState(frame, "doc-b");
|
||||
const auto* details = FindUIEditorPanelHostState(frame, "details");
|
||||
ASSERT_NE(docA, nullptr);
|
||||
ASSERT_NE(docB, nullptr);
|
||||
ASSERT_NE(details, nullptr);
|
||||
|
||||
EXPECT_TRUE(docA->attached);
|
||||
EXPECT_TRUE(docA->visible);
|
||||
EXPECT_TRUE(docA->active);
|
||||
EXPECT_TRUE(docA->focused);
|
||||
|
||||
EXPECT_TRUE(docB->attached);
|
||||
EXPECT_FALSE(docB->visible);
|
||||
EXPECT_FALSE(docB->active);
|
||||
EXPECT_FALSE(docB->focused);
|
||||
|
||||
EXPECT_TRUE(details->attached);
|
||||
EXPECT_TRUE(details->visible);
|
||||
EXPECT_FALSE(details->active);
|
||||
EXPECT_FALSE(details->focused);
|
||||
|
||||
const std::vector<std::string> expectedEvents = {
|
||||
"Attached:doc-a",
|
||||
"Attached:doc-b",
|
||||
"Attached:details",
|
||||
"Shown:doc-a",
|
||||
"Shown:details",
|
||||
"Activated:doc-a",
|
||||
"FocusGained:doc-a"
|
||||
};
|
||||
EXPECT_EQ(FormatEvents(frame.events), expectedEvents);
|
||||
}
|
||||
|
||||
TEST(UIEditorPanelHostLifecycleTest, HidingActiveTabKeepsPanelAttachedButEmitsVisibilityAndActivationTransitions) {
|
||||
const UIEditorPanelRegistry registry = BuildPanelRegistry();
|
||||
UIEditorWorkspaceModel workspace = BuildWorkspace();
|
||||
UIEditorWorkspaceSession session =
|
||||
BuildDefaultUIEditorWorkspaceSession(registry, workspace);
|
||||
|
||||
UIEditorPanelHostLifecycleState lifecycleState = {};
|
||||
UpdateUIEditorPanelHostLifecycle(
|
||||
lifecycleState,
|
||||
registry,
|
||||
workspace,
|
||||
session,
|
||||
UIEditorPanelHostLifecycleRequest{ "doc-a" });
|
||||
|
||||
ASSERT_TRUE(TryHideUIEditorWorkspacePanel(registry, workspace, session, "doc-a"));
|
||||
const auto frame = UpdateUIEditorPanelHostLifecycle(
|
||||
lifecycleState,
|
||||
registry,
|
||||
workspace,
|
||||
session,
|
||||
UIEditorPanelHostLifecycleRequest{ "doc-b" });
|
||||
|
||||
const auto* docA = FindUIEditorPanelHostState(frame, "doc-a");
|
||||
const auto* docB = FindUIEditorPanelHostState(frame, "doc-b");
|
||||
ASSERT_NE(docA, nullptr);
|
||||
ASSERT_NE(docB, nullptr);
|
||||
|
||||
EXPECT_TRUE(docA->attached);
|
||||
EXPECT_FALSE(docA->visible);
|
||||
EXPECT_FALSE(docA->active);
|
||||
EXPECT_FALSE(docA->focused);
|
||||
|
||||
EXPECT_TRUE(docB->attached);
|
||||
EXPECT_TRUE(docB->visible);
|
||||
EXPECT_TRUE(docB->active);
|
||||
EXPECT_TRUE(docB->focused);
|
||||
|
||||
const std::vector<std::string> expectedEvents = {
|
||||
"FocusLost:doc-a",
|
||||
"Deactivated:doc-a",
|
||||
"Hidden:doc-a",
|
||||
"Shown:doc-b",
|
||||
"Activated:doc-b",
|
||||
"FocusGained:doc-b"
|
||||
};
|
||||
EXPECT_EQ(FormatEvents(frame.events), expectedEvents);
|
||||
}
|
||||
|
||||
TEST(UIEditorPanelHostLifecycleTest, ClosingHiddenPanelEmitsDetachWithoutVisibilityTransitions) {
|
||||
const UIEditorPanelRegistry registry = BuildPanelRegistry();
|
||||
UIEditorWorkspaceModel workspace = BuildWorkspace();
|
||||
UIEditorWorkspaceSession session =
|
||||
BuildDefaultUIEditorWorkspaceSession(registry, workspace);
|
||||
|
||||
UIEditorPanelHostLifecycleState lifecycleState = {};
|
||||
UpdateUIEditorPanelHostLifecycle(
|
||||
lifecycleState,
|
||||
registry,
|
||||
workspace,
|
||||
session,
|
||||
UIEditorPanelHostLifecycleRequest{ "doc-a" });
|
||||
|
||||
ASSERT_TRUE(TryCloseUIEditorWorkspacePanel(registry, workspace, session, "doc-b"));
|
||||
const auto frame = UpdateUIEditorPanelHostLifecycle(
|
||||
lifecycleState,
|
||||
registry,
|
||||
workspace,
|
||||
session,
|
||||
UIEditorPanelHostLifecycleRequest{ "doc-a" });
|
||||
|
||||
const auto* docB = FindUIEditorPanelHostState(frame, "doc-b");
|
||||
ASSERT_NE(docB, nullptr);
|
||||
EXPECT_FALSE(docB->attached);
|
||||
EXPECT_FALSE(docB->visible);
|
||||
EXPECT_FALSE(docB->active);
|
||||
EXPECT_FALSE(docB->focused);
|
||||
|
||||
const std::vector<std::string> expectedEvents = {
|
||||
"Detached:doc-b"
|
||||
};
|
||||
EXPECT_EQ(FormatEvents(frame.events), expectedEvents);
|
||||
}
|
||||
|
||||
TEST(UIEditorPanelHostLifecycleTest, ClearingFocusOnlyEmitsFocusLostAndReopeningPanelReattachesIt) {
|
||||
const UIEditorPanelRegistry registry = BuildPanelRegistry();
|
||||
UIEditorWorkspaceModel workspace = BuildWorkspace();
|
||||
UIEditorWorkspaceSession session =
|
||||
BuildDefaultUIEditorWorkspaceSession(registry, workspace);
|
||||
|
||||
UIEditorPanelHostLifecycleState lifecycleState = {};
|
||||
UpdateUIEditorPanelHostLifecycle(
|
||||
lifecycleState,
|
||||
registry,
|
||||
workspace,
|
||||
session,
|
||||
UIEditorPanelHostLifecycleRequest{ "doc-a" });
|
||||
|
||||
const auto focusLostFrame = UpdateUIEditorPanelHostLifecycle(
|
||||
lifecycleState,
|
||||
registry,
|
||||
workspace,
|
||||
session,
|
||||
UIEditorPanelHostLifecycleRequest{});
|
||||
EXPECT_EQ(
|
||||
FormatEvents(focusLostFrame.events),
|
||||
std::vector<std::string>({ "FocusLost:doc-a" }));
|
||||
|
||||
ASSERT_TRUE(TryCloseUIEditorWorkspacePanel(registry, workspace, session, "doc-b"));
|
||||
UpdateUIEditorPanelHostLifecycle(
|
||||
lifecycleState,
|
||||
registry,
|
||||
workspace,
|
||||
session,
|
||||
UIEditorPanelHostLifecycleRequest{});
|
||||
|
||||
ASSERT_TRUE(TryOpenUIEditorWorkspacePanel(registry, workspace, session, "doc-b"));
|
||||
const auto reopenFrame = UpdateUIEditorPanelHostLifecycle(
|
||||
lifecycleState,
|
||||
registry,
|
||||
workspace,
|
||||
session,
|
||||
UIEditorPanelHostLifecycleRequest{ "doc-b" });
|
||||
|
||||
const std::vector<std::string> expectedEvents = {
|
||||
"Deactivated:doc-a",
|
||||
"Hidden:doc-a",
|
||||
"Attached:doc-b",
|
||||
"Shown:doc-b",
|
||||
"Activated:doc-b",
|
||||
"FocusGained:doc-b"
|
||||
};
|
||||
EXPECT_EQ(FormatEvents(reopenFrame.events), expectedEvents);
|
||||
}
|
||||
Reference in New Issue
Block a user