Write out unit test skeletons and helper classes.
Some checks failed
buildbot/Ascendent (FreeBSD) Build done.
buildbot/Ascendent (Alpine) Build done.

Work #21
This commit is contained in:
S David 2022-08-28 09:51:27 -04:00
parent 323448ee9d
commit 400be25557
3 changed files with 108 additions and 72 deletions

View File

@ -1,37 +0,0 @@
---
BasedOnStyle: Mozilla
Language: Cpp
IndentWidth: 8
UseTab: AlignWithSpaces
ColumnLimit: 81
AccessModifierOffset: -4
BinPackParameters: true
AlwaysBreakAfterDefinitionReturnType: TopLevel
AlwaysBreakAfterReturnType: None
ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 4
ConstructorInitializerAllOnOneLineOrOnePerLine: true
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterClass: true
AfterControlStatement: MultiLine
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: true
AfterUnion: true
AfterExternBlock: false
BeforeCatch: true
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: false
SplitEmptyNamespace: true
---

View File

@ -20,7 +20,8 @@ namespace engine {
class Exception : public std::runtime_error
{
public:
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;
@ -32,14 +33,13 @@ class Exception : public std::runtime_error
static void rethrow(const std::string& message, const_c_string file,
unsigned line);
static void handler(const std::exception& ex,
const std::string& caller_name = "");
static void backtrace(const std::exception& ex);
static void handler(const std::exception& ex,
const std::string& caller_name = "");
const_c_string what() const noexcept { return error_message.c_str(); }
private:
protected:
inline static std::reference_wrapper<std::ostream> output = std::cerr;
std::string error_message;
};
@ -54,6 +54,17 @@ catch (...) {
std::throw_with_nested(Exception(message, file, line));
}
inline void
Exception::backtrace(const std::exception& ex)
try {
auto& out = output.get();
out << ex.what() << std::endl;
std::rethrow_if_nested(ex);
}
catch (std::exception& nested_ex) {
backtrace(nested_ex);
}
inline void
Exception::handler(const std::exception& ex, const std::string& caller_name)
try {
@ -72,29 +83,18 @@ catch (...) {
out << "Fatal error in Exception::handler! Terminating!" << std::endl;
std::exit(2);
}
inline void
Exception::backtrace(const std::exception& ex)
try {
auto& out = output.get();
out << ex.what() << std::endl;
std::rethrow_if_nested(ex);
}
catch (std::exception& nested_ex) {
backtrace(nested_ex);
}
}
// Shorthand for throwing an Exception with file and line info using macros
#define throw_exception(message) \
throw engine::Exception(message, __FILE__, __LINE__);
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__);
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 :

View File

@ -9,6 +9,7 @@
#include "test-includes.hpp"
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>
@ -17,8 +18,7 @@
#include <stdexcept>
#include "src/engine/Exception.hpp"
using namespace engine;
#include "src/engine/types.hpp"
BEGIN_TEST_SUITE("Exception.tests")
@ -26,39 +26,112 @@ void
some_random_function()
try {
throw_exception("Inner Exception")
throw_exception("Inner Exception");
}
catch (std::exception& ex) {
rethrow_exception("Rethrowing Inner");
}
CATCH_CASE("Exception collects a backtrace that can be unwound un handler "
"static method")
class ExceptionInspector : public engine::Exception
{
private:
explicit ExceptionInspector(engine::Exception& other)
: engine::Exception(other)
{
}
virtual ~ExceptionInspector() {}
public:
static std::ostream& get_ostream(engine::Exception& instance)
{
return instance.output;
}
};
struct TestFixture
{
TestFixture() : test_subject("Test", __FILE__, __LINE__) {}
~TestFixture() = default;
engine::Exception test_subject;
};
CATCH_CASE("Construction")
try {
// Test ptr construciton as well as compiler macros
auto* ptr = new engine::Exception("Hello", __FILE__, __LINE__);
REQUIRE(nullptr != ptr);
// Test macros from header file that construct Exceptions
REQUIRE_THROWS_AS(throw_exception("Message"), engine::Exception);
}
catch (...) {
throw std::runtime_error("Error occurred during construction");
}
FIXTURE_CASE("Output stream is interchangeable")
try {
std::stringstream buffer;
REQUIRE(&std::cerr == &ExceptionInspector::get_ostream(test_subject));
test_subject.set_ostream(buffer);
REQUIRE(&buffer == &ExceptionInspector::get_ostream(test_subject));
}
catch (...) {
throw std::runtime_error("Error occurred during set_outputstream test");
}
FIXTURE_CASE("rethrow() behaves as expected and nests the exceptions")
{
REQUIRE(true == false);
}
FIXTURE_CASE("backtrace() behaves as expected and outputs a backtrace")
{
REQUIRE(true == false);
}
FIXTURE_CASE(
"handler() behaves as expected and outputs exception text to ostream")
{
REQUIRE(true == false);
}
FIXTURE_CASE("what() returns the error message contents with file and lineinfo")
{
const auto result = test_subject.what();
REQUIRE(0 == std::strcmp("../src/tests/Exception.tests.cpp:54 : Test",
result));
}
CATCH_CASE("Integration Tests: handler method can generate stacktrace.")
{
std::stringstream buffer;
std::vector<std::string> result_lines;
std::vector<std::string> output_lines;
engine::Exception::set_ostream(buffer);
Exception::set_ostream(buffer);
try {
some_random_function();
}
catch (Exception& ex) {
catch (engine::Exception& ex) {
handle_exception(ex);
engine::Exception::set_ostream(std::cerr);
}
buffer.flush();
for (std::string line; std::getline(buffer, line, '\n');) {
result_lines.push_back(line);
output_lines.push_back(line);
}
REQUIRE(result_lines[2].find("Backtrace:") != std::string::npos);
REQUIRE(result_lines[3].find("Exception.tests.cpp") !=
std::string::npos);
REQUIRE(result_lines[3].find("Rethrowing Inner") != std::string::npos);
REQUIRE(result_lines[4].find(
"tests/Exception.tests.cpp:29 : Inner Exception") !=
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);
}
END_TEST_SUITE
// clang-format off