xref: /openbmc/sdbusplus/test/message/read.cpp (revision 242677a2b3dafdb3b79464eb64e0ae8bc7c5a7d5)
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