brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.8 KiB · 5187a0c Raw
290 lines · cpp
1//===-- TerminalTest.cpp --------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Host/FileSystem.h"10#include "lldb/Host/PseudoTerminal.h"11#include "lldb/Host/Terminal.h"12#include "llvm/Testing/Support/Error.h"13#include "TestingSupport/SubsystemRAII.h"14 15#include "gmock/gmock.h"16#include "gtest/gtest.h"17 18#include <termios.h>19#include <unistd.h>20 21using namespace lldb_private;22 23class TerminalTest : public ::testing::Test {24protected:25  SubsystemRAII<FileSystem> subsystems;26  PseudoTerminal m_pty;27  int m_fd;28  Terminal m_term;29 30  void SetUp() override {31    ASSERT_THAT_ERROR(m_pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY),32                      llvm::Succeeded());33    ASSERT_THAT_ERROR(m_pty.OpenSecondary(O_RDWR | O_NOCTTY),34                      llvm::Succeeded());35    m_fd = m_pty.GetSecondaryFileDescriptor();36    ASSERT_NE(m_fd, -1);37    m_term.SetFileDescriptor(m_fd);38  }39};40 41TEST_F(TerminalTest, PtyIsATerminal) {42  EXPECT_EQ(m_term.IsATerminal(), true);43}44 45TEST_F(TerminalTest, PipeIsNotATerminal) {46  int pipefd[2];47  ASSERT_EQ(pipe(pipefd), 0);48  Terminal pipeterm{pipefd[0]};49  EXPECT_EQ(pipeterm.IsATerminal(), false);50  close(pipefd[0]);51  close(pipefd[1]);52}53 54TEST_F(TerminalTest, SetEcho) {55  struct termios terminfo;56 57  ASSERT_THAT_ERROR(m_term.SetEcho(true), llvm::Succeeded());58  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);59  EXPECT_NE(terminfo.c_lflag & ECHO, 0U);60 61  ASSERT_THAT_ERROR(m_term.SetEcho(false), llvm::Succeeded());62  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);63  EXPECT_EQ(terminfo.c_lflag & ECHO, 0U);64}65 66TEST_F(TerminalTest, SetCanonical) {67  struct termios terminfo;68 69  ASSERT_THAT_ERROR(m_term.SetCanonical(true), llvm::Succeeded());70  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);71  EXPECT_NE(terminfo.c_lflag & ICANON, 0U);72 73  ASSERT_THAT_ERROR(m_term.SetCanonical(false), llvm::Succeeded());74  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);75  EXPECT_EQ(terminfo.c_lflag & ICANON, 0U);76}77 78TEST_F(TerminalTest, SetRaw) {79  struct termios terminfo;80 81  ASSERT_THAT_ERROR(m_term.SetRaw(), llvm::Succeeded());82  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);83  // NB: cfmakeraw() on glibc disables IGNBRK, on FreeBSD sets it84  EXPECT_EQ(terminfo.c_iflag &85                (BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON),86            0U);87  EXPECT_EQ(terminfo.c_oflag & OPOST, 0U);88  EXPECT_EQ(terminfo.c_lflag & (ICANON | ECHO | ISIG | IEXTEN), 0U);89  EXPECT_EQ(terminfo.c_cflag & (CSIZE | PARENB), 0U | CS8);90  EXPECT_EQ(terminfo.c_cc[VMIN], 1);91  EXPECT_EQ(terminfo.c_cc[VTIME], 0);92}93 94TEST_F(TerminalTest, SetBaudRate) {95  struct termios terminfo;96 97  ASSERT_THAT_ERROR(m_term.SetBaudRate(38400), llvm::Succeeded());98  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);99  EXPECT_EQ(cfgetispeed(&terminfo), static_cast<speed_t>(B38400));100  EXPECT_EQ(cfgetospeed(&terminfo), static_cast<speed_t>(B38400));101 102  ASSERT_THAT_ERROR(m_term.SetBaudRate(115200), llvm::Succeeded());103  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);104  EXPECT_EQ(cfgetispeed(&terminfo), static_cast<speed_t>(B115200));105  EXPECT_EQ(cfgetospeed(&terminfo), static_cast<speed_t>(B115200));106 107  // uncommon value108#if defined(B153600)109  ASSERT_THAT_ERROR(m_term.SetBaudRate(153600), llvm::Succeeded());110  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);111  EXPECT_EQ(cfgetispeed(&terminfo), static_cast<speed_t>(B153600));112  EXPECT_EQ(cfgetospeed(&terminfo), static_cast<speed_t>(B153600));113#else114  ASSERT_THAT_ERROR(m_term.SetBaudRate(153600),115                    llvm::Failed<llvm::ErrorInfoBase>(testing::Property(116                        &llvm::ErrorInfoBase::message,117                        "baud rate 153600 unsupported by the platform")));118#endif119}120 121TEST_F(TerminalTest, SetStopBits) {122  struct termios terminfo;123 124  ASSERT_THAT_ERROR(m_term.SetStopBits(1), llvm::Succeeded());125  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);126  EXPECT_EQ(terminfo.c_cflag & CSTOPB, 0U);127 128  ASSERT_THAT_ERROR(m_term.SetStopBits(2), llvm::Succeeded());129  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);130  EXPECT_NE(terminfo.c_cflag & CSTOPB, 0U);131 132  ASSERT_THAT_ERROR(m_term.SetStopBits(0),133                    llvm::Failed<llvm::ErrorInfoBase>(testing::Property(134                        &llvm::ErrorInfoBase::message,135                        "invalid stop bit count: 0 (must be 1 or 2)")));136  ASSERT_THAT_ERROR(m_term.SetStopBits(3),137                    llvm::Failed<llvm::ErrorInfoBase>(testing::Property(138                        &llvm::ErrorInfoBase::message,139                        "invalid stop bit count: 3 (must be 1 or 2)")));140}141 142TEST_F(TerminalTest, SetParity) {143  struct termios terminfo;144 145  ASSERT_THAT_ERROR(m_term.SetParity(Terminal::Parity::No), llvm::Succeeded());146  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);147  EXPECT_EQ(terminfo.c_cflag & PARENB, 0U);148 149#if !defined(__linux__) // Linux pty devices do not support setting parity150  ASSERT_THAT_ERROR(m_term.SetParity(Terminal::Parity::Even),151                    llvm::Succeeded());152  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);153  EXPECT_NE(terminfo.c_cflag & PARENB, 0U);154  EXPECT_EQ(terminfo.c_cflag & PARODD, 0U);155#if defined(CMSPAR)156  EXPECT_EQ(terminfo.c_cflag & CMSPAR, 0U);157#endif158 159  ASSERT_THAT_ERROR(m_term.SetParity(Terminal::Parity::Odd), llvm::Succeeded());160  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);161  EXPECT_NE(terminfo.c_cflag & PARENB, 0U);162  EXPECT_NE(terminfo.c_cflag & PARODD, 0U);163#if defined(CMSPAR)164  EXPECT_EQ(terminfo.c_cflag & CMSPAR, 0U);165#endif166 167#if defined(CMSPAR)168  ASSERT_THAT_ERROR(m_term.SetParity(Terminal::Parity::Space),169                    llvm::Succeeded());170  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);171  EXPECT_NE(terminfo.c_cflag & PARENB, 0U);172  EXPECT_EQ(terminfo.c_cflag & PARODD, 0U);173  EXPECT_NE(terminfo.c_cflag & CMSPAR, 0U);174 175  ASSERT_THAT_ERROR(m_term.SetParity(Terminal::Parity::Mark),176                    llvm::Succeeded());177  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);178  EXPECT_NE(terminfo.c_cflag & PARENB, 0U);179  EXPECT_NE(terminfo.c_cflag & PARODD, 0U);180  EXPECT_NE(terminfo.c_cflag & CMSPAR, 0U);181#endif // defined(CMSPAR)182#endif // !defined(__linux__)183 184#if !defined(CMSPAR)185  ASSERT_THAT_ERROR(m_term.SetParity(Terminal::Parity::Space),186                    llvm::Failed<llvm::ErrorInfoBase>(testing::Property(187                        &llvm::ErrorInfoBase::message,188                        "space/mark parity is not supported by the platform")));189  ASSERT_THAT_ERROR(m_term.SetParity(Terminal::Parity::Mark),190                    llvm::Failed<llvm::ErrorInfoBase>(testing::Property(191                        &llvm::ErrorInfoBase::message,192                        "space/mark parity is not supported by the platform")));193#endif194}195 196TEST_F(TerminalTest, SetParityCheck) {197  struct termios terminfo;198 199  ASSERT_THAT_ERROR(m_term.SetParityCheck(Terminal::ParityCheck::No),200                    llvm::Succeeded());201  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);202  EXPECT_EQ(terminfo.c_iflag & (IGNPAR | PARMRK | INPCK), 0U);203 204  ASSERT_THAT_ERROR(205      m_term.SetParityCheck(Terminal::ParityCheck::ReplaceWithNUL),206      llvm::Succeeded());207  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);208  EXPECT_NE(terminfo.c_iflag & INPCK, 0U);209  EXPECT_EQ(terminfo.c_iflag & (IGNPAR | PARMRK), 0U);210 211  ASSERT_THAT_ERROR(m_term.SetParityCheck(Terminal::ParityCheck::Ignore),212                    llvm::Succeeded());213  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);214  EXPECT_NE(terminfo.c_iflag & IGNPAR, 0U);215  EXPECT_EQ(terminfo.c_iflag & PARMRK, 0U);216  EXPECT_NE(terminfo.c_iflag & INPCK, 0U);217 218  ASSERT_THAT_ERROR(m_term.SetParityCheck(Terminal::ParityCheck::Mark),219                    llvm::Succeeded());220  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);221  EXPECT_EQ(terminfo.c_iflag & IGNPAR, 0U);222  EXPECT_NE(terminfo.c_iflag & PARMRK, 0U);223  EXPECT_NE(terminfo.c_iflag & INPCK, 0U);224}225 226TEST_F(TerminalTest, SetHardwareFlowControl) {227#if defined(CRTSCTS)228  struct termios terminfo;229 230  ASSERT_THAT_ERROR(m_term.SetHardwareFlowControl(true), llvm::Succeeded());231  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);232  EXPECT_NE(terminfo.c_cflag & CRTSCTS, 0U);233 234  ASSERT_THAT_ERROR(m_term.SetHardwareFlowControl(false), llvm::Succeeded());235  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);236  EXPECT_EQ(terminfo.c_cflag & CRTSCTS, 0U);237#else238  ASSERT_THAT_ERROR(239      m_term.SetHardwareFlowControl(true),240      llvm::Failed<llvm::ErrorInfoBase>(testing::Property(241          &llvm::ErrorInfoBase::message,242          "hardware flow control is not supported by the platform")));243  ASSERT_THAT_ERROR(m_term.SetHardwareFlowControl(false), llvm::Succeeded());244#endif245}246 247TEST_F(TerminalTest, SaveRestoreRAII) {248  struct termios orig_terminfo;249  struct termios terminfo;250  ASSERT_EQ(tcgetattr(m_fd, &orig_terminfo), 0);251 252  {253    TerminalState term_state{m_term};254    terminfo = orig_terminfo;255 256    // make an arbitrary change257    cfsetispeed(&terminfo,258                cfgetispeed(&orig_terminfo) == B9600 ? B4800 : B9600);259    cfsetospeed(&terminfo,260                cfgetospeed(&orig_terminfo) == B9600 ? B4800 : B9600);261 262    ASSERT_EQ(tcsetattr(m_fd, TCSANOW, &terminfo),263              0);264  }265 266  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);267  ASSERT_EQ(memcmp(&terminfo, &orig_terminfo, sizeof(terminfo)), 0);268}269 270TEST_F(TerminalTest, SaveRestore) {271  TerminalState term_state;272 273  struct termios orig_terminfo;274  struct termios terminfo;275  ASSERT_EQ(tcgetattr(m_fd, &orig_terminfo), 0);276 277  term_state.Save(m_term, false);278  terminfo = orig_terminfo;279 280  // make an arbitrary change281  cfsetispeed(&terminfo, cfgetispeed(&orig_terminfo) == B9600 ? B4800 : B9600);282  cfsetospeed(&terminfo, cfgetospeed(&orig_terminfo) == B9600 ? B4800 : B9600);283 284  ASSERT_EQ(tcsetattr(m_fd, TCSANOW, &terminfo), 0);285 286  term_state.Restore();287  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);288  ASSERT_EQ(memcmp(&terminfo, &orig_terminfo, sizeof(terminfo)), 0);289}290