diff options
Diffstat (limited to 'lldb/unittests/Editline/EditlineTest.cpp')
-rw-r--r-- | lldb/unittests/Editline/EditlineTest.cpp | 493 |
1 files changed, 217 insertions, 276 deletions
diff --git a/lldb/unittests/Editline/EditlineTest.cpp b/lldb/unittests/Editline/EditlineTest.cpp index e2552ffdd3b..55dae525ddc 100644 --- a/lldb/unittests/Editline/EditlineTest.cpp +++ b/lldb/unittests/Editline/EditlineTest.cpp @@ -25,348 +25,289 @@ #include "lldb/Host/Pipe.h" #include "lldb/Utility/PseudoTerminal.h" -namespace -{ - const size_t TIMEOUT_MILLIS = 5000; +namespace { +const size_t TIMEOUT_MILLIS = 5000; } -class FilePointer -{ +class FilePointer { public: + FilePointer() = delete; - FilePointer () = delete; + FilePointer(const FilePointer &) = delete; - FilePointer (const FilePointer&) = delete; + FilePointer(FILE *file_p) : _file_p(file_p) {} - FilePointer (FILE *file_p) - : _file_p (file_p) - { + ~FilePointer() { + if (_file_p != nullptr) { + const int close_result = fclose(_file_p); + EXPECT_EQ(0, close_result); } + } - ~FilePointer () - { - if (_file_p != nullptr) - { - const int close_result = fclose (_file_p); - EXPECT_EQ(0, close_result); - } - } - - operator FILE* () - { - return _file_p; - } + operator FILE *() { return _file_p; } private: - - FILE *_file_p; - + FILE *_file_p; }; /** Wraps an Editline class, providing a simple way to feed input (as if from the keyboard) and receive output from Editline. */ -class EditlineAdapter -{ +class EditlineAdapter { public: + EditlineAdapter(); - EditlineAdapter (); + void CloseInput(); - void - CloseInput (); + bool IsValid() const { return _editline_sp.get() != nullptr; } - bool - IsValid () const - { - return _editline_sp.get () != nullptr; - } + lldb_private::Editline &GetEditline() { return *_editline_sp; } - lldb_private::Editline& - GetEditline () - { - return *_editline_sp; - } + bool SendLine(const std::string &line); - bool - SendLine (const std::string &line); + bool SendLines(const std::vector<std::string> &lines); - bool - SendLines (const std::vector<std::string> &lines); + bool GetLine(std::string &line, bool &interrupted, size_t timeout_millis); - bool - GetLine (std::string &line, bool &interrupted, size_t timeout_millis); + bool GetLines(lldb_private::StringList &lines, bool &interrupted, + size_t timeout_millis); - bool - GetLines (lldb_private::StringList &lines, bool &interrupted, size_t timeout_millis); - - void - ConsumeAllOutput (); + void ConsumeAllOutput(); private: + static bool IsInputComplete(lldb_private::Editline *editline, + lldb_private::StringList &lines, void *baton); - static bool - IsInputComplete ( - lldb_private::Editline * editline, - lldb_private::StringList & lines, - void * baton); - - std::unique_ptr<lldb_private::Editline> _editline_sp; + std::unique_ptr<lldb_private::Editline> _editline_sp; - lldb_utility::PseudoTerminal _pty; - int _pty_master_fd; - int _pty_slave_fd; + lldb_utility::PseudoTerminal _pty; + int _pty_master_fd; + int _pty_slave_fd; - std::unique_ptr<FilePointer> _el_slave_file; + std::unique_ptr<FilePointer> _el_slave_file; }; -EditlineAdapter::EditlineAdapter () : - _editline_sp (), - _pty (), - _pty_master_fd (-1), - _pty_slave_fd (-1), - _el_slave_file () -{ - lldb_private::Error error; - - // Open the first master pty available. - char error_string[256]; - error_string[0] = '\0'; - if (!_pty.OpenFirstAvailableMaster (O_RDWR, error_string, sizeof (error_string))) - { - fprintf(stderr, "failed to open first available master pty: '%s'\n", error_string); - return; - } - - // Grab the master fd. This is a file descriptor we will: - // (1) write to when we want to send input to editline. - // (2) read from when we want to see what editline sends back. - _pty_master_fd = _pty.GetMasterFileDescriptor(); - - // Open the corresponding slave pty. - if (!_pty.OpenSlave (O_RDWR, error_string, sizeof (error_string))) - { - fprintf(stderr, "failed to open slave pty: '%s'\n", error_string); - return; - } - _pty_slave_fd = _pty.GetSlaveFileDescriptor(); +EditlineAdapter::EditlineAdapter() + : _editline_sp(), _pty(), _pty_master_fd(-1), _pty_slave_fd(-1), + _el_slave_file() { + lldb_private::Error error; + + // Open the first master pty available. + char error_string[256]; + error_string[0] = '\0'; + if (!_pty.OpenFirstAvailableMaster(O_RDWR, error_string, + sizeof(error_string))) { + fprintf(stderr, "failed to open first available master pty: '%s'\n", + error_string); + return; + } + + // Grab the master fd. This is a file descriptor we will: + // (1) write to when we want to send input to editline. + // (2) read from when we want to see what editline sends back. + _pty_master_fd = _pty.GetMasterFileDescriptor(); + + // Open the corresponding slave pty. + if (!_pty.OpenSlave(O_RDWR, error_string, sizeof(error_string))) { + fprintf(stderr, "failed to open slave pty: '%s'\n", error_string); + return; + } + _pty_slave_fd = _pty.GetSlaveFileDescriptor(); + + _el_slave_file.reset(new FilePointer(fdopen(_pty_slave_fd, "rw"))); + EXPECT_FALSE(nullptr == *_el_slave_file); + if (*_el_slave_file == nullptr) + return; + + // Create an Editline instance. + _editline_sp.reset(new lldb_private::Editline("gtest editor", *_el_slave_file, + *_el_slave_file, + *_el_slave_file, false)); + _editline_sp->SetPrompt("> "); + + // Hookup our input complete callback. + _editline_sp->SetIsInputCompleteCallback(IsInputComplete, this); +} - _el_slave_file.reset (new FilePointer (fdopen (_pty_slave_fd, "rw"))); - EXPECT_FALSE (nullptr == *_el_slave_file); - if (*_el_slave_file == nullptr) - return; +void EditlineAdapter::CloseInput() { + if (_el_slave_file != nullptr) + _el_slave_file.reset(nullptr); +} - // Create an Editline instance. - _editline_sp.reset (new lldb_private::Editline("gtest editor", *_el_slave_file, *_el_slave_file, *_el_slave_file, false)); - _editline_sp->SetPrompt ("> "); +bool EditlineAdapter::SendLine(const std::string &line) { + // Ensure we're valid before proceeding. + if (!IsValid()) + return false; - // Hookup our input complete callback. - _editline_sp->SetIsInputCompleteCallback(IsInputComplete, this); -} + // Write the line out to the pipe connected to editline's input. + ssize_t input_bytes_written = + ::write(_pty_master_fd, line.c_str(), + line.length() * sizeof(std::string::value_type)); -void -EditlineAdapter::CloseInput () -{ - if (_el_slave_file != nullptr) - _el_slave_file.reset (nullptr); -} + const char *eoln = "\n"; + const size_t eoln_length = strlen(eoln); + input_bytes_written = + ::write(_pty_master_fd, eoln, eoln_length * sizeof(char)); -bool -EditlineAdapter::SendLine (const std::string &line) -{ - // Ensure we're valid before proceeding. - if (!IsValid ()) - return false; - - // Write the line out to the pipe connected to editline's input. - ssize_t input_bytes_written = - ::write (_pty_master_fd, - line.c_str(), - line.length() * sizeof (std::string::value_type)); - - const char *eoln = "\n"; - const size_t eoln_length = strlen(eoln); - input_bytes_written = - ::write (_pty_master_fd, - eoln, - eoln_length * sizeof (char)); - - EXPECT_NE(-1, input_bytes_written) << strerror(errno); - EXPECT_EQ (eoln_length * sizeof (char), size_t(input_bytes_written)); - return eoln_length * sizeof (char) == size_t(input_bytes_written); + EXPECT_NE(-1, input_bytes_written) << strerror(errno); + EXPECT_EQ(eoln_length * sizeof(char), size_t(input_bytes_written)); + return eoln_length * sizeof(char) == size_t(input_bytes_written); } -bool -EditlineAdapter::SendLines (const std::vector<std::string> &lines) -{ - for (auto &line : lines) - { +bool EditlineAdapter::SendLines(const std::vector<std::string> &lines) { + for (auto &line : lines) { #if EDITLINE_TEST_DUMP_OUTPUT - printf ("<stdin> sending line \"%s\"\n", line.c_str()); + printf("<stdin> sending line \"%s\"\n", line.c_str()); #endif - if (!SendLine (line)) - return false; - } - return true; + if (!SendLine(line)) + return false; + } + return true; } // We ignore the timeout for now. -bool -EditlineAdapter::GetLine (std::string &line, bool &interrupted, size_t /* timeout_millis */) -{ - // Ensure we're valid before proceeding. - if (!IsValid ()) - return false; - - _editline_sp->GetLine (line, interrupted); - return true; +bool EditlineAdapter::GetLine(std::string &line, bool &interrupted, + size_t /* timeout_millis */) { + // Ensure we're valid before proceeding. + if (!IsValid()) + return false; + + _editline_sp->GetLine(line, interrupted); + return true; } -bool -EditlineAdapter::GetLines (lldb_private::StringList &lines, bool &interrupted, size_t /* timeout_millis */) -{ - // Ensure we're valid before proceeding. - if (!IsValid ()) - return false; - - _editline_sp->GetLines (1, lines, interrupted); - return true; +bool EditlineAdapter::GetLines(lldb_private::StringList &lines, + bool &interrupted, size_t /* timeout_millis */) { + // Ensure we're valid before proceeding. + if (!IsValid()) + return false; + + _editline_sp->GetLines(1, lines, interrupted); + return true; } -bool -EditlineAdapter::IsInputComplete ( - lldb_private::Editline * editline, - lldb_private::StringList & lines, - void * baton) -{ - // We'll call ourselves complete if we've received a balanced set of braces. - int start_block_count = 0; - int brace_balance = 0; - - for (size_t i = 0; i < lines.GetSize (); ++i) - { - for (auto ch : lines[i]) - { - if (ch == '{') - { - ++start_block_count; - ++brace_balance; - } - else if (ch == '}') - --brace_balance; - } +bool EditlineAdapter::IsInputComplete(lldb_private::Editline *editline, + lldb_private::StringList &lines, + void *baton) { + // We'll call ourselves complete if we've received a balanced set of braces. + int start_block_count = 0; + int brace_balance = 0; + + for (size_t i = 0; i < lines.GetSize(); ++i) { + for (auto ch : lines[i]) { + if (ch == '{') { + ++start_block_count; + ++brace_balance; + } else if (ch == '}') + --brace_balance; } + } - return (start_block_count > 0) && (brace_balance == 0); + return (start_block_count > 0) && (brace_balance == 0); } -void -EditlineAdapter::ConsumeAllOutput () -{ - FilePointer output_file (fdopen (_pty_master_fd, "r")); +void EditlineAdapter::ConsumeAllOutput() { + FilePointer output_file(fdopen(_pty_master_fd, "r")); - int ch; - while ((ch = fgetc(output_file)) != EOF) - { + int ch; + while ((ch = fgetc(output_file)) != EOF) { #if EDITLINE_TEST_DUMP_OUTPUT - char display_str[] = { 0, 0, 0 }; - switch (ch) - { - case '\t': - display_str[0] = '\\'; - display_str[1] = 't'; - break; - case '\n': - display_str[0] = '\\'; - display_str[1] = 'n'; - break; - case '\r': - display_str[0] = '\\'; - display_str[1] = 'r'; - break; - default: - display_str[0] = ch; - break; - } - printf ("<stdout> 0x%02x (%03d) (%s)\n", ch, ch, display_str); - // putc(ch, stdout); -#endif + char display_str[] = {0, 0, 0}; + switch (ch) { + case '\t': + display_str[0] = '\\'; + display_str[1] = 't'; + break; + case '\n': + display_str[0] = '\\'; + display_str[1] = 'n'; + break; + case '\r': + display_str[0] = '\\'; + display_str[1] = 'r'; + break; + default: + display_str[0] = ch; + break; } + printf("<stdout> 0x%02x (%03d) (%s)\n", ch, ch, display_str); +// putc(ch, stdout); +#endif + } } -class EditlineTestFixture : public ::testing::Test -{ +class EditlineTestFixture : public ::testing::Test { private: - EditlineAdapter _el_adapter; - std::shared_ptr<std::thread> _sp_output_thread; + EditlineAdapter _el_adapter; + std::shared_ptr<std::thread> _sp_output_thread; public: - void SetUp() - { - // We need a TERM set properly for editline to work as expected. - setenv("TERM", "vt100", 1); - - // Validate the editline adapter. - EXPECT_TRUE(_el_adapter.IsValid()); - if (!_el_adapter.IsValid()) - return; - - // Dump output. - _sp_output_thread.reset(new std::thread([&] { _el_adapter.ConsumeAllOutput(); })); - } - - void TearDown() - { - _el_adapter.CloseInput(); - if (_sp_output_thread) - _sp_output_thread->join(); - } - - EditlineAdapter &GetEditlineAdapter() { return _el_adapter; } + void SetUp() { + // We need a TERM set properly for editline to work as expected. + setenv("TERM", "vt100", 1); + + // Validate the editline adapter. + EXPECT_TRUE(_el_adapter.IsValid()); + if (!_el_adapter.IsValid()) + return; + + // Dump output. + _sp_output_thread.reset( + new std::thread([&] { _el_adapter.ConsumeAllOutput(); })); + } + + void TearDown() { + _el_adapter.CloseInput(); + if (_sp_output_thread) + _sp_output_thread->join(); + } + + EditlineAdapter &GetEditlineAdapter() { return _el_adapter; } }; -TEST_F(EditlineTestFixture, EditlineReceivesSingleLineText) -{ - // Send it some text via our virtual keyboard. - const std::string input_text ("Hello, world"); - EXPECT_TRUE(GetEditlineAdapter().SendLine(input_text)); +TEST_F(EditlineTestFixture, EditlineReceivesSingleLineText) { + // Send it some text via our virtual keyboard. + const std::string input_text("Hello, world"); + EXPECT_TRUE(GetEditlineAdapter().SendLine(input_text)); - // Verify editline sees what we put in. - std::string el_reported_line; - bool input_interrupted = false; - const bool received_line = GetEditlineAdapter().GetLine(el_reported_line, input_interrupted, TIMEOUT_MILLIS); + // Verify editline sees what we put in. + std::string el_reported_line; + bool input_interrupted = false; + const bool received_line = GetEditlineAdapter().GetLine( + el_reported_line, input_interrupted, TIMEOUT_MILLIS); - EXPECT_TRUE (received_line); - EXPECT_FALSE (input_interrupted); - EXPECT_EQ (input_text, el_reported_line); + EXPECT_TRUE(received_line); + EXPECT_FALSE(input_interrupted); + EXPECT_EQ(input_text, el_reported_line); } -TEST_F(EditlineTestFixture, EditlineReceivesMultiLineText) -{ - // Send it some text via our virtual keyboard. - std::vector<std::string> input_lines; - input_lines.push_back ("int foo()"); - input_lines.push_back ("{"); - input_lines.push_back ("printf(\"Hello, world\");"); - input_lines.push_back ("}"); - input_lines.push_back (""); - - EXPECT_TRUE(GetEditlineAdapter().SendLines(input_lines)); - - // Verify editline sees what we put in. - lldb_private::StringList el_reported_lines; - bool input_interrupted = false; - - EXPECT_TRUE(GetEditlineAdapter().GetLines(el_reported_lines, input_interrupted, TIMEOUT_MILLIS)); - EXPECT_FALSE (input_interrupted); - - // Without any auto indentation support, our output should directly match our input. - EXPECT_EQ (input_lines.size (), el_reported_lines.GetSize ()); - if (input_lines.size () == el_reported_lines.GetSize ()) - { - for (size_t i = 0; i < input_lines.size(); ++i) - EXPECT_EQ (input_lines[i], el_reported_lines[i]); - } +TEST_F(EditlineTestFixture, EditlineReceivesMultiLineText) { + // Send it some text via our virtual keyboard. + std::vector<std::string> input_lines; + input_lines.push_back("int foo()"); + input_lines.push_back("{"); + input_lines.push_back("printf(\"Hello, world\");"); + input_lines.push_back("}"); + input_lines.push_back(""); + + EXPECT_TRUE(GetEditlineAdapter().SendLines(input_lines)); + + // Verify editline sees what we put in. + lldb_private::StringList el_reported_lines; + bool input_interrupted = false; + + EXPECT_TRUE(GetEditlineAdapter().GetLines(el_reported_lines, + input_interrupted, TIMEOUT_MILLIS)); + EXPECT_FALSE(input_interrupted); + + // Without any auto indentation support, our output should directly match our + // input. + EXPECT_EQ(input_lines.size(), el_reported_lines.GetSize()); + if (input_lines.size() == el_reported_lines.GetSize()) { + for (size_t i = 0; i < input_lines.size(); ++i) + EXPECT_EQ(input_lines[i], el_reported_lines[i]); + } } #endif |