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/GTest.h>
24 #include <type_traits>
25 #include <unordered_map>
28 #include <boost/optional.hpp>
30 using std::unique_ptr;
31 using std::shared_ptr;
36 std::ostream& operator<<(std::ostream& os, const Optional<V>& v) {
38 os << "Optional(" << v.value() << ')';
46 NoDefault(int, int) {}
50 static_assert(sizeof(Optional<char>) == 2, "");
51 static_assert(sizeof(Optional<int>) == 8, "");
52 static_assert(sizeof(Optional<NoDefault>) == 4, "");
53 static_assert(sizeof(Optional<char>) == sizeof(boost::optional<char>), "");
54 static_assert(sizeof(Optional<short>) == sizeof(boost::optional<short>), "");
55 static_assert(sizeof(Optional<int>) == sizeof(boost::optional<int>), "");
56 static_assert(sizeof(Optional<double>) == sizeof(boost::optional<double>), "");
58 TEST(Optional, NoDefault) {
59 Optional<NoDefault> x;
67 TEST(Optional, String) {
68 Optional<std::string> maybeString;
69 EXPECT_FALSE(maybeString);
70 maybeString = "hello";
71 EXPECT_TRUE(bool(maybeString));
74 TEST(Optional, Const) {
75 { // default construct
76 Optional<const int> opt;
77 EXPECT_FALSE(bool(opt));
83 EXPECT_FALSE(bool(opt));
87 Optional<const int> opt(x);
92 Optional<const int> opt(std::move(x));
95 // no assignment allowed
98 TEST(Optional, Simple) {
100 EXPECT_FALSE(bool(opt));
101 EXPECT_EQ(42, opt.value_or(42));
103 EXPECT_TRUE(bool(opt));
105 EXPECT_EQ(4, opt.value_or(42));
109 EXPECT_FALSE(bool(opt));
114 /* implicit */ MoveTester(const char* s) : s_(s) {}
115 MoveTester(const MoveTester&) = default;
116 MoveTester(MoveTester&& other) noexcept {
117 s_ = std::move(other.s_);
120 MoveTester& operator=(const MoveTester&) = default;
121 MoveTester& operator=(MoveTester&& other) noexcept {
122 s_ = std::move(other.s_);
127 friend bool operator==(const MoveTester& o1, const MoveTester& o2);
131 bool operator==(const MoveTester& o1, const MoveTester& o2) {
132 return o1.s_ == o2.s_;
135 TEST(Optional, value_or_rvalue_arg) {
136 Optional<MoveTester> opt;
137 MoveTester dflt = "hello";
138 EXPECT_EQ("hello", opt.value_or(dflt));
139 EXPECT_EQ("hello", dflt);
140 EXPECT_EQ("hello", opt.value_or(std::move(dflt)));
142 EXPECT_EQ("world", opt.value_or("world"));
145 // Make sure that the const overload works on const objects
146 const auto& optc = opt;
147 EXPECT_EQ("hello", optc.value_or(dflt));
148 EXPECT_EQ("hello", dflt);
149 EXPECT_EQ("hello", optc.value_or(std::move(dflt)));
151 EXPECT_EQ("world", optc.value_or("world"));
155 EXPECT_EQ("meow", opt.value_or(dflt));
156 EXPECT_EQ("hello", dflt);
157 EXPECT_EQ("meow", opt.value_or(std::move(dflt)));
158 EXPECT_EQ("hello", dflt); // only moved if used
161 TEST(Optional, value_or_noncopyable) {
162 Optional<std::unique_ptr<int>> opt;
163 std::unique_ptr<int> dflt(new int(42));
164 EXPECT_EQ(42, *std::move(opt).value_or(std::move(dflt)));
167 struct ExpectingDeleter {
168 explicit ExpectingDeleter(int expected) : expected(expected) { }
170 void operator()(const int* ptr) {
171 EXPECT_EQ(*ptr, expected);
176 TEST(Optional, value_move) {
177 auto ptr = Optional<std::unique_ptr<int, ExpectingDeleter>>(
178 {new int(42), ExpectingDeleter{1337}}).value();
182 TEST(Optional, dereference_move) {
183 auto ptr = *Optional<std::unique_ptr<int, ExpectingDeleter>>(
184 {new int(42), ExpectingDeleter{1337}});
188 TEST(Optional, EmptyConstruct) {
190 EXPECT_FALSE(bool(opt));
191 Optional<int> test1(opt);
192 EXPECT_FALSE(bool(test1));
193 Optional<int> test2(std::move(opt));
194 EXPECT_FALSE(bool(test2));
197 TEST(Optional, Unique) {
198 Optional<unique_ptr<int>> opt;
201 EXPECT_FALSE(bool(opt));
203 opt.emplace(new int(5));
204 EXPECT_TRUE(bool(opt));
209 opt = unique_ptr<int>(new int(6));
212 opt = unique_ptr<int>(new int(7));
215 // move it out by move construct
216 Optional<unique_ptr<int>> moved(std::move(opt));
217 EXPECT_TRUE(bool(moved));
218 EXPECT_FALSE(bool(opt));
219 EXPECT_EQ(7, **moved);
221 EXPECT_TRUE(bool(moved));
222 opt = std::move(moved); // move it back by move assign
223 EXPECT_FALSE(bool(moved));
224 EXPECT_TRUE(bool(opt));
228 TEST(Optional, Shared) {
230 Optional<shared_ptr<int>> opt;
231 EXPECT_FALSE(bool(opt));
233 opt.emplace(new int(5));
234 EXPECT_TRUE(bool(opt));
236 EXPECT_EQ(ptr.get(), opt->get());
237 EXPECT_EQ(2, ptr.use_count());
239 EXPECT_EQ(1, ptr.use_count());
242 EXPECT_EQ(2, ptr.use_count());
243 EXPECT_EQ(ptr.get(), opt->get());
245 EXPECT_EQ(1, ptr.use_count());
247 opt = std::move(ptr);
248 EXPECT_EQ(1, opt->use_count());
249 EXPECT_EQ(nullptr, ptr.get());
251 Optional<shared_ptr<int>> copied(opt);
252 EXPECT_EQ(2, opt->use_count());
253 Optional<shared_ptr<int>> moved(std::move(opt));
254 EXPECT_EQ(2, moved->use_count());
255 moved.emplace(new int(6));
256 EXPECT_EQ(1, moved->use_count());
258 EXPECT_EQ(2, moved->use_count());
262 TEST(Optional, Order) {
263 std::vector<Optional<int>> vect{
270 std::vector<Optional<int>> expected {
277 std::sort(vect.begin(), vect.end());
278 EXPECT_EQ(vect, expected);
281 TEST(Optional, Swap) {
282 Optional<std::string> a;
283 Optional<std::string> b;
286 EXPECT_FALSE(a.hasValue());
287 EXPECT_FALSE(b.hasValue());
290 EXPECT_TRUE(a.hasValue());
291 EXPECT_FALSE(b.hasValue());
292 EXPECT_EQ("hello", a.value());
295 EXPECT_FALSE(a.hasValue());
296 EXPECT_TRUE(b.hasValue());
297 EXPECT_EQ("hello", b.value());
300 EXPECT_TRUE(a.hasValue());
301 EXPECT_EQ("bye", a.value());
306 TEST(Optional, Comparisons) {
311 EXPECT_TRUE(o_ <= (o_));
312 EXPECT_TRUE(o_ == (o_));
313 EXPECT_TRUE(o_ >= (o_));
315 EXPECT_TRUE(o1 < o2);
316 EXPECT_TRUE(o1 <= o2);
317 EXPECT_TRUE(o1 <= (o1));
318 EXPECT_TRUE(o1 == (o1));
319 EXPECT_TRUE(o1 != o2);
320 EXPECT_TRUE(o1 >= (o1));
321 EXPECT_TRUE(o2 >= o1);
322 EXPECT_TRUE(o2 > o1);
324 EXPECT_FALSE(o2 < o1);
325 EXPECT_FALSE(o2 <= o1);
326 EXPECT_FALSE(o2 <= o1);
327 EXPECT_FALSE(o2 == o1);
328 EXPECT_FALSE(o1 != (o1));
329 EXPECT_FALSE(o1 >= o2);
330 EXPECT_FALSE(o1 >= o2);
331 EXPECT_FALSE(o1 > o2);
333 /* folly::Optional explicitly doesn't support comparisons with contained value
335 EXPECT_TRUE(1 <= o2);
336 EXPECT_TRUE(1 <= o1);
337 EXPECT_TRUE(1 == o1);
338 EXPECT_TRUE(2 != o1);
339 EXPECT_TRUE(1 >= o1);
340 EXPECT_TRUE(2 >= o1);
343 EXPECT_FALSE(o2 < 1);
344 EXPECT_FALSE(o2 <= 1);
345 EXPECT_FALSE(o2 <= 1);
346 EXPECT_FALSE(o2 == 1);
347 EXPECT_FALSE(o2 != 2);
348 EXPECT_FALSE(o1 >= 2);
349 EXPECT_FALSE(o1 >= 2);
350 EXPECT_FALSE(o1 > 2);
353 // boost::optional does support comparison with contained value, which can
354 // lead to confusion when a bool is contained
355 boost::optional<int> boi(3);
356 EXPECT_TRUE(boi < 5);
357 EXPECT_TRUE(boi <= 4);
358 EXPECT_TRUE(boi == 3);
359 EXPECT_TRUE(boi != 2);
360 EXPECT_TRUE(boi >= 1);
361 EXPECT_TRUE(boi > 0);
362 EXPECT_TRUE(1 < boi);
363 EXPECT_TRUE(2 <= boi);
364 EXPECT_TRUE(3 == boi);
365 EXPECT_TRUE(4 != boi);
366 EXPECT_TRUE(5 >= boi);
367 EXPECT_TRUE(6 > boi);
369 boost::optional<bool> bob(false);
370 EXPECT_TRUE((bool)bob);
371 EXPECT_TRUE(bob == false); // well that was confusing
372 EXPECT_FALSE(bob != false);
375 TEST(Optional, Conversions) {
376 Optional<bool> mbool;
377 Optional<short> mshort;
378 Optional<char*> mstr;
381 //These don't compile
390 // intended explicit operator bool, for if (opt).
394 // Truthy tests work and are not ambiguous
395 if (mbool && mshort && mstr && mint) { // only checks not-empty
396 if (*mbool && *mshort && *mstr && *mint) { // only checks value
402 EXPECT_TRUE(bool(mbool));
403 EXPECT_FALSE(*mbool);
406 EXPECT_TRUE(bool(mbool));
410 EXPECT_FALSE(bool(mbool));
412 // No conversion allowed; does not compile
413 // EXPECT_TRUE(mbool == false);
416 TEST(Optional, Pointee) {
418 EXPECT_FALSE(get_pointer(x));
420 EXPECT_TRUE(get_pointer(x));
422 EXPECT_TRUE(*x == 2);
424 EXPECT_FALSE(get_pointer(x));
427 TEST(Optional, MakeOptional) {
428 // const L-value version
429 const std::string s("abc");
430 auto optStr = make_optional(s);
431 ASSERT_TRUE(optStr.hasValue());
432 EXPECT_EQ(*optStr, "abc");
435 EXPECT_EQ(*optStr, "cde");
438 std::string s2("abc");
439 auto optStr2 = make_optional(s2);
440 ASSERT_TRUE(optStr2.hasValue());
441 EXPECT_EQ(*optStr2, "abc");
443 // it's vital to check that s2 wasn't clobbered
444 EXPECT_EQ(s2, "abc");
446 // L-value reference version
448 auto optStr3 = make_optional(s3);
449 ASSERT_TRUE(optStr3.hasValue());
450 EXPECT_EQ(*optStr3, "abc");
452 EXPECT_EQ(s3, "abc");
454 // R-value ref version
455 unique_ptr<int> pInt(new int(3));
456 auto optIntPtr = make_optional(std::move(pInt));
457 EXPECT_TRUE(pInt.get() == nullptr);
458 ASSERT_TRUE(optIntPtr.hasValue());
459 EXPECT_EQ(**optIntPtr, 3);
463 # pragma clang diagnostic push
464 # pragma clang diagnostic ignored "-Wself-move"
467 TEST(Optional, SelfAssignment) {
468 Optional<int> a = 42;
470 ASSERT_TRUE(a.hasValue() && a.value() == 42);
472 Optional<int> b = 23333333;
474 ASSERT_TRUE(b.hasValue() && b.value() == 23333333);
478 # pragma clang diagnostic pop
481 class ContainsOptional {
483 ContainsOptional() { }
484 explicit ContainsOptional(int x) : opt_(x) { }
485 bool hasValue() const { return opt_.hasValue(); }
486 int value() const { return opt_.value(); }
488 ContainsOptional(const ContainsOptional &other) = default;
489 ContainsOptional& operator=(const ContainsOptional &other) = default;
490 ContainsOptional(ContainsOptional &&other) = default;
491 ContainsOptional& operator=(ContainsOptional &&other) = default;
498 * Test that a class containing an Optional can be copy and move assigned.
499 * This was broken under gcc 4.7 until assignment operators were explicitly
502 TEST(Optional, AssignmentContained) {
504 ContainsOptional source(5), target;
506 EXPECT_TRUE(target.hasValue());
507 EXPECT_EQ(5, target.value());
511 ContainsOptional source(5), target;
512 target = std::move(source);
513 EXPECT_TRUE(target.hasValue());
514 EXPECT_EQ(5, target.value());
515 EXPECT_FALSE(source.hasValue());
519 ContainsOptional opt_uninit, target(10);
521 EXPECT_FALSE(target.hasValue());
525 TEST(Optional, Exceptions) {
527 EXPECT_THROW(empty.value(), OptionalEmptyException);
530 TEST(Optional, NoThrowDefaultConstructible) {
531 EXPECT_TRUE(std::is_nothrow_default_constructible<Optional<bool>>::value);
534 struct NoDestructor {};
536 struct WithDestructor {
540 TEST(Optional, TriviallyDestructible) {
541 // These could all be static_asserts but EXPECT_* give much nicer output on
543 EXPECT_TRUE(std::is_trivially_destructible<Optional<NoDestructor>>::value);
544 EXPECT_TRUE(std::is_trivially_destructible<Optional<int>>::value);
545 EXPECT_FALSE(std::is_trivially_destructible<Optional<WithDestructor>>::value);
548 TEST(Optional, Hash) {
549 // Test it's usable in std::unordered map (compile time check)
550 std::unordered_map<Optional<int>, Optional<int>> obj;
551 // Also check the std::hash template can be instantiated by the compiler
552 std::hash<Optional<int>>()(none);
553 std::hash<Optional<int>>()(3);