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
This commit is contained in:
		
				
					committed by
					
						
						Copybara-Service
					
				
			
			
				
	
			
			
			
						parent
						
							b10fad38c4
						
					
				
				
					commit
					76bb2afb8b
				
			@@ -135,6 +135,7 @@
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					#include <exception>
 | 
				
			||||||
#include <functional>
 | 
					#include <functional>
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
@@ -1746,6 +1747,13 @@ struct ThrowAction {
 | 
				
			|||||||
    return [copy](Args...) -> R { throw copy; };
 | 
					    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
 | 
					#endif  // GTEST_HAS_EXCEPTIONS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace internal
 | 
					}  // namespace internal
 | 
				
			||||||
@@ -2062,13 +2070,23 @@ internal::ReturnPointeeAction<Ptr> ReturnPointee(Ptr pointer) {
 | 
				
			|||||||
  return {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
 | 
					#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>
 | 
					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)};
 | 
					  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
 | 
					#endif  // GTEST_HAS_EXCEPTIONS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace internal {
 | 
					namespace internal {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -187,6 +187,7 @@ using testing::SetErrnoAndReturn;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#if GTEST_HAS_EXCEPTIONS
 | 
					#if GTEST_HAS_EXCEPTIONS
 | 
				
			||||||
using testing::Throw;
 | 
					using testing::Throw;
 | 
				
			||||||
 | 
					using testing::Rethrow;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using testing::ContainsRegex;
 | 
					using testing::ContainsRegex;
 | 
				
			||||||
@@ -416,6 +417,14 @@ TEST(LinkTest, TestThrow) {
 | 
				
			|||||||
  EXPECT_CALL(mock, VoidFromString(_)).WillOnce(Throw(42));
 | 
					  EXPECT_CALL(mock, VoidFromString(_)).WillOnce(Throw(42));
 | 
				
			||||||
  EXPECT_THROW(mock.VoidFromString(nullptr), int);
 | 
					  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
 | 
					#endif  // GTEST_HAS_EXCEPTIONS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// The ACTION*() macros trigger warning C4100 (unreferenced formal
 | 
					// The ACTION*() macros trigger warning C4100 (unreferenced formal
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user