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