1 #include <systemd/sd-bus-protocol.h>
2
3 #include <sdbusplus/exception.hpp>
4 #include <sdbusplus/message.hpp>
5 #include <sdbusplus/test/sdbus_mock.hpp>
6
7 #include <cerrno>
8 #include <map>
9 #include <set>
10 #include <string>
11 #include <tuple>
12 #include <unordered_map>
13 #include <unordered_set>
14 #include <variant>
15 #include <vector>
16
17 #include <gmock/gmock.h>
18 #include <gtest/gtest.h>
19
20 namespace
21 {
22
23 using testing::DoAll;
24 using testing::ElementsAre;
25 using testing::Invoke;
26 using testing::Return;
27 using testing::StrEq;
28
ACTION_TEMPLATE(AssignReadVal,HAS_1_TEMPLATE_PARAMS (typename,T),AND_1_VALUE_PARAMS (val))29 ACTION_TEMPLATE(AssignReadVal, HAS_1_TEMPLATE_PARAMS(typename, T),
30 AND_1_VALUE_PARAMS(val))
31 {
32 *static_cast<T*>(arg2) = val;
33 }
34
35 class ReadTest : public testing::Test
36 {
37 protected:
38 testing::StrictMock<sdbusplus::SdBusMock> mock;
39
SetUp()40 void SetUp() override
41 {
42 EXPECT_CALL(mock, sd_bus_message_new_method_call(testing::_, testing::_,
43 nullptr, nullptr,
44 nullptr, nullptr))
45 .WillRepeatedly(Return(0));
46 }
47
new_message()48 sdbusplus::message_t new_message()
49 {
50 return sdbusplus::get_mocked_new(&mock).new_method_call(
51 nullptr, nullptr, nullptr, nullptr);
52 }
53
expect_basic_error(char type,int ret)54 void expect_basic_error(char type, int ret)
55 {
56 EXPECT_CALL(mock, sd_bus_message_read_basic(nullptr, type, testing::_))
57 .WillOnce(Return(ret));
58 }
59
60 template <typename T>
expect_basic(char type,T val)61 void expect_basic(char type, T val)
62 {
63 EXPECT_CALL(mock, sd_bus_message_read_basic(nullptr, type, testing::_))
64 .WillOnce(DoAll(AssignReadVal<T>(val), Return(0)));
65 }
66
67 template <typename T>
read_array_callback(sd_bus_message *,char,const void ** p,size_t * sz)68 static void read_array_callback(sd_bus_message*, char, const void** p,
69 size_t* sz)
70 {
71 static const std::array<T, 3> arr{std::numeric_limits<T>::min(), 0,
72 std::numeric_limits<T>::max()};
73
74 *p = arr.data();
75 *sz = arr.size() * sizeof(T);
76 }
77
78 template <typename T>
expect_read_array(char type)79 void expect_read_array(char type)
80 {
81 EXPECT_CALL(mock, sd_bus_message_read_array(nullptr, type, testing::_,
82 testing::_))
83 .WillOnce(
84 DoAll(testing::Invoke(read_array_callback<T>), Return(0)));
85 }
86
expect_verify_type(char type,const char * contents,int ret)87 void expect_verify_type(char type, const char* contents, int ret)
88 {
89 EXPECT_CALL(mock,
90 sd_bus_message_verify_type(nullptr, type, StrEq(contents)))
91 .WillOnce(Return(ret));
92 }
93
expect_at_end(bool complete,int ret)94 void expect_at_end(bool complete, int ret)
95 {
96 EXPECT_CALL(mock, sd_bus_message_at_end(nullptr, complete))
97 .WillOnce(Return(ret));
98 }
99
expect_skip(const char * contents,int ret=0)100 void expect_skip(const char* contents, int ret = 0)
101 {
102 EXPECT_CALL(mock, sd_bus_message_skip(nullptr, StrEq(contents)))
103 .WillOnce(Return(ret));
104 }
105
expect_enter_container(char type,const char * contents,int ret=0)106 void expect_enter_container(char type, const char* contents, int ret = 0)
107 {
108 EXPECT_CALL(mock, sd_bus_message_enter_container(nullptr, type,
109 StrEq(contents)))
110 .WillOnce(Return(ret));
111 }
112
expect_exit_container(int ret=0)113 void expect_exit_container(int ret = 0)
114 {
115 EXPECT_CALL(mock, sd_bus_message_exit_container(nullptr))
116 .WillOnce(Return(ret));
117 }
118 };
119
TEST_F(ReadTest,Int)120 TEST_F(ReadTest, Int)
121 {
122 const int i = 1;
123 expect_basic<int>(SD_BUS_TYPE_INT32, i);
124 int ret;
125 new_message().read(ret);
126 EXPECT_EQ(i, ret);
127 }
128
TEST_F(ReadTest,Bool)129 TEST_F(ReadTest, Bool)
130 {
131 const bool b = true;
132 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, b);
133 bool ret;
134 new_message().read(ret);
135 EXPECT_EQ(b, ret);
136 }
137
TEST_F(ReadTest,Double)138 TEST_F(ReadTest, Double)
139 {
140 const double d = 1.1;
141 expect_basic<double>(SD_BUS_TYPE_DOUBLE, d);
142 double ret;
143 new_message().read(ret);
144 EXPECT_EQ(d, ret);
145 }
146
TEST_F(ReadTest,CString)147 TEST_F(ReadTest, CString)
148 {
149 const char* const s = "asdf";
150 expect_basic<const char*>(SD_BUS_TYPE_STRING, s);
151 const char* ret;
152 new_message().read(ret);
153 EXPECT_EQ(s, ret);
154 }
155
TEST_F(ReadTest,String)156 TEST_F(ReadTest, String)
157 {
158 const char* const s = "fsda";
159 expect_basic<const char*>(SD_BUS_TYPE_STRING, s);
160 std::string ret;
161 new_message().read(ret);
162 // Pointer comparison here is intentional as we don't expect a copy
163 EXPECT_EQ(s, ret);
164 }
165
TEST_F(ReadTest,ObjectPath)166 TEST_F(ReadTest, ObjectPath)
167 {
168 const char* const s = "/fsda";
169 expect_basic<const char*>(SD_BUS_TYPE_OBJECT_PATH, s);
170 sdbusplus::message::object_path ret;
171 new_message().read(ret);
172 EXPECT_EQ(s, ret.str);
173 }
174
TEST_F(ReadTest,Signature)175 TEST_F(ReadTest, Signature)
176 {
177 const char* const s = "{ii}";
178 expect_basic<const char*>(SD_BUS_TYPE_SIGNATURE, s);
179 sdbusplus::message::signature ret;
180 new_message().read(ret);
181 EXPECT_EQ(s, ret.str);
182 }
183
TEST_F(ReadTest,UnixFd)184 TEST_F(ReadTest, UnixFd)
185 {
186 const int fd = 42;
187 expect_basic<int>(SD_BUS_TYPE_UNIX_FD, fd);
188 sdbusplus::message::unix_fd ret;
189 new_message().read(ret);
190 EXPECT_EQ(fd, ret);
191 }
192
TEST_F(ReadTest,CombinedBasic)193 TEST_F(ReadTest, CombinedBasic)
194 {
195 const double a = 2.2;
196 const char* const b = "ijkd";
197 const bool c = false;
198 const int d = 18;
199
200 {
201 testing::InSequence seq;
202 expect_basic<double>(SD_BUS_TYPE_DOUBLE, a);
203 expect_basic<const char*>(SD_BUS_TYPE_STRING, b);
204 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, c);
205 expect_basic<int>(SD_BUS_TYPE_INT32, d);
206 }
207
208 double ret_a;
209 const char* ret_b;
210 bool ret_c;
211 int ret_d;
212 new_message().read(ret_a, ret_b, ret_c, ret_d);
213 EXPECT_EQ(a, ret_a);
214 EXPECT_EQ(b, ret_b);
215 EXPECT_EQ(c, ret_c);
216 EXPECT_EQ(d, ret_d);
217 }
218
TEST_F(ReadTest,BasicError)219 TEST_F(ReadTest, BasicError)
220 {
221 expect_basic_error(SD_BUS_TYPE_INT32, -EINVAL);
222 int ret;
223 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
224 }
225
TEST_F(ReadTest,BasicStringError)226 TEST_F(ReadTest, BasicStringError)
227 {
228 expect_basic_error(SD_BUS_TYPE_STRING, -EINVAL);
229 std::string ret;
230 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
231 }
232
TEST_F(ReadTest,BasicStringWrapperError)233 TEST_F(ReadTest, BasicStringWrapperError)
234 {
235 expect_basic_error(SD_BUS_TYPE_SIGNATURE, -EINVAL);
236 sdbusplus::message::signature ret;
237 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
238 }
239
TEST_F(ReadTest,BasicBoolError)240 TEST_F(ReadTest, BasicBoolError)
241 {
242 expect_basic_error(SD_BUS_TYPE_BOOLEAN, -EINVAL);
243 bool ret;
244 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
245 }
246
TEST_F(ReadTest,Vector)247 TEST_F(ReadTest, Vector)
248 {
249 const std::vector<std::string> vs{"1", "2", "3", "4"};
250
251 {
252 testing::InSequence seq;
253 expect_enter_container(SD_BUS_TYPE_ARRAY, "s");
254 for (const auto& i : vs)
255 {
256 expect_at_end(false, 0);
257 expect_basic<const char*>(SD_BUS_TYPE_STRING, i.c_str());
258 }
259 expect_at_end(false, 1);
260 expect_exit_container();
261 }
262
263 std::vector<std::string> ret_vs;
264 new_message().read(ret_vs);
265 EXPECT_EQ(vs, ret_vs);
266 }
267
TEST_F(ReadTest,VectorUnsignedIntegral8)268 TEST_F(ReadTest, VectorUnsignedIntegral8)
269 {
270 expect_read_array<uint8_t>(SD_BUS_TYPE_BYTE);
271 std::vector<uint8_t> ret_vi;
272 new_message().read(ret_vi);
273 EXPECT_THAT(ret_vi, ElementsAre(0, 0, 255));
274 }
275
TEST_F(ReadTest,VectorIntegral32)276 TEST_F(ReadTest, VectorIntegral32)
277 {
278 expect_read_array<int32_t>(SD_BUS_TYPE_INT32);
279 std::vector<int32_t> ret_vi;
280 new_message().read(ret_vi);
281 EXPECT_THAT(ret_vi, ElementsAre(-2147483648, 0, 2147483647));
282 }
283
TEST_F(ReadTest,VectorIntegral64)284 TEST_F(ReadTest, VectorIntegral64)
285 {
286 expect_read_array<int64_t>(SD_BUS_TYPE_INT64);
287 std::vector<int64_t> ret_vi;
288 new_message().read(ret_vi);
289 EXPECT_THAT(ret_vi, ElementsAre(-9223372036854775807LL - 1, 0,
290 9223372036854775807LL));
291 }
292
TEST_F(ReadTest,VectorUnsignedIntegral32)293 TEST_F(ReadTest, VectorUnsignedIntegral32)
294 {
295 expect_read_array<uint32_t>(SD_BUS_TYPE_UINT32);
296 std::vector<uint32_t> ret_vi;
297 new_message().read(ret_vi);
298 EXPECT_THAT(ret_vi, ElementsAre(0, 0, 4294967295));
299 }
300
TEST_F(ReadTest,VectorUnsignedIntegral64)301 TEST_F(ReadTest, VectorUnsignedIntegral64)
302 {
303 expect_read_array<uint64_t>(SD_BUS_TYPE_UINT64);
304 std::vector<uint64_t> ret_vi;
305 new_message().read(ret_vi);
306 EXPECT_THAT(ret_vi, ElementsAre(0, 0, 18446744073709551615ULL));
307 }
308
TEST_F(ReadTest,VectorDouble)309 TEST_F(ReadTest, VectorDouble)
310 {
311 expect_read_array<double>(SD_BUS_TYPE_DOUBLE);
312 std::vector<double> ret_vi;
313 new_message().read(ret_vi);
314 EXPECT_THAT(ret_vi, ElementsAre(2.2250738585072014e-308, 0,
315 1.7976931348623157e+308));
316 }
317
TEST_F(ReadTest,VectorEnterError)318 TEST_F(ReadTest, VectorEnterError)
319 {
320 {
321 testing::InSequence seq;
322 expect_enter_container(SD_BUS_TYPE_ARRAY, "s", -EINVAL);
323 }
324
325 std::vector<std::string> ret;
326 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
327 }
328
TEST_F(ReadTest,VectorIterError)329 TEST_F(ReadTest, VectorIterError)
330 {
331 {
332 testing::InSequence seq;
333 expect_enter_container(SD_BUS_TYPE_ARRAY, "s");
334 expect_at_end(false, 0);
335 expect_basic<const char*>(SD_BUS_TYPE_STRING, "1");
336 expect_at_end(false, -EINVAL);
337 }
338
339 std::vector<std::string> ret;
340 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
341 }
342
TEST_F(ReadTest,VectorExitError)343 TEST_F(ReadTest, VectorExitError)
344 {
345 {
346 testing::InSequence seq;
347 expect_enter_container(SD_BUS_TYPE_ARRAY, "s");
348 expect_at_end(false, 0);
349 expect_basic<const char*>(SD_BUS_TYPE_STRING, "1");
350 expect_at_end(false, 0);
351 expect_basic<const char*>(SD_BUS_TYPE_STRING, "2");
352 expect_at_end(false, 1);
353 expect_exit_container(-EINVAL);
354 }
355
356 std::vector<std::string> ret;
357 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
358 }
359
TEST_F(ReadTest,Set)360 TEST_F(ReadTest, Set)
361 {
362 const std::set<std::string> ss{"one", "two", "eight"};
363
364 {
365 testing::InSequence seq;
366 expect_enter_container(SD_BUS_TYPE_ARRAY, "s");
367 for (const auto& s : ss)
368 {
369 expect_at_end(false, 0);
370 expect_basic<const char*>(SD_BUS_TYPE_STRING, s.c_str());
371 }
372 expect_at_end(false, 1);
373 expect_exit_container();
374 }
375
376 std::set<std::string> ret_ss;
377 new_message().read(ret_ss);
378 EXPECT_EQ(ss, ret_ss);
379 }
380
TEST_F(ReadTest,UnorderedSet)381 TEST_F(ReadTest, UnorderedSet)
382 {
383 const std::unordered_set<std::string> ss{"one", "two", "eight"};
384
385 {
386 testing::InSequence seq;
387 expect_enter_container(SD_BUS_TYPE_ARRAY, "s");
388 for (const auto& s : ss)
389 {
390 expect_at_end(false, 0);
391 expect_basic<const char*>(SD_BUS_TYPE_STRING, s.c_str());
392 }
393 expect_at_end(false, 1);
394 expect_exit_container();
395 }
396
397 std::unordered_set<std::string> ret_ss;
398 new_message().read(ret_ss);
399 EXPECT_EQ(ss, ret_ss);
400 }
401
TEST_F(ReadTest,Map)402 TEST_F(ReadTest, Map)
403 {
404 const std::map<int, std::string> mis{
405 {1, "a"},
406 {2, "bc"},
407 {3, "def"},
408 {4, "ghij"},
409 };
410
411 {
412 testing::InSequence seq;
413 expect_enter_container(SD_BUS_TYPE_ARRAY, "{is}");
414 for (const auto& is : mis)
415 {
416 expect_at_end(false, 0);
417 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "is");
418 expect_basic<int>(SD_BUS_TYPE_INT32, is.first);
419 expect_basic<const char*>(SD_BUS_TYPE_STRING, is.second.c_str());
420 expect_exit_container();
421 }
422 expect_at_end(false, 1);
423 expect_exit_container();
424 }
425
426 std::map<int, std::string> ret_mis;
427 new_message().read(ret_mis);
428 EXPECT_EQ(mis, ret_mis);
429 }
430
TEST_F(ReadTest,MapEnterError)431 TEST_F(ReadTest, MapEnterError)
432 {
433 {
434 testing::InSequence seq;
435 expect_enter_container(SD_BUS_TYPE_ARRAY, "{si}", -EINVAL);
436 }
437
438 std::map<std::string, int> ret;
439 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
440 }
441
TEST_F(ReadTest,MapEntryEnterError)442 TEST_F(ReadTest, MapEntryEnterError)
443 {
444 {
445 testing::InSequence seq;
446 expect_enter_container(SD_BUS_TYPE_ARRAY, "{si}");
447 expect_at_end(false, 0);
448 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "si", -EINVAL);
449 }
450
451 std::map<std::string, int> ret;
452 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
453 }
454
TEST_F(ReadTest,MapEntryExitError)455 TEST_F(ReadTest, MapEntryExitError)
456 {
457 {
458 testing::InSequence seq;
459 expect_enter_container(SD_BUS_TYPE_ARRAY, "{si}");
460 expect_at_end(false, 0);
461 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "si");
462 expect_basic<const char*>(SD_BUS_TYPE_STRING, "ab");
463 expect_basic<int>(SD_BUS_TYPE_INT32, 1);
464 expect_exit_container(-EINVAL);
465 }
466
467 std::map<std::string, int> ret;
468 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
469 }
470
TEST_F(ReadTest,MapIterError)471 TEST_F(ReadTest, MapIterError)
472 {
473 {
474 testing::InSequence seq;
475 expect_enter_container(SD_BUS_TYPE_ARRAY, "{si}");
476 expect_at_end(false, 0);
477 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "si");
478 expect_basic<const char*>(SD_BUS_TYPE_STRING, "ab");
479 expect_basic<int>(SD_BUS_TYPE_INT32, 1);
480 expect_exit_container();
481 expect_at_end(false, -EINVAL);
482 }
483
484 std::map<std::string, int> ret;
485 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
486 }
487
TEST_F(ReadTest,MapExitError)488 TEST_F(ReadTest, MapExitError)
489 {
490 {
491 testing::InSequence seq;
492 expect_enter_container(SD_BUS_TYPE_ARRAY, "{si}");
493 expect_at_end(false, 0);
494 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "si");
495 expect_basic<const char*>(SD_BUS_TYPE_STRING, "ab");
496 expect_basic<int>(SD_BUS_TYPE_INT32, 1);
497 expect_exit_container();
498 expect_at_end(false, 1);
499 expect_exit_container(-EINVAL);
500 }
501
502 std::map<std::string, int> ret;
503 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
504 }
505
TEST_F(ReadTest,UnorderedMap)506 TEST_F(ReadTest, UnorderedMap)
507 {
508 const std::unordered_map<int, std::string> mis{
509 {1, "a"},
510 {2, "bc"},
511 {3, "def"},
512 {4, "ghij"},
513 };
514
515 {
516 testing::InSequence seq;
517 expect_enter_container(SD_BUS_TYPE_ARRAY, "{is}");
518 for (const auto& is : mis)
519 {
520 expect_at_end(false, 0);
521 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "is");
522 expect_basic<int>(SD_BUS_TYPE_INT32, is.first);
523 expect_basic<const char*>(SD_BUS_TYPE_STRING, is.second.c_str());
524 expect_exit_container();
525 }
526 expect_at_end(false, 1);
527 expect_exit_container();
528 }
529
530 std::unordered_map<int, std::string> ret_mis;
531 new_message().read(ret_mis);
532 EXPECT_EQ(mis, ret_mis);
533 }
534
TEST_F(ReadTest,Tuple)535 TEST_F(ReadTest, Tuple)
536 {
537 const std::tuple<int, std::string, bool> tisb{3, "hi", false};
538
539 {
540 testing::InSequence seq;
541 expect_enter_container(SD_BUS_TYPE_STRUCT, "isb");
542 expect_basic<int>(SD_BUS_TYPE_INT32, std::get<0>(tisb));
543 expect_basic<const char*>(SD_BUS_TYPE_STRING,
544 std::get<1>(tisb).c_str());
545 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, std::get<2>(tisb));
546 expect_exit_container();
547 }
548
549 std::tuple<int, std::string, bool> ret_tisb;
550 new_message().read(ret_tisb);
551 EXPECT_EQ(tisb, ret_tisb);
552 }
553
TEST_F(ReadTest,TupleEnterError)554 TEST_F(ReadTest, TupleEnterError)
555 {
556 {
557 testing::InSequence seq;
558 expect_enter_container(SD_BUS_TYPE_STRUCT, "bis", -EINVAL);
559 }
560
561 std::tuple<bool, int, std::string> ret;
562 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
563 }
564
TEST_F(ReadTest,TupleExitError)565 TEST_F(ReadTest, TupleExitError)
566 {
567 {
568 testing::InSequence seq;
569 expect_enter_container(SD_BUS_TYPE_STRUCT, "bis");
570 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, false);
571 expect_basic<int>(SD_BUS_TYPE_INT32, 1);
572 expect_basic<const char*>(SD_BUS_TYPE_STRING, "ab");
573 expect_exit_container(-EINVAL);
574 }
575
576 std::tuple<bool, int, std::string> ret;
577 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
578 }
579
TEST_F(ReadTest,Variant)580 TEST_F(ReadTest, Variant)
581 {
582 const bool b1 = false;
583 const std::string s2{"asdf"};
584 const std::variant<int, std::string, bool> v1{b1}, v2{s2};
585
586 {
587 testing::InSequence seq;
588 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", false);
589 expect_verify_type(SD_BUS_TYPE_VARIANT, "s", false);
590 expect_verify_type(SD_BUS_TYPE_VARIANT, "b", true);
591 expect_enter_container(SD_BUS_TYPE_VARIANT, "b");
592 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, b1);
593 expect_exit_container();
594 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", false);
595 expect_verify_type(SD_BUS_TYPE_VARIANT, "s", true);
596 expect_enter_container(SD_BUS_TYPE_VARIANT, "s");
597 expect_basic<const char*>(SD_BUS_TYPE_STRING, s2.c_str());
598 expect_exit_container();
599 }
600
601 std::variant<int, std::string, bool> ret_v1, ret_v2;
602 new_message().read(ret_v1, ret_v2);
603 EXPECT_EQ(v1, ret_v1);
604 EXPECT_EQ(v2, ret_v2);
605 }
606
TEST_F(ReadTest,VariantVerifyError)607 TEST_F(ReadTest, VariantVerifyError)
608 {
609 {
610 testing::InSequence seq;
611 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", -EINVAL);
612 }
613
614 std::variant<int, bool> ret;
615 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
616 }
617
TEST_F(ReadTest,VariantSkipUnmatched)618 TEST_F(ReadTest, VariantSkipUnmatched)
619 {
620 {
621 testing::InSequence seq;
622 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", false);
623 expect_verify_type(SD_BUS_TYPE_VARIANT, "b", false);
624 expect_skip("v");
625 }
626
627 std::variant<int, bool> ret;
628 new_message().read(ret);
629 }
630
TEST_F(ReadTest,VariantSkipError)631 TEST_F(ReadTest, VariantSkipError)
632 {
633 {
634 testing::InSequence seq;
635 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", false);
636 expect_verify_type(SD_BUS_TYPE_VARIANT, "b", false);
637 expect_skip("v", -EINVAL);
638 }
639
640 std::variant<int, bool> ret;
641 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
642 }
643
TEST_F(ReadTest,VariantEnterError)644 TEST_F(ReadTest, VariantEnterError)
645 {
646 {
647 testing::InSequence seq;
648 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", true);
649 expect_enter_container(SD_BUS_TYPE_VARIANT, "i", -EINVAL);
650 }
651
652 std::variant<int, bool> ret;
653 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
654 }
655
TEST_F(ReadTest,VariantExitError)656 TEST_F(ReadTest, VariantExitError)
657 {
658 {
659 testing::InSequence seq;
660 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", true);
661 expect_enter_container(SD_BUS_TYPE_VARIANT, "i");
662 expect_basic<int>(SD_BUS_TYPE_INT32, 10);
663 expect_exit_container(-EINVAL);
664 }
665
666 std::variant<int, bool> ret;
667 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
668 }
669
TEST_F(ReadTest,LargeCombo)670 TEST_F(ReadTest, LargeCombo)
671 {
672 const std::vector<std::set<std::string>> vas{
673 {"a", "b", "c"},
674 {"d", "", "e"},
675 };
676 const std::map<std::string, std::variant<int, double>> msv = {
677 {"a", 3.3}, {"b", 1}, {"c", 4.4}};
678
679 {
680 testing::InSequence seq;
681
682 expect_enter_container(SD_BUS_TYPE_ARRAY, "as");
683 for (const auto& as : vas)
684 {
685 expect_at_end(false, 0);
686 expect_enter_container(SD_BUS_TYPE_ARRAY, "s");
687 for (const auto& s : as)
688 {
689 expect_at_end(false, 0);
690 expect_basic<const char*>(SD_BUS_TYPE_STRING, s.c_str());
691 }
692 expect_at_end(false, 1);
693 expect_exit_container();
694 }
695 expect_at_end(false, 1);
696 expect_exit_container();
697
698 expect_enter_container(SD_BUS_TYPE_ARRAY, "{sv}");
699 for (const auto& sv : msv)
700 {
701 expect_at_end(false, 0);
702 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "sv");
703 expect_basic<const char*>(SD_BUS_TYPE_STRING, sv.first.c_str());
704 if (std::holds_alternative<int>(sv.second))
705 {
706 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", true);
707 expect_enter_container(SD_BUS_TYPE_VARIANT, "i");
708 expect_basic<int>(SD_BUS_TYPE_INT32, std::get<int>(sv.second));
709 expect_exit_container();
710 }
711 else
712 {
713 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", false);
714 expect_verify_type(SD_BUS_TYPE_VARIANT, "d", true);
715 expect_enter_container(SD_BUS_TYPE_VARIANT, "d");
716 expect_basic<double>(SD_BUS_TYPE_DOUBLE,
717 std::get<double>(sv.second));
718 expect_exit_container();
719 }
720 expect_exit_container();
721 }
722 expect_at_end(false, 1);
723 expect_exit_container();
724 }
725
726 std::vector<std::set<std::string>> ret_vas;
727 std::map<std::string, std::variant<int, double>> ret_msv;
728 new_message().read(ret_vas, ret_msv);
729 EXPECT_EQ(vas, ret_vas);
730 EXPECT_EQ(msv, ret_msv);
731 }
732
733 // Unpack tests.
734 // Since unpack uses read, we're mostly just testing the compilation.
735 // Duplicate a few tests from Read using 'unpack'.
736
TEST_F(ReadTest,UnpackSingleVector)737 TEST_F(ReadTest, UnpackSingleVector)
738 {
739 const std::vector<std::string> vs{"a", "b", "c", "d"};
740
741 {
742 testing::InSequence seq;
743 expect_enter_container(SD_BUS_TYPE_ARRAY, "s");
744 for (const auto& i : vs)
745 {
746 expect_at_end(false, 0);
747 expect_basic<const char*>(SD_BUS_TYPE_STRING, i.c_str());
748 }
749 expect_at_end(false, 1);
750 expect_exit_container();
751 }
752
753 auto ret_vs = new_message().unpack<std::vector<std::string>>();
754 EXPECT_EQ(vs, ret_vs);
755 }
756
TEST_F(ReadTest,UnpackMultiple)757 TEST_F(ReadTest, UnpackMultiple)
758 {
759 const std::tuple<int, std::string, bool> tisb{3, "hi", false};
760
761 {
762 testing::InSequence seq;
763 expect_basic<int>(SD_BUS_TYPE_INT32, std::get<0>(tisb));
764 expect_basic<const char*>(SD_BUS_TYPE_STRING,
765 std::get<1>(tisb).c_str());
766 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, std::get<2>(tisb));
767 }
768
769 auto ret_tisb = new_message().unpack<int, std::string, bool>();
770 EXPECT_EQ(tisb, ret_tisb);
771 }
772
TEST_F(ReadTest,UnpackStructuredBinding)773 TEST_F(ReadTest, UnpackStructuredBinding)
774 {
775 const std::tuple<int, std::string, bool> tisb{3, "hi", false};
776
777 {
778 testing::InSequence seq;
779 expect_basic<int>(SD_BUS_TYPE_INT32, std::get<0>(tisb));
780 expect_basic<const char*>(SD_BUS_TYPE_STRING,
781 std::get<1>(tisb).c_str());
782 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, std::get<2>(tisb));
783 }
784
785 auto [ret_ti, ret_ts,
786 ret_tb] = new_message().unpack<int, std::string, bool>();
787 EXPECT_EQ(tisb, std::make_tuple(ret_ti, ret_ts, ret_tb));
788 }
789
TEST_F(ReadTest,UnpackVoid)790 TEST_F(ReadTest, UnpackVoid)
791 {
792 new_message().unpack<>();
793 new_message().unpack<void>();
794 }
795
796 } // namespace
797