| #include <array> |
| #include <gtest/gtest.h> |
| #include <gmock/gmock.h> |
| #include <map> |
| #include <sdbusplus/message.hpp> |
| #include <sdbusplus/test/sdbus_mock.hpp> |
| #include <set> |
| #include <string> |
| #include <systemd/sd-bus-protocol.h> |
| #include <tuple> |
| #include <unordered_map> |
| #include <vector> |
| |
| namespace |
| { |
| |
| using testing::Eq; |
| using testing::MatcherCast; |
| using testing::Pointee; |
| using testing::Return; |
| using testing::SafeMatcherCast; |
| using testing::StrEq; |
| |
| class AppendTest : public testing::Test |
| { |
| protected: |
| testing::StrictMock<sdbusplus::SdBusMock> mock; |
| |
| void SetUp() override |
| { |
| EXPECT_CALL(mock, sd_bus_message_new_method_call(testing::_, testing::_, |
| nullptr, nullptr, |
| nullptr, nullptr)) |
| .WillRepeatedly(Return(0)); |
| }; |
| |
| sdbusplus::message::message new_message() |
| { |
| return sdbusplus::get_mocked_new(&mock).new_method_call( |
| nullptr, nullptr, nullptr, nullptr); |
| } |
| |
| template <typename T> void expect_basic(char type, T val) |
| { |
| EXPECT_CALL(mock, |
| sd_bus_message_append_basic( |
| nullptr, type, |
| MatcherCast<const void *>( |
| SafeMatcherCast<const T *>(Pointee(Eq(val)))))) |
| .WillOnce(Return(0)); |
| } |
| |
| void expect_basic_string(char type, const char *str) |
| { |
| EXPECT_CALL(mock, sd_bus_message_append_basic( |
| nullptr, type, |
| MatcherCast<const void *>( |
| SafeMatcherCast<const char *>(StrEq(str))))) |
| .WillOnce(Return(0)); |
| } |
| |
| void expect_open_container(char type, const char *contents) |
| { |
| EXPECT_CALL( |
| mock, sd_bus_message_open_container(nullptr, type, StrEq(contents))) |
| .WillOnce(Return(0)); |
| } |
| |
| void expect_close_container() |
| { |
| EXPECT_CALL(mock, sd_bus_message_close_container(nullptr)) |
| .WillOnce(Return(0)); |
| } |
| }; |
| |
| TEST_F(AppendTest, RValueInt) |
| { |
| expect_basic<int>(SD_BUS_TYPE_INT32, 1); |
| new_message().append(1); |
| } |
| |
| TEST_F(AppendTest, LValueInt) |
| { |
| const int a = 1; |
| expect_basic<int>(SD_BUS_TYPE_INT32, a); |
| new_message().append(a); |
| } |
| |
| TEST_F(AppendTest, XValueInt) |
| { |
| int a = 1; |
| expect_basic<int>(SD_BUS_TYPE_INT32, a); |
| new_message().append(std::move(a)); |
| } |
| |
| TEST_F(AppendTest, RValueBool) |
| { |
| expect_basic<int>(SD_BUS_TYPE_BOOLEAN, true); |
| new_message().append(true); |
| } |
| |
| TEST_F(AppendTest, LValueBool) |
| { |
| const bool a = false; |
| expect_basic<int>(SD_BUS_TYPE_BOOLEAN, false); |
| new_message().append(a); |
| } |
| |
| TEST_F(AppendTest, XValueBool) |
| { |
| bool a = false; |
| expect_basic<int>(SD_BUS_TYPE_BOOLEAN, false); |
| new_message().append(std::move(a)); |
| } |
| |
| TEST_F(AppendTest, RValueDouble) |
| { |
| expect_basic<double>(SD_BUS_TYPE_DOUBLE, 1.1); |
| new_message().append(1.1); |
| } |
| |
| TEST_F(AppendTest, LValueDouble) |
| { |
| const double a = 1.1; |
| expect_basic<double>(SD_BUS_TYPE_DOUBLE, a); |
| new_message().append(a); |
| } |
| |
| TEST_F(AppendTest, XValueDouble) |
| { |
| double a = 1.1; |
| expect_basic<double>(SD_BUS_TYPE_DOUBLE, a); |
| new_message().append(std::move(a)); |
| } |
| |
| TEST_F(AppendTest, RValueCString) |
| { |
| expect_basic_string(SD_BUS_TYPE_STRING, "asdf"); |
| new_message().append("asdf"); |
| } |
| |
| TEST_F(AppendTest, LValueCString) |
| { |
| const char *const s = "asdf"; |
| expect_basic_string(SD_BUS_TYPE_STRING, s); |
| new_message().append(s); |
| } |
| |
| TEST_F(AppendTest, XValueCString) |
| { |
| const char *s = "asdf"; |
| expect_basic_string(SD_BUS_TYPE_STRING, s); |
| new_message().append(std::move(s)); |
| } |
| |
| TEST_F(AppendTest, RValueString) |
| { |
| expect_basic_string(SD_BUS_TYPE_STRING, "asdf"); |
| new_message().append(std::string{"asdf"}); |
| } |
| |
| TEST_F(AppendTest, LValueString) |
| { |
| std::string s{"asdf"}; |
| expect_basic_string(SD_BUS_TYPE_STRING, s.c_str()); |
| new_message().append(s); |
| } |
| |
| TEST_F(AppendTest, XValueString) |
| { |
| std::string s{"asdf"}; |
| expect_basic_string(SD_BUS_TYPE_STRING, s.c_str()); |
| new_message().append(std::move(s)); |
| } |
| |
| TEST_F(AppendTest, ObjectPath) |
| { |
| sdbusplus::message::object_path o{"/asdf"}; |
| expect_basic_string(SD_BUS_TYPE_OBJECT_PATH, o.str.c_str()); |
| new_message().append(o); |
| } |
| |
| TEST_F(AppendTest, Signature) |
| { |
| sdbusplus::message::signature g{"ii"}; |
| expect_basic_string(SD_BUS_TYPE_SIGNATURE, g.str.c_str()); |
| new_message().append(g); |
| } |
| |
| TEST_F(AppendTest, CombinedBasic) |
| { |
| const int c = 3; |
| const std::string s1{"fdsa"}; |
| const char *const s2 = "asdf"; |
| |
| { |
| testing::InSequence seq; |
| expect_basic<int>(SD_BUS_TYPE_INT32, 1); |
| expect_basic<double>(SD_BUS_TYPE_DOUBLE, 2.2); |
| expect_basic<int>(SD_BUS_TYPE_INT32, c); |
| expect_basic_string(SD_BUS_TYPE_STRING, s1.c_str()); |
| expect_basic<int>(SD_BUS_TYPE_BOOLEAN, false); |
| expect_basic_string(SD_BUS_TYPE_STRING, s2); |
| } |
| new_message().append(1, 2.2, c, s1, false, s2); |
| } |
| |
| TEST_F(AppendTest, Array) |
| { |
| const std::array<double, 4> a{1.1, 2.2, 3.3, 4.4}; |
| |
| { |
| testing::InSequence seq; |
| expect_open_container(SD_BUS_TYPE_ARRAY, "d"); |
| for (const auto &i : a) |
| { |
| expect_basic<double>(SD_BUS_TYPE_DOUBLE, i); |
| } |
| expect_close_container(); |
| } |
| new_message().append(a); |
| } |
| |
| TEST_F(AppendTest, Vector) |
| { |
| const std::vector<int> v{1, 2, 3, 4}; |
| |
| { |
| testing::InSequence seq; |
| expect_open_container(SD_BUS_TYPE_ARRAY, "i"); |
| for (const auto &i : v) |
| { |
| expect_basic<int>(SD_BUS_TYPE_INT32, i); |
| } |
| expect_close_container(); |
| } |
| new_message().append(v); |
| } |
| |
| TEST_F(AppendTest, Set) |
| { |
| const std::set<std::string> s{"one", "two", "eight"}; |
| |
| { |
| testing::InSequence seq; |
| expect_open_container(SD_BUS_TYPE_ARRAY, "s"); |
| for (const auto &i : s) |
| { |
| expect_basic_string(SD_BUS_TYPE_STRING, i.c_str()); |
| } |
| expect_close_container(); |
| } |
| new_message().append(s); |
| } |
| |
| TEST_F(AppendTest, Map) |
| { |
| const std::map<int, std::string> m{ |
| {1, "a"}, |
| {2, "bc"}, |
| {3, "def"}, |
| {4, "ghij"}, |
| }; |
| |
| { |
| testing::InSequence seq; |
| expect_open_container(SD_BUS_TYPE_ARRAY, "{is}"); |
| for (const auto &i : m) |
| { |
| expect_open_container(SD_BUS_TYPE_DICT_ENTRY, "is"); |
| expect_basic<int>(SD_BUS_TYPE_INT32, i.first); |
| expect_basic_string(SD_BUS_TYPE_STRING, i.second.c_str()); |
| expect_close_container(); |
| } |
| expect_close_container(); |
| } |
| new_message().append(m); |
| } |
| |
| TEST_F(AppendTest, UnorderedMap) |
| { |
| const std::unordered_map<int, bool> m{ |
| {1, false}, |
| {2, true}, |
| {3, true}, |
| {4, false}, |
| }; |
| |
| { |
| testing::InSequence seq; |
| expect_open_container(SD_BUS_TYPE_ARRAY, "{ib}"); |
| for (const auto &i : m) |
| { |
| expect_open_container(SD_BUS_TYPE_DICT_ENTRY, "ib"); |
| expect_basic<int>(SD_BUS_TYPE_INT32, i.first); |
| expect_basic<int>(SD_BUS_TYPE_BOOLEAN, i.second); |
| expect_close_container(); |
| } |
| expect_close_container(); |
| } |
| new_message().append(m); |
| } |
| |
| TEST_F(AppendTest, Tuple) |
| { |
| const std::tuple<int, std::string, bool> t{5, "asdf", false}; |
| |
| { |
| testing::InSequence seq; |
| expect_open_container(SD_BUS_TYPE_STRUCT, "isb"); |
| expect_basic<int>(SD_BUS_TYPE_INT32, std::get<0>(t)); |
| expect_basic_string(SD_BUS_TYPE_STRING, std::get<1>(t).c_str()); |
| expect_basic<int>(SD_BUS_TYPE_BOOLEAN, std::get<2>(t)); |
| expect_close_container(); |
| } |
| new_message().append(t); |
| } |
| |
| TEST_F(AppendTest, Variant) |
| { |
| const bool b1 = false; |
| const std::string s2{"asdf"}; |
| const sdbusplus::message::variant<int, std::string, bool> v1{b1}, v2{s2}; |
| |
| { |
| testing::InSequence seq; |
| expect_open_container(SD_BUS_TYPE_VARIANT, "b"); |
| expect_basic<int>(SD_BUS_TYPE_BOOLEAN, b1); |
| expect_close_container(); |
| expect_open_container(SD_BUS_TYPE_VARIANT, "s"); |
| expect_basic_string(SD_BUS_TYPE_STRING, s2.c_str()); |
| expect_close_container(); |
| } |
| new_message().append(v1, v2); |
| } |
| |
| TEST_F(AppendTest, LargeCombo) |
| { |
| std::vector<std::array<std::string, 3>> vas{{"a", "b", "c"}, |
| {"d", "", "e"}}; |
| std::map<std::string, sdbusplus::message::variant<int, double>> msv = { |
| {"a", 3.3}, {"b", 1}, {"c", 4.4}}; |
| |
| { |
| testing::InSequence seq; |
| |
| expect_open_container(SD_BUS_TYPE_ARRAY, "as"); |
| for (const auto &as : vas) |
| { |
| expect_open_container(SD_BUS_TYPE_ARRAY, "s"); |
| for (const auto &s : as) |
| { |
| expect_basic_string(SD_BUS_TYPE_STRING, s.c_str()); |
| } |
| expect_close_container(); |
| } |
| expect_close_container(); |
| |
| expect_open_container(SD_BUS_TYPE_ARRAY, "{sv}"); |
| for (const auto &sv : msv) |
| { |
| expect_open_container(SD_BUS_TYPE_DICT_ENTRY, "sv"); |
| expect_basic_string(SD_BUS_TYPE_STRING, sv.first.c_str()); |
| if (sv.second.is<int>()) |
| { |
| expect_open_container(SD_BUS_TYPE_VARIANT, "i"); |
| expect_basic<int>(SD_BUS_TYPE_INT32, sv.second.get<int>()); |
| expect_close_container(); |
| } |
| else |
| { |
| expect_open_container(SD_BUS_TYPE_VARIANT, "d"); |
| expect_basic<double>(SD_BUS_TYPE_DOUBLE, |
| sv.second.get<double>()); |
| expect_close_container(); |
| } |
| expect_close_container(); |
| } |
| expect_close_container(); |
| } |
| new_message().append(vas, msv); |
| } |
| |
| } // namespace |