mirror of
https://github.com/google/googletest.git
synced 2024-12-26 01:30:49 +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!!!
|
||||
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.
|
||||
inline void PrintIfNotEmpty(const std::string& explanation,
|
||||
::std::ostream* os) {
|
||||
@ -2955,10 +2960,6 @@ class EachMatcher {
|
||||
const M inner_matcher_;
|
||||
};
|
||||
|
||||
// Use go/ranked-overloads for dispatching.
|
||||
struct Rank0 {};
|
||||
struct Rank1 : Rank0 {};
|
||||
|
||||
namespace pair_getters {
|
||||
using std::get;
|
||||
template <typename T>
|
||||
@ -3912,6 +3913,21 @@ GTEST_API_ std::string FormatMatcherDescription(
|
||||
bool negation, const char* matcher_name,
|
||||
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.
|
||||
template <typename ValueMatcher>
|
||||
class OptionalMatcher {
|
||||
@ -3944,7 +3960,7 @@ class OptionalMatcher {
|
||||
|
||||
bool MatchAndExplain(Optional optional,
|
||||
MatchResultListener* listener) const override {
|
||||
if (!optional) {
|
||||
if (!IsOptionalEngaged(optional, HighestRank())) {
|
||||
*listener << "which is not engaged";
|
||||
return false;
|
||||
}
|
||||
@ -5266,9 +5282,10 @@ inline InnerMatcher AllArgs(const InnerMatcher& matcher) {
|
||||
}
|
||||
|
||||
// Returns a matcher that matches the value of an optional<> type variable.
|
||||
// The matcher implementation only uses '!arg' and requires that the optional<>
|
||||
// type has a 'value_type' member type and that '*arg' is of type 'value_type'
|
||||
// and is printable using 'PrintToString'. It is compatible with
|
||||
// The matcher implementation only uses '!arg' (or 'arg.has_value()' if '!arg`
|
||||
// isn't a valid expression) and requires that the optional<> type has a
|
||||
// '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.
|
||||
// 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
|
||||
|
@ -674,6 +674,8 @@ TEST_P(MatcherTupleTestP, ExplainsMatchFailure) {
|
||||
// explanation.
|
||||
}
|
||||
|
||||
#if GTEST_HAS_TYPED_TEST
|
||||
|
||||
// Sample optional type implementation with minimal requirements for use with
|
||||
// Optional matcher.
|
||||
template <typename T>
|
||||
@ -691,38 +693,76 @@ class SampleOptional {
|
||||
bool has_value_;
|
||||
};
|
||||
|
||||
TEST(OptionalTest, DescribesSelf) {
|
||||
const Matcher<SampleOptional<int>> m = Optional(Eq(1));
|
||||
// Sample optional type implementation with alternative minimal requirements for
|
||||
// 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));
|
||||
}
|
||||
|
||||
TEST(OptionalTest, ExplainsSelf) {
|
||||
const Matcher<SampleOptional<int>> m = Optional(Eq(1));
|
||||
EXPECT_EQ("whose value 1 matches", Explain(m, SampleOptional<int>(1)));
|
||||
EXPECT_EQ("whose value 2 doesn't match", Explain(m, SampleOptional<int>(2)));
|
||||
TYPED_TEST(OptionalTest, ExplainsSelf) {
|
||||
const Matcher<TypeParam> m = Optional(Eq(1));
|
||||
EXPECT_EQ("whose value 1 matches", Explain(m, TypeParam(1)));
|
||||
EXPECT_EQ("whose value 2 doesn't match", Explain(m, TypeParam(2)));
|
||||
}
|
||||
|
||||
TEST(OptionalTest, MatchesNonEmptyOptional) {
|
||||
const Matcher<SampleOptional<int>> m1 = Optional(1);
|
||||
const Matcher<SampleOptional<int>> m2 = Optional(Eq(2));
|
||||
const Matcher<SampleOptional<int>> m3 = Optional(Lt(3));
|
||||
SampleOptional<int> opt(1);
|
||||
TYPED_TEST(OptionalTest, MatchesNonEmptyOptional) {
|
||||
const Matcher<TypeParam> m1 = Optional(1);
|
||||
const Matcher<TypeParam> m2 = Optional(Eq(2));
|
||||
const Matcher<TypeParam> m3 = Optional(Lt(3));
|
||||
TypeParam opt(1);
|
||||
EXPECT_TRUE(m1.Matches(opt));
|
||||
EXPECT_FALSE(m2.Matches(opt));
|
||||
EXPECT_TRUE(m3.Matches(opt));
|
||||
}
|
||||
|
||||
TEST(OptionalTest, DoesNotMatchNullopt) {
|
||||
const Matcher<SampleOptional<int>> m = Optional(1);
|
||||
SampleOptional<int> empty;
|
||||
TYPED_TEST(OptionalTest, DoesNotMatchNullopt) {
|
||||
const Matcher<TypeParam> m = Optional(1);
|
||||
TypeParam empty;
|
||||
EXPECT_FALSE(m.Matches(empty));
|
||||
}
|
||||
|
||||
TEST(OptionalTest, WorksWithMoveOnly) {
|
||||
Matcher<SampleOptional<std::unique_ptr<int>>> m = Optional(Eq(nullptr));
|
||||
EXPECT_TRUE(m.Matches(SampleOptional<std::unique_ptr<int>>(nullptr)));
|
||||
template <typename T>
|
||||
class MoveOnlyOptionalTest : public testing::Test {};
|
||||
|
||||
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 {
|
||||
public:
|
||||
SampleVariantIntString(int i) : i_(i), has_int_(true) {}
|
||||
|
Loading…
x
Reference in New Issue
Block a user