1 #include <cerrno> 2 #include <cstring> 3 #include <fcntl.h> 4 #include <gmock/gmock.h> 5 #include <gpioplus/internal/fd.hpp> 6 #include <gpioplus/test/sys.hpp> 7 #include <gtest/gtest.h> 8 #include <memory> 9 #include <signal.h> 10 #include <sys/prctl.h> 11 #include <system_error> 12 #include <type_traits> 13 #include <utility> 14 15 #ifdef HAVE_GCOV 16 // Needed for the abrt test 17 extern "C" void __gcov_flush(void); 18 #endif 19 20 namespace gpioplus 21 { 22 namespace internal 23 { 24 namespace 25 { 26 27 using testing::Assign; 28 using testing::DoAll; 29 using testing::Return; 30 31 class FdTest : public testing::Test 32 { 33 protected: 34 const int expected_fd = 1234; 35 const int expected_fd2 = 2345; 36 const int expected_fd3 = 3456; 37 testing::StrictMock<test::SysMock> mock; 38 testing::StrictMock<test::SysMock> mock2; 39 }; 40 41 TEST_F(FdTest, ConstructSimple) 42 { 43 Fd fd(expected_fd, std::false_type(), &mock); 44 EXPECT_EQ(expected_fd, *fd); 45 EXPECT_EQ(&mock, fd.getSys()); 46 47 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0)); 48 } 49 50 TEST_F(FdTest, ConstructSimplBadFd) 51 { 52 Fd fd(-1, std::false_type(), &mock); 53 EXPECT_EQ(-1, *fd); 54 } 55 56 TEST_F(FdTest, ConstructDup) 57 { 58 EXPECT_CALL(mock, dup(expected_fd)).WillOnce(Return(expected_fd2)); 59 Fd fd(expected_fd, &mock); 60 EXPECT_EQ(expected_fd2, *fd); 61 EXPECT_EQ(&mock, fd.getSys()); 62 63 EXPECT_CALL(mock, close(expected_fd2)).WillOnce(Return(0)); 64 } 65 66 TEST_F(FdTest, ConstructDupFail) 67 { 68 EXPECT_CALL(mock, dup(expected_fd)) 69 .WillOnce(DoAll(Assign(&errno, EINVAL), Return(-1))); 70 EXPECT_THROW(Fd(expected_fd, &mock), std::system_error); 71 } 72 73 void abrt_handler(int signum) 74 { 75 if (signum == SIGABRT) 76 { 77 #ifdef HAVE_GCOV 78 __gcov_flush(); 79 #endif 80 } 81 } 82 83 TEST_F(FdTest, CloseFails) 84 { 85 EXPECT_DEATH( 86 { 87 struct sigaction act; 88 act.sa_handler = abrt_handler; 89 sigemptyset(&act.sa_mask); 90 act.sa_flags = 0; 91 ASSERT_EQ(0, sigaction(SIGABRT, &act, nullptr)); 92 ASSERT_EQ(0, prctl(PR_SET_DUMPABLE, 0, 0, 0, 0)); 93 EXPECT_CALL(mock, close(expected_fd)) 94 .WillOnce(DoAll(Assign(&errno, EINVAL), Return(-1))); 95 Fd(expected_fd, std::false_type(), &mock); 96 }, 97 ""); 98 } 99 100 TEST_F(FdTest, ConstructSuccess) 101 { 102 const char* path = "/no-such-path/gpio"; 103 const int flags = O_RDWR; 104 EXPECT_CALL(mock, open(path, flags)).WillOnce(Return(expected_fd)); 105 Fd fd(path, flags, &mock); 106 EXPECT_EQ(expected_fd, *fd); 107 EXPECT_EQ(&mock, fd.getSys()); 108 109 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0)); 110 } 111 112 TEST_F(FdTest, ConstructError) 113 { 114 const char* path = "/no-such-path/gpio"; 115 const int flags = O_RDWR; 116 EXPECT_CALL(mock, open(path, flags)) 117 .WillOnce(DoAll(Assign(&errno, EBUSY), Return(-1))); 118 EXPECT_THROW(Fd(path, flags, &mock), std::system_error); 119 } 120 121 TEST_F(FdTest, ConstructCopy) 122 { 123 Fd fd(expected_fd, std::false_type(), &mock); 124 { 125 EXPECT_CALL(mock, dup(expected_fd)).WillOnce(Return(expected_fd2)); 126 Fd fd2(fd); 127 EXPECT_EQ(expected_fd2, *fd2); 128 EXPECT_EQ(expected_fd, *fd); 129 130 EXPECT_CALL(mock, close(expected_fd2)).WillOnce(Return(0)); 131 } 132 133 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0)); 134 } 135 136 TEST_F(FdTest, OperatorCopySame) 137 { 138 Fd fd(expected_fd, std::false_type(), &mock); 139 fd = fd; 140 EXPECT_EQ(expected_fd, *fd); 141 142 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0)); 143 } 144 145 TEST_F(FdTest, OperatorCopy) 146 { 147 Fd fd(expected_fd, std::false_type(), &mock); 148 { 149 Fd fd2(expected_fd2, std::false_type(), &mock2); 150 EXPECT_CALL(mock2, close(expected_fd2)).WillOnce(Return(0)); 151 EXPECT_CALL(mock, dup(expected_fd)).WillOnce(Return(expected_fd3)); 152 fd2 = fd; 153 EXPECT_EQ(expected_fd3, *fd2); 154 EXPECT_EQ(&mock, fd2.getSys()); 155 EXPECT_EQ(expected_fd, *fd); 156 EXPECT_EQ(&mock, fd.getSys()); 157 158 EXPECT_CALL(mock, close(expected_fd3)).WillOnce(Return(0)); 159 } 160 161 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0)); 162 } 163 164 TEST_F(FdTest, ConstructMove) 165 { 166 Fd fd(expected_fd, std::false_type(), &mock); 167 { 168 Fd fd2(std::move(fd)); 169 EXPECT_EQ(expected_fd, *fd2); 170 EXPECT_EQ(-1, *fd); 171 172 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0)); 173 } 174 } 175 176 TEST_F(FdTest, OperatorMoveSame) 177 { 178 Fd fd(expected_fd, std::false_type(), &mock); 179 fd = std::move(fd); 180 EXPECT_EQ(expected_fd, *fd); 181 182 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0)); 183 } 184 185 TEST_F(FdTest, OperatorMove) 186 { 187 Fd fd(expected_fd, std::false_type(), &mock); 188 { 189 Fd fd2(expected_fd2, std::false_type(), &mock2); 190 EXPECT_CALL(mock2, close(expected_fd2)).WillOnce(Return(0)); 191 fd2 = std::move(fd); 192 EXPECT_EQ(expected_fd, *fd2); 193 EXPECT_EQ(&mock, fd2.getSys()); 194 EXPECT_EQ(-1, *fd); 195 EXPECT_EQ(&mock, fd.getSys()); 196 197 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0)); 198 } 199 } 200 201 class FdMethodTest : public FdTest 202 { 203 protected: 204 const int flags_blocking = O_SYNC | O_NOATIME; 205 const int flags_noblocking = O_NONBLOCK | flags_blocking; 206 std::unique_ptr<Fd> fd; 207 208 void SetUp() 209 { 210 fd = std::make_unique<Fd>(expected_fd, std::false_type(), &mock); 211 } 212 213 void TearDown() 214 { 215 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0)); 216 fd.reset(); 217 } 218 }; 219 220 TEST_F(FdMethodTest, SetBlockingOnBlocking) 221 { 222 EXPECT_CALL(mock, fcntl_getfl(expected_fd)) 223 .WillOnce(Return(flags_blocking)); 224 EXPECT_CALL(mock, fcntl_setfl(expected_fd, flags_blocking)) 225 .WillOnce(Return(0)); 226 fd->setBlocking(true); 227 } 228 229 TEST_F(FdMethodTest, SetBlockingOnNonBlocking) 230 { 231 EXPECT_CALL(mock, fcntl_getfl(expected_fd)) 232 .WillOnce(Return(flags_noblocking)); 233 EXPECT_CALL(mock, fcntl_setfl(expected_fd, flags_blocking)) 234 .WillOnce(Return(0)); 235 fd->setBlocking(true); 236 } 237 238 TEST_F(FdMethodTest, SetNonBlockingOnBlocking) 239 { 240 EXPECT_CALL(mock, fcntl_getfl(expected_fd)) 241 .WillOnce(Return(flags_blocking)); 242 EXPECT_CALL(mock, fcntl_setfl(expected_fd, flags_noblocking)) 243 .WillOnce(Return(0)); 244 fd->setBlocking(false); 245 } 246 247 TEST_F(FdMethodTest, SetNonBlockingOnNonBlocking) 248 { 249 EXPECT_CALL(mock, fcntl_getfl(expected_fd)) 250 .WillOnce(Return(flags_noblocking)); 251 EXPECT_CALL(mock, fcntl_setfl(expected_fd, flags_noblocking)) 252 .WillOnce(Return(0)); 253 fd->setBlocking(false); 254 } 255 256 TEST_F(FdMethodTest, GetFlagsFail) 257 { 258 EXPECT_CALL(mock, fcntl_getfl(expected_fd)) 259 .WillOnce(DoAll(Assign(&errno, EINVAL), Return(-1))); 260 EXPECT_THROW(fd->setBlocking(true), std::system_error); 261 } 262 263 TEST_F(FdMethodTest, SetFlagsFail) 264 { 265 EXPECT_CALL(mock, fcntl_getfl(expected_fd)).WillOnce(Return(0)); 266 EXPECT_CALL(mock, fcntl_setfl(expected_fd, 0)) 267 .WillOnce(DoAll(Assign(&errno, EINVAL), Return(-1))); 268 EXPECT_THROW(fd->setBlocking(true), std::system_error); 269 } 270 271 } // namespace 272 } // namespace internal 273 } // namespace gpioplus 274