blob: bd349e7baa68b694ebad85fe1e70d373af815e4a [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) :
Ed Tanouscb2fbeb2023-01-06 13:16:19 -080024 reason(r), property(p)
25 {}
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +010026 sdbusplus::UnpackErrorReason reason;
27 std::string property;
28 };
29
30 template <typename... Args>
31 std::optional<UnpackError> operator()(Args&&... args) const
32 {
33 std::optional<UnpackError> error;
34 unpackPropertiesNoThrow(
Patrick Williamsa970d832022-09-08 07:53:40 -050035 [&error](sdbusplus::UnpackErrorReason reason,
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +010036 const std::string& property) {
37 error.emplace(reason, property);
38 },
39 std::forward<Args>(args)...);
40 return error;
Szymon Dompke6d83cf52021-10-19 16:31:29 +020041 }
42};
43
44template <typename A, typename B>
45struct TestingTypes
46{
47 using SystemUnderTest = A;
48 using Container = B;
49};
50
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020051using VariantType = std::variant<std::string, uint32_t, float, double>;
Szymon Dompke6d83cf52021-10-19 16:31:29 +020052using ContainerTypes = testing::Types<
53 TestingTypes<NonThrowingUnpack,
54 std::vector<std::pair<std::string, VariantType>>>,
Szymon Dompke6d83cf52021-10-19 16:31:29 +020055 TestingTypes<ThrowingUnpack,
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +010056 std::vector<std::pair<std::string, VariantType>>>>;
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020057
58template <typename Exception, typename F>
59std::optional<Exception> captureException(F&& code)
60{
61 try
62 {
63 code();
64 }
65 catch (const Exception& e)
66 {
67 return e;
68 }
69
70 return std::nullopt;
71}
72
Szymon Dompke6d83cf52021-10-19 16:31:29 +020073template <typename Params>
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020074struct UnpackPropertiesTest : public testing::Test
75{
76 void SetUp() override
77 {
78 using namespace std::string_literals;
79
80 data.insert(data.end(),
81 std::make_pair("Key-1"s, VariantType("string"s)));
82 data.insert(data.end(), std::make_pair("Key-2"s, VariantType(42.f)));
83 data.insert(data.end(), std::make_pair("Key-3"s, VariantType(15.)));
84 }
85
Szymon Dompke6d83cf52021-10-19 16:31:29 +020086 typename Params::Container data;
87 typename Params::SystemUnderTest unpackPropertiesCall;
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020088};
89
90TYPED_TEST_SUITE(UnpackPropertiesTest, ContainerTypes);
91
92TYPED_TEST(UnpackPropertiesTest, returnsValueWhenKeyIsPresentAndTypeMatches)
93{
94 using namespace testing;
95
96 std::string val1;
97 float val2 = 0.f;
98 double val3 = 0.;
99
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200100 EXPECT_FALSE(this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2",
101 val2, "Key-3", val3));
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200102
103 ASSERT_THAT(val1, Eq("string"));
104 ASSERT_THAT(val2, FloatEq(42.f));
105 ASSERT_THAT(val3, DoubleEq(15.));
106}
107
108TYPED_TEST(UnpackPropertiesTest,
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100109 unpackDoesntChangeOriginalDataWhenPassedAsNonConstReference)
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200110{
111 using namespace testing;
112
113 std::string val1, val2;
114
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200115 EXPECT_FALSE(this->unpackPropertiesCall(this->data, "Key-1", val1));
116 EXPECT_FALSE(this->unpackPropertiesCall(this->data, "Key-1", val2));
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200117
118 ASSERT_THAT(val1, Eq("string"));
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200119 ASSERT_THAT(val2, Eq("string"));
120}
121
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100122TYPED_TEST(UnpackPropertiesTest, doesntReportMissingPropertyForOptional)
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200123{
124 using namespace testing;
125 using namespace std::string_literals;
126
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100127 std::optional<std::string> val1;
128 std::optional<std::string> val4;
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200129
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100130 EXPECT_FALSE(
131 this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-4", val4));
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200132
133 ASSERT_THAT(val1, Eq("string"));
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100134 ASSERT_THAT(val4, Eq(std::nullopt));
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200135}
136
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100137TYPED_TEST(UnpackPropertiesTest, setPresentPointersOnSuccess)
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200138{
139 using namespace testing;
140 using namespace std::string_literals;
141
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100142 const std::string* val1 = nullptr;
143 const float* val2 = nullptr;
144 const double* val3 = nullptr;
145 const std::string* val4 = nullptr;
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200146
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100147 EXPECT_FALSE(this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2",
148 val2, "Key-3", val3, "Key-4",
149 val4));
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200150
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100151 ASSERT_TRUE(val1 && val2 && val3);
152 ASSERT_TRUE(!val4);
153
154 ASSERT_THAT(*val1, Eq("string"));
155 ASSERT_THAT(*val2, FloatEq(42.f));
156 ASSERT_THAT(*val3, DoubleEq(15.));
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200157}
158
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200159template <typename Params>
160struct UnpackPropertiesThrowingTest : public UnpackPropertiesTest<Params>
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200161{};
162
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100163using ContainerTypesThrowing = testing::Types<TestingTypes<
164 ThrowingUnpack, std::vector<std::pair<std::string, VariantType>>>>;
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200165
166TYPED_TEST_SUITE(UnpackPropertiesThrowingTest, ContainerTypesThrowing);
167
168TYPED_TEST(UnpackPropertiesThrowingTest, throwsErrorWhenKeyIsMissing)
169{
170 using namespace testing;
171
172 std::string val1;
173 float val2 = 0.f;
174 double val3 = 0.;
175
176 auto error = captureException<exception::UnpackPropertyError>([&] {
177 this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-4", val2,
178 "Key-3", val3);
179 });
180
181 ASSERT_TRUE(error);
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100182 ASSERT_THAT(error->reason, Eq(UnpackErrorReason::missingProperty));
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200183 ASSERT_THAT(error->propertyName, Eq("Key-4"));
184}
185
186TYPED_TEST(UnpackPropertiesThrowingTest, throwsErrorWhenTypeDoesntMatch)
187{
188 using namespace testing;
189
190 std::string val1;
191 std::string val2;
192 double val3 = 0.;
193
194 auto error = captureException<exception::UnpackPropertyError>([&] {
195 this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2", val2,
196 "Key-3", val3);
197 });
198
199 ASSERT_TRUE(error);
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100200 ASSERT_THAT(error->reason, Eq(UnpackErrorReason::wrongType));
201 ASSERT_THAT(error->propertyName, Eq("Key-2"));
202}
203
204TYPED_TEST(UnpackPropertiesThrowingTest, throwsErrorWhenOptionalTypeDoesntMatch)
205{
206 using namespace testing;
207
208 std::optional<std::string> val1;
209 std::optional<std::string> val2;
210
211 auto error = captureException<exception::UnpackPropertyError>([&] {
212 this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2", val2);
213 });
214
215 ASSERT_TRUE(error);
216 ASSERT_THAT(error->reason, Eq(UnpackErrorReason::wrongType));
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200217 ASSERT_THAT(error->propertyName, Eq("Key-2"));
218}
219
220template <typename Params>
221struct UnpackPropertiesNonThrowingTest : public UnpackPropertiesTest<Params>
222{};
223
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100224using ContainerTypesNonThrowing = testing::Types<TestingTypes<
225 NonThrowingUnpack, std::vector<std::pair<std::string, VariantType>>>>;
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200226
227TYPED_TEST_SUITE(UnpackPropertiesNonThrowingTest, ContainerTypesNonThrowing);
228
229TYPED_TEST(UnpackPropertiesNonThrowingTest, ErrorWhenKeyIsMissing)
230{
231 using namespace testing;
232
233 std::string val1;
234 float val2 = 0.f;
235 double val3 = 0.;
236
237 auto badProperty = this->unpackPropertiesCall(this->data, "Key-1", val1,
238 "Key-4", val2, "Key-3", val3);
239
240 ASSERT_TRUE(badProperty);
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100241 EXPECT_THAT(badProperty->reason, Eq(UnpackErrorReason::missingProperty));
242 EXPECT_THAT(badProperty->property, Eq("Key-4"));
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200243}
244
245TYPED_TEST(UnpackPropertiesNonThrowingTest, ErrorWhenTypeDoesntMatch)
246{
247 using namespace testing;
248
249 std::string val1;
250 std::string val2;
251 double val3 = 0.;
252
253 auto badProperty = this->unpackPropertiesCall(this->data, "Key-1", val1,
254 "Key-2", val2, "Key-3", val3);
255
256 ASSERT_TRUE(badProperty);
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100257 EXPECT_THAT(badProperty->reason, Eq(UnpackErrorReason::wrongType));
258 EXPECT_THAT(badProperty->property, Eq("Key-2"));
259}
260
261TYPED_TEST(UnpackPropertiesNonThrowingTest, ErrorWhenOptionalTypeDoesntMatch)
262{
263 using namespace testing;
264
265 std::optional<std::string> val1;
266 std::optional<std::string> val2;
267
Patrick Williams1a25a102022-09-29 17:18:26 -0500268 auto badProperty = this->unpackPropertiesCall(this->data, "Key-1", val1,
269 "Key-2", val2);
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100270
271 ASSERT_TRUE(badProperty);
272 EXPECT_THAT(badProperty->reason, Eq(UnpackErrorReason::wrongType));
273 EXPECT_THAT(badProperty->property, Eq("Key-2"));
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200274}
275
276template <typename Params>
277struct UnpackPropertiesTest_ForVector : public UnpackPropertiesTest<Params>
278{};
279
280using ContainerTypesVector = testing::Types<
281 TestingTypes<NonThrowingUnpack,
282 std::vector<std::pair<std::string, VariantType>>>,
283 TestingTypes<ThrowingUnpack,
284 std::vector<std::pair<std::string, VariantType>>>>;
285
286TYPED_TEST_SUITE(UnpackPropertiesTest_ForVector, ContainerTypesVector);
287
288TYPED_TEST(UnpackPropertiesTest_ForVector, silentlyDiscardsDuplicatedKeyInData)
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200289{
290 using namespace testing;
291 using namespace std::string_literals;
292
293 std::string val1;
294 float val2 = 0.f;
295 double val3 = 0.;
296
297 this->data.insert(this->data.end(),
298 std::make_pair("Key-1"s, VariantType("string2"s)));
299
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200300 EXPECT_FALSE(this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2",
301 val2, "Key-3", val3));
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200302
303 ASSERT_THAT(val1, Eq("string"));
304 ASSERT_THAT(val2, FloatEq(42.f));
305 ASSERT_THAT(val3, DoubleEq(15.));
306}
307
308} // namespace sdbusplus