folly::make_optional
[folly.git] / folly / test / OptionalTest.cpp
1 /*
2  * Copyright 2013 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
19 #include <memory>
20 #include <vector>
21 #include <algorithm>
22 #include <iomanip>
23 #include <string>
24
25 #include <glog/logging.h>
26 #include <gtest/gtest.h>
27 #include <boost/optional.hpp>
28
29 using namespace folly;
30 using std::unique_ptr;
31 using std::shared_ptr;
32
33 struct NoDefault {
34   NoDefault(int, int) {}
35   char a, b, c;
36 };
37
38 static_assert(sizeof(Optional<char>) == 2, "");
39 static_assert(sizeof(Optional<int>) == 8, "");
40 static_assert(sizeof(Optional<NoDefault>) == 4, "");
41 static_assert(sizeof(Optional<char>) == sizeof(boost::optional<char>), "");
42 static_assert(sizeof(Optional<short>) == sizeof(boost::optional<short>), "");
43 static_assert(sizeof(Optional<int>) == sizeof(boost::optional<int>), "");
44 static_assert(sizeof(Optional<double>) == sizeof(boost::optional<double>), "");
45
46 TEST(Optional, NoDefault) {
47   Optional<NoDefault> x;
48   EXPECT_FALSE(x);
49   x.emplace(4, 5);
50   EXPECT_TRUE(x);
51   x.clear();
52   EXPECT_FALSE(x);
53 }
54
55 TEST(Optional, String) {
56   Optional<std::string> maybeString;
57   EXPECT_FALSE(maybeString);
58   maybeString = "hello";
59   EXPECT_TRUE(maybeString);
60 }
61
62 TEST(Optional, Const) {
63   { // default construct
64     Optional<const int> opt;
65     EXPECT_FALSE(opt);
66     opt.emplace(4);
67     EXPECT_EQ(opt, 4);
68     opt.emplace(5);
69     EXPECT_EQ(opt, 5);
70     opt.clear();
71     EXPECT_FALSE(opt);
72   }
73   { // copy-constructed
74     const int x = 6;
75     Optional<const int> opt(x);
76     EXPECT_EQ(opt, 6);
77   }
78   { // move-constructed
79     const int x = 7;
80     Optional<const int> opt(std::move(x));
81     EXPECT_EQ(opt, 7);
82   }
83   // no assignment allowed
84 }
85
86 TEST(Optional, Simple) {
87   Optional<int> opt;
88   EXPECT_FALSE(opt);
89   opt = 4;
90   EXPECT_TRUE(opt);
91   EXPECT_EQ(4, *opt);
92   opt = 5;
93   EXPECT_EQ(5, *opt);
94   opt.clear();
95   EXPECT_FALSE(opt);
96 }
97
98 TEST(Optional, EmptyConstruct) {
99   Optional<int> opt;
100   EXPECT_FALSE(opt);
101   Optional<int> test1(opt);
102   EXPECT_FALSE(test1);
103   Optional<int> test2(std::move(opt));
104   EXPECT_FALSE(test2);
105 }
106
107 TEST(Optional, Unique) {
108   Optional<unique_ptr<int>> opt;
109
110   opt.clear();
111   EXPECT_FALSE(opt);
112   // empty->emplaced
113   opt.emplace(new int(5));
114   EXPECT_TRUE(opt);
115   EXPECT_EQ(5, **opt);
116
117   opt.clear();
118   // empty->moved
119   opt = unique_ptr<int>(new int(6));
120   EXPECT_EQ(6, **opt);
121   // full->moved
122   opt = unique_ptr<int>(new int(7));
123   EXPECT_EQ(7, **opt);
124
125   // move it out by move construct
126   Optional<unique_ptr<int>> moved(std::move(opt));
127   EXPECT_TRUE(moved);
128   EXPECT_FALSE(opt);
129   EXPECT_EQ(7, **moved);
130
131   EXPECT_TRUE(moved);
132   opt = std::move(moved); // move it back by move assign
133   EXPECT_FALSE(moved);
134   EXPECT_TRUE(opt);
135   EXPECT_EQ(7, **opt);
136 }
137
138 TEST(Optional, Shared) {
139   shared_ptr<int> ptr;
140   Optional<shared_ptr<int>> opt;
141   EXPECT_FALSE(opt);
142   // empty->emplaced
143   opt.emplace(new int(5));
144   EXPECT_TRUE(opt);
145   ptr = opt.value();
146   EXPECT_EQ(ptr.get(), opt->get());
147   EXPECT_EQ(2, ptr.use_count());
148   opt.clear();
149   EXPECT_EQ(1, ptr.use_count());
150   // full->copied
151   opt = ptr;
152   EXPECT_EQ(2, ptr.use_count());
153   EXPECT_EQ(ptr.get(), opt->get());
154   opt.clear();
155   EXPECT_EQ(1, ptr.use_count());
156   // full->moved
157   opt = std::move(ptr);
158   EXPECT_EQ(1, opt->use_count());
159   EXPECT_EQ(nullptr, ptr.get());
160   {
161     Optional<shared_ptr<int>> copied(opt);
162     EXPECT_EQ(2, opt->use_count());
163     Optional<shared_ptr<int>> moved(std::move(opt));
164     EXPECT_EQ(2, moved->use_count());
165     moved.emplace(new int(6));
166     EXPECT_EQ(1, moved->use_count());
167     copied = moved;
168     EXPECT_EQ(2, moved->use_count());
169   }
170 }
171
172 TEST(Optional, Order) {
173   std::vector<Optional<int>> vect{
174     { none },
175     { 3 },
176     { 1 },
177     { none },
178     { 2 },
179   };
180   std::vector<Optional<int>> expected {
181     { none },
182     { none },
183     { 1 },
184     { 2 },
185     { 3 },
186   };
187   std::sort(vect.begin(), vect.end());
188   EXPECT_TRUE(vect == expected);
189 }
190
191 TEST(Optional, Swap) {
192   Optional<std::string> a;
193   Optional<std::string> b;
194
195   swap(a, b);
196   EXPECT_FALSE(a.hasValue());
197   EXPECT_FALSE(b.hasValue());
198
199   a = "hello";
200   EXPECT_TRUE(a.hasValue());
201   EXPECT_FALSE(b.hasValue());
202   EXPECT_EQ("hello", a.value());
203
204   swap(a, b);
205   EXPECT_FALSE(a.hasValue());
206   EXPECT_TRUE(b.hasValue());
207   EXPECT_EQ("hello", b.value());
208
209   a = "bye";
210   EXPECT_TRUE(a.hasValue());
211   EXPECT_EQ("bye", a.value());
212
213   swap(a, b);
214 }
215
216 TEST(Optional, Comparisons) {
217   Optional<int> o_;
218   Optional<int> o1(1);
219   Optional<int> o2(2);
220
221   EXPECT_TRUE(o_ < 1);
222   EXPECT_TRUE(o_ <= 1);
223   EXPECT_TRUE(o_ <= o_);
224   EXPECT_TRUE(o_ == o_);
225   EXPECT_TRUE(o_ != 1);
226   EXPECT_TRUE(o_ >= o_);
227   EXPECT_TRUE(1 >= o_);
228   EXPECT_TRUE(1 > o_);
229
230   EXPECT_TRUE(o1 < o2);
231   EXPECT_TRUE(o1 <= o2);
232   EXPECT_TRUE(o1 <= o1);
233   EXPECT_TRUE(o1 == o1);
234   EXPECT_TRUE(o1 != o2);
235   EXPECT_TRUE(o1 >= o1);
236   EXPECT_TRUE(o2 >= o1);
237   EXPECT_TRUE(o2 > o1);
238
239   EXPECT_FALSE(o2 < o1);
240   EXPECT_FALSE(o2 <= o1);
241   EXPECT_FALSE(o2 <= o1);
242   EXPECT_FALSE(o2 == o1);
243   EXPECT_FALSE(o1 != o1);
244   EXPECT_FALSE(o1 >= o2);
245   EXPECT_FALSE(o1 >= o2);
246   EXPECT_FALSE(o1 > o2);
247
248   EXPECT_TRUE(1 < o2);
249   EXPECT_TRUE(1 <= o2);
250   EXPECT_TRUE(1 <= o1);
251   EXPECT_TRUE(1 == o1);
252   EXPECT_TRUE(2 != o1);
253   EXPECT_TRUE(1 >= o1);
254   EXPECT_TRUE(2 >= o1);
255   EXPECT_TRUE(2 > o1);
256
257   EXPECT_FALSE(o2 < 1);
258   EXPECT_FALSE(o2 <= 1);
259   EXPECT_FALSE(o2 <= 1);
260   EXPECT_FALSE(o2 == 1);
261   EXPECT_FALSE(o2 != 2);
262   EXPECT_FALSE(o1 >= 2);
263   EXPECT_FALSE(o1 >= 2);
264   EXPECT_FALSE(o1 > 2);
265 }
266
267 TEST(Optional, Pointee) {
268   Optional<int> x;
269   EXPECT_FALSE(get_pointer(x));
270   x = 1;
271   EXPECT_TRUE(get_pointer(x));
272   *get_pointer(x) = 2;
273   EXPECT_TRUE(x == 2);
274   x = none;
275   EXPECT_FALSE(get_pointer(x));
276 }
277
278 TEST(Optional, MakeOptional) {
279   // const L-value version
280   const std::string s("abc");
281   auto optStr = make_optional(s);
282   ASSERT_TRUE(optStr.hasValue());
283   EXPECT_EQ(*optStr, "abc");
284   *optStr = "cde";
285   EXPECT_EQ(s, "abc");
286   EXPECT_EQ(*optStr, "cde");
287
288   // L-value version
289   std::string s2("abc");
290   auto optStr2 = make_optional(s2);
291   ASSERT_TRUE(optStr2.hasValue());
292   EXPECT_EQ(*optStr2, "abc");
293   *optStr2 = "cde";
294   // it's vital to check that s2 wasn't clobbered
295   EXPECT_EQ(s2, "abc");
296
297   // L-value reference version
298   std::string& s3(s2);
299   auto optStr3 = make_optional(s3);
300   ASSERT_TRUE(optStr3.hasValue());
301   EXPECT_EQ(*optStr3, "abc");
302   *optStr3 = "cde";
303   EXPECT_EQ(s3, "abc");
304
305   // R-value ref version
306   unique_ptr<int> pInt(new int(3));
307   auto optIntPtr = make_optional(std::move(pInt));
308   EXPECT_TRUE(pInt.get() == nullptr);
309   ASSERT_TRUE(optIntPtr.hasValue());
310   EXPECT_EQ(**optIntPtr, 3);
311 }