Skip to content

Commit 56c2d99

Browse files
committedDec 13, 2017
[Testing/Support] Make the HasValue matcher composable
Summary: This makes it possible to run an arbitrary matcher on the value contained within the Expected<T> object. To do this, I've needed to fully spell out the matcher, instead of using the shorthand MATCHER_P macro. The slight gotcha here is that standard template deduction will fail if one tries to match HasValue(47) against an Expected<int &> -- the workaround is to use HasValue(testing::Eq(47)). The explanations produced by this matcher have changed a bit, since now we delegate to the nested matcher to print the value. Since these don't put quotes around the value, I've changed our PrintTo methods to match. Reviewers: zturner Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D41065 llvm-svn: 320561
1 parent 19c9314 commit 56c2d99

File tree

3 files changed

+75
-21
lines changed

3 files changed

+75
-21
lines changed
 

‎llvm/include/llvm/Testing/Support/Error.h

+58-14
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,60 @@ template <typename T> ExpectedHolder<T> TakeExpected(Expected<T> &Exp) {
2828
template <typename T> ExpectedHolder<T> TakeExpected(Expected<T> &&Exp) {
2929
return TakeExpected(Exp);
3030
}
31+
32+
template <typename T>
33+
class ValueMatchesMono
34+
: public testing::MatcherInterface<const ExpectedHolder<T> &> {
35+
public:
36+
explicit ValueMatchesMono(const testing::Matcher<T> &Matcher)
37+
: Matcher(Matcher) {}
38+
39+
bool MatchAndExplain(const ExpectedHolder<T> &Holder,
40+
testing::MatchResultListener *listener) const override {
41+
if (!Holder.Success)
42+
return false;
43+
44+
bool result = Matcher.MatchAndExplain(*Holder.Exp, listener);
45+
46+
if (result)
47+
return result;
48+
*listener << "(";
49+
Matcher.DescribeNegationTo(listener->stream());
50+
*listener << ")";
51+
return result;
52+
}
53+
54+
void DescribeTo(std::ostream *OS) const override {
55+
*OS << "succeeded with value (";
56+
Matcher.DescribeTo(OS);
57+
*OS << ")";
58+
}
59+
60+
void DescribeNegationTo(std::ostream *OS) const override {
61+
*OS << "did not succeed or value (";
62+
Matcher.DescribeNegationTo(OS);
63+
*OS << ")";
64+
}
65+
66+
private:
67+
testing::Matcher<T> Matcher;
68+
};
69+
70+
template<typename M>
71+
class ValueMatchesPoly {
72+
public:
73+
explicit ValueMatchesPoly(const M &Matcher) : Matcher(Matcher) {}
74+
75+
template <typename T>
76+
operator testing::Matcher<const ExpectedHolder<T> &>() const {
77+
return MakeMatcher(
78+
new ValueMatchesMono<T>(testing::SafeMatcherCast<T>(Matcher)));
79+
}
80+
81+
private:
82+
M Matcher;
83+
};
84+
3185
} // namespace detail
3286

3387
#define EXPECT_THAT_ERROR(Err, Matcher) \
@@ -43,21 +97,11 @@ template <typename T> ExpectedHolder<T> TakeExpected(Expected<T> &&Exp) {
4397
MATCHER(Succeeded, "") { return arg.Success; }
4498
MATCHER(Failed, "") { return !arg.Success; }
4599

46-
MATCHER_P(HasValue, value,
47-
"succeeded with value \"" + testing::PrintToString(value) + '"') {
48-
if (!arg.Success) {
49-
*result_listener << "operation failed";
50-
return false;
51-
}
52-
53-
if (*arg.Exp != value) {
54-
*result_listener << "but \"" + testing::PrintToString(*arg.Exp) +
55-
"\" != \"" + testing::PrintToString(value) + '"';
56-
return false;
57-
}
58-
59-
return true;
100+
template <typename M>
101+
detail::ValueMatchesPoly<M> HasValue(M Matcher) {
102+
return detail::ValueMatchesPoly<M>(Matcher);
60103
}
104+
61105
} // namespace llvm
62106

63107
#endif

‎llvm/include/llvm/Testing/Support/SupportHelpers.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ inline void PrintTo(const ErrorHolder &Err, std::ostream *Out) {
3838
template <typename T>
3939
void PrintTo(const ExpectedHolder<T> &Item, std::ostream *Out) {
4040
if (Item.Success) {
41-
*Out << "succeeded with value \"" << ::testing::PrintToString(*Item.Exp)
42-
<< "\"";
41+
*Out << "succeeded with value " << ::testing::PrintToString(*Item.Exp);
4342
} else {
4443
PrintTo(static_cast<const ErrorHolder &>(Item), Out);
4544
}

‎llvm/unittests/Support/ErrorTest.cpp

+16-5
Original file line numberDiff line numberDiff line change
@@ -735,23 +735,34 @@ TEST(Error, ErrorMatchers) {
735735
EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), Failed());
736736
EXPECT_NONFATAL_FAILURE(
737737
EXPECT_THAT_EXPECTED(Expected<int>(0), Failed()),
738-
"Expected: failed\n Actual: succeeded with value \"0\"");
738+
"Expected: failed\n Actual: succeeded with value 0");
739739

740740
EXPECT_THAT_EXPECTED(Expected<int>(0), HasValue(0));
741741
EXPECT_NONFATAL_FAILURE(
742742
EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)),
743743
HasValue(0)),
744-
"Expected: succeeded with value \"0\"\n"
744+
"Expected: succeeded with value (is equal to 0)\n"
745745
" Actual: failed (CustomError { 0})");
746746
EXPECT_NONFATAL_FAILURE(
747747
EXPECT_THAT_EXPECTED(Expected<int>(1), HasValue(0)),
748-
"Expected: succeeded with value \"0\"\n"
749-
" Actual: succeeded with value \"1\", but \"1\" != \"0\"");
748+
"Expected: succeeded with value (is equal to 0)\n"
749+
" Actual: succeeded with value 1, (isn't equal to 0)");
750750

751751
EXPECT_THAT_EXPECTED(Expected<int &>(make_error<CustomError>(0)), Failed());
752752
int a = 1;
753753
EXPECT_THAT_EXPECTED(Expected<int &>(a), Succeeded());
754-
EXPECT_THAT_EXPECTED(Expected<int &>(a), HasValue(1));
754+
EXPECT_THAT_EXPECTED(Expected<int &>(a), HasValue(testing::Eq(1)));
755+
756+
EXPECT_THAT_EXPECTED(Expected<int>(1), HasValue(testing::Gt(0)));
757+
EXPECT_NONFATAL_FAILURE(
758+
EXPECT_THAT_EXPECTED(Expected<int>(0), HasValue(testing::Gt(1))),
759+
"Expected: succeeded with value (is > 1)\n"
760+
" Actual: succeeded with value 0, (isn't > 1)");
761+
EXPECT_NONFATAL_FAILURE(
762+
EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)),
763+
HasValue(testing::Gt(1))),
764+
"Expected: succeeded with value (is > 1)\n"
765+
" Actual: failed (CustomError { 0})");
755766
}
756767

757768
} // end anon namespace

0 commit comments

Comments
 (0)
Please sign in to comment.