Fix copyright lines for Bits.h and move BitsBenchmark.cpp
[folly.git] / folly / test / ExpectedCoroutinesTest.cpp
1 /*
2  * Copyright 2017 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/ScopeGuard.h>
20 #include <folly/portability/GTest.h>
21
22 using namespace folly;
23
24 namespace {
25
26 struct Exn {};
27
28 // not default-constructible, thereby preventing Expected<T, Err> from being
29 // default-constructible, forcing our implementation to handle such cases
30 class Err {
31  private:
32   enum class Type { Bad, Badder, Baddest };
33
34   Type type_;
35
36   constexpr Err(Type type) : type_(type) {}
37
38  public:
39   Err(Err const&) = default;
40   Err(Err&&) = default;
41   Err& operator=(Err const&) = default;
42   Err& operator=(Err&&) = default;
43
44   friend bool operator==(Err a, Err b) {
45     return a.type_ == b.type_;
46   }
47   friend bool operator!=(Err a, Err b) {
48     return a.type_ != b.type_;
49   }
50
51   static constexpr Err bad() {
52     return Type::Bad;
53   }
54   static constexpr Err badder() {
55     return Type::Badder;
56   }
57   static constexpr Err baddest() {
58     return Type::Baddest;
59   }
60 };
61
62 Expected<int, Err> f1() {
63   return 7;
64 }
65
66 Expected<double, Err> f2(int x) {
67   return 2.0 * x;
68 }
69
70 // move-only type
71 Expected<std::unique_ptr<int>, Err> f3(int x, double y) {
72   return std::make_unique<int>(int(x + y));
73 }
74
75 // error result
76 Expected<int, Err> f4(int, double, Err err) {
77   return makeUnexpected(err);
78 }
79
80 // exception
81 Expected<int, Err> throws() {
82   throw Exn{};
83 }
84
85 } // namespace
86
87 #if FOLLY_HAS_COROUTINES
88
89 TEST(Expected, CoroutineSuccess) {
90   auto r0 = []() -> Expected<int, Err> {
91     auto x = co_await f1();
92     EXPECT_EQ(7, x);
93     auto y = co_await f2(x);
94     EXPECT_EQ(2.0 * 7, y);
95     auto z = co_await f3(x, y);
96     EXPECT_EQ(int(2.0 * 7 + 7), *z);
97     co_return* z;
98   }();
99   EXPECT_TRUE(r0.hasValue());
100   EXPECT_EQ(21, *r0);
101 }
102
103 TEST(Expected, CoroutineFailure) {
104   auto r1 = []() -> Expected<int, Err> {
105     auto x = co_await f1();
106     auto y = co_await f2(x);
107     auto z = co_await f4(x, y, Err::badder());
108     ADD_FAILURE();
109     co_return z;
110   }();
111   EXPECT_TRUE(r1.hasError());
112   EXPECT_EQ(Err::badder(), r1.error());
113 }
114
115 TEST(Expected, CoroutineException) {
116   EXPECT_THROW(
117       ([]() -> Expected<int, Err> {
118         auto x = co_await throws();
119         ADD_FAILURE();
120         co_return x;
121       }()),
122       Exn);
123 }
124
125 // this test makes sure that the coroutine is destroyed properly
126 TEST(Expected, CoroutineCleanedUp) {
127   int count_dest = 0;
128   auto r = [&]() -> Expected<int, Err> {
129     SCOPE_EXIT {
130       ++count_dest;
131     };
132     auto x = co_await Expected<int, Err>(makeUnexpected(Err::badder()));
133     ADD_FAILURE() << "Should not be resuming";
134     co_return x;
135   }();
136   EXPECT_FALSE(r.hasValue());
137   EXPECT_EQ(1, count_dest);
138 }
139
140 #endif