#include "gtest/gtest.h" #include "lumacs/editor_core.hpp" #include "lumacs/buffer_manager.hpp" #include "lumacs/window_manager.hpp" #include "lumacs/kill_ring_manager.hpp" #include "lumacs/register_manager.hpp" #include "lumacs/macro_manager.hpp" #include "lumacs/rectangle_manager.hpp" #include // Test fixture for EditorCore, initializing core subsystems struct EditorCoreTest : public ::testing::Test { lumacs::EditorCore core; void SetUp() override { // EditorCore's constructor already initializes most things. // We might want to mock some dependencies for more isolated tests later. } void TearDown() override { // Clean up } }; TEST_F(EditorCoreTest, InitialSetup) { ASSERT_NE(core.buffer_manager().active_buffer(), nullptr); ASSERT_NE(core.window_manager().active_window(), nullptr); ASSERT_EQ(core.buffer().name(), "*scratch*"); ASSERT_EQ(core.cursor().line, 0); ASSERT_EQ(core.cursor().column, 0); } TEST_F(EditorCoreTest, MoveCursorRight) { // Test assumes initial cursor is at (0,0) on an empty buffer. // EditorCore constructor and init.lua execution might affect this. // Let's ensure a clean state first if needed, but for now test move_right. core.buffer().insert({0,0}, "test"); core.set_cursor({0,0}); core.move_right(); ASSERT_EQ(core.cursor().column, 1); } TEST_F(EditorCoreTest, NewBufferCommand) { core.new_buffer("test_new"); ASSERT_EQ(core.buffer().name(), "test_new"); ASSERT_EQ(core.cursor().line, 0); ASSERT_EQ(core.cursor().column, 0); } TEST_F(EditorCoreTest, SetMessage) { std::string test_message = "Hello, Lumacs!"; core.set_message(test_message); ASSERT_EQ(core.last_message(), test_message); } TEST_F(EditorCoreTest, SplitWindowHorizontally) { core.split_horizontally(); // After split, there should be 2 windows in the layout. std::vector> windows; core.window_manager().collect_windows(core.root_layout().get(), windows); ASSERT_EQ(windows.size(), 2); // The newly created window should be the active one. ASSERT_EQ(core.active_window(), windows[1]); } TEST_F(EditorCoreTest, KillLine) { core.buffer_manager().active_buffer()->insert({0,0}, "Line 1\nLine 2"); core.set_cursor({0,0}); core.kill_line(); ASSERT_EQ(core.buffer().line(0), "Line 2"); ASSERT_FALSE(core.kill_ring_manager().empty()); ASSERT_EQ(core.kill_ring_manager().current(), "Line 1\n"); } TEST_F(EditorCoreTest, Yank) { core.buffer_manager().active_buffer()->insert({0,0}, "some text"); core.set_cursor({0,5}); // at ' ' core.kill_line(); // Kills " text" core.yank(); // Yanks " text" ASSERT_EQ(core.buffer().line(0), "some text"); // Should be "some" + " text" from kill ring ASSERT_EQ(core.cursor().column, 9); // Cursor should be at end of yanked text } TEST_F(EditorCoreTest, CopyToRegisterAndInsert) { char reg_name = 'a'; std::string reg_content = "Register content"; core.copy_to_register(reg_name, reg_content); core.buffer_manager().active_buffer()->insert({0,0}, "Original "); core.set_cursor({0,9}); core.insert_register(reg_name); ASSERT_EQ(core.buffer().line(0), "Original Register content"); } TEST_F(EditorCoreTest, StartAndEndMacro) { ASSERT_FALSE(core.macro_manager().is_recording_macro()); core.start_kbd_macro(); ASSERT_TRUE(core.macro_manager().is_recording_macro()); core.record_key_sequence("a"); core.end_kbd_macro_or_call(); ASSERT_FALSE(core.macro_manager().is_recording_macro()); // Executing the macro will depend on process_key being called // which is hard to test without mocking keybinding_manager directly. // For now, just test recording state. } TEST_F(EditorCoreTest, KillRectangle) { core.buffer_manager().active_buffer()->insert({0,0}, "Line1\nLine2\nLine3"); core.buffer_manager().active_buffer()->set_mark({0,1}); // Mark 'i' core.set_cursor({2,3}); // Cursor 'e' in Line3 core.kill_rectangle(); // Expected buffer state after killing rectangle from (0,1) to (2,3) // "Lne1" // "Lne2" // "Lne3" ASSERT_EQ(core.buffer().line(0), "Le1"); ASSERT_EQ(core.buffer().line(1), "Le2"); ASSERT_EQ(core.buffer().line(2), "Le3"); // Check if rectangle was killed by verifying we can yank it back or check if it's not empty // Since we can't access private members, we'll check side effects or public API // For now, let's just assert that the buffer changed as expected. // A more robust test would verify the content of the rectangle_manager's kill ring // or through `yank_rectangle`. // For this test, we expect the buffer to be modified ASSERT_NE(core.buffer().content(), "Line1\nLine2\nLine3"); }