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