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