1/*
2 * Copyright 2016-present Facebook, Inc.
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 <folly/Expected.h>
18#include <folly/Portability.h>
19#include <folly/portability/GTest.h>
20
21#include <algorithm>
22#include <iomanip>
23#include <memory>
24#include <string>
25#include <type_traits>
26#include <vector>
27
28#include <glog/logging.h>
29
30using std::shared_ptr;
31using std::unique_ptr;
32
33namespace folly {
34
35enum class E { E1, E2 };
36
37std::ostream& operator<<(std::ostream& os, E e) {
38 switch (e) {
39 case E::E1:
40 return os << "E::E1";
41 case E::E2:
42 return os << "E::E2";
43 default:;
44 }
45 return os;
46}
47
48template <class V, class E>
49std::ostream& operator<<(std::ostream& os, const Expected<V, E>& e) {
50 if (e) {
51 os << "Expected(" << e.value() << ')';
52 } else {
53 os << "Unexpected(" << e.error() << ')';
54 }
55 return os;
56}
57
58struct NoDefault {
59 NoDefault(int, int) {}
60 char a, b, c;
61};
62
63TEST(Expected, NoDefault) {
64 static_assert(
65 std::is_default_constructible<Expected<NoDefault, int>>::value, "");
66 Expected<NoDefault, int> x{in_place, 42, 42};
67 EXPECT_TRUE(bool(x));
68 x.emplace(4, 5);
69 EXPECT_TRUE(bool(x));
70 x = makeUnexpected(42);
71 EXPECT_FALSE(bool(x));
72 EXPECT_EQ(42, x.error());
73}
74
75TEST(Expected, String) {
76 Expected<std::string, int> maybeString;
77 EXPECT_FALSE(bool(maybeString));
78 EXPECT_EQ(0, maybeString.error());
79 maybeString = "hello";
80 EXPECT_TRUE(bool(maybeString));
81 EXPECT_EQ("hello", *maybeString);
82}
83
84TEST(Expected, Ambiguous) {
85 // Potentially ambiguous and confusing construction and assignment disallowed:
86 EXPECT_FALSE((std::is_constructible<Expected<int, int>, int>::value));
87 EXPECT_FALSE((std::is_assignable<Expected<int, int>&, int>::value));
88}
89
90TEST(Expected, Const) {
91 { // default construct
92 Expected<const int, int> ex;
93 EXPECT_FALSE(bool(ex));
94 EXPECT_EQ(0, ex.error());
95 ex.emplace(4);
96 EXPECT_EQ(4, *ex);
97 ex.emplace(5);
98 EXPECT_EQ(5, *ex);
99 ex = makeUnexpected(42);
100 EXPECT_FALSE(bool(ex));
101 EXPECT_EQ(42, ex.error());
102 }
103 { // copy-constructed
104 const int x = 6;
105 Expected<const int, int> ex{in_place, x};
106 Expected<const int, int> ex2 = ex;
107 EXPECT_EQ(6, *ex2);
108 }
109 { // move-constructed
110 const int x = 7;
111 Expected<const int, int> ex{in_place, std::move(x)};
112 Expected<const int, int> ex2 = std::move(ex);
113 EXPECT_EQ(7, *ex2);
114 }
115 // no assignment allowed
116 EXPECT_FALSE((std::is_copy_assignable<Expected<const int, int>>::value));
117}
118
119TEST(Expected, Simple) {
120 Expected<int, int> ex;
121 EXPECT_FALSE(bool(ex));
122 EXPECT_EQ(42, ex.value_or(42));
123 ex.emplace(4);
124 EXPECT_TRUE(bool(ex));
125 EXPECT_EQ(4, *ex);
126 EXPECT_EQ(4, ex.value_or(42));
127 ex = makeUnexpected(-1);
128 EXPECT_FALSE(bool(ex));
129 EXPECT_EQ(-1, ex.error());
130 EXPECT_EQ(42, ex.value_or(42));
131}
132
133class MoveTester {
134 public:
135 /* implicit */ MoveTester(const char* s) : s_(s) {}
136 MoveTester(const MoveTester&) = default;
137 MoveTester(MoveTester&& other) noexcept {
138 s_ = std::move(other.s_);
139 other.s_ = "";
140 }
141 MoveTester& operator=(const MoveTester&) = default;
142 MoveTester& operator=(MoveTester&& other) noexcept {
143 s_ = std::move(other.s_);
144 other.s_ = "";
145 return *this;
146 }
147
148 private:
149 friend bool operator==(const MoveTester& o1, const MoveTester& o2);
150 std::string s_;
151};
152
153bool operator==(const MoveTester& o1, const MoveTester& o2) {
154 return o1.s_ == o2.s_;
155}
156
157TEST(Expected, value_or_rvalue_arg) {
158 Expected<MoveTester, int> ex = makeUnexpected(-1);
159 MoveTester dflt = "hello";
160 EXPECT_EQ("hello", ex.value_or(dflt));
161 EXPECT_EQ("hello", dflt);
162 EXPECT_EQ("hello", ex.value_or(std::move(dflt)));
163 EXPECT_EQ("", dflt);
164 EXPECT_EQ("world", ex.value_or("world"));
165
166 dflt = "hello";
167 // Make sure that the const overload works on const objects
168 const auto& exc = ex;
169 EXPECT_EQ("hello", exc.value_or(dflt));
170 EXPECT_EQ("hello", dflt);
171 EXPECT_EQ("hello", exc.value_or(std::move(dflt)));
172 EXPECT_EQ("", dflt);
173 EXPECT_EQ("world", exc.value_or("world"));
174
175 dflt = "hello";
176 ex = "meow";
177 EXPECT_EQ("meow", ex.value_or(dflt));
178 EXPECT_EQ("hello", dflt);
179 EXPECT_EQ("meow", ex.value_or(std::move(dflt)));
180 EXPECT_EQ("hello", dflt); // only moved if used
181}
182
183TEST(Expected, value_or_noncopyable) {
184 Expected<std::unique_ptr<int>, int> ex{unexpected, 42};
185 std::unique_ptr<int> dflt(new int(42));
186 EXPECT_EQ(42, *std::move(ex).value_or(std::move(dflt)));
187}
188
189struct ExpectingDeleter {
190 explicit ExpectingDeleter(int expected_) : expected(expected_) {}
191 int expected;
192 void operator()(const int* ptr) {
193 EXPECT_EQ(*ptr, expected);
194 delete ptr;
195 }
196};
197
198TEST(Expected, value_move) {
199 auto ptr = Expected<std::unique_ptr<int, ExpectingDeleter>, int>(
200 in_place, new int(42), ExpectingDeleter{1337})
201 .value();
202 *ptr = 1337;
203}
204
205TEST(Expected, dereference_move) {
206 auto ptr = *Expected<std::unique_ptr<int, ExpectingDeleter>, int>(
207 in_place, new int(42), ExpectingDeleter{1337});
208 *ptr = 1337;
209}
210
211TEST(Expected, EmptyConstruct) {
212 Expected<int, int> ex{unexpected, 42};
213 EXPECT_FALSE(bool(ex));
214 Expected<int, int> test1(ex);
215 EXPECT_FALSE(bool(test1));
216 Expected<int, int> test2(std::move(ex));
217 EXPECT_FALSE(bool(test2));
218 EXPECT_EQ(42, test2.error());
219}
220
221TEST(Expected, Unique) {
222 Expected<unique_ptr<int>, int> ex;
223
224 ex = makeUnexpected(-1);
225 EXPECT_FALSE(bool(ex));
226 // empty->emplaced
227 ex.emplace(new int(5));
228 EXPECT_TRUE(bool(ex));
229 EXPECT_EQ(5, **ex);
230
231 ex = makeUnexpected(-1);
232 // empty->moved
233 ex = std::make_unique<int>(6);
234 EXPECT_EQ(6, **ex);
235 // full->moved
236 ex = std::make_unique<int>(7);
237 EXPECT_EQ(7, **ex);
238
239 // move it out by move construct
240 Expected<unique_ptr<int>, int> moved(std::move(ex));
241 EXPECT_TRUE(bool(moved));
242 EXPECT_TRUE(bool(ex));
243 EXPECT_EQ(nullptr, ex->get());
244 EXPECT_EQ(7, **moved);
245
246 EXPECT_TRUE(bool(moved));
247 ex = std::move(moved); // move it back by move assign
248 EXPECT_TRUE(bool(moved));
249 EXPECT_EQ(nullptr, moved->get());
250 EXPECT_TRUE(bool(ex));
251 EXPECT_EQ(7, **ex);
252}
253
254TEST(Expected, Shared) {
255 shared_ptr<int> ptr;
256 Expected<shared_ptr<int>, int> ex{unexpected, -1};
257 EXPECT_FALSE(bool(ex));
258 // empty->emplaced
259 ex.emplace(new int(5));
260 EXPECT_TRUE(bool(ex));
261 ptr = ex.value();
262 EXPECT_EQ(ptr.get(), ex->get());
263 EXPECT_EQ(2, ptr.use_count());
264 ex = makeUnexpected(-1);
265 EXPECT_EQ(1, ptr.use_count());
266 // full->copied
267 ex = ptr;
268 EXPECT_EQ(2, ptr.use_count());
269 EXPECT_EQ(ptr.get(), ex->get());
270 ex = makeUnexpected(-1);
271 EXPECT_EQ(1, ptr.use_count());
272 // full->moved
273 ex = std::move(ptr);
274 EXPECT_EQ(1, ex->use_count());
275 EXPECT_EQ(nullptr, ptr.get());
276 {
277 EXPECT_EQ(1, ex->use_count());
278 Expected<shared_ptr<int>, int> copied(ex);
279 EXPECT_EQ(2, ex->use_count());
280 Expected<shared_ptr<int>, int> moved(std::move(ex));
281 EXPECT_EQ(2, moved->use_count());
282 moved.emplace(new int(6));
283 EXPECT_EQ(1, moved->use_count());
284 copied = moved;
285 EXPECT_EQ(2, moved->use_count());
286 }
287}
288
289TEST(Expected, Order) {
290 std::vector<Expected<int, E>> vect{
291 {unexpected, E::E1},
292 {3},
293 {1},
294 {unexpected, E::E1},
295 {2},
296 };
297 std::vector<Expected<int, E>> expected{
298 {unexpected, E::E1},
299 {unexpected, E::E1},
300 {1},
301 {2},
302 {3},
303 };
304 std::sort(vect.begin(), vect.end());
305 EXPECT_EQ(vect, expected);
306}
307
308TEST(Expected, SwapMethod) {
309 Expected<std::string, E> a;
310 Expected<std::string, E> b;
311
312 a.swap(b);
313 EXPECT_FALSE(a.hasValue());
314 EXPECT_FALSE(b.hasValue());
315
316 a = "hello";
317 EXPECT_TRUE(a.hasValue());
318 EXPECT_FALSE(b.hasValue());
319 EXPECT_EQ("hello", a.value());
320
321 b.swap(a);
322 EXPECT_FALSE(a.hasValue());
323 EXPECT_TRUE(b.hasValue());
324 EXPECT_EQ("hello", b.value());
325
326 a = "bye";
327 EXPECT_TRUE(a.hasValue());
328 EXPECT_EQ("bye", a.value());
329
330 a.swap(b);
331 EXPECT_EQ("hello", a.value());
332 EXPECT_EQ("bye", b.value());
333}
334
335TEST(Expected, StdSwapFunction) {
336 Expected<std::string, E> a;
337 Expected<std::string, E> b;
338
339 std::swap(a, b);
340 EXPECT_FALSE(a.hasValue());
341 EXPECT_FALSE(b.hasValue());
342
343 a = "greeting";
344 EXPECT_TRUE(a.hasValue());
345 EXPECT_FALSE(b.hasValue());
346 EXPECT_EQ("greeting", a.value());
347
348 std::swap(a, b);
349 EXPECT_FALSE(a.hasValue());
350 EXPECT_TRUE(b.hasValue());
351 EXPECT_EQ("greeting", b.value());
352
353 a = "goodbye";
354 EXPECT_TRUE(a.hasValue());
355 EXPECT_EQ("goodbye", a.value());
356
357 std::swap(a, b);
358 EXPECT_EQ("greeting", a.value());
359 EXPECT_EQ("goodbye", b.value());
360}
361
362TEST(Expected, FollySwapFunction) {
363 Expected<std::string, E> a;
364 Expected<std::string, E> b;
365
366 folly::swap(a, b);
367 EXPECT_FALSE(a.hasValue());
368 EXPECT_FALSE(b.hasValue());
369
370 a = "salute";
371 EXPECT_TRUE(a.hasValue());
372 EXPECT_FALSE(b.hasValue());
373 EXPECT_EQ("salute", a.value());
374
375 folly::swap(a, b);
376 EXPECT_FALSE(a.hasValue());
377 EXPECT_TRUE(b.hasValue());
378 EXPECT_EQ("salute", b.value());
379
380 a = "adieu";
381 EXPECT_TRUE(a.hasValue());
382 EXPECT_EQ("adieu", a.value());
383
384 folly::swap(a, b);
385 EXPECT_EQ("salute", a.value());
386 EXPECT_EQ("adieu", b.value());
387}
388
389TEST(Expected, Comparisons) {
390 Expected<int, E> o_;
391 Expected<int, E> o1(1);
392 Expected<int, E> o2(2);
393
394 EXPECT_TRUE(o_ <= (o_));
395 EXPECT_TRUE(o_ == (o_));
396 EXPECT_TRUE(o_ >= (o_));
397
398 EXPECT_TRUE(o1 < o2);
399 EXPECT_TRUE(o1 <= o2);
400 EXPECT_TRUE(o1 <= (o1));
401 EXPECT_TRUE(o1 == (o1));
402 EXPECT_TRUE(o1 != o2);
403 EXPECT_TRUE(o1 >= (o1));
404 EXPECT_TRUE(o2 >= o1);
405 EXPECT_TRUE(o2 > o1);
406
407 EXPECT_FALSE(o2 < o1);
408 EXPECT_FALSE(o2 <= o1);
409 EXPECT_FALSE(o2 <= o1);
410 EXPECT_FALSE(o2 == o1);
411 EXPECT_FALSE(o1 != (o1));
412 EXPECT_FALSE(o1 >= o2);
413 EXPECT_FALSE(o1 >= o2);
414 EXPECT_FALSE(o1 > o2);
415
416 /* folly::Expected explicitly doesn't support comparisons with contained value
417 EXPECT_TRUE(1 < o2);
418 EXPECT_TRUE(1 <= o2);
419 EXPECT_TRUE(1 <= o1);
420 EXPECT_TRUE(1 == o1);
421 EXPECT_TRUE(2 != o1);
422 EXPECT_TRUE(1 >= o1);
423 EXPECT_TRUE(2 >= o1);
424 EXPECT_TRUE(2 > o1);
425
426 EXPECT_FALSE(o2 < 1);
427 EXPECT_FALSE(o2 <= 1);
428 EXPECT_FALSE(o2 <= 1);
429 EXPECT_FALSE(o2 == 1);
430 EXPECT_FALSE(o2 != 2);
431 EXPECT_FALSE(o1 >= 2);
432 EXPECT_FALSE(o1 >= 2);
433 EXPECT_FALSE(o1 > 2);
434 */
435}
436
437TEST(Expected, Conversions) {
438 Expected<bool, E> mbool;
439 Expected<short, E> mshort;
440 Expected<char*, E> mstr;
441 Expected<int, E> mint;
442
443 EXPECT_FALSE((std::is_convertible<Expected<bool, E>&, bool>::value));
444 EXPECT_FALSE((std::is_convertible<Expected<short, E>&, short>::value));
445 EXPECT_FALSE((std::is_convertible<Expected<char*, E>&, char*>::value));
446 EXPECT_FALSE((std::is_convertible<Expected<int, E>&, int>::value));
447
448 // intended explicit operator bool, for if (ex).
449 bool b(mbool);
450 EXPECT_FALSE(b);
451
452 // Truthy tests work and are not ambiguous
453 if (mbool && mshort && mstr && mint) { // only checks not-empty
454 if (*mbool && *mshort && *mstr && *mint) { // only checks value
455 ;
456 }
457 }
458
459 mbool = false;
460 EXPECT_TRUE(bool(mbool));
461 EXPECT_FALSE(*mbool);
462
463 mbool = true;
464 EXPECT_TRUE(bool(mbool));
465 EXPECT_TRUE(*mbool);
466
467 mbool = {unexpected, E::E1};
468 EXPECT_FALSE(bool(mbool));
469
470 // No conversion allowed; does not compile
471 // mbool == false;
472}
473
474TEST(Expected, Pointee) {
475 Expected<int, E> x;
476 EXPECT_FALSE(get_pointer(x));
477 x = 1;
478 EXPECT_TRUE(get_pointer(x));
479 *get_pointer(x) = 2;
480 EXPECT_TRUE(*x == 2);
481 x = {unexpected, E::E1};
482 EXPECT_FALSE(get_pointer(x));
483}
484
485TEST(Expected, MakeOptional) {
486 // const L-value version
487 const std::string s("abc");
488 auto exStr = makeExpected<E>(s);
489 ASSERT_TRUE(exStr.hasValue());
490 EXPECT_EQ(*exStr, "abc");
491 *exStr = "cde";
492 EXPECT_EQ(s, "abc");
493 EXPECT_EQ(*exStr, "cde");
494
495 // L-value version
496 std::string s2("abc");
497 auto exStr2 = makeExpected<E>(s2);
498 ASSERT_TRUE(exStr2.hasValue());
499 EXPECT_EQ(*exStr2, "abc");
500 *exStr2 = "cde";
501 // it's vital to check that s2 wasn't clobbered
502 EXPECT_EQ(s2, "abc");
503
504 // L-value reference version
505 std::string& s3(s2);
506 auto exStr3 = makeExpected<E>(s3);
507 ASSERT_TRUE(exStr3.hasValue());
508 EXPECT_EQ(*exStr3, "abc");
509 *exStr3 = "cde";
510 EXPECT_EQ(s3, "abc");
511
512 // R-value ref version
513 unique_ptr<int> pInt(new int(3));
514 auto exIntPtr = makeExpected<E>(std::move(pInt));
515 EXPECT_TRUE(pInt.get() == nullptr);
516 ASSERT_TRUE(exIntPtr.hasValue());
517 EXPECT_EQ(**exIntPtr, 3);
518}
519
520TEST(Expected, SelfAssignment) {
521 Expected<std::string, E> a = "42";
522 a = static_cast<decltype(a)&>(a); // suppress self-assign warning
523 ASSERT_TRUE(a.hasValue() && a.value() == "42");
524
525 Expected<std::string, E> b = "23333333";
526 b = static_cast<decltype(b)&&>(b); // suppress self-move warning
527 ASSERT_TRUE(b.hasValue() && b.value() == "23333333");
528}
529
530class ContainsExpected {
531 public:
532 ContainsExpected() {}
533 explicit ContainsExpected(int x) : ex_(x) {}
534 bool hasValue() const {
535 return ex_.hasValue();
536 }
537 int value() const {
538 return ex_.value();
539 }
540
541 ContainsExpected(const ContainsExpected& other) = default;
542 ContainsExpected& operator=(const ContainsExpected& other) = default;
543 ContainsExpected(ContainsExpected&& other) = default;
544 ContainsExpected& operator=(ContainsExpected&& other) = default;
545
546 private:
547 Expected<int, E> ex_;
548};
549
550/**
551 * Test that a class containing an Expected can be copy and move assigned.
552 * This was broken under gcc 4.7 until assignment operators were explicitly
553 * defined.
554 */
555TEST(Expected, AssignmentContained) {
556 {
557 ContainsExpected source(5), target;
558 target = source;
559 EXPECT_TRUE(target.hasValue());
560 EXPECT_EQ(5, target.value());
561 }
562
563 {
564 ContainsExpected source(5), target;
565 target = std::move(source);
566 EXPECT_TRUE(target.hasValue());
567 EXPECT_EQ(5, target.value());
568 EXPECT_TRUE(source.hasValue());
569 }
570
571 {
572 ContainsExpected ex_uninit, target(10);
573 target = ex_uninit;
574 EXPECT_FALSE(target.hasValue());
575 }
576}
577
578TEST(Expected, Exceptions) {
579 Expected<int, E> empty;
580 EXPECT_THROW(empty.value(), Unexpected<E>::BadExpectedAccess);
581}
582
583struct ThrowingBadness {
584 ThrowingBadness() noexcept(false);
585 ThrowingBadness(const ThrowingBadness&) noexcept(false);
586 ThrowingBadness(ThrowingBadness&&) noexcept(false);
587 ThrowingBadness& operator=(const ThrowingBadness&) noexcept(false);
588 ThrowingBadness& operator=(ThrowingBadness&&) noexcept(false);
589};
590
591TEST(Expected, NoThrowDefaultConstructible) {
592 EXPECT_TRUE(
593 (std::is_nothrow_default_constructible<Expected<bool, E>>::value));
594 EXPECT_TRUE(
595 (std::is_nothrow_default_constructible<Expected<std::string, E>>::value));
596 EXPECT_TRUE((std::is_nothrow_default_constructible<
597 Expected<ThrowingBadness, E>>::value));
598 EXPECT_FALSE((std::is_nothrow_default_constructible<
599 Expected<int, ThrowingBadness>>::value));
600}
601
602TEST(Expected, NoThrowMoveConstructible) {
603 EXPECT_TRUE((std::is_nothrow_move_constructible<Expected<bool, E>>::value));
604 EXPECT_TRUE((std::is_nothrow_move_constructible<
605 Expected<std::unique_ptr<int>, E>>::value));
606 EXPECT_FALSE((
607 std::is_nothrow_move_constructible<Expected<ThrowingBadness, E>>::value));
608}
609
610TEST(Expected, NoThrowMoveAssignable) {
611 EXPECT_TRUE((std::is_nothrow_move_assignable<Expected<bool, E>>::value));
612 EXPECT_TRUE((std::is_nothrow_move_assignable<
613 Expected<std::unique_ptr<int>, E>>::value));
614 EXPECT_FALSE(
615 (std::is_nothrow_move_assignable<Expected<ThrowingBadness, E>>::value));
616}
617
618struct NoSelfAssign {
619 NoSelfAssign() = default;
620 NoSelfAssign(NoSelfAssign&&) = default;
621 NoSelfAssign(const NoSelfAssign&) = default;
622 NoSelfAssign& operator=(NoSelfAssign&& that) {
623 EXPECT_NE(this, &that);
624 return *this;
625 }
626 NoSelfAssign& operator=(const NoSelfAssign& that) {
627 EXPECT_NE(this, &that);
628 return *this;
629 }
630};
631
632#ifdef __GNUC__
633#pragma GCC diagnostic push
634#pragma GCC diagnostic ignored "-Wpragmas"
635#endif
636
637TEST(Expected, NoSelfAssign) {
638 folly::Expected<NoSelfAssign, int> e{NoSelfAssign{}};
639 e = static_cast<decltype(e)&>(e); // suppress self-assign warning
640 e = static_cast<decltype(e)&&>(e); // @nolint suppress self-move warning
641}
642
643#ifdef __GNUC__
644#pragma GCC diagnostic pop
645#endif
646
647struct NoDestructor {};
648
649struct WithDestructor {
650 ~WithDestructor();
651};
652
653TEST(Expected, TriviallyDestructible) {
654 // These could all be static_asserts but EXPECT_* give much nicer output on
655 // failure.
656 EXPECT_TRUE(
657 (std::is_trivially_destructible<Expected<NoDestructor, E>>::value));
658 EXPECT_TRUE((std::is_trivially_destructible<Expected<int, E>>::value));
659 EXPECT_FALSE(
660 (std::is_trivially_destructible<Expected<WithDestructor, E>>::value));
661}
662
663struct NoConstructor {};
664
665struct WithConstructor {
666 WithConstructor();
667};
668
669// libstdc++ with GCC 4.x doesn't have std::is_trivially_copyable
670#if (defined(__clang__) && !defined(_LIBCPP_VERSION)) || \
671 !(defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5)
672TEST(Expected, TriviallyCopyable) {
673 // These could all be static_asserts but EXPECT_* give much nicer output on
674 // failure.
675 EXPECT_TRUE((is_trivially_copyable<Expected<int, E>>::value));
676 EXPECT_TRUE((is_trivially_copyable<Expected<char*, E>>::value));
677 EXPECT_TRUE((is_trivially_copyable<Expected<NoDestructor, E>>::value));
678 EXPECT_FALSE((is_trivially_copyable<Expected<WithDestructor, E>>::value));
679 EXPECT_TRUE((is_trivially_copyable<Expected<NoConstructor, E>>::value));
680 EXPECT_FALSE((is_trivially_copyable<Expected<std::string, E>>::value));
681 EXPECT_FALSE((is_trivially_copyable<Expected<int, std::string>>::value));
682 EXPECT_TRUE((is_trivially_copyable<Expected<WithConstructor, E>>::value));
683 EXPECT_TRUE((is_trivially_copyable<Expected<Expected<int, E>, E>>::value));
684}
685#endif
686
687TEST(Expected, Then) {
688 // Lifting
689 {
690 Expected<int, E> ex =
691 Expected<std::unique_ptr<int>, E>{in_place, new int(42)}.then(
692 [](std::unique_ptr<int> p) { return *p; });
693 EXPECT_TRUE(bool(ex));
694 EXPECT_EQ(42, *ex);
695 }
696
697 // Flattening
698 {
699 Expected<int, E> ex =
700 Expected<std::unique_ptr<int>, E>{in_place, new int(42)}.then(
701 [](std::unique_ptr<int> p) { return makeExpected<E>(*p); });
702 EXPECT_TRUE(bool(ex));
703 EXPECT_EQ(42, *ex);
704 }
705
706 // Void
707 {
708 Expected<Unit, E> ex =
709 Expected<std::unique_ptr<int>, E>{in_place, new int(42)}.then(
710 [](std::unique_ptr<int>) {});
711 EXPECT_TRUE(bool(ex));
712 }
713
714 // Non-flattening (different error codes)
715 {
716 Expected<Expected<int, int>, E> ex =
717 Expected<std::unique_ptr<int>, E>{in_place, new int(42)}.then(
718 [](std::unique_ptr<int> p) { return makeExpected<int>(*p); });
719 EXPECT_TRUE(bool(ex));
720 EXPECT_TRUE(bool(*ex));
721 EXPECT_EQ(42, **ex);
722 }
723
724 {
725 // Error case:
726 Expected<int, E> ex =
727 Expected<std::unique_ptr<int>, E>{unexpected, E::E1}.then(
728 [](std::unique_ptr<int> p) -> int {
729 ADD_FAILURE();
730 return *p;
731 });
732 EXPECT_FALSE(bool(ex));
733 EXPECT_EQ(E::E1, ex.error());
734 }
735
736 // Chaining
737 {
738 Expected<std::string, E> ex =
739 Expected<std::unique_ptr<int>, E>{in_place, new int(42)}.then(
740 [](std::unique_ptr<int> p) { return makeExpected<E>(*p); },
741 [](int i) { return i == 42 ? "yes" : "no"; });
742 EXPECT_TRUE(bool(ex));
743 EXPECT_EQ("yes", *ex);
744 }
745
746 // Chaining with errors
747 {
748 Expected<std::string, E> ex =
749 Expected<std::unique_ptr<int>, E>{in_place, new int(42)}.then(
750 [](std::unique_ptr<int>) {
751 return Expected<int, E>(unexpected, E::E1);
752 },
753 [](int i) { return i == 42 ? "yes" : "no"; });
754 EXPECT_FALSE(bool(ex));
755 EXPECT_EQ(E::E1, ex.error());
756 }
757}
758
759TEST(Expected, ThenOrThrow) {
760 {
761 int e =
762 Expected<std::unique_ptr<int>, E>{in_place, new int(42)}.thenOrThrow(
763 [](std::unique_ptr<int> p) { return *p; });
764 EXPECT_EQ(42, e);
765 }
766
767 {
768 EXPECT_THROW(
769 (Expected<std::unique_ptr<int>, E>{unexpected, E::E1}.thenOrThrow(
770 [](std::unique_ptr<int> p) { return *p; })),
771 Unexpected<E>::BadExpectedAccess);
772 }
773
774 {
775 EXPECT_THROW(
776 (Expected<std::unique_ptr<int>, E>{unexpected, E::E1}.thenOrThrow(
777 [](std::unique_ptr<int> p) { return *p; },
778 [](E) { return std::runtime_error(""); })),
779 std::runtime_error);
780 }
781
782 {
783 EXPECT_THROW(
784 (Expected<std::unique_ptr<int>, E>{unexpected, E::E1}.thenOrThrow(
785 [](std::unique_ptr<int> p) { return *p; },
786 [](E) { throw std::runtime_error(""); })),
787 std::runtime_error);
788 }
789
790 {
791 EXPECT_THROW(
792 (Expected<std::unique_ptr<int>, E>{unexpected, E::E1}.thenOrThrow(
793 [](std::unique_ptr<int> p) { return *p; }, [](E) {})),
794 Unexpected<E>::BadExpectedAccess);
795 }
796}
797} // namespace folly
798