Implement MarkdownRouteHandler text HTML template text substitution
All checks were successful
buildbot/mdml-cgi-darwin-macos-builder Build done.
buildbot/mdml-cgi-linux-podman-builder Build done.
buildbot/mdml-cgi-freebsd-jail-builder Build done.

Close #11 - Add CMAke target that moves program data to the build folder
Close #17 - Implement MarkdownRouteHandler text HTML template text substitution
This commit is contained in:
S David 2023-11-18 08:10:03 -05:00
parent 3d0b08a612
commit 39eaee382c
21 changed files with 485 additions and 150 deletions

View File

@ -205,6 +205,7 @@ endif()
add_custom_target(copy_assets
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/data ${CMAKE_BINARY_DIR}/artifacts/share/data
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/data ${CMAKE_BINARY_DIR}/tests/data
)
add_subdirectory(src)
@ -218,6 +219,7 @@ if (ENABLE_TESTS)
)
add_dependencies(ctest
mdml-tests
copy_assets
)
endif()

View File

@ -1,100 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Your Page Title</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<!-- My CSS --->
<link rel="stylesheet" href="fonts/Berkeley-Mono-Font-face.css">
<link rel="stylesheet" href="fonts/IBM-Plex-Sans.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container-fluid">
<div class="row">
<nav id="navbar"
class="collapse navbar-collapse col-md-2 d-md-block bg-light sidebar">
<!-- Left-column navbar -->
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link active" href="#home">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#about-me">About Me</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#projects">Projects</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#writing">Writing</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#site-cpp">This site runs C++</a>
</li>
</ul>
</nav>
<!-- Page content with Lorem Ipsum text -->
<main class="col-md-10 col-lg-10 px-4">
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 class="h2">Your Page Title</h1>
<span class="navbar-light">
<button id="menuButton" class="navbar-toggler" type="button"
data-toggle="collapse" data-target="#navbar"
aria-controls="navbar" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
</span>
</div>
<!-- Page body with Lorem Ipsum text -->
<div>
<h2>Page Content</h2>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Sed auctor non ante id facilisis. Suspendisse feugiat eros
sit amet dui gravida, ac suscipit justo dignissim. Nullam
hendrerit metus vitae felis cursus, a finibus neque
consequat. Vestibulum id ullamcorper sapien. Phasellus vel
bibendum metus. Donec eu enim erat.<br/>
<span style="font-weight: bold;">0 1 2 3 4 5 6 7 8 9 10</span>
</p>
</div>
</main>
</div>
</div>
<!-- Bootstrap JS (including jQuery and Popper.js) -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.12.9/dist/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<script>
// JavaScript to handle the "Menu" button and show/hide the navbar
const navbar = document.getElementById('navbar');
const menuButton = document.getElementById('menuButton');
function onResize() {
if (window.innerWidth < 768) {
navbar.classList.remove('shown')
menuButton.classList.remove('d-none');
} else {
navbar.classList.add('shown');
menuButton.classList.add('d-none');
}
}
function onMenuClick(){}
// Call the function when the page loads and on window resize
window.addEventListener('resize', onResize);
window.addEventListener('load', onResize);
</script>
</body>
</html>
<!-- vim: set ts=2 sw=2 noet: -->

5
data/test.md Normal file
View File

@ -0,0 +1,5 @@
## Subtitle
Hello world!

10
data/test.thtml Normal file
View File

@ -0,0 +1,10 @@
<!doctype html>
<html lang="en">
<head>
<title>%title%</title>
</head>
<body>
<div class="title">%title%</div>
<div class="content">%content%</div>
</body>
</html>

View File

@ -23,6 +23,7 @@ class Application {
Application(const Application&) = delete;
Application& operator=(const Application&) = delete;
inline static Application& GetInstance() { return *instance_ptr; };
virtual ~Application();
// #region Getters
@ -42,6 +43,7 @@ class Application {
private:
static count_t instance_count;
static Application* instance_ptr;
protected:
void parse_arguments(int argc, c::const_string argv[]);

View File

@ -0,0 +1,58 @@
/* MarkdownRouteHandler.hpp
* Copyright © 2023 Saul D. Beniquez
* License: Mozilla Public License v. 2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v.2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "IRouteHandler.hpp"
#include "types.hpp"
#include <filesystem>
#include <string>
namespace mdml {
namespace {
namespace fs = std::filesystem;
}
class MarkdownRouteHandler : public IRouteHandler {
public:
MarkdownRouteHandler();
virtual ~MarkdownRouteHandler();
void LoadTemplate(const std::string& template_name);
void LoadMarkdown(const std::string& markdown_page_name);
virtual Result<std::string> Process(
const std::string& name, const std::string& request_uri
);
std::reference_wrapper<std::ostream> OutputStream;
#ifdef TESTING
inline std::string& GetHtmlData() { return html_data; }
inline std::string& GetMarkdownData() { return markdown_data; }
#endif
protected:
std::string render_document(
const std::string& title, const std::string& request_uri
);
static void load_document(
const fs::path& document_path, std::string& out_document
);
fs::path work_dir;
std::string html_data;
std::string markdown_data;
};
}
// clang-format off
// vim: set foldmethod=marker foldmarker=#region,#endregion textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :

View File

@ -24,7 +24,8 @@ namespace mdml {
class exception : public std::exception {
public:
exception(const char* error_message = default_error);
exception(c::const_string _message = default_error);
exception(const std::string& message);
exception(const std::exception& inner);
exception& operator=(const exception&) = delete;

View File

@ -18,14 +18,21 @@
using namespace mdml;
count_t Application::instance_count = 0;
Application* Application::instance_ptr = nullptr;
Application::Application(int argc, c::const_string argv[], c::const_string env[])
: arguments(), environment_variables()
{
if (Application::instance_count != 0) {
auto fatal_exception =
std::logic_error("Cannot instantiate more than one "
"mdml::Application class at a time");
std::stringstream buffer;
buffer << this->instance_count;
auto fatal_exception = std::logic_error(
"Cannot instantiate more than one "
"mdml::Application class at a time.\n"
" instance_count = " +
buffer.str()
);
throw mdml::exception(fatal_exception);
}
@ -42,11 +49,14 @@ Application::Application(int argc, c::const_string argv[], c::const_string env[]
++(Application::instance_count);
this->parse_arguments(argc, argv);
this->create_env_dictionary(env);
Application::instance_ptr = this;
}
Application::~Application()
{
(Application::instance_count)--;
--(Application::instance_count);
Application::instance_ptr = nullptr;
}
void

View File

@ -5,6 +5,7 @@ set(LIBMDML_SOURCES
debuginfo.cpp
Application.cpp
CgiApplication.cpp
MarkdownRouteHandler.cpp
)
set(LIBMDML_LINK_LIBS ${STACKTRACE_DEP_LIBS})

View File

@ -43,10 +43,14 @@ CgiApplication::~CgiApplication()
Result<std::string>
CgiApplication::ProcessRequest()
{
auto& environment = Application::environment_variables;
try {
auto& environment = Application::environment_variables;
// Check if REQUEST_URI is in the environment map
if (environment.find("REQUEST_URI") != environment.end()) {
// Check if REQUEST_URI is in the environment map
if (environment.find("REQUEST_URI") == environment.end()) {
throw mdml::exception("No REQUEST_URI in Environment!");
}
/* Parse REQUEST_URI to get the route's basename */
auto request_URI = environment["REQUEST_URI"];
auto question_pos = request_URI.find('?');
auto ampersand_pos = request_URI.find('&');
@ -59,26 +63,29 @@ CgiApplication::ProcessRequest()
}
}
if (question_pos != not_found) {
page_name =
request_URI.substr(question_pos, std::string::npos);
page_name = request_URI.substr(0, question_pos);
}
if (routes.find(page_name) != routes.end()) {
auto route_handler = routes[page_name];
auto result =
route_handler->Process(page_name, request_URI);
if (!result.IsError) {
if (result.IsError) {
auto except =
mdml::exception(result.ErrorData.c_str());
throw except;
}
return result;
} else {
std::stringstream buffer;
buffer << "Unknown route: " << request_URI << std::endl;
throw mdml::exception(buffer.str().c_str());
buffer << "Unknown route: " << page_name << std::endl;
return { ERROR, buffer.str() };
// throw mdml::exception(buffer.str().c_str());
}
} catch (const std::exception& except) {
throw mdml::exception(except);
}
return { NO_ERROR, "Success" };
}
// clang-format off

View File

@ -0,0 +1,141 @@
/* MarkdownRouteHandler.cpp
* Copyright © 2023 Saul D. Beniquez
* License: Mozilla Public License v. 2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v.2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "Application.hpp"
#include "IRouteHandler.hpp"
#include "MarkdownRouteHandler.hpp"
#include "exception.hpp"
#include "types.hpp"
#include "cmark.h"
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>
using namespace mdml;
#if defined(TESTING)
constexpr const char* DEFAULT_WORKDIR = ".";
#else
constexpr const char* DEFAULT_WORKDIR = "/usr/local/www/templates";
#endif
const auto NOT_FOUND = std::string::npos;
void
string_replace(
std::string& out_buffer, const std::string& pattern,
const std::string& replacement
)
{
for (auto pattern_pos = out_buffer.find(pattern);
pattern_pos != NOT_FOUND;
pattern_pos = out_buffer.find(pattern)) {
if (pattern_pos != NOT_FOUND) {
out_buffer.replace(
pattern_pos, pattern.length(), replacement
);
}
}
}
MarkdownRouteHandler::MarkdownRouteHandler()
: IRouteHandler(), OutputStream(std::cout), work_dir(DEFAULT_WORKDIR)
{
work_dir = fs::absolute(work_dir);
}
MarkdownRouteHandler::~MarkdownRouteHandler() {}
void
MarkdownRouteHandler::LoadTemplate(const std::string& template_filename)
{
fs::path full_html_path = work_dir / template_filename;
this->load_document(full_html_path, this->html_data);
}
void
MarkdownRouteHandler::LoadMarkdown(const std::string& markdown_filename)
{
fs::path full_md_path = work_dir / markdown_filename;
this->load_document(full_md_path, this->markdown_data);
}
Result<std::string>
MarkdownRouteHandler::Process(
const std::string& name, const std::string& request_uri
)
{
auto document = render_document(name, request_uri);
auto& out = OutputStream.get();
out << document << std::flush;
return { NO_ERROR, document };
}
void
MarkdownRouteHandler::load_document(
const fs::path& document_path, std::string& out_document
)
{
if (!fs::exists(document_path) || !fs::is_regular_file(document_path)) {
auto error = "File not found: " + document_path.string();
throw mdml::exception(error);
}
try {
std::ifstream file(document_path);
if (file.is_open()) {
std::string htmlContent(
(std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>()
);
out_document = htmlContent;
} else {
auto error_message =
(std::stringstream()
<< "Could not open file '"
<< document_path.filename() << "', at path "
<< document_path.parent_path() << ". ")
.str();
throw mdml::exception(error_message);
}
} catch (const mdml::exception& e) {
throw e;
} catch (const std::exception& e) {
throw mdml::exception(e);
}
}
std::string
MarkdownRouteHandler::render_document(
const std::string& title, const std::string& request_uri
)
{
std::string result = this->html_data;
std::string token = "%content%";
std::string generated_html = cmark_markdown_to_html(
this->markdown_data.c_str(),
this->markdown_data.length(),
CMARK_OPT_DEFAULT
);
string_replace(result, token, generated_html);
string_replace(result, "%title%", title);
return result;
}
// clang-format off
// vim: set foldmethod=marker foldmarker=#region,#endregion textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :

View File

@ -26,7 +26,17 @@ constexpr unsigned DEFAULT_STACKFRAMES_TO_STRIP = 2;
// Helper classes and functions. #region
exception::exception(const char* error_message)
exception::exception(c::const_string error_message)
: std::exception()
, error_message(error_message)
, what_message()
, stack_trace(mdml::generate_stacktrace(DEFAULT_STACKFRAMES_TO_STRIP))
, inner_exception_ptr()
{
build_what_message();
}
exception::exception(const std::string& error_message)
: std::exception()
, error_message(error_message)
, what_message()

View File

@ -12,6 +12,9 @@
#include "Application.hpp"
#include <functional>
#include <optional>
struct simulated_launch {
static const char* argv[];
static const char* env[];
@ -21,9 +24,12 @@ inline const char* simulated_launch::env[] = { "PATH=/usr/bin",
"VAR2=TWO",
nullptr };
template<typename T>
using opt_reference = std::optional<std::reference_wrapper<T>>;
BEGIN_TEST_SUITE("Application-test")
{
TEST("Class construction")
TEST("Application Class construction")
{
auto simple_construction = []() {
auto test_object = mdml::Application(
@ -49,11 +55,19 @@ BEGIN_TEST_SUITE("Application-test")
double_construction(), mdml::exception
);
}
SECTION("Double construction")
SECTION("Get existing instance")
{
REQUIRE_THROWS_AS(
double_construction(), mdml::exception
);
opt_reference<mdml::Application> app;
try {
auto test_object = mdml::Application(
3,
simulated_launch::argv,
simulated_launch::env
);
app = test_object;
} catch (const mdml::exception& e) {
app = mdml::Application::GetInstance();
}
}
auto incorrect_construction = []() {
mdml::Application obj(0, nullptr, nullptr);
@ -67,7 +81,7 @@ BEGIN_TEST_SUITE("Application-test")
}
}
TEST("Parameter capture")
TEST("Application Parameter capture")
{
SECTION("Arguments are captured in vector")
{

View File

@ -6,6 +6,7 @@ set(MDML_TEST_SOURCE_LIST
Result-test.cpp
Application-test.cpp
CgiApplication-test.cpp
MarkdownRouteHandler-test.cpp
)
add_executable(mdml-tests

View File

@ -7,11 +7,14 @@
* obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "tests-common.hpp"
#include "CgiApplication.hpp"
#include "IRouteHandler.hpp"
#include "exception.hpp"
#include "tests-common.hpp"
#include <catch2/matchers/catch_matchers_string.hpp>
namespace {
struct simulated_launch {
static const char* argv[];
static const char* env[];
@ -20,21 +23,46 @@ inline const char* simulated_launch::argv[] = { "param1", "param2", "param3" };
inline const char* simulated_launch::env[] = {
"PATH=/usr/bin",
"VAR2=TWO",
"REQUEST_URI=markdown?msg=hello-world"
"REQUEST_URI=markdown?msg=hello-world",
nullptr
};
}
using namespace mdml;
TEST_CASE("CgiApplication Unit Tests")
BEGIN_TEST_SUITE("CgiApplication")
{
CgiApplication cgiHandler(
1, simulated_launch::argv, simulated_launch::env
);
using namespace mdml;
struct TestFixture {
const char* envp[4] = { "PATH=/usr/bin",
"VAR2=TWO",
"REQUEST_URI=markdown?msg=hello-world",
nullptr };
TestFixture() : cgi_app(1, simulated_launch::argv, envp) {}
SECTION("ProcessRequest with valid route")
CgiApplication cgi_app;
};
TEST("CgiApplication Constructor Test")
{
// Define a test route handler for the "/markdown" route
CgiApplication test(
1, simulated_launch::argv, simulated_launch::env
);
};
TEST("CgiApplication::ProcessRequest no REQUEST_URI variable")
{
const char* no_request_env[] = { "PATH=/usr/bin",
"VAR2=TWO",
nullptr };
CgiApplication test(1, simulated_launch::argv, no_request_env);
REQUIRE_THROWS_AS(
[&]() { test.ProcessRequest(); }(), mdml::exception
);
}
FIXTURE_TEST("CgiApplication ProcessRequest with valid route")
{
// Define a test oute handler for the "/markdown" route
class ExampleRouteHandler : public IRouteHandler {
public:
virtual Result<std::string> Process(
@ -42,34 +70,66 @@ TEST_CASE("CgiApplication Unit Tests")
const std::string& request_uri
) override
{
// Implement test logic for the route handler
return { mdml::NO_ERROR, "Success" };
// Implement test logic for the route
// handler
return { mdml::NO_ERROR, "Processed" };
}
virtual ~ExampleRouteHandler() = default;
};
// Add the test route handler to the Routes dictionary
auto handler = CgiApplication::make_ptr<ExampleRouteHandler>();
cgiHandler.Routes["/markdown"] = handler;
cgi_app.Routes["markdown"] = handler;
auto result = cgiHandler.ProcessRequest();
auto result = cgi_app.ProcessRequest();
// Add assertions to check the result
CHECK(result.IsError == false);
CHECK(result.ErrorData == "Success");
CHECK(result.ErrorData == "Processed");
REQUIRE(result.IsError == false);
}
SECTION("ProcessRequest with unknown route")
FIXTURE_TEST("CgiApplication ProcessRequest with unknown route")
{
// Remove the "/markdown" route from the Routes dictionary
cgiHandler.Routes.erase("/markdown");
cgiHandler.ProcessRequest();
// Remove the "markdown" route from the Routes
// dictionary
for (auto& [key, value] : cgi_app.Routes) {
if (value.get() != nullptr) {
value.reset();
}
cgi_app.Routes.erase(key);
}
// Add assertions to check the result for the unknown route
/*REQUIRE( Add assertions for the test case &/);*/
auto result = cgi_app.ProcessRequest();
// Add assertions to check the result
CHECK(result.ErrorData != "Success");
REQUIRE(result.IsError == true);
}
FIXTURE_TEST("CgiApplication ProcessRequest Route throws exception")
{
// Define a test oute handler for the "/markdown" route
class BadRouteHandler : public IRouteHandler {
public:
virtual Result<std::string> Process(
const std::string& name,
const std::string& request_uri
) override
{
throw std::runtime_error("ERROR");
return { mdml::ERROR,
"This line never executes" };
}
virtual ~BadRouteHandler() = default;
};
auto handler = CgiApplication::make_ptr<BadRouteHandler>();
cgi_app.Routes["markdown"] = handler;
REQUIRE_THROWS_AS(
[&]() { cgi_app.ProcessRequest(); }(), mdml::exception
);
}
}
// clang-format off
// vim: set foldmethod=marker foldmarker=#region,#endregion textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :

View File

@ -0,0 +1,108 @@
/* CgiApplication-test.cpp
* Copyright © 2023 Saul D. Beniquez
* License: Mozilla Public License v. 2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v.2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "tests-common.hpp"
#include "IRouteHandler.hpp"
#include "MarkdownRouteHandler.hpp"
#include <catch2/matchers/catch_matchers_string.hpp>
#include <iostream>
#include <sstream>
namespace {
struct simulated_launch {
static const char* argv[];
static const char* env[];
};
inline const char* simulated_launch::argv[] = { "param1", "param2", "param3" };
inline const char* simulated_launch::env[] = {
"PATH=/usr/bin",
"VAR2=TWO",
"REQUEST_URI=markdown?src=index.md"
};
}
using namespace mdml;
BEGIN_TEST_SUITE("MarkdownRouteHandler Unit Tests")
{
TEST("MarkdownRouteHandler Construction and allocation")
{
REQUIRE_NOTHROW([]() { MarkdownRouteHandler test; }());
}
struct TestFixture {
MarkdownRouteHandler test_obj;
};
FIXTURE_TEST("MarkdownRouteHandler LoadHtml")
{
MarkdownRouteHandler test_obj;
SECTION("File exists")
{
REQUIRE_NOTHROW([&]() {
test_obj.LoadTemplate("data/test.thtml");
}());
REQUIRE(false == test_obj.GetHtmlData().empty());
}
SECTION("File does not exists")
{
REQUIRE_THROWS([&]() {
test_obj.LoadTemplate("not-found.txt");
}());
}
}
FIXTURE_TEST("MarkdownRouteHandler LoadMarkdown")
{
MarkdownRouteHandler test_obj;
SECTION("File exists")
{
REQUIRE_NOTHROW([&]() {
test_obj.LoadMarkdown("data/test.md");
}());
REQUIRE(false == test_obj.GetMarkdownData().empty());
}
SECTION("File does not exists")
{
REQUIRE_THROWS([&]() {
test_obj.LoadMarkdown("not-found.txt");
}());
}
}
FIXTURE_TEST("MarkdownRouteHandler Process")
{
std::stringstream buffer;
test_obj.OutputStream = buffer;
REQUIRE_NOTHROW([&]() {
test_obj.LoadTemplate("data/test.thtml");
test_obj.LoadMarkdown("data/test.md");
test_obj.Process("test", "test?param=1");
}());
auto resulting_document = buffer.str();
REQUIRE_THAT(
resulting_document,
!Catch::Matchers::ContainsSubstring("%content%")
);
REQUIRE_THAT(
resulting_document,
!Catch::Matchers::ContainsSubstring("%title%")
);
}
}
// clang-format off
// vim: set foldmethod=marker foldmarker=#region,#endregion textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :

View File

@ -23,7 +23,7 @@ namespace Match = Catch::Matchers;
using Catch::CaseSensitive;
void
throw_local_variable()
throw_local_exception()
{
auto local = std::logic_error("This is a stack variable");
@ -48,10 +48,15 @@ BEGIN_TEST_SUITE("mdml::exception")
{
mdml::exception obj;
}
SECTION("2. With string parameter")
SECTION("2a. With cstring parameter")
{
mdml::exception obj("Sample Error");
}
SECTION("2b. With std::string parameter")
{
mdml::exception obj(std::string("Sample Error"));
}
SECTION("3. With STL exception")
{
mdml::exception obj(std::runtime_error("Sample Error"));
@ -59,7 +64,7 @@ BEGIN_TEST_SUITE("mdml::exception")
SECTION("4. With destroyed stack")
{
auto nested_function_call = []() {
throw_local_variable();
throw_local_exception();
};
try {
nested_function_call();

View File

@ -24,9 +24,9 @@
#define TEST(testname) TEST_CASE(testname, TEST_SUITE_NAME)
#define TEST_WITH_FIXTURE(FixtureName, testname) \
TEST_CASE_METHOD(FixtureName, #testname, TEST_SUITE_NAME)
TEST_CASE_METHOD(FixtureName, testname, TEST_SUITE_NAME)
#define FIXTURE_TEST(testname) TEST_WITH_FIXTURE(TestFixture, #testname)
#define FIXTURE_TEST(testname) TEST_WITH_FIXTURE(TestFixture, testname)
#ifdef VIM_COMPLETION
#define UNIT_TEST 1