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 | |
30 | using std::shared_ptr; |
31 | using std::unique_ptr; |
32 | |
33 | namespace folly { |
34 | |
35 | enum class E { E1, E2 }; |
36 | |
37 | std::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 | |
48 | template <class V, class E> |
49 | std::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 | |
58 | struct NoDefault { |
59 | NoDefault(int, int) {} |
60 | char a, b, c; |
61 | }; |
62 | |
63 | TEST(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 | |
75 | TEST(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 | |
84 | TEST(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 | |
90 | TEST(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 | |
119 | TEST(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 | |
133 | class 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 | |
153 | bool operator==(const MoveTester& o1, const MoveTester& o2) { |
154 | return o1.s_ == o2.s_; |
155 | } |
156 | |
157 | TEST(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 | |
183 | TEST(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 | |
189 | struct 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 | |
198 | TEST(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 | |
205 | TEST(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 | |
211 | TEST(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 | |
221 | TEST(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 | |
254 | TEST(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 | |
289 | TEST(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 | |
308 | TEST(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 | |
335 | TEST(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 | |
362 | TEST(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 | |
389 | TEST(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 | |
437 | TEST(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 | |
474 | TEST(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 | |
485 | TEST(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 | |
520 | TEST(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 | |
530 | class 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 | */ |
555 | TEST(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 | |
578 | TEST(Expected, Exceptions) { |
579 | Expected<int, E> empty; |
580 | EXPECT_THROW(empty.value(), Unexpected<E>::BadExpectedAccess); |
581 | } |
582 | |
583 | struct 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 | |
591 | TEST(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 | |
602 | TEST(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 | |
610 | TEST(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 | |
618 | struct 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 | |
637 | TEST(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 | |
647 | struct NoDestructor {}; |
648 | |
649 | struct WithDestructor { |
650 | ~WithDestructor(); |
651 | }; |
652 | |
653 | TEST(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 | |
663 | struct NoConstructor {}; |
664 | |
665 | struct 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) |
672 | TEST(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 | |
687 | TEST(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 | |
759 | TEST(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 | |