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

Unified Diff: test/plugin/ExceptionTest.cpp

Issue 5137721374801920: Issue #1173 - Default behavior for catch-all blocks
Patch Set: add 'const'; roll PluginErrorCodes.h into PluginDebug.h Created March 6, 2015, 6 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
« src/plugin/Exception.h ('K') | « 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
===================================================================
new file mode 100644
--- /dev/null
+++ b/test/plugin/ExceptionTest.cpp
@@ -0,0 +1,383 @@
+/*
+ * 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 (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 y) {}
+ static void Exception(std::exception& ex,int y) {}
+ static void LogicError(std::logic_error& ex,int y) { Exception(ex, y); }
+ static void RuntimeError(std::runtime_error& ex,int y) { Exception(ex, y); }
+ static void SystemError(std::system_error& ex,int y) { RuntimeError(ex, y); }
+};
+
+/*
+ * 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
+{
+ InvalidCode = -1,
+ UnknownCode = 1,
+ ExceptionCode,
+ LogicErrorCode,
+ RuntimeErrorCode,
+ SystemErrorCode
+};
+
+struct NullHandlersReturn
+{
+ typedef int ReturnType;
+ static ReturnType Unknown(int) { return UnknownCode; }
+ static ReturnType Exception(std::exception& ex, int) { return ExceptionCode; }
+ static ReturnType LogicError(std::logic_error& ex, int) { return LogicErrorCode; }
+ static ReturnType RuntimeError(std::runtime_error& ex, int) { return RuntimeErrorCode; }
+ static ReturnType SystemError(std::system_error& ex, int) { return SystemErrorCode; }
+};
+
+template<class X>
+void TrivialReturn(int n, X x)
+{
+ ASSERT_NO_THROW(
+ {
+ try
+ {
+ throw x;
+ }
+ catch (...)
+ {
+ ASSERT_EQ(n, CatchAllReturn<NullHandlersReturn>::Handler(0));
+ }
+ });
+}
+
+TEST(Exception, TrivialReturnUnknown)
+{
+ TrivialReturn(UnknownCode, 5);
+}
+
+TEST(Exception, TrivialReturnException)
+{
+ TrivialReturn(ExceptionCode, PlainException());
+}
+
+TEST(Exception, TrivialReturnLogicError)
+{
+ TrivialReturn(LogicErrorCode, std::logic_error(""));
+}
+
+TEST(Exception, TrivialReturnRuntimeError)
+{
+ TrivialReturn(RuntimeErrorCode, std::runtime_error(""));
+}
+
+TEST(Exception, TrivialReturnSystemError)
+{
+ TrivialReturn(SystemErrorCode, std::system_error(std::error_code()));
+}
+
+/*
+ * VS 2012 supports thread_local semantics for POD only, not arbitrary types.
+ * That's good enough for now.
+ * Remove the definition when VS matures.
+ */
+#define thread_local __declspec(thread)
+
+/*
+ * The sub-handlers are purely static functions,
+ * so getting them to return something unique for testing has possible race conditions.
+ * We're using a thread-local variable as a return code from the simple handlers,
+ * which ensures that even a multi-threaded test runner will work here.
+ */
+thread_local int SimpleResult;
+thread_local int SimpleExpected;
+
+/*
+ * The simple tests ensure that the flow of control arrives in the correct subhandler.
+ */
+template<class X, class H>
+void SimpleVoid(X x, H h)
+{
+ SimpleResult = 0;
+ SimpleExpected = std::rand();
+ if (SimpleExpected == 0) { SimpleExpected = 1; }
+ ASSERT_NO_THROW(
+ {
+ try
+ {
+ throw x;
+ }
+ catch (...)
+ {
+ CatchAllVoid<H>::Handler(0);
+ }
+ });
+ EXPECT_EQ(SimpleExpected, SimpleResult);
+}
+
+/*
+ * 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:
+ static void Unknown(int) { FAIL() << "Unexpected exception of unknown type"; }
+ static void Exception(std::exception& ex, int) { FAIL() << "Unexpected std::exception"; }
+ static void LogicError(std::logic_error& ex, int) { FAIL() << "Unexpected std::logic_error"; }
+ static void RuntimeError(std::runtime_error& ex, int) { FAIL() << "Unexpected std::runtime_error"; }
+ static void SystemError(std::system_error& ex, int) { FAIL() << "Unexpected std::system_error"; };
+protected:
+ static void Ping() { SimpleResult = SimpleExpected; }
+};
+
+TEST(Exception, SimpleVoidUnknown)
+{
+ struct Handler :
+ public SimpleHandlersBase
+ {
+ static void Unknown(int) { Ping(); }
+ };
+ SimpleVoid(5, Handler());
+}
+
+TEST(Exception, SimpleVoidException)
+{
+ struct Handler :
+ public SimpleHandlersBase
+ {
+ static void Exception(std::exception& ex, int) { Ping(); }
+ };
+ SimpleVoid(PlainException(), Handler());
+}
+
+TEST(Exception, SimpleVoidLogicError)
+{
+ struct Handler :
+ public SimpleHandlersBase
+ {
+ static void LogicError(std::logic_error& ex, int) { Ping(); }
+ };
+ SimpleVoid(std::logic_error(""), Handler());
+}
+
+TEST(Exception, SimpleVoidRuntimeError)
+{
+ struct Handler :
+ public SimpleHandlersBase
+ {
+ static void RuntimeError(std::runtime_error& ex, int) { Ping(); }
+ };
+ SimpleVoid(std::runtime_error(""), Handler());
+}
+
+TEST(Exception, SimpleVoidSystemError)
+{
+ struct Handler :
+ public SimpleHandlersBase
+ {
+ static void SystemError(std::system_error& ex, int) { Ping(); }
+ };
+ SimpleVoid(std::system_error(std::error_code()), Handler());
+}
+
+template<class X, class H>
+void SimpleReturn(int n, X x, H h)
+{
+ SimpleResult = 0;
+ SimpleExpected = rand();
+ if (SimpleExpected == 0) { SimpleExpected = 1; }
+ ASSERT_NO_THROW(
+ {
+ try
+ {
+ throw x;
+ }
+ catch (...)
+ {
+ EXPECT_EQ(n, CatchAllReturn<H>::Handler(0));
+ }
+ });
+ EXPECT_EQ(SimpleExpected, SimpleResult);
+}
+
+/*
+ * The base handlers class fails every execution path.
+ */
+class SimpleHandlersReturnBase
+{
+public:
+ typedef int ReturnType;
+ static ReturnType Unknown(int) { ADD_FAILURE() << "Unexpected exception of unknown type"; return InvalidCode; }
+ static ReturnType Exception(std::exception& ex, int) { ADD_FAILURE() << "Unexpected std::exception"; return InvalidCode; }
+ static ReturnType LogicError(std::logic_error& ex, int) { ADD_FAILURE() << "Unexpected std::logic_error"; return InvalidCode; }
+ static ReturnType RuntimeError(std::runtime_error& ex, int) { ADD_FAILURE() << "Unexpected std::runtime_error"; return InvalidCode; }
+ static ReturnType SystemError(std::system_error& ex, int) { ADD_FAILURE() << "Unexpected std::system_error"; return InvalidCode; }
+protected:
+ static void Ping() { SimpleResult = SimpleExpected; }
+};
+
+TEST(Exception, SimpleReturnUnknown)
+{
+ struct Handler :
+ public SimpleHandlersReturnBase
+ {
+ static int Unknown(int) { Ping(); return UnknownCode; }
+ };
+ SimpleReturn(UnknownCode, 5, Handler());
+}
+
+TEST(Exception, SimpleReturnException)
+{
+ struct Handler :
+ public SimpleHandlersReturnBase
+ {
+ static int Exception(std::exception& ex, int) { Ping(); return ExceptionCode; }
+ };
+ SimpleReturn(ExceptionCode, PlainException(), Handler());
+}
+
+TEST(Exception, SimpleReturnLogicError)
+{
+ struct Handler :
+ public SimpleHandlersReturnBase
+ {
+ static int LogicError(std::logic_error& ex, int) { Ping(); return LogicErrorCode; }
+ };
+ SimpleReturn(LogicErrorCode, std::logic_error(""), Handler());
+}
+
+TEST(Exception, SimpleReturnRuntimeError)
+{
+ struct Handler :
+ public SimpleHandlersReturnBase
+ {
+ static int RuntimeError(std::runtime_error& ex, int) { Ping(); return RuntimeErrorCode; }
+ };
+ SimpleReturn(RuntimeErrorCode, std::runtime_error(""), Handler());
+}
+
+TEST(Exception, SimpleReturnSystemError)
+{
+ struct Handler :
+ public SimpleHandlersReturnBase
+ {
+ static int SystemError(std::system_error& ex, int) { Ping(); return SystemErrorCode; }
+ };
+ SimpleReturn(SystemErrorCode, std::system_error(std::error_code()), Handler());
+}
+
« src/plugin/Exception.h ('K') | « src/plugin/PluginStdAfx.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld