1 #include <systemd/sd-bus-protocol.h> 2 3 #include <cerrno> 4 #include <map> 5 #include <sdbusplus/exception.hpp> 6 #include <sdbusplus/message.hpp> 7 #include <sdbusplus/test/sdbus_mock.hpp> 8 #include <set> 9 #include <string> 10 #include <tuple> 11 #include <unordered_map> 12 #include <vector> 13 14 #include <gmock/gmock.h> 15 #include <gtest/gtest.h> 16 17 namespace 18 { 19 20 namespace variant_ns = sdbusplus::message::variant_ns; 21 using testing::DoAll; 22 using testing::Return; 23 using testing::StrEq; 24 25 ACTION_TEMPLATE(AssignReadVal, HAS_1_TEMPLATE_PARAMS(typename, T), 26 AND_1_VALUE_PARAMS(val)) 27 { 28 *static_cast<T*>(arg2) = val; 29 } 30 31 class ReadTest : public testing::Test 32 { 33 protected: 34 testing::StrictMock<sdbusplus::SdBusMock> mock; 35 36 void SetUp() override 37 { 38 EXPECT_CALL(mock, sd_bus_message_new_method_call(testing::_, testing::_, 39 nullptr, nullptr, 40 nullptr, nullptr)) 41 .WillRepeatedly(Return(0)); 42 }; 43 44 sdbusplus::message::message new_message() 45 { 46 return sdbusplus::get_mocked_new(&mock).new_method_call( 47 nullptr, nullptr, nullptr, nullptr); 48 } 49 50 void expect_basic_error(char type, int ret) 51 { 52 EXPECT_CALL(mock, sd_bus_message_read_basic(nullptr, type, testing::_)) 53 .WillOnce(Return(ret)); 54 } 55 56 template <typename T> 57 void expect_basic(char type, T val) 58 { 59 EXPECT_CALL(mock, sd_bus_message_read_basic(nullptr, type, testing::_)) 60 .WillOnce(DoAll(AssignReadVal<T>(val), Return(0))); 61 } 62 63 void expect_verify_type(char type, const char* contents, int ret) 64 { 65 EXPECT_CALL(mock, 66 sd_bus_message_verify_type(nullptr, type, StrEq(contents))) 67 .WillOnce(Return(ret)); 68 } 69 70 void expect_at_end(bool complete, int ret) 71 { 72 EXPECT_CALL(mock, sd_bus_message_at_end(nullptr, complete)) 73 .WillOnce(Return(ret)); 74 } 75 76 void expect_skip(const char* contents, int ret = 0) 77 { 78 EXPECT_CALL(mock, sd_bus_message_skip(nullptr, StrEq(contents))) 79 .WillOnce(Return(ret)); 80 } 81 82 void expect_enter_container(char type, const char* contents, int ret = 0) 83 { 84 EXPECT_CALL(mock, sd_bus_message_enter_container(nullptr, type, 85 StrEq(contents))) 86 .WillOnce(Return(ret)); 87 } 88 89 void expect_exit_container(int ret = 0) 90 { 91 EXPECT_CALL(mock, sd_bus_message_exit_container(nullptr)) 92 .WillOnce(Return(ret)); 93 } 94 }; 95 96 TEST_F(ReadTest, Int) 97 { 98 const int i = 1; 99 expect_basic<int>(SD_BUS_TYPE_INT32, i); 100 int ret; 101 new_message().read(ret); 102 EXPECT_EQ(i, ret); 103 } 104 105 TEST_F(ReadTest, Bool) 106 { 107 const bool b = true; 108 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, b); 109 bool ret; 110 new_message().read(ret); 111 EXPECT_EQ(b, ret); 112 } 113 114 TEST_F(ReadTest, Double) 115 { 116 const double d = 1.1; 117 expect_basic<double>(SD_BUS_TYPE_DOUBLE, d); 118 double ret; 119 new_message().read(ret); 120 EXPECT_EQ(d, ret); 121 } 122 123 TEST_F(ReadTest, CString) 124 { 125 const char* const s = "asdf"; 126 expect_basic<const char*>(SD_BUS_TYPE_STRING, s); 127 const char* ret; 128 new_message().read(ret); 129 EXPECT_EQ(s, ret); 130 } 131 132 TEST_F(ReadTest, String) 133 { 134 const char* const s = "fsda"; 135 expect_basic<const char*>(SD_BUS_TYPE_STRING, s); 136 std::string ret; 137 new_message().read(ret); 138 // Pointer comparison here is intentional as we don't expect a copy 139 EXPECT_EQ(s, ret); 140 } 141 142 TEST_F(ReadTest, ObjectPath) 143 { 144 const char* const s = "/fsda"; 145 expect_basic<const char*>(SD_BUS_TYPE_OBJECT_PATH, s); 146 sdbusplus::message::object_path ret; 147 new_message().read(ret); 148 EXPECT_EQ(s, ret.str); 149 } 150 151 TEST_F(ReadTest, Signature) 152 { 153 const char* const s = "{ii}"; 154 expect_basic<const char*>(SD_BUS_TYPE_SIGNATURE, s); 155 sdbusplus::message::signature ret; 156 new_message().read(ret); 157 EXPECT_EQ(s, ret.str); 158 } 159 160 TEST_F(ReadTest, CombinedBasic) 161 { 162 const double a = 2.2; 163 const char* const b = "ijkd"; 164 const bool c = false; 165 const int d = 18; 166 167 { 168 testing::InSequence seq; 169 expect_basic<double>(SD_BUS_TYPE_DOUBLE, a); 170 expect_basic<const char*>(SD_BUS_TYPE_STRING, b); 171 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, c); 172 expect_basic<int>(SD_BUS_TYPE_INT32, d); 173 } 174 175 double ret_a; 176 const char* ret_b; 177 bool ret_c; 178 int ret_d; 179 new_message().read(ret_a, ret_b, ret_c, ret_d); 180 EXPECT_EQ(a, ret_a); 181 EXPECT_EQ(b, ret_b); 182 EXPECT_EQ(c, ret_c); 183 EXPECT_EQ(d, ret_d); 184 } 185 186 TEST_F(ReadTest, BasicError) 187 { 188 expect_basic_error(SD_BUS_TYPE_INT32, -EINVAL); 189 int ret; 190 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 191 } 192 193 TEST_F(ReadTest, BasicStringError) 194 { 195 expect_basic_error(SD_BUS_TYPE_STRING, -EINVAL); 196 std::string ret; 197 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 198 } 199 200 TEST_F(ReadTest, BasicStringWrapperError) 201 { 202 expect_basic_error(SD_BUS_TYPE_SIGNATURE, -EINVAL); 203 sdbusplus::message::signature ret; 204 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 205 } 206 207 TEST_F(ReadTest, BasicBoolError) 208 { 209 expect_basic_error(SD_BUS_TYPE_BOOLEAN, -EINVAL); 210 bool ret; 211 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 212 } 213 214 TEST_F(ReadTest, Vector) 215 { 216 const std::vector<int> vi{1, 2, 3, 4}; 217 218 { 219 testing::InSequence seq; 220 expect_enter_container(SD_BUS_TYPE_ARRAY, "i"); 221 for (const auto& i : vi) 222 { 223 expect_at_end(false, 0); 224 expect_basic<int>(SD_BUS_TYPE_INT32, i); 225 } 226 expect_at_end(false, 1); 227 expect_exit_container(); 228 } 229 230 std::vector<int> ret_vi; 231 new_message().read(ret_vi); 232 EXPECT_EQ(vi, ret_vi); 233 } 234 235 TEST_F(ReadTest, VectorEnterError) 236 { 237 { 238 testing::InSequence seq; 239 expect_enter_container(SD_BUS_TYPE_ARRAY, "i", -EINVAL); 240 } 241 242 std::vector<int> ret; 243 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 244 } 245 246 TEST_F(ReadTest, VectorIterError) 247 { 248 { 249 testing::InSequence seq; 250 expect_enter_container(SD_BUS_TYPE_ARRAY, "i"); 251 expect_at_end(false, 0); 252 expect_basic<int>(SD_BUS_TYPE_INT32, 1); 253 expect_at_end(false, -EINVAL); 254 } 255 256 std::vector<int> ret; 257 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 258 } 259 260 TEST_F(ReadTest, VectorExitError) 261 { 262 { 263 testing::InSequence seq; 264 expect_enter_container(SD_BUS_TYPE_ARRAY, "i"); 265 expect_at_end(false, 0); 266 expect_basic<int>(SD_BUS_TYPE_INT32, 1); 267 expect_at_end(false, 0); 268 expect_basic<int>(SD_BUS_TYPE_INT32, 2); 269 expect_at_end(false, 1); 270 expect_exit_container(-EINVAL); 271 } 272 273 std::vector<int> ret; 274 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 275 } 276 277 TEST_F(ReadTest, Set) 278 { 279 const std::set<std::string> ss{"one", "two", "eight"}; 280 281 { 282 testing::InSequence seq; 283 expect_enter_container(SD_BUS_TYPE_ARRAY, "s"); 284 for (const auto& s : ss) 285 { 286 expect_at_end(false, 0); 287 expect_basic<const char*>(SD_BUS_TYPE_STRING, s.c_str()); 288 } 289 expect_at_end(false, 1); 290 expect_exit_container(); 291 } 292 293 std::set<std::string> ret_ss; 294 new_message().read(ret_ss); 295 EXPECT_EQ(ss, ret_ss); 296 } 297 298 TEST_F(ReadTest, Map) 299 { 300 const std::map<int, std::string> mis{ 301 {1, "a"}, 302 {2, "bc"}, 303 {3, "def"}, 304 {4, "ghij"}, 305 }; 306 307 { 308 testing::InSequence seq; 309 expect_enter_container(SD_BUS_TYPE_ARRAY, "{is}"); 310 for (const auto& is : mis) 311 { 312 expect_at_end(false, 0); 313 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "is"); 314 expect_basic<int>(SD_BUS_TYPE_INT32, is.first); 315 expect_basic<const char*>(SD_BUS_TYPE_STRING, is.second.c_str()); 316 expect_exit_container(); 317 } 318 expect_at_end(false, 1); 319 expect_exit_container(); 320 } 321 322 std::map<int, std::string> ret_mis; 323 new_message().read(ret_mis); 324 EXPECT_EQ(mis, ret_mis); 325 } 326 327 TEST_F(ReadTest, MapEnterError) 328 { 329 { 330 testing::InSequence seq; 331 expect_enter_container(SD_BUS_TYPE_ARRAY, "{si}", -EINVAL); 332 } 333 334 std::map<std::string, int> ret; 335 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 336 } 337 338 TEST_F(ReadTest, MapEntryEnterError) 339 { 340 { 341 testing::InSequence seq; 342 expect_enter_container(SD_BUS_TYPE_ARRAY, "{si}"); 343 expect_at_end(false, 0); 344 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "si", -EINVAL); 345 } 346 347 std::map<std::string, int> ret; 348 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 349 } 350 351 TEST_F(ReadTest, MapEntryExitError) 352 { 353 { 354 testing::InSequence seq; 355 expect_enter_container(SD_BUS_TYPE_ARRAY, "{si}"); 356 expect_at_end(false, 0); 357 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "si"); 358 expect_basic<const char*>(SD_BUS_TYPE_STRING, "ab"); 359 expect_basic<int>(SD_BUS_TYPE_INT32, 1); 360 expect_exit_container(-EINVAL); 361 } 362 363 std::map<std::string, int> ret; 364 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 365 } 366 367 TEST_F(ReadTest, MapIterError) 368 { 369 { 370 testing::InSequence seq; 371 expect_enter_container(SD_BUS_TYPE_ARRAY, "{si}"); 372 expect_at_end(false, 0); 373 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "si"); 374 expect_basic<const char*>(SD_BUS_TYPE_STRING, "ab"); 375 expect_basic<int>(SD_BUS_TYPE_INT32, 1); 376 expect_exit_container(); 377 expect_at_end(false, -EINVAL); 378 } 379 380 std::map<std::string, int> ret; 381 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 382 } 383 384 TEST_F(ReadTest, MapExitError) 385 { 386 { 387 testing::InSequence seq; 388 expect_enter_container(SD_BUS_TYPE_ARRAY, "{si}"); 389 expect_at_end(false, 0); 390 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "si"); 391 expect_basic<const char*>(SD_BUS_TYPE_STRING, "ab"); 392 expect_basic<int>(SD_BUS_TYPE_INT32, 1); 393 expect_exit_container(); 394 expect_at_end(false, 1); 395 expect_exit_container(-EINVAL); 396 } 397 398 std::map<std::string, int> ret; 399 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 400 } 401 402 TEST_F(ReadTest, UnorderedMap) 403 { 404 const std::unordered_map<int, std::string> mis{ 405 {1, "a"}, 406 {2, "bc"}, 407 {3, "def"}, 408 {4, "ghij"}, 409 }; 410 411 { 412 testing::InSequence seq; 413 expect_enter_container(SD_BUS_TYPE_ARRAY, "{is}"); 414 for (const auto& is : mis) 415 { 416 expect_at_end(false, 0); 417 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "is"); 418 expect_basic<int>(SD_BUS_TYPE_INT32, is.first); 419 expect_basic<const char*>(SD_BUS_TYPE_STRING, is.second.c_str()); 420 expect_exit_container(); 421 } 422 expect_at_end(false, 1); 423 expect_exit_container(); 424 } 425 426 std::unordered_map<int, std::string> ret_mis; 427 new_message().read(ret_mis); 428 EXPECT_EQ(mis, ret_mis); 429 } 430 431 TEST_F(ReadTest, Tuple) 432 { 433 const std::tuple<int, std::string, bool> tisb{3, "hi", false}; 434 435 { 436 testing::InSequence seq; 437 expect_enter_container(SD_BUS_TYPE_STRUCT, "isb"); 438 expect_basic<int>(SD_BUS_TYPE_INT32, std::get<0>(tisb)); 439 expect_basic<const char*>(SD_BUS_TYPE_STRING, 440 std::get<1>(tisb).c_str()); 441 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, std::get<2>(tisb)); 442 expect_exit_container(); 443 } 444 445 std::tuple<int, std::string, bool> ret_tisb; 446 new_message().read(ret_tisb); 447 EXPECT_EQ(tisb, ret_tisb); 448 } 449 450 TEST_F(ReadTest, TupleEnterError) 451 { 452 { 453 testing::InSequence seq; 454 expect_enter_container(SD_BUS_TYPE_STRUCT, "bis", -EINVAL); 455 } 456 457 std::tuple<bool, int, std::string> ret; 458 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 459 } 460 461 TEST_F(ReadTest, TupleExitError) 462 { 463 { 464 testing::InSequence seq; 465 expect_enter_container(SD_BUS_TYPE_STRUCT, "bis"); 466 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, false); 467 expect_basic<int>(SD_BUS_TYPE_INT32, 1); 468 expect_basic<const char*>(SD_BUS_TYPE_STRING, "ab"); 469 expect_exit_container(-EINVAL); 470 } 471 472 std::tuple<bool, int, std::string> ret; 473 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 474 } 475 476 TEST_F(ReadTest, Variant) 477 { 478 const bool b1 = false; 479 const std::string s2{"asdf"}; 480 const sdbusplus::message::variant<int, std::string, bool> v1{b1}, v2{s2}; 481 482 { 483 testing::InSequence seq; 484 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", false); 485 expect_verify_type(SD_BUS_TYPE_VARIANT, "s", false); 486 expect_verify_type(SD_BUS_TYPE_VARIANT, "b", true); 487 expect_enter_container(SD_BUS_TYPE_VARIANT, "b"); 488 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, b1); 489 expect_exit_container(); 490 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", false); 491 expect_verify_type(SD_BUS_TYPE_VARIANT, "s", true); 492 expect_enter_container(SD_BUS_TYPE_VARIANT, "s"); 493 expect_basic<const char*>(SD_BUS_TYPE_STRING, s2.c_str()); 494 expect_exit_container(); 495 } 496 497 sdbusplus::message::variant<int, std::string, bool> ret_v1, ret_v2; 498 new_message().read(ret_v1, ret_v2); 499 EXPECT_EQ(v1, ret_v1); 500 EXPECT_EQ(v2, ret_v2); 501 } 502 503 TEST_F(ReadTest, VariantVerifyError) 504 { 505 { 506 testing::InSequence seq; 507 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", -EINVAL); 508 } 509 510 sdbusplus::message::variant<int, bool> ret; 511 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 512 } 513 514 TEST_F(ReadTest, VariantSkipUnmatched) 515 { 516 { 517 testing::InSequence seq; 518 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", false); 519 expect_verify_type(SD_BUS_TYPE_VARIANT, "b", false); 520 expect_skip("v"); 521 } 522 523 sdbusplus::message::variant<int, bool> ret; 524 new_message().read(ret); 525 } 526 527 TEST_F(ReadTest, VariantSkipError) 528 { 529 { 530 testing::InSequence seq; 531 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", false); 532 expect_verify_type(SD_BUS_TYPE_VARIANT, "b", false); 533 expect_skip("v", -EINVAL); 534 } 535 536 sdbusplus::message::variant<int, bool> ret; 537 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 538 } 539 540 TEST_F(ReadTest, VariantEnterError) 541 { 542 { 543 testing::InSequence seq; 544 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", true); 545 expect_enter_container(SD_BUS_TYPE_VARIANT, "i", -EINVAL); 546 } 547 548 sdbusplus::message::variant<int, bool> ret; 549 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 550 } 551 552 TEST_F(ReadTest, VariantExitError) 553 { 554 { 555 testing::InSequence seq; 556 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", true); 557 expect_enter_container(SD_BUS_TYPE_VARIANT, "i"); 558 expect_basic<int>(SD_BUS_TYPE_INT32, 10); 559 expect_exit_container(-EINVAL); 560 } 561 562 sdbusplus::message::variant<int, bool> ret; 563 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 564 } 565 566 TEST_F(ReadTest, LargeCombo) 567 { 568 const std::vector<std::set<std::string>> vas{ 569 {"a", "b", "c"}, 570 {"d", "", "e"}, 571 }; 572 const std::map<std::string, sdbusplus::message::variant<int, double>> msv = 573 {{"a", 3.3}, {"b", 1}, {"c", 4.4}}; 574 575 { 576 testing::InSequence seq; 577 578 expect_enter_container(SD_BUS_TYPE_ARRAY, "as"); 579 for (const auto& as : vas) 580 { 581 expect_at_end(false, 0); 582 expect_enter_container(SD_BUS_TYPE_ARRAY, "s"); 583 for (const auto& s : as) 584 { 585 expect_at_end(false, 0); 586 expect_basic<const char*>(SD_BUS_TYPE_STRING, s.c_str()); 587 } 588 expect_at_end(false, 1); 589 expect_exit_container(); 590 } 591 expect_at_end(false, 1); 592 expect_exit_container(); 593 594 expect_enter_container(SD_BUS_TYPE_ARRAY, "{sv}"); 595 for (const auto& sv : msv) 596 { 597 expect_at_end(false, 0); 598 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "sv"); 599 expect_basic<const char*>(SD_BUS_TYPE_STRING, sv.first.c_str()); 600 if (variant_ns::holds_alternative<int>(sv.second)) 601 { 602 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", true); 603 expect_enter_container(SD_BUS_TYPE_VARIANT, "i"); 604 expect_basic<int>(SD_BUS_TYPE_INT32, 605 variant_ns::get<int>(sv.second)); 606 expect_exit_container(); 607 } 608 else 609 { 610 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", false); 611 expect_verify_type(SD_BUS_TYPE_VARIANT, "d", true); 612 expect_enter_container(SD_BUS_TYPE_VARIANT, "d"); 613 expect_basic<double>(SD_BUS_TYPE_DOUBLE, 614 variant_ns::get<double>(sv.second)); 615 expect_exit_container(); 616 } 617 expect_exit_container(); 618 } 619 expect_at_end(false, 1); 620 expect_exit_container(); 621 } 622 623 std::vector<std::set<std::string>> ret_vas; 624 std::map<std::string, sdbusplus::message::variant<int, double>> ret_msv; 625 new_message().read(ret_vas, ret_msv); 626 EXPECT_EQ(vas, ret_vas); 627 EXPECT_EQ(msv, ret_msv); 628 } 629 630 } // namespace 631