Bug 1642744 [wpt PR 23920] - [ScrollTimeline] Update compositor timeline from blink...
[gecko.git] / mfbt / tests / TestResult.cpp
blobf02484da9202ee210d66a8aa5aa5edda1539c314
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/. */
7 #include <string.h>
8 #include "mozilla/Result.h"
9 #include "mozilla/UniquePtr.h"
11 using mozilla::Err;
12 using mozilla::GenericErrorResult;
13 using mozilla::Ok;
14 using mozilla::Result;
15 using mozilla::UniquePtr;
17 struct Failed {
18 int x;
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");
25 static_assert(
26 sizeof(Result<char*, Failed*>) > sizeof(char*),
27 "Result with unaligned success type `char*` must not be pointer-sized");
28 static_assert(
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() {
55 static Failed failed;
56 return Err<Failed&>(failed);
59 static Result<Ok, Failed&> Task1(bool pass) {
60 if (!pass) {
61 return Fail(); // implicit conversion from GenericErrorResult to Result
63 return Ok();
66 static Result<int, Failed&> Task2(bool pass, int value) {
67 MOZ_TRY(
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) {
73 int x, y;
74 MOZ_TRY_VAR(x, Task2(pass1, value));
75 MOZ_TRY_VAR(y, Task2(pass2, value));
76 return x + y;
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());
85 // MOZ_TRY works.
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);
92 // MOZ_TRY_VAR works.
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());
105 res = Task1(false);
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.
121 int i = 123;
122 double d = 3.14;
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);
131 res = Err(d);
132 MOZ_RELEASE_ASSERT(res.isErr());
133 MOZ_RELEASE_ASSERT(&res.unwrapErr() == &d);
134 MOZ_RELEASE_ASSERT(res.unwrapErr() == 3.14);
138 /* * */
140 struct Snafu : Failed {};
142 static Result<Ok, Snafu*> Explode() {
143 static Snafu snafu;
144 return Err(&snafu);
147 static Result<Ok, Failed*> ErrorGeneralization() {
148 MOZ_TRY(Explode()); // change error type from Snafu* to more general Failed*
149 return Ok();
152 static void TypeConversionTests() {
153 MOZ_RELEASE_ASSERT(ErrorGeneralization().isErr());
156 static void EmptyValueTest() {
157 struct Fine {};
158 mozilla::Result<Fine, int&> res((Fine()));
159 res.unwrap();
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() {
166 struct MyError {
167 int x = 0;
169 MyError merror;
170 Result<int, MyError&> res(merror);
171 MOZ_RELEASE_ASSERT(&res.unwrapErr() == &merror);
174 static void MapTest() {
175 struct MyError {
176 int x;
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);
186 invoked = true;
187 return "hello";
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.
194 MyError err(1);
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);
199 return 'a';
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());
241 return Ok();
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());
293 /* * */
295 int main() {
296 BasicTests();
297 TypeConversionTests();
298 EmptyValueTest();
299 ReferenceTest();
300 MapTest();
301 AndThenTest();
302 UniquePtrTest();
303 return 0;