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