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));
101 EXPECT_TRUE(bool(opt));
106 EXPECT_FALSE(bool(opt));
109 TEST(Optional, EmptyConstruct) {
111 EXPECT_FALSE(bool(opt));
112 Optional<int> test1(opt);
113 EXPECT_FALSE(bool(test1));
114 Optional<int> test2(std::move(opt));
115 EXPECT_FALSE(bool(test2));
118 TEST(Optional, Unique) {
119 Optional<unique_ptr<int>> opt;
122 EXPECT_FALSE(bool(opt));
124 opt.emplace(new int(5));
125 EXPECT_TRUE(bool(opt));
130 opt = unique_ptr<int>(new int(6));
133 opt = unique_ptr<int>(new int(7));
136 // move it out by move construct
137 Optional<unique_ptr<int>> moved(std::move(opt));
138 EXPECT_TRUE(bool(moved));
139 EXPECT_FALSE(bool(opt));
140 EXPECT_EQ(7, **moved);
142 EXPECT_TRUE(bool(moved));
143 opt = std::move(moved); // move it back by move assign
144 EXPECT_FALSE(bool(moved));
145 EXPECT_TRUE(bool(opt));
149 TEST(Optional, Shared) {
151 Optional<shared_ptr<int>> opt;
152 EXPECT_FALSE(bool(opt));
154 opt.emplace(new int(5));
155 EXPECT_TRUE(bool(opt));
157 EXPECT_EQ(ptr.get(), opt->get());
158 EXPECT_EQ(2, ptr.use_count());
160 EXPECT_EQ(1, ptr.use_count());
163 EXPECT_EQ(2, ptr.use_count());
164 EXPECT_EQ(ptr.get(), opt->get());
166 EXPECT_EQ(1, ptr.use_count());
168 opt = std::move(ptr);
169 EXPECT_EQ(1, opt->use_count());
170 EXPECT_EQ(nullptr, ptr.get());
172 Optional<shared_ptr<int>> copied(opt);
173 EXPECT_EQ(2, opt->use_count());
174 Optional<shared_ptr<int>> moved(std::move(opt));
175 EXPECT_EQ(2, moved->use_count());
176 moved.emplace(new int(6));
177 EXPECT_EQ(1, moved->use_count());
179 EXPECT_EQ(2, moved->use_count());
183 TEST(Optional, Order) {
184 std::vector<Optional<int>> vect{
191 std::vector<Optional<int>> expected {
198 std::sort(vect.begin(), vect.end());
199 EXPECT_EQ(vect, expected);
202 TEST(Optional, Swap) {
203 Optional<std::string> a;
204 Optional<std::string> b;
207 EXPECT_FALSE(a.hasValue());
208 EXPECT_FALSE(b.hasValue());
211 EXPECT_TRUE(a.hasValue());
212 EXPECT_FALSE(b.hasValue());
213 EXPECT_EQ("hello", a.value());
216 EXPECT_FALSE(a.hasValue());
217 EXPECT_TRUE(b.hasValue());
218 EXPECT_EQ("hello", b.value());
221 EXPECT_TRUE(a.hasValue());
222 EXPECT_EQ("bye", a.value());
227 TEST(Optional, Comparisons) {
232 EXPECT_TRUE(o_ <= o_);
233 EXPECT_TRUE(o_ == o_);
234 EXPECT_TRUE(o_ >= o_);
236 EXPECT_TRUE(o1 < o2);
237 EXPECT_TRUE(o1 <= o2);
238 EXPECT_TRUE(o1 <= o1);
239 EXPECT_TRUE(o1 == o1);
240 EXPECT_TRUE(o1 != o2);
241 EXPECT_TRUE(o1 >= o1);
242 EXPECT_TRUE(o2 >= o1);
243 EXPECT_TRUE(o2 > o1);
245 EXPECT_FALSE(o2 < o1);
246 EXPECT_FALSE(o2 <= o1);
247 EXPECT_FALSE(o2 <= o1);
248 EXPECT_FALSE(o2 == o1);
249 EXPECT_FALSE(o1 != o1);
250 EXPECT_FALSE(o1 >= o2);
251 EXPECT_FALSE(o1 >= o2);
252 EXPECT_FALSE(o1 > o2);
254 /* folly::Optional explicitly doesn't support comparisons with contained value
256 EXPECT_TRUE(1 <= o2);
257 EXPECT_TRUE(1 <= o1);
258 EXPECT_TRUE(1 == o1);
259 EXPECT_TRUE(2 != o1);
260 EXPECT_TRUE(1 >= o1);
261 EXPECT_TRUE(2 >= o1);
264 EXPECT_FALSE(o2 < 1);
265 EXPECT_FALSE(o2 <= 1);
266 EXPECT_FALSE(o2 <= 1);
267 EXPECT_FALSE(o2 == 1);
268 EXPECT_FALSE(o2 != 2);
269 EXPECT_FALSE(o1 >= 2);
270 EXPECT_FALSE(o1 >= 2);
271 EXPECT_FALSE(o1 > 2);
274 // boost::optional does support comparison with contained value, which can
275 // lead to confusion when a bool is contained
276 boost::optional<int> boi(3);
277 EXPECT_TRUE(boi < 5);
278 EXPECT_TRUE(boi <= 4);
279 EXPECT_TRUE(boi == 3);
280 EXPECT_TRUE(boi != 2);
281 EXPECT_TRUE(boi >= 1);
282 EXPECT_TRUE(boi > 0);
283 EXPECT_TRUE(1 < boi);
284 EXPECT_TRUE(2 <= boi);
285 EXPECT_TRUE(3 == boi);
286 EXPECT_TRUE(4 != boi);
287 EXPECT_TRUE(5 >= boi);
288 EXPECT_TRUE(6 > boi);
290 boost::optional<bool> bob(false);
292 EXPECT_TRUE(bob == false); // well that was confusing
293 EXPECT_FALSE(bob != false);
296 TEST(Optional, Conversions) {
297 Optional<bool> mbool;
298 Optional<short> mshort;
299 Optional<char*> mstr;
302 //These don't compile
311 // intended explicit operator bool, for if (opt).
314 // Truthy tests work and are not ambiguous
315 if (mbool && mshort && mstr && mint) { // only checks not-empty
316 if (*mbool && *mshort && *mstr && *mint) { // only checks value
322 EXPECT_TRUE(bool(mbool));
323 EXPECT_FALSE(*mbool);
326 EXPECT_TRUE(bool(mbool));
330 EXPECT_FALSE(bool(mbool));
332 // No conversion allowed; does not compile
333 // EXPECT_TRUE(mbool == false);
336 TEST(Optional, Pointee) {
338 EXPECT_FALSE(get_pointer(x));
340 EXPECT_TRUE(get_pointer(x));
342 EXPECT_TRUE(*x == 2);
344 EXPECT_FALSE(get_pointer(x));
347 TEST(Optional, MakeOptional) {
348 // const L-value version
349 const std::string s("abc");
350 auto optStr = make_optional(s);
351 ASSERT_TRUE(optStr.hasValue());
352 EXPECT_EQ(*optStr, "abc");
355 EXPECT_EQ(*optStr, "cde");
358 std::string s2("abc");
359 auto optStr2 = make_optional(s2);
360 ASSERT_TRUE(optStr2.hasValue());
361 EXPECT_EQ(*optStr2, "abc");
363 // it's vital to check that s2 wasn't clobbered
364 EXPECT_EQ(s2, "abc");
366 // L-value reference version
368 auto optStr3 = make_optional(s3);
369 ASSERT_TRUE(optStr3.hasValue());
370 EXPECT_EQ(*optStr3, "abc");
372 EXPECT_EQ(s3, "abc");
374 // R-value ref version
375 unique_ptr<int> pInt(new int(3));
376 auto optIntPtr = make_optional(std::move(pInt));
377 EXPECT_TRUE(pInt.get() == nullptr);
378 ASSERT_TRUE(optIntPtr.hasValue());
379 EXPECT_EQ(**optIntPtr, 3);
382 class ContainsOptional {
384 ContainsOptional() { }
385 explicit ContainsOptional(int x) : opt_(x) { }
386 bool hasValue() const { return opt_.hasValue(); }
387 int value() const { return opt_.value(); }
389 ContainsOptional(const ContainsOptional &other) = default;
390 ContainsOptional& operator=(const ContainsOptional &other) = default;
391 ContainsOptional(ContainsOptional &&other) = default;
392 ContainsOptional& operator=(ContainsOptional &&other) = default;
399 * Test that a class containing an Optional can be copy and move assigned.
400 * This was broken under gcc 4.7 until assignment operators were explicitly
403 TEST(Optional, AssignmentContained) {
405 ContainsOptional source(5), target;
407 EXPECT_TRUE(target.hasValue());
408 EXPECT_EQ(5, target.value());
412 ContainsOptional source(5), target;
413 target = std::move(source);
414 EXPECT_TRUE(target.hasValue());
415 EXPECT_EQ(5, target.value());
416 EXPECT_FALSE(source.hasValue());
420 ContainsOptional opt_uninit, target(10);
422 EXPECT_FALSE(target.hasValue());