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