non-throwing, non-allocating exception_wrapper
[folly.git] / folly / test / OptionalTest.cpp
index 58a20685dfdb9cac218ec3d1b7570d1eae44e828..b7484dfa978b6488050eab02470ad15982ea9f67 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  */
 
 #include <folly/Optional.h>
+#include <folly/portability/GTest.h>
 
-#include <memory>
-#include <vector>
 #include <algorithm>
 #include <iomanip>
+#include <memory>
 #include <string>
+#include <type_traits>
+#include <unordered_map>
+#include <vector>
 
-#include <glog/logging.h>
-#include <gtest/gtest.h>
 #include <boost/optional.hpp>
 
 using std::unique_ptr;
@@ -117,7 +118,11 @@ public:
     other.s_ = "";
   }
   MoveTester& operator=(const MoveTester&) = default;
-  MoveTester& operator=(MoveTester&&) = default;
+  MoveTester& operator=(MoveTester&& other) noexcept {
+    s_ = std::move(other.s_);
+    other.s_ = "";
+    return *this;
+  }
 private:
   friend bool operator==(const MoveTester& o1, const MoveTester& o2);
   std::string s_;
@@ -159,6 +164,27 @@ TEST(Optional, value_or_noncopyable) {
   EXPECT_EQ(42, *std::move(opt).value_or(std::move(dflt)));
 }
 
+struct ExpectingDeleter {
+  explicit ExpectingDeleter(int expected) : expected(expected) { }
+  int expected;
+  void operator()(const int* ptr) {
+    EXPECT_EQ(*ptr, expected);
+    delete ptr;
+  }
+};
+
+TEST(Optional, value_move) {
+  auto ptr = Optional<std::unique_ptr<int, ExpectingDeleter>>(
+      {new int(42), ExpectingDeleter{1337}}).value();
+  *ptr = 1337;
+}
+
+TEST(Optional, dereference_move) {
+  auto ptr = *Optional<std::unique_ptr<int, ExpectingDeleter>>(
+      {new int(42), ExpectingDeleter{1337}});
+  *ptr = 1337;
+}
+
 TEST(Optional, EmptyConstruct) {
   Optional<int> opt;
   EXPECT_FALSE(bool(opt));
@@ -282,16 +308,16 @@ TEST(Optional, Comparisons) {
   Optional<int> o1(1);
   Optional<int> o2(2);
 
-  EXPECT_TRUE(o_ <= o_);
-  EXPECT_TRUE(o_ == o_);
-  EXPECT_TRUE(o_ >= o_);
+  EXPECT_TRUE(o_ <= (o_));
+  EXPECT_TRUE(o_ == (o_));
+  EXPECT_TRUE(o_ >= (o_));
 
   EXPECT_TRUE(o1 < o2);
   EXPECT_TRUE(o1 <= o2);
-  EXPECT_TRUE(o1 <= o1);
-  EXPECT_TRUE(o1 == o1);
+  EXPECT_TRUE(o1 <= (o1));
+  EXPECT_TRUE(o1 == (o1));
   EXPECT_TRUE(o1 != o2);
-  EXPECT_TRUE(o1 >= o1);
+  EXPECT_TRUE(o1 >= (o1));
   EXPECT_TRUE(o2 >= o1);
   EXPECT_TRUE(o2 > o1);
 
@@ -299,7 +325,7 @@ TEST(Optional, Comparisons) {
   EXPECT_FALSE(o2 <= o1);
   EXPECT_FALSE(o2 <= o1);
   EXPECT_FALSE(o2 == o1);
-  EXPECT_FALSE(o1 != o1);
+  EXPECT_FALSE(o1 != (o1));
   EXPECT_FALSE(o1 >= o2);
   EXPECT_FALSE(o1 >= o2);
   EXPECT_FALSE(o1 > o2);
@@ -341,7 +367,7 @@ TEST(Optional, Comparisons) {
   EXPECT_TRUE(6 >  boi);
 
   boost::optional<bool> bob(false);
-  EXPECT_TRUE(bob);
+  EXPECT_TRUE((bool)bob);
   EXPECT_TRUE(bob == false); // well that was confusing
   EXPECT_FALSE(bob != false);
 }
@@ -363,6 +389,7 @@ TEST(Optional, Conversions) {
 
   // intended explicit operator bool, for if (opt).
   bool b(mbool);
+  EXPECT_FALSE(b);
 
   // Truthy tests work and are not ambiguous
   if (mbool && mshort && mstr && mint) { // only checks not-empty
@@ -432,6 +459,11 @@ TEST(Optional, MakeOptional) {
   EXPECT_EQ(**optIntPtr, 3);
 }
 
+#if __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wself-move"
+#endif
+
 TEST(Optional, SelfAssignment) {
   Optional<int> a = 42;
   a = a;
@@ -442,6 +474,10 @@ TEST(Optional, SelfAssignment) {
   ASSERT_TRUE(b.hasValue() && b.value() == 23333333);
 }
 
+#if __clang__
+# pragma clang diagnostic pop
+#endif
+
 class ContainsOptional {
  public:
   ContainsOptional() { }
@@ -486,4 +522,34 @@ TEST(Optional, AssignmentContained) {
   }
 }
 
+TEST(Optional, Exceptions) {
+  Optional<int> empty;
+  EXPECT_THROW(empty.value(), OptionalEmptyException);
+}
+
+TEST(Optional, NoThrowDefaultConstructible) {
+  EXPECT_TRUE(std::is_nothrow_default_constructible<Optional<bool>>::value);
+}
+
+struct NoDestructor {};
+
+struct WithDestructor {
+  ~WithDestructor();
+};
+
+TEST(Optional, TriviallyDestructible) {
+  // These could all be static_asserts but EXPECT_* give much nicer output on
+  // failure.
+  EXPECT_TRUE(std::is_trivially_destructible<Optional<NoDestructor>>::value);
+  EXPECT_TRUE(std::is_trivially_destructible<Optional<int>>::value);
+  EXPECT_FALSE(std::is_trivially_destructible<Optional<WithDestructor>>::value);
+}
+
+TEST(Optional, Hash) {
+  // Test it's usable in std::unordered map (compile time check)
+  std::unordered_map<Optional<int>, Optional<int>> obj;
+  // Also check the std::hash template can be instantiated by the compiler
+  std::hash<Optional<int>>()(none);
+  std::hash<Optional<int>>()(3);
+}
 }