2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/Optional.h>
18 #include <folly/Portability.h>
19 #include <folly/portability/GMock.h>
20 #include <folly/portability/GTest.h>
26 #include <type_traits>
27 #include <unordered_map>
30 #include <boost/optional.hpp>
32 using std::unique_ptr;
33 using std::shared_ptr;
38 std::ostream& operator<<(std::ostream& os, const Optional<V>& v) {
40 os << "Optional(" << v.value() << ')';
48 NoDefault(int, int) {}
52 static_assert(sizeof(Optional<char>) == 2, "");
53 static_assert(sizeof(Optional<int>) == 8, "");
54 static_assert(sizeof(Optional<NoDefault>) == 4, "");
55 static_assert(sizeof(Optional<char>) == sizeof(boost::optional<char>), "");
56 static_assert(sizeof(Optional<short>) == sizeof(boost::optional<short>), "");
57 static_assert(sizeof(Optional<int>) == sizeof(boost::optional<int>), "");
58 static_assert(sizeof(Optional<double>) == sizeof(boost::optional<double>), "");
60 TEST(Optional, NoDefault) {
61 Optional<NoDefault> x;
69 TEST(Optional, Emplace) {
70 Optional<std::vector<int>> opt;
71 auto& values1 = opt.emplace(3, 4);
72 EXPECT_THAT(values1, testing::ElementsAre(4, 4, 4));
73 auto& values2 = opt.emplace(2, 5);
74 EXPECT_THAT(values2, testing::ElementsAre(5, 5));
77 TEST(Optional, EmplaceInitializerList) {
78 Optional<std::vector<int>> opt;
79 auto& values1 = opt.emplace({3, 4, 5});
80 EXPECT_THAT(values1, testing::ElementsAre(3, 4, 5));
81 auto& values2 = opt.emplace({4, 5, 6});
82 EXPECT_THAT(values2, testing::ElementsAre(4, 5, 6));
85 TEST(Optional, Reset) {
91 TEST(Optional, String) {
92 Optional<std::string> maybeString;
93 EXPECT_FALSE(maybeString);
94 maybeString = "hello";
95 EXPECT_TRUE(bool(maybeString));
98 TEST(Optional, Const) {
99 { // default construct
100 Optional<const int> opt;
101 EXPECT_FALSE(bool(opt));
107 EXPECT_FALSE(bool(opt));
109 { // copy-constructed
111 Optional<const int> opt(x);
114 { // move-constructed
116 Optional<const int> opt(std::move(x));
119 // no assignment allowed
122 TEST(Optional, Simple) {
124 EXPECT_FALSE(bool(opt));
125 EXPECT_EQ(42, opt.value_or(42));
127 EXPECT_TRUE(bool(opt));
129 EXPECT_EQ(4, opt.value_or(42));
133 EXPECT_FALSE(bool(opt));
138 /* implicit */ MoveTester(const char* s) : s_(s) {}
139 MoveTester(const MoveTester&) = default;
140 MoveTester(MoveTester&& other) noexcept {
141 s_ = std::move(other.s_);
144 MoveTester& operator=(const MoveTester&) = default;
145 MoveTester& operator=(MoveTester&& other) noexcept {
146 s_ = std::move(other.s_);
152 friend bool operator==(const MoveTester& o1, const MoveTester& o2);
156 bool operator==(const MoveTester& o1, const MoveTester& o2) {
157 return o1.s_ == o2.s_;
160 TEST(Optional, value_or_rvalue_arg) {
161 Optional<MoveTester> opt;
162 MoveTester dflt = "hello";
163 EXPECT_EQ("hello", opt.value_or(dflt));
164 EXPECT_EQ("hello", dflt);
165 EXPECT_EQ("hello", opt.value_or(std::move(dflt)));
167 EXPECT_EQ("world", opt.value_or("world"));
170 // Make sure that the const overload works on const objects
171 const auto& optc = opt;
172 EXPECT_EQ("hello", optc.value_or(dflt));
173 EXPECT_EQ("hello", dflt);
174 EXPECT_EQ("hello", optc.value_or(std::move(dflt)));
176 EXPECT_EQ("world", optc.value_or("world"));
180 EXPECT_EQ("meow", opt.value_or(dflt));
181 EXPECT_EQ("hello", dflt);
182 EXPECT_EQ("meow", opt.value_or(std::move(dflt)));
183 EXPECT_EQ("hello", dflt); // only moved if used
186 TEST(Optional, value_or_noncopyable) {
187 Optional<std::unique_ptr<int>> opt;
188 std::unique_ptr<int> dflt(new int(42));
189 EXPECT_EQ(42, *std::move(opt).value_or(std::move(dflt)));
192 struct ExpectingDeleter {
193 explicit ExpectingDeleter(int expected) : expected(expected) { }
195 void operator()(const int* ptr) {
196 EXPECT_EQ(*ptr, expected);
201 TEST(Optional, value_move) {
202 auto ptr = Optional<std::unique_ptr<int, ExpectingDeleter>>(
203 {new int(42), ExpectingDeleter{1337}}).value();
207 TEST(Optional, dereference_move) {
208 auto ptr = *Optional<std::unique_ptr<int, ExpectingDeleter>>(
209 {new int(42), ExpectingDeleter{1337}});
213 TEST(Optional, EmptyConstruct) {
215 EXPECT_FALSE(bool(opt));
216 Optional<int> test1(opt);
217 EXPECT_FALSE(bool(test1));
218 Optional<int> test2(std::move(opt));
219 EXPECT_FALSE(bool(test2));
222 TEST(Optional, InPlaceConstruct) {
223 using A = std::pair<int, double>;
224 Optional<A> opt(in_place, 5, 3.2);
225 EXPECT_TRUE(bool(opt));
226 EXPECT_EQ(5, opt->first);
229 TEST(Optional, InPlaceNestedConstruct) {
230 using A = std::pair<int, double>;
231 Optional<Optional<A>> opt(in_place, in_place, 5, 3.2);
232 EXPECT_TRUE(bool(opt));
233 EXPECT_TRUE(bool(*opt));
234 EXPECT_EQ(5, (*opt)->first);
237 TEST(Optional, Unique) {
238 Optional<unique_ptr<int>> opt;
241 EXPECT_FALSE(bool(opt));
243 opt.emplace(new int(5));
244 EXPECT_TRUE(bool(opt));
249 opt = std::make_unique<int>(6);
252 opt = std::make_unique<int>(7);
255 // move it out by move construct
256 Optional<unique_ptr<int>> moved(std::move(opt));
257 EXPECT_TRUE(bool(moved));
258 EXPECT_FALSE(bool(opt));
259 EXPECT_EQ(7, **moved);
261 EXPECT_TRUE(bool(moved));
262 opt = std::move(moved); // move it back by move assign
263 EXPECT_FALSE(bool(moved));
264 EXPECT_TRUE(bool(opt));
268 TEST(Optional, Shared) {
270 Optional<shared_ptr<int>> opt;
271 EXPECT_FALSE(bool(opt));
273 opt.emplace(new int(5));
274 EXPECT_TRUE(bool(opt));
276 EXPECT_EQ(ptr.get(), opt->get());
277 EXPECT_EQ(2, ptr.use_count());
279 EXPECT_EQ(1, ptr.use_count());
282 EXPECT_EQ(2, ptr.use_count());
283 EXPECT_EQ(ptr.get(), opt->get());
285 EXPECT_EQ(1, ptr.use_count());
287 opt = std::move(ptr);
288 EXPECT_EQ(1, opt->use_count());
289 EXPECT_EQ(nullptr, ptr.get());
291 Optional<shared_ptr<int>> copied(opt);
292 EXPECT_EQ(2, opt->use_count());
293 Optional<shared_ptr<int>> moved(std::move(opt));
294 EXPECT_EQ(2, moved->use_count());
295 moved.emplace(new int(6));
296 EXPECT_EQ(1, moved->use_count());
298 EXPECT_EQ(2, moved->use_count());
302 TEST(Optional, Order) {
303 std::vector<Optional<int>> vect{
310 std::vector<Optional<int>> expected {
317 std::sort(vect.begin(), vect.end());
318 EXPECT_EQ(vect, expected);
321 TEST(Optional, Swap) {
322 Optional<std::string> a;
323 Optional<std::string> b;
326 EXPECT_FALSE(a.hasValue());
327 EXPECT_FALSE(b.hasValue());
330 EXPECT_TRUE(a.hasValue());
331 EXPECT_FALSE(b.hasValue());
332 EXPECT_EQ("hello", a.value());
335 EXPECT_FALSE(a.hasValue());
336 EXPECT_TRUE(b.hasValue());
337 EXPECT_EQ("hello", b.value());
340 EXPECT_TRUE(a.hasValue());
341 EXPECT_EQ("bye", a.value());
344 EXPECT_TRUE(a.hasValue());
345 EXPECT_TRUE(b.hasValue());
346 EXPECT_EQ("hello", a.value());
347 EXPECT_EQ("bye", b.value());
350 TEST(Optional, Comparisons) {
355 EXPECT_TRUE(o_ <= (o_));
356 EXPECT_TRUE(o_ == (o_));
357 EXPECT_TRUE(o_ >= (o_));
359 EXPECT_TRUE(o1 < o2);
360 EXPECT_TRUE(o1 <= o2);
361 EXPECT_TRUE(o1 <= (o1));
362 EXPECT_TRUE(o1 == (o1));
363 EXPECT_TRUE(o1 != o2);
364 EXPECT_TRUE(o1 >= (o1));
365 EXPECT_TRUE(o2 >= o1);
366 EXPECT_TRUE(o2 > o1);
368 EXPECT_FALSE(o2 < o1);
369 EXPECT_FALSE(o2 <= o1);
370 EXPECT_FALSE(o2 <= o1);
371 EXPECT_FALSE(o2 == o1);
372 EXPECT_FALSE(o1 != (o1));
373 EXPECT_FALSE(o1 >= o2);
374 EXPECT_FALSE(o1 >= o2);
375 EXPECT_FALSE(o1 > o2);
377 /* folly::Optional explicitly doesn't support comparisons with contained value
379 EXPECT_TRUE(1 <= o2);
380 EXPECT_TRUE(1 <= o1);
381 EXPECT_TRUE(1 == o1);
382 EXPECT_TRUE(2 != o1);
383 EXPECT_TRUE(1 >= o1);
384 EXPECT_TRUE(2 >= o1);
387 EXPECT_FALSE(o2 < 1);
388 EXPECT_FALSE(o2 <= 1);
389 EXPECT_FALSE(o2 <= 1);
390 EXPECT_FALSE(o2 == 1);
391 EXPECT_FALSE(o2 != 2);
392 EXPECT_FALSE(o1 >= 2);
393 EXPECT_FALSE(o1 >= 2);
394 EXPECT_FALSE(o1 > 2);
397 // boost::optional does support comparison with contained value, which can
398 // lead to confusion when a bool is contained
399 boost::optional<int> boi(3);
400 EXPECT_TRUE(boi < 5);
401 EXPECT_TRUE(boi <= 4);
402 EXPECT_TRUE(boi == 3);
403 EXPECT_TRUE(boi != 2);
404 EXPECT_TRUE(boi >= 1);
405 EXPECT_TRUE(boi > 0);
406 EXPECT_TRUE(1 < boi);
407 EXPECT_TRUE(2 <= boi);
408 EXPECT_TRUE(3 == boi);
409 EXPECT_TRUE(4 != boi);
410 EXPECT_TRUE(5 >= boi);
411 EXPECT_TRUE(6 > boi);
413 boost::optional<bool> bob(false);
414 EXPECT_TRUE((bool)bob);
415 EXPECT_TRUE(bob == false); // well that was confusing
416 EXPECT_FALSE(bob != false);
419 TEST(Optional, HeterogeneousComparisons) {
420 using opt8 = Optional<uint8_t>;
421 using opt64 = Optional<uint64_t>;
423 EXPECT_TRUE(opt8(4) == uint64_t(4));
424 EXPECT_FALSE(opt8(8) == uint64_t(4));
425 EXPECT_FALSE(opt8() == uint64_t(4));
427 EXPECT_TRUE(uint64_t(4) == opt8(4));
428 EXPECT_FALSE(uint64_t(4) == opt8(8));
429 EXPECT_FALSE(uint64_t(4) == opt8());
431 EXPECT_FALSE(opt8(4) != uint64_t(4));
432 EXPECT_TRUE(opt8(8) != uint64_t(4));
433 EXPECT_TRUE(opt8() != uint64_t(4));
435 EXPECT_FALSE(uint64_t(4) != opt8(4));
436 EXPECT_TRUE(uint64_t(4) != opt8(8));
437 EXPECT_TRUE(uint64_t(4) != opt8());
439 EXPECT_TRUE(opt8() == opt64());
440 EXPECT_TRUE(opt8(4) == opt64(4));
441 EXPECT_FALSE(opt8(8) == opt64(4));
442 EXPECT_FALSE(opt8() == opt64(4));
443 EXPECT_FALSE(opt8(4) == opt64());
445 EXPECT_FALSE(opt8() != opt64());
446 EXPECT_FALSE(opt8(4) != opt64(4));
447 EXPECT_TRUE(opt8(8) != opt64(4));
448 EXPECT_TRUE(opt8() != opt64(4));
449 EXPECT_TRUE(opt8(4) != opt64());
451 EXPECT_TRUE(opt8() < opt64(4));
452 EXPECT_TRUE(opt8(4) < opt64(8));
453 EXPECT_FALSE(opt8() < opt64());
454 EXPECT_FALSE(opt8(4) < opt64(4));
455 EXPECT_FALSE(opt8(8) < opt64(4));
456 EXPECT_FALSE(opt8(4) < opt64());
458 EXPECT_FALSE(opt8() > opt64(4));
459 EXPECT_FALSE(opt8(4) > opt64(8));
460 EXPECT_FALSE(opt8() > opt64());
461 EXPECT_FALSE(opt8(4) > opt64(4));
462 EXPECT_TRUE(opt8(8) > opt64(4));
463 EXPECT_TRUE(opt8(4) > opt64());
465 EXPECT_TRUE(opt8() <= opt64(4));
466 EXPECT_TRUE(opt8(4) <= opt64(8));
467 EXPECT_TRUE(opt8() <= opt64());
468 EXPECT_TRUE(opt8(4) <= opt64(4));
469 EXPECT_FALSE(opt8(8) <= opt64(4));
470 EXPECT_FALSE(opt8(4) <= opt64());
472 EXPECT_FALSE(opt8() >= opt64(4));
473 EXPECT_FALSE(opt8(4) >= opt64(8));
474 EXPECT_TRUE(opt8() >= opt64());
475 EXPECT_TRUE(opt8(4) >= opt64(4));
476 EXPECT_TRUE(opt8(8) >= opt64(4));
477 EXPECT_TRUE(opt8(4) >= opt64());
480 TEST(Optional, NoneComparisons) {
481 using opt = Optional<int>;
482 EXPECT_TRUE(opt() == none);
483 EXPECT_TRUE(none == opt());
484 EXPECT_FALSE(opt(1) == none);
485 EXPECT_FALSE(none == opt(1));
487 EXPECT_FALSE(opt() != none);
488 EXPECT_FALSE(none != opt());
489 EXPECT_TRUE(opt(1) != none);
490 EXPECT_TRUE(none != opt(1));
492 EXPECT_FALSE(opt() < none);
493 EXPECT_FALSE(none < opt());
494 EXPECT_FALSE(opt(1) < none);
495 EXPECT_TRUE(none < opt(1));
497 EXPECT_FALSE(opt() > none);
498 EXPECT_FALSE(none > opt());
499 EXPECT_FALSE(none > opt(1));
500 EXPECT_TRUE(opt(1) > none);
502 EXPECT_TRUE(opt() <= none);
503 EXPECT_TRUE(none <= opt());
504 EXPECT_FALSE(opt(1) <= none);
505 EXPECT_TRUE(none <= opt(1));
507 EXPECT_TRUE(opt() >= none);
508 EXPECT_TRUE(none >= opt());
509 EXPECT_TRUE(opt(1) >= none);
510 EXPECT_FALSE(none >= opt(1));
513 TEST(Optional, Conversions) {
514 Optional<bool> mbool;
515 Optional<short> mshort;
516 Optional<char*> mstr;
519 //These don't compile
528 // intended explicit operator bool, for if (opt).
532 // Truthy tests work and are not ambiguous
533 if (mbool && mshort && mstr && mint) { // only checks not-empty
534 if (*mbool && *mshort && *mstr && *mint) { // only checks value
540 EXPECT_TRUE(bool(mbool));
541 EXPECT_FALSE(*mbool);
544 EXPECT_TRUE(bool(mbool));
548 EXPECT_FALSE(bool(mbool));
550 // No conversion allowed; does not compile
551 // EXPECT_TRUE(mbool == false);
554 TEST(Optional, Pointee) {
556 EXPECT_FALSE(get_pointer(x));
558 EXPECT_TRUE(get_pointer(x));
560 EXPECT_TRUE(*x == 2);
562 EXPECT_FALSE(get_pointer(x));
565 TEST(Optional, MakeOptional) {
566 // const L-value version
567 const std::string s("abc");
568 auto optStr = make_optional(s);
569 ASSERT_TRUE(optStr.hasValue());
570 EXPECT_EQ(*optStr, "abc");
573 EXPECT_EQ(*optStr, "cde");
576 std::string s2("abc");
577 auto optStr2 = make_optional(s2);
578 ASSERT_TRUE(optStr2.hasValue());
579 EXPECT_EQ(*optStr2, "abc");
581 // it's vital to check that s2 wasn't clobbered
582 EXPECT_EQ(s2, "abc");
584 // L-value reference version
586 auto optStr3 = make_optional(s3);
587 ASSERT_TRUE(optStr3.hasValue());
588 EXPECT_EQ(*optStr3, "abc");
590 EXPECT_EQ(s3, "abc");
592 // R-value ref version
593 unique_ptr<int> pInt(new int(3));
594 auto optIntPtr = make_optional(std::move(pInt));
595 EXPECT_TRUE(pInt.get() == nullptr);
596 ASSERT_TRUE(optIntPtr.hasValue());
597 EXPECT_EQ(**optIntPtr, 3);
600 #if __CLANG_PREREQ(3, 6)
601 # pragma clang diagnostic push
602 # pragma clang diagnostic ignored "-Wself-move"
605 TEST(Optional, SelfAssignment) {
606 Optional<int> a = 42;
608 ASSERT_TRUE(a.hasValue() && a.value() == 42);
610 Optional<int> b = 23333333;
612 ASSERT_TRUE(b.hasValue() && b.value() == 23333333);
615 #if __CLANG_PREREQ(3, 6)
616 # pragma clang diagnostic pop
619 class ContainsOptional {
621 ContainsOptional() { }
622 explicit ContainsOptional(int x) : opt_(x) { }
623 bool hasValue() const { return opt_.hasValue(); }
624 int value() const { return opt_.value(); }
626 ContainsOptional(const ContainsOptional &other) = default;
627 ContainsOptional& operator=(const ContainsOptional &other) = default;
628 ContainsOptional(ContainsOptional &&other) = default;
629 ContainsOptional& operator=(ContainsOptional &&other) = default;
636 * Test that a class containing an Optional can be copy and move assigned.
637 * This was broken under gcc 4.7 until assignment operators were explicitly
640 TEST(Optional, AssignmentContained) {
642 ContainsOptional source(5), target;
644 EXPECT_TRUE(target.hasValue());
645 EXPECT_EQ(5, target.value());
649 ContainsOptional source(5), target;
650 target = std::move(source);
651 EXPECT_TRUE(target.hasValue());
652 EXPECT_EQ(5, target.value());
653 EXPECT_FALSE(source.hasValue());
657 ContainsOptional opt_uninit, target(10);
659 EXPECT_FALSE(target.hasValue());
663 TEST(Optional, Exceptions) {
665 EXPECT_THROW(empty.value(), OptionalEmptyException);
668 TEST(Optional, NoThrowDefaultConstructible) {
669 EXPECT_TRUE(std::is_nothrow_default_constructible<Optional<bool>>::value);
672 struct NoDestructor {};
674 struct WithDestructor {
678 TEST(Optional, TriviallyDestructible) {
679 // These could all be static_asserts but EXPECT_* give much nicer output on
681 EXPECT_TRUE(std::is_trivially_destructible<Optional<NoDestructor>>::value);
682 EXPECT_TRUE(std::is_trivially_destructible<Optional<int>>::value);
683 EXPECT_FALSE(std::is_trivially_destructible<Optional<WithDestructor>>::value);
686 TEST(Optional, Hash) {
687 // Test it's usable in std::unordered map (compile time check)
688 std::unordered_map<Optional<int>, Optional<int>> obj;
689 // Also check the std::hash template can be instantiated by the compiler
690 std::hash<Optional<int>>()(none);
691 std::hash<Optional<int>>()(3);