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 // Test move operator but newer compilers complain about move-to-self 183 // so use an explicit r-value ref cast to do the same. 184 fd = static_cast<Fd&&>(fd); 185 EXPECT_EQ(expected_fd, *fd); 186 187 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0)); 188 } 189 190 TEST_F(FdTest, OperatorMove) 191 { 192 Fd fd(expected_fd, std::false_type(), &mock); 193 { 194 Fd fd2(expected_fd2, std::false_type(), &mock2); 195 EXPECT_CALL(mock2, close(expected_fd2)).WillOnce(Return(0)); 196 fd2 = std::move(fd); 197 EXPECT_EQ(expected_fd, *fd2); 198 EXPECT_EQ(&mock, fd2.getSys()); 199 EXPECT_EQ(-1, *fd); 200 EXPECT_EQ(&mock, fd.getSys()); 201 202 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0)); 203 } 204 } 205 206 class FdMethodTest : public FdTest 207 { 208 protected: 209 const int flags_blocking = O_SYNC | O_NOATIME; 210 const int flags_noblocking = O_NONBLOCK | flags_blocking; 211 std::unique_ptr<Fd> fd; 212 213 void SetUp() 214 { 215 fd = std::make_unique<Fd>(expected_fd, std::false_type(), &mock); 216 } 217 218 void TearDown() 219 { 220 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0)); 221 fd.reset(); 222 } 223 }; 224 225 TEST_F(FdMethodTest, SetBlockingOnBlocking) 226 { 227 EXPECT_CALL(mock, fcntl_getfl(expected_fd)) 228 .WillOnce(Return(flags_blocking)); 229 EXPECT_CALL(mock, fcntl_setfl(expected_fd, flags_blocking)) 230 .WillOnce(Return(0)); 231 fd->setBlocking(true); 232 } 233 234 TEST_F(FdMethodTest, SetBlockingOnNonBlocking) 235 { 236 EXPECT_CALL(mock, fcntl_getfl(expected_fd)) 237 .WillOnce(Return(flags_noblocking)); 238 EXPECT_CALL(mock, fcntl_setfl(expected_fd, flags_blocking)) 239 .WillOnce(Return(0)); 240 fd->setBlocking(true); 241 } 242 243 TEST_F(FdMethodTest, SetNonBlockingOnBlocking) 244 { 245 EXPECT_CALL(mock, fcntl_getfl(expected_fd)) 246 .WillOnce(Return(flags_blocking)); 247 EXPECT_CALL(mock, fcntl_setfl(expected_fd, flags_noblocking)) 248 .WillOnce(Return(0)); 249 fd->setBlocking(false); 250 } 251 252 TEST_F(FdMethodTest, SetNonBlockingOnNonBlocking) 253 { 254 EXPECT_CALL(mock, fcntl_getfl(expected_fd)) 255 .WillOnce(Return(flags_noblocking)); 256 EXPECT_CALL(mock, fcntl_setfl(expected_fd, flags_noblocking)) 257 .WillOnce(Return(0)); 258 fd->setBlocking(false); 259 } 260 261 TEST_F(FdMethodTest, GetFlagsFail) 262 { 263 EXPECT_CALL(mock, fcntl_getfl(expected_fd)) 264 .WillOnce(DoAll(Assign(&errno, EINVAL), Return(-1))); 265 EXPECT_THROW(fd->setBlocking(true), std::system_error); 266 } 267 268 TEST_F(FdMethodTest, SetFlagsFail) 269 { 270 EXPECT_CALL(mock, fcntl_getfl(expected_fd)).WillOnce(Return(0)); 271 EXPECT_CALL(mock, fcntl_setfl(expected_fd, 0)) 272 .WillOnce(DoAll(Assign(&errno, EINVAL), Return(-1))); 273 EXPECT_THROW(fd->setBlocking(true), std::system_error); 274 } 275 276 } // namespace 277 } // namespace internal 278 } // namespace gpioplus 279