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