xref: /aosp_15_r20/external/federated-compute/fcp/base/result_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/result.h"
18 
19 #include <memory>
20 #include <utility>
21 #include <variant>
22 
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include "fcp/base/tracing_schema.h"
26 #include "fcp/base/unique_value.h"
27 #include "fcp/testing/result_matchers.h"
28 #include "fcp/testing/testing.h"
29 #include "fcp/tracing/test_tracing_recorder.h"
30 
31 namespace fcp {
32 
33 using ::testing::Eq;
34 using ::testing::VariantWith;
35 
36 template <typename T>
HasValue(Result<T> r,T v)37 constexpr bool HasValue(Result<T> r, T v) {
38   return !r.is_error() && r.GetValueOrDie() == v;
39 }
40 
41 template <typename T>
IsError(Result<T> r)42 constexpr bool IsError(Result<T> r) {
43   return r.is_error();
44 }
45 
TEST(ResultTest,Constructor)46 TEST(ResultTest, Constructor) {
47   ASSERT_THAT(Result<int>(TraceTestError()), IsError());
48   ASSERT_THAT(Result(123), HasValue(123));
49 }
50 
TEST(ResultTest,CombinatorsToValue)51 TEST(ResultTest, CombinatorsToValue) {
52   Result<bool> r = Result(123)
53                        .Then([](int i) -> Result<bool> { return i != 123; })
54                        .Map([](bool b) -> bool { return !b; });
55   ASSERT_THAT(r, HasValue(true));
56 }
57 
TEST(ResultTest,CombinatorsToValue_MoveOnly)58 TEST(ResultTest, CombinatorsToValue_MoveOnly) {
59   Result<bool> r =
60       Result(UniqueValue(123))
61           .Then([](UniqueValue<int> i) -> Result<UniqueValue<bool>> {
62             return UniqueValue(std::move(i).Take() != 123);
63           })
64           .Map([](UniqueValue<bool> b) -> UniqueValue<bool> {
65             return UniqueValue(!std::move(b).Take());
66           })
67           .Map([](UniqueValue<bool> b) -> bool { return std::move(b).Take(); });
68   ASSERT_THAT(r, HasValue(true));
69 }
70 
TEST(ResultTest,MapToValue_MoveOnly_Const)71 TEST(ResultTest, MapToValue_MoveOnly_Const) {
72   Result<UniqueValue<int>> r1 = Result(UniqueValue(21));
73   Result<int> r2 = r1.Map([](UniqueValue<int> const& v) { return (*v) * 2; });
74   Result<bool> r1_still_valid =
75       r1.Map([](UniqueValue<int> const& v) { return v.has_value(); });
76 
77   ASSERT_THAT(r2, HasValue(42));
78   ASSERT_THAT(r1_still_valid, HasValue(true));
79 }
80 
TEST(ResultTest,ThenToValue_MoveOnly_Const)81 TEST(ResultTest, ThenToValue_MoveOnly_Const) {
82   Result<UniqueValue<int>> r1 = Result(UniqueValue(21));
83   Result<int> r2 =
84       r1.Then([](UniqueValue<int> const& v) { return Result((*v) * 2); });
85   Result<bool> r1_still_valid =
86       r1.Then([](UniqueValue<int> const& v) { return Result(v.has_value()); });
87 
88   ASSERT_THAT(r2, HasValue(42));
89   ASSERT_THAT(r1_still_valid, HasValue(true));
90 }
91 
ExpectUnreachable()92 void ExpectUnreachable() { FAIL(); }
93 
TEST(ResultTest,CombinatorsToError)94 TEST(ResultTest, CombinatorsToError) {
95   Result<Unit> r = Result(123)
96                        .Then([](int i) -> Result<int> {
97                          if (i > 0) {
98                            return TraceTestError();
99                          } else {
100                            return i;
101                          }
102                        })
103                        .Map([](int i) -> Unit {
104                          ExpectUnreachable();
105                          return Unit{};
106                        });
107   ASSERT_THAT(r, IsError());
108 }
109 
TEST(ResultTest,ResultFrom)110 TEST(ResultTest, ResultFrom) {
111   static_assert(std::is_same_v<ResultFrom<Result<int>>, Result<int>>);
112   static_assert(std::is_same_v<ResultFrom<int>, Result<int>>);
113 }
114 
115 template <typename Expect, typename Fn, typename... Args>
ExpectResultOf(Fn fn,Args...args)116 constexpr Unit ExpectResultOf(Fn fn, Args... args) {
117   using R = ResultOf<Fn, Args...>;
118   static_assert(std::is_same_v<R, Expect>);
119   return {};
120 }
121 
122 namespace result_of_example {
123 
Result0()124 Result<Unit> Result0() { return Unit{}; }
Result1(int)125 Result<Unit> Result1(int) { return Unit{}; }
Value1(int i)126 Unit Value1(int i) { return Unit{}; }
__anond40ed5680c02(auto t) 127 constexpr auto Generic = [](auto t) { return Result(t); };
128 
129 }  // namespace result_of_example
130 
TEST(ResultTest,ResultOf)131 TEST(ResultTest, ResultOf) {
132   static_assert(
133       ExpectResultOf<Result<Unit>>(result_of_example::Result0).True());
134   static_assert(
135       ExpectResultOf<Result<Unit>>(result_of_example::Result1, 123).True());
136   static_assert(
137       ExpectResultOf<Result<Unit>>(result_of_example::Value1, 123).True());
138   static_assert(
139       ExpectResultOf<Result<bool>>(result_of_example::Generic, true).True());
140 }
141 
Example_OneTryExpression(Result<int> r)142 Result<bool> Example_OneTryExpression(Result<int> r) {
143   int i = FCP_TRY(r);
144   if (i < 0) {
145     return TraceTestError();
146   }
147 
148   return i % 2 == 0;
149 }
150 
TEST(ResultTest,TryExpressionWithError)151 TEST(ResultTest, TryExpressionWithError) {
152   EXPECT_THAT(Example_OneTryExpression(TraceTestError()), IsError());
153 }
154 
TEST(ResultTest,TryExpressionWithValue)155 TEST(ResultTest, TryExpressionWithValue) {
156   EXPECT_THAT(Example_OneTryExpression(-1), IsError());
157   EXPECT_THAT(Example_OneTryExpression(1), HasValue(false));
158   EXPECT_THAT(Example_OneTryExpression(2), HasValue(true));
159 }
160 
Example_OneTryExpression_UnparenthesizedCommas(Result<std::variant<int,bool,Unit>> r)161 Result<bool> Example_OneTryExpression_UnparenthesizedCommas(
162     Result<std::variant<int, bool, Unit>> r) {
163   std::variant<int, bool> v = FCP_TRY(r.Then(ExpectOneOf<int, bool>()));
164   if (std::holds_alternative<int>(v)) {
165     return absl::get<int>(v) > 0;
166   } else {
167     return absl::get<bool>(v);
168   }
169 }
170 
TEST(ResultTest,TryExpressionWithValue_UnparenthesizedCommas)171 TEST(ResultTest, TryExpressionWithValue_UnparenthesizedCommas) {
172   using V = std::variant<int, bool, Unit>;
173   EXPECT_THAT(Example_OneTryExpression_UnparenthesizedCommas(V(-1)),
174               HasValue(false));
175   EXPECT_THAT(Example_OneTryExpression_UnparenthesizedCommas(V(1)),
176               HasValue(true));
177   EXPECT_THAT(Example_OneTryExpression_UnparenthesizedCommas(V(false)),
178               HasValue(false));
179   EXPECT_THAT(Example_OneTryExpression_UnparenthesizedCommas(V(true)),
180               HasValue(true));
181   EXPECT_THAT(Example_OneTryExpression_UnparenthesizedCommas(V(Unit{})),
182               IsError());
183 }
184 
Example_SumWithTryExpressions(Result<int> a,Result<int> b)185 Result<int> Example_SumWithTryExpressions(Result<int> a, Result<int> b) {
186   return FCP_TRY(a) + FCP_TRY(b);
187 }
188 
TEST(ResultTest,TwoTryExpressionsWithError)189 TEST(ResultTest, TwoTryExpressionsWithError) {
190   EXPECT_THAT(Example_SumWithTryExpressions(TraceTestError(), 1), IsError());
191   EXPECT_THAT(Example_SumWithTryExpressions(41, TraceTestError()), IsError());
192   EXPECT_THAT(Example_SumWithTryExpressions(TraceTestError(), TraceTestError()),
193               IsError());
194 }
195 
TEST(ResultTest,TwoTryExpressionsWithValues)196 TEST(ResultTest, TwoTryExpressionsWithValues) {
197   EXPECT_THAT(Example_SumWithTryExpressions(1, 41), HasValue(42));
198 }
199 
Example_TryExpression_MoveOnly(Result<std::unique_ptr<int>> r)200 Result<int> Example_TryExpression_MoveOnly(Result<std::unique_ptr<int>> r) {
201   std::unique_ptr<int> p = FCP_TRY(std::move(r));
202   return *p;
203 }
204 
TEST(ResultTest,TryExpressionWithError_MoveOnly)205 TEST(ResultTest, TryExpressionWithError_MoveOnly) {
206   EXPECT_THAT(Example_TryExpression_MoveOnly(TraceTestError()), IsError());
207 }
208 
TEST(ResultTest,TryExpressionWithValue_MoveOnly)209 TEST(ResultTest, TryExpressionWithValue_MoveOnly) {
210   EXPECT_THAT(Example_TryExpression_MoveOnly(std::make_unique<int>(123)),
211               HasValue(123));
212 }
213 
Example_TryStatement(Result<Unit> r)214 Result<bool> Example_TryStatement(Result<Unit> r) {
215   FCP_TRY(r);
216   return true;
217 }
218 
TEST(ResultTest,TryStatementWithError)219 TEST(ResultTest, TryStatementWithError) {
220   EXPECT_THAT(Example_TryStatement(TraceTestError()), IsError());
221 }
222 
TEST(ResultTest,TryStatementWithValue)223 TEST(ResultTest, TryStatementWithValue) {
224   EXPECT_THAT(Example_TryStatement(Unit{}), HasValue(true));
225 }
226 
TEST(ResultTest,ExpectTrue)227 TEST(ResultTest, ExpectTrue) {
228   EXPECT_THAT(Result(true).Then(ExpectTrue()), HasValue(Unit{}));
229   EXPECT_THAT(Result(false).Then(ExpectTrue()), IsError());
230   EXPECT_THAT(Result<bool>(TraceTestError()).Then(ExpectTrue()), IsError());
231 }
232 
TEST(ResultTest,ExpectFalse)233 TEST(ResultTest, ExpectFalse) {
234   EXPECT_THAT(Result(false).Then(ExpectFalse()), HasValue(Unit{}));
235   EXPECT_THAT(Result(true).Then(ExpectFalse()), IsError());
236   EXPECT_THAT(Result<bool>(TraceTestError()).Then(ExpectFalse()), IsError());
237 }
238 
TEST(ResultTest,ExpectHasValue)239 TEST(ResultTest, ExpectHasValue) {
240   using V = std::optional<int>;
241   EXPECT_THAT(Result<V>(123).Then(ExpectHasValue()), HasValue(123));
242   EXPECT_THAT(Result<V>(V{}).Then(ExpectHasValue()), IsError());
243   EXPECT_THAT(Result<V>(TraceTestError()).Then(ExpectHasValue()), IsError());
244 }
245 
TEST(ResultTest,ExpectIsEmpty)246 TEST(ResultTest, ExpectIsEmpty) {
247   using V = std::optional<int>;
248   EXPECT_THAT(Result<V>(123).Then(ExpectIsEmpty()), IsError());
249   EXPECT_THAT(Result<V>(V{}).Then(ExpectIsEmpty()), HasValue(Unit{}));
250   EXPECT_THAT(Result<V>(TraceTestError()).Then(ExpectIsEmpty()), IsError());
251 }
252 
TEST(ResultTest,ExpectIs)253 TEST(ResultTest, ExpectIs) {
254   using V = std::variant<int, char>;
255   EXPECT_THAT(Result<V>(123).Then(ExpectIs<int>()), HasValue(123));
256   EXPECT_THAT(Result<V>('a').Then(ExpectIs<char>()), HasValue('a'));
257   EXPECT_THAT(Result<V>('b').Then(ExpectIs<int>()), IsError());
258   EXPECT_THAT(Result<V>(TraceTestError()).Then(ExpectIs<int>()), IsError());
259   EXPECT_THAT(Result<V>(TraceTestError()).Then(ExpectIs<char>()), IsError());
260 }
261 
TEST(ResultTest,ExpectOneOf)262 TEST(ResultTest, ExpectOneOf) {
263   using V = std::variant<int, char, bool>;
264   EXPECT_THAT(Result<V>(123).Then(ExpectOneOf<int>()),
265               HasValue(VariantWith<int>(123)));
266   EXPECT_THAT(Result<V>(123).Then(ExpectOneOf<bool>()), IsError());
267   EXPECT_THAT((Result<V>(123).Then(ExpectOneOf<int, bool>())),
268               HasValue(VariantWith<int>(123)));
269   EXPECT_THAT((Result<V>(123).Then(ExpectOneOf<char, bool>())), IsError());
270   EXPECT_THAT((Result<V>(TraceTestError()).Then(ExpectOneOf<int, bool>())),
271               IsError());
272 }
273 
TEST(ResultTest,ExpectOk)274 TEST(ResultTest, ExpectOk) {
275   TestTracingRecorder recorder;
276   EXPECT_THAT(Result<Status>(FCP_STATUS(OK)).Then(ExpectOk()),
277               HasValue(Unit{}));
278 }
279 
TEST(ResultTest,ExpectOkReturnsError)280 TEST(ResultTest, ExpectOkReturnsError) {
281   TestTracingRecorder recorder;
282   recorder.ExpectError<ResultExpectStatusError>();
283   EXPECT_THAT(Result<Status>(FCP_STATUS(INVALID_ARGUMENT)).Then(ExpectOk()),
284               IsError());
285 }
286 
TEST(ResultTest,ExpectOkStatusOr)287 TEST(ResultTest, ExpectOkStatusOr) {
288   TestTracingRecorder recorder;
289   EXPECT_THAT(Result<StatusOr<Unit>>(StatusOr<Unit>(Unit{})).Then(ExpectOk()),
290               HasValue(Unit{}));
291 }
292 
TEST(ResultTest,ExpectOkStatusOrReturnsError)293 TEST(ResultTest, ExpectOkStatusOrReturnsError) {
294   TestTracingRecorder recorder;
295   recorder.ExpectError<ResultExpectStatusError>();
296   EXPECT_THAT(
297       Result<StatusOr<Unit>>(FCP_STATUS(INVALID_ARGUMENT)).Then(ExpectOk()),
298       IsError());
299   EXPECT_THAT(
300       recorder.FindAllEvents<ResultExpectStatusError>(),
301       ElementsAre(IsEvent<ResultExpectStatusError>(
302           Eq(TracingStatusCode_Ok), Eq(TracingStatusCode_InvalidArgument))));
303 }
304 
TEST(ResultTest,TraceFailedPrecondition)305 TEST(ResultTest, TraceFailedPrecondition) {
306   TestTracingRecorder recorder;
307   recorder.ExpectError<ResultExpectStatusError>();
308   EXPECT_THAT(
309       Result<StatusOr<Unit>>(FCP_STATUS(FAILED_PRECONDITION)).Then(ExpectOk()),
310       IsError());
311   EXPECT_THAT(
312       recorder.FindAllEvents<ResultExpectStatusError>(),
313       ElementsAre(IsEvent<ResultExpectStatusError>(
314           Eq(TracingStatusCode_Ok), Eq(TracingStatusCode_FailedPrecondition))));
315 }
316 
317 }  // namespace fcp
318