| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- #include "gtest/gtest.h"
- #include "lumacs/window_manager.hpp"
- #include "lumacs/editor_core.hpp"
- #include "lumacs/window.hpp"
- #include "lumacs/layout_node.hpp"
- #include <memory>
- #include <vector>
- #include <numeric> // For std::iota
- using namespace lumacs;
- // Fixture for WindowManager tests
- class WindowManagerTest : public ::testing::Test {
- protected:
- std::unique_ptr<EditorCore> core;
- WindowManager* wm; // Raw pointer for convenience, owned by core
- void SetUp() override {
- // Instantiate EditorCore which in turn initializes WindowManager and BufferManager
- core = std::make_unique<EditorCore>();
- wm = &core->window_manager(); // Get reference to the manager owned by core
- // Ensure a clean slate for some tests by explicitly creating a new scratch buffer
- // if the default one from init.lua is not suitable.
- // For these tests, we mostly care about window *layout*, not buffer content.
- core->buffer().clear();
- core->set_cursor({0,0});
- }
- void TearDown() override {
- core.reset();
- }
- // Helper to count windows in the layout tree
- size_t count_windows_in_layout() {
- std::vector<std::shared_ptr<Window>> windows;
- core->collect_windows(wm->root_layout().get(), windows);
- return windows.size();
- }
- };
- TEST_F(WindowManagerTest, InitialState) {
- // Initially, there should be one active window
- ASSERT_NE(wm->active_window(), nullptr);
- ASSERT_EQ(count_windows_in_layout(), 1);
- ASSERT_EQ(wm->root_layout()->type, LayoutNode::Type::Leaf);
- ASSERT_EQ(wm->root_layout()->window, wm->active_window());
- }
- TEST_F(WindowManagerTest, SplitHorizontally) {
- auto original_active_window = wm->active_window();
- wm->split_horizontally();
- // Should now have two windows
- ASSERT_EQ(count_windows_in_layout(), 2);
- ASSERT_EQ(wm->root_layout()->type, LayoutNode::Type::HorizontalSplit);
- ASSERT_NE(wm->root_layout()->child1, nullptr);
- ASSERT_NE(wm->root_layout()->child2, nullptr);
- // New window should be active
- ASSERT_NE(wm->active_window(), original_active_window);
- }
- TEST_F(WindowManagerTest, SplitVertically) {
- auto original_active_window = wm->active_window();
- wm->split_vertically();
- // Should now have two windows
- ASSERT_EQ(count_windows_in_layout(), 2);
- ASSERT_EQ(wm->root_layout()->type, LayoutNode::Type::VerticalSplit);
- ASSERT_NE(wm->root_layout()->child1, nullptr);
- ASSERT_NE(wm->root_layout()->child2, nullptr);
- // New window should be active
- ASSERT_NE(wm->active_window(), original_active_window);
- }
- TEST_F(WindowManagerTest, CloseActiveWindowMergesLayout) {
- wm->split_horizontally(); // Creates 2 windows
- ASSERT_EQ(count_windows_in_layout(), 2);
- auto window_before_close = wm->active_window();
- wm->close_active_window(); // Closes the newly created window
- ASSERT_EQ(count_windows_in_layout(), 1); // Should merge back to one window
- ASSERT_NE(wm->active_window(), window_before_close); // Active window should be the remaining one
- ASSERT_EQ(wm->root_layout()->type, LayoutNode::Type::Leaf);
- }
- TEST_F(WindowManagerTest, CloseLastWindowDoesNothing) {
- ASSERT_EQ(count_windows_in_layout(), 1);
- auto original_active = wm->active_window();
- wm->close_active_window(); // Attempt to close the only window
- ASSERT_EQ(count_windows_in_layout(), 1); // Should still be one window
- ASSERT_EQ(wm->active_window(), original_active); // Should still be the same window
- }
- TEST_F(WindowManagerTest, NextWindowCyclesFocus) {
- wm->split_horizontally(); // Window 1 (original), Window 2 (newly active)
- auto w1 = wm->root_layout()->child1->window; // Original window
- auto w2 = wm->root_layout()->child2->window; // New window, active
- ASSERT_EQ(wm->active_window(), w2);
-
- wm->next_window(); // Should cycle to w1
- ASSERT_EQ(wm->active_window(), w1);
- wm->next_window(); // Should cycle back to w2
- ASSERT_EQ(wm->active_window(), w2);
- }
- TEST_F(WindowManagerTest, ComplexSplitAndClose) {
- // Initial: W1
- wm->split_vertically(); // Root: |W1|W2| (W2 active)
- wm->split_horizontally(); // Root: |W1| [W3;W2] (W2 active remains W2, so W3 active)
- // The previous split makes the new window active. So if W2 was active, after split_horizontally on W2, W3 is active.
- // Layout: |W1|
- // ----
- // |W3|
- // ---- (W3 active)
- // |W2|
- ASSERT_EQ(count_windows_in_layout(), 3);
- auto w1 = wm->root_layout()->child1->window;
- auto w2_node = wm->root_layout()->child2; // This is a split node
- auto w3 = w2_node->child1->window;
- auto w2 = w2_node->child2->window;
- wm->next_window(); // Should cycle to W1 (or W2, depends on traversal order)
- wm->next_window(); // Cycle again
- wm->close_active_window(); // Close the active window (W2 or W3)
- ASSERT_EQ(count_windows_in_layout(), 2); // Should have 2 windows left
- }
|