|  | #include <boost/container/flat_map.hpp> | 
|  | #include <sdbusplus/unpack_properties.hpp> | 
|  |  | 
|  | #include <gmock/gmock.h> | 
|  |  | 
|  | namespace sdbusplus | 
|  | { | 
|  |  | 
|  | using VariantType = std::variant<std::string, uint32_t, float, double>; | 
|  | using ContainerTypes = | 
|  | testing::Types<std::vector<std::pair<std::string, VariantType>>, | 
|  | boost::container::flat_map<std::string, VariantType>, | 
|  | std::map<std::string, VariantType>>; | 
|  |  | 
|  | template <typename Exception, typename F> | 
|  | std::optional<Exception> captureException(F&& code) | 
|  | { | 
|  | try | 
|  | { | 
|  | code(); | 
|  | } | 
|  | catch (const Exception& e) | 
|  | { | 
|  | return e; | 
|  | } | 
|  |  | 
|  | return std::nullopt; | 
|  | } | 
|  |  | 
|  | template <typename Container> | 
|  | struct UnpackPropertiesTest : public testing::Test | 
|  | { | 
|  | void SetUp() override | 
|  | { | 
|  | using namespace std::string_literals; | 
|  |  | 
|  | data.insert(data.end(), | 
|  | std::make_pair("Key-1"s, VariantType("string"s))); | 
|  | data.insert(data.end(), std::make_pair("Key-2"s, VariantType(42.f))); | 
|  | data.insert(data.end(), std::make_pair("Key-3"s, VariantType(15.))); | 
|  | } | 
|  |  | 
|  | Container data; | 
|  | }; | 
|  |  | 
|  | TYPED_TEST_SUITE(UnpackPropertiesTest, ContainerTypes); | 
|  |  | 
|  | TYPED_TEST(UnpackPropertiesTest, returnsValueWhenKeyIsPresentAndTypeMatches) | 
|  | { | 
|  | using namespace testing; | 
|  |  | 
|  | std::string val1; | 
|  | float val2 = 0.f; | 
|  | double val3 = 0.; | 
|  |  | 
|  | unpackProperties(this->data, "Key-1", val1, "Key-2", val2, "Key-3", val3); | 
|  |  | 
|  | ASSERT_THAT(val1, Eq("string")); | 
|  | ASSERT_THAT(val2, FloatEq(42.f)); | 
|  | ASSERT_THAT(val3, DoubleEq(15.)); | 
|  | } | 
|  |  | 
|  | TYPED_TEST(UnpackPropertiesTest, | 
|  | unpackChangesOriginalDataWhenPassedAsNonConstReference) | 
|  | { | 
|  | using namespace testing; | 
|  |  | 
|  | std::string val1, val2; | 
|  |  | 
|  | unpackProperties(this->data, "Key-1", val1); | 
|  | unpackProperties(this->data, "Key-1", val2); | 
|  |  | 
|  | ASSERT_THAT(val1, Eq("string")); | 
|  | ASSERT_THAT(val2, Not(Eq("string"))); | 
|  | } | 
|  |  | 
|  | TYPED_TEST(UnpackPropertiesTest, | 
|  | unpackDoesntChangeOriginalDataWhenPassesAsConstReference) | 
|  | { | 
|  | using namespace testing; | 
|  |  | 
|  | std::string val1, val2; | 
|  |  | 
|  | unpackProperties(Const(this->data), "Key-1", val1); | 
|  | unpackProperties(Const(this->data), "Key-1", val2); | 
|  |  | 
|  | ASSERT_THAT(val1, Eq("string")); | 
|  | ASSERT_THAT(val2, Eq("string")); | 
|  | } | 
|  |  | 
|  | TYPED_TEST(UnpackPropertiesTest, throwsErrorWhenKeyIsMissing) | 
|  | { | 
|  | using namespace testing; | 
|  |  | 
|  | std::string val1; | 
|  | float val2 = 0.f; | 
|  | double val3 = 0.; | 
|  |  | 
|  | auto error = captureException<exception::UnpackPropertyError>([&] { | 
|  | unpackProperties(this->data, "Key-1", val1, "Key-4", val2, "Key-3", | 
|  | val3); | 
|  | }); | 
|  |  | 
|  | ASSERT_TRUE(error); | 
|  | ASSERT_THAT(error->reason, | 
|  | Eq(exception::UnpackPropertyError::reasonMissingProperty)); | 
|  | ASSERT_THAT(error->propertyName, Eq("Key-4")); | 
|  | } | 
|  |  | 
|  | TYPED_TEST(UnpackPropertiesTest, throwsErrorWhenTypeDoesntMatch) | 
|  | { | 
|  | using namespace testing; | 
|  |  | 
|  | std::string val1; | 
|  | std::string val2; | 
|  | double val3 = 0.; | 
|  |  | 
|  | auto error = captureException<exception::UnpackPropertyError>([&] { | 
|  | unpackProperties(this->data, "Key-1", val1, "Key-2", val2, "Key-3", | 
|  | val3); | 
|  | }); | 
|  |  | 
|  | ASSERT_TRUE(error); | 
|  | ASSERT_THAT(error->reason, | 
|  | Eq(exception::UnpackPropertyError::reasonTypeNotMatched)); | 
|  | ASSERT_THAT(error->propertyName, Eq("Key-2")); | 
|  | } | 
|  |  | 
|  | TYPED_TEST(UnpackPropertiesTest, | 
|  | returnsUndefinedValueForDuplicatedKeysWhenDataIsNonConstReference) | 
|  | { | 
|  | using namespace testing; | 
|  | using namespace std::string_literals; | 
|  |  | 
|  | std::string val1; | 
|  | float val2 = 0.f; | 
|  | double val3 = 0.; | 
|  | std::string val4; | 
|  |  | 
|  | unpackProperties(this->data, "Key-1", val1, "Key-2", val2, "Key-3", val3, | 
|  | "Key-1", val4); | 
|  |  | 
|  | ASSERT_THAT(val1, Eq("string")); | 
|  | ASSERT_THAT(val2, FloatEq(42.f)); | 
|  | ASSERT_THAT(val3, DoubleEq(15.)); | 
|  | ASSERT_THAT(val4, Not(Eq("string"))); | 
|  | } | 
|  |  | 
|  | TYPED_TEST(UnpackPropertiesTest, | 
|  | returnsValueForDuplicatedKeysWhenDataIsConstReference) | 
|  | { | 
|  | using namespace testing; | 
|  | using namespace std::string_literals; | 
|  |  | 
|  | std::string val1; | 
|  | float val2 = 0.f; | 
|  | double val3 = 0.; | 
|  | std::string val4; | 
|  |  | 
|  | unpackProperties(Const(this->data), "Key-1", val1, "Key-2", val2, "Key-3", | 
|  | val3, "Key-1", val4); | 
|  |  | 
|  | ASSERT_THAT(val1, Eq("string")); | 
|  | ASSERT_THAT(val2, FloatEq(42.f)); | 
|  | ASSERT_THAT(val3, DoubleEq(15.)); | 
|  | ASSERT_THAT(val4, Eq("string")); | 
|  | } | 
|  |  | 
|  | struct UnpackPropertiesTest_ForVector : | 
|  | public UnpackPropertiesTest< | 
|  | std::vector<std::pair<std::string, VariantType>>> | 
|  | {}; | 
|  |  | 
|  | TEST_F(UnpackPropertiesTest_ForVector, silentlyDiscardsDuplicatedKeyInData) | 
|  | { | 
|  | using namespace testing; | 
|  | using namespace std::string_literals; | 
|  |  | 
|  | std::string val1; | 
|  | float val2 = 0.f; | 
|  | double val3 = 0.; | 
|  |  | 
|  | this->data.insert(this->data.end(), | 
|  | std::make_pair("Key-1"s, VariantType("string2"s))); | 
|  |  | 
|  | unpackProperties(this->data, "Key-1", val1, "Key-2", val2, "Key-3", val3); | 
|  |  | 
|  | ASSERT_THAT(val1, Eq("string")); | 
|  | ASSERT_THAT(val2, FloatEq(42.f)); | 
|  | ASSERT_THAT(val3, DoubleEq(15.)); | 
|  | } | 
|  |  | 
|  | } // namespace sdbusplus |