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