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