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 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 class BaseImpl : public Base 28 { 29 public: 30 BaseImpl(const Event& event, sd_event_source* source) : Base(event, source) 31 { 32 } 33 BaseImpl(const Event& event, sd_event_source* source, std::false_type) : 34 Base(event, source, std::false_type()) 35 { 36 } 37 }; 38 39 class BaseTest : public testing::Test 40 { 41 protected: 42 testing::StrictMock<test::SdEventMock> mock; 43 sd_event_source* expected_source = reinterpret_cast<sd_event_source*>(1234); 44 sd_event* expected_event = reinterpret_cast<sd_event*>(2345); 45 std::unique_ptr<Event> event; 46 47 virtual void SetUp() 48 { 49 event = 50 std::make_unique<Event>(expected_event, std::false_type(), &mock); 51 } 52 virtual void TearDown() 53 { 54 EXPECT_CALL(mock, sd_event_unref(expected_event)) 55 .WillOnce(Return(nullptr)); 56 event.reset(); 57 } 58 }; 59 60 TEST_F(BaseTest, NewBaseRef) 61 { 62 EXPECT_CALL(mock, sd_event_ref(expected_event)) 63 .WillOnce(Return(expected_event)); 64 EXPECT_CALL(mock, sd_event_source_ref(expected_source)) 65 .WillOnce(Return(expected_source)); 66 BaseImpl source(*event, expected_source); 67 EXPECT_EQ(expected_source, source.get()); 68 EXPECT_NE(event.get(), &source.get_event()); 69 EXPECT_EQ(expected_event, source.get_event().get()); 70 EXPECT_FALSE(source.get_prepare()); 71 72 { 73 testing::InSequence seq; 74 EXPECT_CALL(mock, 75 sd_event_source_set_enabled(expected_source, SD_EVENT_OFF)) 76 .WillOnce(Return(0)); 77 EXPECT_CALL(mock, sd_event_source_unref(expected_source)) 78 .WillOnce(Return(nullptr)); 79 } 80 EXPECT_CALL(mock, sd_event_unref(expected_event)).WillOnce(Return(nullptr)); 81 } 82 83 TEST_F(BaseTest, NewBaseNoRef) 84 { 85 EXPECT_CALL(mock, sd_event_ref(expected_event)) 86 .WillOnce(Return(expected_event)); 87 BaseImpl source(*event, expected_source, std::false_type()); 88 EXPECT_EQ(expected_source, source.get()); 89 EXPECT_NE(event.get(), &source.get_event()); 90 EXPECT_EQ(expected_event, source.get_event().get()); 91 EXPECT_FALSE(source.get_prepare()); 92 93 { 94 testing::InSequence seq; 95 EXPECT_CALL(mock, 96 sd_event_source_set_enabled(expected_source, SD_EVENT_OFF)) 97 .WillOnce(Return(0)); 98 EXPECT_CALL(mock, sd_event_source_unref(expected_source)) 99 .WillOnce(Return(nullptr)); 100 } 101 EXPECT_CALL(mock, sd_event_unref(expected_event)).WillOnce(Return(nullptr)); 102 } 103 104 TEST_F(BaseTest, NoSource) 105 { 106 EXPECT_CALL(mock, sd_event_ref(expected_event)) 107 .WillOnce(Return(expected_event)); 108 BaseImpl source(*event, nullptr, std::false_type()); 109 EXPECT_EQ(nullptr, source.get()); 110 EXPECT_NE(event.get(), &source.get_event()); 111 EXPECT_EQ(expected_event, source.get_event().get()); 112 EXPECT_FALSE(source.get_prepare()); 113 114 EXPECT_CALL(mock, sd_event_source_unref(nullptr)).WillOnce(Return(nullptr)); 115 EXPECT_CALL(mock, sd_event_unref(expected_event)).WillOnce(Return(nullptr)); 116 } 117 118 class BaseMethodTest : public BaseTest 119 { 120 protected: 121 std::unique_ptr<BaseImpl> base; 122 123 void SetUp() override 124 { 125 BaseTest::SetUp(); 126 EXPECT_CALL(mock, sd_event_ref(expected_event)) 127 .WillOnce(Return(expected_event)); 128 base = std::make_unique<BaseImpl>(*event, expected_source, 129 std::false_type()); 130 } 131 132 void TearDown() override 133 { 134 { 135 testing::InSequence seq; 136 EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source, 137 SD_EVENT_OFF)) 138 .WillOnce(Return(0)); 139 EXPECT_CALL(mock, sd_event_source_unref(expected_source)) 140 .WillOnce(Return(nullptr)); 141 } 142 EXPECT_CALL(mock, sd_event_unref(expected_event)) 143 .WillOnce(Return(nullptr)); 144 base.reset(); 145 BaseTest::TearDown(); 146 } 147 }; 148 149 TEST_F(BaseMethodTest, GetDescriptionSuccess) 150 { 151 const char* expected = "test_desc"; 152 EXPECT_CALL(mock, 153 sd_event_source_get_description(expected_source, testing::_)) 154 .WillOnce(DoAll(SetArgPointee<1>(expected), Return(0))); 155 // Intentionally comparing pointers to make sure no copying is happening 156 EXPECT_EQ(expected, base->get_description()); 157 } 158 159 TEST_F(BaseMethodTest, GetDescriptionError) 160 { 161 EXPECT_CALL(mock, 162 sd_event_source_get_description(expected_source, testing::_)) 163 .WillOnce(Return(-EINVAL)); 164 EXPECT_THROW(base->get_description(), SdEventError); 165 } 166 167 TEST_F(BaseMethodTest, SetDescriptionSuccess) 168 { 169 const char* expected = "test desc"; 170 // Intentionally comparing pointers to make sure no copying is happening 171 EXPECT_CALL(mock, 172 sd_event_source_set_description(expected_source, expected)) 173 .WillOnce(Return(0)); 174 base->set_description(expected); 175 } 176 177 TEST_F(BaseMethodTest, SetDescriptionError) 178 { 179 const char* expected = "test desc"; 180 // Intentionally comparing pointers to make sure no copying is happening 181 EXPECT_CALL(mock, 182 sd_event_source_set_description(expected_source, expected)) 183 .WillOnce(Return(-EINVAL)); 184 EXPECT_THROW(base->set_description(expected), SdEventError); 185 } 186 187 TEST_F(BaseMethodTest, SetPrepareCallback) 188 { 189 bool completed = false; 190 Base::Callback callback = [&completed](Base&) { completed = true; }; 191 sd_event_handler_t event_handler; 192 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_)) 193 .WillOnce(DoAll(SaveArg<1>(&event_handler), Return(0))); 194 base->set_prepare(std::move(callback)); 195 EXPECT_TRUE(base->get_prepare()); 196 EXPECT_FALSE(callback); 197 EXPECT_FALSE(completed); 198 199 EXPECT_EQ(0, event_handler(nullptr, base.get())); 200 EXPECT_TRUE(completed); 201 } 202 203 TEST_F(BaseMethodTest, SetPrepareCallbackNoUserdata) 204 { 205 Base::Callback callback = [](Base&) {}; 206 sd_event_handler_t event_handler; 207 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_)) 208 .WillOnce(DoAll(SaveArg<1>(&event_handler), Return(0))); 209 base->set_prepare(std::move(callback)); 210 EXPECT_TRUE(base->get_prepare()); 211 EXPECT_FALSE(callback); 212 213 EXPECT_EQ(-EINVAL, event_handler(nullptr, nullptr)); 214 } 215 216 TEST_F(BaseMethodTest, SetPrepareNull) 217 { 218 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, nullptr)) 219 .WillOnce(Return(0)); 220 base->set_prepare(nullptr); 221 EXPECT_EQ(-ENOSYS, base->prepareCallback()); 222 } 223 224 TEST_F(BaseMethodTest, SetPrepareSystemError) 225 { 226 Base::Callback callback = [](Base&) { 227 throw std::system_error(EBUSY, std::generic_category()); 228 }; 229 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_)) 230 .WillOnce(Return(0)); 231 base->set_prepare(std::move(callback)); 232 EXPECT_TRUE(base->get_prepare()); 233 EXPECT_FALSE(callback); 234 EXPECT_EQ(-EBUSY, base->prepareCallback()); 235 } 236 237 TEST_F(BaseMethodTest, SetPrepareUnknownException) 238 { 239 Base::Callback callback = [](Base&) { throw static_cast<int>(1); }; 240 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_)) 241 .WillOnce(Return(0)); 242 base->set_prepare(std::move(callback)); 243 EXPECT_TRUE(base->get_prepare()); 244 EXPECT_FALSE(callback); 245 EXPECT_EQ(-ENOSYS, base->prepareCallback()); 246 } 247 248 TEST_F(BaseMethodTest, SetPrepareError) 249 { 250 Base::Callback callback = [](Base&) {}; 251 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_)) 252 .WillOnce(Return(-EINVAL)); 253 EXPECT_THROW(base->set_prepare(std::move(callback)), SdEventError); 254 EXPECT_FALSE(base->get_prepare()); 255 EXPECT_TRUE(callback); 256 EXPECT_EQ(-ENOSYS, base->prepareCallback()); 257 } 258 259 TEST_F(BaseMethodTest, GetPendingSuccess) 260 { 261 EXPECT_CALL(mock, sd_event_source_get_pending(expected_source)) 262 .WillOnce(Return(0)); 263 EXPECT_EQ(0, base->get_pending()); 264 EXPECT_CALL(mock, sd_event_source_get_pending(expected_source)) 265 .WillOnce(Return(4)); 266 EXPECT_EQ(4, base->get_pending()); 267 } 268 269 TEST_F(BaseMethodTest, GetPendingError) 270 { 271 EXPECT_CALL(mock, sd_event_source_get_pending(expected_source)) 272 .WillOnce(Return(-EINVAL)); 273 EXPECT_THROW(base->get_pending(), SdEventError); 274 } 275 276 TEST_F(BaseMethodTest, GetPrioritySuccess) 277 { 278 EXPECT_CALL(mock, sd_event_source_get_priority(expected_source, testing::_)) 279 .WillOnce(DoAll(SetArgPointee<1>(1024), Return(0))); 280 EXPECT_EQ(1024, base->get_priority()); 281 } 282 283 TEST_F(BaseMethodTest, GetPriorityError) 284 { 285 EXPECT_CALL(mock, sd_event_source_get_priority(expected_source, testing::_)) 286 .WillOnce(Return(-EINVAL)); 287 EXPECT_THROW(base->get_priority(), SdEventError); 288 } 289 290 TEST_F(BaseMethodTest, SetPrioritySuccess) 291 { 292 EXPECT_CALL(mock, sd_event_source_set_priority(expected_source, 1024)) 293 .WillOnce(Return(0)); 294 base->set_priority(1024); 295 } 296 297 TEST_F(BaseMethodTest, SetPriorityError) 298 { 299 EXPECT_CALL(mock, sd_event_source_set_priority(expected_source, 1024)) 300 .WillOnce(Return(-EINVAL)); 301 EXPECT_THROW(base->set_priority(1024), SdEventError); 302 } 303 304 TEST_F(BaseMethodTest, GetEnabledSuccess) 305 { 306 EXPECT_CALL(mock, sd_event_source_get_enabled(expected_source, testing::_)) 307 .WillOnce(DoAll(SetArgPointee<1>(SD_EVENT_ON), Return(0))); 308 EXPECT_EQ(SD_EVENT_ON, base->get_enabled()); 309 } 310 311 TEST_F(BaseMethodTest, GetEnabledError) 312 { 313 EXPECT_CALL(mock, sd_event_source_get_enabled(expected_source, testing::_)) 314 .WillOnce(Return(-EINVAL)); 315 EXPECT_THROW(base->get_enabled(), SdEventError); 316 } 317 318 TEST_F(BaseMethodTest, SetEnabledSuccess) 319 { 320 EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source, SD_EVENT_ON)) 321 .WillOnce(Return(0)); 322 base->set_enabled(SD_EVENT_ON); 323 } 324 325 TEST_F(BaseMethodTest, SetEnabledError) 326 { 327 EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source, SD_EVENT_ON)) 328 .WillOnce(Return(-EINVAL)); 329 EXPECT_THROW(base->set_enabled(SD_EVENT_ON), SdEventError); 330 } 331 332 } // namespace 333 } // namespace source 334 } // namespace sdeventplus 335