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