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/GTest.h>
25 #include <type_traits>
26 #include <unordered_map>
29 #include <boost/optional.hpp>
31 using std::unique_ptr;
32 using std::shared_ptr;
37 std::ostream& operator<<(std::ostream& os, const Optional<V>& v) {
39 os << "Optional(" << v.value() << ')';
47 NoDefault(int, int) {}
51 static_assert(sizeof(Optional<char>) == 2, "");
52 static_assert(sizeof(Optional<int>) == 8, "");
53 static_assert(sizeof(Optional<NoDefault>) == 4, "");
54 static_assert(sizeof(Optional<char>) == sizeof(boost::optional<char>), "");
55 static_assert(sizeof(Optional<short>) == sizeof(boost::optional<short>), "");
56 static_assert(sizeof(Optional<int>) == sizeof(boost::optional<int>), "");
57 static_assert(sizeof(Optional<double>) == sizeof(boost::optional<double>), "");
59 TEST(Optional, NoDefault) {
60 Optional<NoDefault> x;
68 TEST(Optional, String) {
69 Optional<std::string> maybeString;
70 EXPECT_FALSE(maybeString);
71 maybeString = "hello";
72 EXPECT_TRUE(bool(maybeString));
75 TEST(Optional, Const) {
76 { // default construct
77 Optional<const int> opt;
78 EXPECT_FALSE(bool(opt));
84 EXPECT_FALSE(bool(opt));
88 Optional<const int> opt(x);
93 Optional<const int> opt(std::move(x));
96 // no assignment allowed
99 TEST(Optional, Simple) {
101 EXPECT_FALSE(bool(opt));
102 EXPECT_EQ(42, opt.value_or(42));
104 EXPECT_TRUE(bool(opt));
106 EXPECT_EQ(4, opt.value_or(42));
110 EXPECT_FALSE(bool(opt));
115 /* implicit */ MoveTester(const char* s) : s_(s) {}
116 MoveTester(const MoveTester&) = default;
117 MoveTester(MoveTester&& other) noexcept {
118 s_ = std::move(other.s_);
121 MoveTester& operator=(const MoveTester&) = default;
122 MoveTester& operator=(MoveTester&& other) noexcept {
123 s_ = std::move(other.s_);
128 friend bool operator==(const MoveTester& o1, const MoveTester& o2);
132 bool operator==(const MoveTester& o1, const MoveTester& o2) {
133 return o1.s_ == o2.s_;
136 TEST(Optional, value_or_rvalue_arg) {
137 Optional<MoveTester> opt;
138 MoveTester dflt = "hello";
139 EXPECT_EQ("hello", opt.value_or(dflt));
140 EXPECT_EQ("hello", dflt);
141 EXPECT_EQ("hello", opt.value_or(std::move(dflt)));
143 EXPECT_EQ("world", opt.value_or("world"));
146 // Make sure that the const overload works on const objects
147 const auto& optc = opt;
148 EXPECT_EQ("hello", optc.value_or(dflt));
149 EXPECT_EQ("hello", dflt);
150 EXPECT_EQ("hello", optc.value_or(std::move(dflt)));
152 EXPECT_EQ("world", optc.value_or("world"));
156 EXPECT_EQ("meow", opt.value_or(dflt));
157 EXPECT_EQ("hello", dflt);
158 EXPECT_EQ("meow", opt.value_or(std::move(dflt)));
159 EXPECT_EQ("hello", dflt); // only moved if used
162 TEST(Optional, value_or_noncopyable) {
163 Optional<std::unique_ptr<int>> opt;
164 std::unique_ptr<int> dflt(new int(42));
165 EXPECT_EQ(42, *std::move(opt).value_or(std::move(dflt)));
168 struct ExpectingDeleter {
169 explicit ExpectingDeleter(int expected) : expected(expected) { }
171 void operator()(const int* ptr) {
172 EXPECT_EQ(*ptr, expected);
177 TEST(Optional, value_move) {
178 auto ptr = Optional<std::unique_ptr<int, ExpectingDeleter>>(
179 {new int(42), ExpectingDeleter{1337}}).value();
183 TEST(Optional, dereference_move) {
184 auto ptr = *Optional<std::unique_ptr<int, ExpectingDeleter>>(
185 {new int(42), ExpectingDeleter{1337}});
189 TEST(Optional, EmptyConstruct) {
191 EXPECT_FALSE(bool(opt));
192 Optional<int> test1(opt);
193 EXPECT_FALSE(bool(test1));
194 Optional<int> test2(std::move(opt));
195 EXPECT_FALSE(bool(test2));
198 TEST(Optional, InPlaceConstruct) {
199 using A = std::pair<int, double>;
200 Optional<A> opt(in_place, 5, 3.2);
201 EXPECT_TRUE(bool(opt));
202 EXPECT_EQ(5, opt->first);
205 TEST(Optional, InPlaceNestedConstruct) {
206 using A = std::pair<int, double>;
207 Optional<Optional<A>> opt(in_place, in_place, 5, 3.2);
208 EXPECT_TRUE(bool(opt));
209 EXPECT_TRUE(bool(*opt));
210 EXPECT_EQ(5, (*opt)->first);
213 TEST(Optional, Unique) {
214 Optional<unique_ptr<int>> opt;
217 EXPECT_FALSE(bool(opt));
219 opt.emplace(new int(5));
220 EXPECT_TRUE(bool(opt));
225 opt = unique_ptr<int>(new int(6));
228 opt = unique_ptr<int>(new int(7));
231 // move it out by move construct
232 Optional<unique_ptr<int>> moved(std::move(opt));
233 EXPECT_TRUE(bool(moved));
234 EXPECT_FALSE(bool(opt));
235 EXPECT_EQ(7, **moved);
237 EXPECT_TRUE(bool(moved));
238 opt = std::move(moved); // move it back by move assign
239 EXPECT_FALSE(bool(moved));
240 EXPECT_TRUE(bool(opt));
244 TEST(Optional, Shared) {
246 Optional<shared_ptr<int>> opt;
247 EXPECT_FALSE(bool(opt));
249 opt.emplace(new int(5));
250 EXPECT_TRUE(bool(opt));
252 EXPECT_EQ(ptr.get(), opt->get());
253 EXPECT_EQ(2, ptr.use_count());
255 EXPECT_EQ(1, ptr.use_count());
258 EXPECT_EQ(2, ptr.use_count());
259 EXPECT_EQ(ptr.get(), opt->get());
261 EXPECT_EQ(1, ptr.use_count());
263 opt = std::move(ptr);
264 EXPECT_EQ(1, opt->use_count());
265 EXPECT_EQ(nullptr, ptr.get());
267 Optional<shared_ptr<int>> copied(opt);
268 EXPECT_EQ(2, opt->use_count());
269 Optional<shared_ptr<int>> moved(std::move(opt));
270 EXPECT_EQ(2, moved->use_count());
271 moved.emplace(new int(6));
272 EXPECT_EQ(1, moved->use_count());
274 EXPECT_EQ(2, moved->use_count());
278 TEST(Optional, Order) {
279 std::vector<Optional<int>> vect{
286 std::vector<Optional<int>> expected {
293 std::sort(vect.begin(), vect.end());
294 EXPECT_EQ(vect, expected);
297 TEST(Optional, Swap) {
298 Optional<std::string> a;
299 Optional<std::string> b;
302 EXPECT_FALSE(a.hasValue());
303 EXPECT_FALSE(b.hasValue());
306 EXPECT_TRUE(a.hasValue());
307 EXPECT_FALSE(b.hasValue());
308 EXPECT_EQ("hello", a.value());
311 EXPECT_FALSE(a.hasValue());
312 EXPECT_TRUE(b.hasValue());
313 EXPECT_EQ("hello", b.value());
316 EXPECT_TRUE(a.hasValue());
317 EXPECT_EQ("bye", a.value());
322 TEST(Optional, Comparisons) {
327 EXPECT_TRUE(o_ <= (o_));
328 EXPECT_TRUE(o_ == (o_));
329 EXPECT_TRUE(o_ >= (o_));
331 EXPECT_TRUE(o1 < o2);
332 EXPECT_TRUE(o1 <= o2);
333 EXPECT_TRUE(o1 <= (o1));
334 EXPECT_TRUE(o1 == (o1));
335 EXPECT_TRUE(o1 != o2);
336 EXPECT_TRUE(o1 >= (o1));
337 EXPECT_TRUE(o2 >= o1);
338 EXPECT_TRUE(o2 > o1);
340 EXPECT_FALSE(o2 < o1);
341 EXPECT_FALSE(o2 <= o1);
342 EXPECT_FALSE(o2 <= o1);
343 EXPECT_FALSE(o2 == o1);
344 EXPECT_FALSE(o1 != (o1));
345 EXPECT_FALSE(o1 >= o2);
346 EXPECT_FALSE(o1 >= o2);
347 EXPECT_FALSE(o1 > o2);
349 /* folly::Optional explicitly doesn't support comparisons with contained value
351 EXPECT_TRUE(1 <= o2);
352 EXPECT_TRUE(1 <= o1);
353 EXPECT_TRUE(1 == o1);
354 EXPECT_TRUE(2 != o1);
355 EXPECT_TRUE(1 >= o1);
356 EXPECT_TRUE(2 >= o1);
359 EXPECT_FALSE(o2 < 1);
360 EXPECT_FALSE(o2 <= 1);
361 EXPECT_FALSE(o2 <= 1);
362 EXPECT_FALSE(o2 == 1);
363 EXPECT_FALSE(o2 != 2);
364 EXPECT_FALSE(o1 >= 2);
365 EXPECT_FALSE(o1 >= 2);
366 EXPECT_FALSE(o1 > 2);
369 // boost::optional does support comparison with contained value, which can
370 // lead to confusion when a bool is contained
371 boost::optional<int> boi(3);
372 EXPECT_TRUE(boi < 5);
373 EXPECT_TRUE(boi <= 4);
374 EXPECT_TRUE(boi == 3);
375 EXPECT_TRUE(boi != 2);
376 EXPECT_TRUE(boi >= 1);
377 EXPECT_TRUE(boi > 0);
378 EXPECT_TRUE(1 < boi);
379 EXPECT_TRUE(2 <= boi);
380 EXPECT_TRUE(3 == boi);
381 EXPECT_TRUE(4 != boi);
382 EXPECT_TRUE(5 >= boi);
383 EXPECT_TRUE(6 > boi);
385 boost::optional<bool> bob(false);
386 EXPECT_TRUE((bool)bob);
387 EXPECT_TRUE(bob == false); // well that was confusing
388 EXPECT_FALSE(bob != false);
391 TEST(Optional, HeterogeneousComparisons) {
392 using opt8 = Optional<uint8_t>;
393 using opt64 = Optional<uint64_t>;
395 EXPECT_TRUE(opt8(4) == uint64_t(4));
396 EXPECT_FALSE(opt8(8) == uint64_t(4));
397 EXPECT_FALSE(opt8() == uint64_t(4));
399 EXPECT_TRUE(uint64_t(4) == opt8(4));
400 EXPECT_FALSE(uint64_t(4) == opt8(8));
401 EXPECT_FALSE(uint64_t(4) == opt8());
403 EXPECT_FALSE(opt8(4) != uint64_t(4));
404 EXPECT_TRUE(opt8(8) != uint64_t(4));
405 EXPECT_TRUE(opt8() != uint64_t(4));
407 EXPECT_FALSE(uint64_t(4) != opt8(4));
408 EXPECT_TRUE(uint64_t(4) != opt8(8));
409 EXPECT_TRUE(uint64_t(4) != opt8());
411 EXPECT_TRUE(opt8() == opt64());
412 EXPECT_TRUE(opt8(4) == opt64(4));
413 EXPECT_FALSE(opt8(8) == opt64(4));
414 EXPECT_FALSE(opt8() == opt64(4));
415 EXPECT_FALSE(opt8(4) == opt64());
417 EXPECT_FALSE(opt8() != opt64());
418 EXPECT_FALSE(opt8(4) != opt64(4));
419 EXPECT_TRUE(opt8(8) != opt64(4));
420 EXPECT_TRUE(opt8() != opt64(4));
421 EXPECT_TRUE(opt8(4) != opt64());
423 EXPECT_TRUE(opt8() < opt64(4));
424 EXPECT_TRUE(opt8(4) < opt64(8));
425 EXPECT_FALSE(opt8() < opt64());
426 EXPECT_FALSE(opt8(4) < opt64(4));
427 EXPECT_FALSE(opt8(8) < opt64(4));
428 EXPECT_FALSE(opt8(4) < opt64());
430 EXPECT_FALSE(opt8() > opt64(4));
431 EXPECT_FALSE(opt8(4) > opt64(8));
432 EXPECT_FALSE(opt8() > opt64());
433 EXPECT_FALSE(opt8(4) > opt64(4));
434 EXPECT_TRUE(opt8(8) > opt64(4));
435 EXPECT_TRUE(opt8(4) > opt64());
437 EXPECT_TRUE(opt8() <= opt64(4));
438 EXPECT_TRUE(opt8(4) <= opt64(8));
439 EXPECT_TRUE(opt8() <= opt64());
440 EXPECT_TRUE(opt8(4) <= opt64(4));
441 EXPECT_FALSE(opt8(8) <= opt64(4));
442 EXPECT_FALSE(opt8(4) <= opt64());
444 EXPECT_FALSE(opt8() >= opt64(4));
445 EXPECT_FALSE(opt8(4) >= opt64(8));
446 EXPECT_TRUE(opt8() >= opt64());
447 EXPECT_TRUE(opt8(4) >= opt64(4));
448 EXPECT_TRUE(opt8(8) >= opt64(4));
449 EXPECT_TRUE(opt8(4) >= opt64());
452 TEST(Optional, Conversions) {
453 Optional<bool> mbool;
454 Optional<short> mshort;
455 Optional<char*> mstr;
458 //These don't compile
467 // intended explicit operator bool, for if (opt).
471 // Truthy tests work and are not ambiguous
472 if (mbool && mshort && mstr && mint) { // only checks not-empty
473 if (*mbool && *mshort && *mstr && *mint) { // only checks value
479 EXPECT_TRUE(bool(mbool));
480 EXPECT_FALSE(*mbool);
483 EXPECT_TRUE(bool(mbool));
487 EXPECT_FALSE(bool(mbool));
489 // No conversion allowed; does not compile
490 // EXPECT_TRUE(mbool == false);
493 TEST(Optional, Pointee) {
495 EXPECT_FALSE(get_pointer(x));
497 EXPECT_TRUE(get_pointer(x));
499 EXPECT_TRUE(*x == 2);
501 EXPECT_FALSE(get_pointer(x));
504 TEST(Optional, MakeOptional) {
505 // const L-value version
506 const std::string s("abc");
507 auto optStr = make_optional(s);
508 ASSERT_TRUE(optStr.hasValue());
509 EXPECT_EQ(*optStr, "abc");
512 EXPECT_EQ(*optStr, "cde");
515 std::string s2("abc");
516 auto optStr2 = make_optional(s2);
517 ASSERT_TRUE(optStr2.hasValue());
518 EXPECT_EQ(*optStr2, "abc");
520 // it's vital to check that s2 wasn't clobbered
521 EXPECT_EQ(s2, "abc");
523 // L-value reference version
525 auto optStr3 = make_optional(s3);
526 ASSERT_TRUE(optStr3.hasValue());
527 EXPECT_EQ(*optStr3, "abc");
529 EXPECT_EQ(s3, "abc");
531 // R-value ref version
532 unique_ptr<int> pInt(new int(3));
533 auto optIntPtr = make_optional(std::move(pInt));
534 EXPECT_TRUE(pInt.get() == nullptr);
535 ASSERT_TRUE(optIntPtr.hasValue());
536 EXPECT_EQ(**optIntPtr, 3);
539 #if __CLANG_PREREQ(3, 6)
540 # pragma clang diagnostic push
541 # pragma clang diagnostic ignored "-Wself-move"
544 TEST(Optional, SelfAssignment) {
545 Optional<int> a = 42;
547 ASSERT_TRUE(a.hasValue() && a.value() == 42);
549 Optional<int> b = 23333333;
551 ASSERT_TRUE(b.hasValue() && b.value() == 23333333);
554 #if __CLANG_PREREQ(3, 6)
555 # pragma clang diagnostic pop
558 class ContainsOptional {
560 ContainsOptional() { }
561 explicit ContainsOptional(int x) : opt_(x) { }
562 bool hasValue() const { return opt_.hasValue(); }
563 int value() const { return opt_.value(); }
565 ContainsOptional(const ContainsOptional &other) = default;
566 ContainsOptional& operator=(const ContainsOptional &other) = default;
567 ContainsOptional(ContainsOptional &&other) = default;
568 ContainsOptional& operator=(ContainsOptional &&other) = default;
575 * Test that a class containing an Optional can be copy and move assigned.
576 * This was broken under gcc 4.7 until assignment operators were explicitly
579 TEST(Optional, AssignmentContained) {
581 ContainsOptional source(5), target;
583 EXPECT_TRUE(target.hasValue());
584 EXPECT_EQ(5, target.value());
588 ContainsOptional source(5), target;
589 target = std::move(source);
590 EXPECT_TRUE(target.hasValue());
591 EXPECT_EQ(5, target.value());
592 EXPECT_FALSE(source.hasValue());
596 ContainsOptional opt_uninit, target(10);
598 EXPECT_FALSE(target.hasValue());
602 TEST(Optional, Exceptions) {
604 EXPECT_THROW(empty.value(), OptionalEmptyException);
607 TEST(Optional, NoThrowDefaultConstructible) {
608 EXPECT_TRUE(std::is_nothrow_default_constructible<Optional<bool>>::value);
611 struct NoDestructor {};
613 struct WithDestructor {
617 TEST(Optional, TriviallyDestructible) {
618 // These could all be static_asserts but EXPECT_* give much nicer output on
620 EXPECT_TRUE(std::is_trivially_destructible<Optional<NoDestructor>>::value);
621 EXPECT_TRUE(std::is_trivially_destructible<Optional<int>>::value);
622 EXPECT_FALSE(std::is_trivially_destructible<Optional<WithDestructor>>::value);
625 TEST(Optional, Hash) {
626 // Test it's usable in std::unordered map (compile time check)
627 std::unordered_map<Optional<int>, Optional<int>> obj;
628 // Also check the std::hash template can be instantiated by the compiler
629 std::hash<Optional<int>>()(none);
630 std::hash<Optional<int>>()(3);