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