mirror of
https://github.com/google/googletest.git
synced 2024-12-27 10:11:03 +08:00
gmock-actions: improve comments and tests for the implicit cast in Return.
Commit a070cbd91c added an implicit cast to this path but didn't leave a very clear explanation for why it was desirable, a clear example, or even test coverage. Add a better comment and a test that fails when the implicit cast is removed. PiperOrigin-RevId: 444871311 Change-Id: I127982fa8d5bce9b6d1b68177c12dc0709449164
This commit is contained in:
parent
c144d78f82
commit
830fb56728
@ -935,15 +935,16 @@ class ReturnAction {
|
|||||||
typedef typename Function<F>::Result Result;
|
typedef typename Function<F>::Result Result;
|
||||||
typedef typename Function<F>::ArgumentTuple ArgumentTuple;
|
typedef typename Function<F>::ArgumentTuple ArgumentTuple;
|
||||||
|
|
||||||
// The implicit cast is necessary when Result has more than one
|
|
||||||
// single-argument constructor (e.g. Result is std::vector<int>) and R
|
|
||||||
// has a type conversion operator template. In that case, value_(value)
|
|
||||||
// won't compile as the compiler doesn't known which constructor of
|
|
||||||
// Result to call. ImplicitCast_ forces the compiler to convert R to
|
|
||||||
// Result without considering explicit constructors, thus resolving the
|
|
||||||
// ambiguity. value_ is then initialized using its copy constructor.
|
|
||||||
explicit Impl(const std::shared_ptr<R>& value)
|
explicit Impl(const std::shared_ptr<R>& value)
|
||||||
: value_before_cast_(*value),
|
: value_before_cast_(*value),
|
||||||
|
// Make an implicit conversion to Result before initializing the
|
||||||
|
// Result object we store, avoiding calling any explicit constructor
|
||||||
|
// of Result from R.
|
||||||
|
//
|
||||||
|
// This simulates the language rules: a function with return type
|
||||||
|
// Result that does `return R()` requires R to be implicitly
|
||||||
|
// convertible to Result, and uses that path for the conversion, even
|
||||||
|
// if Result has an explicit constructor from R.
|
||||||
value_(ImplicitCast_<Result>(value_before_cast_)) {}
|
value_(ImplicitCast_<Result>(value_before_cast_)) {}
|
||||||
|
|
||||||
Result Perform(const ArgumentTuple&) override { return value_; }
|
Result Perform(const ArgumentTuple&) override { return value_; }
|
||||||
|
@ -667,6 +667,37 @@ TEST(ReturnTest, SupportsWrapperReturnType) {
|
|||||||
EXPECT_THAT(result, ::testing::ElementsAre(0, 1, 2, 3, 4));
|
EXPECT_THAT(result, ::testing::ElementsAre(0, 1, 2, 3, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ReturnTest, PrefersConversionOperator) {
|
||||||
|
// Define types In and Out such that:
|
||||||
|
//
|
||||||
|
// * In is implicitly convertible to Out.
|
||||||
|
// * Out also has an explicit constructor from In.
|
||||||
|
//
|
||||||
|
struct In;
|
||||||
|
struct Out {
|
||||||
|
int x;
|
||||||
|
|
||||||
|
explicit Out(const int x) : x(x) {}
|
||||||
|
explicit Out(const In&) : x(0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct In {
|
||||||
|
operator Out() const { return Out{19}; } // NOLINT
|
||||||
|
};
|
||||||
|
|
||||||
|
// Assumption check: the C++ language rules are such that a function that
|
||||||
|
// returns Out which uses In a return statement will use the implicit
|
||||||
|
// conversion path rather than the explicit constructor.
|
||||||
|
EXPECT_THAT([]() -> Out { return In(); }(), Field(&Out::x, 19));
|
||||||
|
|
||||||
|
// Return should work the same way: if the mock function's return type is Out
|
||||||
|
// and we feed Return an In value, then the Out should be created through the
|
||||||
|
// implicit conversion path rather than the explicit constructor.
|
||||||
|
MockFunction<Out()> mock;
|
||||||
|
EXPECT_CALL(mock, Call).WillOnce(Return(In()));
|
||||||
|
EXPECT_THAT(mock.AsStdFunction()(), Field(&Out::x, 19));
|
||||||
|
}
|
||||||
|
|
||||||
// Tests that Return(v) is covaraint.
|
// Tests that Return(v) is covaraint.
|
||||||
|
|
||||||
struct Base {
|
struct Base {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user