mirror of
https://github.com/google/googletest.git
synced 2024-12-27 02:01:25 +08:00
Optional(): Add support for std::optional<>-like types lacking bool conversion.
PiperOrigin-RevId: 681053268 Change-Id: If80ba667fd4c91340e1405a9691f5ca0350fa9eb
This commit is contained in:
parent
6dae7eb4a5
commit
a1e255a582
@ -561,6 +561,11 @@ Matcher<T> A();
|
|||||||
// and MUST NOT BE USED IN USER CODE!!!
|
// and MUST NOT BE USED IN USER CODE!!!
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
// Used per go/ranked-overloads for dispatching.
|
||||||
|
struct Rank0 {};
|
||||||
|
struct Rank1 : Rank0 {};
|
||||||
|
using HighestRank = Rank1;
|
||||||
|
|
||||||
// If the explanation is not empty, prints it to the ostream.
|
// If the explanation is not empty, prints it to the ostream.
|
||||||
inline void PrintIfNotEmpty(const std::string& explanation,
|
inline void PrintIfNotEmpty(const std::string& explanation,
|
||||||
::std::ostream* os) {
|
::std::ostream* os) {
|
||||||
@ -2955,10 +2960,6 @@ class EachMatcher {
|
|||||||
const M inner_matcher_;
|
const M inner_matcher_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Use go/ranked-overloads for dispatching.
|
|
||||||
struct Rank0 {};
|
|
||||||
struct Rank1 : Rank0 {};
|
|
||||||
|
|
||||||
namespace pair_getters {
|
namespace pair_getters {
|
||||||
using std::get;
|
using std::get;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -3912,6 +3913,21 @@ GTEST_API_ std::string FormatMatcherDescription(
|
|||||||
bool negation, const char* matcher_name,
|
bool negation, const char* matcher_name,
|
||||||
const std::vector<const char*>& param_names, const Strings& param_values);
|
const std::vector<const char*>& param_names, const Strings& param_values);
|
||||||
|
|
||||||
|
// Overloads to support `OptionalMatcher` being used with a type that either
|
||||||
|
// supports implicit conversion to bool or a `has_value()` method.
|
||||||
|
template <typename Optional>
|
||||||
|
auto IsOptionalEngaged(const Optional& optional,
|
||||||
|
Rank1) -> decltype(!!optional) {
|
||||||
|
// The use of double-negation here is to preserve historical behavior where
|
||||||
|
// the matcher used `operator!` rather than directly using `operator bool`.
|
||||||
|
return !static_cast<bool>(!optional);
|
||||||
|
}
|
||||||
|
template <typename Optional>
|
||||||
|
auto IsOptionalEngaged(const Optional& optional,
|
||||||
|
Rank0) -> decltype(!optional.has_value()) {
|
||||||
|
return optional.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
// Implements a matcher that checks the value of a optional<> type variable.
|
// Implements a matcher that checks the value of a optional<> type variable.
|
||||||
template <typename ValueMatcher>
|
template <typename ValueMatcher>
|
||||||
class OptionalMatcher {
|
class OptionalMatcher {
|
||||||
@ -3944,7 +3960,7 @@ class OptionalMatcher {
|
|||||||
|
|
||||||
bool MatchAndExplain(Optional optional,
|
bool MatchAndExplain(Optional optional,
|
||||||
MatchResultListener* listener) const override {
|
MatchResultListener* listener) const override {
|
||||||
if (!optional) {
|
if (!IsOptionalEngaged(optional, HighestRank())) {
|
||||||
*listener << "which is not engaged";
|
*listener << "which is not engaged";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -5266,9 +5282,10 @@ inline InnerMatcher AllArgs(const InnerMatcher& matcher) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns a matcher that matches the value of an optional<> type variable.
|
// Returns a matcher that matches the value of an optional<> type variable.
|
||||||
// The matcher implementation only uses '!arg' and requires that the optional<>
|
// The matcher implementation only uses '!arg' (or 'arg.has_value()' if '!arg`
|
||||||
// type has a 'value_type' member type and that '*arg' is of type 'value_type'
|
// isn't a valid expression) and requires that the optional<> type has a
|
||||||
// and is printable using 'PrintToString'. It is compatible with
|
// 'value_type' member type and that '*arg' is of type 'value_type' and is
|
||||||
|
// printable using 'PrintToString'. It is compatible with
|
||||||
// std::optional/std::experimental::optional.
|
// std::optional/std::experimental::optional.
|
||||||
// Note that to compare an optional type variable against nullopt you should
|
// Note that to compare an optional type variable against nullopt you should
|
||||||
// use Eq(nullopt) and not Eq(Optional(nullopt)). The latter implies that the
|
// use Eq(nullopt) and not Eq(Optional(nullopt)). The latter implies that the
|
||||||
|
@ -674,6 +674,8 @@ TEST_P(MatcherTupleTestP, ExplainsMatchFailure) {
|
|||||||
// explanation.
|
// explanation.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if GTEST_HAS_TYPED_TEST
|
||||||
|
|
||||||
// Sample optional type implementation with minimal requirements for use with
|
// Sample optional type implementation with minimal requirements for use with
|
||||||
// Optional matcher.
|
// Optional matcher.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -691,38 +693,76 @@ class SampleOptional {
|
|||||||
bool has_value_;
|
bool has_value_;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(OptionalTest, DescribesSelf) {
|
// Sample optional type implementation with alternative minimal requirements for
|
||||||
const Matcher<SampleOptional<int>> m = Optional(Eq(1));
|
// use with Optional matcher. In particular, while it doesn't have a bool
|
||||||
|
// conversion operator, it does have a has_value() method.
|
||||||
|
template <typename T>
|
||||||
|
class SampleOptionalWithoutBoolConversion {
|
||||||
|
public:
|
||||||
|
using value_type = T;
|
||||||
|
explicit SampleOptionalWithoutBoolConversion(T value)
|
||||||
|
: value_(std::move(value)), has_value_(true) {}
|
||||||
|
SampleOptionalWithoutBoolConversion() : value_(), has_value_(false) {}
|
||||||
|
bool has_value() const { return has_value_; }
|
||||||
|
const T& operator*() const { return value_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
T value_;
|
||||||
|
bool has_value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class OptionalTest : public testing::Test {};
|
||||||
|
|
||||||
|
using OptionalTestTypes =
|
||||||
|
testing::Types<SampleOptional<int>,
|
||||||
|
SampleOptionalWithoutBoolConversion<int>>;
|
||||||
|
|
||||||
|
TYPED_TEST_SUITE(OptionalTest, OptionalTestTypes);
|
||||||
|
|
||||||
|
TYPED_TEST(OptionalTest, DescribesSelf) {
|
||||||
|
const Matcher<TypeParam> m = Optional(Eq(1));
|
||||||
EXPECT_EQ("value is equal to 1", Describe(m));
|
EXPECT_EQ("value is equal to 1", Describe(m));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(OptionalTest, ExplainsSelf) {
|
TYPED_TEST(OptionalTest, ExplainsSelf) {
|
||||||
const Matcher<SampleOptional<int>> m = Optional(Eq(1));
|
const Matcher<TypeParam> m = Optional(Eq(1));
|
||||||
EXPECT_EQ("whose value 1 matches", Explain(m, SampleOptional<int>(1)));
|
EXPECT_EQ("whose value 1 matches", Explain(m, TypeParam(1)));
|
||||||
EXPECT_EQ("whose value 2 doesn't match", Explain(m, SampleOptional<int>(2)));
|
EXPECT_EQ("whose value 2 doesn't match", Explain(m, TypeParam(2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(OptionalTest, MatchesNonEmptyOptional) {
|
TYPED_TEST(OptionalTest, MatchesNonEmptyOptional) {
|
||||||
const Matcher<SampleOptional<int>> m1 = Optional(1);
|
const Matcher<TypeParam> m1 = Optional(1);
|
||||||
const Matcher<SampleOptional<int>> m2 = Optional(Eq(2));
|
const Matcher<TypeParam> m2 = Optional(Eq(2));
|
||||||
const Matcher<SampleOptional<int>> m3 = Optional(Lt(3));
|
const Matcher<TypeParam> m3 = Optional(Lt(3));
|
||||||
SampleOptional<int> opt(1);
|
TypeParam opt(1);
|
||||||
EXPECT_TRUE(m1.Matches(opt));
|
EXPECT_TRUE(m1.Matches(opt));
|
||||||
EXPECT_FALSE(m2.Matches(opt));
|
EXPECT_FALSE(m2.Matches(opt));
|
||||||
EXPECT_TRUE(m3.Matches(opt));
|
EXPECT_TRUE(m3.Matches(opt));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(OptionalTest, DoesNotMatchNullopt) {
|
TYPED_TEST(OptionalTest, DoesNotMatchNullopt) {
|
||||||
const Matcher<SampleOptional<int>> m = Optional(1);
|
const Matcher<TypeParam> m = Optional(1);
|
||||||
SampleOptional<int> empty;
|
TypeParam empty;
|
||||||
EXPECT_FALSE(m.Matches(empty));
|
EXPECT_FALSE(m.Matches(empty));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(OptionalTest, WorksWithMoveOnly) {
|
template <typename T>
|
||||||
Matcher<SampleOptional<std::unique_ptr<int>>> m = Optional(Eq(nullptr));
|
class MoveOnlyOptionalTest : public testing::Test {};
|
||||||
EXPECT_TRUE(m.Matches(SampleOptional<std::unique_ptr<int>>(nullptr)));
|
|
||||||
|
using MoveOnlyOptionalTestTypes =
|
||||||
|
testing::Types<SampleOptional<std::unique_ptr<int>>,
|
||||||
|
SampleOptionalWithoutBoolConversion<std::unique_ptr<int>>>;
|
||||||
|
|
||||||
|
TYPED_TEST_SUITE(MoveOnlyOptionalTest, MoveOnlyOptionalTestTypes);
|
||||||
|
|
||||||
|
TYPED_TEST(MoveOnlyOptionalTest, WorksWithMoveOnly) {
|
||||||
|
Matcher<TypeParam> m = Optional(Eq(nullptr));
|
||||||
|
EXPECT_TRUE(m.Matches(TypeParam(nullptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // GTEST_HAS_TYPED_TEST
|
||||||
|
|
||||||
class SampleVariantIntString {
|
class SampleVariantIntString {
|
||||||
public:
|
public:
|
||||||
SampleVariantIntString(int i) : i_(i), has_int_(true) {}
|
SampleVariantIntString(int i) : i_(i), has_int_(true) {}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user