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