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