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