Fix: Router Functions are the same weight as classes
also added some basic tests for it.
This commit is contained in:
parent
516e33d165
commit
f001b24749
7 changed files with 138 additions and 13 deletions
|
@ -6,6 +6,8 @@ set(project_lower vweb)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUGSOFT")
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUGSOFT")
|
||||||
|
option(BUILD_TESTS "Build tests" OFF)
|
||||||
|
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
|
@ -47,3 +49,23 @@ configure_file(
|
||||||
install(FILES ${PROJECT_BINARY_DIR}/pkg/${project_lower}-config.cmake
|
install(FILES ${PROJECT_BINARY_DIR}/pkg/${project_lower}-config.cmake
|
||||||
${PROJECT_BINARY_DIR}/${project_lower}-config-version.cmake
|
${PROJECT_BINARY_DIR}/${project_lower}-config-version.cmake
|
||||||
DESTINATION lib/${PROJECT_NAME}-${version})
|
DESTINATION lib/${PROJECT_NAME}-${version})
|
||||||
|
|
||||||
|
if (BUILD_TESTS)
|
||||||
|
add_subdirectory(Tests)
|
||||||
|
get_property(test_sources GLOBAL PROPERTY Test_SRCS)
|
||||||
|
set(TESTS_SRCS ${test_sources})
|
||||||
|
|
||||||
|
Include(FetchContent)
|
||||||
|
FetchContent_Declare(
|
||||||
|
Catch2
|
||||||
|
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||||
|
GIT_TAG v3.4.0
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(Catch2)
|
||||||
|
add_executable(tests ${SOURCE_FILES} ${TESTS_SRCS})
|
||||||
|
target_link_libraries(tests PRIVATE Catch2::Catch2WithMain)
|
||||||
|
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
|
||||||
|
include(CTest)
|
||||||
|
include(Catch)
|
||||||
|
catch_discover_tests(tests WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Tests)
|
||||||
|
endif ()
|
|
@ -23,3 +23,16 @@ macro(add_headers)
|
||||||
endforeach ()
|
endforeach ()
|
||||||
set_property(GLOBAL PROPERTY Headers ${tmp})
|
set_property(GLOBAL PROPERTY Headers ${tmp})
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
|
macro(add_tests)
|
||||||
|
get_property(tmp GLOBAL PROPERTY Test_SRCS)
|
||||||
|
file(RELATIVE_PATH _relPath "${PROJECT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
foreach (_src ${ARGN})
|
||||||
|
if (_relPath)
|
||||||
|
list(APPEND tmp "${_relPath}/${_src}")
|
||||||
|
else ()
|
||||||
|
list(APPEND tmp "${_src}")
|
||||||
|
endif ()
|
||||||
|
endforeach ()
|
||||||
|
set_property(GLOBAL PROPERTY Test_SRCS ${tmp})
|
||||||
|
endmacro()
|
|
@ -21,6 +21,7 @@ public:
|
||||||
void Stop();
|
void Stop();
|
||||||
void SetRouter(Ref<Router> &router);
|
void SetRouter(Ref<Router> &router);
|
||||||
void AddSendResponse(SendData);
|
void AddSendResponse(SendData);
|
||||||
|
void CloseRequest(int id) const;
|
||||||
Ref<MiddleWareHandler> &Middleware() { return m_MiddleWare; }
|
Ref<MiddleWareHandler> &Middleware() { return m_MiddleWare; }
|
||||||
bool HasBodyParser(const std::string &key) {
|
bool HasBodyParser(const std::string &key) {
|
||||||
return m_ParseFunctions.contains(key);
|
return m_ParseFunctions.contains(key);
|
||||||
|
|
|
@ -123,6 +123,10 @@ struct RequestJob : public WorkerJob {
|
||||||
MRequestHandler->AddSendResponse(
|
MRequestHandler->AddSendResponse(
|
||||||
{0, (ssize_t)content.size(), MRequest->ID, content});
|
{0, (ssize_t)content.size(), MRequest->ID, content});
|
||||||
MMiddleWareHandler->Shutdown(MRequest, response);
|
MMiddleWareHandler->Shutdown(MRequest, response);
|
||||||
|
} catch (const std::bad_alloc &e) {
|
||||||
|
// We are out of memory... try to clean up some request...
|
||||||
|
SocketUtils::Close(MRequest->ID);
|
||||||
|
MRequestHandler->CloseRequest(MRequest->ID);
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"[VWEB] >> Failed to handle Requests... Error thrown\n%s\n",
|
"[VWEB] >> Failed to handle Requests... Error thrown\n%s\n",
|
||||||
|
@ -157,8 +161,11 @@ void RequestHandler::AddSendResponse(SendData sendData) {
|
||||||
auto id = sendData.SocketID;
|
auto id = sendData.SocketID;
|
||||||
m_Server->m_OutRequest.Add(id, sendData);
|
m_Server->m_OutRequest.Add(id, sendData);
|
||||||
if (!m_SocketManager->SetSendListen(id)) {
|
if (!m_SocketManager->SetSendListen(id)) {
|
||||||
|
CloseRequest(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void RequestHandler::CloseRequest(const int id) const {
|
||||||
SocketUtils::Close(id);
|
SocketUtils::Close(id);
|
||||||
m_Server->m_OutRequest.Remove(id);
|
m_Server->m_OutRequest.Remove(id);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} // namespace VWeb
|
} // namespace VWeb
|
||||||
|
|
|
@ -156,28 +156,23 @@ struct InlineRoute : Route {
|
||||||
};
|
};
|
||||||
|
|
||||||
void Router::Get(const std::string &path, const RouteFunction &func) {
|
void Router::Get(const std::string &path, const RouteFunction &func) {
|
||||||
m_Tree.Add(s_HttpMethodToString[HttpMethod::GET] + path,
|
m_Tree.Add(path, static_cast<uint32_t>(HttpMethod::GET),
|
||||||
(uint32_t)HttpMethod::GET,
|
|
||||||
[func] { return std::make_shared<InlineRoute>(func); });
|
[func] { return std::make_shared<InlineRoute>(func); });
|
||||||
}
|
}
|
||||||
void Router::Post(const std::string &path, const RouteFunction &func) {
|
void Router::Post(const std::string &path, const RouteFunction &func) {
|
||||||
m_Tree.Add(s_HttpMethodToString[HttpMethod::POST] + path,
|
m_Tree.Add(path, static_cast<uint32_t>(HttpMethod::POST),
|
||||||
(uint32_t)HttpMethod::POST,
|
|
||||||
[func] { return std::make_shared<InlineRoute>(func); });
|
[func] { return std::make_shared<InlineRoute>(func); });
|
||||||
}
|
}
|
||||||
void Router::Put(const std::string &path, const RouteFunction &func) {
|
void Router::Put(const std::string &path, const RouteFunction &func) {
|
||||||
m_Tree.Add(s_HttpMethodToString[HttpMethod::PUT] + path,
|
m_Tree.Add(path, static_cast<uint32_t>(HttpMethod::PUT),
|
||||||
(uint32_t)HttpMethod::PUT,
|
|
||||||
[func] { return std::make_shared<InlineRoute>(func); });
|
[func] { return std::make_shared<InlineRoute>(func); });
|
||||||
}
|
}
|
||||||
void Router::Patch(const std::string &path, const RouteFunction &func) {
|
void Router::Patch(const std::string &path, const RouteFunction &func) {
|
||||||
m_Tree.Add(s_HttpMethodToString[HttpMethod::PATCH] + path,
|
m_Tree.Add(path, static_cast<uint32_t>(HttpMethod::PATCH),
|
||||||
(uint32_t)HttpMethod::PATCH,
|
|
||||||
[func] { return std::make_shared<InlineRoute>(func); });
|
[func] { return std::make_shared<InlineRoute>(func); });
|
||||||
}
|
}
|
||||||
void Router::Delete(const std::string &path, const RouteFunction &func) {
|
void Router::Delete(const std::string &path, const RouteFunction &func) {
|
||||||
m_Tree.Add(s_HttpMethodToString[HttpMethod::DELETE] + path,
|
m_Tree.Add(path, static_cast<uint32_t>(HttpMethod::DELETE),
|
||||||
(uint32_t)HttpMethod::DELETE,
|
|
||||||
[func] { return std::make_shared<InlineRoute>(func); });
|
[func] { return std::make_shared<InlineRoute>(func); });
|
||||||
}
|
}
|
||||||
} // namespace VWeb
|
} // namespace VWeb
|
||||||
|
|
3
Tests/CMakeLists.txt
Normal file
3
Tests/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
add_tests(
|
||||||
|
Router.cpp
|
||||||
|
)
|
84
Tests/Router.cpp
Normal file
84
Tests/Router.cpp
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
#include "Includes/Router.h"
|
||||||
|
|
||||||
|
#include "Includes/Request.h"
|
||||||
|
#include "Includes/Response.h"
|
||||||
|
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
|
namespace VWeb {
|
||||||
|
|
||||||
|
class FailureRoute final : public Route {
|
||||||
|
public:
|
||||||
|
bool IsAllowed(Request &request) override { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_CASE("route_that_exists_returns_route", "[Router]") {
|
||||||
|
Router router;
|
||||||
|
Ref<Request> request = CreateRef<Request>();
|
||||||
|
request->URI = "/test";
|
||||||
|
router.Register<Route>("/test");
|
||||||
|
|
||||||
|
REQUIRE(router.FindRoute(request) != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("route_that_not_exists_returns_nullptr", "[Router]") {
|
||||||
|
Router router;
|
||||||
|
Ref<Request> request = CreateRef<Request>();
|
||||||
|
request->URI = "/testre";
|
||||||
|
router.Register<Route>("/test");
|
||||||
|
|
||||||
|
REQUIRE(router.FindRoute(request) == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("route_matches_exactly", "[Router]") {
|
||||||
|
Router router;
|
||||||
|
Ref<Request> request = CreateRef<Request>();
|
||||||
|
request->URI = "/test/id";
|
||||||
|
router.Register<FailureRoute>("/test/:id");
|
||||||
|
router.Register<Route>("/test/id");
|
||||||
|
|
||||||
|
auto route = router.FindRoute(request);
|
||||||
|
REQUIRE(route);
|
||||||
|
REQUIRE(route->IsAllowed(*request));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("route_can_handle_variants", "[Router]") {
|
||||||
|
Router router;
|
||||||
|
Ref<Request> request = CreateRef<Request>();
|
||||||
|
request->URI = "/test/1";
|
||||||
|
router.Register<FailureRoute>("/test/id");
|
||||||
|
router.Register<Route>("/test/:id");
|
||||||
|
|
||||||
|
auto route = router.FindRoute(request);
|
||||||
|
REQUIRE(route);
|
||||||
|
REQUIRE(route->IsAllowed(*request));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("router_returns_function_instead_of_class", "[Router]") {
|
||||||
|
Router router;
|
||||||
|
Ref<Request> request = CreateRef<Request>();
|
||||||
|
request->URI = "/test/id";
|
||||||
|
router.Register<FailureRoute>("/test/:id");
|
||||||
|
router.Get("/test/id", [](Request &, Response &) {
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
auto route = router.FindRoute(request);
|
||||||
|
REQUIRE(route);
|
||||||
|
REQUIRE(route->IsAllowed(*request));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("router_returns_class_if_function_is_provided", "[Router]") {
|
||||||
|
Router router;
|
||||||
|
Ref<Request> request = CreateRef<Request>();
|
||||||
|
request->URI = "/test/1";
|
||||||
|
router.Register<FailureRoute>("/test/:id");
|
||||||
|
router.Get("/test/id", [](Request &, Response &) {
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
auto route = router.FindRoute(request);
|
||||||
|
REQUIRE(route);
|
||||||
|
REQUIRE_FALSE(route->IsAllowed(*request));
|
||||||
|
}
|
||||||
|
} // namespace VWeb
|
Loading…
Reference in a new issue