#include "gtest/gtest.h" #include "BufferView.h" #define C(x) ((uint32_t)(x)) static std::shared_ptr buffer1() { static const char data[] = "0\n" "1ab\n" "2abc\n" "3\n" "4\n" "5\n" "6abcdefg\n" "7\n" "8\n" "9abcdefghijklmno\n" "10\n" "11\n" "12\n"; return std::make_shared((const uint8_t *)data, strlen(data)); } static std::shared_ptr buffer2() { static const char data[] = "0\n" "\n" "2\n" "3\n" "4\n" "\n" "6\n" "7\n" "8\n"; return std::make_shared((const uint8_t *)data, strlen(data)); } static std::shared_ptr buffer_empty() { return std::make_shared(nullptr, 0u); } class MyCharacterWidthDeterminer : public CharacterWidthDeterminer { int operator()(uint32_t character) { if (character < 32) { return 2; } else { return 1; } } } Cwd; static int LineNumber(std::shared_ptr iterator) { int line_number = 0; auto i = std::make_shared(*iterator); i->go_start_of_line(); for (;;) { uint32_t c = **i; if ((c < '0') || (c > '9')) break; line_number *= 10; line_number += ((int)c - '0'); i->go_forward(); } return line_number; } TEST(BufferViewTest, does_not_iterate_for_empty_buffer) { std::shared_ptr b = buffer_empty(); std::shared_ptr iterator = b->add_iterator(); BufferView bv(b, iterator, Cwd); bv.resize(40, 8); int iter_count = 0; bv.update(); for (auto it = bv.vert_iter(); it.is_valid(); it++) { iter_count++; } EXPECT_EQ(0, iter_count); EXPECT_EQ(0, bv.cursor_screen_row()); EXPECT_EQ(0, bv.cursor_screen_column()); EXPECT_EQ(0, bv.cursor_virtual_column()); } TEST(BufferViewTest, iterates_through_screen_lines_with_no_wrapping) { std::shared_ptr b = buffer1(); std::shared_ptr iterator = b->add_iterator(); BufferView bv(b, iterator, Cwd); bv.resize(40, 8); int iter_count = 0; bv.update(); for (auto it = bv.vert_iter(); it.is_valid(); it++) { EXPECT_EQ(iter_count, LineNumber(it.iterator())); iter_count++; } EXPECT_EQ(8, iter_count); EXPECT_EQ(0, bv.cursor_screen_row()); EXPECT_EQ(0, bv.cursor_screen_column()); EXPECT_EQ(0, bv.cursor_virtual_column()); } TEST(BufferViewTest, iterates_through_screen_lines_with_wrapping) { std::shared_ptr b = buffer1(); std::shared_ptr iterator = b->add_iterator(); BufferView bv(b, iterator, Cwd); bv.resize(3, 10); int iter_count = 0; int expected_row_offsets[] = {0, 1, 2, 4, 5, 6, 7}; bv.update(); for (auto it = bv.vert_iter(); it.is_valid(); it++) { EXPECT_EQ(iter_count, LineNumber(it.iterator())); EXPECT_EQ(expected_row_offsets[iter_count], it.row_offset()); iter_count++; } EXPECT_EQ(7, iter_count); EXPECT_EQ(0, bv.cursor_screen_row()); EXPECT_EQ(0, bv.cursor_screen_column()); EXPECT_EQ(0, bv.cursor_virtual_column()); } TEST(BufferViewTest, fills_view_with_last_lines_of_buffer_when_cursor_warps_to_last_line) { std::shared_ptr b = buffer1(); std::shared_ptr iterator = b->add_iterator(); BufferView bv(b, iterator, Cwd); while (iterator->go_next_line()) { } bv.resize(40, 3); int iter_count = 0; int expected_row_offsets[] = {0, 1, 2}; bv.update(); for (auto it = bv.vert_iter(); it.is_valid(); it++) { EXPECT_EQ(10 + iter_count, LineNumber(it.iterator())); EXPECT_EQ(expected_row_offsets[iter_count], it.row_offset()); iter_count++; } EXPECT_EQ(3, iter_count); EXPECT_EQ(2, bv.cursor_screen_row()); EXPECT_EQ(0, bv.cursor_screen_column()); EXPECT_EQ(0, bv.cursor_virtual_column()); } TEST(BufferViewTest, adjusts_cursor_row_as_cursor_moves) { auto b = buffer1(); auto iterator = b->add_iterator(); BufferView bv(b, iterator, Cwd); bv.resize(5, 5); bv.update(); EXPECT_EQ(0, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false); // to 1 bv.update(); EXPECT_EQ(1, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false); // to 2 bv.update(); EXPECT_EQ(2, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false); // to 3 bv.update(); EXPECT_EQ(3, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false); // to 4 bv.update(); EXPECT_EQ(4, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false); // to 5 bv.update(); EXPECT_EQ(4, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false); // to 6 bv.update(); EXPECT_EQ(4, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false); // to 7 bv.update(); EXPECT_EQ(4, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::UP, 0u, false); // to 6 bv.update(); EXPECT_EQ(2, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::UP, 0u, false); // to 5 bv.update(); EXPECT_EQ(1, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::UP, 0u, false); // to 4 bv.update(); EXPECT_EQ(0, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::UP, 0u, false); // to 3 bv.update(); EXPECT_EQ(0, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::UP, 0u, false); // to 2 bv.update(); EXPECT_EQ(0, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::UP, 0u, false); // to 1 bv.update(); EXPECT_EQ(0, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::UP, 0u, false); // to 0 bv.update(); EXPECT_EQ(0, bv.cursor_screen_row()); } TEST(BufferViewTest, adjusts_cursor_row_as_cursor_moves_with_scroll_offset_1) { auto b = buffer1(); auto iterator = b->add_iterator(); BufferView bv(b, iterator, Cwd); bv.resize(5, 5); bv.set_scroll_offset(1); bv.update(); EXPECT_EQ(0, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false); // to 1 bv.update(); EXPECT_EQ(1, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false); // to 2 bv.update(); EXPECT_EQ(2, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false); // to 3 bv.update(); EXPECT_EQ(3, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false); // to 4 bv.update(); EXPECT_EQ(3, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false); // to 5 bv.update(); EXPECT_EQ(3, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false); // to 6 bv.update(); EXPECT_EQ(3, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false); // to 7 bv.update(); EXPECT_EQ(3, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::UP, 0u, false); // to 6 bv.update(); EXPECT_EQ(1, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::UP, 0u, false); // to 5 bv.update(); EXPECT_EQ(1, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::UP, 0u, false); // to 4 bv.update(); EXPECT_EQ(1, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::UP, 0u, false); // to 3 bv.update(); EXPECT_EQ(1, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::UP, 0u, false); // to 2 bv.update(); EXPECT_EQ(1, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::UP, 0u, false); // to 1 bv.update(); EXPECT_EQ(1, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::UP, 0u, false); // to 0 bv.update(); EXPECT_EQ(0, bv.cursor_screen_row()); } TEST(BufferViewTest, moves_view_down_while_traversing_a_wrapped_line_right) { auto b = buffer1(); auto iterator = b->add_iterator(); BufferView bv(b, iterator, Cwd); bv.resize(4, 10); for (int i = 0; i < 9; i++) { EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false)); bv.update(); } EXPECT_EQ(9, bv.cursor_screen_row()); EXPECT_EQ(0, bv.cursor_screen_column()); EXPECT_EQ(0, bv.cursor_virtual_column()); EXPECT_EQ(C('9'), **iterator); for (int i = 0; i < 3; i++) { EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::RIGHT, 0u, false)); bv.update(); EXPECT_EQ(9, bv.cursor_screen_row()); EXPECT_EQ(1 + i, bv.cursor_screen_column()); EXPECT_EQ(1 + i, bv.cursor_virtual_column()); } for (int i = 0; i < 4; i++) { EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::RIGHT, 0u, false)); bv.update(); EXPECT_EQ(9, bv.cursor_screen_row()); EXPECT_EQ(i, bv.cursor_screen_column()); EXPECT_EQ(4 + i, bv.cursor_virtual_column()); } for (int i = 0; i < 4; i++) { EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::RIGHT, 0u, false)); bv.update(); EXPECT_EQ(9, bv.cursor_screen_row()); EXPECT_EQ(i, bv.cursor_screen_column()); EXPECT_EQ(8 + i, bv.cursor_virtual_column()); } EXPECT_EQ(C('k'), **iterator); } TEST(BufferViewTest, moves_view_down_while_jumping_to_the_end_of_a_wrapped_line) { auto b = buffer1(); auto iterator = b->add_iterator(); BufferView bv(b, iterator, Cwd); bv.resize(4, 10); for (int i = 0; i < 9; i++) { bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false); bv.update(); } EXPECT_EQ(9, bv.cursor_screen_row()); EXPECT_EQ(0, bv.cursor_screen_column()); EXPECT_EQ(0, bv.cursor_virtual_column()); EXPECT_EQ(C('9'), **iterator); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::EOL, 0u, false)); bv.update(); EXPECT_EQ(9, bv.cursor_screen_row()); EXPECT_EQ(3, bv.cursor_screen_column()); EXPECT_EQ(15, bv.cursor_virtual_column()); EXPECT_EQ(C('o'), **iterator); } TEST(BufferViewTest, moves_view_up_while_traversing_a_wrapped_line_left) { auto b = buffer1(); auto iterator = b->add_iterator(); BufferView bv(b, iterator, Cwd); bv.resize(2, 3); for (int i = 0; i < 4; i++) { EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false)); bv.update(); } EXPECT_EQ(2, bv.cursor_screen_row()); EXPECT_EQ(0, bv.cursor_screen_column()); EXPECT_EQ(0, bv.cursor_virtual_column()); for (int i = 0; i < 4; i++) { iterator->go_back(); } /* Cursor at end of line 2 */ bv.set_cursor_screen_row(0); bv.update(); EXPECT_EQ(0, bv.cursor_screen_row()); EXPECT_EQ(1, bv.cursor_screen_column()); EXPECT_EQ(3, bv.cursor_virtual_column()); EXPECT_EQ(C('c'), **iterator); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::LEFT, 0u, false)); bv.update(); EXPECT_EQ(0, bv.cursor_screen_row()); EXPECT_EQ(0, bv.cursor_screen_column()); EXPECT_EQ(2, bv.cursor_virtual_column()); EXPECT_EQ(C('b'), **iterator); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::LEFT, 0u, false)); bv.update(); EXPECT_EQ(0, bv.cursor_screen_row()); EXPECT_EQ(1, bv.cursor_screen_column()); EXPECT_EQ(1, bv.cursor_virtual_column()); EXPECT_EQ(C('a'), **iterator); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::LEFT, 0u, false)); bv.update(); EXPECT_EQ(0, bv.cursor_screen_row()); EXPECT_EQ(0, bv.cursor_screen_column()); EXPECT_EQ(0, bv.cursor_virtual_column()); EXPECT_EQ(C('2'), **iterator); EXPECT_FALSE(bv.cursor_move(BufferView::CursorMovement::LEFT, 0u, false)); bv.update(); EXPECT_EQ(0, bv.cursor_screen_row()); EXPECT_EQ(0, bv.cursor_screen_column()); EXPECT_EQ(0, bv.cursor_virtual_column()); EXPECT_EQ(C('2'), **iterator); } TEST(BufferViewTest, moves_view_up_while_jumping_to_start_of_a_wrapped_line) { auto b = buffer1(); auto iterator = b->add_iterator(); BufferView bv(b, iterator, Cwd); bv.resize(2, 3); for (int i = 0; i < 4; i++) { bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false); bv.update(); } EXPECT_EQ(2, bv.cursor_screen_row()); EXPECT_EQ(0, bv.cursor_screen_column()); EXPECT_EQ(0, bv.cursor_virtual_column()); for (int i = 0; i < 4; i++) { iterator->go_back(); } /* Cursor at end of line 2 */ bv.set_cursor_screen_row(0); bv.update(); EXPECT_EQ(0, bv.cursor_screen_row()); EXPECT_EQ(1, bv.cursor_screen_column()); EXPECT_EQ(3, bv.cursor_virtual_column()); EXPECT_EQ(C('c'), **iterator); bv.cursor_move(BufferView::CursorMovement::SOL, 0u, false); bv.update(); EXPECT_EQ(0, bv.cursor_screen_row()); EXPECT_EQ(0, bv.cursor_screen_column()); EXPECT_EQ(0, bv.cursor_virtual_column()); EXPECT_EQ(C('2'), **iterator); } TEST(BufferViewTest, warps_view_when_jumping_to_beginning_and_end_of_buffer) { auto b = buffer1(); auto iterator = b->add_iterator(); BufferView bv(b, iterator, Cwd); bv.resize(4, 4); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::LAST_LINE, 0u, false)); bv.update(); EXPECT_EQ(12, LineNumber(iterator)); EXPECT_EQ(3, bv.cursor_screen_row()); EXPECT_EQ(0, bv.cursor_screen_column()); EXPECT_EQ(0, bv.cursor_virtual_column()); EXPECT_FALSE(bv.cursor_move(BufferView::CursorMovement::LAST_LINE, 0u, false)); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::FIRST_LINE, 0u, false)); bv.update(); EXPECT_EQ(0, LineNumber(iterator)); EXPECT_EQ(0, bv.cursor_screen_row()); EXPECT_EQ(0, bv.cursor_screen_column()); EXPECT_EQ(0, bv.cursor_virtual_column()); EXPECT_FALSE(bv.cursor_move(BufferView::CursorMovement::FIRST_LINE, 0u, false)); } TEST(BufferViewTest, sets_target_column_to_eol_when_jumping_to_SOL_and_EOL) { auto b = buffer1(); auto iterator = b->add_iterator(); BufferView bv(b, iterator, Cwd); bv.resize(4, 4); bv.cursor_move(BufferView::CursorMovement::EOL, 0u, false); bv.update(); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false)); bv.update(); EXPECT_EQ(1, bv.cursor_screen_row()); EXPECT_EQ(C('b'), **iterator); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::UP, 0u, false)); bv.update(); EXPECT_EQ(0, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::SOL, 0u, false); bv.update(); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false)); EXPECT_EQ(C('1'), **iterator); EXPECT_EQ(1, bv.cursor_screen_row()); } TEST(BufferViewTest, sets_target_column_when_traversing_left_and_right) { auto b = buffer1(); auto iterator = b->add_iterator(); BufferView bv(b, iterator, Cwd); bv.resize(4, 4); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false)); bv.update(); EXPECT_EQ(1, LineNumber(iterator)); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::RIGHT, 0u, false)); bv.update(); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::RIGHT, 0u, false)); bv.update(); EXPECT_EQ(1, LineNumber(iterator)); EXPECT_EQ(C('b'), **iterator); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::DOWN, 0u, false)); bv.update(); EXPECT_EQ(2, LineNumber(iterator)); EXPECT_EQ(C('b'), **iterator); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::LEFT, 0u, false)); bv.update(); EXPECT_EQ(2, LineNumber(iterator)); EXPECT_EQ(C('a'), **iterator); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::UP, 0u, false)); bv.update(); EXPECT_EQ(1, LineNumber(iterator)); EXPECT_EQ(C('a'), **iterator); } TEST(BufferViewTest, moves_cursor_by_screen_row) { auto b = buffer1(); auto iterator = b->add_iterator(); BufferView bv(b, iterator, Cwd); bv.resize(4, 4); for (int i = 0; i < 6; i++) { EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_DOWN, 0u, false)); bv.update(); EXPECT_EQ(1 + i, LineNumber(iterator)); } EXPECT_EQ(C('6'), **iterator); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_DOWN, 0u, false)); bv.update(); EXPECT_EQ(6, LineNumber(iterator)); EXPECT_EQ(C('d'), **iterator); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::RIGHT, 0u, false)); bv.update(); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::RIGHT, 0u, false)); bv.update(); EXPECT_EQ(C('f'), **iterator); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_DOWN, 0u, false)); bv.update(); EXPECT_EQ(C('7'), **iterator); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_UP, 0u, false)); bv.update(); EXPECT_EQ(C('f'), **iterator); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_UP, 0u, false)); bv.update(); EXPECT_EQ(C('b'), **iterator); EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_UP, 0u, false)); bv.update(); EXPECT_EQ(C('5'), **iterator); } TEST(BufferViewTest, cursor_move_screen_row_up_and_down_returns_false_at_top_and_bottom) { auto b = buffer1(); auto iterator = b->add_iterator(); BufferView bv(b, iterator, Cwd); bv.resize(4, 4); EXPECT_FALSE(bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_UP, 0u, false)); bv.update(); EXPECT_EQ(0, LineNumber(iterator)); for (int i = 0; i < 16; i++) { EXPECT_TRUE(bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_DOWN, 0u, false)); bv.update(); } EXPECT_FALSE(bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_DOWN, 0u, false)); } TEST(BufferViewTest, scrolls_the_view_up_and_down) { auto b = buffer1(); auto iterator = b->add_iterator(); BufferView bv(b, iterator, Cwd); bv.resize(40, 6); bv.update(); EXPECT_EQ(0, LineNumber(iterator)); EXPECT_EQ(0, bv.cursor_screen_row()); bv.scroll_view_down(1, false); bv.update(); EXPECT_EQ(1, LineNumber(iterator)); EXPECT_EQ(0, bv.cursor_screen_row()); bv.scroll_view_down(5, false); bv.update(); EXPECT_EQ(6, LineNumber(iterator)); EXPECT_EQ(0, bv.cursor_screen_row()); bv.scroll_view_down(1, false); bv.update(); EXPECT_EQ(7, LineNumber(iterator)); EXPECT_EQ(0, bv.cursor_screen_row()); bv.scroll_view_down(1, false); bv.update(); EXPECT_EQ(7, LineNumber(iterator)); EXPECT_EQ(0, bv.cursor_screen_row()); bv.scroll_view_down(3, false); bv.update(); EXPECT_EQ(7, LineNumber(iterator)); EXPECT_EQ(0, bv.cursor_screen_row()); bv.scroll_view_up(1, false); bv.update(); EXPECT_EQ(7, LineNumber(iterator)); EXPECT_EQ(1, bv.cursor_screen_row()); bv.scroll_view_up(4, false); bv.update(); EXPECT_EQ(7, LineNumber(iterator)); EXPECT_EQ(5, bv.cursor_screen_row()); bv.scroll_view_up(1, false); bv.update(); EXPECT_EQ(6, LineNumber(iterator)); EXPECT_EQ(5, bv.cursor_screen_row()); bv.scroll_view_up(1, false); bv.update(); EXPECT_EQ(5, LineNumber(iterator)); EXPECT_EQ(5, bv.cursor_screen_row()); bv.scroll_view_up(1, false); bv.update(); EXPECT_EQ(5, LineNumber(iterator)); EXPECT_EQ(5, bv.cursor_screen_row()); bv.scroll_view_up(3, false); bv.update(); EXPECT_EQ(5, LineNumber(iterator)); EXPECT_EQ(5, bv.cursor_screen_row()); } TEST(BufferViewTest, scrolls_the_view_up_and_down_with_wrapped_lines) { auto b = buffer1(); auto iterator = b->add_iterator(); BufferView bv(b, iterator, Cwd); bv.resize(4, 2); bv.update(); EXPECT_EQ(0, LineNumber(iterator)); EXPECT_EQ(0, bv.cursor_screen_row()); bv.scroll_view_down(6, false); bv.update(); EXPECT_EQ(6, LineNumber(iterator)); EXPECT_EQ(C('6'), **iterator); EXPECT_EQ(0, bv.cursor_screen_row()); bv.scroll_view_down(1, false); bv.update(); EXPECT_EQ(6, LineNumber(iterator)); EXPECT_EQ(C('d'), **iterator); bv.scroll_view_down(1, false); bv.update(); EXPECT_EQ(7, LineNumber(iterator)); EXPECT_EQ(C('7'), **iterator); bv.scroll_view_down(4, false); bv.update(); EXPECT_EQ(9, LineNumber(iterator)); EXPECT_EQ(C('h'), **iterator); bv.scroll_view_down(2, false); bv.update(); EXPECT_EQ(10, LineNumber(iterator)); EXPECT_EQ(C('1'), **iterator); bv.cursor_move(BufferView::CursorMovement::RIGHT, 0u, false); bv.update(); bv.scroll_view_up(3, false); bv.update(); EXPECT_EQ(9, LineNumber(iterator)); EXPECT_EQ(C('i'), **iterator); bv.scroll_view_up(5, false); bv.update(); EXPECT_EQ(6, LineNumber(iterator)); EXPECT_EQ(C('e'), **iterator); } TEST(BufferViewTest, scrolls_the_view_up_and_down_with_nonzero_scroll_offset) { auto b = buffer1(); auto iterator = b->add_iterator(); BufferView bv(b, iterator, Cwd); bv.resize(40, 6); bv.set_scroll_offset(2); bv.update(); EXPECT_EQ(0, LineNumber(iterator)); EXPECT_EQ(0, bv.cursor_screen_row()); bv.scroll_view_down(1, false); bv.update(); EXPECT_EQ(3, LineNumber(iterator)); EXPECT_EQ(2, bv.cursor_screen_row()); bv.scroll_view_down(5, false); bv.update(); EXPECT_EQ(8, LineNumber(iterator)); EXPECT_EQ(2, bv.cursor_screen_row()); bv.scroll_view_down(1, false); bv.update(); EXPECT_EQ(9, LineNumber(iterator)); EXPECT_EQ(2, bv.cursor_screen_row()); bv.scroll_view_down(1, false); bv.update(); EXPECT_EQ(9, LineNumber(iterator)); EXPECT_EQ(2, bv.cursor_screen_row()); bv.scroll_view_down(3, false); bv.update(); EXPECT_EQ(9, LineNumber(iterator)); EXPECT_EQ(2, bv.cursor_screen_row()); bv.scroll_view_up(1, false); bv.update(); EXPECT_EQ(9, LineNumber(iterator)); EXPECT_EQ(3, bv.cursor_screen_row()); bv.scroll_view_up(4, false); bv.update(); EXPECT_EQ(5, LineNumber(iterator)); EXPECT_EQ(3, bv.cursor_screen_row()); bv.scroll_view_up(1, false); bv.update(); EXPECT_EQ(4, LineNumber(iterator)); EXPECT_EQ(3, bv.cursor_screen_row()); bv.scroll_view_up(1, false); bv.update(); EXPECT_EQ(3, LineNumber(iterator)); EXPECT_EQ(3, bv.cursor_screen_row()); bv.scroll_view_up(1, false); bv.update(); EXPECT_EQ(3, LineNumber(iterator)); EXPECT_EQ(3, bv.cursor_screen_row()); bv.scroll_view_up(3, false); bv.update(); EXPECT_EQ(3, LineNumber(iterator)); EXPECT_EQ(3, bv.cursor_screen_row()); } TEST(BufferViewTest, scrolls_window_through_a_very_long_single_line_file) { auto b = std::make_shared(); auto iterator = b->add_cursor(); for (int row = 0; row < 120; row++) { for (int col = 0; col < 10; col++) { b->insert_code_point(*iterator, (uint32_t)(row + 1000)); } } iterator->go_start_of_line(); BufferView bv(b, iterator, Cwd); bv.resize(10, 10); bv.update(); EXPECT_EQ(0, bv.cursor_screen_row()); EXPECT_EQ(1000u, **iterator); for (uint32_t i = 0u; i < 100u; i++) { bv.scroll_view_down(1, false); bv.update(); EXPECT_EQ(0, bv.cursor_screen_row()); EXPECT_EQ(i + 1001u, **iterator); } bv.scroll_view_down(20, false); bv.update(); EXPECT_EQ(0, bv.cursor_screen_row()); EXPECT_EQ(1110u, **iterator); for (int i = 0; i < 9; i++) { bv.scroll_view_up(1, false); bv.update(); EXPECT_EQ(i + 1, bv.cursor_screen_row()); EXPECT_EQ(1110u, **iterator); } for (uint32_t i = 0; i < 50; i++) { bv.scroll_view_up(1, false); bv.update(); EXPECT_EQ(9, bv.cursor_screen_row()); EXPECT_EQ(1109u - i, **iterator); } bv.scroll_view_up(1000u, false); bv.update(); EXPECT_EQ(9, bv.cursor_screen_row()); EXPECT_EQ(1009u, **iterator); } TEST(BufferViewTest, shows_only_lines_in_buffer_if_fewer_lines_in_buffer_than_view) { auto b = buffer1(); auto iterator = b->add_iterator(); BufferView bv(b, iterator, Cwd); bv.resize(50, 50); bv.update(); int count = 0; for (auto it = bv.vert_iter(); it.is_valid(); it++) { EXPECT_EQ(count, it.row_offset()); count++; } EXPECT_EQ(13, count); } TEST(BufferViewTest, scrolls_past_empty_lines) { auto b = buffer2(); auto iterator = b->add_cursor(); BufferView bv(b, iterator, Cwd); bv.resize(10, 1); bv.update(); EXPECT_EQ(0, LineNumber(iterator)); bv.scroll_view_down(3, false); bv.update(); EXPECT_EQ(3, LineNumber(iterator)); bv.scroll_view_up(3, false); bv.update(); EXPECT_EQ(0, LineNumber(iterator)); } TEST(BufferViewTest, moving_cursor_screen_row_down_jumps_past_wrapped_tab) { static const char data[] = "0\n" "1abc\tdefghijklmnopqrstuvwxyz\n" "2\n" "3\n"; auto b = std::make_shared((const uint8_t *)data, strlen(data)); auto iterator = b->add_cursor(); BufferView bv(b, iterator, Cwd); bv.resize(5, 10); bv.update(); EXPECT_EQ(C('0'), **iterator); EXPECT_EQ(0, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_DOWN, 0u, false); bv.update(); EXPECT_EQ(C('1'), **iterator); EXPECT_EQ(1, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_DOWN, 0u, false); bv.update(); EXPECT_EQ(C('d'), **iterator); EXPECT_EQ(2, bv.cursor_screen_row()); bv.cursor_move(BufferView::CursorMovement::SCREEN_ROW_DOWN, 0u, false); bv.update(); EXPECT_EQ(C('f'), **iterator); EXPECT_EQ(3, bv.cursor_screen_row()); }