blob: b4a3e32d1c05cf03d83d7ea2a2c3b148f87b26a1 [file] [log] [blame]
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +02001#include <boost/container/flat_map.hpp>
2#include <sdbusplus/unpack_properties.hpp>
3
4#include <gmock/gmock.h>
5
6namespace sdbusplus
7{
8
Szymon Dompke6d83cf52021-10-19 16:31:29 +02009struct ThrowingUnpack
10{
11 template <typename... Args>
12 bool operator()(Args&&... args) const
13 {
14 unpackProperties(std::forward<Args>(args)...);
15 return false;
16 }
17};
18
19struct NonThrowingUnpack
20{
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +010021 struct UnpackError
Szymon Dompke6d83cf52021-10-19 16:31:29 +020022 {
Patrick Williamsa970d832022-09-08 07:53:40 -050023 UnpackError(sdbusplus::UnpackErrorReason r, const std::string& p) :
24 reason(r), property(p){};
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +010025 sdbusplus::UnpackErrorReason reason;
26 std::string property;
27 };
28
29 template <typename... Args>
30 std::optional<UnpackError> operator()(Args&&... args) const
31 {
32 std::optional<UnpackError> error;
33 unpackPropertiesNoThrow(
Patrick Williamsa970d832022-09-08 07:53:40 -050034 [&error](sdbusplus::UnpackErrorReason reason,
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +010035 const std::string& property) {
36 error.emplace(reason, property);
37 },
38 std::forward<Args>(args)...);
39 return error;
Szymon Dompke6d83cf52021-10-19 16:31:29 +020040 }
41};
42
43template <typename A, typename B>
44struct TestingTypes
45{
46 using SystemUnderTest = A;
47 using Container = B;
48};
49
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020050using VariantType = std::variant<std::string, uint32_t, float, double>;
Szymon Dompke6d83cf52021-10-19 16:31:29 +020051using ContainerTypes = testing::Types<
52 TestingTypes<NonThrowingUnpack,
53 std::vector<std::pair<std::string, VariantType>>>,
Szymon Dompke6d83cf52021-10-19 16:31:29 +020054 TestingTypes<ThrowingUnpack,
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +010055 std::vector<std::pair<std::string, VariantType>>>>;
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020056
57template <typename Exception, typename F>
58std::optional<Exception> captureException(F&& code)
59{
60 try
61 {
62 code();
63 }
64 catch (const Exception& e)
65 {
66 return e;
67 }
68
69 return std::nullopt;
70}
71
Szymon Dompke6d83cf52021-10-19 16:31:29 +020072template <typename Params>
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020073struct UnpackPropertiesTest : public testing::Test
74{
75 void SetUp() override
76 {
77 using namespace std::string_literals;
78
79 data.insert(data.end(),
80 std::make_pair("Key-1"s, VariantType("string"s)));
81 data.insert(data.end(), std::make_pair("Key-2"s, VariantType(42.f)));
82 data.insert(data.end(), std::make_pair("Key-3"s, VariantType(15.)));
83 }
84
Szymon Dompke6d83cf52021-10-19 16:31:29 +020085 typename Params::Container data;
86 typename Params::SystemUnderTest unpackPropertiesCall;
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020087};
88
89TYPED_TEST_SUITE(UnpackPropertiesTest, ContainerTypes);
90
91TYPED_TEST(UnpackPropertiesTest, returnsValueWhenKeyIsPresentAndTypeMatches)
92{
93 using namespace testing;
94
95 std::string val1;
96 float val2 = 0.f;
97 double val3 = 0.;
98
Szymon Dompke6d83cf52021-10-19 16:31:29 +020099 EXPECT_FALSE(this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2",
100 val2, "Key-3", val3));
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200101
102 ASSERT_THAT(val1, Eq("string"));
103 ASSERT_THAT(val2, FloatEq(42.f));
104 ASSERT_THAT(val3, DoubleEq(15.));
105}
106
107TYPED_TEST(UnpackPropertiesTest,
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100108 unpackDoesntChangeOriginalDataWhenPassedAsNonConstReference)
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200109{
110 using namespace testing;
111
112 std::string val1, val2;
113
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200114 EXPECT_FALSE(this->unpackPropertiesCall(this->data, "Key-1", val1));
115 EXPECT_FALSE(this->unpackPropertiesCall(this->data, "Key-1", val2));
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200116
117 ASSERT_THAT(val1, Eq("string"));
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200118 ASSERT_THAT(val2, Eq("string"));
119}
120
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100121TYPED_TEST(UnpackPropertiesTest, doesntReportMissingPropertyForOptional)
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200122{
123 using namespace testing;
124 using namespace std::string_literals;
125
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100126 std::optional<std::string> val1;
127 std::optional<std::string> val4;
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200128
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100129 EXPECT_FALSE(
130 this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-4", val4));
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200131
132 ASSERT_THAT(val1, Eq("string"));
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100133 ASSERT_THAT(val4, Eq(std::nullopt));
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200134}
135
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100136TYPED_TEST(UnpackPropertiesTest, setPresentPointersOnSuccess)
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200137{
138 using namespace testing;
139 using namespace std::string_literals;
140
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100141 const std::string* val1 = nullptr;
142 const float* val2 = nullptr;
143 const double* val3 = nullptr;
144 const std::string* val4 = nullptr;
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200145
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100146 EXPECT_FALSE(this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2",
147 val2, "Key-3", val3, "Key-4",
148 val4));
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200149
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100150 ASSERT_TRUE(val1 && val2 && val3);
151 ASSERT_TRUE(!val4);
152
153 ASSERT_THAT(*val1, Eq("string"));
154 ASSERT_THAT(*val2, FloatEq(42.f));
155 ASSERT_THAT(*val3, DoubleEq(15.));
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200156}
157
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200158template <typename Params>
159struct UnpackPropertiesThrowingTest : public UnpackPropertiesTest<Params>
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200160{};
161
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100162using ContainerTypesThrowing = testing::Types<TestingTypes<
163 ThrowingUnpack, std::vector<std::pair<std::string, VariantType>>>>;
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200164
165TYPED_TEST_SUITE(UnpackPropertiesThrowingTest, ContainerTypesThrowing);
166
167TYPED_TEST(UnpackPropertiesThrowingTest, throwsErrorWhenKeyIsMissing)
168{
169 using namespace testing;
170
171 std::string val1;
172 float val2 = 0.f;
173 double val3 = 0.;
174
175 auto error = captureException<exception::UnpackPropertyError>([&] {
176 this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-4", val2,
177 "Key-3", val3);
178 });
179
180 ASSERT_TRUE(error);
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100181 ASSERT_THAT(error->reason, Eq(UnpackErrorReason::missingProperty));
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200182 ASSERT_THAT(error->propertyName, Eq("Key-4"));
183}
184
185TYPED_TEST(UnpackPropertiesThrowingTest, throwsErrorWhenTypeDoesntMatch)
186{
187 using namespace testing;
188
189 std::string val1;
190 std::string val2;
191 double val3 = 0.;
192
193 auto error = captureException<exception::UnpackPropertyError>([&] {
194 this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2", val2,
195 "Key-3", val3);
196 });
197
198 ASSERT_TRUE(error);
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100199 ASSERT_THAT(error->reason, Eq(UnpackErrorReason::wrongType));
200 ASSERT_THAT(error->propertyName, Eq("Key-2"));
201}
202
203TYPED_TEST(UnpackPropertiesThrowingTest, throwsErrorWhenOptionalTypeDoesntMatch)
204{
205 using namespace testing;
206
207 std::optional<std::string> val1;
208 std::optional<std::string> val2;
209
210 auto error = captureException<exception::UnpackPropertyError>([&] {
211 this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2", val2);
212 });
213
214 ASSERT_TRUE(error);
215 ASSERT_THAT(error->reason, Eq(UnpackErrorReason::wrongType));
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200216 ASSERT_THAT(error->propertyName, Eq("Key-2"));
217}
218
219template <typename Params>
220struct UnpackPropertiesNonThrowingTest : public UnpackPropertiesTest<Params>
221{};
222
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100223using ContainerTypesNonThrowing = testing::Types<TestingTypes<
224 NonThrowingUnpack, std::vector<std::pair<std::string, VariantType>>>>;
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200225
226TYPED_TEST_SUITE(UnpackPropertiesNonThrowingTest, ContainerTypesNonThrowing);
227
228TYPED_TEST(UnpackPropertiesNonThrowingTest, ErrorWhenKeyIsMissing)
229{
230 using namespace testing;
231
232 std::string val1;
233 float val2 = 0.f;
234 double val3 = 0.;
235
236 auto badProperty = this->unpackPropertiesCall(this->data, "Key-1", val1,
237 "Key-4", val2, "Key-3", val3);
238
239 ASSERT_TRUE(badProperty);
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100240 EXPECT_THAT(badProperty->reason, Eq(UnpackErrorReason::missingProperty));
241 EXPECT_THAT(badProperty->property, Eq("Key-4"));
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200242}
243
244TYPED_TEST(UnpackPropertiesNonThrowingTest, ErrorWhenTypeDoesntMatch)
245{
246 using namespace testing;
247
248 std::string val1;
249 std::string val2;
250 double val3 = 0.;
251
252 auto badProperty = this->unpackPropertiesCall(this->data, "Key-1", val1,
253 "Key-2", val2, "Key-3", val3);
254
255 ASSERT_TRUE(badProperty);
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100256 EXPECT_THAT(badProperty->reason, Eq(UnpackErrorReason::wrongType));
257 EXPECT_THAT(badProperty->property, Eq("Key-2"));
258}
259
260TYPED_TEST(UnpackPropertiesNonThrowingTest, ErrorWhenOptionalTypeDoesntMatch)
261{
262 using namespace testing;
263
264 std::optional<std::string> val1;
265 std::optional<std::string> val2;
266
267 auto badProperty =
268 this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2", val2);
269
270 ASSERT_TRUE(badProperty);
271 EXPECT_THAT(badProperty->reason, Eq(UnpackErrorReason::wrongType));
272 EXPECT_THAT(badProperty->property, Eq("Key-2"));
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200273}
274
275template <typename Params>
276struct UnpackPropertiesTest_ForVector : public UnpackPropertiesTest<Params>
277{};
278
279using ContainerTypesVector = testing::Types<
280 TestingTypes<NonThrowingUnpack,
281 std::vector<std::pair<std::string, VariantType>>>,
282 TestingTypes<ThrowingUnpack,
283 std::vector<std::pair<std::string, VariantType>>>>;
284
285TYPED_TEST_SUITE(UnpackPropertiesTest_ForVector, ContainerTypesVector);
286
287TYPED_TEST(UnpackPropertiesTest_ForVector, silentlyDiscardsDuplicatedKeyInData)
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200288{
289 using namespace testing;
290 using namespace std::string_literals;
291
292 std::string val1;
293 float val2 = 0.f;
294 double val3 = 0.;
295
296 this->data.insert(this->data.end(),
297 std::make_pair("Key-1"s, VariantType("string2"s)));
298
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200299 EXPECT_FALSE(this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2",
300 val2, "Key-3", val3));
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200301
302 ASSERT_THAT(val1, Eq("string"));
303 ASSERT_THAT(val2, FloatEq(42.f));
304 ASSERT_THAT(val3, DoubleEq(15.));
305}
306
307} // namespace sdbusplus