Skip to content

Commit

Permalink
iox-eclipse-iceoryx#1750 Add 'Expects' call to 'expected::value()' an…
Browse files Browse the repository at this point in the history
…d 'has_error'

Signed-off-by: Simon Hoinkis <[email protected]>
  • Loading branch information
mossmaurice committed Oct 20, 2022
1 parent 8df1f7e commit db5ecdd
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 35 deletions.
36 changes: 18 additions & 18 deletions iceoryx_hoofs/include/iceoryx_hoofs/cxx/expected.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,21 +243,22 @@ class IOX_NO_DISCARD expected<ErrorType> : public FunctionalInterface<expected<E
bool has_error() const noexcept;

/// @brief returns a reference to the contained error value, if the expected
/// does not contain an error this is undefined behavior
/// does not contain an error the application terminates
/// @return reference to the internally contained error
ErrorType& get_error() & noexcept;

/// @brief returns a const reference to the contained error value, if the expected
/// does not contain an error this is undefined behavior
/// does not contain an error the application terminates
/// @return const reference to the internally contained error
const ErrorType& get_error() const& noexcept;

/// @brief returns a rvalue reference to the contained error value, if the expected
/// does not contain an error this is undefined behavior
/// does not contain an error the application terminates
/// @return rvalue reference to the internally contained error
ErrorType&& get_error() && noexcept;

private:
const ErrorType& get_error_unchecked() const noexcept;
explicit expected(variant<ErrorType>&& store) noexcept;
variant<ErrorType> m_store;
static constexpr uint64_t ERROR_INDEX = 0U;
Expand Down Expand Up @@ -358,38 +359,37 @@ class IOX_NO_DISCARD expected<ValueType, ErrorType>
bool has_error() const noexcept;

/// @brief returns a reference to the contained error value, if the expected
/// does not contain an error this is undefined behavior
/// does not contain an error the application terminates
/// @return reference to the internally contained error
ErrorType& get_error() & noexcept;

/// @brief returns a const reference to the contained error value, if the expected
/// does not contain an error this is undefined behavior
/// does not contain an error the application terminates
/// @return const reference to the internally contained error
const ErrorType& get_error() const& noexcept;

/// @brief returns a rvalue reference to the contained error value, if the expected
/// does not contain an error this is undefined behavior
/// does not contain an error the application terminates
/// @return rvalue reference to the internally contained error
ErrorType&& get_error() && noexcept;

/// @brief returns a reference to the contained success value, if the expected
/// does not contain a success value this is undefined behavior
/// does not contain a success value the application terminates
/// @return reference to the internally contained value
ValueType& value() & noexcept;

/// @brief returns a const reference to the contained success value, if the expected
/// does not contain a success value this is undefined behavior
/// does not contain a success value the application terminates
/// @return const reference to the internally contained value
const ValueType& value() const& noexcept;

/// @brief returns a reference to the contained success value, if the expected
/// does not contain a success value this is undefined behavior
/// does not contain a success value the application terminates
/// @return rvalue reference to the internally contained value
ValueType&& value() && noexcept;

/// @brief dereferencing operator which returns a reference to the contained
/// success value. if the expected contains an error the behavior is
/// undefined.
/// success value. if the expected contains an error the application terminates
/// @return reference to the contained value
/// @code
/// cxx::expected<int, float> frodo(success<int>(45));
Expand All @@ -399,8 +399,7 @@ class IOX_NO_DISCARD expected<ValueType, ErrorType>
ValueType& operator*() noexcept;

/// @brief dereferencing operator which returns a reference to the contained
/// success value. if the expected contains an error the behavior is
/// undefined.
/// success value. if the expected contains an error the application terminates
/// @return const reference to the contained value
/// @code
/// cxx::expected<int, float> frodo(success<int>(45));
Expand All @@ -409,17 +408,17 @@ class IOX_NO_DISCARD expected<ValueType, ErrorType>
/// @endcode
const ValueType& operator*() const noexcept;

/// @brief arrow operator which returns the pointer to the contained success value.
/// if the expected contains an error the behavior is undefined.
/// @brief arrow operator which returns the pointer to the contained success value
/// if the expected contains an error the application terminates
/// @return pointer of type ValueType to the contained value
/// @code
/// cxx::expected<std::vector<int>, int> holyPiotr(success<std::vector<int>>({1,2,3}));
/// holyPiotr->push_back(4);
/// @endcode
ValueType* operator->() noexcept;

/// @brief arrow operator which returns the pointer to the contained success value.
/// if the expected contains an error the behavior is undefined.
/// @brief arrow operator which returns the pointer to the contained success value
/// if the expected contains an error the the application terminates
/// @return pointer of type const ValueType to the contained value
/// @code
/// cxx::expected<std::vector<int>, int> holyPiotr(success<std::vector<int>>({1,2,3}));
Expand Down Expand Up @@ -449,6 +448,8 @@ class IOX_NO_DISCARD expected<ValueType, ErrorType>

private:
explicit expected(variant<ValueType, ErrorType>&& store) noexcept;
const ErrorType& get_error_unchecked() const noexcept;
const ValueType& value_unchecked() const noexcept;
variant<ValueType, ErrorType> m_store;
static constexpr uint64_t VALUE_INDEX = 0U;
static constexpr uint64_t ERROR_INDEX = 1U;
Expand All @@ -461,7 +462,6 @@ class IOX_NO_DISCARD expected<void, ErrorType> : public expected<ErrorType>
using expected<ErrorType>::expected;
};


} // namespace cxx
} // namespace iox

Expand Down
61 changes: 44 additions & 17 deletions iceoryx_hoofs/include/iceoryx_hoofs/internal/cxx/expected.inl
Original file line number Diff line number Diff line change
Expand Up @@ -156,43 +156,55 @@ inline bool expected<ValueType, ErrorType>::has_error() const noexcept
template <typename ValueType, typename ErrorType>
inline ErrorType&& expected<ValueType, ErrorType>::get_error() && noexcept
{
return std::move(*m_store.template get_at_index<ERROR_INDEX>());
return std::move(get_error());
}

template <typename ValueType, typename ErrorType>
inline ErrorType& expected<ValueType, ErrorType>::get_error() & noexcept
{
// AXIVION Next Construct AutosarC++19_03-A5.2.3 : const cast to avoid code duplication
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
return const_cast<ErrorType&>(const_cast<const expected<ValueType, ErrorType>*>(this)->get_error());
}

template <typename ValueType, typename ErrorType>
inline const ErrorType& expected<ValueType, ErrorType>::get_error() const& noexcept
{
Expects(has_error());
return get_error_unchecked();
}

template <typename ValueType, typename ErrorType>
inline const ErrorType& expected<ValueType, ErrorType>::get_error_unchecked() const noexcept
{
return *m_store.template get_at_index<ERROR_INDEX>();
}

template <typename ValueType, typename ErrorType>
inline ValueType&& expected<ValueType, ErrorType>::value() && noexcept
{
return std::move(*m_store.template get_at_index<VALUE_INDEX>());
return std::move(value());
}

template <typename ValueType, typename ErrorType>
inline const ValueType& expected<ValueType, ErrorType>::value() const& noexcept
{
return *m_store.template get_at_index<VALUE_INDEX>();
Expects(!has_error());
return value_unchecked();
}

template <typename ValueType, typename ErrorType>
inline ValueType& expected<ValueType, ErrorType>::value() & noexcept
{
return *m_store.template get_at_index<VALUE_INDEX>();
}

template <typename ErrorType>
inline const ErrorType& expected<ErrorType>::get_error() const& noexcept
{
return *m_store.template get_at_index<ERROR_INDEX>();
// AXIVION Next Construct AutosarC++19_03-A5.2.3 : const cast to avoid code duplication
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
return const_cast<ValueType&>(const_cast<const expected<ValueType, ErrorType>*>(this)->value());
}

template <typename ValueType, typename ErrorType>
inline ValueType* expected<ValueType, ErrorType>::operator->() noexcept
{
return m_store.template get_at_index<VALUE_INDEX>();
return &value();
}

template <typename ValueType, typename ErrorType>
Expand All @@ -206,7 +218,7 @@ inline const ValueType* expected<ValueType, ErrorType>::operator->() const noexc
template <typename ValueType, typename ErrorType>
inline ValueType& expected<ValueType, ErrorType>::operator*() noexcept
{
return *m_store.template get_at_index<VALUE_INDEX>();
return value();
}

template <typename ValueType, typename ErrorType>
Expand All @@ -217,6 +229,12 @@ inline const ValueType& expected<ValueType, ErrorType>::operator*() const noexce
return const_cast<const ValueType&>(const_cast<expected*>(this)->operator*());
}

template <typename ValueType, typename ErrorType>
const ValueType& expected<ValueType, ErrorType>::value_unchecked() const noexcept
{
return *m_store.template get_at_index<VALUE_INDEX>();
}

template <typename ValueType, typename ErrorType>
template <typename T>
inline expected<ValueType, ErrorType>::operator expected<T>() const noexcept
Expand Down Expand Up @@ -359,17 +377,26 @@ inline bool expected<ErrorType>::has_error() const noexcept
template <typename ErrorType>
inline ErrorType&& expected<ErrorType>::get_error() && noexcept
{
return std::move(*m_store.template get_at_index<ERROR_INDEX>());
return std::move(get_error());
}

template <typename ValueType, typename ErrorType>
inline const ErrorType& expected<ValueType, ErrorType>::get_error() const& noexcept
template <typename ErrorType>
inline ErrorType& expected<ErrorType>::get_error() & noexcept
{
return *m_store.template get_at_index<ERROR_INDEX>();
// AXIVION Next Construct AutosarC++19_03-A5.2.3 : const cast to avoid code duplication
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
return const_cast<ErrorType&>(const_cast<const expected<ErrorType>*>(this)->get_error());
}

template <typename ErrorType>
inline ErrorType& expected<ErrorType>::get_error() & noexcept
inline const ErrorType& expected<ErrorType>::get_error() const& noexcept
{
Expects(has_error());
return get_error_unchecked();
}

template <typename ErrorType>
inline const ErrorType& expected<ErrorType>::get_error_unchecked() const noexcept
{
return *m_store.template get_at_index<ERROR_INDEX>();
}
Expand Down
121 changes: 121 additions & 0 deletions iceoryx_hoofs/test/moduletests/test_cxx_expected.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -578,4 +578,125 @@ TEST_F(expected_test, MoveAssignmentIsNotEnforcedInMoveConstructor)
ASSERT_THAT(destination.has_error(), Eq(true));
}
}

TEST_F(expected_test, AccessingErrorOfLValueErrorOnlyExpectedWhichContainsValueLeadsToErrorHandlerCall)
{
::testing::Test::RecordProperty("TEST_ID", "da162edf-06b5-47d2-b35f-361d6004a6c4");
auto sut = expected<TestError>::create_value();
// @todo iox-#1613 remove EXPECT_DEATH
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg)
EXPECT_DEATH({ sut.get_error(); }, ".*");
}

TEST_F(expected_test, AccessingErrorOfConstLValueErrorOnlyExpectedWhichContainsValueLeadsToErrorHandlerCall)
{
::testing::Test::RecordProperty("TEST_ID", "324cab7d-ba04-4ff0-870f-79af993c272f");
const auto sut = expected<TestError>::create_value();
// @todo iox-#1613 remove EXPECT_DEATH
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg)
EXPECT_DEATH({ sut.get_error(); }, ".*");
}

TEST_F(expected_test, AccessingErrorOfRValueErrorOnlyExpectedWhichContainsValueLeadsToErrorHandlerCall)
{
::testing::Test::RecordProperty("TEST_ID", "0a4309e8-d9f3-41a9-9c4b-bdcfda917277");
auto sut = expected<TestError>::create_value();
// @todo iox-#1613 remove EXPECT_DEATH
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg)
EXPECT_DEATH({ std::move(sut).get_error(); }, ".*");
}

TEST_F(expected_test, AccessingValueOfLValueExpectedWhichContainsErrorWithArrowOpLeadsToErrorHandlerCall)
{
::testing::Test::RecordProperty("TEST_ID", "1a821c6f-83db-4fe1-8adf-873afa1251a1");
auto sut = expected<TestClass, TestError>::create_error(TestError::ERROR1);
// @todo iox-#1613 remove EXPECT_DEATH
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg)
EXPECT_DEATH({ sut->m_a; }, ".*");
}

TEST_F(expected_test, AccessingValueOfConstLValueExpectedWhichContainsErrorWithArrowOpLeadsToErrorHandlerCall)
{
::testing::Test::RecordProperty("TEST_ID", "c4f04d7c-9fa3-48f6-a6fd-b8e4e47b7632");
const auto sut = expected<TestClass, TestError>::create_error(TestError::ERROR1);
// @todo iox-#1613 remove EXPECT_DEATH
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg)
EXPECT_DEATH({ sut->m_a; }, ".*");
}

TEST_F(expected_test, AccessingValueOfLValueExpectedWhichContainsErrorWithDerefOpLeadsToErrorHandlerCall)
{
::testing::Test::RecordProperty("TEST_ID", "08ce6a3f-3813-46de-8e1e-3ffe8087521e");
auto sut = expected<TestClass, TestError>::create_error(TestError::ERROR1);
// @todo iox-#1613 remove EXPECT_DEATH
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg)
EXPECT_DEATH({ *sut; }, ".*");
}

TEST_F(expected_test, AccessingValueOfConstLValueExpectedWhichContainsErrorWithDerefOpLeadsToErrorHandlerCall)
{
::testing::Test::RecordProperty("TEST_ID", "838dd364-f91f-40a7-9720-2b662a045b1e");
const auto sut = expected<TestClass, TestError>::create_error(TestError::ERROR1);
// @todo iox-#1613 remove EXPECT_DEATH
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg)
EXPECT_DEATH({ *sut; }, ".*");
}

TEST_F(expected_test, AccessingValueOfLValueExpectedWhichContainsErrorLeadsToErrorHandlerCall)
{
::testing::Test::RecordProperty("TEST_ID", "92139583-b8d6-4d83-ae7e-f4109b98d214");
auto sut = expected<TestClass, TestError>::create_error(TestError::ERROR1);
// @todo iox-#1613 remove EXPECT_DEATH
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg)
EXPECT_DEATH({ sut.value(); }, ".*");
}

TEST_F(expected_test, AccessingValueOfConstLValueExpectedWhichContainsErrorLeadsToErrorHandlerCall)
{
::testing::Test::RecordProperty("TEST_ID", "1bcbb835-8b4c-4430-a534-a26573c2380d");
const auto sut = expected<TestClass, TestError>::create_error(TestError::ERROR1);
// @todo iox-#1613 remove EXPECT_DEATH
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg)
EXPECT_DEATH({ sut.value(); }, ".*");
}


TEST_F(expected_test, AccessingValueOfRValueExpectedWhichContainsErrorLeadsToErrorHandlerCall)
{
::testing::Test::RecordProperty("TEST_ID", "32d59b52-81f5-417a-8670-dfb2c54fedfb");
auto sut = expected<TestClass, TestError>::create_error(TestError::ERROR1);
// @todo iox-#1613 remove EXPECT_DEATH
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg)
EXPECT_DEATH({ std::move(sut).value(); }, ".*");
}

TEST_F(expected_test, AccessingErrorOfLValueExpectedWhichContainsValueLeadsToErrorHandlerCall)
{
::testing::Test::RecordProperty("TEST_ID", "aee85ead-e066-49fd-99fe-6f1a6045756d");
constexpr int VALID_VALUE{42};
auto sut = expected<TestClass, TestError>::create_value(VALID_VALUE, VALID_VALUE);
// @todo iox-#1613 remove EXPECT_DEATH
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg)
EXPECT_DEATH({ sut.get_error(); }, ".*");
}

TEST_F(expected_test, AccessingErrorOfConstLValueExpectedWhichContainsValueLeadsToErrorHandlerCall)
{
::testing::Test::RecordProperty("TEST_ID", "a49cf02e-b165-4fd6-9c24-65cedc6cddb9");
constexpr int VALID_VALUE{42};
const auto sut = expected<TestClass, TestError>::create_value(VALID_VALUE, VALID_VALUE);
// @todo iox-#1613 remove EXPECT_DEATH
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg)
EXPECT_DEATH({ sut.get_error(); }, ".*");
}

TEST_F(expected_test, AccessingErrorOfRValueExpectedWhichContainsValueLeadsToErrorHandlerCall)
{
::testing::Test::RecordProperty("TEST_ID", "0ea90b5d-1af6-494a-b35c-da103bed2331");
constexpr int VALID_VALUE{42};
auto sut = expected<TestClass, TestError>::create_value(VALID_VALUE, VALID_VALUE);
// @todo iox-#1613 remove EXPECT_DEATH
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg)
EXPECT_DEATH({ std::move(sut).get_error(); }, ".*");
}
} // namespace

0 comments on commit db5ecdd

Please sign in to comment.