1 #include <systemd/sd-bus-protocol.h> 2 3 #include <array> 4 #include <map> 5 #include <sdbusplus/message.hpp> 6 #include <sdbusplus/test/sdbus_mock.hpp> 7 #include <set> 8 #include <string> 9 #include <tuple> 10 #include <unordered_map> 11 #include <vector> 12 13 #include <gmock/gmock.h> 14 #include <gtest/gtest.h> 15 16 namespace 17 { 18 19 namespace variant_ns = sdbusplus::message::variant_ns; 20 using testing::Eq; 21 using testing::MatcherCast; 22 using testing::Pointee; 23 using testing::Return; 24 using testing::SafeMatcherCast; 25 using testing::StrEq; 26 27 class AppendTest : public testing::Test 28 { 29 protected: 30 testing::StrictMock<sdbusplus::SdBusMock> mock; 31 32 void SetUp() override 33 { 34 EXPECT_CALL(mock, sd_bus_message_new_method_call(testing::_, testing::_, 35 nullptr, nullptr, 36 nullptr, nullptr)) 37 .WillRepeatedly(Return(0)); 38 }; 39 40 sdbusplus::message::message new_message() 41 { 42 return sdbusplus::get_mocked_new(&mock).new_method_call( 43 nullptr, nullptr, nullptr, nullptr); 44 } 45 46 template <typename T> 47 void expect_basic(char type, T val) 48 { 49 EXPECT_CALL(mock, sd_bus_message_append_basic( 50 nullptr, type, 51 MatcherCast<const void*>( 52 SafeMatcherCast<const T*>(Pointee(Eq(val)))))) 53 .WillOnce(Return(0)); 54 } 55 56 void expect_basic_string(char type, const char* str) 57 { 58 EXPECT_CALL(mock, sd_bus_message_append_basic( 59 nullptr, type, 60 MatcherCast<const void*>( 61 SafeMatcherCast<const char*>(StrEq(str))))) 62 .WillOnce(Return(0)); 63 } 64 65 void expect_open_container(char type, const char* contents) 66 { 67 EXPECT_CALL( 68 mock, sd_bus_message_open_container(nullptr, type, StrEq(contents))) 69 .WillOnce(Return(0)); 70 } 71 72 void expect_close_container() 73 { 74 EXPECT_CALL(mock, sd_bus_message_close_container(nullptr)) 75 .WillOnce(Return(0)); 76 } 77 }; 78 79 TEST_F(AppendTest, RValueInt) 80 { 81 expect_basic<int>(SD_BUS_TYPE_INT32, 1); 82 new_message().append(1); 83 } 84 85 TEST_F(AppendTest, LValueInt) 86 { 87 const int a = 1; 88 expect_basic<int>(SD_BUS_TYPE_INT32, a); 89 new_message().append(a); 90 } 91 92 TEST_F(AppendTest, XValueInt) 93 { 94 int a = 1; 95 expect_basic<int>(SD_BUS_TYPE_INT32, a); 96 new_message().append(std::move(a)); 97 } 98 99 TEST_F(AppendTest, RValueBool) 100 { 101 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, true); 102 new_message().append(true); 103 } 104 105 TEST_F(AppendTest, LValueBool) 106 { 107 const bool a = false; 108 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, false); 109 new_message().append(a); 110 } 111 112 TEST_F(AppendTest, XValueBool) 113 { 114 bool a = false; 115 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, false); 116 new_message().append(std::move(a)); 117 } 118 119 TEST_F(AppendTest, RValueDouble) 120 { 121 expect_basic<double>(SD_BUS_TYPE_DOUBLE, 1.1); 122 new_message().append(1.1); 123 } 124 125 TEST_F(AppendTest, LValueDouble) 126 { 127 const double a = 1.1; 128 expect_basic<double>(SD_BUS_TYPE_DOUBLE, a); 129 new_message().append(a); 130 } 131 132 TEST_F(AppendTest, XValueDouble) 133 { 134 double a = 1.1; 135 expect_basic<double>(SD_BUS_TYPE_DOUBLE, a); 136 new_message().append(std::move(a)); 137 } 138 139 TEST_F(AppendTest, RValueCString) 140 { 141 expect_basic_string(SD_BUS_TYPE_STRING, "asdf"); 142 new_message().append("asdf"); 143 } 144 145 TEST_F(AppendTest, LValueCString) 146 { 147 const char* const s = "asdf"; 148 expect_basic_string(SD_BUS_TYPE_STRING, s); 149 new_message().append(s); 150 } 151 152 TEST_F(AppendTest, XValueCString) 153 { 154 const char* s = "asdf"; 155 expect_basic_string(SD_BUS_TYPE_STRING, s); 156 new_message().append(std::move(s)); 157 } 158 159 TEST_F(AppendTest, RValueString) 160 { 161 expect_basic_string(SD_BUS_TYPE_STRING, "asdf"); 162 new_message().append(std::string{"asdf"}); 163 } 164 165 TEST_F(AppendTest, LValueString) 166 { 167 std::string s{"asdf"}; 168 expect_basic_string(SD_BUS_TYPE_STRING, s.c_str()); 169 new_message().append(s); 170 } 171 172 TEST_F(AppendTest, XValueString) 173 { 174 std::string s{"asdf"}; 175 expect_basic_string(SD_BUS_TYPE_STRING, s.c_str()); 176 new_message().append(std::move(s)); 177 } 178 179 TEST_F(AppendTest, ObjectPath) 180 { 181 sdbusplus::message::object_path o{"/asdf"}; 182 expect_basic_string(SD_BUS_TYPE_OBJECT_PATH, o.str.c_str()); 183 new_message().append(o); 184 } 185 186 TEST_F(AppendTest, Signature) 187 { 188 sdbusplus::message::signature g{"ii"}; 189 expect_basic_string(SD_BUS_TYPE_SIGNATURE, g.str.c_str()); 190 new_message().append(g); 191 } 192 193 TEST_F(AppendTest, CombinedBasic) 194 { 195 const int c = 3; 196 const std::string s1{"fdsa"}; 197 const char* const s2 = "asdf"; 198 199 { 200 testing::InSequence seq; 201 expect_basic<int>(SD_BUS_TYPE_INT32, 1); 202 expect_basic<double>(SD_BUS_TYPE_DOUBLE, 2.2); 203 expect_basic<int>(SD_BUS_TYPE_INT32, c); 204 expect_basic_string(SD_BUS_TYPE_STRING, s1.c_str()); 205 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, false); 206 expect_basic_string(SD_BUS_TYPE_STRING, s2); 207 } 208 new_message().append(1, 2.2, c, s1, false, s2); 209 } 210 211 TEST_F(AppendTest, Array) 212 { 213 const std::array<double, 4> a{1.1, 2.2, 3.3, 4.4}; 214 215 { 216 testing::InSequence seq; 217 expect_open_container(SD_BUS_TYPE_ARRAY, "d"); 218 for (const auto& i : a) 219 { 220 expect_basic<double>(SD_BUS_TYPE_DOUBLE, i); 221 } 222 expect_close_container(); 223 } 224 new_message().append(a); 225 } 226 227 TEST_F(AppendTest, Vector) 228 { 229 const std::vector<int> v{1, 2, 3, 4}; 230 231 { 232 testing::InSequence seq; 233 expect_open_container(SD_BUS_TYPE_ARRAY, "i"); 234 for (const auto& i : v) 235 { 236 expect_basic<int>(SD_BUS_TYPE_INT32, i); 237 } 238 expect_close_container(); 239 } 240 new_message().append(v); 241 } 242 243 TEST_F(AppendTest, Set) 244 { 245 const std::set<std::string> s{"one", "two", "eight"}; 246 247 { 248 testing::InSequence seq; 249 expect_open_container(SD_BUS_TYPE_ARRAY, "s"); 250 for (const auto& i : s) 251 { 252 expect_basic_string(SD_BUS_TYPE_STRING, i.c_str()); 253 } 254 expect_close_container(); 255 } 256 new_message().append(s); 257 } 258 259 TEST_F(AppendTest, Map) 260 { 261 const std::map<int, std::string> m{ 262 {1, "a"}, 263 {2, "bc"}, 264 {3, "def"}, 265 {4, "ghij"}, 266 }; 267 268 { 269 testing::InSequence seq; 270 expect_open_container(SD_BUS_TYPE_ARRAY, "{is}"); 271 for (const auto& i : m) 272 { 273 expect_open_container(SD_BUS_TYPE_DICT_ENTRY, "is"); 274 expect_basic<int>(SD_BUS_TYPE_INT32, i.first); 275 expect_basic_string(SD_BUS_TYPE_STRING, i.second.c_str()); 276 expect_close_container(); 277 } 278 expect_close_container(); 279 } 280 new_message().append(m); 281 } 282 283 TEST_F(AppendTest, UnorderedMap) 284 { 285 const std::unordered_map<int, bool> m{ 286 {1, false}, 287 {2, true}, 288 {3, true}, 289 {4, false}, 290 }; 291 292 { 293 testing::InSequence seq; 294 expect_open_container(SD_BUS_TYPE_ARRAY, "{ib}"); 295 for (const auto& i : m) 296 { 297 expect_open_container(SD_BUS_TYPE_DICT_ENTRY, "ib"); 298 expect_basic<int>(SD_BUS_TYPE_INT32, i.first); 299 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, i.second); 300 expect_close_container(); 301 } 302 expect_close_container(); 303 } 304 new_message().append(m); 305 } 306 307 TEST_F(AppendTest, Tuple) 308 { 309 const std::tuple<int, std::string, bool> t{5, "asdf", false}; 310 311 { 312 testing::InSequence seq; 313 expect_open_container(SD_BUS_TYPE_STRUCT, "isb"); 314 expect_basic<int>(SD_BUS_TYPE_INT32, std::get<0>(t)); 315 expect_basic_string(SD_BUS_TYPE_STRING, std::get<1>(t).c_str()); 316 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, std::get<2>(t)); 317 expect_close_container(); 318 } 319 new_message().append(t); 320 } 321 322 TEST_F(AppendTest, Variant) 323 { 324 const bool b1 = false; 325 const std::string s2{"asdf"}; 326 const sdbusplus::message::variant<int, std::string, bool> v1{b1}, v2{s2}; 327 328 { 329 testing::InSequence seq; 330 expect_open_container(SD_BUS_TYPE_VARIANT, "b"); 331 expect_basic<int>(SD_BUS_TYPE_BOOLEAN, b1); 332 expect_close_container(); 333 expect_open_container(SD_BUS_TYPE_VARIANT, "s"); 334 expect_basic_string(SD_BUS_TYPE_STRING, s2.c_str()); 335 expect_close_container(); 336 } 337 new_message().append(v1, v2); 338 } 339 340 TEST_F(AppendTest, LargeCombo) 341 { 342 std::vector<std::array<std::string, 3>> vas{{"a", "b", "c"}, 343 {"d", "", "e"}}; 344 std::map<std::string, sdbusplus::message::variant<int, double>> msv = { 345 {"a", 3.3}, {"b", 1}, {"c", 4.4}}; 346 347 { 348 testing::InSequence seq; 349 350 expect_open_container(SD_BUS_TYPE_ARRAY, "as"); 351 for (const auto& as : vas) 352 { 353 expect_open_container(SD_BUS_TYPE_ARRAY, "s"); 354 for (const auto& s : as) 355 { 356 expect_basic_string(SD_BUS_TYPE_STRING, s.c_str()); 357 } 358 expect_close_container(); 359 } 360 expect_close_container(); 361 362 expect_open_container(SD_BUS_TYPE_ARRAY, "{sv}"); 363 for (const auto& sv : msv) 364 { 365 expect_open_container(SD_BUS_TYPE_DICT_ENTRY, "sv"); 366 expect_basic_string(SD_BUS_TYPE_STRING, sv.first.c_str()); 367 if (variant_ns::holds_alternative<int>(sv.second)) 368 { 369 expect_open_container(SD_BUS_TYPE_VARIANT, "i"); 370 expect_basic<int>(SD_BUS_TYPE_INT32, 371 variant_ns::get<int>(sv.second)); 372 expect_close_container(); 373 } 374 else 375 { 376 expect_open_container(SD_BUS_TYPE_VARIANT, "d"); 377 expect_basic<double>(SD_BUS_TYPE_DOUBLE, 378 variant_ns::get<double>(sv.second)); 379 expect_close_container(); 380 } 381 expect_close_container(); 382 } 383 expect_close_container(); 384 } 385 new_message().append(vas, msv); 386 } 387 388 } // namespace 389