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