1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <gmock/gmock.h> 18 #include <gtest/gtest.h> 19 20 #include <stdio.h> 21 #include <sys/types.h> 22 #include <unistd.h> 23 24 #include <string> 25 26 #include "bugreportz.h" 27 28 using ::testing::StrEq; 29 using ::testing::internal::CaptureStdout; 30 using ::testing::internal::GetCapturedStdout; 31 32 class BugreportzTest : public ::testing::Test { 33 public: 34 // Creates the pipe used to communicate with bugreportz() 35 void SetUp() { 36 int fds[2]; 37 ASSERT_EQ(0, pipe(fds)); 38 read_fd_ = fds[0]; 39 write_fd_ = fds[1]; 40 } 41 42 // Closes the pipe FDs. 43 // If a FD is closed manually during a test, set it to -1 to prevent TearDown() trying to close 44 // it again. 45 void TearDown() { 46 for (int fd : {read_fd_, write_fd_}) { 47 if (fd >= 0) { 48 close(fd); 49 } 50 } 51 } 52 53 // Emulates dumpstate output by writing to the socket passed to bugreportz() 54 void WriteToSocket(const std::string& data) { 55 if (write_fd_ < 0) { 56 ADD_FAILURE() << "cannot write '" << data << "' because socket is already closed"; 57 return; 58 } 59 int expected = data.length(); 60 int actual = write(write_fd_, data.data(), data.length()); 61 ASSERT_EQ(expected, actual) << "wrong number of bytes written to socket"; 62 } 63 64 void AssertStdoutEquals(const std::string& expected) { 65 ASSERT_THAT(stdout_, StrEq(expected)) << "wrong stdout output"; 66 } 67 68 // Calls bugreportz() using the internal pipe. 69 // 70 // Tests must call WriteToSocket() to set what's written prior to calling it, since the writing 71 // end of the pipe will be closed before calling bugreportz() (otherwise that function would 72 // hang). 73 void Bugreportz(bool show_progress) { 74 close(write_fd_); 75 write_fd_ = -1; 76 77 CaptureStdout(); 78 int status = bugreportz(read_fd_, show_progress); 79 80 close(read_fd_); 81 read_fd_ = -1; 82 stdout_ = GetCapturedStdout(); 83 84 ASSERT_EQ(0, status) << "bugrepotz() call failed (stdout: " << stdout_ << ")"; 85 } 86 87 private: 88 int read_fd_; 89 int write_fd_; 90 std::string stdout_; 91 }; 92 93 // Tests 'bugreportz', without any argument - it will ignore progress lines. 94 TEST_F(BugreportzTest, NoArgument) { 95 WriteToSocket("BEGIN:THE IGNORED PATH WARS HAS!\n"); // Should be ommited. 96 WriteToSocket("What happens on 'dumpstate',"); 97 WriteToSocket("stays on 'bugreportz'.\n"); 98 WriteToSocket("PROGRESS:Y U NO OMITTED?\n"); // Should be ommited. 99 WriteToSocket("But "); 100 WriteToSocket("PROGRESS IN THE MIDDLE"); // Ok - not starting a line. 101 WriteToSocket(" is accepted\n"); 102 103 Bugreportz(false); 104 105 AssertStdoutEquals( 106 "What happens on 'dumpstate',stays on 'bugreportz'.\n" 107 "But PROGRESS IN THE MIDDLE is accepted\n"); 108 } 109 110 // Tests 'bugreportz -p' - it will just echo dumpstate's output to stdout 111 TEST_F(BugreportzTest, WithProgress) { 112 WriteToSocket("BEGIN:I AM YOUR PATH\n"); 113 WriteToSocket("What happens on 'dumpstate',"); 114 WriteToSocket("stays on 'bugreportz'.\n"); 115 WriteToSocket("PROGRESS:IS INEVITABLE\n"); 116 WriteToSocket("PROG"); 117 WriteToSocket("RESS:IS NOT AUTOMATIC\n"); 118 WriteToSocket("Newline is optional"); 119 120 Bugreportz(true); 121 122 AssertStdoutEquals( 123 "BEGIN:I AM YOUR PATH\n" 124 "What happens on 'dumpstate',stays on 'bugreportz'.\n" 125 "PROGRESS:IS INEVITABLE\n" 126 "PROGRESS:IS NOT AUTOMATIC\n" 127 "Newline is optional"); 128 } 129