xref: /aosp_15_r20/external/federated-compute/fcp/base/match_test.cc (revision 14675a029014e728ec732f129a32e299b2da0601)
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