Commit 763d588e authored by Nico Caprioli's avatar Nico Caprioli

Master merge and tests

* Manually merged with master
* Fixed bugs
* invokeHandler modified in findRoute
* router_tests
parent 01eb1fbf
......@@ -68,9 +68,7 @@ struct Route {
enum class Status { Match, NotFound };
enum class Result {
Ok, Failure
};
enum class Result { Ok, Failure };
typedef std::function<Result(const Request, Http::ResponseWriter)> Handler;
......@@ -84,8 +82,6 @@ struct Route {
Handler handler_;
};
namespace Private {
class RouterHandler;
}
......@@ -112,20 +108,29 @@ private:
static FragmentType getFragmentType(const std::string_view &fragment);
Route::Status invokeRouteHandler(const std::string_view &path,
const Http::Request& req, Http::ResponseWriter response,
std::vector<TypedParam> &params,
std::vector<TypedParam> &splats) const;
std::tuple<std::shared_ptr<Route>, std::vector<TypedParam>, std::vector<TypedParam>>
findRoute(const std::string_view &path,
std::vector<TypedParam> &params,
std::vector<TypedParam> &splats) const;
public:
FragmentTreeNode();
explicit FragmentTreeNode(const std::shared_ptr<char> &resourceReference);
void addRoute(const std::string_view &path, Route::Handler &handler, std::shared_ptr<char> &resourceReference);
void addRoute(const std::string_view &path, const Route::Handler &handler,
const std::shared_ptr<char> &resourceReference);
bool removeRoute(const std::string_view &path);
Route::Status invokeRouteHandler(const Http::Request& req, Http::ResponseWriter response) const;
/**
* Finds the correct route for the given path.
* \param[in] path Requested resource path (usually derived from request)
* \throws std::runtime_error An empty path was given
* \return Found route with its resolved parameters and splats (if no route is found, first element of the tuple
* is a null pointer).
*/
std::tuple<std::shared_ptr<Route>, std::vector<TypedParam>, std::vector<TypedParam>>
findRoute(const std::string_view &path) const;
};
class Router {
......@@ -150,9 +155,7 @@ public:
inline bool hasNotFoundHandler() { return notFoundHandler != nullptr; }
void invokeNotFoundHandler(const Http::Request &req, Http::ResponseWriter resp) const;
Route::Status route(const Http::Request& request, Http::ResponseWriter response);
Status route(const Http::Request& request, Http::ResponseWriter response);
Route::Status route(const Http::Request& request, Http::ResponseWriter response);
private:
void addRoute(Http::Method method, std::string resource, Route::Handler handler);
......
......@@ -46,7 +46,7 @@ namespace std {
string_view
substr(size_type pos = 0, size_type count = npos) const {
substr(size_type pos, size_type count = npos) const {
if (pos > size_) {
throw std::out_of_range("Out of range.");
}
......
This diff is collapsed.
......@@ -12,23 +12,25 @@
using namespace Pistache;
bool match(const Rest::Route& route, const std::string& req) {
return std::get<0>(route.match(req));
bool match(const Rest::FragmentTreeNode& routes, const std::string& req) {
std::shared_ptr<Rest::Route> route;
std::tie(route, std::ignore, std::ignore) = routes.findRoute({req.data(), req.size()});
return route != nullptr;
}
bool matchParams(
const Rest::Route& route, const std::string& req,
const Rest::FragmentTreeNode& routes, const std::string& req,
std::initializer_list<std::pair<std::string, std::string>> list)
{
bool ok;
std::shared_ptr<Rest::Route> route;
std::vector<Rest::TypedParam> params;
std::tie(ok, params, std::ignore) = route.match(req);
std::tie(route, params, std::ignore) = routes.findRoute({req.data(), req.size()});
if (!ok) return false;
if (route == nullptr) return false;
for (const auto& p: list) {
auto it = std::find_if(params.begin(), params.end(), [&](const Rest::TypedParam& param) {
return param.name() == p.first;
return param.name() == std::string_view(p.first.data(), p.first.size());
});
if (it == std::end(params)) {
std::cerr << "Did not find param '" << p.first << "'" << std::endl;
......@@ -45,14 +47,14 @@ bool matchParams(
}
bool matchSplat(
const Rest::Route& route, const std::string& req,
const Rest::FragmentTreeNode& routes, const std::string& req,
std::initializer_list<std::string> list)
{
bool ok;
std::shared_ptr<Rest::Route> route;
std::vector<Rest::TypedParam> splats;
std::tie(ok, std::ignore, splats) = route.match(req);
if (!ok) return false;
std::tie(route, std::ignore, splats) = routes.findRoute({req.data(), req.size()});
if (route == nullptr) return false;
if (list.size() != splats.size()) {
std::cerr << "Size mismatch (" << list.size() << " != " << splats.size() << ")"
......@@ -74,55 +76,57 @@ bool matchSplat(
return true;
}
Rest::Route
makeRoute(std::string value) {
auto noop = [](const Http::Request&, Http::Response) { return Rest::Route::Result::Ok; };
return Rest::Route(value, Http::Method::Get, noop);
}
TEST(router_test, test_fixed_routes) {
auto r1 = makeRoute("/v1/hello");
ASSERT_TRUE(match(r1, "/v1/hello"));
ASSERT_FALSE(match(r1, "/v2/hello"));
ASSERT_FALSE(match(r1, "/v1/hell0"));
Rest::FragmentTreeNode routes;
routes.addRoute(std::string_view("/v1/hello"), nullptr, nullptr);
ASSERT_TRUE(match(routes, "/v1/hello"));
ASSERT_FALSE(match(routes, "/v2/hello"));
ASSERT_FALSE(match(routes, "/v1/hell0"));
auto r2 = makeRoute("/a/b/c");
ASSERT_TRUE(match(r2, "/a/b/c"));
routes.addRoute(std::string_view("/a/b/c"), nullptr, nullptr);
ASSERT_TRUE(match(routes, "/a/b/c"));
}
TEST(router_test, test_parameters) {
auto r1 = makeRoute("/v1/hello/:name");
ASSERT_TRUE(matchParams(r1, "/v1/hello/joe", {
Rest::FragmentTreeNode routes;
routes.addRoute(std::string_view("/v1/hello/:name"), nullptr, nullptr);
ASSERT_TRUE(matchParams(routes, "/v1/hello/joe", {
{ ":name", "joe" }
}));
auto r2 = makeRoute("/greetings/:from/:to");
ASSERT_TRUE(matchParams(r2, "/greetings/foo/bar", {
routes.addRoute(std::string_view("/greetings/:from/:to"), nullptr, nullptr);
ASSERT_TRUE(matchParams(routes, "/greetings/foo/bar", {
{ ":from", "foo" },
{ ":to" , "bar" }
}));
}
TEST(router_test, test_optional) {
auto r1 = makeRoute("/get/:key?");
ASSERT_TRUE(match(r1, "/get"));
ASSERT_TRUE(match(r1, "/get/"));
ASSERT_TRUE(matchParams(r1, "/get/foo", {
Rest::FragmentTreeNode routes;
routes.addRoute(std::string_view("/get/:key?"), nullptr, nullptr);
ASSERT_TRUE(match(routes, "/get"));
ASSERT_TRUE(match(routes, "/get/"));
ASSERT_TRUE(matchParams(routes, "/get/foo", {
{ ":key", "foo" }
}));
ASSERT_TRUE(matchParams(r1, "/get/foo/", {
ASSERT_TRUE(matchParams(routes, "/get/foo/", {
{ ":key", "foo" }
}));
ASSERT_FALSE(match(r1, "/get/foo/bar"));
ASSERT_FALSE(match(routes, "/get/foo/bar"));
}
TEST(router_test, test_splat) {
auto r1 = makeRoute("/say/*/to/*");
ASSERT_TRUE(match(r1, "/say/hello/to/user"));
ASSERT_FALSE(match(r1, "/say/hello/to"));
ASSERT_FALSE(match(r1, "/say/hello/to/user/please"));
Rest::FragmentTreeNode routes;
routes.addRoute(std::string_view("/say/*/to/*"), nullptr, nullptr);
ASSERT_TRUE(matchSplat(r1, "/say/hello/to/user", { "hello", "user" }));
ASSERT_TRUE(matchSplat(r1, "/say/hello/to/user/", { "hello", "user" }));
}
ASSERT_TRUE(match(routes, "/say/hello/to/user"));
ASSERT_FALSE(match(routes, "/say/hello/to"));
ASSERT_FALSE(match(routes, "/say/hello/to/user/please"));
ASSERT_TRUE(matchSplat(routes, "/say/hello/to/user", { "hello", "user" }));
ASSERT_TRUE(matchSplat(routes, "/say/hello/to/user/", { "hello", "user" }));
}
\ No newline at end of file
......@@ -5,7 +5,7 @@ TEST(string_view_test, substr_test) {
std::string_view orig ("test");
std::string_view targ ("est");
sub = orig.substr(1);
std::string_view sub = orig.substr(1);
ASSERT_EQ(sub, targ);
sub = orig.substr(1, 10);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment