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