Copyright 2014->2015
[folly.git] / folly / test / OptionalTest.cpp
1 /*
2  * Copyright 2015 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 std::unique_ptr;
30 using std::shared_ptr;
31
32 namespace folly {
33
34 template<class V>
35 std::ostream& operator<<(std::ostream& os, const Optional<V>& v) {
36   if (v) {
37     os << "Optional(" << v.value() << ')';
38   } else {
39     os << "None";
40   }
41   return os;
42 }
43
44 struct NoDefault {
45   NoDefault(int, int) {}
46   char a, b, c;
47 };
48
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>), "");
56
57 TEST(Optional, NoDefault) {
58   Optional<NoDefault> x;
59   EXPECT_FALSE(x);
60   x.emplace(4, 5);
61   EXPECT_TRUE(bool(x));
62   x.clear();
63   EXPECT_FALSE(x);
64 }
65
66 TEST(Optional, String) {
67   Optional<std::string> maybeString;
68   EXPECT_FALSE(maybeString);
69   maybeString = "hello";
70   EXPECT_TRUE(bool(maybeString));
71 }
72
73 TEST(Optional, Const) {
74   { // default construct
75     Optional<const int> opt;
76     EXPECT_FALSE(bool(opt));
77     opt.emplace(4);
78     EXPECT_EQ(*opt, 4);
79     opt.emplace(5);
80     EXPECT_EQ(*opt, 5);
81     opt.clear();
82     EXPECT_FALSE(bool(opt));
83   }
84   { // copy-constructed
85     const int x = 6;
86     Optional<const int> opt(x);
87     EXPECT_EQ(*opt, 6);
88   }
89   { // move-constructed
90     const int x = 7;
91     Optional<const int> opt(std::move(x));
92     EXPECT_EQ(*opt, 7);
93   }
94   // no assignment allowed
95 }
96
97 TEST(Optional, Simple) {
98   Optional<int> opt;
99   EXPECT_FALSE(bool(opt));
100   EXPECT_EQ(42, opt.value_or(42));
101   opt = 4;
102   EXPECT_TRUE(bool(opt));
103   EXPECT_EQ(4, *opt);
104   EXPECT_EQ(4, opt.value_or(42));
105   opt = 5;
106   EXPECT_EQ(5, *opt);
107   opt.clear();
108   EXPECT_FALSE(bool(opt));
109 }
110
111 class MoveTester {
112 public:
113   /* implicit */ MoveTester(const char* s) : s_(s) {}
114   MoveTester(const MoveTester&) = default;
115   MoveTester(MoveTester&& other) noexcept {
116     s_ = std::move(other.s_);
117     other.s_ = "";
118   }
119   MoveTester& operator=(const MoveTester&) = default;
120   MoveTester& operator=(MoveTester&&) = default;
121 private:
122   friend bool operator==(const MoveTester& o1, const MoveTester& o2);
123   std::string s_;
124 };
125
126 bool operator==(const MoveTester& o1, const MoveTester& o2) {
127   return o1.s_ == o2.s_;
128 }
129
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)));
136   EXPECT_EQ("", dflt);
137   EXPECT_EQ("world", opt.value_or("world"));
138
139   dflt = "hello";
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)));
145   EXPECT_EQ("", dflt);
146   EXPECT_EQ("world", optc.value_or("world"));
147
148   dflt = "hello";
149   opt = "meow";
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
154 }
155
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)));
160 }
161
162 TEST(Optional, EmptyConstruct) {
163   Optional<int> opt;
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));
169 }
170
171 TEST(Optional, Unique) {
172   Optional<unique_ptr<int>> opt;
173
174   opt.clear();
175   EXPECT_FALSE(bool(opt));
176   // empty->emplaced
177   opt.emplace(new int(5));
178   EXPECT_TRUE(bool(opt));
179   EXPECT_EQ(5, **opt);
180
181   opt.clear();
182   // empty->moved
183   opt = unique_ptr<int>(new int(6));
184   EXPECT_EQ(6, **opt);
185   // full->moved
186   opt = unique_ptr<int>(new int(7));
187   EXPECT_EQ(7, **opt);
188
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);
194
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));
199   EXPECT_EQ(7, **opt);
200 }
201
202 TEST(Optional, Shared) {
203   shared_ptr<int> ptr;
204   Optional<shared_ptr<int>> opt;
205   EXPECT_FALSE(bool(opt));
206   // empty->emplaced
207   opt.emplace(new int(5));
208   EXPECT_TRUE(bool(opt));
209   ptr = opt.value();
210   EXPECT_EQ(ptr.get(), opt->get());
211   EXPECT_EQ(2, ptr.use_count());
212   opt.clear();
213   EXPECT_EQ(1, ptr.use_count());
214   // full->copied
215   opt = ptr;
216   EXPECT_EQ(2, ptr.use_count());
217   EXPECT_EQ(ptr.get(), opt->get());
218   opt.clear();
219   EXPECT_EQ(1, ptr.use_count());
220   // full->moved
221   opt = std::move(ptr);
222   EXPECT_EQ(1, opt->use_count());
223   EXPECT_EQ(nullptr, ptr.get());
224   {
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());
231     copied = moved;
232     EXPECT_EQ(2, moved->use_count());
233   }
234 }
235
236 TEST(Optional, Order) {
237   std::vector<Optional<int>> vect{
238     { none },
239     { 3 },
240     { 1 },
241     { none },
242     { 2 },
243   };
244   std::vector<Optional<int>> expected {
245     { none },
246     { none },
247     { 1 },
248     { 2 },
249     { 3 },
250   };
251   std::sort(vect.begin(), vect.end());
252   EXPECT_EQ(vect, expected);
253 }
254
255 TEST(Optional, Swap) {
256   Optional<std::string> a;
257   Optional<std::string> b;
258
259   swap(a, b);
260   EXPECT_FALSE(a.hasValue());
261   EXPECT_FALSE(b.hasValue());
262
263   a = "hello";
264   EXPECT_TRUE(a.hasValue());
265   EXPECT_FALSE(b.hasValue());
266   EXPECT_EQ("hello", a.value());
267
268   swap(a, b);
269   EXPECT_FALSE(a.hasValue());
270   EXPECT_TRUE(b.hasValue());
271   EXPECT_EQ("hello", b.value());
272
273   a = "bye";
274   EXPECT_TRUE(a.hasValue());
275   EXPECT_EQ("bye", a.value());
276
277   swap(a, b);
278 }
279
280 TEST(Optional, Comparisons) {
281   Optional<int> o_;
282   Optional<int> o1(1);
283   Optional<int> o2(2);
284
285   EXPECT_TRUE(o_ <= (o_));
286   EXPECT_TRUE(o_ == (o_));
287   EXPECT_TRUE(o_ >= (o_));
288
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);
297
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);
306
307   /* folly::Optional explicitly doesn't support comparisons with contained value
308   EXPECT_TRUE(1 < o2);
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);
315   EXPECT_TRUE(2 > o1);
316
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);
325   */
326
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);
342
343   boost::optional<bool> bob(false);
344   EXPECT_TRUE((bool)bob);
345   EXPECT_TRUE(bob == false); // well that was confusing
346   EXPECT_FALSE(bob != false);
347 }
348
349 TEST(Optional, Conversions) {
350   Optional<bool> mbool;
351   Optional<short> mshort;
352   Optional<char*> mstr;
353   Optional<int> mint;
354
355   //These don't compile
356   //bool b = mbool;
357   //short s = mshort;
358   //char* c = mstr;
359   //int x = mint;
360   //char* c(mstr);
361   //short s(mshort);
362   //int x(mint);
363
364   // intended explicit operator bool, for if (opt).
365   bool b(mbool);
366
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
370       ;
371     }
372   }
373
374   mbool = false;
375   EXPECT_TRUE(bool(mbool));
376   EXPECT_FALSE(*mbool);
377
378   mbool = true;
379   EXPECT_TRUE(bool(mbool));
380   EXPECT_TRUE(*mbool);
381
382   mbool = none;
383   EXPECT_FALSE(bool(mbool));
384
385   // No conversion allowed; does not compile
386   // EXPECT_TRUE(mbool == false);
387 }
388
389 TEST(Optional, Pointee) {
390   Optional<int> x;
391   EXPECT_FALSE(get_pointer(x));
392   x = 1;
393   EXPECT_TRUE(get_pointer(x));
394   *get_pointer(x) = 2;
395   EXPECT_TRUE(*x == 2);
396   x = none;
397   EXPECT_FALSE(get_pointer(x));
398 }
399
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");
406   *optStr = "cde";
407   EXPECT_EQ(s, "abc");
408   EXPECT_EQ(*optStr, "cde");
409
410   // L-value version
411   std::string s2("abc");
412   auto optStr2 = make_optional(s2);
413   ASSERT_TRUE(optStr2.hasValue());
414   EXPECT_EQ(*optStr2, "abc");
415   *optStr2 = "cde";
416   // it's vital to check that s2 wasn't clobbered
417   EXPECT_EQ(s2, "abc");
418
419   // L-value reference version
420   std::string& s3(s2);
421   auto optStr3 = make_optional(s3);
422   ASSERT_TRUE(optStr3.hasValue());
423   EXPECT_EQ(*optStr3, "abc");
424   *optStr3 = "cde";
425   EXPECT_EQ(s3, "abc");
426
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);
433 }
434
435 #ifdef __clang__
436 # pragma clang diagnostic push
437 # if __clang_major__ > 3 || __clang_minor__ >= 6
438 #  pragma clang diagnostic ignored "-Wself-move"
439 # endif
440 #endif
441
442 TEST(Optional, SelfAssignment) {
443   Optional<int> a = 42;
444   a = a;
445   ASSERT_TRUE(a.hasValue() && a.value() == 42);
446
447   Optional<int> b = 23333333;
448   b = std::move(b);
449   ASSERT_TRUE(b.hasValue() && b.value() == 23333333);
450 }
451
452 #ifdef __clang__
453 #pragma clang diagnostic pop
454 #endif
455
456 class ContainsOptional {
457  public:
458   ContainsOptional() { }
459   explicit ContainsOptional(int x) : opt_(x) { }
460   bool hasValue() const { return opt_.hasValue(); }
461   int value() const { return opt_.value(); }
462
463   ContainsOptional(const ContainsOptional &other) = default;
464   ContainsOptional& operator=(const ContainsOptional &other) = default;
465   ContainsOptional(ContainsOptional &&other) = default;
466   ContainsOptional& operator=(ContainsOptional &&other) = default;
467
468  private:
469   Optional<int> opt_;
470 };
471
472 /**
473  * Test that a class containing an Optional can be copy and move assigned.
474  * This was broken under gcc 4.7 until assignment operators were explicitly
475  * defined.
476  */
477 TEST(Optional, AssignmentContained) {
478   {
479     ContainsOptional source(5), target;
480     target = source;
481     EXPECT_TRUE(target.hasValue());
482     EXPECT_EQ(5, target.value());
483   }
484
485   {
486     ContainsOptional source(5), target;
487     target = std::move(source);
488     EXPECT_TRUE(target.hasValue());
489     EXPECT_EQ(5, target.value());
490     EXPECT_FALSE(source.hasValue());
491   }
492
493   {
494     ContainsOptional opt_uninit, target(10);
495     target = opt_uninit;
496     EXPECT_FALSE(target.hasValue());
497   }
498 }
499
500 }