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