xref: /openbmc/sdbusplus/test/message/read.cpp (revision 88c6a8237f03409a7ec9a95f79d03fc67f5f94bd)
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  
ACTION_TEMPLATE(AssignReadVal,HAS_1_TEMPLATE_PARAMS (typename,T),AND_1_VALUE_PARAMS (val))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  
SetUp()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  
new_message()46      sdbusplus::message_t new_message()
47      {
48          return sdbusplus::get_mocked_new(&mock).new_method_call(
49              nullptr, nullptr, nullptr, nullptr);
50      }
51  
expect_basic_error(char type,int ret)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>
expect_basic(char type,T val)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  
expect_verify_type(char type,const char * contents,int ret)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  
expect_at_end(bool complete,int ret)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  
expect_skip(const char * contents,int ret=0)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  
expect_enter_container(char type,const char * contents,int ret=0)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  
expect_exit_container(int ret=0)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  
TEST_F(ReadTest,Int)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  
TEST_F(ReadTest,Bool)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  
TEST_F(ReadTest,Double)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  
TEST_F(ReadTest,CString)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  
TEST_F(ReadTest,String)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  
TEST_F(ReadTest,ObjectPath)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  
TEST_F(ReadTest,Signature)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  
TEST_F(ReadTest,UnixFd)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  
TEST_F(ReadTest,CombinedBasic)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  
TEST_F(ReadTest,BasicError)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  
TEST_F(ReadTest,BasicStringError)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  
TEST_F(ReadTest,BasicStringWrapperError)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  
TEST_F(ReadTest,BasicBoolError)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  
TEST_F(ReadTest,Vector)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  
TEST_F(ReadTest,VectorEnterError)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  
TEST_F(ReadTest,VectorIterError)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  
TEST_F(ReadTest,VectorExitError)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  
TEST_F(ReadTest,Set)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  
TEST_F(ReadTest,UnorderedSet)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  
TEST_F(ReadTest,Map)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  
TEST_F(ReadTest,MapEnterError)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  
TEST_F(ReadTest,MapEntryEnterError)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  
TEST_F(ReadTest,MapEntryExitError)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  
TEST_F(ReadTest,MapIterError)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  
TEST_F(ReadTest,MapExitError)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  
TEST_F(ReadTest,UnorderedMap)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  
TEST_F(ReadTest,Tuple)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  
TEST_F(ReadTest,TupleEnterError)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  
TEST_F(ReadTest,TupleExitError)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  
TEST_F(ReadTest,Variant)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  
TEST_F(ReadTest,VariantVerifyError)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  
TEST_F(ReadTest,VariantSkipUnmatched)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  
TEST_F(ReadTest,VariantSkipError)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  
TEST_F(ReadTest,VariantEnterError)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  
TEST_F(ReadTest,VariantExitError)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  
TEST_F(ReadTest,LargeCombo)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  
TEST_F(ReadTest,UnpackSingleVector)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  
TEST_F(ReadTest,UnpackMultiple)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  
TEST_F(ReadTest,UnpackStructuredBinding)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  
TEST_F(ReadTest,UnpackVoid)718  TEST_F(ReadTest, UnpackVoid)
719  {
720      new_message().unpack<>();
721      new_message().unpack<void>();
722  }
723  
724  } // namespace
725