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) : 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
make_event(sd_event * event)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()>>
make_base(const Event & event,sd_event_source * source)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
set_prepare_placeholder(BaseImpl & base)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
empty_base(BaseImpl && other)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
expect_base_destruct(const Event & event,sd_event_source * source)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
TEST_F(BaseTest,NewBaseFail)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
TEST_F(BaseTest,NewBaseNoRef)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
TEST_F(BaseTest,UserdataOutlives)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
TEST_F(BaseTest,CopyCorrectness)210 TEST_F(BaseTest, CopyCorrectness)
211 {
212 std::unique_ptr<BaseImpl> base1, base2;
213 std::function<void()> destroy;
214 std::tie(base1, destroy) = make_base(*event, expected_source);
215 set_prepare_placeholder(*base1);
216 EXPECT_TRUE(base1->get_prepare());
217
218 EXPECT_CALL(mock, sd_event_ref(expected_event))
219 .WillOnce(Return(expected_event));
220 EXPECT_CALL(mock, sd_event_source_ref(expected_source))
221 .WillOnce(Return(expected_source));
222 base2 = std::make_unique<BaseImpl>(*base1);
223 EXPECT_EQ(&base1->get_prepare(), &base2->get_prepare());
224
225 empty_base(std::move(*base1));
226 EXPECT_THROW(base1->get_prepare(), std::bad_optional_access);
227 EXPECT_CALL(mock, sd_event_ref(expected_event))
228 .WillOnce(Return(expected_event));
229 EXPECT_CALL(mock, sd_event_source_ref(expected_source))
230 .WillOnce(Return(expected_source));
231 *base1 = *base2;
232 EXPECT_EQ(&base1->get_prepare(), &base2->get_prepare());
233
234 expect_base_destruct(*event, expected_source);
235 base2.reset();
236 expect_base_destruct(*event, expected_source);
237 base1.reset();
238 destroy();
239 }
240
241 class BaseMethodTest : public BaseTest
242 {
243 protected:
244 std::unique_ptr<BaseImpl> base;
245 std::function<void()> destroy;
246
SetUp()247 void SetUp()
248 {
249 std::tie(base, destroy) = make_base(*event, expected_source);
250 }
251
TearDown()252 void TearDown()
253 {
254 expect_base_destruct(base->get_event(), base->get());
255 base.reset();
256 destroy();
257 }
258 };
259
TEST_F(BaseMethodTest,GetDescriptionSuccess)260 TEST_F(BaseMethodTest, GetDescriptionSuccess)
261 {
262 const char* expected = "test_desc";
263 EXPECT_CALL(mock,
264 sd_event_source_get_description(expected_source, testing::_))
265 .WillOnce(DoAll(SetArgPointee<1>(expected), Return(0)));
266 // Intentionally comparing pointers to make sure no copying is happening
267 EXPECT_EQ(expected, base->get_description());
268 }
269
TEST_F(BaseMethodTest,GetDescriptionError)270 TEST_F(BaseMethodTest, GetDescriptionError)
271 {
272 EXPECT_CALL(mock,
273 sd_event_source_get_description(expected_source, testing::_))
274 .WillOnce(Return(-EINVAL));
275 EXPECT_THROW(base->get_description(), SdEventError);
276 }
277
TEST_F(BaseMethodTest,SetDescriptionSuccess)278 TEST_F(BaseMethodTest, SetDescriptionSuccess)
279 {
280 const char* expected = "test desc";
281 // Intentionally comparing pointers to make sure no copying is happening
282 EXPECT_CALL(mock,
283 sd_event_source_set_description(expected_source, expected))
284 .WillOnce(Return(0));
285 base->set_description(expected);
286 }
287
TEST_F(BaseMethodTest,SetDescriptionError)288 TEST_F(BaseMethodTest, SetDescriptionError)
289 {
290 const char* expected = "test desc";
291 // Intentionally comparing pointers to make sure no copying is happening
292 EXPECT_CALL(mock,
293 sd_event_source_set_description(expected_source, expected))
294 .WillOnce(Return(-EINVAL));
295 EXPECT_THROW(base->set_description(expected), SdEventError);
296 }
297
TEST_F(BaseMethodTest,SetPrepareCallback)298 TEST_F(BaseMethodTest, SetPrepareCallback)
299 {
300 bool completed = false;
301 Base::Callback callback = [&completed](Base&) { completed = true; };
302 sd_event_handler_t event_handler;
303 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
304 .WillOnce(DoAll(SaveArg<1>(&event_handler), Return(0)));
305 base->set_prepare(std::move(callback));
306 EXPECT_TRUE(base->get_prepare());
307 EXPECT_FALSE(callback);
308 EXPECT_FALSE(completed);
309
310 EXPECT_EQ(0, event_handler(nullptr, base.get()));
311 EXPECT_TRUE(completed);
312 }
313
TEST_F(BaseMethodTest,SetPrepareCallbackNoUserdata)314 TEST_F(BaseMethodTest, SetPrepareCallbackNoUserdata)
315 {
316 Base::Callback callback = [](Base&) {};
317 sd_event_handler_t event_handler;
318 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
319 .WillOnce(DoAll(SaveArg<1>(&event_handler), Return(0)));
320 base->set_prepare(std::move(callback));
321 EXPECT_TRUE(base->get_prepare());
322 EXPECT_FALSE(callback);
323
324 EXPECT_EQ(-EINVAL, event_handler(nullptr, nullptr));
325 }
326
TEST_F(BaseMethodTest,SetPrepareError)327 TEST_F(BaseMethodTest, SetPrepareError)
328 {
329 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
330 .WillOnce(Return(0));
331 base->set_prepare([](Base&) {});
332 EXPECT_TRUE(base->get_prepare());
333
334 Base::Callback callback = [](Base&) {};
335 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
336 .WillOnce(Return(-EINVAL));
337 EXPECT_THROW(base->set_prepare(std::move(callback)), SdEventError);
338 EXPECT_FALSE(base->get_prepare());
339 EXPECT_TRUE(callback);
340 }
341
TEST_F(BaseMethodTest,SetPrepareNull)342 TEST_F(BaseMethodTest, SetPrepareNull)
343 {
344 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
345 .WillOnce(Return(0));
346 base->set_prepare([](Base&) {});
347 EXPECT_TRUE(base->get_prepare());
348
349 EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, nullptr))
350 .WillOnce(Return(0));
351 base->set_prepare(nullptr);
352 EXPECT_FALSE(base->get_prepare());
353 }
354
TEST_F(BaseMethodTest,GetPendingSuccess)355 TEST_F(BaseMethodTest, GetPendingSuccess)
356 {
357 EXPECT_CALL(mock, sd_event_source_get_pending(expected_source))
358 .WillOnce(Return(0));
359 EXPECT_FALSE(base->get_pending());
360 EXPECT_CALL(mock, sd_event_source_get_pending(expected_source))
361 .WillOnce(Return(4));
362 EXPECT_TRUE(base->get_pending());
363 }
364
TEST_F(BaseMethodTest,GetPendingError)365 TEST_F(BaseMethodTest, GetPendingError)
366 {
367 EXPECT_CALL(mock, sd_event_source_get_pending(expected_source))
368 .WillOnce(Return(-EINVAL));
369 EXPECT_THROW(base->get_pending(), SdEventError);
370 }
371
TEST_F(BaseMethodTest,GetPrioritySuccess)372 TEST_F(BaseMethodTest, GetPrioritySuccess)
373 {
374 EXPECT_CALL(mock, sd_event_source_get_priority(expected_source, testing::_))
375 .WillOnce(DoAll(SetArgPointee<1>(1024), Return(0)));
376 EXPECT_EQ(1024, base->get_priority());
377 }
378
TEST_F(BaseMethodTest,GetPriorityError)379 TEST_F(BaseMethodTest, GetPriorityError)
380 {
381 EXPECT_CALL(mock, sd_event_source_get_priority(expected_source, testing::_))
382 .WillOnce(Return(-EINVAL));
383 EXPECT_THROW(base->get_priority(), SdEventError);
384 }
385
TEST_F(BaseMethodTest,SetPrioritySuccess)386 TEST_F(BaseMethodTest, SetPrioritySuccess)
387 {
388 EXPECT_CALL(mock, sd_event_source_set_priority(expected_source, 1024))
389 .WillOnce(Return(0));
390 base->set_priority(1024);
391 }
392
TEST_F(BaseMethodTest,SetPriorityError)393 TEST_F(BaseMethodTest, SetPriorityError)
394 {
395 EXPECT_CALL(mock, sd_event_source_set_priority(expected_source, 1024))
396 .WillOnce(Return(-EINVAL));
397 EXPECT_THROW(base->set_priority(1024), SdEventError);
398 }
399
TEST_F(BaseMethodTest,GetEnabledSuccess)400 TEST_F(BaseMethodTest, GetEnabledSuccess)
401 {
402 EXPECT_CALL(mock, sd_event_source_get_enabled(expected_source, testing::_))
403 .WillOnce(DoAll(SetArgPointee<1>(SD_EVENT_ON), Return(0)));
404 EXPECT_EQ(Enabled::On, base->get_enabled());
405 }
406
TEST_F(BaseMethodTest,GetEnabledError)407 TEST_F(BaseMethodTest, GetEnabledError)
408 {
409 EXPECT_CALL(mock, sd_event_source_get_enabled(expected_source, testing::_))
410 .WillOnce(Return(-EINVAL));
411 EXPECT_THROW(base->get_enabled(), SdEventError);
412 }
413
TEST_F(BaseMethodTest,SetEnabledSuccess)414 TEST_F(BaseMethodTest, SetEnabledSuccess)
415 {
416 EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source, SD_EVENT_ON))
417 .WillOnce(Return(0));
418 base->set_enabled(Enabled::On);
419 }
420
TEST_F(BaseMethodTest,SetEnabledError)421 TEST_F(BaseMethodTest, SetEnabledError)
422 {
423 EXPECT_CALL(mock,
424 sd_event_source_set_enabled(expected_source, SD_EVENT_ONESHOT))
425 .WillOnce(Return(-EINVAL));
426 EXPECT_THROW(base->set_enabled(Enabled::OneShot), SdEventError);
427 }
428
TEST_F(BaseMethodTest,GetFloatingSuccess)429 TEST_F(BaseMethodTest, GetFloatingSuccess)
430 {
431 EXPECT_CALL(mock, sd_event_source_get_floating(expected_source))
432 .WillOnce(Return(2));
433 EXPECT_TRUE(base->get_floating());
434 EXPECT_CALL(mock, sd_event_source_get_floating(expected_source))
435 .WillOnce(Return(0));
436 EXPECT_FALSE(base->get_floating());
437 }
438
TEST_F(BaseMethodTest,GetFloatingError)439 TEST_F(BaseMethodTest, GetFloatingError)
440 {
441 EXPECT_CALL(mock, sd_event_source_get_floating(expected_source))
442 .WillOnce(Return(-EINVAL));
443 EXPECT_THROW(base->get_floating(), SdEventError);
444 }
445
TEST_F(BaseMethodTest,SetFloatingSuccess)446 TEST_F(BaseMethodTest, SetFloatingSuccess)
447 {
448 EXPECT_CALL(mock, sd_event_source_set_floating(expected_source, 1))
449 .WillOnce(Return(0));
450 base->set_floating(true);
451 }
452
TEST_F(BaseMethodTest,SetFloatingError)453 TEST_F(BaseMethodTest, SetFloatingError)
454 {
455 EXPECT_CALL(mock, sd_event_source_set_floating(expected_source, 1))
456 .WillOnce(Return(-EINVAL));
457 EXPECT_THROW(base->set_floating(true), SdEventError);
458 }
459
460 } // namespace
461 } // namespace source
462 } // namespace sdeventplus
463