mirror of
https://github.com/CrowCpp/Crow.git
synced 2024-06-07 21:10:44 +00:00
increase test coverage of json.h
This commit is contained in:
parent
1173eba332
commit
dd74354a7b
@ -4,8 +4,3 @@ Flask++
|
||||
Simple C++ HTTP Server (inspired by Python Flask)
|
||||
|
||||
|
||||
|
||||
Other JSON library
|
||||
==================
|
||||
|
||||
https://github.com/d-led/picojson_serializer
|
||||
|
8
flask.h
8
flask.h
@ -7,7 +7,7 @@
|
||||
#include <type_traits>
|
||||
#include <thread>
|
||||
|
||||
#define FLASK_ENABLE_LOGGING
|
||||
//#define FLASK_ENABLE_LOGGING
|
||||
|
||||
#include "http_server.h"
|
||||
#include "utility.h"
|
||||
@ -39,12 +39,6 @@ namespace flask
|
||||
return router_.new_rule_tagged<Tag>(std::move(rule));
|
||||
}
|
||||
|
||||
auto route(std::string&& rule)
|
||||
-> typename std::result_of<decltype(&Router::new_rule)(Router, std::string&&)>::type
|
||||
{
|
||||
return router_.new_rule(std::move(rule));
|
||||
}
|
||||
|
||||
Flask& port(std::uint16_t port)
|
||||
{
|
||||
port_ = port;
|
||||
|
22
json.h
22
json.h
@ -267,15 +267,6 @@ namespace flask
|
||||
return boost::lexical_cast<double>(start_, end_-start_);
|
||||
}
|
||||
|
||||
detail::r_string s_raw() const
|
||||
{
|
||||
#ifndef FLASKPP_JSON_NO_ERROR_CHECK
|
||||
if (t() != type::String)
|
||||
throw std::runtime_error("value is not string");
|
||||
#endif
|
||||
return detail::r_string{start_, (uint32_t)(end_-start_), has_escaping()};
|
||||
}
|
||||
|
||||
detail::r_string s() const
|
||||
{
|
||||
#ifndef FLASKPP_JSON_NO_ERROR_CHECK
|
||||
@ -481,7 +472,7 @@ namespace flask
|
||||
case type::False: os << "false"; break;
|
||||
case type::True: os << "true"; break;
|
||||
case type::Number: os << r.d(); break;
|
||||
case type::String: os << '"' << r.s_raw() << '"'; break;
|
||||
case type::String: os << '"' << r.s() << '"'; break;
|
||||
case type::List:
|
||||
{
|
||||
os << '[';
|
||||
@ -591,7 +582,7 @@ namespace flask
|
||||
uint8_t has_escaping = 0;
|
||||
while(1)
|
||||
{
|
||||
if (flask_json_likely(*data != '"' && *data != '\\'))
|
||||
if (flask_json_likely(*data != '"' && *data != '\\' && *data != '\0'))
|
||||
{
|
||||
data ++;
|
||||
}
|
||||
@ -625,6 +616,8 @@ namespace flask
|
||||
return {};
|
||||
}
|
||||
}
|
||||
else
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@ -906,9 +899,9 @@ namespace flask
|
||||
rvalue parse()
|
||||
{
|
||||
ws_skip();
|
||||
auto ret = decode_object(); // or decode value?
|
||||
auto ret = decode_value(); // or decode object?
|
||||
ws_skip();
|
||||
if (*data != '\0')
|
||||
if (ret && *data != '\0')
|
||||
ret.set_error();
|
||||
return ret;
|
||||
}
|
||||
@ -920,7 +913,8 @@ namespace flask
|
||||
inline rvalue load(const char* data, size_t size)
|
||||
{
|
||||
char* s = new char[size+1];
|
||||
memcpy(s, data, size+1);
|
||||
memcpy(s, data, size);
|
||||
s[size] = 0;
|
||||
auto ret = load_nocopy_internal(s, size);
|
||||
if (ret)
|
||||
ret.key_.force(s, size);
|
||||
|
84
routing.h
84
routing.h
@ -46,56 +46,6 @@ namespace flask
|
||||
friend class Router;
|
||||
};
|
||||
|
||||
class Rule : public BaseRule
|
||||
{
|
||||
public:
|
||||
Rule(std::string rule) noexcept
|
||||
: BaseRule(std::move(rule))
|
||||
{
|
||||
}
|
||||
|
||||
Rule& name(std::string name) noexcept
|
||||
{
|
||||
name_ = std::move(name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
void operator()(Func&& f)
|
||||
{
|
||||
static_assert(black_magic::CallHelper<Func, black_magic::S<>>::value,
|
||||
"Handler type is mismatched with URL paramters");
|
||||
static_assert(!std::is_same<void, decltype(f())>::value,
|
||||
"Handler function cannot have void return type; valid return types: string, int, flask::resposne");
|
||||
handler_ = [f = std::move(f)]{
|
||||
return response(f());
|
||||
};
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
void operator()(std::string name, Func&& f)
|
||||
{
|
||||
name_ = std::move(name);
|
||||
this->operator()<Func>(f);
|
||||
}
|
||||
|
||||
void validate()
|
||||
{
|
||||
if (!handler_)
|
||||
{
|
||||
throw std::runtime_error(name_ + (!name_.empty() ? ": " : "") + "no handler for url " + rule_);
|
||||
}
|
||||
}
|
||||
|
||||
response handle(const request&, const routing_params&)
|
||||
{
|
||||
return handler_();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::function<response()> handler_;
|
||||
};
|
||||
|
||||
template <typename ... Args>
|
||||
class TaggedRule : public BaseRule
|
||||
{
|
||||
@ -192,6 +142,10 @@ namespace flask
|
||||
|
||||
void validate()
|
||||
{
|
||||
if (!handler_ && !handler_with_req_)
|
||||
{
|
||||
throw std::runtime_error(name_ + (!name_.empty() ? ": " : "") + "no handler for url " + rule_);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
@ -208,6 +162,7 @@ namespace flask
|
||||
handler_ = [f = std::move(f)](Args ... args){
|
||||
return response(f(args...));
|
||||
};
|
||||
handler_with_req_ = nullptr;
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
@ -224,6 +179,7 @@ namespace flask
|
||||
handler_with_req_ = [f = std::move(f)](const flask::request& request, Args ... args){
|
||||
return response(f(request, args...));
|
||||
};
|
||||
handler_ = nullptr;
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
@ -481,8 +437,6 @@ public:
|
||||
char c = url[i];
|
||||
if (c == '<')
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
static struct ParamTraits
|
||||
{
|
||||
ParamType type;
|
||||
@ -498,27 +452,21 @@ public:
|
||||
{ ParamType::PATH, "<path>" },
|
||||
};
|
||||
|
||||
for(auto it = std::begin(paramTraits); it != std::end(paramTraits); ++it)
|
||||
for(auto& x:paramTraits)
|
||||
{
|
||||
if (url.compare(i, it->name.size(), it->name) == 0)
|
||||
if (url.compare(i, x.name.size(), x.name) == 0)
|
||||
{
|
||||
if (!nodes_[idx].param_childrens[(int)it->type])
|
||||
if (!nodes_[idx].param_childrens[(int)x.type])
|
||||
{
|
||||
auto new_node_idx = new_node();
|
||||
nodes_[idx].param_childrens[(int)it->type] = new_node_idx;
|
||||
nodes_[idx].param_childrens[(int)x.type] = new_node_idx;
|
||||
}
|
||||
idx = nodes_[idx].param_childrens[(int)it->type];
|
||||
i += it->name.size();
|
||||
found = true;
|
||||
idx = nodes_[idx].param_childrens[(int)x.type];
|
||||
i += x.name.size();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
throw std::runtime_error("Invalid parameter type: " + url +
|
||||
" (" + boost::lexical_cast<std::string>(i) + ")");
|
||||
}
|
||||
i --;
|
||||
}
|
||||
else
|
||||
@ -616,14 +564,6 @@ public:
|
||||
return *ruleObject;
|
||||
}
|
||||
|
||||
Rule& new_rule(const std::string& rule)
|
||||
{
|
||||
Rule* r(new Rule(rule));
|
||||
rules_.emplace_back(r);
|
||||
trie_.add(rule, rules_.size() - 1);
|
||||
return *r;
|
||||
}
|
||||
|
||||
void validate()
|
||||
{
|
||||
trie_.validate();
|
||||
|
49
unittest.cpp
49
unittest.cpp
@ -29,7 +29,7 @@ void fail(Args...args) { error_print(args...);failed__ = true; }
|
||||
|
||||
#define ASSERT_TRUE(x) if (!(x)) fail("Assert fail: expected ", #x, " is true, at " __FILE__ ":",__LINE__)
|
||||
#define ASSERT_EQUAL(a, b) if ((a) != (b)) fail("Assert fail: expected ", (a), " actual " , (b), ", " #a " == " #b ", at " __FILE__ ":",__LINE__)
|
||||
#define ASSERT_NOTEQUAL(a, b) if ((a) != (b)) fail("Assert fail: not expected ", (a), ", " #a " != " #b ", at " __FILE__ ":",__LINE__)
|
||||
#define ASSERT_NOTEQUAL(a, b) if ((a) == (b)) fail("Assert fail: not expected ", (a), ", " #a " != " #b ", at " __FILE__ ":",__LINE__)
|
||||
#define ASSERT_THROW(x) \
|
||||
try \
|
||||
{ \
|
||||
@ -49,14 +49,14 @@ void fail(Args...args) { error_print(args...);failed__ = true; }
|
||||
|
||||
TEST(Rule)
|
||||
{
|
||||
Rule r("/http/");
|
||||
TaggedRule<> r("/http/");
|
||||
r.name("abc");
|
||||
|
||||
// empty handler - fail to validate
|
||||
try
|
||||
{
|
||||
r.validate();
|
||||
fail();
|
||||
fail("empty handler should fail to validate");
|
||||
}
|
||||
catch(runtime_error& e)
|
||||
{
|
||||
@ -73,6 +73,16 @@ TEST(Rule)
|
||||
ASSERT_EQUAL(0, x);
|
||||
r.handle(request(), routing_params());
|
||||
ASSERT_EQUAL(1, x);
|
||||
|
||||
// registering handler with request argument
|
||||
r([&x](const flask::request&){x = 2;return "";});
|
||||
|
||||
r.validate();
|
||||
|
||||
// executing handler
|
||||
ASSERT_EQUAL(1, x);
|
||||
r.handle(request(), routing_params());
|
||||
ASSERT_EQUAL(2, x);
|
||||
}
|
||||
|
||||
TEST(ParameterTagging)
|
||||
@ -211,8 +221,8 @@ TEST(multi_server)
|
||||
{
|
||||
static char buf[2048];
|
||||
Flask app1, app2;
|
||||
app1.route("/")([]{return "A";});
|
||||
app2.route("/")([]{return "B";});
|
||||
FLASK_ROUTE(app1, "/")([]{return "A";});
|
||||
FLASK_ROUTE(app2, "/")([]{return "B";});
|
||||
|
||||
Server<Flask> server1(&app1, 45451);
|
||||
Server<Flask> server2(&app2, 45452);
|
||||
@ -252,9 +262,29 @@ TEST(multi_server)
|
||||
TEST(json_read)
|
||||
{
|
||||
{
|
||||
auto x = json::load("{} 3");
|
||||
const char* json_error_tests[] =
|
||||
{
|
||||
"{} 3", "{{}", "{3}",
|
||||
"3.4.5", "+3", "3-2", "00", "03", "1e3e3", "1e+.3",
|
||||
"nll", "f", "t",
|
||||
"{\"x\":3,}",
|
||||
"{\"x\"}",
|
||||
"{\"x\":3 q}",
|
||||
"{\"x\":[3 4]}",
|
||||
"{\"x\":[\"",
|
||||
"{\"x\":[[], 4],\"y\",}",
|
||||
"{\"x\":[3",
|
||||
"{\"x\":[ null, false, true}",
|
||||
};
|
||||
for(auto s:json_error_tests)
|
||||
{
|
||||
auto x = json::load(s);
|
||||
if (x)
|
||||
fail("should fail to parse");
|
||||
{
|
||||
fail("should fail to parse ", s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto x = json::load(R"({"message":"hello, world"})");
|
||||
@ -270,6 +300,8 @@ TEST(json_read)
|
||||
std::string s = R"({"int":3, "ints" :[1,2,3,4,5] })";
|
||||
auto y = json::load(s);
|
||||
ASSERT_EQUAL(3, y["int"]);
|
||||
ASSERT_EQUAL(3.0, y["int"]);
|
||||
ASSERT_NOTEQUAL(3.01, y["int"]);
|
||||
ASSERT_EQUAL(5, y["ints"].size());
|
||||
ASSERT_EQUAL(1, y["ints"][0]);
|
||||
ASSERT_EQUAL(2, y["ints"][1]);
|
||||
@ -308,7 +340,8 @@ TEST(json_write)
|
||||
|
||||
y["scores"][2][0] = "real";
|
||||
y["scores"][2][1] = false;
|
||||
ASSERT_EQUAL(R"({"scores":[1,"king",["real",false]]})", json::dump(y));
|
||||
y["scores"][2][2] = true;
|
||||
ASSERT_EQUAL(R"({"scores":[1,"king",["real",false,true]]})", json::dump(y));
|
||||
|
||||
y["scores"]["a"]["b"]["c"] = nullptr;
|
||||
ASSERT_EQUAL(R"({"scores":{"a":{"b":{"c":null}}}})", json::dump(y));
|
||||
|
Loading…
Reference in New Issue
Block a user