|
|
@@ -0,0 +1,118 @@
|
|
|
+#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 <string>
|
|
|
+
|
|
|
+// 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) {
|
|
|
+ core.buffer_manager().active_buffer()->insert({0,0}, "hello");
|
|
|
+ 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<std::shared_ptr<lumacs::Window>> windows;
|
|
|
+ core.window_manager().collect_windows(core.root_layout(), 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 text"); // Should be "some text" + " text"
|
|
|
+ ASSERT_EQ(core.cursor().column, 14); // 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), "Lne1");
|
|
|
+ ASSERT_EQ(core.buffer().line(1), "Lne2");
|
|
|
+ ASSERT_EQ(core.buffer().line(2), "Lne3");
|
|
|
+ ASSERT_FALSE(core.rectangle_manager().rectangle_kill_ring_.empty()); // Check internal state
|
|
|
+}
|