Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: test/plugin/ExceptionTest.cpp

Issue 5743529531801600: Playing with Default behavior for catch-all blocks
Patch Set: proposed changes Created March 31, 2015, 1:49 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/plugin/PluginStdAfx.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/plugin/ExceptionTest.cpp
diff --git a/test/plugin/ExceptionTest.cpp b/test/plugin/ExceptionTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e67e4103ac18f280edb548d1a18f742336031f0a
--- /dev/null
+++ b/test/plugin/ExceptionTest.cpp
@@ -0,0 +1,387 @@
+/*
+ * This file is part of Adblock Plus <https://adblockplus.org/>,
+ * Copyright (C) 2006-2015 Eyeo GmbH
+ *
+ * Adblock Plus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Adblock Plus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtest/gtest.h>
+#include "../../src/plugin/Exception.h"
+#include <stdexcept>
+
+void AssignCurrentException(std::exception_ptr& e)
+{
+ e = std::current_exception();
+}
+
+/*
+ * This test verifies that std::current_exception works during exception handling generally,
+ * not just in the immediate context of a 'catch' clause.
+ */
+TEST(Exception, CurrentExceptionWorksOutsideCatchHandler)
+{
+ std::exception_ptr ep;
+ const auto e = std::runtime_error("BJTCiRhkVAmvMg");
+ try
+ {
+ throw e;
+ }
+ catch (...)
+ {
+ AssignCurrentException(ep);
+ ASSERT_TRUE(ep);
+ /*
+ * You might think that the next set would be EXPECT_EQ betwwen the thrown exception and the original one.
+ * Such a test does not pass, nor is in necessary.
+ * The throw statement above is throwing by value, so it makes a copy.
+ */
+ }
+ try
+ {
+ rethrow_exception(ep);
+ FAIL() << "Statement after 'rethrow_exception' executed.";
+ }
+ catch (const std::runtime_error& ex)
+ {
+ EXPECT_STREQ(e.what(), ex.what());
+ return;
+ }
+ catch (...)
+ {
+ FAIL() << "Rethrown exception isn't the same type as the original";
+ }
+ FAIL() << "Did not return after catching rethrown exception";
+}
+
+/*
+ * A plain exception, not a subclass of std::runtime_error or std::logic_error.
+ */
+class PlainException
+ : public std::exception
+{
+ const char* what() const override
+ {
+ return "Plain";
+ };
+};
+
+struct NullHandlers
+{
+ static void Unknown(int) {}
+ static void Exception(const std::exception&,int) {}
+};
+
+/*
+ * The trivial tests assure that nothing escapes the catch-all function,
+ * that is, we ensure that nothing is thrown or rethrown.
+ */
+template<class X>
+void TrivialVoid(X x)
+{
+ ASSERT_NO_THROW(
+ {
+ try
+ {
+ throw x;
+ }
+ catch (...)
+ {
+ CatchAllVoid<NullHandlers>::Handler(0);
+ }
+ });
+}
+
+TEST(Exception, TrivialVoidUnknown)
+{
+ TrivialVoid(5);
+}
+
+TEST(Exception, TrivialVoidException)
+{
+ TrivialVoid(PlainException());
+}
+
+TEST(Exception, TrivialVoidLogicError)
+{
+ TrivialVoid(std::logic_error(""));
+}
+
+TEST(Exception, TrivialVoidRuntimeError)
+{
+ TrivialVoid(std::runtime_error(""));
+}
+
+TEST(Exception, TrivialVoidSystemError)
+{
+ TrivialVoid(std::system_error(std::error_code()));
+}
+
+enum class ReturnType
+{
+ InvalidCode = -1,
+ UnknownCode = 1,
+ ExceptionCode,
+ LogicErrorCode,
+ RuntimeErrorCode,
+ SystemErrorCode
+};
+
+struct NullHandlersReturn
+{
+ typedef ReturnType ReturnType;
+ static ReturnType Unknown(int) { return ReturnType::UnknownCode; }
+ static ReturnType Exception(const std::exception&, int) { return ReturnType::ExceptionCode; }
+ static ReturnType Exception(const std::logic_error&, int) { return ReturnType::LogicErrorCode; }
+ static ReturnType Exception(const std::runtime_error&, int) { return ReturnType::RuntimeErrorCode; }
+ static ReturnType Exception(const std::system_error&, int) { return ReturnType::SystemErrorCode; }
+};
+
+template<class X>
+void TrivialReturn(ReturnType n, X x)
+{
+ ASSERT_NO_THROW(
+ {
+ try
+ {
+ throw x;
+ }
+ catch (...)
+ {
+ ASSERT_EQ(n, CatchAllReturn<NullHandlersReturn>::Handler(0));
+ }
+ });
+}
+
+TEST(Exception, TrivialReturnUnknown)
+{
+ TrivialReturn(ReturnType::UnknownCode, 5);
+}
+
+TEST(Exception, TrivialReturnException)
+{
+ TrivialReturn(ReturnType::ExceptionCode, PlainException());
+}
+
+TEST(Exception, TrivialReturnLogicError)
+{
+ TrivialReturn(ReturnType::LogicErrorCode, std::logic_error(""));
+}
+
+TEST(Exception, TrivialReturnRuntimeError)
+{
+ TrivialReturn(ReturnType::RuntimeErrorCode, std::runtime_error(""));
+}
+
+TEST(Exception, TrivialReturnSystemError)
+{
+ TrivialReturn(ReturnType::SystemErrorCode, std::system_error(std::error_code()));
+}
+
+class Touchable
+{
+public:
+ Touchable() : m_isTouched(false){}
+ bool IsTouched() const
+ {
+ return m_isTouched;
+ }
+ void Touch()
+ {
+ m_isTouched = true;
+ }
+private:
+ // In the tests we use `Touchable&` as the type for UserData, so let's make
+ // it uncopyable to be sure that it's not copied somewhere by accident.
+ Touchable(const Touchable&);
+ void operator=(const Touchable&);
+private:
+ bool m_isTouched;
+};
+
+/*
+ * The simple tests ensure that the flow of control arrives in the correct subhandler.
+ */
+template<typename H, class X>
+void SimpleVoid(X x)
+{
+ Touchable userData;
+ ASSERT_NO_THROW(
+ {
+ try
+ {
+ throw x;
+ }
+ catch (...)
+ {
+ CatchAllVoid<H>::Handler<Touchable&>(userData);
+ }
+ });
+ EXPECT_TRUE(userData.IsTouched());
+}
+
+/*
+ * The base handler class for the simple tests fails every execution path.
+ * Each specific test redefines a single one of the handler functions that it uses.
+ */
+class SimpleHandlersBase
+{
+public:
+ typedef Touchable& UserData;
+ SimpleHandlersBase(){}
+ static void Unknown(UserData) { FAIL() << "Unexpected exception of unknown type"; }
+ static void Exception(const std::exception&, UserData) { FAIL() << "Unexpected std::exception"; }
+ static void Exception(const std::logic_error&, UserData) { FAIL() << "Unexpected std::logic_error"; }
sergei 2015/04/01 07:16:02 JIC, actually, these three methods as well as the
+ static void Exception(const std::runtime_error&, UserData) { FAIL() << "Unexpected std::runtime_error"; }
+ static void Exception(const std::system_error&, UserData) { FAIL() << "Unexpected std::system_error"; };
+};
+
+TEST(Exception, SimpleVoidUnknown)
+{
+ struct Handler :
+ public SimpleHandlersBase
+ {
+ static void Unknown(UserData h) { h.Touch(); }
+ };
+ SimpleVoid<Handler>(5);
+}
+
+TEST(Exception, SimpleVoidException)
+{
+ struct Handler :
+ public SimpleHandlersBase
+ {
+ static void Exception(const std::exception&, UserData h) { h.Touch(); }
+ };
+ SimpleVoid<Handler>(PlainException());
+}
+
+TEST(Exception, SimpleVoidLogicError)
+{
+ struct Handler :
+ public SimpleHandlersBase
+ {
+ static void Exception(const std::logic_error&, UserData h) { h.Touch(); }
+ using SimpleHandlersBase::Exception;
+ };
+ SimpleVoid<Handler>(std::logic_error(""));
+}
+
+TEST(Exception, SimpleVoidRuntimeError)
+{
+ struct Handler :
+ public SimpleHandlersBase
+ {
+ static void Exception(const std::runtime_error&, UserData h) { h.Touch(); }
+ using SimpleHandlersBase::Exception;
+ };
+ SimpleVoid<Handler>(std::runtime_error(""));
+}
+
+TEST(Exception, SimpleVoidSystemError)
+{
+ struct Handler :
+ public SimpleHandlersBase
+ {
+ static void Exception(const std::system_error&, UserData h) { h.Touch(); }
+ using SimpleHandlersBase::Exception;
+ };
+ SimpleVoid<Handler>(std::system_error(std::error_code()));
+}
+
+template<class H, class X>
+void SimpleReturn(ReturnType n, X x)
+{
+ Touchable userData;
+ ASSERT_NO_THROW(
+ {
+ try
+ {
+ throw x;
+ }
+ catch (...)
+ {
+ EXPECT_EQ(n, CatchAllReturn<H>::Handler<Touchable&>(userData));
+ }
+ });
+ EXPECT_TRUE(userData.IsTouched());
+}
+
+/*
+ * The base handlers class fails every execution path.
+ */
+class SimpleHandlersReturnBase
+{
+public:
+ typedef ReturnType ReturnType;
+ typedef Touchable& UserData;
+ static ReturnType Unknown(UserData) { ADD_FAILURE() << "Unexpected exception of unknown type"; return ReturnType::InvalidCode; }
+ static ReturnType Exception(const std::exception&, UserData) { ADD_FAILURE() << "Unexpected std::exception"; return ReturnType::InvalidCode; }
+ static ReturnType Exception(const std::logic_error&, UserData) { ADD_FAILURE() << "Unexpected std::logic_error"; return ReturnType::InvalidCode; }
+ static ReturnType Exception(const std::runtime_error&, UserData) { ADD_FAILURE() << "Unexpected std::runtime_error"; return ReturnType::InvalidCode; }
+ static ReturnType Exception(const std::system_error&, UserData) { ADD_FAILURE() << "Unexpected std::system_error"; return ReturnType::InvalidCode; }
+};
+
+TEST(Exception, SimpleReturnUnknown)
+{
+ struct Handler :
+ public SimpleHandlersReturnBase
+ {
+ static ReturnType Unknown(UserData h) { h.Touch(); return ReturnType::UnknownCode; }
+ using SimpleHandlersReturnBase::Exception;
+ };
+ SimpleReturn<Handler>(ReturnType::UnknownCode, 5);
+}
+
+TEST(Exception, SimpleReturnException)
+{
+ struct Handler :
+ public SimpleHandlersReturnBase
+ {
+ static ReturnType Exception(const std::exception&, UserData h) { h.Touch(); return ReturnType::ExceptionCode; }
+ using SimpleHandlersReturnBase::Exception;
+ };
+ SimpleReturn<Handler>(ReturnType::ExceptionCode, PlainException());
+}
+
+TEST(Exception, SimpleReturnLogicError)
+{
+ struct Handler :
+ public SimpleHandlersReturnBase
+ {
+ static ReturnType Exception(const std::logic_error&, UserData h) { h.Touch(); return ReturnType::LogicErrorCode; }
+ using SimpleHandlersReturnBase::Exception;
+ };
+ SimpleReturn<Handler>(ReturnType::LogicErrorCode, std::logic_error(""));
+}
+
+TEST(Exception, SimpleReturnRuntimeError)
+{
+ struct Handler :
+ public SimpleHandlersReturnBase
+ {
+ static ReturnType Exception(const std::runtime_error&, UserData h) { h.Touch(); return ReturnType::RuntimeErrorCode; }
+ using SimpleHandlersReturnBase::Exception;
+ };
+ SimpleReturn<Handler>(ReturnType::RuntimeErrorCode, std::runtime_error(""));
+}
+
+TEST(Exception, SimpleReturnSystemError)
+{
+ struct Handler :
+ public SimpleHandlersReturnBase
+ {
+ static ReturnType Exception(const std::system_error&, UserData h) { h.Touch(); return ReturnType::SystemErrorCode; }
+ using SimpleHandlersReturnBase::Exception;
+ };
+ SimpleReturn<Handler>(ReturnType::SystemErrorCode, std::system_error(std::error_code()));
+}
« no previous file with comments | « src/plugin/PluginStdAfx.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld