2 * Copyright 2014 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>
25 #include <glog/logging.h>
26 #include <gtest/gtest.h>
27 #include <boost/optional.hpp>
29 using std::unique_ptr;
30 using std::shared_ptr;
35 std::ostream& operator<<(std::ostream& os, const Optional<V>& v) {
37 os << "Optional(" << v.value() << ')';
45 NoDefault(int, int) {}
49 static_assert(sizeof(Optional<char>) == 2, "");
50 static_assert(sizeof(Optional<int>) == 8, "");
51 static_assert(sizeof(Optional<NoDefault>) == 4, "");
52 static_assert(sizeof(Optional<char>) == sizeof(boost::optional<char>), "");
53 static_assert(sizeof(Optional<short>) == sizeof(boost::optional<short>), "");
54 static_assert(sizeof(Optional<int>) == sizeof(boost::optional<int>), "");
55 static_assert(sizeof(Optional<double>) == sizeof(boost::optional<double>), "");
57 TEST(Optional, NoDefault) {
58 Optional<NoDefault> x;
66 TEST(Optional, String) {
67 Optional<std::string> maybeString;
68 EXPECT_FALSE(maybeString);
69 maybeString = "hello";
70 EXPECT_TRUE(bool(maybeString));
73 TEST(Optional, Const) {
74 { // default construct
75 Optional<const int> opt;
76 EXPECT_FALSE(bool(opt));
82 EXPECT_FALSE(bool(opt));
86 Optional<const int> opt(x);
91 Optional<const int> opt(std::move(x));
94 // no assignment allowed
97 TEST(Optional, Simple) {
99 EXPECT_FALSE(bool(opt));
100 EXPECT_EQ(42, opt.value_or(42));
102 EXPECT_TRUE(bool(opt));
104 EXPECT_EQ(4, opt.value_or(42));
108 EXPECT_FALSE(bool(opt));
113 /* implicit */ MoveTester(const char* s) : s_(s) {}
114 MoveTester(const MoveTester&) = default;
115 MoveTester(MoveTester&& other) noexcept {
116 s_ = std::move(other.s_);
119 MoveTester& operator=(const MoveTester&) = default;
120 MoveTester& operator=(MoveTester&&) = default;
122 friend bool operator==(const MoveTester& o1, const MoveTester& o2);
126 bool operator==(const MoveTester& o1, const MoveTester& o2) {
127 return o1.s_ == o2.s_;
130 TEST(Optional, value_or_rvalue_arg) {
131 Optional<MoveTester> opt;
132 MoveTester dflt = "hello";
133 EXPECT_EQ("hello", opt.value_or(dflt));
134 EXPECT_EQ("hello", dflt);
135 EXPECT_EQ("hello", opt.value_or(std::move(dflt)));
137 EXPECT_EQ("world", opt.value_or("world"));
140 // Make sure that the const overload works on const objects
141 const auto& optc = opt;
142 EXPECT_EQ("hello", optc.value_or(dflt));
143 EXPECT_EQ("hello", dflt);
144 EXPECT_EQ("hello", optc.value_or(std::move(dflt)));
146 EXPECT_EQ("world", optc.value_or("world"));
150 EXPECT_EQ("meow", opt.value_or(dflt));
151 EXPECT_EQ("hello", dflt);
152 EXPECT_EQ("meow", opt.value_or(std::move(dflt)));
153 EXPECT_EQ("hello", dflt); // only moved if used
156 TEST(Optional, value_or_noncopyable) {
157 Optional<std::unique_ptr<int>> opt;
158 std::unique_ptr<int> dflt(new int(42));
159 EXPECT_EQ(42, *std::move(opt).value_or(std::move(dflt)));
162 TEST(Optional, EmptyConstruct) {
164 EXPECT_FALSE(bool(opt));
165 Optional<int> test1(opt);
166 EXPECT_FALSE(bool(test1));
167 Optional<int> test2(std::move(opt));
168 EXPECT_FALSE(bool(test2));
171 TEST(Optional, Unique) {
172 Optional<unique_ptr<int>> opt;
175 EXPECT_FALSE(bool(opt));
177 opt.emplace(new int(5));
178 EXPECT_TRUE(bool(opt));
183 opt = unique_ptr<int>(new int(6));
186 opt = unique_ptr<int>(new int(7));
189 // move it out by move construct
190 Optional<unique_ptr<int>> moved(std::move(opt));
191 EXPECT_TRUE(bool(moved));
192 EXPECT_FALSE(bool(opt));
193 EXPECT_EQ(7, **moved);
195 EXPECT_TRUE(bool(moved));
196 opt = std::move(moved); // move it back by move assign
197 EXPECT_FALSE(bool(moved));
198 EXPECT_TRUE(bool(opt));
202 TEST(Optional, Shared) {
204 Optional<shared_ptr<int>> opt;
205 EXPECT_FALSE(bool(opt));
207 opt.emplace(new int(5));
208 EXPECT_TRUE(bool(opt));
210 EXPECT_EQ(ptr.get(), opt->get());
211 EXPECT_EQ(2, ptr.use_count());
213 EXPECT_EQ(1, ptr.use_count());
216 EXPECT_EQ(2, ptr.use_count());
217 EXPECT_EQ(ptr.get(), opt->get());
219 EXPECT_EQ(1, ptr.use_count());
221 opt = std::move(ptr);
222 EXPECT_EQ(1, opt->use_count());
223 EXPECT_EQ(nullptr, ptr.get());
225 Optional<shared_ptr<int>> copied(opt);
226 EXPECT_EQ(2, opt->use_count());
227 Optional<shared_ptr<int>> moved(std::move(opt));
228 EXPECT_EQ(2, moved->use_count());
229 moved.emplace(new int(6));
230 EXPECT_EQ(1, moved->use_count());
232 EXPECT_EQ(2, moved->use_count());
236 TEST(Optional, Order) {
237 std::vector<Optional<int>> vect{
244 std::vector<Optional<int>> expected {
251 std::sort(vect.begin(), vect.end());
252 EXPECT_EQ(vect, expected);
255 TEST(Optional, Swap) {
256 Optional<std::string> a;
257 Optional<std::string> b;
260 EXPECT_FALSE(a.hasValue());
261 EXPECT_FALSE(b.hasValue());
264 EXPECT_TRUE(a.hasValue());
265 EXPECT_FALSE(b.hasValue());
266 EXPECT_EQ("hello", a.value());
269 EXPECT_FALSE(a.hasValue());
270 EXPECT_TRUE(b.hasValue());
271 EXPECT_EQ("hello", b.value());
274 EXPECT_TRUE(a.hasValue());
275 EXPECT_EQ("bye", a.value());
280 TEST(Optional, Comparisons) {
285 EXPECT_TRUE(o_ <= o_);
286 EXPECT_TRUE(o_ == o_);
287 EXPECT_TRUE(o_ >= o_);
289 EXPECT_TRUE(o1 < o2);
290 EXPECT_TRUE(o1 <= o2);
291 EXPECT_TRUE(o1 <= o1);
292 EXPECT_TRUE(o1 == o1);
293 EXPECT_TRUE(o1 != o2);
294 EXPECT_TRUE(o1 >= o1);
295 EXPECT_TRUE(o2 >= o1);
296 EXPECT_TRUE(o2 > o1);
298 EXPECT_FALSE(o2 < o1);
299 EXPECT_FALSE(o2 <= o1);
300 EXPECT_FALSE(o2 <= o1);
301 EXPECT_FALSE(o2 == o1);
302 EXPECT_FALSE(o1 != o1);
303 EXPECT_FALSE(o1 >= o2);
304 EXPECT_FALSE(o1 >= o2);
305 EXPECT_FALSE(o1 > o2);
307 /* folly::Optional explicitly doesn't support comparisons with contained value
309 EXPECT_TRUE(1 <= o2);
310 EXPECT_TRUE(1 <= o1);
311 EXPECT_TRUE(1 == o1);
312 EXPECT_TRUE(2 != o1);
313 EXPECT_TRUE(1 >= o1);
314 EXPECT_TRUE(2 >= o1);
317 EXPECT_FALSE(o2 < 1);
318 EXPECT_FALSE(o2 <= 1);
319 EXPECT_FALSE(o2 <= 1);
320 EXPECT_FALSE(o2 == 1);
321 EXPECT_FALSE(o2 != 2);
322 EXPECT_FALSE(o1 >= 2);
323 EXPECT_FALSE(o1 >= 2);
324 EXPECT_FALSE(o1 > 2);
327 // boost::optional does support comparison with contained value, which can
328 // lead to confusion when a bool is contained
329 boost::optional<int> boi(3);
330 EXPECT_TRUE(boi < 5);
331 EXPECT_TRUE(boi <= 4);
332 EXPECT_TRUE(boi == 3);
333 EXPECT_TRUE(boi != 2);
334 EXPECT_TRUE(boi >= 1);
335 EXPECT_TRUE(boi > 0);
336 EXPECT_TRUE(1 < boi);
337 EXPECT_TRUE(2 <= boi);
338 EXPECT_TRUE(3 == boi);
339 EXPECT_TRUE(4 != boi);
340 EXPECT_TRUE(5 >= boi);
341 EXPECT_TRUE(6 > boi);
343 boost::optional<bool> bob(false);
345 EXPECT_TRUE(bob == false); // well that was confusing
346 EXPECT_FALSE(bob != false);
349 TEST(Optional, Conversions) {
350 Optional<bool> mbool;
351 Optional<short> mshort;
352 Optional<char*> mstr;
355 //These don't compile
364 // intended explicit operator bool, for if (opt).
367 // Truthy tests work and are not ambiguous
368 if (mbool && mshort && mstr && mint) { // only checks not-empty
369 if (*mbool && *mshort && *mstr && *mint) { // only checks value
375 EXPECT_TRUE(bool(mbool));
376 EXPECT_FALSE(*mbool);
379 EXPECT_TRUE(bool(mbool));
383 EXPECT_FALSE(bool(mbool));
385 // No conversion allowed; does not compile
386 // EXPECT_TRUE(mbool == false);
389 TEST(Optional, Pointee) {
391 EXPECT_FALSE(get_pointer(x));
393 EXPECT_TRUE(get_pointer(x));
395 EXPECT_TRUE(*x == 2);
397 EXPECT_FALSE(get_pointer(x));
400 TEST(Optional, MakeOptional) {
401 // const L-value version
402 const std::string s("abc");
403 auto optStr = make_optional(s);
404 ASSERT_TRUE(optStr.hasValue());
405 EXPECT_EQ(*optStr, "abc");
408 EXPECT_EQ(*optStr, "cde");
411 std::string s2("abc");
412 auto optStr2 = make_optional(s2);
413 ASSERT_TRUE(optStr2.hasValue());
414 EXPECT_EQ(*optStr2, "abc");
416 // it's vital to check that s2 wasn't clobbered
417 EXPECT_EQ(s2, "abc");
419 // L-value reference version
421 auto optStr3 = make_optional(s3);
422 ASSERT_TRUE(optStr3.hasValue());
423 EXPECT_EQ(*optStr3, "abc");
425 EXPECT_EQ(s3, "abc");
427 // R-value ref version
428 unique_ptr<int> pInt(new int(3));
429 auto optIntPtr = make_optional(std::move(pInt));
430 EXPECT_TRUE(pInt.get() == nullptr);
431 ASSERT_TRUE(optIntPtr.hasValue());
432 EXPECT_EQ(**optIntPtr, 3);
435 TEST(Optional, SelfAssignment) {
436 Optional<int> a = 42;
438 ASSERT_TRUE(a.hasValue() && a.value() == 42);
440 Optional<int> b = 23333333;
442 ASSERT_TRUE(b.hasValue() && b.value() == 23333333);
445 class ContainsOptional {
447 ContainsOptional() { }
448 explicit ContainsOptional(int x) : opt_(x) { }
449 bool hasValue() const { return opt_.hasValue(); }
450 int value() const { return opt_.value(); }
452 ContainsOptional(const ContainsOptional &other) = default;
453 ContainsOptional& operator=(const ContainsOptional &other) = default;
454 ContainsOptional(ContainsOptional &&other) = default;
455 ContainsOptional& operator=(ContainsOptional &&other) = default;
462 * Test that a class containing an Optional can be copy and move assigned.
463 * This was broken under gcc 4.7 until assignment operators were explicitly
466 TEST(Optional, AssignmentContained) {
468 ContainsOptional source(5), target;
470 EXPECT_TRUE(target.hasValue());
471 EXPECT_EQ(5, target.value());
475 ContainsOptional source(5), target;
476 target = std::move(source);
477 EXPECT_TRUE(target.hasValue());
478 EXPECT_EQ(5, target.value());
479 EXPECT_FALSE(source.hasValue());
483 ContainsOptional opt_uninit, target(10);
485 EXPECT_FALSE(target.hasValue());