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