xref: /openbmc/sdbusplus/test/message/append.cpp (revision 47ac18da9347b199df9be04250b2a987fc4c30a7)
1 #include <systemd/sd-bus-protocol.h>
2 
3 #include <sdbusplus/message.hpp>
4 #include <sdbusplus/test/sdbus_mock.hpp>
5 
6 #include <array>
7 #include <map>
8 #include <set>
9 #include <span>
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::Eq;
24 using testing::MatcherCast;
25 using testing::Pointee;
26 using testing::Return;
27 using testing::SafeMatcherCast;
28 using testing::StrEq;
29 
30 MATCHER_P(iovec_equal, match_string, "")
31 {
32     const char* start = std::bit_cast<char*>(arg->iov_base);
33     return std::string(start, arg->iov_len) == match_string;
34 }
35 
36 class AppendTest : public testing::Test
37 {
38   protected:
39     testing::StrictMock<sdbusplus::SdBusMock> mock;
40 
SetUp()41     void SetUp() override
42     {
43         EXPECT_CALL(mock, sd_bus_message_new_method_call(testing::_, testing::_,
44                                                          nullptr, nullptr,
45                                                          nullptr, nullptr))
46             .WillRepeatedly(Return(0));
47     }
48 
new_message()49     sdbusplus::message_t new_message()
50     {
51         return sdbusplus::get_mocked_new(&mock).new_method_call(
52             nullptr, nullptr, nullptr, nullptr);
53     }
54 
55     template <typename T>
expect_basic(char type,T val)56     void expect_basic(char type, T val)
57     {
58         EXPECT_CALL(mock, sd_bus_message_append_basic(
59                               nullptr, type,
60                               MatcherCast<const void*>(
61                                   SafeMatcherCast<const T*>(Pointee(Eq(val))))))
62             .WillOnce(Return(0));
63     }
64 
expect_basic_string(char type,const char * str)65     void expect_basic_string(char type, const char* str)
66     {
67         EXPECT_CALL(mock, sd_bus_message_append_basic(
68                               nullptr, type,
69                               MatcherCast<const void*>(
70                                   SafeMatcherCast<const char*>(StrEq(str)))))
71             .WillOnce(Return(0));
72     }
expect_basic_string_iovec(const char * str,size_t size)73     void expect_basic_string_iovec(const char* str, size_t size)
74     {
75         std::string tmp = {str, size};
76         EXPECT_CALL(mock, sd_bus_message_append_string_iovec(
77                               nullptr, iovec_equal(tmp), 1))
78             .WillOnce(Return(0));
79     }
80 
expect_open_container(char type,const char * contents)81     void expect_open_container(char type, const char* contents)
82     {
83         EXPECT_CALL(
84             mock, sd_bus_message_open_container(nullptr, type, StrEq(contents)))
85             .WillOnce(Return(0));
86     }
87 
expect_close_container()88     void expect_close_container()
89     {
90         EXPECT_CALL(mock, sd_bus_message_close_container(nullptr))
91             .WillOnce(Return(0));
92     }
93 
on_array_append(sd_bus_message *,char,const void *,size_t)94     static int on_array_append(sd_bus_message*, char, const void*, size_t)
95     {
96         return 0;
97     }
98 
expect_append_array(char type,size_t sz)99     void expect_append_array(char type, size_t sz)
100     {
101         EXPECT_CALL(mock,
102                     sd_bus_message_append_array(nullptr, type, testing::_, sz))
103             .WillOnce(testing::Invoke(on_array_append));
104     }
105 };
106 
TEST_F(AppendTest,RValueInt)107 TEST_F(AppendTest, RValueInt)
108 {
109     expect_basic<int>(SD_BUS_TYPE_INT32, 1);
110     new_message().append(1);
111 }
112 
TEST_F(AppendTest,LValueInt)113 TEST_F(AppendTest, LValueInt)
114 {
115     const int a = 1;
116     expect_basic<int>(SD_BUS_TYPE_INT32, a);
117     new_message().append(a);
118 }
119 
TEST_F(AppendTest,XValueInt)120 TEST_F(AppendTest, XValueInt)
121 {
122     int a = 1;
123     expect_basic<int>(SD_BUS_TYPE_INT32, a);
124     new_message().append(std::move(a));
125 }
126 
TEST_F(AppendTest,RValueBool)127 TEST_F(AppendTest, RValueBool)
128 {
129     expect_basic<int>(SD_BUS_TYPE_BOOLEAN, true);
130     new_message().append(true);
131 }
132 
TEST_F(AppendTest,LValueBool)133 TEST_F(AppendTest, LValueBool)
134 {
135     const bool a = false;
136     expect_basic<int>(SD_BUS_TYPE_BOOLEAN, false);
137     new_message().append(a);
138 }
139 
TEST_F(AppendTest,XValueBool)140 TEST_F(AppendTest, XValueBool)
141 {
142     bool a = false;
143     expect_basic<int>(SD_BUS_TYPE_BOOLEAN, false);
144     new_message().append(std::move(a));
145 }
146 
TEST_F(AppendTest,RValueDouble)147 TEST_F(AppendTest, RValueDouble)
148 {
149     expect_basic<double>(SD_BUS_TYPE_DOUBLE, 1.1);
150     new_message().append(1.1);
151 }
152 
TEST_F(AppendTest,LValueDouble)153 TEST_F(AppendTest, LValueDouble)
154 {
155     const double a = 1.1;
156     expect_basic<double>(SD_BUS_TYPE_DOUBLE, a);
157     new_message().append(a);
158 }
159 
TEST_F(AppendTest,XValueDouble)160 TEST_F(AppendTest, XValueDouble)
161 {
162     double a = 1.1;
163     expect_basic<double>(SD_BUS_TYPE_DOUBLE, a);
164     new_message().append(std::move(a));
165 }
166 
TEST_F(AppendTest,RValueCString)167 TEST_F(AppendTest, RValueCString)
168 {
169     expect_basic_string(SD_BUS_TYPE_STRING, "asdf");
170     new_message().append("asdf");
171 }
172 
TEST_F(AppendTest,LValueCString)173 TEST_F(AppendTest, LValueCString)
174 {
175     const char* const s = "asdf";
176     expect_basic_string(SD_BUS_TYPE_STRING, s);
177     new_message().append(s);
178 }
179 
TEST_F(AppendTest,XValueCString)180 TEST_F(AppendTest, XValueCString)
181 {
182     const char* s = "asdf";
183     expect_basic_string(SD_BUS_TYPE_STRING, s);
184     new_message().append(std::move(s));
185 }
186 
TEST_F(AppendTest,RValueString)187 TEST_F(AppendTest, RValueString)
188 {
189     expect_basic_string(SD_BUS_TYPE_STRING, "asdf");
190     new_message().append(std::string{"asdf"});
191 }
192 
TEST_F(AppendTest,LValueString)193 TEST_F(AppendTest, LValueString)
194 {
195     std::string s{"asdf"};
196     expect_basic_string(SD_BUS_TYPE_STRING, s.c_str());
197     new_message().append(s);
198 }
199 
TEST_F(AppendTest,XValueString)200 TEST_F(AppendTest, XValueString)
201 {
202     std::string s{"asdf"};
203     expect_basic_string(SD_BUS_TYPE_STRING, s.c_str());
204     new_message().append(std::move(s));
205 }
206 
TEST_F(AppendTest,LValueStringView)207 TEST_F(AppendTest, LValueStringView)
208 {
209     std::string_view s{"asdf"};
210     expect_basic_string_iovec(s.data(), s.size());
211     new_message().append(s);
212 }
213 
TEST_F(AppendTest,RValueStringView)214 TEST_F(AppendTest, RValueStringView)
215 {
216     std::string_view s{"asdf"};
217     expect_basic_string_iovec(s.data(), s.size());
218     new_message().append(std::string_view{"asdf"});
219 }
220 
TEST_F(AppendTest,ObjectPath)221 TEST_F(AppendTest, ObjectPath)
222 {
223     sdbusplus::message::object_path o{"/asdf"};
224     expect_basic_string(SD_BUS_TYPE_OBJECT_PATH, o.str.c_str());
225     new_message().append(o);
226 }
227 
TEST_F(AppendTest,Signature)228 TEST_F(AppendTest, Signature)
229 {
230     sdbusplus::message::signature g{"ii"};
231     expect_basic_string(SD_BUS_TYPE_SIGNATURE, g.str.c_str());
232     new_message().append(g);
233 }
234 
TEST_F(AppendTest,CombinedBasic)235 TEST_F(AppendTest, CombinedBasic)
236 {
237     const int c = 3;
238     const std::string s1{"fdsa"};
239     const char* const s2 = "asdf";
240 
241     {
242         testing::InSequence seq;
243         expect_basic<int>(SD_BUS_TYPE_INT32, 1);
244         expect_basic<double>(SD_BUS_TYPE_DOUBLE, 2.2);
245         expect_basic<int>(SD_BUS_TYPE_INT32, c);
246         expect_basic_string(SD_BUS_TYPE_STRING, s1.c_str());
247         expect_basic<int>(SD_BUS_TYPE_BOOLEAN, false);
248         expect_basic_string(SD_BUS_TYPE_STRING, s2);
249     }
250     new_message().append(1, 2.2, c, s1, false, s2);
251 }
252 
TEST_F(AppendTest,Array)253 TEST_F(AppendTest, Array)
254 {
255     const std::array<double, 4> a{1.1, 2.2, 3.3, 4.4};
256 
257     {
258         expect_append_array(SD_BUS_TYPE_DOUBLE, a.size() * sizeof(double));
259     }
260     new_message().append(a);
261 }
262 
TEST_F(AppendTest,Span)263 TEST_F(AppendTest, Span)
264 {
265     const std::array<double, 4> a{1.1, 2.2, 3.3, 4.4};
266     auto s = std::span{a};
267 
268     {
269         expect_append_array(SD_BUS_TYPE_DOUBLE, a.size() * sizeof(double));
270     }
271     new_message().append(s);
272 }
273 
TEST_F(AppendTest,Vector)274 TEST_F(AppendTest, Vector)
275 {
276     const std::vector<std::string> v{"a", "b", "c", "d"};
277 
278     {
279         testing::InSequence seq;
280         expect_open_container(SD_BUS_TYPE_ARRAY, "s");
281         for (const auto& i : v)
282         {
283             expect_basic_string(SD_BUS_TYPE_STRING, i.c_str());
284         }
285         expect_close_container();
286     }
287     new_message().append(v);
288 }
289 
TEST_F(AppendTest,VectorIntegral)290 TEST_F(AppendTest, VectorIntegral)
291 {
292     const std::vector<int32_t> v{1, 2, 3, 4};
293     expect_append_array(SD_BUS_TYPE_INT32, v.size() * sizeof(int32_t));
294     new_message().append(v);
295 }
296 
TEST_F(AppendTest,VectorBoolean)297 TEST_F(AppendTest, VectorBoolean)
298 {
299     const std::vector<bool> v{false, true, false, true};
300     {
301         testing::InSequence seq;
302         expect_open_container(SD_BUS_TYPE_ARRAY, "b");
303         for (const auto& i : v)
304         {
305             expect_basic<bool>(SD_BUS_TYPE_BOOLEAN, (int)i);
306         }
307         expect_close_container();
308     }
309     new_message().append(v);
310 }
311 
TEST_F(AppendTest,VectorNestIntegral)312 TEST_F(AppendTest, VectorNestIntegral)
313 {
314     const std::vector<std::array<int32_t, 3>> v{
315         {1, 2, 3}, {3, 4, 5}, {6, 7, 8}};
316 
317     {
318         testing::InSequence seq;
319         expect_open_container(SD_BUS_TYPE_ARRAY, "ai");
320         for (long unsigned int i = 0; i < v.size(); i++)
321         {
322             expect_append_array(SD_BUS_TYPE_INT32,
323                                 v[i].size() * sizeof(int32_t));
324         }
325         expect_close_container();
326     }
327     new_message().append(v);
328 }
329 
TEST_F(AppendTest,Set)330 TEST_F(AppendTest, Set)
331 {
332     const std::set<std::string> s{"one", "two", "eight"};
333 
334     {
335         testing::InSequence seq;
336         expect_open_container(SD_BUS_TYPE_ARRAY, "s");
337         for (const auto& i : s)
338         {
339             expect_basic_string(SD_BUS_TYPE_STRING, i.c_str());
340         }
341         expect_close_container();
342     }
343     new_message().append(s);
344 }
345 
TEST_F(AppendTest,UnorderedSet)346 TEST_F(AppendTest, UnorderedSet)
347 {
348     const std::unordered_set<std::string> s{"one", "two", "eight"};
349 
350     {
351         testing::InSequence seq;
352         expect_open_container(SD_BUS_TYPE_ARRAY, "s");
353         for (const auto& i : s)
354         {
355             expect_basic_string(SD_BUS_TYPE_STRING, i.c_str());
356         }
357         expect_close_container();
358     }
359     new_message().append(s);
360 }
361 
TEST_F(AppendTest,Map)362 TEST_F(AppendTest, Map)
363 {
364     const std::map<int, std::string> m{
365         {1, "a"},
366         {2, "bc"},
367         {3, "def"},
368         {4, "ghij"},
369     };
370 
371     {
372         testing::InSequence seq;
373         expect_open_container(SD_BUS_TYPE_ARRAY, "{is}");
374         for (const auto& i : m)
375         {
376             expect_open_container(SD_BUS_TYPE_DICT_ENTRY, "is");
377             expect_basic<int>(SD_BUS_TYPE_INT32, i.first);
378             expect_basic_string(SD_BUS_TYPE_STRING, i.second.c_str());
379             expect_close_container();
380         }
381         expect_close_container();
382     }
383     new_message().append(m);
384 }
385 
TEST_F(AppendTest,UnorderedMap)386 TEST_F(AppendTest, UnorderedMap)
387 {
388     const std::unordered_map<int, bool> m{
389         {1, false},
390         {2, true},
391         {3, true},
392         {4, false},
393     };
394 
395     {
396         testing::InSequence seq;
397         expect_open_container(SD_BUS_TYPE_ARRAY, "{ib}");
398         for (const auto& i : m)
399         {
400             expect_open_container(SD_BUS_TYPE_DICT_ENTRY, "ib");
401             expect_basic<int>(SD_BUS_TYPE_INT32, i.first);
402             expect_basic<int>(SD_BUS_TYPE_BOOLEAN, i.second);
403             expect_close_container();
404         }
405         expect_close_container();
406     }
407     new_message().append(m);
408 }
409 
TEST_F(AppendTest,Tuple)410 TEST_F(AppendTest, Tuple)
411 {
412     const std::tuple<int, std::string, bool> t{5, "asdf", false};
413 
414     {
415         testing::InSequence seq;
416         expect_open_container(SD_BUS_TYPE_STRUCT, "isb");
417         expect_basic<int>(SD_BUS_TYPE_INT32, std::get<0>(t));
418         expect_basic_string(SD_BUS_TYPE_STRING, std::get<1>(t).c_str());
419         expect_basic<int>(SD_BUS_TYPE_BOOLEAN, std::get<2>(t));
420         expect_close_container();
421     }
422     new_message().append(t);
423 }
424 
TEST_F(AppendTest,Variant)425 TEST_F(AppendTest, Variant)
426 {
427     const bool b1 = false;
428     const std::string s2{"asdf"};
429     const std::variant<int, std::string, bool> v1{b1}, v2{s2};
430 
431     {
432         testing::InSequence seq;
433         expect_open_container(SD_BUS_TYPE_VARIANT, "b");
434         expect_basic<int>(SD_BUS_TYPE_BOOLEAN, b1);
435         expect_close_container();
436         expect_open_container(SD_BUS_TYPE_VARIANT, "s");
437         expect_basic_string(SD_BUS_TYPE_STRING, s2.c_str());
438         expect_close_container();
439     }
440     new_message().append(v1, v2);
441 }
442 
TEST_F(AppendTest,LargeCombo)443 TEST_F(AppendTest, LargeCombo)
444 {
445     std::vector<std::array<std::string, 3>> vas{{"a", "b", "c"},
446                                                 {"d", "", "e"}};
447     std::map<std::string, std::variant<int, double>> msv = {
448         {"a", 3.3}, {"b", 1}, {"c", 4.4}};
449 
450     {
451         testing::InSequence seq;
452 
453         expect_open_container(SD_BUS_TYPE_ARRAY, "as");
454         for (const auto& as : vas)
455         {
456             expect_open_container(SD_BUS_TYPE_ARRAY, "s");
457             for (const auto& s : as)
458             {
459                 expect_basic_string(SD_BUS_TYPE_STRING, s.c_str());
460             }
461             expect_close_container();
462         }
463         expect_close_container();
464 
465         expect_open_container(SD_BUS_TYPE_ARRAY, "{sv}");
466         for (const auto& sv : msv)
467         {
468             expect_open_container(SD_BUS_TYPE_DICT_ENTRY, "sv");
469             expect_basic_string(SD_BUS_TYPE_STRING, sv.first.c_str());
470             if (std::holds_alternative<int>(sv.second))
471             {
472                 expect_open_container(SD_BUS_TYPE_VARIANT, "i");
473                 expect_basic<int>(SD_BUS_TYPE_INT32, std::get<int>(sv.second));
474                 expect_close_container();
475             }
476             else
477             {
478                 expect_open_container(SD_BUS_TYPE_VARIANT, "d");
479                 expect_basic<double>(SD_BUS_TYPE_DOUBLE,
480                                      std::get<double>(sv.second));
481                 expect_close_container();
482             }
483             expect_close_container();
484         }
485         expect_close_container();
486     }
487     new_message().append(vas, msv);
488 }
489 
490 } // namespace
491