logging: add a LogHandler::getConfig() method
[folly.git] / folly / test / ScopeGuardTest.cpp
index 35b1e3a905e8328f86b75935b8a947dadd6d1752..0b635c02e1327daf5244c8142cd0a07326d2be59 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013 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.
  * limitations under the License.
  */
 
-#include "folly/ScopeGuard.h"
+#include <folly/ScopeGuard.h>
 
-#include <gflags/gflags.h>
-#include <gtest/gtest.h>
 #include <glog/logging.h>
 
 #include <functional>
 #include <stdexcept>
 
+#include <folly/portability/GTest.h>
+
 using folly::ScopeGuard;
 using folly::makeGuard;
 using std::vector;
@@ -48,6 +48,7 @@ TEST(ScopeGuard, DifferentWaysToBind) {
     // There is implicit conversion from func pointer
     // double (*)() to function<void()>.
     ScopeGuard g = makeGuard(returnsDouble);
+    (void)g;
   }
 
   vector<int> v;
@@ -57,36 +58,42 @@ TEST(ScopeGuard, DifferentWaysToBind) {
   {
     // binding to member function.
     ScopeGuard g = makeGuard(std::bind(&vector<int>::pop_back, &v));
+    (void)g;
   }
   EXPECT_EQ(0, v.size());
 
   {
     // bind member function with args. v is passed-by-value!
     ScopeGuard g = makeGuard(std::bind(push_back, v, 2));
+    (void)g;
   }
   EXPECT_EQ(0, v.size()); // push_back happened on a copy of v... fail!
 
   // pass in an argument by pointer so to avoid copy.
   {
     ScopeGuard g = makeGuard(std::bind(push_back, &v, 4));
+    (void)g;
   }
   EXPECT_EQ(1, v.size());
 
   {
     // pass in an argument by reference so to avoid copy.
     ScopeGuard g = makeGuard(std::bind(push_back, std::ref(v), 4));
+    (void)g;
   }
   EXPECT_EQ(2, v.size());
 
   // lambda with a reference to v
   {
     ScopeGuard g = makeGuard([&] { v.push_back(5); });
+    (void)g;
   }
   EXPECT_EQ(3, v.size());
 
   // lambda with a copy of v
   {
     ScopeGuard g = makeGuard([v] () mutable { v.push_back(6); });
+    (void)g;
   }
   EXPECT_EQ(3, v.size());
 
@@ -95,6 +102,7 @@ TEST(ScopeGuard, DifferentWaysToBind) {
   {
     MyFunctor f(&n);
     ScopeGuard g = makeGuard(f);
+    (void)g;
   }
   EXPECT_EQ(1, n);
 
@@ -102,6 +110,7 @@ TEST(ScopeGuard, DifferentWaysToBind) {
   n = 0;
   {
     ScopeGuard g = makeGuard(MyFunctor(&n));
+    (void)g;
   }
   EXPECT_EQ(1, n);
 
@@ -109,6 +118,7 @@ TEST(ScopeGuard, DifferentWaysToBind) {
   n = 2;
   {
     auto g = makeGuard(MyFunctor(&n));
+    (void)g;
   }
   EXPECT_EQ(3, n);
 
@@ -116,6 +126,7 @@ TEST(ScopeGuard, DifferentWaysToBind) {
   n = 10;
   {
     const auto& g = makeGuard(MyFunctor(&n));
+    (void)g;
   }
   EXPECT_EQ(11, n);
 }
@@ -125,8 +136,10 @@ TEST(ScopeGuard, GuardException) {
     ScopeGuard g = makeGuard([&] {
       throw std::runtime_error("destructors should never throw!");
     });
+    (void)g;
   },
-  "destructors should never throw");
+  "destructors should never throw!"
+  );
 }
 
 /**
@@ -195,6 +208,7 @@ void testFinally(ErrorBehavior error) {
 
   try {
     ScopeGuard guard = makeGuard([&] { cleanupOccurred = true; });
+    (void)guard;
 
     try {
       if (error == ErrorBehavior::HANDLED_ERROR) {
@@ -227,7 +241,7 @@ TEST(ScopeGuard, TEST_SCOPE_EXIT) {
 }
 
 class Foo {
-public:
+ public:
   Foo() {}
   ~Foo() {
     try {
@@ -252,8 +266,59 @@ TEST(ScopeGuard, TEST_SCOPE_FAILURE2) {
   }
 }
 
-int main(int argc, char** argv) {
-  testing::InitGoogleTest(&argc, argv);
-  google::ParseCommandLineFlags(&argc, &argv, true);
-  return RUN_ALL_TESTS();
+void testScopeFailAndScopeSuccess(ErrorBehavior error, bool expectFail) {
+  bool scopeFailExecuted = false;
+  bool scopeSuccessExecuted = false;
+
+  try {
+    SCOPE_FAIL { scopeFailExecuted = true; };
+    SCOPE_SUCCESS { scopeSuccessExecuted = true; };
+
+    try {
+      if (error == ErrorBehavior::HANDLED_ERROR) {
+        throw std::runtime_error("throwing an expected error");
+      } else if (error == ErrorBehavior::UNHANDLED_ERROR) {
+        throw "never throw raw strings";
+      }
+    } catch (const std::runtime_error&) {
+    }
+  } catch (...) {
+    // Outer catch to swallow the error for the UNHANDLED_ERROR behavior
+  }
+
+  EXPECT_EQ(expectFail, scopeFailExecuted);
+  EXPECT_EQ(!expectFail, scopeSuccessExecuted);
+}
+
+TEST(ScopeGuard, TEST_SCOPE_FAIL_AND_SCOPE_SUCCESS) {
+  testScopeFailAndScopeSuccess(ErrorBehavior::SUCCESS, false);
+  testScopeFailAndScopeSuccess(ErrorBehavior::HANDLED_ERROR, false);
+  testScopeFailAndScopeSuccess(ErrorBehavior::UNHANDLED_ERROR, true);
+}
+
+TEST(ScopeGuard, TEST_SCOPE_SUCCESS_THROW) {
+  auto lambda = []() {
+    SCOPE_SUCCESS { throw std::runtime_error("ehm"); };
+  };
+  EXPECT_THROW(lambda(), std::runtime_error);
+}
+
+TEST(ScopeGuard, TEST_THROWING_CLEANUP_ACTION) {
+  struct ThrowingCleanupAction {
+    explicit ThrowingCleanupAction(int& scopeExitExecuted)
+        : scopeExitExecuted_(scopeExitExecuted) {}
+    [[noreturn]]
+    ThrowingCleanupAction(const ThrowingCleanupAction& other)
+        : scopeExitExecuted_(other.scopeExitExecuted_) {
+      throw std::runtime_error("whoa");
+    }
+    void operator()() { ++scopeExitExecuted_; }
+
+   private:
+    int& scopeExitExecuted_;
+  };
+  int scopeExitExecuted = 0;
+  ThrowingCleanupAction onExit(scopeExitExecuted);
+  EXPECT_THROW(makeGuard(onExit), std::runtime_error);
+  EXPECT_EQ(scopeExitExecuted, 1);
 }