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