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