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, CombinedBasic) 163 { 164 const double a = 2.2; 165 const char* const b = "ijkd"; 166 const bool c = false; 167 const int d = 18; 168 169 { 170 testing::InSequence seq; 171 expect_basic<double>(SD_BUS_TYPE_DOUBLE, a); 172 expect_basic<const char*>(SD_BUS_TYPE_STRING, b); 173 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, c); 174 expect_basic<int>(SD_BUS_TYPE_INT32, d); 175 } 176 177 double ret_a; 178 const char* ret_b; 179 bool ret_c; 180 int ret_d; 181 new_message().read(ret_a, ret_b, ret_c, ret_d); 182 EXPECT_EQ(a, ret_a); 183 EXPECT_EQ(b, ret_b); 184 EXPECT_EQ(c, ret_c); 185 EXPECT_EQ(d, ret_d); 186 } 187 188 TEST_F(ReadTest, BasicError) 189 { 190 expect_basic_error(SD_BUS_TYPE_INT32, -EINVAL); 191 int ret; 192 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 193 } 194 195 TEST_F(ReadTest, BasicStringError) 196 { 197 expect_basic_error(SD_BUS_TYPE_STRING, -EINVAL); 198 std::string ret; 199 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 200 } 201 202 TEST_F(ReadTest, BasicStringWrapperError) 203 { 204 expect_basic_error(SD_BUS_TYPE_SIGNATURE, -EINVAL); 205 sdbusplus::message::signature ret; 206 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 207 } 208 209 TEST_F(ReadTest, BasicBoolError) 210 { 211 expect_basic_error(SD_BUS_TYPE_BOOLEAN, -EINVAL); 212 bool ret; 213 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 214 } 215 216 TEST_F(ReadTest, Vector) 217 { 218 const std::vector<int> vi{1, 2, 3, 4}; 219 220 { 221 testing::InSequence seq; 222 expect_enter_container(SD_BUS_TYPE_ARRAY, "i"); 223 for (const auto& i : vi) 224 { 225 expect_at_end(false, 0); 226 expect_basic<int>(SD_BUS_TYPE_INT32, i); 227 } 228 expect_at_end(false, 1); 229 expect_exit_container(); 230 } 231 232 std::vector<int> ret_vi; 233 new_message().read(ret_vi); 234 EXPECT_EQ(vi, ret_vi); 235 } 236 237 TEST_F(ReadTest, VectorEnterError) 238 { 239 { 240 testing::InSequence seq; 241 expect_enter_container(SD_BUS_TYPE_ARRAY, "i", -EINVAL); 242 } 243 244 std::vector<int> ret; 245 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 246 } 247 248 TEST_F(ReadTest, VectorIterError) 249 { 250 { 251 testing::InSequence seq; 252 expect_enter_container(SD_BUS_TYPE_ARRAY, "i"); 253 expect_at_end(false, 0); 254 expect_basic<int>(SD_BUS_TYPE_INT32, 1); 255 expect_at_end(false, -EINVAL); 256 } 257 258 std::vector<int> ret; 259 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 260 } 261 262 TEST_F(ReadTest, VectorExitError) 263 { 264 { 265 testing::InSequence seq; 266 expect_enter_container(SD_BUS_TYPE_ARRAY, "i"); 267 expect_at_end(false, 0); 268 expect_basic<int>(SD_BUS_TYPE_INT32, 1); 269 expect_at_end(false, 0); 270 expect_basic<int>(SD_BUS_TYPE_INT32, 2); 271 expect_at_end(false, 1); 272 expect_exit_container(-EINVAL); 273 } 274 275 std::vector<int> ret; 276 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 277 } 278 279 TEST_F(ReadTest, Set) 280 { 281 const std::set<std::string> ss{"one", "two", "eight"}; 282 283 { 284 testing::InSequence seq; 285 expect_enter_container(SD_BUS_TYPE_ARRAY, "s"); 286 for (const auto& s : ss) 287 { 288 expect_at_end(false, 0); 289 expect_basic<const char*>(SD_BUS_TYPE_STRING, s.c_str()); 290 } 291 expect_at_end(false, 1); 292 expect_exit_container(); 293 } 294 295 std::set<std::string> ret_ss; 296 new_message().read(ret_ss); 297 EXPECT_EQ(ss, ret_ss); 298 } 299 300 TEST_F(ReadTest, UnorderedSet) 301 { 302 const std::unordered_set<std::string> ss{"one", "two", "eight"}; 303 304 { 305 testing::InSequence seq; 306 expect_enter_container(SD_BUS_TYPE_ARRAY, "s"); 307 for (const auto& s : ss) 308 { 309 expect_at_end(false, 0); 310 expect_basic<const char*>(SD_BUS_TYPE_STRING, s.c_str()); 311 } 312 expect_at_end(false, 1); 313 expect_exit_container(); 314 } 315 316 std::unordered_set<std::string> ret_ss; 317 new_message().read(ret_ss); 318 EXPECT_EQ(ss, ret_ss); 319 } 320 321 TEST_F(ReadTest, Map) 322 { 323 const std::map<int, std::string> mis{ 324 {1, "a"}, 325 {2, "bc"}, 326 {3, "def"}, 327 {4, "ghij"}, 328 }; 329 330 { 331 testing::InSequence seq; 332 expect_enter_container(SD_BUS_TYPE_ARRAY, "{is}"); 333 for (const auto& is : mis) 334 { 335 expect_at_end(false, 0); 336 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "is"); 337 expect_basic<int>(SD_BUS_TYPE_INT32, is.first); 338 expect_basic<const char*>(SD_BUS_TYPE_STRING, is.second.c_str()); 339 expect_exit_container(); 340 } 341 expect_at_end(false, 1); 342 expect_exit_container(); 343 } 344 345 std::map<int, std::string> ret_mis; 346 new_message().read(ret_mis); 347 EXPECT_EQ(mis, ret_mis); 348 } 349 350 TEST_F(ReadTest, MapEnterError) 351 { 352 { 353 testing::InSequence seq; 354 expect_enter_container(SD_BUS_TYPE_ARRAY, "{si}", -EINVAL); 355 } 356 357 std::map<std::string, int> ret; 358 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 359 } 360 361 TEST_F(ReadTest, MapEntryEnterError) 362 { 363 { 364 testing::InSequence seq; 365 expect_enter_container(SD_BUS_TYPE_ARRAY, "{si}"); 366 expect_at_end(false, 0); 367 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "si", -EINVAL); 368 } 369 370 std::map<std::string, int> ret; 371 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 372 } 373 374 TEST_F(ReadTest, MapEntryExitError) 375 { 376 { 377 testing::InSequence seq; 378 expect_enter_container(SD_BUS_TYPE_ARRAY, "{si}"); 379 expect_at_end(false, 0); 380 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "si"); 381 expect_basic<const char*>(SD_BUS_TYPE_STRING, "ab"); 382 expect_basic<int>(SD_BUS_TYPE_INT32, 1); 383 expect_exit_container(-EINVAL); 384 } 385 386 std::map<std::string, int> ret; 387 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 388 } 389 390 TEST_F(ReadTest, MapIterError) 391 { 392 { 393 testing::InSequence seq; 394 expect_enter_container(SD_BUS_TYPE_ARRAY, "{si}"); 395 expect_at_end(false, 0); 396 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "si"); 397 expect_basic<const char*>(SD_BUS_TYPE_STRING, "ab"); 398 expect_basic<int>(SD_BUS_TYPE_INT32, 1); 399 expect_exit_container(); 400 expect_at_end(false, -EINVAL); 401 } 402 403 std::map<std::string, int> ret; 404 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 405 } 406 407 TEST_F(ReadTest, MapExitError) 408 { 409 { 410 testing::InSequence seq; 411 expect_enter_container(SD_BUS_TYPE_ARRAY, "{si}"); 412 expect_at_end(false, 0); 413 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "si"); 414 expect_basic<const char*>(SD_BUS_TYPE_STRING, "ab"); 415 expect_basic<int>(SD_BUS_TYPE_INT32, 1); 416 expect_exit_container(); 417 expect_at_end(false, 1); 418 expect_exit_container(-EINVAL); 419 } 420 421 std::map<std::string, int> ret; 422 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 423 } 424 425 TEST_F(ReadTest, UnorderedMap) 426 { 427 const std::unordered_map<int, std::string> mis{ 428 {1, "a"}, 429 {2, "bc"}, 430 {3, "def"}, 431 {4, "ghij"}, 432 }; 433 434 { 435 testing::InSequence seq; 436 expect_enter_container(SD_BUS_TYPE_ARRAY, "{is}"); 437 for (const auto& is : mis) 438 { 439 expect_at_end(false, 0); 440 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "is"); 441 expect_basic<int>(SD_BUS_TYPE_INT32, is.first); 442 expect_basic<const char*>(SD_BUS_TYPE_STRING, is.second.c_str()); 443 expect_exit_container(); 444 } 445 expect_at_end(false, 1); 446 expect_exit_container(); 447 } 448 449 std::unordered_map<int, std::string> ret_mis; 450 new_message().read(ret_mis); 451 EXPECT_EQ(mis, ret_mis); 452 } 453 454 TEST_F(ReadTest, Tuple) 455 { 456 const std::tuple<int, std::string, bool> tisb{3, "hi", false}; 457 458 { 459 testing::InSequence seq; 460 expect_enter_container(SD_BUS_TYPE_STRUCT, "isb"); 461 expect_basic<int>(SD_BUS_TYPE_INT32, std::get<0>(tisb)); 462 expect_basic<const char*>(SD_BUS_TYPE_STRING, 463 std::get<1>(tisb).c_str()); 464 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, std::get<2>(tisb)); 465 expect_exit_container(); 466 } 467 468 std::tuple<int, std::string, bool> ret_tisb; 469 new_message().read(ret_tisb); 470 EXPECT_EQ(tisb, ret_tisb); 471 } 472 473 TEST_F(ReadTest, TupleEnterError) 474 { 475 { 476 testing::InSequence seq; 477 expect_enter_container(SD_BUS_TYPE_STRUCT, "bis", -EINVAL); 478 } 479 480 std::tuple<bool, int, std::string> ret; 481 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 482 } 483 484 TEST_F(ReadTest, TupleExitError) 485 { 486 { 487 testing::InSequence seq; 488 expect_enter_container(SD_BUS_TYPE_STRUCT, "bis"); 489 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, false); 490 expect_basic<int>(SD_BUS_TYPE_INT32, 1); 491 expect_basic<const char*>(SD_BUS_TYPE_STRING, "ab"); 492 expect_exit_container(-EINVAL); 493 } 494 495 std::tuple<bool, int, std::string> ret; 496 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 497 } 498 499 TEST_F(ReadTest, Variant) 500 { 501 const bool b1 = false; 502 const std::string s2{"asdf"}; 503 const std::variant<int, std::string, bool> v1{b1}, v2{s2}; 504 505 { 506 testing::InSequence seq; 507 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", false); 508 expect_verify_type(SD_BUS_TYPE_VARIANT, "s", false); 509 expect_verify_type(SD_BUS_TYPE_VARIANT, "b", true); 510 expect_enter_container(SD_BUS_TYPE_VARIANT, "b"); 511 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, b1); 512 expect_exit_container(); 513 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", false); 514 expect_verify_type(SD_BUS_TYPE_VARIANT, "s", true); 515 expect_enter_container(SD_BUS_TYPE_VARIANT, "s"); 516 expect_basic<const char*>(SD_BUS_TYPE_STRING, s2.c_str()); 517 expect_exit_container(); 518 } 519 520 std::variant<int, std::string, bool> ret_v1, ret_v2; 521 new_message().read(ret_v1, ret_v2); 522 EXPECT_EQ(v1, ret_v1); 523 EXPECT_EQ(v2, ret_v2); 524 } 525 526 TEST_F(ReadTest, VariantVerifyError) 527 { 528 { 529 testing::InSequence seq; 530 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", -EINVAL); 531 } 532 533 std::variant<int, bool> ret; 534 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 535 } 536 537 TEST_F(ReadTest, VariantSkipUnmatched) 538 { 539 { 540 testing::InSequence seq; 541 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", false); 542 expect_verify_type(SD_BUS_TYPE_VARIANT, "b", false); 543 expect_skip("v"); 544 } 545 546 std::variant<int, bool> ret; 547 new_message().read(ret); 548 } 549 550 TEST_F(ReadTest, VariantSkipError) 551 { 552 { 553 testing::InSequence seq; 554 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", false); 555 expect_verify_type(SD_BUS_TYPE_VARIANT, "b", false); 556 expect_skip("v", -EINVAL); 557 } 558 559 std::variant<int, bool> ret; 560 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 561 } 562 563 TEST_F(ReadTest, VariantEnterError) 564 { 565 { 566 testing::InSequence seq; 567 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", true); 568 expect_enter_container(SD_BUS_TYPE_VARIANT, "i", -EINVAL); 569 } 570 571 std::variant<int, bool> ret; 572 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 573 } 574 575 TEST_F(ReadTest, VariantExitError) 576 { 577 { 578 testing::InSequence seq; 579 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", true); 580 expect_enter_container(SD_BUS_TYPE_VARIANT, "i"); 581 expect_basic<int>(SD_BUS_TYPE_INT32, 10); 582 expect_exit_container(-EINVAL); 583 } 584 585 std::variant<int, bool> ret; 586 EXPECT_THROW(new_message().read(ret), sdbusplus::exception::SdBusError); 587 } 588 589 TEST_F(ReadTest, LargeCombo) 590 { 591 const std::vector<std::set<std::string>> vas{ 592 {"a", "b", "c"}, 593 {"d", "", "e"}, 594 }; 595 const std::map<std::string, std::variant<int, double>> msv = { 596 {"a", 3.3}, {"b", 1}, {"c", 4.4}}; 597 598 { 599 testing::InSequence seq; 600 601 expect_enter_container(SD_BUS_TYPE_ARRAY, "as"); 602 for (const auto& as : vas) 603 { 604 expect_at_end(false, 0); 605 expect_enter_container(SD_BUS_TYPE_ARRAY, "s"); 606 for (const auto& s : as) 607 { 608 expect_at_end(false, 0); 609 expect_basic<const char*>(SD_BUS_TYPE_STRING, s.c_str()); 610 } 611 expect_at_end(false, 1); 612 expect_exit_container(); 613 } 614 expect_at_end(false, 1); 615 expect_exit_container(); 616 617 expect_enter_container(SD_BUS_TYPE_ARRAY, "{sv}"); 618 for (const auto& sv : msv) 619 { 620 expect_at_end(false, 0); 621 expect_enter_container(SD_BUS_TYPE_DICT_ENTRY, "sv"); 622 expect_basic<const char*>(SD_BUS_TYPE_STRING, sv.first.c_str()); 623 if (std::holds_alternative<int>(sv.second)) 624 { 625 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", true); 626 expect_enter_container(SD_BUS_TYPE_VARIANT, "i"); 627 expect_basic<int>(SD_BUS_TYPE_INT32, std::get<int>(sv.second)); 628 expect_exit_container(); 629 } 630 else 631 { 632 expect_verify_type(SD_BUS_TYPE_VARIANT, "i", false); 633 expect_verify_type(SD_BUS_TYPE_VARIANT, "d", true); 634 expect_enter_container(SD_BUS_TYPE_VARIANT, "d"); 635 expect_basic<double>(SD_BUS_TYPE_DOUBLE, 636 std::get<double>(sv.second)); 637 expect_exit_container(); 638 } 639 expect_exit_container(); 640 } 641 expect_at_end(false, 1); 642 expect_exit_container(); 643 } 644 645 std::vector<std::set<std::string>> ret_vas; 646 std::map<std::string, std::variant<int, double>> ret_msv; 647 new_message().read(ret_vas, ret_msv); 648 EXPECT_EQ(vas, ret_vas); 649 EXPECT_EQ(msv, ret_msv); 650 } 651 652 // Unpack tests. 653 // Since unpack uses read, we're mostly just testing the compilation. 654 // Duplicate a few tests from Read using 'unpack'. 655 656 TEST_F(ReadTest, UnpackSingleVector) 657 { 658 const std::vector<int> vi{1, 2, 3, 4}; 659 660 { 661 testing::InSequence seq; 662 expect_enter_container(SD_BUS_TYPE_ARRAY, "i"); 663 for (const auto& i : vi) 664 { 665 expect_at_end(false, 0); 666 expect_basic<int>(SD_BUS_TYPE_INT32, i); 667 } 668 expect_at_end(false, 1); 669 expect_exit_container(); 670 } 671 672 auto ret_vi = new_message().unpack<std::vector<int>>(); 673 EXPECT_EQ(vi, ret_vi); 674 } 675 676 TEST_F(ReadTest, UnpackMultiple) 677 { 678 const std::tuple<int, std::string, bool> tisb{3, "hi", false}; 679 680 { 681 testing::InSequence seq; 682 expect_basic<int>(SD_BUS_TYPE_INT32, std::get<0>(tisb)); 683 expect_basic<const char*>(SD_BUS_TYPE_STRING, 684 std::get<1>(tisb).c_str()); 685 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, std::get<2>(tisb)); 686 } 687 688 auto ret_tisb = new_message().unpack<int, std::string, bool>(); 689 EXPECT_EQ(tisb, ret_tisb); 690 } 691 692 } // namespace 693