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_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUGSOFT")
|
||||
option(BUILD_TESTS "Build tests" OFF)
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
|
@ -46,4 +48,24 @@ configure_file(
|
|||
|
||||
install(FILES ${PROJECT_BINARY_DIR}/pkg/${project_lower}-config.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 ()
|
|
@ -22,4 +22,17 @@ macro(add_headers)
|
|||
endif ()
|
||||
endforeach ()
|
||||
set_property(GLOBAL PROPERTY Headers ${tmp})
|
||||
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 SetRouter(Ref<Router> &router);
|
||||
void AddSendResponse(SendData);
|
||||
void CloseRequest(int id) const;
|
||||
Ref<MiddleWareHandler> &Middleware() { return m_MiddleWare; }
|
||||
bool HasBodyParser(const std::string &key) {
|
||||
return m_ParseFunctions.contains(key);
|
||||
|
|
|
@ -123,6 +123,10 @@ struct RequestJob : public WorkerJob {
|
|||
MRequestHandler->AddSendResponse(
|
||||
{0, (ssize_t)content.size(), MRequest->ID, content});
|
||||
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) {
|
||||
fprintf(stderr,
|
||||
"[VWEB] >> Failed to handle Requests... Error thrown\n%s\n",
|
||||
|
@ -157,8 +161,11 @@ void RequestHandler::AddSendResponse(SendData sendData) {
|
|||
auto id = sendData.SocketID;
|
||||
m_Server->m_OutRequest.Add(id, sendData);
|
||||
if (!m_SocketManager->SetSendListen(id)) {
|
||||
SocketUtils::Close(id);
|
||||
m_Server->m_OutRequest.Remove(id);
|
||||
CloseRequest(id);
|
||||
}
|
||||
}
|
||||
void RequestHandler::CloseRequest(const int id) const {
|
||||
SocketUtils::Close(id);
|
||||
m_Server->m_OutRequest.Remove(id);
|
||||
}
|
||||
} // namespace VWeb
|
||||
|
|
|
@ -156,28 +156,23 @@ struct InlineRoute : Route {
|
|||
};
|
||||
|
||||
void Router::Get(const std::string &path, const RouteFunction &func) {
|
||||
m_Tree.Add(s_HttpMethodToString[HttpMethod::GET] + path,
|
||||
(uint32_t)HttpMethod::GET,
|
||||
m_Tree.Add(path, static_cast<uint32_t>(HttpMethod::GET),
|
||||
[func] { return std::make_shared<InlineRoute>(func); });
|
||||
}
|
||||
void Router::Post(const std::string &path, const RouteFunction &func) {
|
||||
m_Tree.Add(s_HttpMethodToString[HttpMethod::POST] + path,
|
||||
(uint32_t)HttpMethod::POST,
|
||||
m_Tree.Add(path, static_cast<uint32_t>(HttpMethod::POST),
|
||||
[func] { return std::make_shared<InlineRoute>(func); });
|
||||
}
|
||||
void Router::Put(const std::string &path, const RouteFunction &func) {
|
||||
m_Tree.Add(s_HttpMethodToString[HttpMethod::PUT] + path,
|
||||
(uint32_t)HttpMethod::PUT,
|
||||
m_Tree.Add(path, static_cast<uint32_t>(HttpMethod::PUT),
|
||||
[func] { return std::make_shared<InlineRoute>(func); });
|
||||
}
|
||||
void Router::Patch(const std::string &path, const RouteFunction &func) {
|
||||
m_Tree.Add(s_HttpMethodToString[HttpMethod::PATCH] + path,
|
||||
(uint32_t)HttpMethod::PATCH,
|
||||
m_Tree.Add(path, static_cast<uint32_t>(HttpMethod::PATCH),
|
||||
[func] { return std::make_shared<InlineRoute>(func); });
|
||||
}
|
||||
void Router::Delete(const std::string &path, const RouteFunction &func) {
|
||||
m_Tree.Add(s_HttpMethodToString[HttpMethod::DELETE] + path,
|
||||
(uint32_t)HttpMethod::DELETE,
|
||||
m_Tree.Add(path, static_cast<uint32_t>(HttpMethod::DELETE),
|
||||
[func] { return std::make_shared<InlineRoute>(func); });
|
||||
}
|
||||
} // 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