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