Flesh out Optional members swap, reset, emplace, has_value
[folly.git] / folly / test / OptionalTest.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/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 <iomanip>
24 #include <memory>
25 #include <string>
26 #include <type_traits>
27 #include <unordered_map>
28 #include <vector>
29
30 #include <boost/optional.hpp>
31
32 using std::unique_ptr;
33 using std::shared_ptr;
34
35 namespace folly {
36
37 template <class V>
38 std::ostream& operator<<(std::ostream& os, const Optional<V>& v) {
39   if (v) {
40     os << "Optional(" << v.value() << ')';
41   } else {
42     os << "None";
43   }
44   return os;
45 }
46
47 struct NoDefault {
48   NoDefault(int, int) {}
49   char a, b, c;
50 };
51
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>), "");
59
60 TEST(Optional, NoDefault) {
61   Optional<NoDefault> x;
62   EXPECT_FALSE(x);
63   x.emplace(4, 5);
64   EXPECT_TRUE(bool(x));
65   x.clear();
66   EXPECT_FALSE(x);
67 }
68
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));
75 }
76
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));
83 }
84
85 TEST(Optional, Reset) {
86   Optional<int> opt(3);
87   opt.reset();
88   EXPECT_FALSE(opt);
89 }
90
91 TEST(Optional, String) {
92   Optional<std::string> maybeString;
93   EXPECT_FALSE(maybeString);
94   maybeString = "hello";
95   EXPECT_TRUE(bool(maybeString));
96 }
97
98 TEST(Optional, Const) {
99   { // default construct
100     Optional<const int> opt;
101     EXPECT_FALSE(bool(opt));
102     opt.emplace(4);
103     EXPECT_EQ(*opt, 4);
104     opt.emplace(5);
105     EXPECT_EQ(*opt, 5);
106     opt.clear();
107     EXPECT_FALSE(bool(opt));
108   }
109   { // copy-constructed
110     const int x = 6;
111     Optional<const int> opt(x);
112     EXPECT_EQ(*opt, 6);
113   }
114   { // move-constructed
115     const int x = 7;
116     Optional<const int> opt(std::move(x));
117     EXPECT_EQ(*opt, 7);
118   }
119   // no assignment allowed
120 }
121
122 TEST(Optional, Simple) {
123   Optional<int> opt;
124   EXPECT_FALSE(bool(opt));
125   EXPECT_EQ(42, opt.value_or(42));
126   opt = 4;
127   EXPECT_TRUE(bool(opt));
128   EXPECT_EQ(4, *opt);
129   EXPECT_EQ(4, opt.value_or(42));
130   opt = 5;
131   EXPECT_EQ(5, *opt);
132   opt.clear();
133   EXPECT_FALSE(bool(opt));
134 }
135
136 class MoveTester {
137  public:
138   /* implicit */ MoveTester(const char* s) : s_(s) {}
139   MoveTester(const MoveTester&) = default;
140   MoveTester(MoveTester&& other) noexcept {
141     s_ = std::move(other.s_);
142     other.s_ = "";
143   }
144   MoveTester& operator=(const MoveTester&) = default;
145   MoveTester& operator=(MoveTester&& other) noexcept {
146     s_ = std::move(other.s_);
147     other.s_ = "";
148     return *this;
149   }
150
151  private:
152   friend bool operator==(const MoveTester& o1, const MoveTester& o2);
153   std::string s_;
154 };
155
156 bool operator==(const MoveTester& o1, const MoveTester& o2) {
157   return o1.s_ == o2.s_;
158 }
159
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)));
166   EXPECT_EQ("", dflt);
167   EXPECT_EQ("world", opt.value_or("world"));
168
169   dflt = "hello";
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)));
175   EXPECT_EQ("", dflt);
176   EXPECT_EQ("world", optc.value_or("world"));
177
178   dflt = "hello";
179   opt = "meow";
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
184 }
185
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)));
190 }
191
192 struct ExpectingDeleter {
193   explicit ExpectingDeleter(int expected) : expected(expected) { }
194   int expected;
195   void operator()(const int* ptr) {
196     EXPECT_EQ(*ptr, expected);
197     delete ptr;
198   }
199 };
200
201 TEST(Optional, value_move) {
202   auto ptr = Optional<std::unique_ptr<int, ExpectingDeleter>>(
203       {new int(42), ExpectingDeleter{1337}}).value();
204   *ptr = 1337;
205 }
206
207 TEST(Optional, dereference_move) {
208   auto ptr = *Optional<std::unique_ptr<int, ExpectingDeleter>>(
209       {new int(42), ExpectingDeleter{1337}});
210   *ptr = 1337;
211 }
212
213 TEST(Optional, EmptyConstruct) {
214   Optional<int> opt;
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));
220 }
221
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);
227 }
228
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);
235 }
236
237 TEST(Optional, Unique) {
238   Optional<unique_ptr<int>> opt;
239
240   opt.clear();
241   EXPECT_FALSE(bool(opt));
242   // empty->emplaced
243   opt.emplace(new int(5));
244   EXPECT_TRUE(bool(opt));
245   EXPECT_EQ(5, **opt);
246
247   opt.clear();
248   // empty->moved
249   opt = std::make_unique<int>(6);
250   EXPECT_EQ(6, **opt);
251   // full->moved
252   opt = std::make_unique<int>(7);
253   EXPECT_EQ(7, **opt);
254
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);
260
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));
265   EXPECT_EQ(7, **opt);
266 }
267
268 TEST(Optional, Shared) {
269   shared_ptr<int> ptr;
270   Optional<shared_ptr<int>> opt;
271   EXPECT_FALSE(bool(opt));
272   // empty->emplaced
273   opt.emplace(new int(5));
274   EXPECT_TRUE(bool(opt));
275   ptr = opt.value();
276   EXPECT_EQ(ptr.get(), opt->get());
277   EXPECT_EQ(2, ptr.use_count());
278   opt.clear();
279   EXPECT_EQ(1, ptr.use_count());
280   // full->copied
281   opt = ptr;
282   EXPECT_EQ(2, ptr.use_count());
283   EXPECT_EQ(ptr.get(), opt->get());
284   opt.clear();
285   EXPECT_EQ(1, ptr.use_count());
286   // full->moved
287   opt = std::move(ptr);
288   EXPECT_EQ(1, opt->use_count());
289   EXPECT_EQ(nullptr, ptr.get());
290   {
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());
297     copied = moved;
298     EXPECT_EQ(2, moved->use_count());
299   }
300 }
301
302 TEST(Optional, Order) {
303   std::vector<Optional<int>> vect{
304     { none },
305     { 3 },
306     { 1 },
307     { none },
308     { 2 },
309   };
310   std::vector<Optional<int>> expected {
311     { none },
312     { none },
313     { 1 },
314     { 2 },
315     { 3 },
316   };
317   std::sort(vect.begin(), vect.end());
318   EXPECT_EQ(vect, expected);
319 }
320
321 TEST(Optional, Swap) {
322   Optional<std::string> a;
323   Optional<std::string> b;
324
325   swap(a, b);
326   EXPECT_FALSE(a.hasValue());
327   EXPECT_FALSE(b.hasValue());
328
329   a = "hello";
330   EXPECT_TRUE(a.hasValue());
331   EXPECT_FALSE(b.hasValue());
332   EXPECT_EQ("hello", a.value());
333
334   swap(a, b);
335   EXPECT_FALSE(a.hasValue());
336   EXPECT_TRUE(b.hasValue());
337   EXPECT_EQ("hello", b.value());
338
339   a = "bye";
340   EXPECT_TRUE(a.hasValue());
341   EXPECT_EQ("bye", a.value());
342
343   swap(a, b);
344   EXPECT_TRUE(a.hasValue());
345   EXPECT_TRUE(b.hasValue());
346   EXPECT_EQ("hello", a.value());
347   EXPECT_EQ("bye", b.value());
348 }
349
350 TEST(Optional, Comparisons) {
351   Optional<int> o_;
352   Optional<int> o1(1);
353   Optional<int> o2(2);
354
355   EXPECT_TRUE(o_ <= (o_));
356   EXPECT_TRUE(o_ == (o_));
357   EXPECT_TRUE(o_ >= (o_));
358
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);
367
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);
376
377   /* folly::Optional explicitly doesn't support comparisons with contained value
378   EXPECT_TRUE(1 < o2);
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);
385   EXPECT_TRUE(2 > o1);
386
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);
395   */
396
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);
412
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);
417 }
418
419 TEST(Optional, HeterogeneousComparisons) {
420   using opt8 = Optional<uint8_t>;
421   using opt64 = Optional<uint64_t>;
422
423   EXPECT_TRUE(opt8(4) == uint64_t(4));
424   EXPECT_FALSE(opt8(8) == uint64_t(4));
425   EXPECT_FALSE(opt8() == uint64_t(4));
426
427   EXPECT_TRUE(uint64_t(4) == opt8(4));
428   EXPECT_FALSE(uint64_t(4) == opt8(8));
429   EXPECT_FALSE(uint64_t(4) == opt8());
430
431   EXPECT_FALSE(opt8(4) != uint64_t(4));
432   EXPECT_TRUE(opt8(8) != uint64_t(4));
433   EXPECT_TRUE(opt8() != uint64_t(4));
434
435   EXPECT_FALSE(uint64_t(4) != opt8(4));
436   EXPECT_TRUE(uint64_t(4) != opt8(8));
437   EXPECT_TRUE(uint64_t(4) != opt8());
438
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());
444
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());
450
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());
457
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());
464
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());
471
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());
478 }
479
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));
486
487   EXPECT_FALSE(opt() != none);
488   EXPECT_FALSE(none != opt());
489   EXPECT_TRUE(opt(1) != none);
490   EXPECT_TRUE(none != opt(1));
491
492   EXPECT_FALSE(opt() < none);
493   EXPECT_FALSE(none < opt());
494   EXPECT_FALSE(opt(1) < none);
495   EXPECT_TRUE(none < opt(1));
496
497   EXPECT_FALSE(opt() > none);
498   EXPECT_FALSE(none > opt());
499   EXPECT_FALSE(none > opt(1));
500   EXPECT_TRUE(opt(1) > none);
501
502   EXPECT_TRUE(opt() <= none);
503   EXPECT_TRUE(none <= opt());
504   EXPECT_FALSE(opt(1) <= none);
505   EXPECT_TRUE(none <= opt(1));
506
507   EXPECT_TRUE(opt() >= none);
508   EXPECT_TRUE(none >= opt());
509   EXPECT_TRUE(opt(1) >= none);
510   EXPECT_FALSE(none >= opt(1));
511 }
512
513 TEST(Optional, Conversions) {
514   Optional<bool> mbool;
515   Optional<short> mshort;
516   Optional<char*> mstr;
517   Optional<int> mint;
518
519   //These don't compile
520   //bool b = mbool;
521   //short s = mshort;
522   //char* c = mstr;
523   //int x = mint;
524   //char* c(mstr);
525   //short s(mshort);
526   //int x(mint);
527
528   // intended explicit operator bool, for if (opt).
529   bool b(mbool);
530   EXPECT_FALSE(b);
531
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
535       ;
536     }
537   }
538
539   mbool = false;
540   EXPECT_TRUE(bool(mbool));
541   EXPECT_FALSE(*mbool);
542
543   mbool = true;
544   EXPECT_TRUE(bool(mbool));
545   EXPECT_TRUE(*mbool);
546
547   mbool = none;
548   EXPECT_FALSE(bool(mbool));
549
550   // No conversion allowed; does not compile
551   // EXPECT_TRUE(mbool == false);
552 }
553
554 TEST(Optional, Pointee) {
555   Optional<int> x;
556   EXPECT_FALSE(get_pointer(x));
557   x = 1;
558   EXPECT_TRUE(get_pointer(x));
559   *get_pointer(x) = 2;
560   EXPECT_TRUE(*x == 2);
561   x = none;
562   EXPECT_FALSE(get_pointer(x));
563 }
564
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");
571   *optStr = "cde";
572   EXPECT_EQ(s, "abc");
573   EXPECT_EQ(*optStr, "cde");
574
575   // L-value version
576   std::string s2("abc");
577   auto optStr2 = make_optional(s2);
578   ASSERT_TRUE(optStr2.hasValue());
579   EXPECT_EQ(*optStr2, "abc");
580   *optStr2 = "cde";
581   // it's vital to check that s2 wasn't clobbered
582   EXPECT_EQ(s2, "abc");
583
584   // L-value reference version
585   std::string& s3(s2);
586   auto optStr3 = make_optional(s3);
587   ASSERT_TRUE(optStr3.hasValue());
588   EXPECT_EQ(*optStr3, "abc");
589   *optStr3 = "cde";
590   EXPECT_EQ(s3, "abc");
591
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);
598 }
599
600 #if __CLANG_PREREQ(3, 6)
601 # pragma clang diagnostic push
602 # pragma clang diagnostic ignored "-Wself-move"
603 #endif
604
605 TEST(Optional, SelfAssignment) {
606   Optional<int> a = 42;
607   a = a;
608   ASSERT_TRUE(a.hasValue() && a.value() == 42);
609
610   Optional<int> b = 23333333;
611   b = std::move(b);
612   ASSERT_TRUE(b.hasValue() && b.value() == 23333333);
613 }
614
615 #if __CLANG_PREREQ(3, 6)
616 # pragma clang diagnostic pop
617 #endif
618
619 class ContainsOptional {
620  public:
621   ContainsOptional() { }
622   explicit ContainsOptional(int x) : opt_(x) { }
623   bool hasValue() const { return opt_.hasValue(); }
624   int value() const { return opt_.value(); }
625
626   ContainsOptional(const ContainsOptional &other) = default;
627   ContainsOptional& operator=(const ContainsOptional &other) = default;
628   ContainsOptional(ContainsOptional &&other) = default;
629   ContainsOptional& operator=(ContainsOptional &&other) = default;
630
631  private:
632   Optional<int> opt_;
633 };
634
635 /**
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
638  * defined.
639  */
640 TEST(Optional, AssignmentContained) {
641   {
642     ContainsOptional source(5), target;
643     target = source;
644     EXPECT_TRUE(target.hasValue());
645     EXPECT_EQ(5, target.value());
646   }
647
648   {
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());
654   }
655
656   {
657     ContainsOptional opt_uninit, target(10);
658     target = opt_uninit;
659     EXPECT_FALSE(target.hasValue());
660   }
661 }
662
663 TEST(Optional, Exceptions) {
664   Optional<int> empty;
665   EXPECT_THROW(empty.value(), OptionalEmptyException);
666 }
667
668 TEST(Optional, NoThrowDefaultConstructible) {
669   EXPECT_TRUE(std::is_nothrow_default_constructible<Optional<bool>>::value);
670 }
671
672 struct NoDestructor {};
673
674 struct WithDestructor {
675   ~WithDestructor();
676 };
677
678 TEST(Optional, TriviallyDestructible) {
679   // These could all be static_asserts but EXPECT_* give much nicer output on
680   // failure.
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);
684 }
685
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);
692 }
693 } // namespace folly