1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "mozilla/Result.h"
9 #include "mozilla/UniquePtr.h"
12 using mozilla::GenericErrorResult
;
14 using mozilla::Result
;
15 using mozilla::UniquePtr
;
21 static_assert(sizeof(Result
<Ok
, Failed
&>) == sizeof(uintptr_t),
22 "Result with empty value type should be pointer-sized");
23 static_assert(sizeof(Result
<int*, Failed
&>) == sizeof(uintptr_t),
24 "Result with two aligned pointer types should be pointer-sized");
26 sizeof(Result
<char*, Failed
*>) > sizeof(char*),
27 "Result with unaligned success type `char*` must not be pointer-sized");
29 sizeof(Result
<int*, char*>) > sizeof(char*),
30 "Result with unaligned error type `char*` must not be pointer-sized");
32 enum Foo8
: uint8_t {};
33 enum Foo16
: uint16_t {};
34 enum Foo32
: uint32_t {};
35 static_assert(sizeof(Result
<Ok
, Foo8
>) <= sizeof(uintptr_t),
36 "Result with small types should be pointer-sized");
37 static_assert(sizeof(Result
<Ok
, Foo16
>) <= sizeof(uintptr_t),
38 "Result with small types should be pointer-sized");
39 static_assert(sizeof(Foo32
) >= sizeof(uintptr_t) ||
40 sizeof(Result
<Ok
, Foo32
>) <= sizeof(uintptr_t),
41 "Result with small types should be pointer-sized");
43 static_assert(sizeof(Result
<Foo16
, Foo8
>) <= sizeof(uintptr_t),
44 "Result with small types should be pointer-sized");
45 static_assert(sizeof(Result
<Foo8
, Foo16
>) <= sizeof(uintptr_t),
46 "Result with small types should be pointer-sized");
47 static_assert(sizeof(Foo32
) >= sizeof(uintptr_t) ||
48 sizeof(Result
<Foo32
, Foo16
>) <= sizeof(uintptr_t),
49 "Result with small types should be pointer-sized");
50 static_assert(sizeof(Foo32
) >= sizeof(uintptr_t) ||
51 sizeof(Result
<Foo16
, Foo32
>) <= sizeof(uintptr_t),
52 "Result with small types should be pointer-sized");
54 static GenericErrorResult
<Failed
&> Fail() {
56 return Err
<Failed
&>(failed
);
59 static Result
<Ok
, Failed
&> Task1(bool pass
) {
61 return Fail(); // implicit conversion from GenericErrorResult to Result
66 static Result
<int, Failed
&> Task2(bool pass
, int value
) {
68 Task1(pass
)); // converts one type of result to another in the error case
69 return value
; // implicit conversion from T to Result<T, E>
72 static Result
<int, Failed
&> Task3(bool pass1
, bool pass2
, int value
) {
74 MOZ_TRY_VAR(x
, Task2(pass1
, value
));
75 MOZ_TRY_VAR(y
, Task2(pass2
, value
));
79 static void BasicTests() {
80 MOZ_RELEASE_ASSERT(Task1(true).isOk());
81 MOZ_RELEASE_ASSERT(!Task1(true).isErr());
82 MOZ_RELEASE_ASSERT(!Task1(false).isOk());
83 MOZ_RELEASE_ASSERT(Task1(false).isErr());
86 MOZ_RELEASE_ASSERT(Task2(true, 3).isOk());
87 MOZ_RELEASE_ASSERT(Task2(true, 3).unwrap() == 3);
88 MOZ_RELEASE_ASSERT(Task2(true, 3).unwrapOr(6) == 3);
89 MOZ_RELEASE_ASSERT(Task2(false, 3).isErr());
90 MOZ_RELEASE_ASSERT(Task2(false, 3).unwrapOr(6) == 6);
93 MOZ_RELEASE_ASSERT(Task3(true, true, 3).isOk());
94 MOZ_RELEASE_ASSERT(Task3(true, true, 3).unwrap() == 6);
95 MOZ_RELEASE_ASSERT(Task3(true, false, 3).isErr());
96 MOZ_RELEASE_ASSERT(Task3(false, true, 3).isErr());
97 MOZ_RELEASE_ASSERT(Task3(false, true, 3).unwrapOr(6) == 6);
99 // Lvalues should work too.
101 Result
<Ok
, Failed
&> res
= Task1(true);
102 MOZ_RELEASE_ASSERT(res
.isOk());
103 MOZ_RELEASE_ASSERT(!res
.isErr());
106 MOZ_RELEASE_ASSERT(!res
.isOk());
107 MOZ_RELEASE_ASSERT(res
.isErr());
111 Result
<int, Failed
&> res
= Task2(true, 3);
112 MOZ_RELEASE_ASSERT(res
.isOk());
113 MOZ_RELEASE_ASSERT(res
.unwrap() == 3);
115 res
= Task2(false, 4);
116 MOZ_RELEASE_ASSERT(res
.isErr());
119 // Some tests for pointer tagging.
124 Result
<int*, double&> res
= &i
;
125 static_assert(sizeof(res
) == sizeof(uintptr_t),
126 "should use pointer tagging to fit in a word");
128 MOZ_RELEASE_ASSERT(res
.isOk());
129 MOZ_RELEASE_ASSERT(*res
.unwrap() == 123);
132 MOZ_RELEASE_ASSERT(res
.isErr());
133 MOZ_RELEASE_ASSERT(&res
.unwrapErr() == &d
);
134 MOZ_RELEASE_ASSERT(res
.unwrapErr() == 3.14);
140 struct Snafu
: Failed
{};
142 static Result
<Ok
, Snafu
*> Explode() {
147 static Result
<Ok
, Failed
*> ErrorGeneralization() {
148 MOZ_TRY(Explode()); // change error type from Snafu* to more general Failed*
152 static void TypeConversionTests() {
153 MOZ_RELEASE_ASSERT(ErrorGeneralization().isErr());
156 static void EmptyValueTest() {
158 mozilla::Result
<Fine
, int&> res((Fine()));
160 MOZ_RELEASE_ASSERT(res
.isOk());
161 static_assert(sizeof(res
) == sizeof(uintptr_t),
162 "Result with empty value type should be pointer-sized");
165 static void ReferenceTest() {
170 Result
<int, MyError
&> res(merror
);
171 MOZ_RELEASE_ASSERT(&res
.unwrapErr() == &merror
);
174 static void MapTest() {
178 explicit MyError(int y
) : x(y
) {}
181 // Mapping over success values.
182 Result
<int, MyError
> res(5);
183 bool invoked
= false;
184 auto res2
= res
.map([&invoked
](int x
) {
185 MOZ_RELEASE_ASSERT(x
== 5);
189 MOZ_RELEASE_ASSERT(res2
.isOk());
190 MOZ_RELEASE_ASSERT(invoked
);
191 MOZ_RELEASE_ASSERT(strcmp(res2
.unwrap(), "hello") == 0);
193 // Mapping over error values.
195 Result
<char, MyError
> res3(err
);
196 MOZ_RELEASE_ASSERT(res3
.isErr());
197 Result
<char, MyError
> res4
= res3
.map([](int x
) {
198 MOZ_RELEASE_ASSERT(false);
201 MOZ_RELEASE_ASSERT(res4
.isErr());
202 MOZ_RELEASE_ASSERT(res4
.unwrapErr().x
== err
.x
);
204 // Function pointers instead of lamdbas as the mapping function.
205 Result
<const char*, MyError
> res5("hello");
206 auto res6
= res5
.map(strlen
);
207 MOZ_RELEASE_ASSERT(res6
.isOk());
208 MOZ_RELEASE_ASSERT(res6
.unwrap() == 5);
211 static void AndThenTest() {
212 // `andThen`ing over success results.
213 Result
<int, const char*> r1(10);
214 Result
<int, const char*> r2
=
215 r1
.andThen([](int x
) { return Result
<int, const char*>(x
+ 1); });
216 MOZ_RELEASE_ASSERT(r2
.isOk());
217 MOZ_RELEASE_ASSERT(r2
.unwrap() == 11);
219 // `andThen`ing over error results.
220 Result
<int, const char*> r3("error");
221 Result
<int, const char*> r4
= r3
.andThen([](int x
) {
222 MOZ_RELEASE_ASSERT(false);
223 return Result
<int, const char*>(1);
225 MOZ_RELEASE_ASSERT(r4
.isErr());
226 MOZ_RELEASE_ASSERT(r3
.unwrapErr() == r4
.unwrapErr());
229 using UniqueResult
= Result
<UniquePtr
<int>, const char*>;
231 static UniqueResult
UniqueTask() { return mozilla::MakeUnique
<int>(3); }
232 static UniqueResult
UniqueTaskError() { return Err("bad"); }
234 using UniqueErrorResult
= Result
<int, UniquePtr
<int>>;
235 static UniqueErrorResult
UniqueError() {
236 return Err(mozilla::MakeUnique
<int>(4));
239 static Result
<Ok
, UniquePtr
<int>> TryUniqueErrorResult() {
240 MOZ_TRY(UniqueError());
244 static void UniquePtrTest() {
246 auto result
= UniqueTask();
247 MOZ_RELEASE_ASSERT(result
.isOk());
248 auto ptr
= result
.unwrap();
249 MOZ_RELEASE_ASSERT(ptr
);
250 MOZ_RELEASE_ASSERT(*ptr
== 3);
251 auto moved
= result
.unwrap();
252 MOZ_RELEASE_ASSERT(!moved
);
256 auto err
= UniqueTaskError();
257 MOZ_RELEASE_ASSERT(err
.isErr());
258 auto ptr
= err
.unwrapOr(mozilla::MakeUnique
<int>(4));
259 MOZ_RELEASE_ASSERT(ptr
);
260 MOZ_RELEASE_ASSERT(*ptr
== 4);
264 auto result
= UniqueTaskError();
265 result
= UniqueResult(mozilla::MakeUnique
<int>(6));
266 MOZ_RELEASE_ASSERT(result
.isOk());
267 MOZ_RELEASE_ASSERT(result
.inspect() && *result
.inspect() == 6);
271 auto result
= UniqueError();
272 MOZ_RELEASE_ASSERT(result
.isErr());
273 MOZ_RELEASE_ASSERT(result
.inspectErr());
274 MOZ_RELEASE_ASSERT(*result
.inspectErr() == 4);
275 auto err
= result
.unwrapErr();
276 MOZ_RELEASE_ASSERT(!result
.inspectErr());
277 MOZ_RELEASE_ASSERT(err
);
278 MOZ_RELEASE_ASSERT(*err
== 4);
280 result
= UniqueErrorResult(0);
281 MOZ_RELEASE_ASSERT(result
.isOk() && result
.unwrap() == 0);
285 auto result
= TryUniqueErrorResult();
286 MOZ_RELEASE_ASSERT(result
.isErr());
287 auto err
= result
.unwrapErr();
288 MOZ_RELEASE_ASSERT(err
&& *err
== 4);
289 MOZ_RELEASE_ASSERT(!result
.inspectErr());
297 TypeConversionTests();