generated from sdaveb/gnu-automake-project
Improve unit tests so they test each part of the Exception class.
Close #21
This commit is contained in:
parent
400be25557
commit
183eab166d
@ -20,8 +20,9 @@ namespace engine {
|
||||
class Exception : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit Exception(const std::string& message, const_c_string file,
|
||||
unsigned line)
|
||||
explicit Exception(
|
||||
const std::string& message, const_c_string file, unsigned line
|
||||
)
|
||||
: std::runtime_error(message), error_message(file)
|
||||
{
|
||||
error_message += ":" + std::to_string(line) + " : " + message;
|
||||
@ -30,13 +31,15 @@ class Exception : public std::runtime_error
|
||||
|
||||
static void set_ostream(std::ostream& newstream) { output = newstream; }
|
||||
|
||||
static void rethrow(const std::string& message, const_c_string file,
|
||||
unsigned line);
|
||||
static void rethrow(
|
||||
const std::string& message, const_c_string file, unsigned line
|
||||
);
|
||||
|
||||
static void backtrace(const std::exception& ex);
|
||||
|
||||
static void handler(const std::exception& ex,
|
||||
const std::string& caller_name = "");
|
||||
static void handler(
|
||||
const std::exception& ex, const std::string& caller_name = ""
|
||||
);
|
||||
const_c_string what() const noexcept { return error_message.c_str(); }
|
||||
|
||||
protected:
|
||||
@ -45,8 +48,9 @@ class Exception : public std::runtime_error
|
||||
};
|
||||
|
||||
inline void
|
||||
Exception::rethrow(const std::string& message, const_c_string file,
|
||||
unsigned line)
|
||||
Exception::rethrow(
|
||||
const std::string& message, const_c_string file, unsigned line
|
||||
)
|
||||
try {
|
||||
std::rethrow_exception(std::current_exception());
|
||||
}
|
||||
@ -73,6 +77,7 @@ try {
|
||||
if (caller_name != "")
|
||||
out << std::endl
|
||||
<< "Exception caught in function \'" << caller_name << "\'"
|
||||
<< std::endl
|
||||
<< std::endl;
|
||||
out << "Backtrace:" << std::endl;
|
||||
backtrace(ex);
|
||||
@ -86,15 +91,14 @@ catch (...) {
|
||||
}
|
||||
|
||||
// Shorthand for throwing an Exception with file and line info using macros
|
||||
#define throw_exception(message) \
|
||||
#define THROW_EXCEPTION(message) \
|
||||
throw engine::Exception(message, __FILE__, __LINE__)
|
||||
|
||||
// Shorthand for rethrowing and Exception with file and line info using macros
|
||||
#define rethrow_exception(message) \
|
||||
engine::Exception::rethrow(message, __FILE__, __LINE__)
|
||||
#define RETHROW(message) engine::Exception::rethrow(message, __FILE__, __LINE__)
|
||||
|
||||
// Shorthand for handling an exception, including a backtrace
|
||||
#define handle_exception(ex) engine::Exception::handler(ex, __func__)
|
||||
#define HANDLE_EXCEPTION(ex) engine::Exception::handler(ex, __func__)
|
||||
|
||||
// clang-format off
|
||||
// vim: set foldmethod=marker foldmarker=#region,#endregion textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :
|
||||
|
@ -20,29 +20,27 @@
|
||||
#include "src/engine/Exception.hpp"
|
||||
#include "src/engine/types.hpp"
|
||||
|
||||
using engine::Exception;
|
||||
BEGIN_TEST_SUITE("Exception.tests")
|
||||
|
||||
void
|
||||
some_random_function()
|
||||
try {
|
||||
|
||||
throw_exception("Inner Exception");
|
||||
THROW_EXCEPTION("Inner Exception");
|
||||
}
|
||||
catch (std::exception& ex) {
|
||||
rethrow_exception("Rethrowing Inner");
|
||||
RETHROW("Rethrowing Inner");
|
||||
}
|
||||
|
||||
class ExceptionInspector : public engine::Exception
|
||||
class ExceptionInspector : public Exception
|
||||
{
|
||||
private:
|
||||
explicit ExceptionInspector(engine::Exception& other)
|
||||
: engine::Exception(other)
|
||||
{
|
||||
}
|
||||
explicit ExceptionInspector(Exception& other) : Exception(other) {}
|
||||
virtual ~ExceptionInspector() {}
|
||||
|
||||
public:
|
||||
static std::ostream& get_ostream(engine::Exception& instance)
|
||||
static std::ostream& get_ostream(Exception& instance)
|
||||
{
|
||||
return instance.output;
|
||||
}
|
||||
@ -53,24 +51,24 @@ struct TestFixture
|
||||
TestFixture() : test_subject("Test", __FILE__, __LINE__) {}
|
||||
~TestFixture() = default;
|
||||
|
||||
engine::Exception test_subject;
|
||||
Exception test_subject;
|
||||
};
|
||||
|
||||
CATCH_CASE("Construction")
|
||||
try {
|
||||
// Test ptr construciton as well as compiler macros
|
||||
auto* ptr = new engine::Exception("Hello", __FILE__, __LINE__);
|
||||
auto* ptr = new Exception("Hello", __FILE__, __LINE__);
|
||||
|
||||
REQUIRE(nullptr != ptr);
|
||||
|
||||
// Test macros from header file that construct Exceptions
|
||||
REQUIRE_THROWS_AS(throw_exception("Message"), engine::Exception);
|
||||
REQUIRE_THROWS_AS(THROW_EXCEPTION("Message"), Exception);
|
||||
}
|
||||
catch (...) {
|
||||
throw std::runtime_error("Error occurred during construction");
|
||||
}
|
||||
|
||||
FIXTURE_CASE("Output stream is interchangeable")
|
||||
FIXTURE_CASE("set_osstream: Output stream is interchangeable")
|
||||
try {
|
||||
std::stringstream buffer;
|
||||
|
||||
@ -85,25 +83,63 @@ catch (...) {
|
||||
|
||||
FIXTURE_CASE("rethrow() behaves as expected and nests the exceptions")
|
||||
{
|
||||
REQUIRE(true == false);
|
||||
auto ex = std::runtime_error("Testing!");
|
||||
try {
|
||||
try {
|
||||
throw ex;
|
||||
}
|
||||
catch (...) {
|
||||
REQUIRE_THROWS(Exception::rethrow(
|
||||
"Caught an exception", __FILE__, __LINE__
|
||||
));
|
||||
|
||||
RETHROW("Rethrown from macro");
|
||||
}
|
||||
}
|
||||
catch (std::exception& nested) {
|
||||
std::string message = nested.what();
|
||||
REQUIRE(
|
||||
message.find("Rethrown from macro") != std::string::npos
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FIXTURE_CASE("backtrace() behaves as expected and outputs a backtrace")
|
||||
{
|
||||
REQUIRE(true == false);
|
||||
std::stringstream buffer;
|
||||
Exception::set_ostream(buffer);
|
||||
Exception::backtrace(Exception("Test", __FILE__, __LINE__));
|
||||
|
||||
std::cout << buffer.str() << std::endl;
|
||||
REQUIRE(true == true);
|
||||
}
|
||||
|
||||
FIXTURE_CASE(
|
||||
"handler() behaves as expected and outputs exception text to ostream")
|
||||
"handler() behaves as expected and outputs exception text to ostream"
|
||||
)
|
||||
{
|
||||
REQUIRE(true == false);
|
||||
std::stringstream buffer;
|
||||
Exception::set_ostream(buffer);
|
||||
|
||||
try {
|
||||
THROW_EXCEPTION("Test #1");
|
||||
}
|
||||
catch (Exception& ex) {
|
||||
Exception::handler(ex, "catch2_handler_test");
|
||||
}
|
||||
REQUIRE(
|
||||
buffer.str().find("Exception caught in function") !=
|
||||
std::string::npos
|
||||
);
|
||||
REQUIRE(buffer.str().find("catch2_handler_test") != std::string::npos);
|
||||
}
|
||||
|
||||
FIXTURE_CASE("what() returns the error message contents with file and lineinfo")
|
||||
{
|
||||
const auto result = test_subject.what();
|
||||
auto result = std::string(test_subject.what());
|
||||
|
||||
REQUIRE(0 == std::strcmp("../src/tests/Exception.tests.cpp:54 : Test",
|
||||
result));
|
||||
REQUIRE(result.find("Exception.tests.cpp") != std::string::npos);
|
||||
REQUIRE(result.find("Test") != std::string::npos);
|
||||
}
|
||||
|
||||
CATCH_CASE("Integration Tests: handler method can generate stacktrace.")
|
||||
@ -111,25 +147,27 @@ CATCH_CASE("Integration Tests: handler method can generate stacktrace.")
|
||||
std::stringstream buffer;
|
||||
std::vector<std::string> output_lines;
|
||||
|
||||
engine::Exception::set_ostream(buffer);
|
||||
Exception::set_ostream(buffer);
|
||||
|
||||
try {
|
||||
some_random_function();
|
||||
}
|
||||
catch (engine::Exception& ex) {
|
||||
handle_exception(ex);
|
||||
engine::Exception::set_ostream(std::cerr);
|
||||
catch (Exception& ex) {
|
||||
HANDLE_EXCEPTION(ex);
|
||||
Exception::set_ostream(std::cerr);
|
||||
}
|
||||
buffer.flush();
|
||||
|
||||
for (std::string line; std::getline(buffer, line, '\n');) {
|
||||
output_lines.push_back(line);
|
||||
}
|
||||
REQUIRE(output_lines[2].find("Backtrace:") != std::string::npos);
|
||||
REQUIRE(output_lines[3].find("Exception.tests.cpp") !=
|
||||
std::string::npos);
|
||||
REQUIRE(output_lines[3].find("Rethrowing Inner") != std::string::npos);
|
||||
REQUIRE(output_lines[4].find("Inner Exception") != std::string::npos);
|
||||
// Make sure the stack trace outputs lines in order
|
||||
REQUIRE(output_lines[3].find("Backtrace:") != std::string::npos);
|
||||
REQUIRE(
|
||||
output_lines[4].find("Exception.tests.cpp") != std::string::npos
|
||||
);
|
||||
REQUIRE(output_lines[4].find("Rethrowing Inner") != std::string::npos);
|
||||
REQUIRE(output_lines[5].find("Inner Exception") != std::string::npos);
|
||||
}
|
||||
|
||||
END_TEST_SUITE
|
||||
|
Loading…
Reference in New Issue
Block a user