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