Fixes for Try::withException
[folly.git] / folly / test / TryTest.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/Try.h>
18
19 #include <glog/logging.h>
20
21 #include <folly/Memory.h>
22 #include <folly/portability/GTest.h>
23
24 using namespace folly;
25
26 TEST(Try, basic) {
27   class A {
28    public:
29     A(int x) : x_(x) {}
30
31     int x() const {
32       return x_;
33     }
34    private:
35     int x_;
36   };
37
38   A a(5);
39   Try<A> t_a(std::move(a));
40
41   Try<Unit> t_void;
42
43   EXPECT_EQ(5, t_a.value().x());
44 }
45
46 // Make sure we can copy Trys for copyable types
47 TEST(Try, copy) {
48   Try<int> t;
49   auto t2 = t;
50 }
51
52 // But don't choke on move-only types
53 TEST(Try, moveOnly) {
54   Try<std::unique_ptr<int>> t;
55   std::vector<Try<std::unique_ptr<int>>> v;
56   v.reserve(10);
57 }
58
59 TEST(Try, makeTryWith) {
60   auto func = []() {
61     return std::make_unique<int>(1);
62   };
63
64   auto result = makeTryWith(func);
65   EXPECT_TRUE(result.hasValue());
66   EXPECT_EQ(*result.value(), 1);
67 }
68
69 TEST(Try, makeTryWithThrow) {
70   auto func = []() -> std::unique_ptr<int> {
71     throw std::runtime_error("Runtime");
72   };
73
74   auto result = makeTryWith(func);
75   EXPECT_TRUE(result.hasException<std::runtime_error>());
76 }
77
78 TEST(Try, makeTryWithVoid) {
79   auto func = []() {
80     return;
81   };
82
83   auto result = makeTryWith(func);
84   EXPECT_TRUE(result.hasValue());
85 }
86
87 TEST(Try, makeTryWithVoidThrow) {
88   auto func = []() {
89     throw std::runtime_error("Runtime");
90   };
91
92   auto result = makeTryWith(func);
93   EXPECT_TRUE(result.hasException<std::runtime_error>());
94 }
95
96 template <typename E>
97 static E* get_exception(std::exception_ptr eptr) {
98   try {
99     std::rethrow_exception(eptr);
100   } catch (E& e) {
101     return &e;
102   } catch (...) {
103     return nullptr;
104   }
105 }
106
107 TEST(Try, tryGetExceptionObject) {
108   auto epexn = std::make_exception_ptr(std::range_error("oops"));
109   auto epnum = std::make_exception_ptr(17);
110
111   auto exn = CHECK_NOTNULL(get_exception<std::range_error>(epexn));
112   auto num = CHECK_NOTNULL(get_exception<int>(epnum));
113
114   {
115     auto t = Try<bool>(true);
116     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
117     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
118     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
119   }
120
121   {
122     auto t = Try<bool>(exception_wrapper(epexn, *exn));
123     EXPECT_EQ(exn, t.tryGetExceptionObject());
124     EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>());
125     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
126   }
127
128   {
129     auto t = Try<bool>(exception_wrapper(epnum, *num));
130     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
131     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
132     EXPECT_EQ(num, t.tryGetExceptionObject<int>());
133   }
134
135   {
136     auto t = Try<void>();
137     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
138     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
139     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
140   }
141
142   {
143     auto t = Try<void>(exception_wrapper(epexn, *exn));
144     EXPECT_EQ(exn, t.tryGetExceptionObject());
145     EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>());
146     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
147   }
148
149   {
150     auto t = Try<void>(exception_wrapper(epnum, *num));
151     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
152     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
153     EXPECT_EQ(num, t.tryGetExceptionObject<int>());
154   }
155
156   {
157     auto const t = Try<bool>(true);
158     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
159     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
160     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
161   }
162
163   {
164     auto const t = Try<bool>(exception_wrapper(epexn, *exn));
165     EXPECT_EQ(exn, t.tryGetExceptionObject());
166     EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>());
167     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
168   }
169
170   {
171     auto const t = Try<bool>(exception_wrapper(epnum, *num));
172     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
173     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
174     EXPECT_EQ(num, t.tryGetExceptionObject<int>());
175   }
176
177   {
178     auto const t = Try<void>();
179     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
180     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
181     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
182   }
183
184   {
185     auto const t = Try<void>(exception_wrapper(epexn, *exn));
186     EXPECT_EQ(exn, t.tryGetExceptionObject());
187     EXPECT_EQ(exn, t.tryGetExceptionObject<std::runtime_error>());
188     EXPECT_EQ(nullptr, t.tryGetExceptionObject<int>());
189   }
190
191   {
192     auto const t = Try<void>(exception_wrapper(epnum, *num));
193     EXPECT_EQ(nullptr, t.tryGetExceptionObject());
194     EXPECT_EQ(nullptr, t.tryGetExceptionObject<std::runtime_error>());
195     EXPECT_EQ(num, t.tryGetExceptionObject<int>());
196   }
197 }
198
199 TEST(Try, withException) {
200   auto ew = make_exception_wrapper<std::range_error>("oops");
201
202   {
203     auto t = Try<bool>(true);
204     EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {}));
205     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
206     EXPECT_FALSE(t.withException([](std::runtime_error&) {}));
207     EXPECT_FALSE(t.withException([](std::logic_error&) {}));
208   }
209
210   {
211     auto t = Try<bool>(ew);
212     EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {}));
213     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
214     EXPECT_TRUE(t.withException([](std::runtime_error&) {}));
215     EXPECT_FALSE(t.withException([](std::logic_error&) {}));
216   }
217
218   {
219     auto t = Try<void>();
220     EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {}));
221     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
222     EXPECT_FALSE(t.withException([](std::runtime_error&) {}));
223     EXPECT_FALSE(t.withException([](std::logic_error&) {}));
224   }
225
226   {
227     auto t = Try<void>(ew);
228     EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {}));
229     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
230     EXPECT_TRUE(t.withException([](std::runtime_error&) {}));
231     EXPECT_FALSE(t.withException([](std::logic_error&) {}));
232   }
233
234   {
235     auto const t = Try<bool>(true);
236     EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {}));
237     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
238     EXPECT_FALSE(t.withException([](std::runtime_error const&) {}));
239     EXPECT_FALSE(t.withException([](std::logic_error const&) {}));
240   }
241
242   {
243     auto const t = Try<bool>(ew);
244     EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {}));
245     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
246     EXPECT_TRUE(t.withException([](std::runtime_error const&) {}));
247     EXPECT_FALSE(t.withException([](std::logic_error const&) {}));
248   }
249
250   {
251     auto const t = Try<void>();
252     EXPECT_FALSE(t.withException<std::runtime_error>([](auto&) {}));
253     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
254     EXPECT_FALSE(t.withException([](std::runtime_error const&) {}));
255     EXPECT_FALSE(t.withException([](std::logic_error const&) {}));
256   }
257
258   {
259     auto const t = Try<void>(ew);
260     EXPECT_TRUE(t.withException<std::runtime_error>([](auto&) {}));
261     EXPECT_FALSE(t.withException<std::logic_error>([](auto&) {}));
262     EXPECT_TRUE(t.withException([](std::runtime_error const&) {}));
263     EXPECT_FALSE(t.withException([](std::logic_error const&) {}));
264   }
265 }