Skip to content

Commit

Permalink
Implement testing::Rethrow to throw exceptions more easily via `std…
Browse files Browse the repository at this point in the history
…::exception_ptr`

We avoid overloading or specializing `testing::Throw` as this is fundamentally a different operation than throwing the object.
However, we disable the corresponding overload of `testing::Throw` to prevent likely mistakes in the usage.

Fixes: #4412
PiperOrigin-RevId: 585745469
Change-Id: I03bb585427ce51983d914e88f2bf65a13545c920
  • Loading branch information
Abseil Team authored and copybara-github committed Nov 27, 2023
1 parent b10fad3 commit 76bb2af
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 3 deletions.
24 changes: 21 additions & 3 deletions googlemock/include/gmock/gmock-actions.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@
#endif

#include <algorithm>
#include <exception>
#include <functional>
#include <memory>
#include <string>
Expand Down Expand Up @@ -1746,6 +1747,13 @@ struct ThrowAction {
return [copy](Args...) -> R { throw copy; };
}
};
struct RethrowAction {
std::exception_ptr exception;
template <typename R, typename... Args>
operator Action<R(Args...)>() const { // NOLINT
return [ex = exception](Args...) -> R { std::rethrow_exception(ex); };
}
};
#endif // GTEST_HAS_EXCEPTIONS

} // namespace internal
Expand Down Expand Up @@ -2062,13 +2070,23 @@ internal::ReturnPointeeAction<Ptr> ReturnPointee(Ptr pointer) {
return {pointer};
}

// Action Throw(exception) can be used in a mock function of any type
// to throw the given exception. Any copyable value can be thrown.
#if GTEST_HAS_EXCEPTIONS
// Action Throw(exception) can be used in a mock function of any type
// to throw the given exception. Any copyable value can be thrown,
// except for std::exception_ptr, which is likely a mistake if
// thrown directly.
template <typename T>
internal::ThrowAction<typename std::decay<T>::type> Throw(T&& exception) {
typename std::enable_if<
!std::is_base_of<std::exception_ptr, typename std::decay<T>::type>::value,
internal::ThrowAction<typename std::decay<T>::type>>::type
Throw(T&& exception) {
return {std::forward<T>(exception)};
}
// Action Rethrow(exception_ptr) can be used in a mock function of any type
// to rethrow any exception_ptr. Note that the same object is thrown each time.
inline internal::RethrowAction Rethrow(std::exception_ptr exception) {
return {std::move(exception)};
}
#endif // GTEST_HAS_EXCEPTIONS

namespace internal {
Expand Down
9 changes: 9 additions & 0 deletions googlemock/test/gmock_link_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ using testing::SetErrnoAndReturn;

#if GTEST_HAS_EXCEPTIONS
using testing::Throw;
using testing::Rethrow;
#endif

using testing::ContainsRegex;
Expand Down Expand Up @@ -416,6 +417,14 @@ TEST(LinkTest, TestThrow) {
EXPECT_CALL(mock, VoidFromString(_)).WillOnce(Throw(42));
EXPECT_THROW(mock.VoidFromString(nullptr), int);
}
// Tests the linkage of the Rethrow action.
TEST(LinkTest, TestRethrow) {
Mock mock;

EXPECT_CALL(mock, VoidFromString(_))
.WillOnce(Rethrow(std::make_exception_ptr(42)));
EXPECT_THROW(mock.VoidFromString(nullptr), int);
}
#endif // GTEST_HAS_EXCEPTIONS

// The ACTION*() macros trigger warning C4100 (unreferenced formal
Expand Down

0 comments on commit 76bb2af

Please sign in to comment.