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