fix compiler warnings from gcc-4.9 + -Wunused-variable
[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&& other) noexcept {
121     s_ = std::move(other.s_);
122     other.s_ = "";
123     return *this;
124   }
125 private:
126   friend bool operator==(const MoveTester& o1, const MoveTester& o2);
127   std::string s_;
128 };
129
130 bool operator==(const MoveTester& o1, const MoveTester& o2) {
131   return o1.s_ == o2.s_;
132 }
133
134 TEST(Optional, value_or_rvalue_arg) {
135   Optional<MoveTester> opt;
136   MoveTester dflt = "hello";
137   EXPECT_EQ("hello", opt.value_or(dflt));
138   EXPECT_EQ("hello", dflt);
139   EXPECT_EQ("hello", opt.value_or(std::move(dflt)));
140   EXPECT_EQ("", dflt);
141   EXPECT_EQ("world", opt.value_or("world"));
142
143   dflt = "hello";
144   // Make sure that the const overload works on const objects
145   const auto& optc = opt;
146   EXPECT_EQ("hello", optc.value_or(dflt));
147   EXPECT_EQ("hello", dflt);
148   EXPECT_EQ("hello", optc.value_or(std::move(dflt)));
149   EXPECT_EQ("", dflt);
150   EXPECT_EQ("world", optc.value_or("world"));
151
152   dflt = "hello";
153   opt = "meow";
154   EXPECT_EQ("meow", opt.value_or(dflt));
155   EXPECT_EQ("hello", dflt);
156   EXPECT_EQ("meow", opt.value_or(std::move(dflt)));
157   EXPECT_EQ("hello", dflt);  // only moved if used
158 }
159
160 TEST(Optional, value_or_noncopyable) {
161   Optional<std::unique_ptr<int>> opt;
162   std::unique_ptr<int> dflt(new int(42));
163   EXPECT_EQ(42, *std::move(opt).value_or(std::move(dflt)));
164 }
165
166 struct ExpectingDeleter {
167   explicit ExpectingDeleter(int expected) : expected(expected) { }
168   int expected;
169   void operator()(const int* ptr) {
170     EXPECT_EQ(*ptr, expected);
171     delete ptr;
172   }
173 };
174
175 TEST(Optional, value_life_extention) {
176   // Extends the life of the value.
177   const auto& ptr = Optional<std::unique_ptr<int, ExpectingDeleter>>(
178       {new int(42), ExpectingDeleter{1337}}).value();
179   *ptr = 1337;
180 }
181
182 TEST(Optional, value_move) {
183   auto ptr = Optional<std::unique_ptr<int, ExpectingDeleter>>(
184       {new int(42), ExpectingDeleter{1337}}).value();
185   *ptr = 1337;
186 }
187
188 TEST(Optional, dereference_life_extention) {
189   // Extends the life of the value.
190   const auto& ptr = *Optional<std::unique_ptr<int, ExpectingDeleter>>(
191       {new int(42), ExpectingDeleter{1337}});
192   *ptr = 1337;
193 }
194
195 TEST(Optional, dereference_move) {
196   auto ptr = *Optional<std::unique_ptr<int, ExpectingDeleter>>(
197       {new int(42), ExpectingDeleter{1337}});
198   *ptr = 1337;
199 }
200
201 TEST(Optional, EmptyConstruct) {
202   Optional<int> opt;
203   EXPECT_FALSE(bool(opt));
204   Optional<int> test1(opt);
205   EXPECT_FALSE(bool(test1));
206   Optional<int> test2(std::move(opt));
207   EXPECT_FALSE(bool(test2));
208 }
209
210 TEST(Optional, Unique) {
211   Optional<unique_ptr<int>> opt;
212
213   opt.clear();
214   EXPECT_FALSE(bool(opt));
215   // empty->emplaced
216   opt.emplace(new int(5));
217   EXPECT_TRUE(bool(opt));
218   EXPECT_EQ(5, **opt);
219
220   opt.clear();
221   // empty->moved
222   opt = unique_ptr<int>(new int(6));
223   EXPECT_EQ(6, **opt);
224   // full->moved
225   opt = unique_ptr<int>(new int(7));
226   EXPECT_EQ(7, **opt);
227
228   // move it out by move construct
229   Optional<unique_ptr<int>> moved(std::move(opt));
230   EXPECT_TRUE(bool(moved));
231   EXPECT_FALSE(bool(opt));
232   EXPECT_EQ(7, **moved);
233
234   EXPECT_TRUE(bool(moved));
235   opt = std::move(moved); // move it back by move assign
236   EXPECT_FALSE(bool(moved));
237   EXPECT_TRUE(bool(opt));
238   EXPECT_EQ(7, **opt);
239 }
240
241 TEST(Optional, Shared) {
242   shared_ptr<int> ptr;
243   Optional<shared_ptr<int>> opt;
244   EXPECT_FALSE(bool(opt));
245   // empty->emplaced
246   opt.emplace(new int(5));
247   EXPECT_TRUE(bool(opt));
248   ptr = opt.value();
249   EXPECT_EQ(ptr.get(), opt->get());
250   EXPECT_EQ(2, ptr.use_count());
251   opt.clear();
252   EXPECT_EQ(1, ptr.use_count());
253   // full->copied
254   opt = ptr;
255   EXPECT_EQ(2, ptr.use_count());
256   EXPECT_EQ(ptr.get(), opt->get());
257   opt.clear();
258   EXPECT_EQ(1, ptr.use_count());
259   // full->moved
260   opt = std::move(ptr);
261   EXPECT_EQ(1, opt->use_count());
262   EXPECT_EQ(nullptr, ptr.get());
263   {
264     Optional<shared_ptr<int>> copied(opt);
265     EXPECT_EQ(2, opt->use_count());
266     Optional<shared_ptr<int>> moved(std::move(opt));
267     EXPECT_EQ(2, moved->use_count());
268     moved.emplace(new int(6));
269     EXPECT_EQ(1, moved->use_count());
270     copied = moved;
271     EXPECT_EQ(2, moved->use_count());
272   }
273 }
274
275 TEST(Optional, Order) {
276   std::vector<Optional<int>> vect{
277     { none },
278     { 3 },
279     { 1 },
280     { none },
281     { 2 },
282   };
283   std::vector<Optional<int>> expected {
284     { none },
285     { none },
286     { 1 },
287     { 2 },
288     { 3 },
289   };
290   std::sort(vect.begin(), vect.end());
291   EXPECT_EQ(vect, expected);
292 }
293
294 TEST(Optional, Swap) {
295   Optional<std::string> a;
296   Optional<std::string> b;
297
298   swap(a, b);
299   EXPECT_FALSE(a.hasValue());
300   EXPECT_FALSE(b.hasValue());
301
302   a = "hello";
303   EXPECT_TRUE(a.hasValue());
304   EXPECT_FALSE(b.hasValue());
305   EXPECT_EQ("hello", a.value());
306
307   swap(a, b);
308   EXPECT_FALSE(a.hasValue());
309   EXPECT_TRUE(b.hasValue());
310   EXPECT_EQ("hello", b.value());
311
312   a = "bye";
313   EXPECT_TRUE(a.hasValue());
314   EXPECT_EQ("bye", a.value());
315
316   swap(a, b);
317 }
318
319 TEST(Optional, Comparisons) {
320   Optional<int> o_;
321   Optional<int> o1(1);
322   Optional<int> o2(2);
323
324   EXPECT_TRUE(o_ <= (o_));
325   EXPECT_TRUE(o_ == (o_));
326   EXPECT_TRUE(o_ >= (o_));
327
328   EXPECT_TRUE(o1 < o2);
329   EXPECT_TRUE(o1 <= o2);
330   EXPECT_TRUE(o1 <= (o1));
331   EXPECT_TRUE(o1 == (o1));
332   EXPECT_TRUE(o1 != o2);
333   EXPECT_TRUE(o1 >= (o1));
334   EXPECT_TRUE(o2 >= o1);
335   EXPECT_TRUE(o2 > o1);
336
337   EXPECT_FALSE(o2 < o1);
338   EXPECT_FALSE(o2 <= o1);
339   EXPECT_FALSE(o2 <= o1);
340   EXPECT_FALSE(o2 == o1);
341   EXPECT_FALSE(o1 != (o1));
342   EXPECT_FALSE(o1 >= o2);
343   EXPECT_FALSE(o1 >= o2);
344   EXPECT_FALSE(o1 > o2);
345
346   /* folly::Optional explicitly doesn't support comparisons with contained value
347   EXPECT_TRUE(1 < o2);
348   EXPECT_TRUE(1 <= o2);
349   EXPECT_TRUE(1 <= o1);
350   EXPECT_TRUE(1 == o1);
351   EXPECT_TRUE(2 != o1);
352   EXPECT_TRUE(1 >= o1);
353   EXPECT_TRUE(2 >= o1);
354   EXPECT_TRUE(2 > o1);
355
356   EXPECT_FALSE(o2 < 1);
357   EXPECT_FALSE(o2 <= 1);
358   EXPECT_FALSE(o2 <= 1);
359   EXPECT_FALSE(o2 == 1);
360   EXPECT_FALSE(o2 != 2);
361   EXPECT_FALSE(o1 >= 2);
362   EXPECT_FALSE(o1 >= 2);
363   EXPECT_FALSE(o1 > 2);
364   */
365
366   // boost::optional does support comparison with contained value, which can
367   // lead to confusion when a bool is contained
368   boost::optional<int> boi(3);
369   EXPECT_TRUE(boi < 5);
370   EXPECT_TRUE(boi <= 4);
371   EXPECT_TRUE(boi == 3);
372   EXPECT_TRUE(boi != 2);
373   EXPECT_TRUE(boi >= 1);
374   EXPECT_TRUE(boi > 0);
375   EXPECT_TRUE(1 <  boi);
376   EXPECT_TRUE(2 <= boi);
377   EXPECT_TRUE(3 == boi);
378   EXPECT_TRUE(4 != boi);
379   EXPECT_TRUE(5 >= boi);
380   EXPECT_TRUE(6 >  boi);
381
382   boost::optional<bool> bob(false);
383   EXPECT_TRUE((bool)bob);
384   EXPECT_TRUE(bob == false); // well that was confusing
385   EXPECT_FALSE(bob != false);
386 }
387
388 TEST(Optional, Conversions) {
389   Optional<bool> mbool;
390   Optional<short> mshort;
391   Optional<char*> mstr;
392   Optional<int> mint;
393
394   //These don't compile
395   //bool b = mbool;
396   //short s = mshort;
397   //char* c = mstr;
398   //int x = mint;
399   //char* c(mstr);
400   //short s(mshort);
401   //int x(mint);
402
403   // intended explicit operator bool, for if (opt).
404   bool b(mbool);
405   EXPECT_FALSE(b);
406
407   // Truthy tests work and are not ambiguous
408   if (mbool && mshort && mstr && mint) { // only checks not-empty
409     if (*mbool && *mshort && *mstr && *mint) { // only checks value
410       ;
411     }
412   }
413
414   mbool = false;
415   EXPECT_TRUE(bool(mbool));
416   EXPECT_FALSE(*mbool);
417
418   mbool = true;
419   EXPECT_TRUE(bool(mbool));
420   EXPECT_TRUE(*mbool);
421
422   mbool = none;
423   EXPECT_FALSE(bool(mbool));
424
425   // No conversion allowed; does not compile
426   // EXPECT_TRUE(mbool == false);
427 }
428
429 TEST(Optional, Pointee) {
430   Optional<int> x;
431   EXPECT_FALSE(get_pointer(x));
432   x = 1;
433   EXPECT_TRUE(get_pointer(x));
434   *get_pointer(x) = 2;
435   EXPECT_TRUE(*x == 2);
436   x = none;
437   EXPECT_FALSE(get_pointer(x));
438 }
439
440 TEST(Optional, MakeOptional) {
441   // const L-value version
442   const std::string s("abc");
443   auto optStr = make_optional(s);
444   ASSERT_TRUE(optStr.hasValue());
445   EXPECT_EQ(*optStr, "abc");
446   *optStr = "cde";
447   EXPECT_EQ(s, "abc");
448   EXPECT_EQ(*optStr, "cde");
449
450   // L-value version
451   std::string s2("abc");
452   auto optStr2 = make_optional(s2);
453   ASSERT_TRUE(optStr2.hasValue());
454   EXPECT_EQ(*optStr2, "abc");
455   *optStr2 = "cde";
456   // it's vital to check that s2 wasn't clobbered
457   EXPECT_EQ(s2, "abc");
458
459   // L-value reference version
460   std::string& s3(s2);
461   auto optStr3 = make_optional(s3);
462   ASSERT_TRUE(optStr3.hasValue());
463   EXPECT_EQ(*optStr3, "abc");
464   *optStr3 = "cde";
465   EXPECT_EQ(s3, "abc");
466
467   // R-value ref version
468   unique_ptr<int> pInt(new int(3));
469   auto optIntPtr = make_optional(std::move(pInt));
470   EXPECT_TRUE(pInt.get() == nullptr);
471   ASSERT_TRUE(optIntPtr.hasValue());
472   EXPECT_EQ(**optIntPtr, 3);
473 }
474
475 #ifdef __clang__
476 # pragma clang diagnostic push
477 # if __clang_major__ > 3 || __clang_minor__ >= 6
478 #  pragma clang diagnostic ignored "-Wself-move"
479 # endif
480 #endif
481
482 TEST(Optional, SelfAssignment) {
483   Optional<int> a = 42;
484   a = a;
485   ASSERT_TRUE(a.hasValue() && a.value() == 42);
486
487   Optional<int> b = 23333333;
488   b = std::move(b);
489   ASSERT_TRUE(b.hasValue() && b.value() == 23333333);
490 }
491
492 #ifdef __clang__
493 #pragma clang diagnostic pop
494 #endif
495
496 class ContainsOptional {
497  public:
498   ContainsOptional() { }
499   explicit ContainsOptional(int x) : opt_(x) { }
500   bool hasValue() const { return opt_.hasValue(); }
501   int value() const { return opt_.value(); }
502
503   ContainsOptional(const ContainsOptional &other) = default;
504   ContainsOptional& operator=(const ContainsOptional &other) = default;
505   ContainsOptional(ContainsOptional &&other) = default;
506   ContainsOptional& operator=(ContainsOptional &&other) = default;
507
508  private:
509   Optional<int> opt_;
510 };
511
512 /**
513  * Test that a class containing an Optional can be copy and move assigned.
514  * This was broken under gcc 4.7 until assignment operators were explicitly
515  * defined.
516  */
517 TEST(Optional, AssignmentContained) {
518   {
519     ContainsOptional source(5), target;
520     target = source;
521     EXPECT_TRUE(target.hasValue());
522     EXPECT_EQ(5, target.value());
523   }
524
525   {
526     ContainsOptional source(5), target;
527     target = std::move(source);
528     EXPECT_TRUE(target.hasValue());
529     EXPECT_EQ(5, target.value());
530     EXPECT_FALSE(source.hasValue());
531   }
532
533   {
534     ContainsOptional opt_uninit, target(10);
535     target = opt_uninit;
536     EXPECT_FALSE(target.hasValue());
537   }
538 }
539
540 TEST(Optional, Exceptions) {
541   Optional<int> empty;
542   EXPECT_THROW(empty.value(), OptionalEmptyException);
543 }
544
545 }