aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAbseil Team <absl-team@google.com>2023-11-27 13:31:59 -0800
committerCopybara-Service <copybara-worker@google.com>2023-11-27 13:32:49 -0800
commit76bb2afb8b522d24496ad1c757a49784fbfa2e42 (patch)
treedfc624e5c005a86b9a7680926625b1aaf881cd43
parentb10fad38c4026a29ea6561ab15fc4818170d1c10 (diff)
downloadgoogletest-76bb2afb8b522d24496ad1c757a49784fbfa2e42.tar.gz
Implement `testing::Rethrow` to throw exceptions more easily via `std::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
-rw-r--r--googlemock/include/gmock/gmock-actions.h24
-rw-r--r--googlemock/test/gmock_link_test.h9
2 files changed, 30 insertions, 3 deletions
diff --git a/googlemock/include/gmock/gmock-actions.h b/googlemock/include/gmock/gmock-actions.h
index f20258bc..fab99933 100644
--- a/googlemock/include/gmock/gmock-actions.h
+++ b/googlemock/include/gmock/gmock-actions.h
@@ -135,6 +135,7 @@
#endif
#include <algorithm>
+#include <exception>
#include <functional>
#include <memory>
#include <string>
@@ -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
@@ -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 {
diff --git a/googlemock/test/gmock_link_test.h b/googlemock/test/gmock_link_test.h
index db11c2d2..cf0a985b 100644
--- a/googlemock/test/gmock_link_test.h
+++ b/googlemock/test/gmock_link_test.h
@@ -187,6 +187,7 @@ using testing::SetErrnoAndReturn;
#if GTEST_HAS_EXCEPTIONS
using testing::Throw;
+using testing::Rethrow;
#endif
using testing::ContainsRegex;
@@ -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