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 <system_error> 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 42 class BaseTest : public testing::Test 43 { 44 protected: 45 testing::StrictMock<test::SdEventMock> mock; 46 sd_event_source* const expected_source = 47 reinterpret_cast<sd_event_source*>(1234); 48 sd_event* const expected_event = reinterpret_cast<sd_event*>(2345); 49 UniqueEvent event = make_event(expected_event); 50 51 UniqueEvent make_event(sd_event* event) 52 { 53 auto deleter = [this, event](Event* e) { 54 EXPECT_CALL(this->mock, sd_event_unref(event)) 55 .WillOnce(Return(nullptr)); 56 delete e; 57 }; 58 return UniqueEvent(new Event(event, std::false_type(), &mock), deleter); 59 } 60 61 // Using a unique_ptr to make sure we don't get any superfluous moves or 62 // copies. 63 std::unique_ptr<BaseImpl> make_base(const Event& event, 64 sd_event_source* source) 65 { 66 EXPECT_CALL(mock, sd_event_ref(event.get())) 67 .WillOnce(Return(event.get())); 68 auto ret = std::make_unique<BaseImpl>(event, source, std::false_type()); 69 EXPECT_EQ(source, ret->get()); 70 EXPECT_NE(&event, &ret->get_event()); 71 EXPECT_EQ(event.get(), ret->get_event().get()); 72 EXPECT_FALSE(ret->get_prepare()); 73 return ret; 74 } 75 76 void set_prepare_placeholder(Base& base) 77 { 78 EXPECT_CALL(mock, sd_event_source_set_prepare(base.get(), testing::_)) 79 .WillOnce(Return(0)); 80 base.set_prepare([](Base&) {}); 81 EXPECT_TRUE(base.get_prepare()); 82 } 83 84 void empty_base(BaseImpl&& other) 85 { 86 BaseImpl mover(std::move(other)); 87 EXPECT_EQ(nullptr, other.get()); 88 EXPECT_EQ(nullptr, other.get_event().get()); 89 EXPECT_FALSE(other.get_prepare()); 90 91 expect_base_destruct(mover.get_event(), mover.get()); 92 } 93 94 void expect_base_destruct(const Event& event, sd_event_source* source) 95 { 96 { 97 testing::InSequence seq; 98 EXPECT_CALL(mock, sd_event_source_set_enabled(source, SD_EVENT_OFF)) 99 .WillOnce(Return(0)); 100 EXPECT_CALL(mock, sd_event_source_unref(source)) 101 .WillOnce(Return(nullptr)); 102 } 103 EXPECT_CALL(mock, sd_event_unref(event.get())) 104 .WillOnce(Return(nullptr)); 105 } 106 }; 107 108 TEST_F(BaseTest, NewBaseRef) 109 { 110 EXPECT_CALL(mock, sd_event_ref(expected_event)) 111 .WillOnce(Return(expected_event)); 112 EXPECT_CALL(mock, sd_event_source_ref(expected_source)) 113 .WillOnce(Return(expected_source)); 114 BaseImpl source(*event, expected_source); 115 EXPECT_EQ(expected_source, source.get()); 116 EXPECT_NE(event.get(), &source.get_event()); 117 EXPECT_EQ(expected_event, source.get_event().get()); 118 EXPECT_FALSE(source.get_prepare()); 119 120 expect_base_destruct(*event, expected_source); 121 } 122 123 TEST_F(BaseTest, NewBaseNoRef) 124 { 125 EXPECT_CALL(mock, sd_event_ref(expected_event)) 126 .WillOnce(Return(expected_event)); 127 BaseImpl source(*event, expected_source, std::false_type()); 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, MoveConstruct) 137 { 138 std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source); 139 set_prepare_placeholder(*source1); 140 141 BaseImpl source2(std::move(*source1)); 142 EXPECT_EQ(nullptr, source1->get()); 143 EXPECT_EQ(nullptr, source1->get_event().get()); 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 testing::InSequence seq; 175 *source2 = std::move(*source1); 176 } 177 EXPECT_EQ(nullptr, source1->get()); 178 EXPECT_EQ(nullptr, source1->get_event().get()); 179 EXPECT_FALSE(source1->get_prepare()); 180 EXPECT_EQ(expected_source, source2->get()); 181 EXPECT_EQ(expected_event, source2->get_event().get()); 182 EXPECT_TRUE(source2->get_prepare()); 183 184 // Make sure source1 is deleted to ensure it isn't holding a reference 185 source1.reset(); 186 expect_base_destruct(*event, expected_source); 187 } 188 189 TEST_F(BaseTest, MoveAssignExisting) 190 { 191 sd_event_source* const expected_source2 = 192 reinterpret_cast<sd_event_source*>(3456); 193 sd_event* const expected_event2 = reinterpret_cast<sd_event*>(4567); 194 195 std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source); 196 set_prepare_placeholder(*source1); 197 198 UniqueEvent event2 = make_event(expected_event2); 199 std::unique_ptr<BaseImpl> source2 = make_base(*event2, expected_source2); 200 201 { 202 expect_base_destruct(*event2, expected_source2); 203 *source2 = std::move(*source1); 204 } 205 EXPECT_EQ(nullptr, source1->get()); 206 EXPECT_EQ(nullptr, source1->get_event().get()); 207 EXPECT_FALSE(source1->get_prepare()); 208 EXPECT_EQ(expected_source, source2->get()); 209 EXPECT_EQ(expected_event, source2->get_event().get()); 210 EXPECT_TRUE(source2->get_prepare()); 211 212 // Make sure source1 is deleted to ensure it isn't holding a reference 213 source1.reset(); 214 expect_base_destruct(*event, expected_source); 215 } 216 217 class BaseMethodTest : public BaseTest 218 { 219 protected: 220 std::unique_ptr<BaseImpl> base = make_base(*event, expected_source); 221 222 void TearDown() 223 { 224 expect_base_destruct(base->get_event(), base->get()); 225 base.reset(); 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, SetPrepareNull) 297 { 298 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, nullptr)) 299 .WillOnce(Return(0)); 300 base->set_prepare(nullptr); 301 EXPECT_EQ(-ENOSYS, base->prepareCallback()); 302 } 303 304 TEST_F(BaseMethodTest, SetPrepareSystemError) 305 { 306 Base::Callback callback = [](Base&) { 307 throw std::system_error(EBUSY, std::generic_category()); 308 }; 309 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_)) 310 .WillOnce(Return(0)); 311 base->set_prepare(std::move(callback)); 312 EXPECT_TRUE(base->get_prepare()); 313 EXPECT_FALSE(callback); 314 EXPECT_EQ(-EBUSY, base->prepareCallback()); 315 } 316 317 TEST_F(BaseMethodTest, SetPrepareUnknownException) 318 { 319 Base::Callback callback = [](Base&) { throw static_cast<int>(1); }; 320 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_)) 321 .WillOnce(Return(0)); 322 base->set_prepare(std::move(callback)); 323 EXPECT_TRUE(base->get_prepare()); 324 EXPECT_FALSE(callback); 325 EXPECT_EQ(-ENOSYS, base->prepareCallback()); 326 } 327 328 TEST_F(BaseMethodTest, SetPrepareError) 329 { 330 Base::Callback callback = [](Base&) {}; 331 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_)) 332 .WillOnce(Return(-EINVAL)); 333 EXPECT_THROW(base->set_prepare(std::move(callback)), SdEventError); 334 EXPECT_FALSE(base->get_prepare()); 335 EXPECT_TRUE(callback); 336 EXPECT_EQ(-ENOSYS, base->prepareCallback()); 337 } 338 339 TEST_F(BaseMethodTest, GetPendingSuccess) 340 { 341 EXPECT_CALL(mock, sd_event_source_get_pending(expected_source)) 342 .WillOnce(Return(0)); 343 EXPECT_EQ(0, base->get_pending()); 344 EXPECT_CALL(mock, sd_event_source_get_pending(expected_source)) 345 .WillOnce(Return(4)); 346 EXPECT_EQ(4, base->get_pending()); 347 } 348 349 TEST_F(BaseMethodTest, GetPendingError) 350 { 351 EXPECT_CALL(mock, sd_event_source_get_pending(expected_source)) 352 .WillOnce(Return(-EINVAL)); 353 EXPECT_THROW(base->get_pending(), SdEventError); 354 } 355 356 TEST_F(BaseMethodTest, GetPrioritySuccess) 357 { 358 EXPECT_CALL(mock, sd_event_source_get_priority(expected_source, testing::_)) 359 .WillOnce(DoAll(SetArgPointee<1>(1024), Return(0))); 360 EXPECT_EQ(1024, base->get_priority()); 361 } 362 363 TEST_F(BaseMethodTest, GetPriorityError) 364 { 365 EXPECT_CALL(mock, sd_event_source_get_priority(expected_source, testing::_)) 366 .WillOnce(Return(-EINVAL)); 367 EXPECT_THROW(base->get_priority(), SdEventError); 368 } 369 370 TEST_F(BaseMethodTest, SetPrioritySuccess) 371 { 372 EXPECT_CALL(mock, sd_event_source_set_priority(expected_source, 1024)) 373 .WillOnce(Return(0)); 374 base->set_priority(1024); 375 } 376 377 TEST_F(BaseMethodTest, SetPriorityError) 378 { 379 EXPECT_CALL(mock, sd_event_source_set_priority(expected_source, 1024)) 380 .WillOnce(Return(-EINVAL)); 381 EXPECT_THROW(base->set_priority(1024), SdEventError); 382 } 383 384 TEST_F(BaseMethodTest, GetEnabledSuccess) 385 { 386 EXPECT_CALL(mock, sd_event_source_get_enabled(expected_source, testing::_)) 387 .WillOnce(DoAll(SetArgPointee<1>(SD_EVENT_ON), Return(0))); 388 EXPECT_EQ(SD_EVENT_ON, base->get_enabled()); 389 } 390 391 TEST_F(BaseMethodTest, GetEnabledError) 392 { 393 EXPECT_CALL(mock, sd_event_source_get_enabled(expected_source, testing::_)) 394 .WillOnce(Return(-EINVAL)); 395 EXPECT_THROW(base->get_enabled(), SdEventError); 396 } 397 398 TEST_F(BaseMethodTest, SetEnabledSuccess) 399 { 400 EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source, SD_EVENT_ON)) 401 .WillOnce(Return(0)); 402 base->set_enabled(SD_EVENT_ON); 403 } 404 405 TEST_F(BaseMethodTest, SetEnabledError) 406 { 407 EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source, SD_EVENT_ON)) 408 .WillOnce(Return(-EINVAL)); 409 EXPECT_THROW(base->set_enabled(SD_EVENT_ON), SdEventError); 410 } 411 412 } // namespace 413 } // namespace source 414 } // namespace sdeventplus 415