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