X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2Ftest%2FScopeGuardTest.cpp;h=1303ee741a6c9c515b1e0b8d788dbdb2a5341269;hb=HEAD;hp=b741e37503536cfbc7977e316b1f4e607b82cd16;hpb=77cc480dad0500f00717a5feec7ac37a4e3ac0a9;p=folly.git diff --git a/folly/test/ScopeGuardTest.cpp b/folly/test/ScopeGuardTest.cpp index b741e375..1303ee74 100644 --- a/folly/test/ScopeGuardTest.cpp +++ b/folly/test/ScopeGuardTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013 Facebook, Inc. + * Copyright 2011-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,17 +14,15 @@ * limitations under the License. */ -#include "folly/ScopeGuard.h" -#include "folly/Portability.h" +#include -#include -#include #include #include #include -using folly::ScopeGuard; +#include + using folly::makeGuard; using std::vector; @@ -48,7 +46,8 @@ TEST(ScopeGuard, DifferentWaysToBind) { { // There is implicit conversion from func pointer // double (*)() to function. - ScopeGuard g = makeGuard(returnsDouble); + auto g = makeGuard(returnsDouble); + (void)g; } vector v; @@ -57,37 +56,43 @@ TEST(ScopeGuard, DifferentWaysToBind) { v.push_back(1); { // binding to member function. - ScopeGuard g = makeGuard(std::bind(&vector::pop_back, &v)); + auto g = makeGuard(std::bind(&vector::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)); + auto 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)); + auto 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)); + auto 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); }); + auto 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); }); + auto g = makeGuard([v]() mutable { v.push_back(6); }); + (void)g; } EXPECT_EQ(3, v.size()); @@ -95,14 +100,16 @@ TEST(ScopeGuard, DifferentWaysToBind) { int n = 0; { MyFunctor f(&n); - ScopeGuard g = makeGuard(f); + auto g = makeGuard(f); + (void)g; } EXPECT_EQ(1, n); // temporary functor object n = 0; { - ScopeGuard g = makeGuard(MyFunctor(&n)); + auto g = makeGuard(MyFunctor(&n)); + (void)g; } EXPECT_EQ(1, n); @@ -110,6 +117,7 @@ TEST(ScopeGuard, DifferentWaysToBind) { n = 2; { auto g = makeGuard(MyFunctor(&n)); + (void)g; } EXPECT_EQ(3, n); @@ -117,22 +125,15 @@ TEST(ScopeGuard, DifferentWaysToBind) { n = 10; { const auto& g = makeGuard(MyFunctor(&n)); + (void)g; } EXPECT_EQ(11, n); } TEST(ScopeGuard, GuardException) { - EXPECT_DEATH({ - ScopeGuard g = makeGuard([&] { - throw std::runtime_error("destructors should never throw!"); - }); - }, -#if FOLLY_USE_LIBCPP - "terminate called throwing an exception" -#else - "destructors should never throw" -#endif - ); + EXPECT_DEATH( + makeGuard([] { throw std::runtime_error("dtors should never throw!"); }), + "dtors should never throw!"); } /** @@ -148,7 +149,7 @@ void testUndoAction(bool failure) { v.push_back(1); // The guard is triggered to undo the insertion unless dismiss() is called. - ScopeGuard guard = makeGuard([&] { v.pop_back(); }); + auto guard = makeGuard([&] { v.pop_back(); }); // Do some action; Use the failure argument to pretend // if it failed or succeeded. @@ -200,7 +201,8 @@ void testFinally(ErrorBehavior error) { bool cleanupOccurred = false; try { - ScopeGuard guard = makeGuard([&] { cleanupOccurred = true; }); + auto guard = makeGuard([&] { cleanupOccurred = true; }); + (void)guard; try { if (error == ErrorBehavior::HANDLED_ERROR) { @@ -233,7 +235,7 @@ TEST(ScopeGuard, TEST_SCOPE_EXIT) { } class Foo { -public: + public: Foo() {} ~Foo() { try { @@ -258,8 +260,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); }