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 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 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> 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 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 } 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 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 88 void expect_close_container() 89 { 90 EXPECT_CALL(mock, sd_bus_message_close_container(nullptr)) 91 .WillOnce(Return(0)); 92 } 93 }; 94 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 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 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 119 TEST_F(AppendTest, RValueBool) 120 { 121 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, true); 122 new_message().append(true); 123 } 124 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 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 139 TEST_F(AppendTest, RValueDouble) 140 { 141 expect_basic<double>(SD_BUS_TYPE_DOUBLE, 1.1); 142 new_message().append(1.1); 143 } 144 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 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 159 TEST_F(AppendTest, RValueCString) 160 { 161 expect_basic_string(SD_BUS_TYPE_STRING, "asdf"); 162 new_message().append("asdf"); 163 } 164 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 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 181 TEST_F(AppendTest, RValueString) 182 { 183 expect_basic_string(SD_BUS_TYPE_STRING, "asdf"); 184 new_message().append(std::string{"asdf"}); 185 } 186 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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