xref: /openbmc/sdbusplus/test/unpack_properties.cpp (revision 06f265f6f18e22b1fb68761edb50ecd6722c2a47)
109b88f26SKrzysztof Grobelny #include <boost/container/flat_map.hpp>
209b88f26SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
309b88f26SKrzysztof Grobelny 
409b88f26SKrzysztof Grobelny #include <gmock/gmock.h>
509b88f26SKrzysztof Grobelny 
609b88f26SKrzysztof Grobelny namespace sdbusplus
709b88f26SKrzysztof Grobelny {
809b88f26SKrzysztof Grobelny 
96d83cf53SSzymon Dompke struct ThrowingUnpack
106d83cf53SSzymon Dompke {
116d83cf53SSzymon Dompke     template <typename... Args>
operator ()sdbusplus::ThrowingUnpack126d83cf53SSzymon Dompke     bool operator()(Args&&... args) const
136d83cf53SSzymon Dompke     {
146d83cf53SSzymon Dompke         unpackProperties(std::forward<Args>(args)...);
156d83cf53SSzymon Dompke         return false;
166d83cf53SSzymon Dompke     }
176d83cf53SSzymon Dompke };
186d83cf53SSzymon Dompke 
196d83cf53SSzymon Dompke struct NonThrowingUnpack
206d83cf53SSzymon Dompke {
21c8447d52SKrzysztof Grobelny     struct UnpackError
226d83cf53SSzymon Dompke     {
UnpackErrorsdbusplus::NonThrowingUnpack::UnpackError23a970d836SPatrick Williams         UnpackError(sdbusplus::UnpackErrorReason r, const std::string& p) :
24cb2fbeb9SEd Tanous             reason(r), property(p)
25cb2fbeb9SEd Tanous         {}
26c8447d52SKrzysztof Grobelny         sdbusplus::UnpackErrorReason reason;
27c8447d52SKrzysztof Grobelny         std::string property;
28c8447d52SKrzysztof Grobelny     };
29c8447d52SKrzysztof Grobelny 
30c8447d52SKrzysztof Grobelny     template <typename... Args>
operator ()sdbusplus::NonThrowingUnpack31c8447d52SKrzysztof Grobelny     std::optional<UnpackError> operator()(Args&&... args) const
32c8447d52SKrzysztof Grobelny     {
33c8447d52SKrzysztof Grobelny         std::optional<UnpackError> error;
34c8447d52SKrzysztof Grobelny         unpackPropertiesNoThrow(
35a970d836SPatrick Williams             [&error](sdbusplus::UnpackErrorReason reason,
36c8447d52SKrzysztof Grobelny                      const std::string& property) {
37c8447d52SKrzysztof Grobelny                 error.emplace(reason, property);
38c8447d52SKrzysztof Grobelny             },
39c8447d52SKrzysztof Grobelny             std::forward<Args>(args)...);
40c8447d52SKrzysztof Grobelny         return error;
416d83cf53SSzymon Dompke     }
426d83cf53SSzymon Dompke };
436d83cf53SSzymon Dompke 
446d83cf53SSzymon Dompke template <typename A, typename B>
456d83cf53SSzymon Dompke struct TestingTypes
466d83cf53SSzymon Dompke {
476d83cf53SSzymon Dompke     using SystemUnderTest = A;
486d83cf53SSzymon Dompke     using Container = B;
496d83cf53SSzymon Dompke };
506d83cf53SSzymon Dompke 
5109b88f26SKrzysztof Grobelny using VariantType = std::variant<std::string, uint32_t, float, double>;
526d83cf53SSzymon Dompke using ContainerTypes = testing::Types<
536d83cf53SSzymon Dompke     TestingTypes<NonThrowingUnpack,
546d83cf53SSzymon Dompke                  std::vector<std::pair<std::string, VariantType>>>,
556d83cf53SSzymon Dompke     TestingTypes<ThrowingUnpack,
56c8447d52SKrzysztof Grobelny                  std::vector<std::pair<std::string, VariantType>>>>;
5709b88f26SKrzysztof Grobelny 
5809b88f26SKrzysztof Grobelny template <typename Exception, typename F>
captureException(F && code)5909b88f26SKrzysztof Grobelny std::optional<Exception> captureException(F&& code)
6009b88f26SKrzysztof Grobelny {
6109b88f26SKrzysztof Grobelny     try
6209b88f26SKrzysztof Grobelny     {
6309b88f26SKrzysztof Grobelny         code();
6409b88f26SKrzysztof Grobelny     }
6509b88f26SKrzysztof Grobelny     catch (const Exception& e)
6609b88f26SKrzysztof Grobelny     {
6709b88f26SKrzysztof Grobelny         return e;
6809b88f26SKrzysztof Grobelny     }
6909b88f26SKrzysztof Grobelny 
7009b88f26SKrzysztof Grobelny     return std::nullopt;
7109b88f26SKrzysztof Grobelny }
7209b88f26SKrzysztof Grobelny 
736d83cf53SSzymon Dompke template <typename Params>
7409b88f26SKrzysztof Grobelny struct UnpackPropertiesTest : public testing::Test
7509b88f26SKrzysztof Grobelny {
SetUpsdbusplus::UnpackPropertiesTest7609b88f26SKrzysztof Grobelny     void SetUp() override
7709b88f26SKrzysztof Grobelny     {
7809b88f26SKrzysztof Grobelny         using namespace std::string_literals;
7909b88f26SKrzysztof Grobelny 
8009b88f26SKrzysztof Grobelny         data.insert(data.end(),
8109b88f26SKrzysztof Grobelny                     std::make_pair("Key-1"s, VariantType("string"s)));
8209b88f26SKrzysztof Grobelny         data.insert(data.end(), std::make_pair("Key-2"s, VariantType(42.f)));
8309b88f26SKrzysztof Grobelny         data.insert(data.end(), std::make_pair("Key-3"s, VariantType(15.)));
8409b88f26SKrzysztof Grobelny     }
8509b88f26SKrzysztof Grobelny 
866d83cf53SSzymon Dompke     typename Params::Container data;
876d83cf53SSzymon Dompke     typename Params::SystemUnderTest unpackPropertiesCall;
8809b88f26SKrzysztof Grobelny };
8909b88f26SKrzysztof Grobelny 
9009b88f26SKrzysztof Grobelny TYPED_TEST_SUITE(UnpackPropertiesTest, ContainerTypes);
9109b88f26SKrzysztof Grobelny 
TYPED_TEST(UnpackPropertiesTest,returnsValueWhenKeyIsPresentAndTypeMatches)9209b88f26SKrzysztof Grobelny TYPED_TEST(UnpackPropertiesTest, returnsValueWhenKeyIsPresentAndTypeMatches)
9309b88f26SKrzysztof Grobelny {
9409b88f26SKrzysztof Grobelny     using namespace testing;
9509b88f26SKrzysztof Grobelny 
9609b88f26SKrzysztof Grobelny     std::string val1;
9709b88f26SKrzysztof Grobelny     float val2 = 0.f;
9809b88f26SKrzysztof Grobelny     double val3 = 0.;
9909b88f26SKrzysztof Grobelny 
1006d83cf53SSzymon Dompke     EXPECT_FALSE(this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2",
1016d83cf53SSzymon Dompke                                             val2, "Key-3", val3));
10209b88f26SKrzysztof Grobelny 
10309b88f26SKrzysztof Grobelny     ASSERT_THAT(val1, Eq("string"));
10409b88f26SKrzysztof Grobelny     ASSERT_THAT(val2, FloatEq(42.f));
10509b88f26SKrzysztof Grobelny     ASSERT_THAT(val3, DoubleEq(15.));
10609b88f26SKrzysztof Grobelny }
10709b88f26SKrzysztof Grobelny 
TYPED_TEST(UnpackPropertiesTest,unpackDoesntChangeOriginalDataWhenPassedAsNonConstReference)10809b88f26SKrzysztof Grobelny TYPED_TEST(UnpackPropertiesTest,
109c8447d52SKrzysztof Grobelny            unpackDoesntChangeOriginalDataWhenPassedAsNonConstReference)
11009b88f26SKrzysztof Grobelny {
11109b88f26SKrzysztof Grobelny     using namespace testing;
11209b88f26SKrzysztof Grobelny 
11309b88f26SKrzysztof Grobelny     std::string val1, val2;
11409b88f26SKrzysztof Grobelny 
1156d83cf53SSzymon Dompke     EXPECT_FALSE(this->unpackPropertiesCall(this->data, "Key-1", val1));
1166d83cf53SSzymon Dompke     EXPECT_FALSE(this->unpackPropertiesCall(this->data, "Key-1", val2));
11709b88f26SKrzysztof Grobelny 
11809b88f26SKrzysztof Grobelny     ASSERT_THAT(val1, Eq("string"));
11909b88f26SKrzysztof Grobelny     ASSERT_THAT(val2, Eq("string"));
12009b88f26SKrzysztof Grobelny }
12109b88f26SKrzysztof Grobelny 
TYPED_TEST(UnpackPropertiesTest,doesntReportMissingPropertyForOptional)122c8447d52SKrzysztof Grobelny TYPED_TEST(UnpackPropertiesTest, doesntReportMissingPropertyForOptional)
12309b88f26SKrzysztof Grobelny {
12409b88f26SKrzysztof Grobelny     using namespace testing;
12509b88f26SKrzysztof Grobelny     using namespace std::string_literals;
12609b88f26SKrzysztof Grobelny 
127c8447d52SKrzysztof Grobelny     std::optional<std::string> val1;
128c8447d52SKrzysztof Grobelny     std::optional<std::string> val4;
12909b88f26SKrzysztof Grobelny 
130c8447d52SKrzysztof Grobelny     EXPECT_FALSE(
131c8447d52SKrzysztof Grobelny         this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-4", val4));
13209b88f26SKrzysztof Grobelny 
13309b88f26SKrzysztof Grobelny     ASSERT_THAT(val1, Eq("string"));
134c8447d52SKrzysztof Grobelny     ASSERT_THAT(val4, Eq(std::nullopt));
13509b88f26SKrzysztof Grobelny }
13609b88f26SKrzysztof Grobelny 
TYPED_TEST(UnpackPropertiesTest,setPresentPointersOnSuccess)137c8447d52SKrzysztof Grobelny TYPED_TEST(UnpackPropertiesTest, setPresentPointersOnSuccess)
13809b88f26SKrzysztof Grobelny {
13909b88f26SKrzysztof Grobelny     using namespace testing;
14009b88f26SKrzysztof Grobelny     using namespace std::string_literals;
14109b88f26SKrzysztof Grobelny 
142c8447d52SKrzysztof Grobelny     const std::string* val1 = nullptr;
143c8447d52SKrzysztof Grobelny     const float* val2 = nullptr;
144c8447d52SKrzysztof Grobelny     const double* val3 = nullptr;
145c8447d52SKrzysztof Grobelny     const std::string* val4 = nullptr;
14609b88f26SKrzysztof Grobelny 
147*06f265f6SPatrick Williams     EXPECT_FALSE(
148*06f265f6SPatrick Williams         this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2", val2,
149*06f265f6SPatrick Williams                                    "Key-3", val3, "Key-4", val4));
15009b88f26SKrzysztof Grobelny 
151c8447d52SKrzysztof Grobelny     ASSERT_TRUE(val1 && val2 && val3);
152c8447d52SKrzysztof Grobelny     ASSERT_TRUE(!val4);
153c8447d52SKrzysztof Grobelny 
154c8447d52SKrzysztof Grobelny     ASSERT_THAT(*val1, Eq("string"));
155c8447d52SKrzysztof Grobelny     ASSERT_THAT(*val2, FloatEq(42.f));
156c8447d52SKrzysztof Grobelny     ASSERT_THAT(*val3, DoubleEq(15.));
15709b88f26SKrzysztof Grobelny }
15809b88f26SKrzysztof Grobelny 
1596d83cf53SSzymon Dompke template <typename Params>
1606d83cf53SSzymon Dompke struct UnpackPropertiesThrowingTest : public UnpackPropertiesTest<Params>
16109b88f26SKrzysztof Grobelny {};
16209b88f26SKrzysztof Grobelny 
163c8447d52SKrzysztof Grobelny using ContainerTypesThrowing = testing::Types<TestingTypes<
164c8447d52SKrzysztof Grobelny     ThrowingUnpack, std::vector<std::pair<std::string, VariantType>>>>;
1656d83cf53SSzymon Dompke 
1666d83cf53SSzymon Dompke TYPED_TEST_SUITE(UnpackPropertiesThrowingTest, ContainerTypesThrowing);
1676d83cf53SSzymon Dompke 
TYPED_TEST(UnpackPropertiesThrowingTest,throwsErrorWhenKeyIsMissing)1686d83cf53SSzymon Dompke TYPED_TEST(UnpackPropertiesThrowingTest, throwsErrorWhenKeyIsMissing)
1696d83cf53SSzymon Dompke {
1706d83cf53SSzymon Dompke     using namespace testing;
1716d83cf53SSzymon Dompke 
1726d83cf53SSzymon Dompke     std::string val1;
1736d83cf53SSzymon Dompke     float val2 = 0.f;
1746d83cf53SSzymon Dompke     double val3 = 0.;
1756d83cf53SSzymon Dompke 
1766d83cf53SSzymon Dompke     auto error = captureException<exception::UnpackPropertyError>([&] {
1776d83cf53SSzymon Dompke         this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-4", val2,
1786d83cf53SSzymon Dompke                                    "Key-3", val3);
1796d83cf53SSzymon Dompke     });
1806d83cf53SSzymon Dompke 
1816d83cf53SSzymon Dompke     ASSERT_TRUE(error);
182c8447d52SKrzysztof Grobelny     ASSERT_THAT(error->reason, Eq(UnpackErrorReason::missingProperty));
1836d83cf53SSzymon Dompke     ASSERT_THAT(error->propertyName, Eq("Key-4"));
1846d83cf53SSzymon Dompke }
1856d83cf53SSzymon Dompke 
TYPED_TEST(UnpackPropertiesThrowingTest,throwsErrorWhenTypeDoesntMatch)1866d83cf53SSzymon Dompke TYPED_TEST(UnpackPropertiesThrowingTest, throwsErrorWhenTypeDoesntMatch)
1876d83cf53SSzymon Dompke {
1886d83cf53SSzymon Dompke     using namespace testing;
1896d83cf53SSzymon Dompke 
1906d83cf53SSzymon Dompke     std::string val1;
1916d83cf53SSzymon Dompke     std::string val2;
1926d83cf53SSzymon Dompke     double val3 = 0.;
1936d83cf53SSzymon Dompke 
1946d83cf53SSzymon Dompke     auto error = captureException<exception::UnpackPropertyError>([&] {
1956d83cf53SSzymon Dompke         this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2", val2,
1966d83cf53SSzymon Dompke                                    "Key-3", val3);
1976d83cf53SSzymon Dompke     });
1986d83cf53SSzymon Dompke 
1996d83cf53SSzymon Dompke     ASSERT_TRUE(error);
200c8447d52SKrzysztof Grobelny     ASSERT_THAT(error->reason, Eq(UnpackErrorReason::wrongType));
201c8447d52SKrzysztof Grobelny     ASSERT_THAT(error->propertyName, Eq("Key-2"));
202c8447d52SKrzysztof Grobelny }
203c8447d52SKrzysztof Grobelny 
TYPED_TEST(UnpackPropertiesThrowingTest,throwsErrorWhenOptionalTypeDoesntMatch)204c8447d52SKrzysztof Grobelny TYPED_TEST(UnpackPropertiesThrowingTest, throwsErrorWhenOptionalTypeDoesntMatch)
205c8447d52SKrzysztof Grobelny {
206c8447d52SKrzysztof Grobelny     using namespace testing;
207c8447d52SKrzysztof Grobelny 
208c8447d52SKrzysztof Grobelny     std::optional<std::string> val1;
209c8447d52SKrzysztof Grobelny     std::optional<std::string> val2;
210c8447d52SKrzysztof Grobelny 
211c8447d52SKrzysztof Grobelny     auto error = captureException<exception::UnpackPropertyError>([&] {
212c8447d52SKrzysztof Grobelny         this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2", val2);
213c8447d52SKrzysztof Grobelny     });
214c8447d52SKrzysztof Grobelny 
215c8447d52SKrzysztof Grobelny     ASSERT_TRUE(error);
216c8447d52SKrzysztof Grobelny     ASSERT_THAT(error->reason, Eq(UnpackErrorReason::wrongType));
2176d83cf53SSzymon Dompke     ASSERT_THAT(error->propertyName, Eq("Key-2"));
2186d83cf53SSzymon Dompke }
2196d83cf53SSzymon Dompke 
2206d83cf53SSzymon Dompke template <typename Params>
2216d83cf53SSzymon Dompke struct UnpackPropertiesNonThrowingTest : public UnpackPropertiesTest<Params>
2226d83cf53SSzymon Dompke {};
2236d83cf53SSzymon Dompke 
224c8447d52SKrzysztof Grobelny using ContainerTypesNonThrowing = testing::Types<TestingTypes<
225c8447d52SKrzysztof Grobelny     NonThrowingUnpack, std::vector<std::pair<std::string, VariantType>>>>;
2266d83cf53SSzymon Dompke 
2276d83cf53SSzymon Dompke TYPED_TEST_SUITE(UnpackPropertiesNonThrowingTest, ContainerTypesNonThrowing);
2286d83cf53SSzymon Dompke 
TYPED_TEST(UnpackPropertiesNonThrowingTest,ErrorWhenKeyIsMissing)2296d83cf53SSzymon Dompke TYPED_TEST(UnpackPropertiesNonThrowingTest, ErrorWhenKeyIsMissing)
2306d83cf53SSzymon Dompke {
2316d83cf53SSzymon Dompke     using namespace testing;
2326d83cf53SSzymon Dompke 
2336d83cf53SSzymon Dompke     std::string val1;
2346d83cf53SSzymon Dompke     float val2 = 0.f;
2356d83cf53SSzymon Dompke     double val3 = 0.;
2366d83cf53SSzymon Dompke 
2376d83cf53SSzymon Dompke     auto badProperty = this->unpackPropertiesCall(this->data, "Key-1", val1,
2386d83cf53SSzymon Dompke                                                   "Key-4", val2, "Key-3", val3);
2396d83cf53SSzymon Dompke 
2406d83cf53SSzymon Dompke     ASSERT_TRUE(badProperty);
241c8447d52SKrzysztof Grobelny     EXPECT_THAT(badProperty->reason, Eq(UnpackErrorReason::missingProperty));
242c8447d52SKrzysztof Grobelny     EXPECT_THAT(badProperty->property, Eq("Key-4"));
2436d83cf53SSzymon Dompke }
2446d83cf53SSzymon Dompke 
TYPED_TEST(UnpackPropertiesNonThrowingTest,ErrorWhenTypeDoesntMatch)2456d83cf53SSzymon Dompke TYPED_TEST(UnpackPropertiesNonThrowingTest, ErrorWhenTypeDoesntMatch)
2466d83cf53SSzymon Dompke {
2476d83cf53SSzymon Dompke     using namespace testing;
2486d83cf53SSzymon Dompke 
2496d83cf53SSzymon Dompke     std::string val1;
2506d83cf53SSzymon Dompke     std::string val2;
2516d83cf53SSzymon Dompke     double val3 = 0.;
2526d83cf53SSzymon Dompke 
2536d83cf53SSzymon Dompke     auto badProperty = this->unpackPropertiesCall(this->data, "Key-1", val1,
2546d83cf53SSzymon Dompke                                                   "Key-2", val2, "Key-3", val3);
2556d83cf53SSzymon Dompke 
2566d83cf53SSzymon Dompke     ASSERT_TRUE(badProperty);
257c8447d52SKrzysztof Grobelny     EXPECT_THAT(badProperty->reason, Eq(UnpackErrorReason::wrongType));
258c8447d52SKrzysztof Grobelny     EXPECT_THAT(badProperty->property, Eq("Key-2"));
259c8447d52SKrzysztof Grobelny }
260c8447d52SKrzysztof Grobelny 
TYPED_TEST(UnpackPropertiesNonThrowingTest,ErrorWhenOptionalTypeDoesntMatch)261c8447d52SKrzysztof Grobelny TYPED_TEST(UnpackPropertiesNonThrowingTest, ErrorWhenOptionalTypeDoesntMatch)
262c8447d52SKrzysztof Grobelny {
263c8447d52SKrzysztof Grobelny     using namespace testing;
264c8447d52SKrzysztof Grobelny 
265c8447d52SKrzysztof Grobelny     std::optional<std::string> val1;
266c8447d52SKrzysztof Grobelny     std::optional<std::string> val2;
267c8447d52SKrzysztof Grobelny 
268*06f265f6SPatrick Williams     auto badProperty =
269*06f265f6SPatrick Williams         this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2", val2);
270c8447d52SKrzysztof Grobelny 
271c8447d52SKrzysztof Grobelny     ASSERT_TRUE(badProperty);
272c8447d52SKrzysztof Grobelny     EXPECT_THAT(badProperty->reason, Eq(UnpackErrorReason::wrongType));
273c8447d52SKrzysztof Grobelny     EXPECT_THAT(badProperty->property, Eq("Key-2"));
2746d83cf53SSzymon Dompke }
2756d83cf53SSzymon Dompke 
2766d83cf53SSzymon Dompke template <typename Params>
2776d83cf53SSzymon Dompke struct UnpackPropertiesTest_ForVector : public UnpackPropertiesTest<Params>
2786d83cf53SSzymon Dompke {};
2796d83cf53SSzymon Dompke 
2806d83cf53SSzymon Dompke using ContainerTypesVector = testing::Types<
2816d83cf53SSzymon Dompke     TestingTypes<NonThrowingUnpack,
2826d83cf53SSzymon Dompke                  std::vector<std::pair<std::string, VariantType>>>,
2836d83cf53SSzymon Dompke     TestingTypes<ThrowingUnpack,
2846d83cf53SSzymon Dompke                  std::vector<std::pair<std::string, VariantType>>>>;
2856d83cf53SSzymon Dompke 
2866d83cf53SSzymon Dompke TYPED_TEST_SUITE(UnpackPropertiesTest_ForVector, ContainerTypesVector);
2876d83cf53SSzymon Dompke 
TYPED_TEST(UnpackPropertiesTest_ForVector,silentlyDiscardsDuplicatedKeyInData)2886d83cf53SSzymon Dompke TYPED_TEST(UnpackPropertiesTest_ForVector, silentlyDiscardsDuplicatedKeyInData)
28909b88f26SKrzysztof Grobelny {
29009b88f26SKrzysztof Grobelny     using namespace testing;
29109b88f26SKrzysztof Grobelny     using namespace std::string_literals;
29209b88f26SKrzysztof Grobelny 
29309b88f26SKrzysztof Grobelny     std::string val1;
29409b88f26SKrzysztof Grobelny     float val2 = 0.f;
29509b88f26SKrzysztof Grobelny     double val3 = 0.;
29609b88f26SKrzysztof Grobelny 
29709b88f26SKrzysztof Grobelny     this->data.insert(this->data.end(),
29809b88f26SKrzysztof Grobelny                       std::make_pair("Key-1"s, VariantType("string2"s)));
29909b88f26SKrzysztof Grobelny 
3006d83cf53SSzymon Dompke     EXPECT_FALSE(this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2",
3016d83cf53SSzymon Dompke                                             val2, "Key-3", val3));
30209b88f26SKrzysztof Grobelny 
30309b88f26SKrzysztof Grobelny     ASSERT_THAT(val1, Eq("string"));
30409b88f26SKrzysztof Grobelny     ASSERT_THAT(val2, FloatEq(42.f));
30509b88f26SKrzysztof Grobelny     ASSERT_THAT(val3, DoubleEq(15.));
30609b88f26SKrzysztof Grobelny }
30709b88f26SKrzysztof Grobelny 
30809b88f26SKrzysztof Grobelny } // namespace sdbusplus
309