[lldb] Add unit tests for Terminal API
authorMichał Górny <mgorny@moritz.systems>
Fri, 1 Oct 2021 19:28:08 +0000 (21:28 +0200)
committerMichał Górny <mgorny@moritz.systems>
Mon, 4 Oct 2021 12:19:34 +0000 (14:19 +0200)
Differential Revision: https://reviews.llvm.org/D110962

lldb/unittests/Host/CMakeLists.txt
lldb/unittests/Host/posix/TerminalTest.cpp [new file with mode: 0644]

index 14c4fe4..ae6afd5 100644 (file)
@@ -22,6 +22,12 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux|Android")
   )
 endif()
 
+if (LLDB_ENABLE_TERMIOS)
+  list(APPEND FILES
+    posix/TerminalTest.cpp
+  )
+endif()
+
 add_lldb_unittest(HostTests
   ${FILES}
   LINK_LIBS
diff --git a/lldb/unittests/Host/posix/TerminalTest.cpp b/lldb/unittests/Host/posix/TerminalTest.cpp
new file mode 100644 (file)
index 0000000..ecdb548
--- /dev/null
@@ -0,0 +1,126 @@
+//===-- TerminalTest.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/PseudoTerminal.h"
+#include "lldb/Host/Terminal.h"
+#include "llvm/Testing/Support/Error.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include <termios.h>
+#include <unistd.h>
+
+using namespace lldb_private;
+
+class TerminalTest : public ::testing::Test {
+protected:
+  PseudoTerminal m_pty;
+
+  void SetUp() override {
+    EXPECT_THAT_ERROR(m_pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY),
+                      llvm::Succeeded());
+  }
+};
+
+TEST_F(TerminalTest, PtyIsATerminal) {
+  Terminal term{m_pty.GetPrimaryFileDescriptor()};
+  EXPECT_EQ(term.IsATerminal(), true);
+}
+
+TEST_F(TerminalTest, PipeIsNotATerminal) {
+  int pipefd[2];
+  ASSERT_EQ(pipe(pipefd), 0);
+  Terminal pipeterm{pipefd[0]};
+  EXPECT_EQ(pipeterm.IsATerminal(), false);
+  close(pipefd[0]);
+  close(pipefd[1]);
+}
+
+TEST_F(TerminalTest, SetEcho) {
+  struct termios terminfo;
+  Terminal term{m_pty.GetPrimaryFileDescriptor()};
+
+  ASSERT_EQ(term.SetEcho(true), true);
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &terminfo), 0);
+  EXPECT_NE(terminfo.c_lflag & ECHO, 0U);
+
+  ASSERT_EQ(term.SetEcho(false), true);
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &terminfo), 0);
+  EXPECT_EQ(terminfo.c_lflag & ECHO, 0U);
+}
+
+TEST_F(TerminalTest, SetCanonical) {
+  struct termios terminfo;
+  Terminal term{m_pty.GetPrimaryFileDescriptor()};
+
+  ASSERT_EQ(term.SetCanonical(true), true);
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &terminfo), 0);
+  EXPECT_NE(terminfo.c_lflag & ICANON, 0U);
+
+  ASSERT_EQ(term.SetCanonical(false), true);
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &terminfo), 0);
+  EXPECT_EQ(terminfo.c_lflag & ICANON, 0U);
+}
+
+TEST_F(TerminalTest, SaveRestoreRAII) {
+  struct termios orig_terminfo;
+  struct termios terminfo;
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &orig_terminfo), 0);
+
+  Terminal term{m_pty.GetPrimaryFileDescriptor()};
+
+  {
+    TerminalState term_state{term};
+    terminfo = orig_terminfo;
+
+    // make some arbitrary changes
+    terminfo.c_iflag ^= IGNPAR | INLCR;
+    terminfo.c_oflag ^= OPOST | OCRNL;
+    terminfo.c_cflag ^= PARENB | PARODD;
+    terminfo.c_lflag ^= ICANON | ECHO;
+    terminfo.c_cc[VEOF] ^= 8;
+    terminfo.c_cc[VEOL] ^= 4;
+    cfsetispeed(&terminfo, B9600);
+    cfsetospeed(&terminfo, B9600);
+
+    ASSERT_EQ(tcsetattr(m_pty.GetPrimaryFileDescriptor(), TCSANOW, &terminfo),
+              0);
+  }
+
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &terminfo), 0);
+  ASSERT_EQ(memcmp(&terminfo, &orig_terminfo, sizeof(terminfo)), 0);
+}
+
+TEST_F(TerminalTest, SaveRestore) {
+  TerminalState term_state;
+
+  struct termios orig_terminfo;
+  struct termios terminfo;
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &orig_terminfo), 0);
+
+  Terminal term{m_pty.GetPrimaryFileDescriptor()};
+  term_state.Save(term, false);
+  terminfo = orig_terminfo;
+
+  // make some arbitrary changes
+  terminfo.c_iflag ^= IGNPAR | INLCR;
+  terminfo.c_oflag ^= OPOST | OCRNL;
+  terminfo.c_cflag ^= PARENB | PARODD;
+  terminfo.c_lflag ^= ICANON | ECHO;
+  terminfo.c_cc[VEOF] ^= 8;
+  terminfo.c_cc[VEOL] ^= 4;
+  cfsetispeed(&terminfo, B9600);
+  cfsetospeed(&terminfo, B9600);
+
+  ASSERT_EQ(tcsetattr(m_pty.GetPrimaryFileDescriptor(), TCSANOW, &terminfo), 0);
+
+  term_state.Restore();
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &terminfo), 0);
+  ASSERT_EQ(memcmp(&terminfo, &orig_terminfo, sizeof(terminfo)), 0);
+}