xref: /openbmc/sdbusplus/test/message/read.cpp (revision e1c73d3b)
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 
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 
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 
46     sdbusplus::message::message new_message()
47     {
48         return sdbusplus::get_mocked_new(&mock).new_method_call(
49             nullptr, nullptr, nullptr, nullptr);
50     }
51 
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>
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
162 TEST_F(ReadTest, CombinedBasic)
163 {
164     const double a = 2.2;
165     const char* const b = "ijkd";
166     const bool c = false;
167     const int d = 18;
168 
169     {
170         testing::InSequence seq;
171         expect_basic<double>(SD_BUS_TYPE_DOUBLE, a);
172         expect_basic<const char*>(SD_BUS_TYPE_STRING, b);
173         expect_basic<int>(SD_BUS_TYPE_BOOLEAN, c);
174         expect_basic<int>(SD_BUS_TYPE_INT32, d);
175     }
176 
177     double ret_a;
178     const char* ret_b;
179     bool ret_c;
180     int ret_d;
181     new_message().read(ret_a, ret_b, ret_c, ret_d);
182     EXPECT_EQ(a, ret_a);
183     EXPECT_EQ(b, ret_b);
184     EXPECT_EQ(c, ret_c);
185     EXPECT_EQ(d, ret_d);
186 }
187 
188 TEST_F(ReadTest, BasicError)
189 {
190     expect_basic_error(SD_BUS_TYPE_INT32, -EINVAL);
191     int ret;
192     EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
193 }
194 
195 TEST_F(ReadTest, BasicStringError)
196 {
197     expect_basic_error(SD_BUS_TYPE_STRING, -EINVAL);
198     std::string ret;
199     EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
200 }
201 
202 TEST_F(ReadTest, BasicStringWrapperError)
203 {
204     expect_basic_error(SD_BUS_TYPE_SIGNATURE, -EINVAL);
205     sdbusplus::message::signature ret;
206     EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
207 }
208 
209 TEST_F(ReadTest, BasicBoolError)
210 {
211     expect_basic_error(SD_BUS_TYPE_BOOLEAN, -EINVAL);
212     bool ret;
213     EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
214 }
215 
216 TEST_F(ReadTest, Vector)
217 {
218     const std::vector<int> vi{1, 2, 3, 4};
219 
220     {
221         testing::InSequence seq;
222         expect_enter_container(SD_BUS_TYPE_ARRAY, "i");
223         for (const auto& i : vi)
224         {
225             expect_at_end(false, 0);
226             expect_basic<int>(SD_BUS_TYPE_INT32, i);
227         }
228         expect_at_end(false, 1);
229         expect_exit_container();
230     }
231 
232     std::vector<int> ret_vi;
233     new_message().read(ret_vi);
234     EXPECT_EQ(vi, ret_vi);
235 }
236 
237 TEST_F(ReadTest, VectorEnterError)
238 {
239     {
240         testing::InSequence seq;
241         expect_enter_container(SD_BUS_TYPE_ARRAY, "i", -EINVAL);
242     }
243 
244     std::vector<int> ret;
245     EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
246 }
247 
248 TEST_F(ReadTest, VectorIterError)
249 {
250     {
251         testing::InSequence seq;
252         expect_enter_container(SD_BUS_TYPE_ARRAY, "i");
253         expect_at_end(false, 0);
254         expect_basic<int>(SD_BUS_TYPE_INT32, 1);
255         expect_at_end(false, -EINVAL);
256     }
257 
258     std::vector<int> ret;
259     EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
260 }
261 
262 TEST_F(ReadTest, VectorExitError)
263 {
264     {
265         testing::InSequence seq;
266         expect_enter_container(SD_BUS_TYPE_ARRAY, "i");
267         expect_at_end(false, 0);
268         expect_basic<int>(SD_BUS_TYPE_INT32, 1);
269         expect_at_end(false, 0);
270         expect_basic<int>(SD_BUS_TYPE_INT32, 2);
271         expect_at_end(false, 1);
272         expect_exit_container(-EINVAL);
273     }
274 
275     std::vector<int> ret;
276     EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
277 }
278 
279 TEST_F(ReadTest, Set)
280 {
281     const std::set<std::string> ss{"one", "two", "eight"};
282 
283     {
284         testing::InSequence seq;
285         expect_enter_container(SD_BUS_TYPE_ARRAY, "s");
286         for (const auto& s : ss)
287         {
288             expect_at_end(false, 0);
289             expect_basic<const char*>(SD_BUS_TYPE_STRING, s.c_str());
290         }
291         expect_at_end(false, 1);
292         expect_exit_container();
293     }
294 
295     std::set<std::string> ret_ss;
296     new_message().read(ret_ss);
297     EXPECT_EQ(ss, ret_ss);
298 }
299 
300 TEST_F(ReadTest, UnorderedSet)
301 {
302     const std::unordered_set<std::string> ss{"one", "two", "eight"};
303 
304     {
305         testing::InSequence seq;
306         expect_enter_container(SD_BUS_TYPE_ARRAY, "s");
307         for (const auto& s : ss)
308         {
309             expect_at_end(false, 0);
310             expect_basic<const char*>(SD_BUS_TYPE_STRING, s.c_str());
311         }
312         expect_at_end(false, 1);
313         expect_exit_container();
314     }
315 
316     std::unordered_set<std::string> ret_ss;
317     new_message().read(ret_ss);
318     EXPECT_EQ(ss, ret_ss);
319 }
320 
321 TEST_F(ReadTest, Map)
322 {
323     const std::map<int, std::string> mis{
324         {1, "a"},
325         {2, "bc"},
326         {3, "def"},
327         {4, "ghij"},
328     };
329 
330     {
331         testing::InSequence seq;
332         expect_enter_container(SD_BUS_TYPE_ARRAY, "{is}");
333         for (const auto& is : mis)
334         {
335             expect_at_end(false, 0);
336             expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "is");
337             expect_basic<int>(SD_BUS_TYPE_INT32, is.first);
338             expect_basic<const char*>(SD_BUS_TYPE_STRING, is.second.c_str());
339             expect_exit_container();
340         }
341         expect_at_end(false, 1);
342         expect_exit_container();
343     }
344 
345     std::map<int, std::string> ret_mis;
346     new_message().read(ret_mis);
347     EXPECT_EQ(mis, ret_mis);
348 }
349 
350 TEST_F(ReadTest, MapEnterError)
351 {
352     {
353         testing::InSequence seq;
354         expect_enter_container(SD_BUS_TYPE_ARRAY, "{si}", -EINVAL);
355     }
356 
357     std::map<std::string, int> ret;
358     EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
359 }
360 
361 TEST_F(ReadTest, MapEntryEnterError)
362 {
363     {
364         testing::InSequence seq;
365         expect_enter_container(SD_BUS_TYPE_ARRAY, "{si}");
366         expect_at_end(false, 0);
367         expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "si", -EINVAL);
368     }
369 
370     std::map<std::string, int> ret;
371     EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
372 }
373 
374 TEST_F(ReadTest, MapEntryExitError)
375 {
376     {
377         testing::InSequence seq;
378         expect_enter_container(SD_BUS_TYPE_ARRAY, "{si}");
379         expect_at_end(false, 0);
380         expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "si");
381         expect_basic<const char*>(SD_BUS_TYPE_STRING, "ab");
382         expect_basic<int>(SD_BUS_TYPE_INT32, 1);
383         expect_exit_container(-EINVAL);
384     }
385 
386     std::map<std::string, int> ret;
387     EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
388 }
389 
390 TEST_F(ReadTest, MapIterError)
391 {
392     {
393         testing::InSequence seq;
394         expect_enter_container(SD_BUS_TYPE_ARRAY, "{si}");
395         expect_at_end(false, 0);
396         expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "si");
397         expect_basic<const char*>(SD_BUS_TYPE_STRING, "ab");
398         expect_basic<int>(SD_BUS_TYPE_INT32, 1);
399         expect_exit_container();
400         expect_at_end(false, -EINVAL);
401     }
402 
403     std::map<std::string, int> ret;
404     EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
405 }
406 
407 TEST_F(ReadTest, MapExitError)
408 {
409     {
410         testing::InSequence seq;
411         expect_enter_container(SD_BUS_TYPE_ARRAY, "{si}");
412         expect_at_end(false, 0);
413         expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "si");
414         expect_basic<const char*>(SD_BUS_TYPE_STRING, "ab");
415         expect_basic<int>(SD_BUS_TYPE_INT32, 1);
416         expect_exit_container();
417         expect_at_end(false, 1);
418         expect_exit_container(-EINVAL);
419     }
420 
421     std::map<std::string, int> ret;
422     EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
423 }
424 
425 TEST_F(ReadTest, UnorderedMap)
426 {
427     const std::unordered_map<int, std::string> mis{
428         {1, "a"},
429         {2, "bc"},
430         {3, "def"},
431         {4, "ghij"},
432     };
433 
434     {
435         testing::InSequence seq;
436         expect_enter_container(SD_BUS_TYPE_ARRAY, "{is}");
437         for (const auto& is : mis)
438         {
439             expect_at_end(false, 0);
440             expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "is");
441             expect_basic<int>(SD_BUS_TYPE_INT32, is.first);
442             expect_basic<const char*>(SD_BUS_TYPE_STRING, is.second.c_str());
443             expect_exit_container();
444         }
445         expect_at_end(false, 1);
446         expect_exit_container();
447     }
448 
449     std::unordered_map<int, std::string> ret_mis;
450     new_message().read(ret_mis);
451     EXPECT_EQ(mis, ret_mis);
452 }
453 
454 TEST_F(ReadTest, Tuple)
455 {
456     const std::tuple<int, std::string, bool> tisb{3, "hi", false};
457 
458     {
459         testing::InSequence seq;
460         expect_enter_container(SD_BUS_TYPE_STRUCT, "isb");
461         expect_basic<int>(SD_BUS_TYPE_INT32, std::get<0>(tisb));
462         expect_basic<const char*>(SD_BUS_TYPE_STRING,
463                                   std::get<1>(tisb).c_str());
464         expect_basic<int>(SD_BUS_TYPE_BOOLEAN, std::get<2>(tisb));
465         expect_exit_container();
466     }
467 
468     std::tuple<int, std::string, bool> ret_tisb;
469     new_message().read(ret_tisb);
470     EXPECT_EQ(tisb, ret_tisb);
471 }
472 
473 TEST_F(ReadTest, TupleEnterError)
474 {
475     {
476         testing::InSequence seq;
477         expect_enter_container(SD_BUS_TYPE_STRUCT, "bis", -EINVAL);
478     }
479 
480     std::tuple<bool, int, std::string> ret;
481     EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
482 }
483 
484 TEST_F(ReadTest, TupleExitError)
485 {
486     {
487         testing::InSequence seq;
488         expect_enter_container(SD_BUS_TYPE_STRUCT, "bis");
489         expect_basic<int>(SD_BUS_TYPE_BOOLEAN, false);
490         expect_basic<int>(SD_BUS_TYPE_INT32, 1);
491         expect_basic<const char*>(SD_BUS_TYPE_STRING, "ab");
492         expect_exit_container(-EINVAL);
493     }
494 
495     std::tuple<bool, int, std::string> ret;
496     EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
497 }
498 
499 TEST_F(ReadTest, Variant)
500 {
501     const bool b1 = false;
502     const std::string s2{"asdf"};
503     const std::variant<int, std::string, bool> v1{b1}, v2{s2};
504 
505     {
506         testing::InSequence seq;
507         expect_verify_type(SD_BUS_TYPE_VARIANT, "i", false);
508         expect_verify_type(SD_BUS_TYPE_VARIANT, "s", false);
509         expect_verify_type(SD_BUS_TYPE_VARIANT, "b", true);
510         expect_enter_container(SD_BUS_TYPE_VARIANT, "b");
511         expect_basic<int>(SD_BUS_TYPE_BOOLEAN, b1);
512         expect_exit_container();
513         expect_verify_type(SD_BUS_TYPE_VARIANT, "i", false);
514         expect_verify_type(SD_BUS_TYPE_VARIANT, "s", true);
515         expect_enter_container(SD_BUS_TYPE_VARIANT, "s");
516         expect_basic<const char*>(SD_BUS_TYPE_STRING, s2.c_str());
517         expect_exit_container();
518     }
519 
520     std::variant<int, std::string, bool> ret_v1, ret_v2;
521     new_message().read(ret_v1, ret_v2);
522     EXPECT_EQ(v1, ret_v1);
523     EXPECT_EQ(v2, ret_v2);
524 }
525 
526 TEST_F(ReadTest, VariantVerifyError)
527 {
528     {
529         testing::InSequence seq;
530         expect_verify_type(SD_BUS_TYPE_VARIANT, "i", -EINVAL);
531     }
532 
533     std::variant<int, bool> ret;
534     EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
535 }
536 
537 TEST_F(ReadTest, VariantSkipUnmatched)
538 {
539     {
540         testing::InSequence seq;
541         expect_verify_type(SD_BUS_TYPE_VARIANT, "i", false);
542         expect_verify_type(SD_BUS_TYPE_VARIANT, "b", false);
543         expect_skip("v");
544     }
545 
546     std::variant<int, bool> ret;
547     new_message().read(ret);
548 }
549 
550 TEST_F(ReadTest, VariantSkipError)
551 {
552     {
553         testing::InSequence seq;
554         expect_verify_type(SD_BUS_TYPE_VARIANT, "i", false);
555         expect_verify_type(SD_BUS_TYPE_VARIANT, "b", false);
556         expect_skip("v", -EINVAL);
557     }
558 
559     std::variant<int, bool> ret;
560     EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
561 }
562 
563 TEST_F(ReadTest, VariantEnterError)
564 {
565     {
566         testing::InSequence seq;
567         expect_verify_type(SD_BUS_TYPE_VARIANT, "i", true);
568         expect_enter_container(SD_BUS_TYPE_VARIANT, "i", -EINVAL);
569     }
570 
571     std::variant<int, bool> ret;
572     EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
573 }
574 
575 TEST_F(ReadTest, VariantExitError)
576 {
577     {
578         testing::InSequence seq;
579         expect_verify_type(SD_BUS_TYPE_VARIANT, "i", true);
580         expect_enter_container(SD_BUS_TYPE_VARIANT, "i");
581         expect_basic<int>(SD_BUS_TYPE_INT32, 10);
582         expect_exit_container(-EINVAL);
583     }
584 
585     std::variant<int, bool> ret;
586     EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError);
587 }
588 
589 TEST_F(ReadTest, LargeCombo)
590 {
591     const std::vector<std::set<std::string>> vas{
592         {"a", "b", "c"},
593         {"d", "", "e"},
594     };
595     const std::map<std::string, std::variant<int, double>> msv = {
596         {"a", 3.3}, {"b", 1}, {"c", 4.4}};
597 
598     {
599         testing::InSequence seq;
600 
601         expect_enter_container(SD_BUS_TYPE_ARRAY, "as");
602         for (const auto& as : vas)
603         {
604             expect_at_end(false, 0);
605             expect_enter_container(SD_BUS_TYPE_ARRAY, "s");
606             for (const auto& s : as)
607             {
608                 expect_at_end(false, 0);
609                 expect_basic<const char*>(SD_BUS_TYPE_STRING, s.c_str());
610             }
611             expect_at_end(false, 1);
612             expect_exit_container();
613         }
614         expect_at_end(false, 1);
615         expect_exit_container();
616 
617         expect_enter_container(SD_BUS_TYPE_ARRAY, "{sv}");
618         for (const auto& sv : msv)
619         {
620             expect_at_end(false, 0);
621             expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "sv");
622             expect_basic<const char*>(SD_BUS_TYPE_STRING, sv.first.c_str());
623             if (std::holds_alternative<int>(sv.second))
624             {
625                 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", true);
626                 expect_enter_container(SD_BUS_TYPE_VARIANT, "i");
627                 expect_basic<int>(SD_BUS_TYPE_INT32, std::get<int>(sv.second));
628                 expect_exit_container();
629             }
630             else
631             {
632                 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", false);
633                 expect_verify_type(SD_BUS_TYPE_VARIANT, "d", true);
634                 expect_enter_container(SD_BUS_TYPE_VARIANT, "d");
635                 expect_basic<double>(SD_BUS_TYPE_DOUBLE,
636                                      std::get<double>(sv.second));
637                 expect_exit_container();
638             }
639             expect_exit_container();
640         }
641         expect_at_end(false, 1);
642         expect_exit_container();
643     }
644 
645     std::vector<std::set<std::string>> ret_vas;
646     std::map<std::string, std::variant<int, double>> ret_msv;
647     new_message().read(ret_vas, ret_msv);
648     EXPECT_EQ(vas, ret_vas);
649     EXPECT_EQ(msv, ret_msv);
650 }
651 
652 } // namespace
653