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