1 /*
2 * Copyright 2019 Google LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "fcp/base/match.h"
18
19 #include <memory>
20 #include <optional>
21 #include <variant>
22
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include "fcp/base/result.h"
26 #include "fcp/testing/result_matchers.h"
27 #include "fcp/testing/testing.h"
28
29 namespace fcp {
30
31 namespace {
32
33 using ::testing::Eq;
34 using ::testing::Optional;
35
36 struct X {
37 int x;
38 };
39
40 struct Y {
41 int y;
42 };
43
44 struct Z {
45 int z;
46 };
47
48 using V = std::variant<X, Y, Z>;
49
50 using VMoveOnly =
51 std::variant<std::unique_ptr<X>, std::unique_ptr<Y>, std::unique_ptr<Z>>;
52
TEST(MatchTest,AllDefault)53 TEST(MatchTest, AllDefault) {
54 constexpr auto matcher =
55 MakeMatcher<V>([](Default, V const&) { return 1; });
56
57 static_assert(matcher.Match(X{}) == 1);
58 static_assert(matcher.Match(Z{}) == 1);
59 static_assert(matcher.Match(Y{}) == 1);
60 }
61
TEST(MatchTest,SingleDefault)62 TEST(MatchTest, SingleDefault) {
63 constexpr auto matcher = MakeMatcher<V>(
64 [](X const& x) { return 10 + x.x; }, //
65 [](Z const& z) { return 20 + z.z; },
66 [](Default, V const& v) { return 30 + absl::get<Y>(v).y; });
67 static_assert(matcher.Match(X{1}) == 11);
68 static_assert(matcher.Match(Z{2}) == 22);
69 static_assert(matcher.Match(Y{3}) == 33);
70 }
71
TEST(MatchTest,SingleDefault_Pointer)72 TEST(MatchTest, SingleDefault_Pointer) {
73 constexpr auto matcher =
74 MakeMatcher<V>([](X* x) { return 10 + x->x; }, //
75 [](Z* z) { return 20 + z->z; },
76 [](Default, V* v) { return 30 + absl::get<Y>(*v).y; });
77
78 V x = X{1};
79 V z = Z{2};
80 V y = Y{3};
81
82 EXPECT_THAT(matcher.Match(&x), Eq(11));
83 EXPECT_THAT(matcher.Match(&z), Eq(22));
84 EXPECT_THAT(matcher.Match(&y), Eq(33));
85 }
86
TEST(MatchTest,Exhaustive)87 TEST(MatchTest, Exhaustive) {
88 constexpr auto matcher = MakeMatcher<V>(
89 [](X const& x) { return 10 + x.x; }, [](Z const& z) { return 20 + z.z; },
90 [](Y const& y) { return 30 + y.y; });
91 static_assert(matcher.Match(X{1}) == 11);
92 static_assert(matcher.Match(Z{2}) == 22);
93 static_assert(matcher.Match(Y{3}) == 33);
94 }
95
TEST(MatchTest,Exhaustive_Pointer)96 TEST(MatchTest, Exhaustive_Pointer) {
97 constexpr auto matcher = MakeMatcher<V>([](X* x) { return 10 + x->x; },
98 [](Z* z) { return 20 + z->z; },
99 [](Y* y) { return 30 + y->y; });
100
101 V x = X{1};
102 V z = Z{2};
103 V y = Y{3};
104
105 EXPECT_THAT(matcher.Match(&x), Eq(11));
106 EXPECT_THAT(matcher.Match(&z), Eq(22));
107 EXPECT_THAT(matcher.Match(&y), Eq(33));
108 }
109
TEST(MatchTest,Exhaustive_MatchInsteadOfMatcher)110 TEST(MatchTest, Exhaustive_MatchInsteadOfMatcher) {
111 constexpr auto do_match = [](V const& v) {
112 return Match(
113 v, //
114 [](X const& x) { return 10 + x.x; },
115 [](Z const& z) { return 20 + z.z; },
116 [](Y const& y) { return 30 + y.y; });
117 };
118
119 static_assert(do_match(X{1}) == 11);
120 static_assert(do_match(Z{2}) == 22);
121 static_assert(do_match(Y{3}) == 33);
122 }
123
TEST(MatchTest,CoerceViaExplicitReturnType)124 TEST(MatchTest, CoerceViaExplicitReturnType) {
125 constexpr auto do_match = [](V const& v) {
126 return Match<std::optional<int>>(
127 v, //
128 [](X const& x) { return 10 + x.x; },
129 [](Z const& z) { return 20 + z.z; },
130 [](Y const& y) { return std::nullopt; });
131 };
132
133 static_assert(*do_match(X{1}) == 11);
134 static_assert(*do_match(Z{2}) == 22);
135 static_assert(!do_match(Y{3}).has_value());
136 }
137
TEST(MatchTest,MoveOnly_Borrow_Exhaustive)138 TEST(MatchTest, MoveOnly_Borrow_Exhaustive) {
139 constexpr auto matcher = MakeMatcher<VMoveOnly>(
140 [](std::unique_ptr<X> const& x) { return 10 + x->x; },
141 [](std::unique_ptr<Z> const& z) { return 20 + z->z; },
142 [](std::unique_ptr<Y> const& y) { return 30 + y->y; });
143
144 VMoveOnly v_x = std::make_unique<X>(X{1});
145 VMoveOnly v_z = std::make_unique<Z>(Z{2});
146 VMoveOnly v_y = std::make_unique<Y>(Y{3});
147
148 EXPECT_THAT(matcher.Match(v_x), Eq(11));
149 EXPECT_THAT(matcher.Match(v_z), Eq(22));
150 EXPECT_THAT(matcher.Match(v_y), Eq(33));
151 }
152
TEST(MatchTest,MoveOnly_Consume_Exhaustive)153 TEST(MatchTest, MoveOnly_Consume_Exhaustive) {
154 constexpr auto matcher = MakeMatcher<VMoveOnly>(
155 [](std::unique_ptr<X> x) { return 10 + x->x; },
156 [](std::unique_ptr<Z> z) { return 20 + z->z; },
157 [](std::unique_ptr<Y> y) { return 30 + y->y; });
158
159 VMoveOnly v_x = std::make_unique<X>(X{1});
160 VMoveOnly v_z = std::make_unique<Z>(Z{2});
161 VMoveOnly v_y = std::make_unique<Y>(Y{3});
162
163 EXPECT_THAT(matcher.Match(std::move(v_x)), Eq(11));
164 EXPECT_THAT(matcher.Match(std::move(v_z)), Eq(22));
165 EXPECT_THAT(matcher.Match(std::move(v_y)), Eq(33));
166 }
167
168 // std::optional is handled with a special MatchTraits implementation.
169 // The corresponding std::variant has to be synthesized on the fly, so that
170 // implementation is trickier than usual.
171
TEST(MatchTest,Optional_Ref)172 TEST(MatchTest, Optional_Ref) {
173 using O = std::optional<std::unique_ptr<X>>;
174 constexpr auto matcher =
175 MakeMatcher<O>([](std::unique_ptr<X> const& x) { return x->x; },
176 [](std::nullopt_t) { return 0; });
177
178 O const engaged = std::make_unique<X>(X{123});
179 O const empty = std::nullopt;
180
181 EXPECT_THAT(matcher.Match(engaged), Eq(123));
182 EXPECT_THAT(matcher.Match(empty), Eq(0));
183 }
184
TEST(MatchTest,Optional_Pointer)185 TEST(MatchTest, Optional_Pointer) {
186 using O = std::optional<std::unique_ptr<X>>;
187 constexpr auto matcher = MakeMatcher<O>(
188 [](std::unique_ptr<X>* x) {
189 int v = (*x)->x;
190 x->reset();
191 return v;
192 },
193 [](std::nullopt_t) { return 0; });
194
195 O engaged = std::make_unique<X>(X{123});
196 O empty = std::nullopt;
197
198 EXPECT_THAT(matcher.Match(&engaged), Eq(123));
199 EXPECT_THAT(engaged, Optional(Eq(nullptr)));
200 EXPECT_THAT(matcher.Match(&empty), Eq(0));
201 }
202
TEST(MatchTest,Optional_Consume)203 TEST(MatchTest, Optional_Consume) {
204 using O = std::optional<std::unique_ptr<X>>;
205 constexpr auto matcher =
206 MakeMatcher<O>([](std::unique_ptr<X> x) { return x->x; },
207 [](std::nullopt_t) { return 0; });
208
209 EXPECT_THAT(matcher.Match(O{std::make_unique<X>(X{123})}), Eq(123));
210 EXPECT_THAT(matcher.Match(O{std::nullopt}), Eq(0));
211 }
212
213 // Result<T> uses the extensibility mechanism provided by MatchTrait
214 // (VariantType alias and a variant() accessor). These tests demonstrate that
215 // MatchTraits is extensible (in addition to testing the particular
216 // implementation for Result).
217
TEST(MatchTest,Result_Ref)218 TEST(MatchTest, Result_Ref) {
219 using R = Result<std::unique_ptr<X>>;
220 constexpr auto matcher =
221 MakeMatcher<R>([](std::unique_ptr<X> const& x) { return x->x; },
222 [](Error) { return 0; });
223
224 R const val = std::make_unique<X>(X{123});
225 R const err = TraceTestError();
226
227 EXPECT_THAT(matcher.Match(val), Eq(123));
228 EXPECT_THAT(matcher.Match(err), Eq(0));
229 }
230
TEST(MatchTest,Result_Pointer)231 TEST(MatchTest, Result_Pointer) {
232 using R = Result<std::unique_ptr<X>>;
233 constexpr auto matcher = MakeMatcher<R>(
234 [](std::unique_ptr<X>* x) {
235 int v = (*x)->x;
236 x->reset();
237 return v;
238 },
239 [](Error*) { return 0; });
240
241 R val = std::make_unique<X>(X{123});
242 R err = TraceTestError();
243
244 EXPECT_THAT(matcher.Match(&val), Eq(123));
245 EXPECT_THAT(val, HasValue(Eq(nullptr)));
246 EXPECT_THAT(matcher.Match(&err), Eq(0));
247 }
248
TEST(MatchTest,Result_Consume)249 TEST(MatchTest, Result_Consume) {
250 using R = Result<std::unique_ptr<X>>;
251 constexpr auto matcher = MakeMatcher<R>(
252 [](std::unique_ptr<X> x) { return x->x; }, [](Error) { return 0; });
253
254 EXPECT_THAT(matcher.Match(R(std::make_unique<X>(X{123}))), Eq(123));
255 EXPECT_THAT(matcher.Match(R(TraceTestError())), Eq(0));
256 }
257
258 } // namespace
259
260 } // namespace fcp
261