Commence refactoring and code style conformity changes

This commit is contained in:
S David 2024-03-15 13:12:54 -04:00
parent fc5e5188e4
commit e0faeef2ba
16 changed files with 3022 additions and 138 deletions

79
.clang-tidy Normal file
View File

@ -0,0 +1,79 @@
HeaderFilterRegex: '.*hpp'
Checks: '-*,readability-identifier-naming,readability-identifier-length,readability-function-cognitive-complexity,google-readability-casting,modernize-use-trailing-return-type,modernize-use-default-member-init,modernize-use-uncaught-exceptions,modernize-type-traits,modernize-use-override,misc-non-copyable-objects'
CheckOptions:
# Modernize constructors
- { key: modernize-use-default-member-init.UseAssignment, value : false}
- { key: modernize-use-default-member-init.IgnoreMacros, value : false}
# Warn about complex functions
- { key: readability-function-cognitive-complexity.Threshold, value: 10 }
- { key: readability-function-cognitive-complexity.DescribeBasicIncrements, value: true }
- { key: readability-function-cognitive-complexity.IgnoreMacros, value: true }
# Minimum Variable Length
- { key: readability-identifier-length.MinimumVariableLength, value: 3 }
- { key: readability-identifier-length.IgnoredVariableNames, value: "^(i|j|n|x|y|z|it)$" }
# Minimum Parameter Length
- { key: readability-identifier-length.MinimumParameterNameLength, value: 3 }
- { key: readability-identifier-length.IgnoredParameterNames, value: "^(i|j|n|x|y|z|it)$" }
# Minimum Loop Counter Length
- { key: readability-identifier-length.MinimumLoopCounterNameLength, value: 3 }
- { key: readability-identifier-length.IgnoredLoopCounterNames, value: "^(i|j|n|it)$" }
# Minimum ExceptionName Length:
- { key: readability-identifier-length.MinimumExceptionNameLength, value: 3 }
- { key: readability-identifier-length.IgnoredExceptionVariableNames, value: "^[e]$" }
# Class Names
- { key: readability-identifier-naming.ClassCase, value: CamelCase }
- { key: readability-identifier-naming.StructCase, value: CamelCase }
- { key: readability-identifier-naming.EnumCase, value: CamelCase }
- { key: readability-identifier-naming.EnumIgnoredRegexp, value: '^.*_t$' }
# Abstract Class Name
# - { key: readability-identifier-naming.AbstractClassPrefix,value: 'I' }
# - { key: readability-identifier-naming.AbstractClassIgnoredRegexp,
# value: '^.*able$|^.*Base$|^Abstract.*|^Component$' }
# Template Parameters
- { key: readability-identifier-naming.TypeTemplateParameterPrefix,
value: 'T' }
- { key: readability-identifier-naming.TypeTemplateParameterSuffix,
value: '' }
- { key: readability-identifier-naming.TypeTemplateParameterCase,
value: CamelCase }
# TypeAlias Rules
- { key: readability-identifier-naming.TypeAliasCase, value: CamelCase }
- { key: readability-identifier-naming.TypeAliasTemplateCase, value: CamelCase }
- { key: readability-identifier-naming.TypeAliasIgnoredRegexp,
value: '.*_t|string|.*_string' }
# Function Names
- { key: readability-identifier-naming.FunctionCase, value: lower_case }
- { key: readability-identifier-naming.PublicMethodCase, value: camelBack }
- { key: readability-identifier-naming.PrivateMethodCase, value: lower_case }
# Variable Names
- { key: readability-identifier-naming.VariableCase, value: lower_case }
- { key: readability-identifier-naming.PrivateMemberCase, value: lower_case }
# Constants and Enum Values
- { key: readability-identifier-naming.ConstantPrefix, value: 'k' }
- { key: readability-identifier-naming.ConstantCase, value: CamelCase }
- { key: readability-identifier-naming.EnumConstantPrefix, value: '' }
- { key: readability-identifier-naming.EnumConstantCase, value: CamelCase }
# Constant Expression
- { key: readability-identifier-naming.ConstexprVariablePrefix, value: 'k' }
- { key: readability-identifier-naming.ConstexprVariableCase, value: Camelcase }
- { key: readability-identifier-naming.ConstexprFunctionCase, value: Camel_Snake_Case }
- { key: readability-identifier-naming.ConstexprMethodCase, value: Camel_Snake_Case }
# vim: set ts=4 noet sw=4 sts=0 colorcolumn=100 :

2
.gitignore vendored
View File

@ -1,4 +1,5 @@
# ---> C++
# Prerequisites
*.d
@ -55,3 +56,4 @@ release/*
*-build/
*debug/
docs/*

View File

@ -19,7 +19,7 @@ else()
endif()
option(USE_SYSTEM_CATCH2
"Do not download & compile catch2 library for unit tests"
"Use system-provided Catch2 instead of compiling from source"
ON
)
@ -31,10 +31,8 @@ else()
option(USE_EXECINFO_STACKTRACE "Use BSD/UNIX execinfo for stack traces" OFF)
endif()
project(mdml
VERSION 0.1
VERSION 0.2
LANGUAGES C CXX
# HOMEPAGE_URL
DESCRIPTION "A CGI script written in C++ that converts markdown to HTML"
@ -82,7 +80,6 @@ if (cmark_FOUND)
set(USE_SYSTEM_CMARK True)
endif()
# Avoid building Catch2 if unit tests aren't going to be built
if (ENABLE_TESTS)
if (NOT USE_SYSTEM_CATCH2)
@ -108,7 +105,6 @@ endif()
if (NOT cmark_FOUND)
set(USE_SYSTEM_CMARK False)
set(CMARK_STATIC_LINKAGE True)
# FetchContent: cmark @{
# Instead of calling FetchContent_MakeAvailable, use a more manual way
# to import cmark's build targets
@ -160,6 +156,10 @@ if (NOT cmark_FOUND)
endif(NOT cmark_POPULATED) # @}
endif(NOT cmark_FOUND) # @}
set(STACKTRACE_DEP_LIBS, "")
# If using the system cmark libraries, we need to import the include and library
# directories
if (USE_SYSTEM_CMARK)
include_directories(${cmark_INCLUDE_DIRS})
link_directories(${cmark_LIBRARY_DIRS})
@ -178,22 +178,31 @@ if (USE_EXECINFO_STACKTRACE)
)
if (LIB_EXEC_INFO)
message(STATUS "Found libexecinfo: ${LIB_EXEC_INFO}")
set(STACKTRACE_DEP_LIBS ${LIB_EXEC_INFO})
list(APPEND STACKTRACE_DEP_LIBS ${LIB_EXEC_INFO})
endif()
endif()
# Defining and handling specific project directories
include_directories(
${CMAKE_SOURCE_DIR}/src
${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/include/private
)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/artifacts/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/artifacts/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/artifacts/bin)
set(OUTPUT_DIR ${CMAKE_BINARY_DIR}/out)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OUTPUT_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OUTPUT_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR}/bin)
add_custom_target(copy_assets
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/data ${CMAKE_BINARY_DIR}/out/share/data
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/data ${CMAKE_BINARY_DIR}/tests/data
)
# Specifying configuration for Debug vs Release
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(custom_dbg_flags "-O0 -ggdb")
add_compile_definitions("-DDEBUG=1")
# Custom flags for Debug configuration
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${custom_dbg_flags}")
@ -213,27 +222,27 @@ if(USE_BOOST_STACKTRACE)
set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_STATIC_RUNTIME OFF) # Do not require static C++ runtime
set(Boost_USE_MULTITHREADED ON)
find_package(Boost 1.82.0 COMPONENTS system filesystem REQUIRED)
if (Boost_FOUND)
add_definitions(-DBOOST_STACKTRACE_USE_ADDR2LINE=1)
include_directories(${Boost_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
list(APPEND STACKTRACE_DEP_LIBS ${Boost_LIBRARIES})
endif()
endif()
if (Boost_FOUND)
add_definitions(-DBOOST_STACKTRACE_USE_ADDR2LINE=1)
include_directories(${Boost_INCLUDE_DIRS})
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)
add_subdirectory(apps)
if (ENABLE_TESTS)
add_subdirectory(tests)
endif()
#add_subdirectory(apps)
# vim: ft=cmake sw=4 ts=4 noet sts=4 foldmethod=marker foldmarker=@{,@} :

2816
Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
" editorconfig/local.vimrc
" Copyright © 2023 Saul D. Beniquez @{
" Copyright © 2023-2024 Saul D. Beniquez @{
"
" Redistribution and use in source and binary forms, with or without
" modification, are permitted provided that the following conditions are met:
@ -23,15 +24,22 @@
" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
" POSSIBILITY OF SUCH DAMAGE. @}
let s:build_dir = 'vim-debug'
let s:build_cores = 2
let s:make_args = '-C '. s:build_dir . ' -j ' . s:build_cores
set foldmethod=expr
\ foldexpr=lsp#ui#vim#folding#foldexpr()
\ foldtext=lsp#ui#vim#folding#foldtext()
let s:cmake_path = system('which ' . 'cmake')
let s:ninja_path = system('which ' . 'ninja')
let s:build_dir = 'vim-debug'
let s:build_cores = 6
let s:make_args = '-C '. s:build_dir . ' -j ' . s:build_cores . ' all'
let s:cmake_path = substitute(system('which ' . 'cmake'),'\n$', '', '')
let s:ninja_path = substitute(system('which ' . 'ninja'),'\n$', '', '')
let s:make_prg = substitute(system('which ' . 'make'),'\n$', '','')
let s:cmake_generator = 'Unix Makefiles'
if (s:ninja_path != '')
let s:make_prg = s:ninja_path
let s:cmake_generator = 'Ninja'
endif
@ -42,8 +50,10 @@ if (s:cmake_path != '')
\' -G ' . s:cmake_generator
endif
let s:make_call = 'make ' . s:make_args
let s:ninja_call = 'ninja ' . s:make_args
let s:make_prg = "nice -20 " . s:make_prg
let s:make_call = s:make_prg . " " . s:make_args
let &makeprg = s:make_prg
if ! get(s:, 'defined', 0) " -- prevents the function from being redefined after compiling
function! BuildDebug()
@ -58,10 +68,9 @@ function! BuildDebug()
\ )
exec ':Dispatch ' . s:cmake_call
exec ':Dispatch ' . s:cmake_call . ' && ' . s:make_call
endif
set makeprg='ninja'
exec ':Make ' . s:make_args
else
if (
@ -125,5 +134,7 @@ set path+=src
set path+=include
set path+=app
autocmd! BufWritePre *.c,*.h,*.cpp,*.hpp LspDocumentFormat
" vim: set ts=4 sts=4 noet sw=4 foldmethod=marker foldmarker=@{,@} :

View File

@ -32,16 +32,11 @@ class CgiApplication : public Application {
inline void ImportRoutes(RouteDictionary& route_collection)
{
this->routes = std::move(route_collection);
this->Routes = std::move(route_collection);
}
#ifdef TESTING
/* Expose a public reference to the Routes map, but only for unit-testing
* builds */
RouteDictionary& Routes;
#endif
protected:
RouteDictionary routes;
RouteDictionary Routes;
};
}

View File

@ -23,7 +23,7 @@ namespace fs = std::filesystem;
class MarkdownRouteHandler : public IRouteHandler {
public:
MarkdownRouteHandler();
explicit MarkdownRouteHandler(fs::path working_dir);
MarkdownRouteHandler(const MarkdownRouteHandler& other) = default;
/*: IRouteHandler(other)
, html_data(other.html_data)
@ -40,18 +40,18 @@ class MarkdownRouteHandler : public IRouteHandler {
const std::string& name, const std::string& request_uri
);
#ifdef TESTING
inline std::string& GetHtmlData() { return html_data; }
inline std::string& GetMarkdownData() { return markdown_data; }
#endif
std::string& GetHtmlData() { return html_data; }
std::string& GetMarkdownData() { return markdown_data; }
static Dictionary<route::ptr<IRouteHandler>> GenerateRoutes(
static Dictionary<route::ptr<IRouteHandler>> GenerateRoutes(MarkdownRouteHandler& ref,
std::filesystem::path content_dir,
std::filesystem::path main_template
);
std::reference_wrapper<std::ostream> OutputStream;
const fs::path& getWorkingDir() { return this->work_dir; }
protected:
std::string render_document(
const std::string& title, const std::string& request_uri
@ -61,7 +61,7 @@ class MarkdownRouteHandler : public IRouteHandler {
const fs::path& document_path, std::string& out_document
);
static fs::path work_dir;
fs::path work_dir;
std::string html_data;
std::string markdown_data;
};

View File

@ -9,7 +9,7 @@
#pragma once
#include "debuginfo.hpp"
#include "private/debuginfo.hpp"
#include "types.hpp"
#include <algorithm>

View File

@ -1,5 +1,7 @@
# Copyright (c) 2024 Saul D. Beniquez
# License: MIT
set(LIBMDML_SOURCES
set(MDML_SOURCES
libmdml.cpp
exception.cpp
debuginfo.cpp
@ -8,46 +10,30 @@ set(LIBMDML_SOURCES
MarkdownRouteHandler.cpp
)
set(LIBMDML_LINK_LIBS ${LIBMDML_LINK_LIBS} ${STACKTRACE_DEP_LIBS} )
add_library(mdml OBJECT
${MDML_SOURCES}
)
set(LIBMDML_DEP_LIBS ${LIBMDML_DEP_LIBS} ${STACKTRACE_DEP_LIBS} )
if (USE_SYSTEM_CMARK)
set(LIBMDML_LINK_LIBS ${LIBMDML_LINK_LIBS} ${cmark_LIBRARIES} )
endif()
add_library(mdml SHARED ${LIBMDML_SOURCES})
add_library(mdml_static STATIC ${LIBMDML_SOURCES})
add_library(mdml_test STATIC ${LIBMDML_SOURCES})
target_compile_options(mdml PRIVATE ${CMAKE_CXX_FLAGS})
target_compile_options(mdml_static PRIVATE ${CMAKE_CXX_FLAGS})
target_compile_options(mdml_test PRIVATE ${CMAKE_CXX_FLAGS})
set_target_properties(mdml_static PROPERTIES
CMAKE_POSITION_INDEPENDENT_CODE OFF # This forces all linkages to be static (?)
)
set_target_properties(mdml_test PROPERTIES
CMAKE_POSITION_INDEPENDENT_CODE OFF # This forces all linkages to be static (?)
)
target_compile_definitions(mdml_test PRIVATE -DTESTING)
if (NOT CMARK_STATIC_LINKAGE)
target_link_libraries(mdml PRIVATE cmark)
target_link_libraries(mdml_static PRIVATE cmark)
target_link_libraries(mdml_test PRIVATE cmark)
set(LIBMDML_DEP_LIBS ${LIBMDML_DEP_LIBS} ${cmark_LIBRARIES} )
else()
target_link_libraries(mdml PRIVATE cmark_static)
target_link_libraries(mdml_static PRIVATE cmark_static)
target_link_libraries(mdml_test PRIVATE cmark_static)
if (NOT CMARK_STATIC_LINKAGE)
set(LIBMDML_DEP_LIBS cmark)
else()
set(LIBMDML_DEP_LIBS cmark_static)
endif()
endif()
set_target_properties(mdml PROPERTIES
CMAKE_POSITION_INDEPENDENT_CODE OFF
)
# Check if the system is Linux
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
# Add the -rdynamic linker option
target_link_options(mdml PUBLIC -rdynamic)
target_link_options(mdml_static PUBLIC -rdynamic)
target_link_options(mdml_test PUBLIC -rdynamic)
endif()
target_link_libraries(mdml PRIVATE ${LIBMDML_LINK_LIBS})
target_link_libraries(mdml_static PRIVATE ${LIBMDML_LINK_LIBS})
target_link_libraries(mdml_test PRIVATE ${LIBMDML_LINK_LIBS})
target_link_libraries(mdml PUBLIC ${LIBMDML_DEP_LIBS})

View File

@ -25,15 +25,15 @@ CgiApplication::CgiApplication(
int argc, c::const_string argv[], c::const_string env[]
)
: Application(argc, argv, env)
, routes()
, Routes()
#ifdef TESTING
, Routes(this->routes)
, Routes(this->Routes)
#endif
{
}
CgiApplication::~CgiApplication()
{
for (auto& [key, val_ptr] : this->routes) {
for (auto& [key, val_ptr] : this->Routes) {
if (val_ptr.get() != nullptr) {
val_ptr.reset();
}
@ -65,8 +65,8 @@ CgiApplication::ProcessRequest()
if (question_pos != not_found) {
page_name = request_URI.substr(0, question_pos);
}
if (routes.find(page_name) != routes.end()) {
auto route_handler = routes[page_name];
if (Routes.find(page_name) != Routes.end()) {
auto route_handler = Routes[page_name];
auto result =
route_handler->Process(page_name, request_URI);

View File

@ -23,14 +23,7 @@
using namespace mdml;
#if defined(TESTING)
constexpr const char* DEFAULT_WORKDIR = "./data";
#else
constexpr const char* DEFAULT_WORKDIR = "/usr/local/www";
#endif
fs::path MarkdownRouteHandler::work_dir = fs::absolute(DEFAULT_WORKDIR);
namespace {
const auto NOT_FOUND = std::string::npos;
void
@ -49,11 +42,12 @@ string_replace(
}
}
}
}
MarkdownRouteHandler::MarkdownRouteHandler()
: IRouteHandler(), OutputStream(std::cout)
MarkdownRouteHandler::MarkdownRouteHandler(fs::path working_dir)
: IRouteHandler(), OutputStream(std::cout), work_dir(working_dir)
{
work_dir = fs::absolute(work_dir);
}
MarkdownRouteHandler::~MarkdownRouteHandler() {}
@ -99,12 +93,12 @@ MarkdownRouteHandler::Process(
}
Dictionary<route::ptr<IRouteHandler>>
MarkdownRouteHandler::GenerateRoutes(
MarkdownRouteHandler::GenerateRoutes(MarkdownRouteHandler& ref,
std::filesystem::path content_dir, std::filesystem::path main_template
)
{
if (content_dir.is_relative()) {
content_dir = work_dir / content_dir;
content_dir = ref.work_dir / content_dir;
}
Dictionary<route::ptr<IRouteHandler>> results;
@ -118,12 +112,11 @@ MarkdownRouteHandler::GenerateRoutes(
// Check if the file has a .md extension and a specific
// name pattern
if (extension == ".md") {
auto& routeHandler =
*(new MarkdownRouteHandler());
auto& routeHandler = ref;
// Load template and document
routeHandler.LoadTemplate(
(work_dir / main_template).string()
(ref.work_dir / main_template).string()
);
routeHandler.LoadMarkdown(entry.path().string());

View File

@ -7,8 +7,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "debuginfo.hpp"
#include "platform.hpp"
#include "private/platform.hpp"
#include "private/debuginfo.hpp"
#if defined(HAVE_EXECINFO_H) && !defined(__linux__)
#include <cxxabi.h>

View File

@ -9,7 +9,7 @@
#include "exception.hpp"
#include "debuginfo.hpp"
#include "private/debuginfo.hpp"
#include "types.hpp"
#include <algorithm>

View File

@ -1,42 +1,35 @@
# Copyright (c) 2024 Saul D. Beniquez
# License: MIT
# Add the test executable
set(MDML_TEST_SOURCE_LIST
add_executable(test-runner
exception-test.cpp
Result-test.cpp
Application-test.cpp
CgiApplication-test.cpp
MarkdownRouteHandler-test.cpp
#MarkdownRouteHandler-test.cpp
)
add_executable(mdml-tests
${MDML_TEST_SOURCE_LIST}
set_target_properties(test-runner PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests"
)
set_target_properties(mdml-tests PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/artifacts/tests"
)
target_link_directories(test-runner PRIVATE ${CATCH2_LIBRARY_DIRS})
target_include_directories(test-runner PRIVATE ${Catch2_INCLUDE_DIRS})
target_compile_definitions(mdml-tests PUBLIC -DTESTING)
target_link_directories(mdml-tests PRIVATE ${CATCH2_LIBRARY_DIRS})
target_include_directories(mdml-tests PRIVATE ${Catch2_INCLUDE_DIRS})
# Link the test executable with libmdml_static source code and Catch2
target_link_libraries(mdml-tests
# Link the test executable with libmdml and Catch2
target_link_libraries(test-runner
PRIVATE
mdml_test
mdml
Catch2::Catch2WithMain
)
# Extras: Catch2 Ctest integration. @{
# add catch2's ctest CMake module and register the tests defined by mdml-tests
# add catch2's ctest CMake module and register the tests defined by test-runner
# using catch_discover_tests
list(APPEND CMAKE_MODULE_PATH ${Catch2_SOURCE_DIR}/extras)
include(CTest)
include(Catch)
catch_discover_tests(mdml-tests)
catch_discover_tests(test-runner)
# @}
# Add a custom ctest target to the build system
@ -44,7 +37,7 @@ add_custom_target(ctest
COMMAND ctest -C $CONFIGURATION --test-dir . --output-on-failure
)
add_dependencies(ctest
mdml-tests
test-runner
copy_assets
)
# vim: ft=cmake sw=4 ts=4 noet sts=4 foldmethod=marker foldmarker=@{,@} :

View File

@ -14,7 +14,9 @@
#include "tests-common.hpp"
#include <catch2/matchers/catch_matchers_string.hpp>
namespace {
BEGIN_TEST_SUITE("CgiApplication")
{
struct simulated_launch {
static const char* argv[];
static const char* env[];
@ -41,10 +43,8 @@ class ExampleRouteHandler : public mdml::IRouteHandler {
virtual ~ExampleRouteHandler() = default;
};
}
BEGIN_TEST_SUITE("CgiApplication")
{
using namespace mdml;
struct TestFixture {
const char* envp[4] = { "PATH=/usr/bin",

View File

@ -37,14 +37,14 @@ BEGIN_TEST_SUITE("MarkdownRouteHandler Unit Tests")
TEST("MarkdownRouteHandler Construction and allocation")
{
REQUIRE_NOTHROW([]() { MarkdownRouteHandler test; }());
REQUIRE_NOTHROW([]() { MarkdownRouteHandler test("/tmp"); }());
}
TEST("MarkdownRouteHandler Static Route Generator")
{
REQUIRE_NOTHROW([]() {
auto routes = MarkdownRouteHandler::GenerateRoutes(
MarkdownRouteHandler router("/tmp");
REQUIRE_NOTHROW([&]() {
auto routes = MarkdownRouteHandler::GenerateRoutes(router,
"content", "templates/main.thtml"
);
@ -59,7 +59,7 @@ BEGIN_TEST_SUITE("MarkdownRouteHandler Unit Tests")
FIXTURE_TEST("MarkdownRouteHandler LoadHtml")
{
MarkdownRouteHandler test_obj;
MarkdownRouteHandler test_obj("/tmp");
SECTION("File exists")
{