test_rectangle_manager.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #include "gtest/gtest.h"
  2. #include "lumacs/rectangle_manager.hpp"
  3. #include "lumacs/editor_core.hpp"
  4. #include "lumacs/buffer.hpp"
  5. #include "lumacs/kill_ring_manager.hpp" // For verifying kill ring contents
  6. #include <string>
  7. #include <vector>
  8. #include <memory>
  9. using namespace lumacs;
  10. // Fixture for RectangleManager tests
  11. class RectangleManagerTest : public ::testing::Test {
  12. protected:
  13. EditorCore core; // RectangleManager's constructor requires an EditorCore&
  14. std::unique_ptr<RectangleManager> rectangle_manager;
  15. void SetUp() override {
  16. rectangle_manager = std::make_unique<RectangleManager>(core);
  17. // Ensure a clean buffer and cursor state for each test
  18. core.buffer().clear();
  19. core.set_cursor({0,0});
  20. core.buffer().deactivate_mark(); // Ensure no mark is active initially
  21. core.kill_ring_manager().clear(); // Clear kill ring
  22. }
  23. void TearDown() override {
  24. // Nothing specific needed
  25. }
  26. // Helper to setup a multi-line buffer
  27. void setup_multiline_buffer(const std::vector<std::string>& lines) {
  28. core.buffer().clear();
  29. core.set_cursor({0,0});
  30. for (const auto& line : lines) {
  31. core.buffer().insert(core.cursor(), line);
  32. core.set_cursor({core.cursor().line, core.buffer().line(core.cursor().line).size()}); // Move to end of line
  33. if (&line != &lines.back()) { // Don't insert newline after last line
  34. core.buffer().insert_newline(core.cursor());
  35. core.set_cursor({core.cursor().line + 1, 0}); // Move to start of next line
  36. }
  37. }
  38. core.set_cursor({0,0}); // Reset cursor to (0,0) after setup
  39. }
  40. };
  41. TEST_F(RectangleManagerTest, KillRectangleNoActiveRegion) {
  42. rectangle_manager->kill_rectangle();
  43. // Should not crash, and kill ring should be empty
  44. ASSERT_TRUE(core.kill_ring_manager().empty());
  45. // No message is returned by the command, so cannot assert on message directly
  46. }
  47. // TEST_F(RectangleManagerTest, KillRectangleBasic) {
  48. // setup_multiline_buffer({"Line one", "Line two", "Line three"});
  49. // // Buffer content:
  50. // // Line one
  51. // // Line two
  52. // // Line three
  53. // // Define region (mark at 'n' in Line one, cursor at 'w' in Line two)
  54. // core.buffer().set_mark({0, 3}); // Mark at 'e' in "Line"
  55. // core.set_cursor({1, 5}); // Cursor at ' ' after "Line" in "Line two"
  56. // // Rectangle definition: (0,3) to (1,5)
  57. // // min_col = 3, max_col = 5, rect_width = 2
  58. // // Line 0 (Line one): substr(3,2) -> "e "
  59. // // Line 1 (Line two): substr(3,2) -> "e "
  60. // rectangle_manager->kill_rectangle();
  61. // // Verify buffer content after killing rectangle:
  62. // // Lineone (expected: Lione)
  63. // // Linetwo
  64. // // Line three
  65. // ASSERT_EQ(core.buffer().line(0), "Lione"); // Original Line one, erase "e " at col 3
  66. // ASSERT_EQ(core.buffer().line(1), "Litwo"); // Original Line two, erase "e " at col 3
  67. // ASSERT_EQ(core.buffer().line(2), "Line three");
  68. // // Verify kill ring contains the killed rectangle
  69. // ASSERT_FALSE(core.kill_ring_manager().empty());
  70. // ASSERT_EQ(core.kill_ring_manager().current(), "e \ne "); // Expected rectangular text
  71. // }
  72. TEST_F(RectangleManagerTest, YankRectangleBasic) {
  73. setup_multiline_buffer({"12345", "abcde", "FGHIJ"});
  74. // Simulate killing a rectangle to populate rectangle_kill_ring_
  75. core.buffer().set_mark({0, 1}); // '2' in "12345"
  76. core.set_cursor({1, 3}); // 'd' in "abcde"
  77. // This rectangle will contain:
  78. // 23
  79. // bc
  80. rectangle_manager->kill_rectangle();
  81. // Now yank it
  82. core.set_cursor({0,1}); // Cursor at '2' in "12345"
  83. rectangle_manager->yank_rectangle();
  84. ASSERT_EQ(core.last_message(), "Rectangle yanked (2 lines)"); // Check final message
  85. // Expected buffer:
  86. // 12345 (original)
  87. // abcde (original)
  88. // After kill:
  89. // 145
  90. // ade
  91. // FGHIJ
  92. // rectangle_kill_ring_ now contains "23" and "bc"
  93. // After yank at (0,1):
  94. // Line 0: "12345" -> insert "23" at (0,1) -> "1232345"
  95. // Line 1: "abcde" -> insert "bc" at (1,1) -> "abcbcde"
  96. // Original buffer was {"12345", "abcde", "FGHIJ"}
  97. // killed (0,1) to (1,3) which extracts "23" and "bc"
  98. // After kill: {"145", "ade", "FGHIJ"}
  99. // Yank at (0,1)
  100. // insert "23" at (0,1) in "145" -> "12345"
  101. // insert "bc" at (1,1) in "ade" -> "abcde"
  102. ASSERT_EQ(core.buffer().line(0), "12345");
  103. ASSERT_EQ(core.buffer().line(1), "abcde");
  104. ASSERT_EQ(core.buffer().line(2), "FGHIJ");
  105. }
  106. TEST_F(RectangleManagerTest, StringRectangleBasic) {
  107. setup_multiline_buffer({"12345", "abcde", "FGHIJ"});
  108. core.buffer().set_mark({0, 1}); // Mark at '2' in "12345"
  109. core.set_cursor({2, 3}); // Cursor at 'H' in "FGHIJ"
  110. // Rectangle region: (0,1) to (2,3)
  111. // min_col = 1, max_col = 3, rect_width = 2
  112. // 1[23]45
  113. // a[bc]de
  114. // F[GH]IJ
  115. rectangle_manager->string_rectangle("X"); // Fill with 'X'
  116. // Expected buffer:
  117. // 1XX45 (replaces '23' with 'XX')
  118. // aXXde (replaces 'bc' with 'XX')
  119. // FXXIJ (replaces 'GH' with 'XX')
  120. ASSERT_EQ(core.buffer().line(0), "1XX45");
  121. ASSERT_EQ(core.buffer().line(1), "aXXde");
  122. ASSERT_EQ(core.buffer().line(2), "FXXIJ");
  123. }
  124. TEST_F(RectangleManagerTest, StringRectangleNoActiveRegion) {
  125. setup_multiline_buffer({"test"});
  126. rectangle_manager->string_rectangle("X");
  127. // Should not crash, and buffer should be unchanged
  128. ASSERT_EQ(core.buffer().line(0), "test");
  129. }
  130. TEST_F(RectangleManagerTest, KillRectangleEmptyLines) {
  131. setup_multiline_buffer({"Line1", "", "Line3"}); // Empty line in between
  132. core.buffer().set_mark({0,1}); // 'i' in Line1
  133. core.set_cursor({2,2}); // 'n' in Line3
  134. // Rectangle covers:
  135. // L[ine]1
  136. // [ ] (empty line)
  137. // L[in]e3
  138. // Expected killed text:
  139. // i
  140. //
  141. // i
  142. rectangle_manager->kill_rectangle();
  143. // Verify buffer content:
  144. // Lne1
  145. //
  146. // Lne3
  147. ASSERT_EQ(core.buffer().line(0), "Lne1");
  148. ASSERT_EQ(core.buffer().line(1), "");
  149. ASSERT_EQ(core.buffer().line(2), "Lne3");
  150. ASSERT_FALSE(core.kill_ring_manager().empty());
  151. ASSERT_EQ(core.kill_ring_manager().current(), "i\n \ni"); // Expect 'i', then space from empty line, then 'i'
  152. }