diff --git a/src/input/path_input.cc b/src/input/path_input.cc index d1594229..04a36355 100644 --- a/src/input/path_input.cc +++ b/src/input/path_input.cc @@ -100,7 +100,7 @@ PathInput::receive_do_complete() { entry.s_name += '/'; } - range_type r = find_incomplete(dir, str().substr(dirEnd, get_pos())); + range_type r = find_incomplete(dir, str().substr(dirEnd, get_pos() - dirEnd)); if (r.first == r.second) return; // Show some nice colors here. diff --git a/test/src/test_input_path_input.cc b/test/src/test_input_path_input.cc new file mode 100644 index 00000000..7fadbb61 --- /dev/null +++ b/test/src/test_input_path_input.cc @@ -0,0 +1,77 @@ +#include "config.h" + +#include "test/src/test_input_path_input.h" + +#include +#include +#include + +#include "input/path_input.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(TestInputPathInput); + +void +TestInputPathInput::setUp() { + test_fixture::setUp(); + + char temp_dir[] = "/tmp/rtorrent_test_path_input_XXXXXX"; + + CPPUNIT_ASSERT(mkdtemp(temp_dir) != nullptr); + + m_temp_dir = temp_dir; + + CPPUNIT_ASSERT_EQUAL(0, mkdir((m_temp_dir + "/alpha").c_str(), 0755)); + CPPUNIT_ASSERT_EQUAL(0, mkdir((m_temp_dir + "/alpha/beta").c_str(), 0755)); +} + +void +TestInputPathInput::tearDown() { + rmdir((m_temp_dir + "/alpha/beta").c_str()); + rmdir((m_temp_dir + "/alpha").c_str()); + rmdir(m_temp_dir.c_str()); + + test_fixture::tearDown(); +} + +// Tab at the end of the line completes the trailing component. +void +TestInputPathInput::test_complete_at_end() { + input::PathInput input; + + input.str() = m_temp_dir + "/al"; + input.set_pos(input.str().size()); + + CPPUNIT_ASSERT(input.pressed('\t')); + + CPPUNIT_ASSERT_EQUAL(m_temp_dir + "/alpha/", input.str()); + CPPUNIT_ASSERT_EQUAL(input.str().size(), input.get_pos()); +} + +// The same completion with the cursor left inside the line. Only the text up to +// the cursor selects the entry, and the rest of the line is discarded. +void +TestInputPathInput::test_complete_mid_line() { + input::PathInput input; + + input.str() = m_temp_dir + "/alZZZ"; + input.set_pos(m_temp_dir.size() + 3); + + CPPUNIT_ASSERT(input.pressed('\t')); + + CPPUNIT_ASSERT_EQUAL(m_temp_dir + "/alpha/", input.str()); + CPPUNIT_ASSERT_EQUAL(input.str().size(), input.get_pos()); +} + +// A cursor resting on a separator keeps completing the component after it. +void +TestInputPathInput::test_cursor_on_separator() { + input::PathInput input; + + input.str() = m_temp_dir + "/alpha/be"; + input.set_pos(m_temp_dir.size() + 6); + + CPPUNIT_ASSERT(input.pressed('\t')); + + CPPUNIT_ASSERT_EQUAL(m_temp_dir + "/alpha/beta/", input.str()); + CPPUNIT_ASSERT_EQUAL(input.str().size(), input.get_pos()); +} diff --git a/test/src/test_input_path_input.h b/test/src/test_input_path_input.h new file mode 100644 index 00000000..505b21dd --- /dev/null +++ b/test/src/test_input_path_input.h @@ -0,0 +1,24 @@ +#include "test/helpers/test_fixture.h" + +#include + +class TestInputPathInput : public test_fixture { + CPPUNIT_TEST_SUITE(TestInputPathInput); + + CPPUNIT_TEST(test_complete_at_end); + CPPUNIT_TEST(test_complete_mid_line); + CPPUNIT_TEST(test_cursor_on_separator); + + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void test_complete_at_end(); + void test_complete_mid_line(); + void test_cursor_on_separator(); + +private: + std::string m_temp_dir; +};