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/ResultVariant.h"
9 #include "mozilla/UniquePtr.h"
12 using mozilla::GenericErrorResult
;
14 using mozilla::Result
;
15 using mozilla::UniquePtr
;
17 #define MOZ_STATIC_AND_RELEASE_ASSERT(expr) \
18 static_assert(expr); \
19 MOZ_RELEASE_ASSERT(expr)
21 enum struct TestUnusedZeroEnum
: int16_t { Ok
= 0, NotOk
= 1 };
23 namespace mozilla::detail
{
25 struct UnusedZero
<TestUnusedZeroEnum
> : UnusedZeroEnum
<TestUnusedZeroEnum
> {};
26 } // namespace mozilla::detail
30 namespace mozilla::detail
{
32 struct UnusedZero
<Failed
> {
33 using StorageType
= uintptr_t;
35 static constexpr bool value
= true;
36 static constexpr StorageType nullValue
= 0;
37 static constexpr StorageType
GetDefaultValue() { return 2; }
39 static constexpr void AssertValid(StorageType aValue
) {}
40 static constexpr Failed
Inspect(const StorageType
& aValue
) {
43 static constexpr Failed
Unwrap(StorageType aValue
) { return Failed
{}; }
44 static constexpr StorageType
Store(Failed aValue
) {
45 return GetDefaultValue();
49 } // namespace mozilla::detail
51 // V is trivially default-constructible, and E has UnusedZero<E>::value == true,
52 // for a reference type and for a non-reference type
53 static_assert(mozilla::detail::SelectResultImpl
<uintptr_t, Failed
>::value
==
54 mozilla::detail::PackingStrategy::NullIsOk
);
56 mozilla::detail::SelectResultImpl
<Ok
, TestUnusedZeroEnum
>::value
==
57 mozilla::detail::PackingStrategy::NullIsOk
);
58 static_assert(mozilla::detail::SelectResultImpl
<Ok
, Failed
>::value
==
59 mozilla::detail::PackingStrategy::LowBitTagIsError
);
61 static_assert(std::is_trivially_destructible_v
<Result
<uintptr_t, Failed
>>);
62 static_assert(std::is_trivially_destructible_v
<Result
<Ok
, TestUnusedZeroEnum
>>);
63 static_assert(std::is_trivially_destructible_v
<Result
<Ok
, Failed
>>);
66 sizeof(Result
<bool, TestUnusedZeroEnum
>) <= sizeof(uintptr_t),
67 "Result with bool value type should not be larger than pointer-sized");
68 static_assert(sizeof(Result
<Ok
, Failed
>) == sizeof(uint8_t),
69 "Result with empty value type should be size 1");
70 static_assert(sizeof(Result
<int*, Failed
>) == sizeof(uintptr_t),
71 "Result with two aligned pointer types should be pointer-sized");
73 sizeof(Result
<char*, Failed
*>) > sizeof(char*),
74 "Result with unaligned success type `char*` must not be pointer-sized");
76 sizeof(Result
<int*, char*>) > sizeof(char*),
77 "Result with unaligned error type `char*` must not be pointer-sized");
79 enum Foo8
: uint8_t {};
80 enum Foo16
: uint16_t {};
81 enum Foo32
: uint32_t {};
82 static_assert(sizeof(Result
<Ok
, Foo8
>) <= sizeof(uintptr_t),
83 "Result with small types should be pointer-sized");
84 static_assert(sizeof(Result
<Ok
, Foo16
>) <= sizeof(uintptr_t),
85 "Result with small types should be pointer-sized");
86 static_assert(sizeof(Foo32
) >= sizeof(uintptr_t) ||
87 sizeof(Result
<Ok
, Foo32
>) <= sizeof(uintptr_t),
88 "Result with small types should be pointer-sized");
90 static_assert(sizeof(Result
<Foo16
, Foo8
>) <= sizeof(uintptr_t),
91 "Result with small types should be pointer-sized");
92 static_assert(sizeof(Result
<Foo8
, Foo16
>) <= sizeof(uintptr_t),
93 "Result with small types should be pointer-sized");
94 static_assert(sizeof(Foo32
) >= sizeof(uintptr_t) ||
95 sizeof(Result
<Foo32
, Foo16
>) <= sizeof(uintptr_t),
96 "Result with small types should be pointer-sized");
97 static_assert(sizeof(Foo32
) >= sizeof(uintptr_t) ||
98 sizeof(Result
<Foo16
, Foo32
>) <= sizeof(uintptr_t),
99 "Result with small types should be pointer-sized");
101 static_assert(std::is_literal_type_v
<Result
<int*, Failed
>>);
102 static_assert(std::is_literal_type_v
<Result
<Ok
, Failed
>>);
103 static_assert(std::is_literal_type_v
<Result
<Ok
, Foo8
>>);
104 static_assert(std::is_literal_type_v
<Result
<Foo8
, Foo16
>>);
105 static_assert(!std::is_literal_type_v
<Result
<Ok
, UniquePtr
<int>>>);
107 static constexpr GenericErrorResult
<Failed
> Fail() { return Err(Failed
{}); }
109 static constexpr GenericErrorResult
<TestUnusedZeroEnum
>
110 FailTestUnusedZeroEnum() {
111 return Err(TestUnusedZeroEnum::NotOk
);
114 static constexpr Result
<Ok
, Failed
> Task1(bool pass
) {
116 return Fail(); // implicit conversion from GenericErrorResult to Result
121 static constexpr Result
<Ok
, TestUnusedZeroEnum
> Task1UnusedZeroEnumErr(
124 return FailTestUnusedZeroEnum(); // implicit conversion from
125 // GenericErrorResult to Result
130 static constexpr Result
<int, Failed
> Task2(bool pass
, int value
) {
132 Task1(pass
)); // converts one type of result to another in the error case
133 return value
; // implicit conversion from T to Result<T, E>
136 static constexpr Result
<int, TestUnusedZeroEnum
> Task2UnusedZeroEnumErr(
137 bool pass
, int value
) {
138 MOZ_TRY(Task1UnusedZeroEnumErr(
139 pass
)); // converts one type of result to another in the error case
140 return value
; // implicit conversion from T to Result<T, E>
143 static Result
<int, Failed
> Task3(bool pass1
, bool pass2
, int value
) {
145 MOZ_TRY_VAR(x
, Task2(pass1
, value
));
146 MOZ_TRY_VAR(y
, Task2(pass2
, value
));
150 static void BasicTests() {
151 MOZ_STATIC_AND_RELEASE_ASSERT(Task1(true).isOk());
152 MOZ_STATIC_AND_RELEASE_ASSERT(!Task1(true).isErr());
153 MOZ_STATIC_AND_RELEASE_ASSERT(!Task1(false).isOk());
154 MOZ_STATIC_AND_RELEASE_ASSERT(Task1(false).isErr());
156 MOZ_STATIC_AND_RELEASE_ASSERT(Task1UnusedZeroEnumErr(true).isOk());
157 MOZ_STATIC_AND_RELEASE_ASSERT(!Task1UnusedZeroEnumErr(true).isErr());
158 MOZ_STATIC_AND_RELEASE_ASSERT(!Task1UnusedZeroEnumErr(false).isOk());
159 MOZ_STATIC_AND_RELEASE_ASSERT(Task1UnusedZeroEnumErr(false).isErr());
160 MOZ_STATIC_AND_RELEASE_ASSERT(TestUnusedZeroEnum::NotOk
==
161 Task1UnusedZeroEnumErr(false).inspectErr());
162 MOZ_STATIC_AND_RELEASE_ASSERT(TestUnusedZeroEnum::NotOk
==
163 Task1UnusedZeroEnumErr(false).unwrapErr());
166 MOZ_STATIC_AND_RELEASE_ASSERT(Task2(true, 3).isOk());
167 MOZ_STATIC_AND_RELEASE_ASSERT(Task2(true, 3).unwrap() == 3);
168 MOZ_STATIC_AND_RELEASE_ASSERT(Task2(true, 3).unwrapOr(6) == 3);
169 MOZ_RELEASE_ASSERT(Task2(false, 3).isErr());
170 MOZ_RELEASE_ASSERT(Task2(false, 3).unwrapOr(6) == 6);
172 MOZ_STATIC_AND_RELEASE_ASSERT(Task2UnusedZeroEnumErr(true, 3).isOk());
173 MOZ_STATIC_AND_RELEASE_ASSERT(Task2UnusedZeroEnumErr(true, 3).unwrap() == 3);
174 MOZ_STATIC_AND_RELEASE_ASSERT(Task2UnusedZeroEnumErr(true, 3).unwrapOr(6) ==
176 MOZ_STATIC_AND_RELEASE_ASSERT(Task2UnusedZeroEnumErr(false, 3).isErr());
177 MOZ_STATIC_AND_RELEASE_ASSERT(Task2UnusedZeroEnumErr(false, 3).unwrapOr(6) ==
180 // MOZ_TRY_VAR works.
181 MOZ_RELEASE_ASSERT(Task3(true, true, 3).isOk());
182 MOZ_RELEASE_ASSERT(Task3(true, true, 3).unwrap() == 6);
183 MOZ_RELEASE_ASSERT(Task3(true, false, 3).isErr());
184 MOZ_RELEASE_ASSERT(Task3(false, true, 3).isErr());
185 MOZ_RELEASE_ASSERT(Task3(false, true, 3).unwrapOr(6) == 6);
187 // Lvalues should work too.
189 constexpr Result
<Ok
, Failed
> res1
= Task1(true);
190 MOZ_STATIC_AND_RELEASE_ASSERT(res1
.isOk());
191 MOZ_STATIC_AND_RELEASE_ASSERT(!res1
.isErr());
193 constexpr Result
<Ok
, Failed
> res2
= Task1(false);
194 MOZ_STATIC_AND_RELEASE_ASSERT(!res2
.isOk());
195 MOZ_STATIC_AND_RELEASE_ASSERT(res2
.isErr());
199 Result
<int, Failed
> res
= Task2(true, 3);
200 MOZ_RELEASE_ASSERT(res
.isOk());
201 MOZ_RELEASE_ASSERT(res
.unwrap() == 3);
203 res
= Task2(false, 4);
204 MOZ_RELEASE_ASSERT(res
.isErr());
207 // Some tests for pointer tagging.
211 Result
<int*, Failed
> res
= &i
;
212 static_assert(sizeof(res
) == sizeof(uintptr_t),
213 "should use pointer tagging to fit in a word");
215 MOZ_RELEASE_ASSERT(res
.isOk());
216 MOZ_RELEASE_ASSERT(*res
.unwrap() == 123);
219 MOZ_RELEASE_ASSERT(res
.isErr());
223 struct NonCopyableNonMovable
{
224 explicit constexpr NonCopyableNonMovable(uint32_t aValue
) : mValue(aValue
) {}
226 NonCopyableNonMovable(const NonCopyableNonMovable
&) = delete;
227 NonCopyableNonMovable(NonCopyableNonMovable
&&) = delete;
228 NonCopyableNonMovable
& operator=(const NonCopyableNonMovable
&) = delete;
229 NonCopyableNonMovable
& operator=(NonCopyableNonMovable
&&) = delete;
234 static void InPlaceConstructionTests() {
236 // PackingStrategy == NullIsOk
237 static_assert(mozilla::detail::SelectResultImpl
<NonCopyableNonMovable
,
239 mozilla::detail::PackingStrategy::NullIsOk
);
240 constexpr Result
<NonCopyableNonMovable
, Failed
> result
{std::in_place
, 42u};
241 MOZ_STATIC_AND_RELEASE_ASSERT(42 == result
.inspect().mValue
);
245 // PackingStrategy == Variant
247 mozilla::detail::SelectResultImpl
<NonCopyableNonMovable
, int>::value
==
248 mozilla::detail::PackingStrategy::Variant
);
249 const Result
<NonCopyableNonMovable
, int> result
{std::in_place
, 42};
250 MOZ_RELEASE_ASSERT(42 == result
.inspect().mValue
);
256 struct Snafu
: Failed
{};
258 static Result
<Ok
, Snafu
*> Explode() {
263 static Result
<Ok
, Failed
*> ErrorGeneralization() {
264 MOZ_TRY(Explode()); // change error type from Snafu* to more general Failed*
268 static void TypeConversionTests() {
269 MOZ_RELEASE_ASSERT(ErrorGeneralization().isErr());
272 const Result
<Ok
, Failed
*> res
= Explode();
273 MOZ_RELEASE_ASSERT(res
.isErr());
277 const Result
<Ok
, Failed
*> res
= Result
<Ok
, Snafu
*>{Ok
{}};
278 MOZ_RELEASE_ASSERT(res
.isOk());
282 static void EmptyValueTest() {
284 mozilla::Result
<Fine
, Failed
> res((Fine()));
286 MOZ_RELEASE_ASSERT(res
.isOk());
287 static_assert(sizeof(res
) == sizeof(uint8_t),
288 "Result with empty value and error types should be size 1");
291 static void MapTest() {
295 explicit MyError(int y
) : x(y
) {}
298 // Mapping over success values, to the same success type.
300 Result
<int, MyError
> res(5);
301 bool invoked
= false;
302 auto res2
= res
.map([&invoked
](int x
) {
303 MOZ_RELEASE_ASSERT(x
== 5);
307 MOZ_RELEASE_ASSERT(res2
.isOk());
308 MOZ_RELEASE_ASSERT(invoked
);
309 MOZ_RELEASE_ASSERT(res2
.unwrap() == 6);
312 // Mapping over success values, to a different success type.
314 Result
<int, MyError
> res(5);
315 bool invoked
= false;
316 auto res2
= res
.map([&invoked
](int x
) {
317 MOZ_RELEASE_ASSERT(x
== 5);
321 MOZ_RELEASE_ASSERT(res2
.isOk());
322 MOZ_RELEASE_ASSERT(invoked
);
323 MOZ_RELEASE_ASSERT(strcmp(res2
.unwrap(), "hello") == 0);
326 // Mapping over success values (constexpr).
328 constexpr uint64_t kValue
= 42u;
329 constexpr auto res2a
= Result
<int32_t, Failed
>{5}.map([](int32_t x
) {
330 MOZ_RELEASE_ASSERT(x
== 5);
333 MOZ_STATIC_AND_RELEASE_ASSERT(res2a
.isOk());
334 MOZ_STATIC_AND_RELEASE_ASSERT(kValue
== res2a
.inspect());
337 // Mapping over error values.
340 Result
<char, MyError
> res(err
);
341 MOZ_RELEASE_ASSERT(res
.isErr());
342 Result
<char, MyError
> res2
= res
.map([](int x
) {
343 MOZ_RELEASE_ASSERT(false);
346 MOZ_RELEASE_ASSERT(res2
.isErr());
347 MOZ_RELEASE_ASSERT(res2
.unwrapErr().x
== err
.x
);
350 // Function pointers instead of lambdas as the mapping function.
352 Result
<const char*, MyError
> res("hello");
353 auto res2
= res
.map(strlen
);
354 MOZ_RELEASE_ASSERT(res2
.isOk());
355 MOZ_RELEASE_ASSERT(res2
.unwrap() == 5);
359 static void MapErrTest() {
363 explicit MyError(int y
) : x(y
) {}
369 explicit MyError2(int b
) : a(b
) {}
372 // Mapping over error values, to the same error type.
375 Result
<char, MyError
> res(err
);
376 MOZ_RELEASE_ASSERT(res
.isErr());
377 bool invoked
= false;
378 auto res2
= res
.mapErr([&invoked
](const auto err
) {
379 MOZ_RELEASE_ASSERT(err
.x
== 1);
383 MOZ_RELEASE_ASSERT(res2
.isErr());
384 MOZ_RELEASE_ASSERT(invoked
);
385 MOZ_RELEASE_ASSERT(res2
.unwrapErr().x
== 2);
388 // Mapping over error values, to a different error type.
391 Result
<char, MyError
> res(err
);
392 MOZ_RELEASE_ASSERT(res
.isErr());
393 bool invoked
= false;
394 auto res2
= res
.mapErr([&invoked
](const auto err
) {
395 MOZ_RELEASE_ASSERT(err
.x
== 1);
399 MOZ_RELEASE_ASSERT(res2
.isErr());
400 MOZ_RELEASE_ASSERT(invoked
);
401 MOZ_RELEASE_ASSERT(res2
.unwrapErr().a
== 2);
404 // Mapping over success values.
406 Result
<int, MyError
> res(5);
407 auto res2
= res
.mapErr([](const auto err
) {
408 MOZ_RELEASE_ASSERT(false);
411 MOZ_RELEASE_ASSERT(res2
.isOk());
412 MOZ_RELEASE_ASSERT(res2
.unwrap() == 5);
415 // Function pointers instead of lambdas as the mapping function.
417 Result
<Ok
, const char*> res("hello");
418 auto res2
= res
.mapErr(strlen
);
419 MOZ_RELEASE_ASSERT(res2
.isErr());
420 MOZ_RELEASE_ASSERT(res2
.unwrapErr() == 5);
424 static Result
<Ok
, size_t> strlen_ResultWrapper(const char* aValue
) {
425 return Err(strlen(aValue
));
428 static void OrElseTest() {
432 explicit constexpr MyError(int y
) : x(y
) {}
438 explicit constexpr MyError2(int b
) : a(b
) {}
441 // `orElse`ing over error values, to Result<V, E> (the same error type) error
445 Result
<char, MyError
> res(err
);
446 MOZ_RELEASE_ASSERT(res
.isErr());
447 bool invoked
= false;
448 auto res2
= res
.orElse([&invoked
](const auto err
) -> Result
<char, MyError
> {
449 MOZ_RELEASE_ASSERT(err
.x
== 1);
452 return Err(MyError(2));
456 MOZ_RELEASE_ASSERT(res2
.isErr());
457 MOZ_RELEASE_ASSERT(invoked
);
458 MOZ_RELEASE_ASSERT(res2
.unwrapErr().x
== 2);
461 // `orElse`ing over error values, to Result<V, E> (the same error type)
465 Result
<char, MyError
> res(err
);
466 MOZ_RELEASE_ASSERT(res
.isErr());
467 bool invoked
= false;
468 auto res2
= res
.orElse([&invoked
](const auto err
) -> Result
<char, MyError
> {
469 MOZ_RELEASE_ASSERT(err
.x
== 42);
472 return Err(MyError(2));
476 MOZ_RELEASE_ASSERT(res2
.isOk());
477 MOZ_RELEASE_ASSERT(invoked
);
478 MOZ_RELEASE_ASSERT(res2
.unwrap() == 'a');
481 // `orElse`ing over error values, to Result<V, E2> (a different error type)
485 Result
<char, MyError
> res(err
);
486 MOZ_RELEASE_ASSERT(res
.isErr());
487 bool invoked
= false;
489 res
.orElse([&invoked
](const auto err
) -> Result
<char, MyError2
> {
490 MOZ_RELEASE_ASSERT(err
.x
== 1);
493 return Err(MyError2(2));
497 MOZ_RELEASE_ASSERT(res2
.isErr());
498 MOZ_RELEASE_ASSERT(invoked
);
499 MOZ_RELEASE_ASSERT(res2
.unwrapErr().a
== 2);
502 // `orElse`ing over error values, to Result<V, E2> (a different error type)
506 Result
<char, MyError
> res(err
);
507 MOZ_RELEASE_ASSERT(res
.isErr());
508 bool invoked
= false;
510 res
.orElse([&invoked
](const auto err
) -> Result
<char, MyError2
> {
511 MOZ_RELEASE_ASSERT(err
.x
== 42);
514 return Err(MyError2(2));
518 MOZ_RELEASE_ASSERT(res2
.isOk());
519 MOZ_RELEASE_ASSERT(invoked
);
520 MOZ_RELEASE_ASSERT(res2
.unwrap() == 'a');
523 // `orElse`ing over success values.
525 Result
<int, MyError
> res(5);
526 auto res2
= res
.orElse([](const auto err
) -> Result
<int, MyError
> {
527 MOZ_RELEASE_ASSERT(false);
528 return Err(MyError(1));
530 MOZ_RELEASE_ASSERT(res2
.isOk());
531 MOZ_RELEASE_ASSERT(res2
.unwrap() == 5);
534 // Function pointers instead of lambdas as the `orElse`ing function.
536 Result
<Ok
, const char*> res("hello");
537 auto res2
= res
.orElse(strlen_ResultWrapper
);
538 MOZ_RELEASE_ASSERT(res2
.isErr());
539 MOZ_RELEASE_ASSERT(res2
.unwrapErr() == 5);
543 static void AndThenTest() {
544 // `andThen`ing over success results.
546 Result
<int, const char*> r1(10);
547 Result
<int, const char*> r2
=
548 r1
.andThen([](int x
) { return Result
<int, const char*>(x
+ 1); });
549 MOZ_RELEASE_ASSERT(r2
.isOk());
550 MOZ_RELEASE_ASSERT(r2
.unwrap() == 11);
553 // `andThen`ing over success results (constexpr).
555 constexpr Result
<int, Failed
> r2a
= Result
<int, Failed
>{10}.andThen(
556 [](int x
) { return Result
<int, Failed
>(x
+ 1); });
557 MOZ_STATIC_AND_RELEASE_ASSERT(r2a
.isOk());
558 MOZ_STATIC_AND_RELEASE_ASSERT(r2a
.inspect() == 11);
561 // `andThen`ing over error results.
563 Result
<int, const char*> r3("error");
564 Result
<int, const char*> r4
= r3
.andThen([](int x
) {
565 MOZ_RELEASE_ASSERT(false);
566 return Result
<int, const char*>(1);
568 MOZ_RELEASE_ASSERT(r4
.isErr());
569 MOZ_RELEASE_ASSERT(r3
.unwrapErr() == r4
.unwrapErr());
572 // andThen with a function accepting an rvalue
574 Result
<int, const char*> r1(10);
575 Result
<int, const char*> r2
=
576 r1
.andThen([](int&& x
) { return Result
<int, const char*>(x
+ 1); });
577 MOZ_RELEASE_ASSERT(r2
.isOk());
578 MOZ_RELEASE_ASSERT(r2
.unwrap() == 11);
581 // `andThen`ing over error results (constexpr).
583 constexpr Result
<int, Failed
> r4a
=
584 Result
<int, Failed
>{Failed
{}}.andThen([](int x
) {
585 MOZ_RELEASE_ASSERT(false);
586 return Result
<int, Failed
>(1);
588 MOZ_STATIC_AND_RELEASE_ASSERT(r4a
.isErr());
592 using UniqueResult
= Result
<UniquePtr
<int>, const char*>;
594 static UniqueResult
UniqueTask() { return mozilla::MakeUnique
<int>(3); }
595 static UniqueResult
UniqueTaskError() { return Err("bad"); }
597 using UniqueErrorResult
= Result
<int, UniquePtr
<int>>;
598 static UniqueErrorResult
UniqueError() {
599 return Err(mozilla::MakeUnique
<int>(4));
602 static Result
<Ok
, UniquePtr
<int>> TryUniqueErrorResult() {
603 MOZ_TRY(UniqueError());
607 static void UniquePtrTest() {
609 auto result
= UniqueTask();
610 MOZ_RELEASE_ASSERT(result
.isOk());
611 auto ptr
= result
.unwrap();
612 MOZ_RELEASE_ASSERT(ptr
);
613 MOZ_RELEASE_ASSERT(*ptr
== 3);
614 auto moved
= result
.unwrap();
615 MOZ_RELEASE_ASSERT(!moved
);
619 auto err
= UniqueTaskError();
620 MOZ_RELEASE_ASSERT(err
.isErr());
621 auto ptr
= err
.unwrapOr(mozilla::MakeUnique
<int>(4));
622 MOZ_RELEASE_ASSERT(ptr
);
623 MOZ_RELEASE_ASSERT(*ptr
== 4);
627 auto result
= UniqueTaskError();
628 result
= UniqueResult(mozilla::MakeUnique
<int>(6));
629 MOZ_RELEASE_ASSERT(result
.isOk());
630 MOZ_RELEASE_ASSERT(result
.inspect() && *result
.inspect() == 6);
634 auto result
= UniqueError();
635 MOZ_RELEASE_ASSERT(result
.isErr());
636 MOZ_RELEASE_ASSERT(result
.inspectErr());
637 MOZ_RELEASE_ASSERT(*result
.inspectErr() == 4);
638 auto err
= result
.unwrapErr();
639 MOZ_RELEASE_ASSERT(!result
.inspectErr());
640 MOZ_RELEASE_ASSERT(err
);
641 MOZ_RELEASE_ASSERT(*err
== 4);
643 result
= UniqueErrorResult(0);
644 MOZ_RELEASE_ASSERT(result
.isOk() && result
.unwrap() == 0);
648 auto result
= TryUniqueErrorResult();
649 MOZ_RELEASE_ASSERT(result
.isErr());
650 auto err
= result
.unwrapErr();
651 MOZ_RELEASE_ASSERT(err
&& *err
== 4);
652 MOZ_RELEASE_ASSERT(!result
.inspectErr());
660 InPlaceConstructionTests();
661 TypeConversionTests();