Bug 1883853 [wpt PR 44937] - [wdspec] fix test_set_permission_origin_unknown, a=testonly
[gecko.git] / mfbt / tests / TestResult.cpp
bloba2e10640c5d927b68cc8d2b983ef4184b53e4ed9
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 <stdint.h>
8 #include <string.h>
9 #include "mozilla/ResultVariant.h"
10 #include "mozilla/Try.h"
11 #include "mozilla/UniquePtr.h"
13 using mozilla::Err;
14 using mozilla::GenericErrorResult;
15 using mozilla::Ok;
16 using mozilla::Result;
17 using mozilla::UniquePtr;
19 #define MOZ_STATIC_AND_RELEASE_ASSERT(expr) \
20 static_assert(expr); \
21 MOZ_RELEASE_ASSERT(expr)
23 enum struct TestUnusedZeroEnum : int16_t { Ok = 0, NotOk = 1 };
25 namespace mozilla::detail {
26 template <>
27 struct UnusedZero<TestUnusedZeroEnum> : UnusedZeroEnum<TestUnusedZeroEnum> {};
28 } // namespace mozilla::detail
30 struct Failed {};
32 namespace mozilla::detail {
33 template <>
34 struct UnusedZero<Failed> {
35 using StorageType = uintptr_t;
37 static constexpr bool value = true;
38 static constexpr StorageType nullValue = 0;
39 static constexpr StorageType GetDefaultValue() { return 2; }
41 static constexpr void AssertValid(StorageType aValue) {}
42 static constexpr Failed Inspect(const StorageType& aValue) {
43 return Failed{};
45 static constexpr Failed Unwrap(StorageType aValue) { return Failed{}; }
46 static constexpr StorageType Store(Failed aValue) {
47 return GetDefaultValue();
51 } // namespace mozilla::detail
53 // V is trivially default-constructible, and E has UnusedZero<E>::value == true,
54 // for a reference type and for a non-reference type
55 static_assert(mozilla::detail::SelectResultImpl<uintptr_t, Failed>::value ==
56 mozilla::detail::PackingStrategy::NullIsOk);
57 static_assert(
58 mozilla::detail::SelectResultImpl<Ok, TestUnusedZeroEnum>::value ==
59 mozilla::detail::PackingStrategy::NullIsOk);
60 static_assert(mozilla::detail::SelectResultImpl<Ok, Failed>::value ==
61 mozilla::detail::PackingStrategy::LowBitTagIsError);
63 static_assert(std::is_trivially_destructible_v<Result<uintptr_t, Failed>>);
64 static_assert(std::is_trivially_destructible_v<Result<Ok, TestUnusedZeroEnum>>);
65 static_assert(std::is_trivially_destructible_v<Result<Ok, Failed>>);
67 static_assert(
68 sizeof(Result<bool, TestUnusedZeroEnum>) <= sizeof(uintptr_t),
69 "Result with bool value type should not be larger than pointer-sized");
70 static_assert(sizeof(Result<Ok, Failed>) == sizeof(uint8_t),
71 "Result with empty value type should be size 1");
72 static_assert(sizeof(Result<int*, Failed>) == sizeof(uintptr_t),
73 "Result with two aligned pointer types should be pointer-sized");
74 static_assert(
75 sizeof(Result<char*, Failed*>) > sizeof(char*),
76 "Result with unaligned success type `char*` must not be pointer-sized");
77 static_assert(
78 sizeof(Result<int*, char*>) > sizeof(char*),
79 "Result with unaligned error type `char*` must not be pointer-sized");
81 enum Foo8 : uint8_t {};
82 enum Foo16 : uint16_t {};
83 enum Foo32 : uint32_t {};
84 static_assert(sizeof(Result<Ok, Foo8>) <= sizeof(uintptr_t),
85 "Result with small types should be pointer-sized");
86 static_assert(sizeof(Result<Ok, Foo16>) <= sizeof(uintptr_t),
87 "Result with small types should be pointer-sized");
88 static_assert(sizeof(Foo32) >= sizeof(uintptr_t) ||
89 sizeof(Result<Ok, Foo32>) <= sizeof(uintptr_t),
90 "Result with small types should be pointer-sized");
92 static_assert(sizeof(Result<Foo16, Foo8>) <= sizeof(uintptr_t),
93 "Result with small types should be pointer-sized");
94 static_assert(sizeof(Result<Foo8, Foo16>) <= sizeof(uintptr_t),
95 "Result with small types should be pointer-sized");
96 static_assert(sizeof(Foo32) >= sizeof(uintptr_t) ||
97 sizeof(Result<Foo32, Foo16>) <= sizeof(uintptr_t),
98 "Result with small types should be pointer-sized");
99 static_assert(sizeof(Foo32) >= sizeof(uintptr_t) ||
100 sizeof(Result<Foo16, Foo32>) <= sizeof(uintptr_t),
101 "Result with small types should be pointer-sized");
103 #if __cplusplus < 202002L
104 static_assert(std::is_literal_type_v<Result<int*, Failed>>);
105 static_assert(std::is_literal_type_v<Result<Ok, Failed>>);
106 static_assert(std::is_literal_type_v<Result<Ok, Foo8>>);
107 static_assert(std::is_literal_type_v<Result<Foo8, Foo16>>);
108 static_assert(!std::is_literal_type_v<Result<Ok, UniquePtr<int>>>);
109 #endif
111 static constexpr GenericErrorResult<Failed> Fail() { return Err(Failed{}); }
113 static constexpr GenericErrorResult<TestUnusedZeroEnum>
114 FailTestUnusedZeroEnum() {
115 return Err(TestUnusedZeroEnum::NotOk);
118 static constexpr Result<Ok, Failed> Task1(bool pass) {
119 if (!pass) {
120 return Fail(); // implicit conversion from GenericErrorResult to Result
122 return Ok();
125 static constexpr Result<Ok, TestUnusedZeroEnum> Task1UnusedZeroEnumErr(
126 bool pass) {
127 if (!pass) {
128 return FailTestUnusedZeroEnum(); // implicit conversion from
129 // GenericErrorResult to Result
131 return Ok();
134 static constexpr Result<int, Failed> Task2(bool pass, int value) {
135 MOZ_TRY(
136 Task1(pass)); // converts one type of result to another in the error case
137 return value; // implicit conversion from T to Result<T, E>
140 static constexpr Result<int, TestUnusedZeroEnum> Task2UnusedZeroEnumErr(
141 bool pass, int value) {
142 MOZ_TRY(Task1UnusedZeroEnumErr(
143 pass)); // converts one type of result to another in the error case
144 return value; // implicit conversion from T to Result<T, E>
147 static Result<int, Failed> Task3(bool pass1, bool pass2, int value) {
148 int x, y;
149 MOZ_TRY_VAR(x, Task2(pass1, value));
150 MOZ_TRY_VAR(y, Task2(pass2, value));
151 return x + y;
154 static void BasicTests() {
155 MOZ_STATIC_AND_RELEASE_ASSERT(Task1(true).isOk());
156 MOZ_STATIC_AND_RELEASE_ASSERT(!Task1(true).isErr());
157 MOZ_STATIC_AND_RELEASE_ASSERT(!Task1(false).isOk());
158 MOZ_STATIC_AND_RELEASE_ASSERT(Task1(false).isErr());
160 MOZ_STATIC_AND_RELEASE_ASSERT(Task1UnusedZeroEnumErr(true).isOk());
161 MOZ_STATIC_AND_RELEASE_ASSERT(!Task1UnusedZeroEnumErr(true).isErr());
162 MOZ_STATIC_AND_RELEASE_ASSERT(!Task1UnusedZeroEnumErr(false).isOk());
163 MOZ_STATIC_AND_RELEASE_ASSERT(Task1UnusedZeroEnumErr(false).isErr());
164 MOZ_STATIC_AND_RELEASE_ASSERT(TestUnusedZeroEnum::NotOk ==
165 Task1UnusedZeroEnumErr(false).inspectErr());
166 MOZ_STATIC_AND_RELEASE_ASSERT(TestUnusedZeroEnum::NotOk ==
167 Task1UnusedZeroEnumErr(false).unwrapErr());
169 // MOZ_TRY works.
170 MOZ_STATIC_AND_RELEASE_ASSERT(Task2(true, 3).isOk());
171 MOZ_STATIC_AND_RELEASE_ASSERT(Task2(true, 3).unwrap() == 3);
172 MOZ_STATIC_AND_RELEASE_ASSERT(Task2(true, 3).unwrapOr(6) == 3);
173 MOZ_RELEASE_ASSERT(Task2(false, 3).isErr());
174 MOZ_RELEASE_ASSERT(Task2(false, 3).unwrapOr(6) == 6);
176 MOZ_STATIC_AND_RELEASE_ASSERT(Task2UnusedZeroEnumErr(true, 3).isOk());
177 MOZ_STATIC_AND_RELEASE_ASSERT(Task2UnusedZeroEnumErr(true, 3).unwrap() == 3);
178 MOZ_STATIC_AND_RELEASE_ASSERT(Task2UnusedZeroEnumErr(true, 3).unwrapOr(6) ==
180 MOZ_STATIC_AND_RELEASE_ASSERT(Task2UnusedZeroEnumErr(false, 3).isErr());
181 MOZ_STATIC_AND_RELEASE_ASSERT(Task2UnusedZeroEnumErr(false, 3).unwrapOr(6) ==
184 // MOZ_TRY_VAR works.
185 MOZ_RELEASE_ASSERT(Task3(true, true, 3).isOk());
186 MOZ_RELEASE_ASSERT(Task3(true, true, 3).unwrap() == 6);
187 MOZ_RELEASE_ASSERT(Task3(true, false, 3).isErr());
188 MOZ_RELEASE_ASSERT(Task3(false, true, 3).isErr());
189 MOZ_RELEASE_ASSERT(Task3(false, true, 3).unwrapOr(6) == 6);
191 // Lvalues should work too.
193 constexpr Result<Ok, Failed> res1 = Task1(true);
194 MOZ_STATIC_AND_RELEASE_ASSERT(res1.isOk());
195 MOZ_STATIC_AND_RELEASE_ASSERT(!res1.isErr());
197 constexpr Result<Ok, Failed> res2 = Task1(false);
198 MOZ_STATIC_AND_RELEASE_ASSERT(!res2.isOk());
199 MOZ_STATIC_AND_RELEASE_ASSERT(res2.isErr());
203 Result<int, Failed> res = Task2(true, 3);
204 MOZ_RELEASE_ASSERT(res.isOk());
205 MOZ_RELEASE_ASSERT(res.unwrap() == 3);
207 res = Task2(false, 4);
208 MOZ_RELEASE_ASSERT(res.isErr());
211 // Some tests for pointer tagging.
213 int i = 123;
215 Result<int*, Failed> res = &i;
216 static_assert(sizeof(res) == sizeof(uintptr_t),
217 "should use pointer tagging to fit in a word");
219 MOZ_RELEASE_ASSERT(res.isOk());
220 MOZ_RELEASE_ASSERT(*res.unwrap() == 123);
222 res = Err(Failed());
223 MOZ_RELEASE_ASSERT(res.isErr());
227 struct NonCopyableNonMovable {
228 explicit constexpr NonCopyableNonMovable(uint32_t aValue) : mValue(aValue) {}
230 NonCopyableNonMovable(const NonCopyableNonMovable&) = delete;
231 NonCopyableNonMovable(NonCopyableNonMovable&&) = delete;
232 NonCopyableNonMovable& operator=(const NonCopyableNonMovable&) = delete;
233 NonCopyableNonMovable& operator=(NonCopyableNonMovable&&) = delete;
235 uint32_t mValue;
238 static void InPlaceConstructionTests() {
240 // PackingStrategy == NullIsOk
241 static_assert(mozilla::detail::SelectResultImpl<NonCopyableNonMovable,
242 Failed>::value ==
243 mozilla::detail::PackingStrategy::NullIsOk);
244 constexpr Result<NonCopyableNonMovable, Failed> result{std::in_place, 42u};
245 MOZ_STATIC_AND_RELEASE_ASSERT(42 == result.inspect().mValue);
249 // PackingStrategy == Variant
250 static_assert(
251 mozilla::detail::SelectResultImpl<NonCopyableNonMovable, int>::value ==
252 mozilla::detail::PackingStrategy::Variant);
253 const Result<NonCopyableNonMovable, int> result{std::in_place, 42};
254 MOZ_RELEASE_ASSERT(42 == result.inspect().mValue);
258 /* * */
260 struct Snafu : Failed {};
262 static Result<Ok, Snafu*> Explode() {
263 static Snafu snafu;
264 return Err(&snafu);
267 static Result<Ok, Failed*> ErrorGeneralization() {
268 MOZ_TRY(Explode()); // change error type from Snafu* to more general Failed*
269 return Ok();
272 static void TypeConversionTests() {
273 MOZ_RELEASE_ASSERT(ErrorGeneralization().isErr());
276 const Result<Ok, Failed*> res = Explode();
277 MOZ_RELEASE_ASSERT(res.isErr());
281 const Result<Ok, Failed*> res = Result<Ok, Snafu*>{Ok{}};
282 MOZ_RELEASE_ASSERT(res.isOk());
286 static void EmptyValueTest() {
287 struct Fine {};
288 mozilla::Result<Fine, Failed> res((Fine()));
289 res.unwrap();
290 MOZ_RELEASE_ASSERT(res.isOk());
291 static_assert(sizeof(res) == sizeof(uint8_t),
292 "Result with empty value and error types should be size 1");
295 static void MapTest() {
296 struct MyError {
297 int x;
299 explicit MyError(int y) : x(y) {}
302 // Mapping over success values, to the same success type.
304 Result<int, MyError> res(5);
305 bool invoked = false;
306 auto res2 = res.map([&invoked](int x) {
307 MOZ_RELEASE_ASSERT(x == 5);
308 invoked = true;
309 return 6;
311 MOZ_RELEASE_ASSERT(res2.isOk());
312 MOZ_RELEASE_ASSERT(invoked);
313 MOZ_RELEASE_ASSERT(res2.unwrap() == 6);
316 // Mapping over success values, to a different success type.
318 Result<int, MyError> res(5);
319 bool invoked = false;
320 auto res2 = res.map([&invoked](int x) {
321 MOZ_RELEASE_ASSERT(x == 5);
322 invoked = true;
323 return "hello";
325 MOZ_RELEASE_ASSERT(res2.isOk());
326 MOZ_RELEASE_ASSERT(invoked);
327 MOZ_RELEASE_ASSERT(strcmp(res2.unwrap(), "hello") == 0);
330 // Mapping over success values (constexpr).
332 constexpr uint64_t kValue = 42u;
333 constexpr auto res2a = Result<int32_t, Failed>{5}.map([](int32_t x) {
334 MOZ_RELEASE_ASSERT(x == 5);
335 return kValue;
337 MOZ_STATIC_AND_RELEASE_ASSERT(res2a.isOk());
338 MOZ_STATIC_AND_RELEASE_ASSERT(kValue == res2a.inspect());
341 // Mapping over error values.
343 MyError err(1);
344 Result<char, MyError> res(err);
345 MOZ_RELEASE_ASSERT(res.isErr());
346 Result<char, MyError> res2 = res.map([](int x) {
347 MOZ_RELEASE_ASSERT(false);
348 return 'a';
350 MOZ_RELEASE_ASSERT(res2.isErr());
351 MOZ_RELEASE_ASSERT(res2.unwrapErr().x == err.x);
354 // Function pointers instead of lambdas as the mapping function.
356 Result<const char*, MyError> res("hello");
357 auto res2 = res.map(strlen);
358 MOZ_RELEASE_ASSERT(res2.isOk());
359 MOZ_RELEASE_ASSERT(res2.unwrap() == 5);
363 static void MapErrTest() {
364 struct MyError {
365 int x;
367 explicit MyError(int y) : x(y) {}
370 struct MyError2 {
371 int a;
373 explicit MyError2(int b) : a(b) {}
376 // Mapping over error values, to the same error type.
378 MyError err(1);
379 Result<char, MyError> res(err);
380 MOZ_RELEASE_ASSERT(res.isErr());
381 bool invoked = false;
382 auto res2 = res.mapErr([&invoked](const auto err) {
383 MOZ_RELEASE_ASSERT(err.x == 1);
384 invoked = true;
385 return MyError(2);
387 MOZ_RELEASE_ASSERT(res2.isErr());
388 MOZ_RELEASE_ASSERT(invoked);
389 MOZ_RELEASE_ASSERT(res2.unwrapErr().x == 2);
392 // Mapping over error values, to a different error type.
394 MyError err(1);
395 Result<char, MyError> res(err);
396 MOZ_RELEASE_ASSERT(res.isErr());
397 bool invoked = false;
398 auto res2 = res.mapErr([&invoked](const auto err) {
399 MOZ_RELEASE_ASSERT(err.x == 1);
400 invoked = true;
401 return MyError2(2);
403 MOZ_RELEASE_ASSERT(res2.isErr());
404 MOZ_RELEASE_ASSERT(invoked);
405 MOZ_RELEASE_ASSERT(res2.unwrapErr().a == 2);
408 // Mapping over success values.
410 Result<int, MyError> res(5);
411 auto res2 = res.mapErr([](const auto err) {
412 MOZ_RELEASE_ASSERT(false);
413 return MyError(1);
415 MOZ_RELEASE_ASSERT(res2.isOk());
416 MOZ_RELEASE_ASSERT(res2.unwrap() == 5);
419 // Function pointers instead of lambdas as the mapping function.
421 Result<Ok, const char*> res("hello");
422 auto res2 = res.mapErr(strlen);
423 MOZ_RELEASE_ASSERT(res2.isErr());
424 MOZ_RELEASE_ASSERT(res2.unwrapErr() == 5);
428 static Result<Ok, size_t> strlen_ResultWrapper(const char* aValue) {
429 return Err(strlen(aValue));
432 static void OrElseTest() {
433 struct MyError {
434 int x;
436 explicit constexpr MyError(int y) : x(y) {}
439 struct MyError2 {
440 int a;
442 explicit constexpr MyError2(int b) : a(b) {}
445 // `orElse`ing over error values, to Result<V, E> (the same error type) error
446 // variant.
448 MyError err(1);
449 Result<char, MyError> res(err);
450 MOZ_RELEASE_ASSERT(res.isErr());
451 bool invoked = false;
452 auto res2 = res.orElse([&invoked](const auto err) -> Result<char, MyError> {
453 MOZ_RELEASE_ASSERT(err.x == 1);
454 invoked = true;
455 if (err.x != 42) {
456 return Err(MyError(2));
458 return 'a';
460 MOZ_RELEASE_ASSERT(res2.isErr());
461 MOZ_RELEASE_ASSERT(invoked);
462 MOZ_RELEASE_ASSERT(res2.unwrapErr().x == 2);
465 // `orElse`ing over error values, to Result<V, E> (the same error type)
466 // success variant.
468 MyError err(42);
469 Result<char, MyError> res(err);
470 MOZ_RELEASE_ASSERT(res.isErr());
471 bool invoked = false;
472 auto res2 = res.orElse([&invoked](const auto err) -> Result<char, MyError> {
473 MOZ_RELEASE_ASSERT(err.x == 42);
474 invoked = true;
475 if (err.x != 42) {
476 return Err(MyError(2));
478 return 'a';
480 MOZ_RELEASE_ASSERT(res2.isOk());
481 MOZ_RELEASE_ASSERT(invoked);
482 MOZ_RELEASE_ASSERT(res2.unwrap() == 'a');
485 // `orElse`ing over error values, to Result<V, E2> (a different error type)
486 // error variant.
488 MyError err(1);
489 Result<char, MyError> res(err);
490 MOZ_RELEASE_ASSERT(res.isErr());
491 bool invoked = false;
492 auto res2 =
493 res.orElse([&invoked](const auto err) -> Result<char, MyError2> {
494 MOZ_RELEASE_ASSERT(err.x == 1);
495 invoked = true;
496 if (err.x != 42) {
497 return Err(MyError2(2));
499 return 'a';
501 MOZ_RELEASE_ASSERT(res2.isErr());
502 MOZ_RELEASE_ASSERT(invoked);
503 MOZ_RELEASE_ASSERT(res2.unwrapErr().a == 2);
506 // `orElse`ing over error values, to Result<V, E2> (a different error type)
507 // success variant.
509 MyError err(42);
510 Result<char, MyError> res(err);
511 MOZ_RELEASE_ASSERT(res.isErr());
512 bool invoked = false;
513 auto res2 =
514 res.orElse([&invoked](const auto err) -> Result<char, MyError2> {
515 MOZ_RELEASE_ASSERT(err.x == 42);
516 invoked = true;
517 if (err.x != 42) {
518 return Err(MyError2(2));
520 return 'a';
522 MOZ_RELEASE_ASSERT(res2.isOk());
523 MOZ_RELEASE_ASSERT(invoked);
524 MOZ_RELEASE_ASSERT(res2.unwrap() == 'a');
527 // `orElse`ing over success values.
529 Result<int, MyError> res(5);
530 auto res2 = res.orElse([](const auto err) -> Result<int, MyError> {
531 MOZ_RELEASE_ASSERT(false);
532 return Err(MyError(1));
534 MOZ_RELEASE_ASSERT(res2.isOk());
535 MOZ_RELEASE_ASSERT(res2.unwrap() == 5);
538 // Function pointers instead of lambdas as the `orElse`ing function.
540 Result<Ok, const char*> res("hello");
541 auto res2 = res.orElse(strlen_ResultWrapper);
542 MOZ_RELEASE_ASSERT(res2.isErr());
543 MOZ_RELEASE_ASSERT(res2.unwrapErr() == 5);
547 static void AndThenTest() {
548 // `andThen`ing over success results.
550 Result<int, const char*> r1(10);
551 Result<int, const char*> r2 =
552 r1.andThen([](int x) { return Result<int, const char*>(x + 1); });
553 MOZ_RELEASE_ASSERT(r2.isOk());
554 MOZ_RELEASE_ASSERT(r2.unwrap() == 11);
557 // `andThen`ing over success results (constexpr).
559 constexpr Result<int, Failed> r2a = Result<int, Failed>{10}.andThen(
560 [](int x) { return Result<int, Failed>(x + 1); });
561 MOZ_STATIC_AND_RELEASE_ASSERT(r2a.isOk());
562 MOZ_STATIC_AND_RELEASE_ASSERT(r2a.inspect() == 11);
565 // `andThen`ing over error results.
567 Result<int, const char*> r3("error");
568 Result<int, const char*> r4 = r3.andThen([](int x) {
569 MOZ_RELEASE_ASSERT(false);
570 return Result<int, const char*>(1);
572 MOZ_RELEASE_ASSERT(r4.isErr());
573 MOZ_RELEASE_ASSERT(r3.unwrapErr() == r4.unwrapErr());
576 // andThen with a function accepting an rvalue
578 Result<int, const char*> r1(10);
579 Result<int, const char*> r2 =
580 r1.andThen([](int&& x) { return Result<int, const char*>(x + 1); });
581 MOZ_RELEASE_ASSERT(r2.isOk());
582 MOZ_RELEASE_ASSERT(r2.unwrap() == 11);
585 // `andThen`ing over error results (constexpr).
587 constexpr Result<int, Failed> r4a =
588 Result<int, Failed>{Failed{}}.andThen([](int x) {
589 MOZ_RELEASE_ASSERT(false);
590 return Result<int, Failed>(1);
592 MOZ_STATIC_AND_RELEASE_ASSERT(r4a.isErr());
596 using UniqueResult = Result<UniquePtr<int>, const char*>;
598 static UniqueResult UniqueTask() { return mozilla::MakeUnique<int>(3); }
599 static UniqueResult UniqueTaskError() { return Err("bad"); }
601 using UniqueErrorResult = Result<int, UniquePtr<int>>;
602 static UniqueErrorResult UniqueError() {
603 return Err(mozilla::MakeUnique<int>(4));
606 static Result<Ok, UniquePtr<int>> TryUniqueErrorResult() {
607 MOZ_TRY(UniqueError());
608 return Ok();
611 static void UniquePtrTest() {
613 auto result = UniqueTask();
614 MOZ_RELEASE_ASSERT(result.isOk());
615 auto ptr = result.unwrap();
616 MOZ_RELEASE_ASSERT(ptr);
617 MOZ_RELEASE_ASSERT(*ptr == 3);
618 auto moved = result.unwrap();
619 MOZ_RELEASE_ASSERT(!moved);
623 auto err = UniqueTaskError();
624 MOZ_RELEASE_ASSERT(err.isErr());
625 auto ptr = err.unwrapOr(mozilla::MakeUnique<int>(4));
626 MOZ_RELEASE_ASSERT(ptr);
627 MOZ_RELEASE_ASSERT(*ptr == 4);
631 auto result = UniqueTaskError();
632 result = UniqueResult(mozilla::MakeUnique<int>(6));
633 MOZ_RELEASE_ASSERT(result.isOk());
634 MOZ_RELEASE_ASSERT(result.inspect() && *result.inspect() == 6);
638 auto result = UniqueError();
639 MOZ_RELEASE_ASSERT(result.isErr());
640 MOZ_RELEASE_ASSERT(result.inspectErr());
641 MOZ_RELEASE_ASSERT(*result.inspectErr() == 4);
642 auto err = result.unwrapErr();
643 MOZ_RELEASE_ASSERT(!result.inspectErr());
644 MOZ_RELEASE_ASSERT(err);
645 MOZ_RELEASE_ASSERT(*err == 4);
647 result = UniqueErrorResult(0);
648 MOZ_RELEASE_ASSERT(result.isOk() && result.unwrap() == 0);
652 auto result = TryUniqueErrorResult();
653 MOZ_RELEASE_ASSERT(result.isErr());
654 auto err = result.unwrapErr();
655 MOZ_RELEASE_ASSERT(err && *err == 4);
656 MOZ_RELEASE_ASSERT(!result.inspectErr());
660 struct ZeroIsUnusedStructForPointer {
661 int x = 1;
663 enum class ZeroIsUnusedEnum1 : uint8_t {
664 V1 = 1,
665 V2 = 2,
667 enum class ZeroIsUnusedEnum2 : uint16_t {
668 V1 = 1,
669 V2 = 2,
671 enum class ZeroIsUnusedEnum4 : uint32_t {
672 V1 = 1,
673 V2 = 2,
675 enum class ZeroIsUnusedEnum8 : uint64_t {
676 V1 = 1,
677 V2 = 2,
679 struct EmptyErrorStruct {};
681 template <>
682 struct mozilla::detail::UnusedZero<ZeroIsUnusedStructForPointer*> {
683 static const bool value = true;
685 template <>
686 struct mozilla::detail::UnusedZero<ZeroIsUnusedEnum1> {
687 static const bool value = true;
689 template <>
690 struct mozilla::detail::UnusedZero<ZeroIsUnusedEnum2> {
691 static const bool value = true;
693 template <>
694 struct mozilla::detail::UnusedZero<ZeroIsUnusedEnum4> {
695 static const bool value = true;
697 template <>
698 struct mozilla::detail::UnusedZero<ZeroIsUnusedEnum8> {
699 static const bool value = true;
702 static void ZeroIsEmptyErrorTest() {
704 ZeroIsUnusedStructForPointer s;
706 using V = ZeroIsUnusedStructForPointer*;
708 mozilla::Result<V, EmptyErrorStruct> result(&s);
709 MOZ_RELEASE_ASSERT(sizeof(result) == sizeof(V));
711 MOZ_RELEASE_ASSERT(result.isOk());
712 MOZ_RELEASE_ASSERT(result.inspect() == &s);
716 using V = ZeroIsUnusedStructForPointer*;
718 mozilla::Result<V, EmptyErrorStruct> result(Err(EmptyErrorStruct{}));
720 MOZ_RELEASE_ASSERT(result.isErr());
721 MOZ_RELEASE_ASSERT(*reinterpret_cast<V*>(&result) == nullptr);
725 ZeroIsUnusedEnum1 e = ZeroIsUnusedEnum1::V1;
727 using V = ZeroIsUnusedEnum1;
729 mozilla::Result<V, EmptyErrorStruct> result(e);
730 MOZ_RELEASE_ASSERT(sizeof(result) == sizeof(V));
732 MOZ_RELEASE_ASSERT(result.isOk());
733 MOZ_RELEASE_ASSERT(result.inspect() == e);
737 using V = ZeroIsUnusedEnum1;
739 mozilla::Result<V, EmptyErrorStruct> result(Err(EmptyErrorStruct()));
741 MOZ_RELEASE_ASSERT(result.isErr());
742 MOZ_RELEASE_ASSERT(*reinterpret_cast<uint8_t*>(&result) == 0);
746 ZeroIsUnusedEnum2 e = ZeroIsUnusedEnum2::V1;
748 using V = ZeroIsUnusedEnum2;
750 mozilla::Result<V, EmptyErrorStruct> result(e);
751 MOZ_RELEASE_ASSERT(sizeof(result) == sizeof(V));
753 MOZ_RELEASE_ASSERT(result.isOk());
754 MOZ_RELEASE_ASSERT(result.inspect() == e);
758 using V = ZeroIsUnusedEnum2;
760 mozilla::Result<V, EmptyErrorStruct> result(Err(EmptyErrorStruct()));
762 MOZ_RELEASE_ASSERT(result.isErr());
763 MOZ_RELEASE_ASSERT(*reinterpret_cast<uint16_t*>(&result) == 0);
767 ZeroIsUnusedEnum4 e = ZeroIsUnusedEnum4::V1;
769 using V = ZeroIsUnusedEnum4;
771 mozilla::Result<V, EmptyErrorStruct> result(e);
772 MOZ_RELEASE_ASSERT(sizeof(result) == sizeof(V));
774 MOZ_RELEASE_ASSERT(result.isOk());
775 MOZ_RELEASE_ASSERT(result.inspect() == e);
779 using V = ZeroIsUnusedEnum4;
781 mozilla::Result<V, EmptyErrorStruct> result(Err(EmptyErrorStruct()));
783 MOZ_RELEASE_ASSERT(result.isErr());
784 MOZ_RELEASE_ASSERT(*reinterpret_cast<uint32_t*>(&result) == 0);
788 ZeroIsUnusedEnum8 e = ZeroIsUnusedEnum8::V1;
790 using V = ZeroIsUnusedEnum8;
792 mozilla::Result<V, EmptyErrorStruct> result(e);
793 MOZ_RELEASE_ASSERT(sizeof(result) == sizeof(V));
795 MOZ_RELEASE_ASSERT(result.isOk());
796 MOZ_RELEASE_ASSERT(result.inspect() == e);
800 using V = ZeroIsUnusedEnum8;
802 mozilla::Result<V, EmptyErrorStruct> result(Err(EmptyErrorStruct()));
804 MOZ_RELEASE_ASSERT(result.isErr());
805 MOZ_RELEASE_ASSERT(*reinterpret_cast<uint64_t*>(&result) == 0);
809 class Foo {};
811 class C1 {};
812 class C2 : public C1 {};
814 class E1 {};
815 class E2 : public E1 {};
817 void UpcastTest() {
819 C2 c2;
821 mozilla::Result<C2*, Failed> result(&c2);
822 mozilla::Result<C1*, Failed> copied(std::move(result));
824 MOZ_RELEASE_ASSERT(copied.inspect() == &c2);
828 E2 e2;
830 mozilla::Result<Foo, E2*> result(Err(&e2));
831 mozilla::Result<Foo, E1*> copied(std::move(result));
833 MOZ_RELEASE_ASSERT(copied.inspectErr() == &e2);
837 C2 c2;
839 mozilla::Result<C2*, E2*> result(&c2);
840 mozilla::Result<C1*, E1*> copied(std::move(result));
842 MOZ_RELEASE_ASSERT(copied.inspect() == &c2);
846 E2 e2;
848 mozilla::Result<C2*, E2*> result(Err(&e2));
849 mozilla::Result<C1*, E1*> copied(std::move(result));
851 MOZ_RELEASE_ASSERT(copied.inspectErr() == &e2);
855 /* * */
857 int main() {
858 BasicTests();
859 InPlaceConstructionTests();
860 TypeConversionTests();
861 EmptyValueTest();
862 MapTest();
863 MapErrTest();
864 OrElseTest();
865 AndThenTest();
866 UniquePtrTest();
867 ZeroIsEmptyErrorTest();
868 UpcastTest();
869 return 0;