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