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