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