diff --git a/include/behaviortree_cpp/contrib/expected.hpp b/include/behaviortree_cpp/contrib/expected.hpp index 305f3abad..a9a7f172c 100644 --- a/include/behaviortree_cpp/contrib/expected.hpp +++ b/include/behaviortree_cpp/contrib/expected.hpp @@ -258,6 +258,7 @@ namespace nonstd { #include #include #include +#include #include #include #include @@ -1607,9 +1608,10 @@ class bad_expected_access : public bad_expected_access< void > : m_error( error ) {} + // BT.CPP patch (#1263): report the error message when the error is a string. virtual char const * what() const noexcept override { - return "bad_expected_access"; + return what_of( m_error ); } nsel_constexpr14 error_type & error() & @@ -1637,6 +1639,17 @@ class bad_expected_access : public bad_expected_access< void > #endif private: + static char const * what_of( std::string const & error ) noexcept + { + return error.empty() ? "bad_expected_access" : error.c_str(); + } + + template< typename T > + static char const * what_of( T const & ) noexcept + { + return "bad_expected_access"; + } + error_type m_error; }; diff --git a/tests/gtest_basic_types.cpp b/tests/gtest_basic_types.cpp index a224bc127..78ab87bb5 100644 --- a/tests/gtest_basic_types.cpp +++ b/tests/gtest_basic_types.cpp @@ -484,6 +484,49 @@ TEST(BasicTypes, Result_Error) ASSERT_EQ(result.error(), "error message"); } +TEST(BasicTypes, Expected_BadAccessMessage) +{ + auto bb = Blackboard::create(); + try + { + (void)bb->getStamped("missing_key").value(); + FAIL() << "value() should throw"; + } + catch(const std::exception& ex) + { + const std::string msg = ex.what(); + EXPECT_NE(msg.find("Missing key [missing_key]"), std::string::npos) << msg; + } + + Expected res = nonstd::make_unexpected(std::string("error message")); + try + { + (void)res.value(); + FAIL() << "value() should throw"; + } + catch(const nonstd::bad_expected_access& ex) + { + const auto copy = ex; + EXPECT_STREQ(copy.what(), "error message"); + EXPECT_EQ(copy.error(), "error message"); + } +} + +TEST(BasicTypes, Expected_BadAccessMessageNotString) +{ + nonstd::expected res = nonstd::make_unexpected(42); + try + { + (void)res.value(); + FAIL() << "value() should throw"; + } + catch(const nonstd::bad_expected_access& ex) + { + EXPECT_STREQ(ex.what(), "bad_expected_access"); + EXPECT_EQ(ex.error(), 42); + } +} + // ============ StringView tests ============ TEST(BasicTypes, StringView_FromString)