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