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