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