1 #include <cerrno> 2 #include <gmock/gmock.h> 3 #include <gtest/gtest.h> 4 #include <memory> 5 #include <sdeventplus/event.hpp> 6 #include <sdeventplus/exception.hpp> 7 #include <sdeventplus/internal/sdevent.hpp> 8 #include <sdeventplus/source/base.hpp> 9 #include <sdeventplus/test/sdevent.hpp> 10 #include <string> 11 #include <system_error> 12 #include <systemd/sd-event.h> 13 #include <type_traits> 14 #include <utility> 15 16 namespace sdeventplus 17 { 18 namespace source 19 { 20 namespace 21 { 22 23 using testing::DoAll; 24 using testing::Return; 25 using testing::SaveArg; 26 using testing::SetArgPointee; 27 28 using UniqueEvent = std::unique_ptr<Event, std::function<void(Event*)>>; 29 30 class BaseImpl : public Base 31 { 32 public: 33 BaseImpl(const Event& event, sd_event_source* source) : Base(event, source) 34 { 35 } 36 BaseImpl(const Event& event, sd_event_source* source, std::false_type) : 37 Base(event, source, std::false_type()) 38 { 39 } 40 }; 41 42 class BaseTest : public testing::Test 43 { 44 protected: 45 testing::StrictMock<test::SdEventMock> mock; 46 sd_event_source* const expected_source = 47 reinterpret_cast<sd_event_source*>(1234); 48 sd_event* const expected_event = reinterpret_cast<sd_event*>(2345); 49 UniqueEvent event = make_event(expected_event); 50 51 UniqueEvent make_event(sd_event* event) 52 { 53 auto deleter = [this, event](Event* e) { 54 EXPECT_CALL(this->mock, sd_event_unref(event)) 55 .WillOnce(Return(nullptr)); 56 delete e; 57 }; 58 return UniqueEvent(new Event(event, std::false_type(), &mock), deleter); 59 } 60 61 // Using a unique_ptr to make sure we don't get any superfluous moves or 62 // copies. 63 std::unique_ptr<BaseImpl> make_base(const Event& event, 64 sd_event_source* source) 65 { 66 EXPECT_CALL(mock, sd_event_ref(event.get())) 67 .WillOnce(Return(event.get())); 68 void* userdata; 69 EXPECT_CALL(mock, sd_event_source_set_userdata(source, testing::_)) 70 .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr))); 71 auto ret = std::make_unique<BaseImpl>(event, source, std::false_type()); 72 EXPECT_EQ(ret.get(), userdata); 73 EXPECT_EQ(source, ret->get()); 74 EXPECT_NE(&event, &ret->get_event()); 75 EXPECT_EQ(event.get(), ret->get_event().get()); 76 EXPECT_FALSE(ret->get_prepare()); 77 return ret; 78 } 79 80 void set_prepare_placeholder(Base& base) 81 { 82 EXPECT_CALL(mock, sd_event_source_set_prepare(base.get(), testing::_)) 83 .WillOnce(Return(0)); 84 base.set_prepare([](Base&) {}); 85 EXPECT_TRUE(base.get_prepare()); 86 } 87 88 void empty_base(BaseImpl&& other) 89 { 90 void* userdata; 91 EXPECT_CALL(mock, sd_event_source_set_userdata(other.get(), testing::_)) 92 .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr))); 93 BaseImpl mover(std::move(other)); 94 EXPECT_EQ(&mover, userdata); 95 EXPECT_EQ(nullptr, other.get()); 96 EXPECT_EQ(nullptr, other.get_event().get()); 97 EXPECT_FALSE(other.get_prepare()); 98 99 expect_base_destruct(mover.get_event(), mover.get()); 100 } 101 102 void expect_base_destruct(const Event& event, sd_event_source* source) 103 { 104 { 105 testing::InSequence seq; 106 EXPECT_CALL(mock, sd_event_source_set_enabled(source, SD_EVENT_OFF)) 107 .WillOnce(Return(0)); 108 EXPECT_CALL(mock, sd_event_source_unref(source)) 109 .WillOnce(Return(nullptr)); 110 } 111 EXPECT_CALL(mock, sd_event_unref(event.get())) 112 .WillOnce(Return(nullptr)); 113 } 114 }; 115 116 TEST_F(BaseTest, NewBaseRef) 117 { 118 EXPECT_CALL(mock, sd_event_ref(expected_event)) 119 .WillOnce(Return(expected_event)); 120 EXPECT_CALL(mock, sd_event_source_ref(expected_source)) 121 .WillOnce(Return(expected_source)); 122 void* userdata; 123 EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_)) 124 .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr))); 125 BaseImpl source(*event, expected_source); 126 EXPECT_EQ(&source, userdata); 127 EXPECT_EQ(expected_source, source.get()); 128 EXPECT_NE(event.get(), &source.get_event()); 129 EXPECT_EQ(expected_event, source.get_event().get()); 130 EXPECT_FALSE(source.get_prepare()); 131 132 expect_base_destruct(*event, expected_source); 133 } 134 135 TEST_F(BaseTest, NewBaseNoRef) 136 { 137 EXPECT_CALL(mock, sd_event_ref(expected_event)) 138 .WillOnce(Return(expected_event)); 139 void* userdata; 140 EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_)) 141 .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr))); 142 BaseImpl source(*event, expected_source, std::false_type()); 143 EXPECT_EQ(&source, userdata); 144 EXPECT_EQ(expected_source, source.get()); 145 EXPECT_NE(event.get(), &source.get_event()); 146 EXPECT_EQ(expected_event, source.get_event().get()); 147 EXPECT_FALSE(source.get_prepare()); 148 149 expect_base_destruct(*event, expected_source); 150 } 151 152 TEST_F(BaseTest, MoveConstruct) 153 { 154 std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source); 155 set_prepare_placeholder(*source1); 156 157 void* userdata; 158 EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_)) 159 .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr))); 160 BaseImpl source2(std::move(*source1)); 161 EXPECT_EQ(&source2, userdata); 162 EXPECT_EQ(nullptr, source1->get()); 163 EXPECT_EQ(nullptr, source1->get_event().get()); 164 EXPECT_FALSE(source1->get_prepare()); 165 EXPECT_EQ(expected_source, source2.get()); 166 EXPECT_EQ(expected_event, source2.get_event().get()); 167 EXPECT_TRUE(source2.get_prepare()); 168 169 expect_base_destruct(*event, expected_source); 170 } 171 172 TEST_F(BaseTest, MoveAssignSelf) 173 { 174 std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source); 175 set_prepare_placeholder(*source1); 176 177 *source1 = std::move(*source1); 178 EXPECT_EQ(expected_source, source1->get()); 179 EXPECT_EQ(expected_event, source1->get_event().get()); 180 EXPECT_TRUE(source1->get_prepare()); 181 182 expect_base_destruct(*event, expected_source); 183 } 184 185 TEST_F(BaseTest, MoveAssignEmpty) 186 { 187 std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source); 188 set_prepare_placeholder(*source1); 189 190 std::unique_ptr<BaseImpl> source2 = make_base(*event, expected_source); 191 empty_base(std::move(*source2)); 192 193 { 194 void* userdata; 195 EXPECT_CALL(mock, 196 sd_event_source_set_userdata(expected_source, testing::_)) 197 .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr))); 198 *source2 = std::move(*source1); 199 EXPECT_EQ(source2.get(), userdata); 200 } 201 EXPECT_EQ(nullptr, source1->get()); 202 EXPECT_EQ(nullptr, source1->get_event().get()); 203 EXPECT_FALSE(source1->get_prepare()); 204 EXPECT_EQ(expected_source, source2->get()); 205 EXPECT_EQ(expected_event, source2->get_event().get()); 206 EXPECT_TRUE(source2->get_prepare()); 207 208 // Make sure source1 is deleted to ensure it isn't holding a reference 209 source1.reset(); 210 expect_base_destruct(*event, expected_source); 211 } 212 213 TEST_F(BaseTest, MoveAssignExisting) 214 { 215 sd_event_source* const expected_source2 = 216 reinterpret_cast<sd_event_source*>(3456); 217 sd_event* const expected_event2 = reinterpret_cast<sd_event*>(4567); 218 219 std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source); 220 set_prepare_placeholder(*source1); 221 222 UniqueEvent event2 = make_event(expected_event2); 223 std::unique_ptr<BaseImpl> source2 = make_base(*event2, expected_source2); 224 225 { 226 expect_base_destruct(*event2, expected_source2); 227 void* userdata; 228 EXPECT_CALL(mock, 229 sd_event_source_set_userdata(expected_source, testing::_)) 230 .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr))); 231 *source2 = std::move(*source1); 232 EXPECT_EQ(source2.get(), userdata); 233 } 234 EXPECT_EQ(nullptr, source1->get()); 235 EXPECT_EQ(nullptr, source1->get_event().get()); 236 EXPECT_FALSE(source1->get_prepare()); 237 EXPECT_EQ(expected_source, source2->get()); 238 EXPECT_EQ(expected_event, source2->get_event().get()); 239 EXPECT_TRUE(source2->get_prepare()); 240 241 // Make sure source1 is deleted to ensure it isn't holding a reference 242 source1.reset(); 243 expect_base_destruct(*event, expected_source); 244 } 245 246 class BaseMethodTest : public BaseTest 247 { 248 protected: 249 std::unique_ptr<BaseImpl> base = make_base(*event, expected_source); 250 251 void TearDown() 252 { 253 expect_base_destruct(base->get_event(), base->get()); 254 base.reset(); 255 } 256 }; 257 258 TEST_F(BaseMethodTest, GetDescriptionSuccess) 259 { 260 const char* expected = "test_desc"; 261 EXPECT_CALL(mock, 262 sd_event_source_get_description(expected_source, testing::_)) 263 .WillOnce(DoAll(SetArgPointee<1>(expected), Return(0))); 264 // Intentionally comparing pointers to make sure no copying is happening 265 EXPECT_EQ(expected, base->get_description()); 266 } 267 268 TEST_F(BaseMethodTest, GetDescriptionError) 269 { 270 EXPECT_CALL(mock, 271 sd_event_source_get_description(expected_source, testing::_)) 272 .WillOnce(Return(-EINVAL)); 273 EXPECT_THROW(base->get_description(), SdEventError); 274 } 275 276 TEST_F(BaseMethodTest, SetDescriptionSuccess) 277 { 278 const char* expected = "test desc"; 279 // Intentionally comparing pointers to make sure no copying is happening 280 EXPECT_CALL(mock, 281 sd_event_source_set_description(expected_source, expected)) 282 .WillOnce(Return(0)); 283 base->set_description(expected); 284 } 285 286 TEST_F(BaseMethodTest, SetDescriptionError) 287 { 288 const char* expected = "test desc"; 289 // Intentionally comparing pointers to make sure no copying is happening 290 EXPECT_CALL(mock, 291 sd_event_source_set_description(expected_source, expected)) 292 .WillOnce(Return(-EINVAL)); 293 EXPECT_THROW(base->set_description(expected), SdEventError); 294 } 295 296 TEST_F(BaseMethodTest, SetPrepareCallback) 297 { 298 bool completed = false; 299 Base::Callback callback = [&completed](Base&) { completed = true; }; 300 sd_event_handler_t event_handler; 301 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_)) 302 .WillOnce(DoAll(SaveArg<1>(&event_handler), Return(0))); 303 base->set_prepare(std::move(callback)); 304 EXPECT_TRUE(base->get_prepare()); 305 EXPECT_FALSE(callback); 306 EXPECT_FALSE(completed); 307 308 EXPECT_EQ(0, event_handler(nullptr, base.get())); 309 EXPECT_TRUE(completed); 310 } 311 312 TEST_F(BaseMethodTest, SetPrepareCallbackNoUserdata) 313 { 314 Base::Callback callback = [](Base&) {}; 315 sd_event_handler_t event_handler; 316 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_)) 317 .WillOnce(DoAll(SaveArg<1>(&event_handler), Return(0))); 318 base->set_prepare(std::move(callback)); 319 EXPECT_TRUE(base->get_prepare()); 320 EXPECT_FALSE(callback); 321 322 EXPECT_EQ(-EINVAL, event_handler(nullptr, nullptr)); 323 } 324 325 TEST_F(BaseMethodTest, SetPrepareNull) 326 { 327 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, nullptr)) 328 .WillOnce(Return(0)); 329 base->set_prepare(nullptr); 330 EXPECT_EQ(-ENOSYS, base->prepareCallback()); 331 } 332 333 TEST_F(BaseMethodTest, SetPrepareSystemError) 334 { 335 Base::Callback callback = [](Base&) { 336 throw std::system_error(EBUSY, std::generic_category()); 337 }; 338 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_)) 339 .WillOnce(Return(0)); 340 base->set_prepare(std::move(callback)); 341 EXPECT_TRUE(base->get_prepare()); 342 EXPECT_FALSE(callback); 343 EXPECT_EQ(-EBUSY, base->prepareCallback()); 344 } 345 346 TEST_F(BaseMethodTest, SetPrepareUnknownException) 347 { 348 Base::Callback callback = [](Base&) { throw static_cast<int>(1); }; 349 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_)) 350 .WillOnce(Return(0)); 351 base->set_prepare(std::move(callback)); 352 EXPECT_TRUE(base->get_prepare()); 353 EXPECT_FALSE(callback); 354 EXPECT_EQ(-ENOSYS, base->prepareCallback()); 355 } 356 357 TEST_F(BaseMethodTest, SetPrepareError) 358 { 359 Base::Callback callback = [](Base&) {}; 360 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_)) 361 .WillOnce(Return(-EINVAL)); 362 EXPECT_THROW(base->set_prepare(std::move(callback)), SdEventError); 363 EXPECT_FALSE(base->get_prepare()); 364 EXPECT_TRUE(callback); 365 EXPECT_EQ(-ENOSYS, base->prepareCallback()); 366 } 367 368 TEST_F(BaseMethodTest, GetPendingSuccess) 369 { 370 EXPECT_CALL(mock, sd_event_source_get_pending(expected_source)) 371 .WillOnce(Return(0)); 372 EXPECT_EQ(0, base->get_pending()); 373 EXPECT_CALL(mock, sd_event_source_get_pending(expected_source)) 374 .WillOnce(Return(4)); 375 EXPECT_EQ(4, base->get_pending()); 376 } 377 378 TEST_F(BaseMethodTest, GetPendingError) 379 { 380 EXPECT_CALL(mock, sd_event_source_get_pending(expected_source)) 381 .WillOnce(Return(-EINVAL)); 382 EXPECT_THROW(base->get_pending(), SdEventError); 383 } 384 385 TEST_F(BaseMethodTest, GetPrioritySuccess) 386 { 387 EXPECT_CALL(mock, sd_event_source_get_priority(expected_source, testing::_)) 388 .WillOnce(DoAll(SetArgPointee<1>(1024), Return(0))); 389 EXPECT_EQ(1024, base->get_priority()); 390 } 391 392 TEST_F(BaseMethodTest, GetPriorityError) 393 { 394 EXPECT_CALL(mock, sd_event_source_get_priority(expected_source, testing::_)) 395 .WillOnce(Return(-EINVAL)); 396 EXPECT_THROW(base->get_priority(), SdEventError); 397 } 398 399 TEST_F(BaseMethodTest, SetPrioritySuccess) 400 { 401 EXPECT_CALL(mock, sd_event_source_set_priority(expected_source, 1024)) 402 .WillOnce(Return(0)); 403 base->set_priority(1024); 404 } 405 406 TEST_F(BaseMethodTest, SetPriorityError) 407 { 408 EXPECT_CALL(mock, sd_event_source_set_priority(expected_source, 1024)) 409 .WillOnce(Return(-EINVAL)); 410 EXPECT_THROW(base->set_priority(1024), SdEventError); 411 } 412 413 TEST_F(BaseMethodTest, GetEnabledSuccess) 414 { 415 EXPECT_CALL(mock, sd_event_source_get_enabled(expected_source, testing::_)) 416 .WillOnce(DoAll(SetArgPointee<1>(SD_EVENT_ON), Return(0))); 417 EXPECT_EQ(SD_EVENT_ON, base->get_enabled()); 418 } 419 420 TEST_F(BaseMethodTest, GetEnabledError) 421 { 422 EXPECT_CALL(mock, sd_event_source_get_enabled(expected_source, testing::_)) 423 .WillOnce(Return(-EINVAL)); 424 EXPECT_THROW(base->get_enabled(), SdEventError); 425 } 426 427 TEST_F(BaseMethodTest, SetEnabledSuccess) 428 { 429 EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source, SD_EVENT_ON)) 430 .WillOnce(Return(0)); 431 base->set_enabled(SD_EVENT_ON); 432 } 433 434 TEST_F(BaseMethodTest, SetEnabledError) 435 { 436 EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source, SD_EVENT_ON)) 437 .WillOnce(Return(-EINVAL)); 438 EXPECT_THROW(base->set_enabled(SD_EVENT_ON), SdEventError); 439 } 440 441 } // namespace 442 } // namespace source 443 } // namespace sdeventplus 444