added support for optionals in unpackProperties
- Added support for optionals
- Added support for pointers
- Removed support for moving data from input container
- Removed support for container types other than std::vector
Tested:
- Unit tests are passing
- Examples which use unpackProperties are working correctly
Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
Change-Id: I3dbd7333237a1373d784187951ad6abe217567d1
diff --git a/example/get-all-properties.cpp b/example/get-all-properties.cpp
index 330e0c1..53d2466 100644
--- a/example/get-all-properties.cpp
+++ b/example/get-all-properties.cpp
@@ -61,26 +61,26 @@
++fatalErrors_;
}
- void logBadProperty(const std::string& badProperty)
+ void logUnpackError(const sdbusplus::UnpackErrorReason reason,
+ const std::string& property)
{
- std::cerr << "BadProperty: " << badProperty << "\n";
+ std::cerr << "UnpackError: " << static_cast<int>(reason) << ", "
+ << property << "\n";
++fatalErrors_;
}
void logExpectedException(
const sdbusplus::exception::UnpackPropertyError& error)
{
- std::cout << "As expected " << error.what() << " => "
- << error.propertyName << " is missing because "
- << error.reason << "\n";
+ std::cout << "As expected " << error.what() << "\n";
}
void asyncGetAllPropertiesStringTypeOnly()
{
sdbusplus::asio::getAllProperties(
bus_, demoServiceName, demoObjectPath, demoInterfaceName,
- [this](boost::system::error_code ec,
- std::vector<std::pair<
+ [this](const boost::system::error_code ec,
+ const std::vector<std::pair<
std::string, std::variant<std::monostate, std::string>>>&
properties) -> void {
if (ec)
@@ -89,22 +89,25 @@
return;
}
{
- std::string greetings;
- std::string goodbyes;
- std::optional<std::string> badProperty =
- sdbusplus::unpackPropertiesNoThrow(
- properties, propertyGrettingName, greetings,
- propertyGoodbyesName, goodbyes);
+ const std::string* greetings = nullptr;
+ const std::string* goodbyes = nullptr;
+ const bool success = sdbusplus::unpackPropertiesNoThrow(
+ [this](const sdbusplus::UnpackErrorReason reason,
+ const std::string& property) {
+ logUnpackError(reason, property);
+ },
+ properties, propertyGrettingName, greetings,
+ propertyGoodbyesName, goodbyes);
- if (badProperty)
+ if (success)
{
- logBadProperty(*badProperty);
+ std::cout << "value of greetings: " << *greetings
+ << "\n";
+ std::cout << "value of goodbyes: " << *goodbyes << "\n";
}
else
{
- std::cout << "value of greetings: " << greetings
- << "\n";
- std::cout << "value of goodbyes: " << goodbyes << "\n";
+ ++fatalErrors_;
}
}
@@ -129,8 +132,8 @@
{
sdbusplus::asio::getAllProperties(
bus_, demoServiceName, demoObjectPath, demoInterfaceName,
- [this](boost::system::error_code ec,
- std::vector<std::pair<
+ [this](const boost::system::error_code ec,
+ const std::vector<std::pair<
std::string,
std::variant<std::monostate, std::string, uint32_t>>>&
properties) -> void {
diff --git a/include/sdbusplus/asio/property.hpp b/include/sdbusplus/asio/property.hpp
index 24c31bc..7dbec52 100644
--- a/include/sdbusplus/asio/property.hpp
+++ b/include/sdbusplus/asio/property.hpp
@@ -1,41 +1,61 @@
#pragma once
+#include <boost/type_traits.hpp>
#include <sdbusplus/asio/connection.hpp>
+#include <sdbusplus/utility/type_traits.hpp>
namespace sdbusplus::asio
{
+template <typename VariantType>
+inline void getAllProperties(
+ sdbusplus::asio::connection& bus, const std::string& service,
+ const std::string& path, const std::string& interface,
+ std::function<void(
+ const boost::system::error_code,
+ const std::vector<std::pair<std::string, VariantType>>&)>&& handler)
+{
+ static_assert(std::is_same_v<VariantType, std::decay_t<VariantType>>);
+
+ bus.async_method_call(std::move(handler), service, path,
+ "org.freedesktop.DBus.Properties", "GetAll",
+ interface);
+}
+
template <typename Handler>
inline void getAllProperties(sdbusplus::asio::connection& bus,
const std::string& service,
const std::string& path,
const std::string& interface, Handler&& handler)
{
- bus.async_method_call(std::forward<Handler>(handler), service, path,
- "org.freedesktop.DBus.Properties", "GetAll",
- interface);
+ using arg1_type =
+ std::tuple_element_t<1, boost::callable_traits::args_t<Handler>>;
+ using arg1_pair_type = std::decay_t<arg1_type>::value_type;
+ using arg1_value_type = arg1_pair_type::second_type;
+ getAllProperties<arg1_value_type>(bus, service, path, interface,
+ std::forward<Handler>(handler));
}
-template <typename T>
-inline void
- getProperty(sdbusplus::asio::connection& bus, const std::string& service,
- const std::string& path, const std::string& interface,
- const std::string& propertyName,
- std::function<void(boost::system::error_code, T)>&& handler)
+template <typename PropertyType>
+inline void getProperty(
+ sdbusplus::asio::connection& bus, const std::string& service,
+ const std::string& path, const std::string& interface,
+ const std::string& propertyName,
+ std::function<void(boost::system::error_code, PropertyType)>&& handler)
{
- static_assert(std::is_same_v<T, std::decay_t<T>>);
+ static_assert(std::is_same_v<PropertyType, std::decay_t<PropertyType>>);
bus.async_method_call(
- [handler =
- std::move(handler)](boost::system::error_code ec,
- std::variant<std::monostate, T>& ret) mutable {
+ [handler = std::move(handler)](
+ boost::system::error_code ec,
+ std::variant<std::monostate, PropertyType>& ret) mutable {
if (ec)
{
handler(ec, {});
return;
}
- if (T* value = std::get_if<T>(&ret))
+ if (PropertyType* value = std::get_if<PropertyType>(&ret))
{
handler(ec, std::move(*value));
return;
@@ -82,17 +102,18 @@
propertyName);
}
-template <typename T, typename Handler>
+template <typename PropertyType, typename Handler>
inline void setProperty(sdbusplus::asio::connection& bus,
const std::string& service, const std::string& path,
const std::string& interface,
- const std::string& propertyName, T&& propertyValue,
- Handler&& handler)
+ const std::string& propertyName,
+ PropertyType&& propertyValue, Handler&& handler)
{
- bus.async_method_call(
- std::forward<Handler>(handler), service, path,
- "org.freedesktop.DBus.Properties", "Set", interface, propertyName,
- std::variant<std::decay_t<T>>(std::forward<T>(propertyValue)));
+ bus.async_method_call(std::forward<Handler>(handler), service, path,
+ "org.freedesktop.DBus.Properties", "Set", interface,
+ propertyName,
+ std::variant<std::decay_t<PropertyType>>(
+ std::forward<PropertyType>(propertyValue)));
}
} // namespace sdbusplus::asio
diff --git a/include/sdbusplus/exception.hpp b/include/sdbusplus/exception.hpp
index 516f6f3..1b17f07 100644
--- a/include/sdbusplus/exception.hpp
+++ b/include/sdbusplus/exception.hpp
@@ -10,6 +10,12 @@
namespace sdbusplus
{
+enum class UnpackErrorReason
+{
+ missingProperty,
+ wrongType
+};
+
namespace exception
{
@@ -100,11 +106,8 @@
class UnpackPropertyError final : public internal_exception
{
public:
- UnpackPropertyError(std::string_view propertyName, std::string_view reason);
-
- static constexpr std::string_view reasonMissingProperty =
- "Missing property";
- static constexpr std::string_view reasonTypeNotMatched = "Type not matched";
+ UnpackPropertyError(std::string_view propertyName,
+ const UnpackErrorReason reason);
static constexpr auto errName =
"xyz.openbmc_project.sdbusplus.Error.UnpackPropertyError";
@@ -120,7 +123,7 @@
int get_errno() const noexcept override;
const std::string propertyName;
- const std::string reason;
+ const UnpackErrorReason reason;
private:
const std::string errWhatDetailed;
diff --git a/include/sdbusplus/unpack_properties.hpp b/include/sdbusplus/unpack_properties.hpp
index 4c1adfa..ac681aa 100644
--- a/include/sdbusplus/unpack_properties.hpp
+++ b/include/sdbusplus/unpack_properties.hpp
@@ -13,151 +13,151 @@
namespace sdbusplus
{
-namespace detail
+
+namespace details
{
-template <typename Variant, typename ValueType>
-bool getIf(Variant&& variant, ValueType& outValue) noexcept
+template <typename VariantType>
+inline auto findProperty(
+ const std::vector<std::pair<std::string, VariantType>>& container,
+ const std::string& key) noexcept
{
- if (auto value = std::get_if<ValueType>(&variant))
- {
- outValue = std::move(*value);
- return true;
- }
-
- return false;
+ return std::find_if(
+ container.begin(), container.end(),
+ [&key](const auto& keyValue) { return keyValue.first == key; });
}
-template <typename Container>
-auto findProperty(Container&& container, const std::string& key) noexcept
+template <typename OnErrorCallback, typename VariantType, typename ValueType>
+inline bool readProperty(
+ const OnErrorCallback& onErrorCallback,
+ const std::vector<std::pair<std::string, VariantType>>& container,
+ const std::string& expectedKey,
+ ValueType&
+ outValue) noexcept(noexcept(onErrorCallback(sdbusplus::
+ UnpackErrorReason{},
+ std::string{})))
{
- if constexpr (utility::has_member_find_v<Container>)
- {
- return container.find(key);
- }
- else
- {
- return std::find_if(
- std::begin(container), std::end(container),
- [&key](const auto& keyValue) { return keyValue.first == key; });
- }
-}
+ auto it = findProperty(container, expectedKey);
-template <typename Container>
-bool containsProperty(Container&& container, const std::string& key) noexcept
-{
- if constexpr (utility::has_member_contains_v<Container>)
+ if (it != container.end())
{
- return container.contains(key);
- }
- else
- {
- return findProperty(std::forward<Container>(container), key) !=
- std::end(container);
- }
-}
-
-template <size_t Index, typename Container, size_t N, typename ValueType,
- typename... Args>
-void readProperties(Container&& container, std::bitset<N>& assigned,
- const std::string& expectedKey, ValueType& outValue,
- Args&&... args) noexcept
-{
- static_assert(Index < N);
-
- auto it = findProperty(std::forward<Container>(container), expectedKey);
-
- if (it != std::end(container))
- {
- if (getIf(it->second, outValue))
+ if constexpr (std::is_pointer_v<ValueType>)
{
- assigned.set(Index);
- }
- }
-
- if constexpr (sizeof...(Args) > 0)
- {
- readProperties<Index + 1>(std::forward<Container>(container), assigned,
- std::forward<Args>(args)...);
- }
-}
-
-template <size_t Index, size_t N, typename ValueType, typename... Args>
-std::string findMissingProperty(std::bitset<N>& assigned,
- const std::string& key, ValueType&,
- Args&&... args) noexcept
-{
- static_assert(Index < N);
-
- if (!assigned.test(Index))
- {
- return key;
- }
-
- if constexpr (sizeof...(Args) > 0)
- {
- return findMissingProperty<Index + 1>(assigned,
- std::forward<Args>(args)...);
- }
-
- return {};
-}
-
-template <bool ReturnBadProperty, typename Container, typename... Args>
-auto unpackPropertiesCommon(Container&& input,
- Args&&... args) noexcept(ReturnBadProperty)
-{
- static_assert(sizeof...(Args) % 2 == 0);
-
- auto assigned = std::bitset<sizeof...(Args) / 2>();
-
- detail::readProperties<0>(input, assigned, std::forward<Args>(args)...);
-
- if (!assigned.all())
- {
- auto missingProperty = detail::findMissingProperty<0>(
- assigned, std::forward<Args>(args)...);
-
- if constexpr (ReturnBadProperty)
- {
- return std::optional{missingProperty};
- }
- else
- {
- if (detail::containsProperty(std::forward<Container>(input),
- missingProperty))
+ if (const auto* value = std::get_if<
+ std::remove_cv_t<std::remove_pointer_t<ValueType>>>(
+ &it->second))
{
- throw exception::UnpackPropertyError(
- missingProperty,
- exception::UnpackPropertyError::reasonTypeNotMatched);
+ outValue = value;
}
else
{
- throw exception::UnpackPropertyError(
- missingProperty,
- exception::UnpackPropertyError::reasonMissingProperty);
+ onErrorCallback(UnpackErrorReason::wrongType, expectedKey);
+ return false;
+ }
+ }
+ else if constexpr (utility::is_optional_v<ValueType>)
+ {
+ using InnerType = typename ValueType::value_type;
+ static_assert(!std::is_pointer_v<InnerType>,
+ "std::optional<T*> is not supported");
+ if (const auto value = std::get_if<InnerType>(&it->second))
+
+ {
+ outValue = *value;
+ }
+ else
+ {
+ onErrorCallback(UnpackErrorReason::wrongType, expectedKey);
+ return false;
+ }
+ }
+ else
+ {
+ if (const auto value = std::get_if<ValueType>(&it->second))
+ {
+ outValue = *value;
+ }
+ else
+ {
+ onErrorCallback(UnpackErrorReason::wrongType, expectedKey);
+ return false;
}
}
}
- return std::conditional_t<ReturnBadProperty, std::optional<std::string>,
- void>();
+ else if constexpr (!utility::is_optional_v<ValueType> &&
+ !std::is_pointer_v<ValueType>)
+ {
+ onErrorCallback(UnpackErrorReason::missingProperty, expectedKey);
+ return false;
+ }
+
+ return true;
}
-} // namespace detail
-
-template <typename Container, typename... Args>
-void unpackProperties(Container&& input, Args&&... args)
+template <typename OnErrorCallback, typename VariantType, typename ValueType,
+ typename... Args>
+inline bool readProperties(
+ OnErrorCallback&& onErrorCallback,
+ const std::vector<std::pair<std::string, VariantType>>& container,
+ const std::string& expectedKey, ValueType& outValue,
+ Args&&... args) noexcept(noexcept(onErrorCallback(sdbusplus::
+ UnpackErrorReason{},
+ std::string{})))
{
- detail::unpackPropertiesCommon<false, Container, Args...>(
- std::forward<Container>(input), std::forward<Args>(args)...);
+ if (!readProperty(onErrorCallback, container, expectedKey, outValue))
+ {
+ return false;
+ }
+
+ if constexpr (sizeof...(Args) > 0)
+ {
+ return readProperties(std::forward<OnErrorCallback>(onErrorCallback),
+ container, std::forward<Args>(args)...);
+ }
+
+ return true;
}
-template <typename Container, typename... Args>
-std::optional<std::string> unpackPropertiesNoThrow(Container&& input,
- Args&&... args) noexcept
+template <typename OnErrorCallback, typename VariantType, typename... Args>
+inline auto unpackPropertiesCommon(
+ OnErrorCallback&& onErrorCallback,
+ const std::vector<std::pair<std::string, VariantType>>& input,
+ Args&&... args) noexcept(noexcept(onErrorCallback(sdbusplus::
+ UnpackErrorReason{},
+ std::string{})))
{
- return detail::unpackPropertiesCommon<true, Container, Args...>(
- std::forward<Container>(input), std::forward<Args>(args)...);
+ static_assert(
+ sizeof...(Args) % 2 == 0,
+ "Expected number of arguments to be even, but got odd number instead");
+
+ return details::readProperties(
+ std::forward<OnErrorCallback>(onErrorCallback), input,
+ std::forward<Args>(args)...);
+}
+
+} // namespace details
+
+template <typename VariantType, typename... Args>
+inline void unpackProperties(
+ const std::vector<std::pair<std::string, VariantType>>& input,
+ Args&&... args)
+{
+ details::unpackPropertiesCommon(
+ [](const UnpackErrorReason reason, const std::string& property) {
+ throw exception::UnpackPropertyError(property, reason);
+ },
+ input, std::forward<Args>(args)...);
+}
+
+template <typename OnErrorCallback, typename VariantType, typename... Args>
+inline bool unpackPropertiesNoThrow(
+ OnErrorCallback&& onErrorCallback,
+ const std::vector<std::pair<std::string, VariantType>>& input,
+ Args&&... args) noexcept
+{
+ return details::unpackPropertiesCommon(
+ std::forward<OnErrorCallback>(onErrorCallback), input,
+ std::forward<Args>(args)...);
}
} // namespace sdbusplus
diff --git a/include/sdbusplus/utility/type_traits.hpp b/include/sdbusplus/utility/type_traits.hpp
index 2b0ddd0..b91fa20 100644
--- a/include/sdbusplus/utility/type_traits.hpp
+++ b/include/sdbusplus/utility/type_traits.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include <cstddef>
+#include <optional>
#include <tuple>
#include <type_traits>
@@ -145,6 +147,29 @@
template <typename T>
constexpr bool has_member_contains_v = has_member_contains<T>::value;
+template <typename T>
+struct is_optional : public std::false_type
+{};
+
+template <typename T>
+struct is_optional<std::optional<T>> : public std::true_type
+{};
+
+template <typename T>
+struct is_optional<const std::optional<T>> : public std::true_type
+{};
+
+template <typename T>
+struct is_optional<std::optional<T>&> : public std::true_type
+{};
+
+template <typename T>
+struct is_optional<const std::optional<T>&> : public std::true_type
+{};
+
+template <typename T>
+constexpr bool is_optional_v = is_optional<T>::value;
+
} // namespace utility
} // namespace sdbusplus
diff --git a/src/exception.cpp b/src/exception.cpp
index 4a04dea..05edf92 100644
--- a/src/exception.cpp
+++ b/src/exception.cpp
@@ -139,12 +139,24 @@
return EINVAL;
}
+std::string unpackErrorReasonToString(const UnpackErrorReason reason)
+{
+ switch (reason)
+ {
+ case UnpackErrorReason::missingProperty:
+ return "Missing property";
+ case UnpackErrorReason::wrongType:
+ return "Type not matched";
+ }
+ return "Unknown";
+}
+
UnpackPropertyError::UnpackPropertyError(std::string_view propertyNameIn,
- std::string_view reasonIn) :
+ const UnpackErrorReason reasonIn) :
propertyName(propertyNameIn),
reason(reasonIn),
errWhatDetailed(std::string(errWhat) + " PropertyName: '" + propertyName +
- "', Reason: '" + reason + "'.")
+ "', Reason: '" + unpackErrorReasonToString(reason) + "'.")
{}
const char* UnpackPropertyError::name() const noexcept
diff --git a/test/unpack_properties.cpp b/test/unpack_properties.cpp
index cb7b122..656dc41 100644
--- a/test/unpack_properties.cpp
+++ b/test/unpack_properties.cpp
@@ -18,10 +18,23 @@
struct NonThrowingUnpack
{
- template <typename... Args>
- std::optional<std::string> operator()(Args&&... args) const
+ struct UnpackError
{
- return unpackPropertiesNoThrow(std::forward<Args>(args)...);
+ sdbusplus::UnpackErrorReason reason;
+ std::string property;
+ };
+
+ template <typename... Args>
+ std::optional<UnpackError> operator()(Args&&... args) const
+ {
+ std::optional<UnpackError> error;
+ unpackPropertiesNoThrow(
+ [&error](const sdbusplus::UnpackErrorReason reason,
+ const std::string& property) {
+ error.emplace(reason, property);
+ },
+ std::forward<Args>(args)...);
+ return error;
}
};
@@ -36,14 +49,8 @@
using ContainerTypes = testing::Types<
TestingTypes<NonThrowingUnpack,
std::vector<std::pair<std::string, VariantType>>>,
- TestingTypes<NonThrowingUnpack,
- boost::container::flat_map<std::string, VariantType>>,
- TestingTypes<NonThrowingUnpack, std::map<std::string, VariantType>>,
TestingTypes<ThrowingUnpack,
- std::vector<std::pair<std::string, VariantType>>>,
- TestingTypes<ThrowingUnpack,
- boost::container::flat_map<std::string, VariantType>>,
- TestingTypes<ThrowingUnpack, std::map<std::string, VariantType>>>;
+ std::vector<std::pair<std::string, VariantType>>>>;
template <typename Exception, typename F>
std::optional<Exception> captureException(F&& code)
@@ -96,7 +103,7 @@
}
TYPED_TEST(UnpackPropertiesTest,
- unpackChangesOriginalDataWhenPassedAsNonConstReference)
+ unpackDoesntChangeOriginalDataWhenPassedAsNonConstReference)
{
using namespace testing;
@@ -106,75 +113,52 @@
EXPECT_FALSE(this->unpackPropertiesCall(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;
-
- EXPECT_FALSE(this->unpackPropertiesCall(Const(this->data), "Key-1", val1));
- EXPECT_FALSE(this->unpackPropertiesCall(Const(this->data), "Key-1", val2));
-
- ASSERT_THAT(val1, Eq("string"));
ASSERT_THAT(val2, Eq("string"));
}
-TYPED_TEST(UnpackPropertiesTest,
- returnsUndefinedValueForDuplicatedKeysWhenDataIsNonConstReference)
+TYPED_TEST(UnpackPropertiesTest, doesntReportMissingPropertyForOptional)
{
using namespace testing;
using namespace std::string_literals;
- std::string val1;
- float val2 = 0.f;
- double val3 = 0.;
- std::string val4;
+ std::optional<std::string> val1;
+ std::optional<std::string> val4;
- EXPECT_FALSE(this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2",
- val2, "Key-3", val3, "Key-1",
- val4));
+ EXPECT_FALSE(
+ this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-4", val4));
ASSERT_THAT(val1, Eq("string"));
- ASSERT_THAT(val2, FloatEq(42.f));
- ASSERT_THAT(val3, DoubleEq(15.));
- ASSERT_THAT(val4, Not(Eq("string")));
+ ASSERT_THAT(val4, Eq(std::nullopt));
}
-TYPED_TEST(UnpackPropertiesTest,
- returnsValueForDuplicatedKeysWhenDataIsConstReference)
+TYPED_TEST(UnpackPropertiesTest, setPresentPointersOnSuccess)
{
using namespace testing;
using namespace std::string_literals;
- std::string val1;
- float val2 = 0.f;
- double val3 = 0.;
- std::string val4;
+ const std::string* val1 = nullptr;
+ const float* val2 = nullptr;
+ const double* val3 = nullptr;
+ const std::string* val4 = nullptr;
- EXPECT_FALSE(this->unpackPropertiesCall(Const(this->data), "Key-1", val1,
- "Key-2", val2, "Key-3", val3,
- "Key-1", val4));
+ EXPECT_FALSE(this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2",
+ val2, "Key-3", val3, "Key-4",
+ val4));
- ASSERT_THAT(val1, Eq("string"));
- ASSERT_THAT(val2, FloatEq(42.f));
- ASSERT_THAT(val3, DoubleEq(15.));
- ASSERT_THAT(val4, Eq("string"));
+ ASSERT_TRUE(val1 && val2 && val3);
+ ASSERT_TRUE(!val4);
+
+ ASSERT_THAT(*val1, Eq("string"));
+ ASSERT_THAT(*val2, FloatEq(42.f));
+ ASSERT_THAT(*val3, DoubleEq(15.));
}
template <typename Params>
struct UnpackPropertiesThrowingTest : public UnpackPropertiesTest<Params>
{};
-using ContainerTypesThrowing = testing::Types<
- TestingTypes<ThrowingUnpack,
- std::vector<std::pair<std::string, VariantType>>>,
- TestingTypes<ThrowingUnpack,
- boost::container::flat_map<std::string, VariantType>>,
- TestingTypes<ThrowingUnpack, std::map<std::string, VariantType>>>;
+using ContainerTypesThrowing = testing::Types<TestingTypes<
+ ThrowingUnpack, std::vector<std::pair<std::string, VariantType>>>>;
TYPED_TEST_SUITE(UnpackPropertiesThrowingTest, ContainerTypesThrowing);
@@ -192,8 +176,7 @@
});
ASSERT_TRUE(error);
- ASSERT_THAT(error->reason,
- Eq(exception::UnpackPropertyError::reasonMissingProperty));
+ ASSERT_THAT(error->reason, Eq(UnpackErrorReason::missingProperty));
ASSERT_THAT(error->propertyName, Eq("Key-4"));
}
@@ -211,8 +194,23 @@
});
ASSERT_TRUE(error);
- ASSERT_THAT(error->reason,
- Eq(exception::UnpackPropertyError::reasonTypeNotMatched));
+ ASSERT_THAT(error->reason, Eq(UnpackErrorReason::wrongType));
+ ASSERT_THAT(error->propertyName, Eq("Key-2"));
+}
+
+TYPED_TEST(UnpackPropertiesThrowingTest, throwsErrorWhenOptionalTypeDoesntMatch)
+{
+ using namespace testing;
+
+ std::optional<std::string> val1;
+ std::optional<std::string> val2;
+
+ auto error = captureException<exception::UnpackPropertyError>([&] {
+ this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2", val2);
+ });
+
+ ASSERT_TRUE(error);
+ ASSERT_THAT(error->reason, Eq(UnpackErrorReason::wrongType));
ASSERT_THAT(error->propertyName, Eq("Key-2"));
}
@@ -220,12 +218,8 @@
struct UnpackPropertiesNonThrowingTest : public UnpackPropertiesTest<Params>
{};
-using ContainerTypesNonThrowing = testing::Types<
- TestingTypes<NonThrowingUnpack,
- std::vector<std::pair<std::string, VariantType>>>,
- TestingTypes<NonThrowingUnpack,
- boost::container::flat_map<std::string, VariantType>>,
- TestingTypes<NonThrowingUnpack, std::map<std::string, VariantType>>>;
+using ContainerTypesNonThrowing = testing::Types<TestingTypes<
+ NonThrowingUnpack, std::vector<std::pair<std::string, VariantType>>>>;
TYPED_TEST_SUITE(UnpackPropertiesNonThrowingTest, ContainerTypesNonThrowing);
@@ -241,7 +235,8 @@
"Key-4", val2, "Key-3", val3);
ASSERT_TRUE(badProperty);
- ASSERT_THAT(*badProperty, Eq("Key-4"));
+ EXPECT_THAT(badProperty->reason, Eq(UnpackErrorReason::missingProperty));
+ EXPECT_THAT(badProperty->property, Eq("Key-4"));
}
TYPED_TEST(UnpackPropertiesNonThrowingTest, ErrorWhenTypeDoesntMatch)
@@ -256,7 +251,23 @@
"Key-2", val2, "Key-3", val3);
ASSERT_TRUE(badProperty);
- ASSERT_THAT(*badProperty, Eq("Key-2"));
+ EXPECT_THAT(badProperty->reason, Eq(UnpackErrorReason::wrongType));
+ EXPECT_THAT(badProperty->property, Eq("Key-2"));
+}
+
+TYPED_TEST(UnpackPropertiesNonThrowingTest, ErrorWhenOptionalTypeDoesntMatch)
+{
+ using namespace testing;
+
+ std::optional<std::string> val1;
+ std::optional<std::string> val2;
+
+ auto badProperty =
+ this->unpackPropertiesCall(this->data, "Key-1", val1, "Key-2", val2);
+
+ ASSERT_TRUE(badProperty);
+ EXPECT_THAT(badProperty->reason, Eq(UnpackErrorReason::wrongType));
+ EXPECT_THAT(badProperty->property, Eq("Key-2"));
}
template <typename Params>
diff --git a/test/utility/type_traits.cpp b/test/utility/type_traits.cpp
index 8526f29..e5197d2 100644
--- a/test/utility/type_traits.cpp
+++ b/test/utility/type_traits.cpp
@@ -84,6 +84,20 @@
ASSERT_THAT(has_member_contains_v<Bar>, Eq(false));
}
+TEST(TypeTraits, IsOptional)
+{
+ using sdbusplus::utility::is_optional;
+ using sdbusplus::utility::is_optional_v;
+
+ ASSERT_TRUE(is_optional<std::optional<int>>::value);
+ ASSERT_TRUE(is_optional<std::optional<int>&>::value);
+ ASSERT_FALSE(is_optional<int>::value);
+
+ ASSERT_TRUE(is_optional_v<std::optional<int>>);
+ ASSERT_TRUE(is_optional_v<std::optional<int>&>);
+ ASSERT_FALSE(is_optional_v<int>);
+}
+
// Tests for dedup_variant.
static_assert(std::is_same_v<std::variant<size_t>,
sdbusplus::utility::dedup_variant_t<size_t>>);