From 031615ac866cc3c8f1900dd4b4aae2106ad31230 Mon Sep 17 00:00:00 2001 From: ipknHama Date: Thu, 7 Aug 2014 01:18:33 +0900 Subject: source resturcturing + CMake --- tests/unittest.cpp | 484 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 484 insertions(+) create mode 100644 tests/unittest.cpp (limited to 'tests/unittest.cpp') diff --git a/tests/unittest.cpp b/tests/unittest.cpp new file mode 100644 index 0000000..918d027 --- /dev/null +++ b/tests/unittest.cpp @@ -0,0 +1,484 @@ +//#define CROW_ENABLE_LOGGING +#define CROW_ENABLE_DEBUG +#include +#include +#include "routing.h" +#include "utility.h" +#include "crow.h" +#include "json.h" +#include "mustache.h" +using namespace std; +using namespace crow; + +struct Test { Test(); virtual void test() = 0; }; +vector tests; +Test::Test() { tests.push_back(this); } + +bool failed__ = false; +void error_print() +{ + cerr << endl; +} + +template +void error_print(const A& a, Args...args) +{ + cerr< +void fail(Args...args) { error_print(args...);failed__ = true; } + +#define ASSERT_TRUE(x) if (!(x)) fail(__FILE__ ":", __LINE__, ": Assert fail: expected ", #x, " is true, at " __FILE__ ":",__LINE__) +#define ASSERT_EQUAL(a, b) if ((a) != (b)) fail(__FILE__ ":", __LINE__, ": Assert fail: expected ", (a), " actual " , (b), ", " #a " == " #b ", at " __FILE__ ":",__LINE__) +#define ASSERT_NOTEQUAL(a, b) if ((a) == (b)) fail(__FILE__ ":", __LINE__, ": Assert fail: not expected ", (a), ", " #a " != " #b ", at " __FILE__ ":",__LINE__) +#define ASSERT_THROW(x) \ + try \ + { \ + x; \ + fail(__FILE__ ":", __LINE__, ": Assert fail: exception should be thrown"); \ + } \ + catch(std::exception&) \ + { \ + } + + + +#define TEST(x) struct test##x:public Test{void test();}x##_; \ + void test##x::test() +#define DISABLE_TEST(x) struct test##x{void test();}x##_; \ + void test##x::test() + +TEST(Rule) +{ + TaggedRule<> r("/http/"); + r.name("abc"); + + // empty handler - fail to validate + try + { + r.validate(); + fail("empty handler should fail to validate"); + } + catch(runtime_error& e) + { + } + + int x = 0; + + // registering handler + r([&x]{x = 1;return "";}); + + r.validate(); + + response res; + + // executing handler + ASSERT_EQUAL(0, x); + r.handle(request(), res, routing_params()); + ASSERT_EQUAL(1, x); + + // registering handler with request argument + r([&x](const crow::request&){x = 2;return "";}); + + r.validate(); + + // executing handler + ASSERT_EQUAL(1, x); + r.handle(request(), res, routing_params()); + ASSERT_EQUAL(2, x); +} + +TEST(ParameterTagging) +{ + static_assert(black_magic::is_valid(""), "valid url"); + static_assert(!black_magic::is_valid(""), "invalid url"); + static_assert(!black_magic::is_valid("nt>"), "invalid url"); + ASSERT_EQUAL(1, black_magic::get_parameter_tag("")); + ASSERT_EQUAL(2, black_magic::get_parameter_tag("")); + ASSERT_EQUAL(3, black_magic::get_parameter_tag("")); + ASSERT_EQUAL(3, black_magic::get_parameter_tag("")); + ASSERT_EQUAL(4, black_magic::get_parameter_tag("")); + ASSERT_EQUAL(4, black_magic::get_parameter_tag("")); + ASSERT_EQUAL(5, black_magic::get_parameter_tag("")); + ASSERT_EQUAL(6*6+6+1, black_magic::get_parameter_tag("")); + ASSERT_EQUAL(6*6+6+2, black_magic::get_parameter_tag("")); + ASSERT_EQUAL(6*6+6*3+2, black_magic::get_parameter_tag("")); + + // url definition parsed in compile time, build into *one number*, and given to template argument + static_assert(std::is_same, black_magic::arguments<6*6+6*3+2>::type>::value, "tag to type container"); +} + +TEST(RoutingTest) +{ + Crow app; + int A{}; + uint32_t B{}; + double C{}; + string D{}; + string E{}; + + CROW_ROUTE(app, "/0/") + ([&](uint32_t b){ + B = b; + return "OK"; + }); + + CROW_ROUTE(app, "/1//") + ([&](int a, uint32_t b){ + A = a; B = b; + return "OK"; + }); + + CROW_ROUTE(app, "/4////") + ([&](int a, uint32_t b, double c, string d){ + A = a; B = b; C = c; D = d; + return "OK"; + }); + + CROW_ROUTE(app, "/5/////") + ([&](int a, uint32_t b, double c, string d, string e){ + A = a; B = b; C = c; D = d; E = e; + return "OK"; + }); + + app.validate(); + //app.debug_print(); + { + request req; + response res; + + req.url = "/-1"; + + app.handle(req, res); + + ASSERT_EQUAL(404, res.code); + } + + { + request req; + response res; + + req.url = "/0/1001999"; + + app.handle(req, res); + + ASSERT_EQUAL(200, res.code); + + ASSERT_EQUAL(1001999, B); + } + + { + request req; + response res; + + req.url = "/1/-100/1999"; + + app.handle(req, res); + + ASSERT_EQUAL(200, res.code); + + ASSERT_EQUAL(-100, A); + ASSERT_EQUAL(1999, B); + } + { + request req; + response res; + + req.url = "/4/5000/3/-2.71828/hellhere"; + req.headers["TestHeader"] = "Value"; + + app.handle(req, res); + + ASSERT_EQUAL(200, res.code); + + ASSERT_EQUAL(5000, A); + ASSERT_EQUAL(3, B); + ASSERT_EQUAL(-2.71828, C); + ASSERT_EQUAL("hellhere", D); + } + { + request req; + response res; + + req.url = "/5/-5/999/3.141592/hello_there/a/b/c/d"; + req.headers["TestHeader"] = "Value"; + + app.handle(req, res); + + ASSERT_EQUAL(200, res.code); + + ASSERT_EQUAL(-5, A); + ASSERT_EQUAL(999, B); + ASSERT_EQUAL(3.141592, C); + ASSERT_EQUAL("hello_there", D); + ASSERT_EQUAL("a/b/c/d", E); + } +} + +TEST(simple_response_routing_params) +{ + ASSERT_EQUAL(100, response(100).code); + ASSERT_EQUAL(200, response("Hello there").code); + ASSERT_EQUAL(500, response(500, "Internal Error?").code); + + routing_params rp; + rp.int_params.push_back(1); + rp.int_params.push_back(5); + rp.uint_params.push_back(2); + rp.double_params.push_back(3); + rp.string_params.push_back("hello"); + ASSERT_EQUAL(1, rp.get(0)); + ASSERT_EQUAL(5, rp.get(1)); + ASSERT_EQUAL(2, rp.get(0)); + ASSERT_EQUAL(3, rp.get(0)); + ASSERT_EQUAL("hello", rp.get(0)); +} + +TEST(handler_with_response) +{ + Crow app; + CROW_ROUTE(app, "/")([](const crow::request&, crow::response&) + { + }); +} + +TEST(server_handling_error_request) +{ + static char buf[2048]; + Crow app; + CROW_ROUTE(app, "/")([]{return "A";}); + Server server(&app, 45451); + auto _ = async(launch::async, [&]{server.run();}); + std::string sendmsg = "POX"; + asio::io_service is; + { + asio::ip::tcp::socket c(is); + c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string("127.0.0.1"), 45451)); + + + c.send(asio::buffer(sendmsg)); + + try + { + c.receive(asio::buffer(buf, 2048)); + fail(); + } + catch(std::exception& e) + { + //std::cerr << e.what() << std::endl; + } + } + server.stop(); +} + +TEST(multi_server) +{ + static char buf[2048]; + Crow app1, app2; + CROW_ROUTE(app1, "/")([]{return "A";}); + CROW_ROUTE(app2, "/")([]{return "B";}); + + Server server1(&app1, 45451); + Server server2(&app2, 45452); + + auto _ = async(launch::async, [&]{server1.run();}); + auto _2 = async(launch::async, [&]{server2.run();}); + + std::string sendmsg = "POST /\r\nContent-Length:3\r\nX-HeaderTest: 123\r\n\r\nA=B\r\n"; + asio::io_service is; + { + asio::ip::tcp::socket c(is); + c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string("127.0.0.1"), 45451)); + + + c.send(asio::buffer(sendmsg)); + + size_t recved = c.receive(asio::buffer(buf, 2048)); + ASSERT_EQUAL('A', buf[recved-1]); + } + + { + asio::ip::tcp::socket c(is); + c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string("127.0.0.1"), 45452)); + + for(auto ch:sendmsg) + { + char buf[1] = {ch}; + c.send(asio::buffer(buf)); + } + + size_t recved = c.receive(asio::buffer(buf, 2048)); + ASSERT_EQUAL('B', buf[recved-1]); + } + + server1.stop(); + server2.stop(); +} + +TEST(json_read) +{ + { + 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 ", s); + return; + } + } + } + + auto x = json::load(R"({"message":"hello, world"})"); + if (!x) + fail("fail to parse"); + ASSERT_EQUAL("hello, world", x["message"]); + ASSERT_EQUAL(1, x.size()); + ASSERT_EQUAL(false, x.has("mess")); + ASSERT_THROW(x["mess"]); + ASSERT_THROW(3 == x["message"]); + ASSERT_EQUAL(12, x["message"].size()); + + 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]); + ASSERT_EQUAL(3, y["ints"][2]); + ASSERT_EQUAL(4, y["ints"][3]); + ASSERT_EQUAL(5, y["ints"][4]); + ASSERT_EQUAL(1u, y["ints"][0]); + ASSERT_EQUAL(1.f, y["ints"][0]); + + int q = (int)y["ints"][1]; + ASSERT_EQUAL(2, q); + q = y["ints"][2].i(); + ASSERT_EQUAL(3, q); + +} + +TEST(json_read_unescaping) +{ + { + auto x = json::load(R"({"data":"\ud55c\n\t\r"})"); + if (!x) + { + fail("fail to parse"); + return; + } + ASSERT_EQUAL(6, x["data"].size()); + ASSERT_EQUAL("한\n\t\r", x["data"]); + } + { + // multiple r_string instance + auto x = json::load(R"({"data":"\ud55c\n\t\r"})"); + auto a = x["data"].s(); + auto b = x["data"].s(); + ASSERT_EQUAL(6, a.size()); + ASSERT_EQUAL(6, b.size()); + ASSERT_EQUAL(6, x["data"].size()); + } +} + +TEST(json_write) +{ + json::wvalue x; + x["message"] = "hello world"; + ASSERT_EQUAL(R"({"message":"hello world"})", json::dump(x)); + x["message"] = std::string("string value"); + ASSERT_EQUAL(R"({"message":"string value"})", json::dump(x)); + x["message"]["x"] = 3; + ASSERT_EQUAL(R"({"message":{"x":3}})", json::dump(x)); + x["message"]["y"] = 5; + ASSERT_TRUE(R"({"message":{"x":3,"y":5}})" == json::dump(x) || R"({"message":{"y":5,"x":3}})" == json::dump(x)); + x["message"] = 5.5; + ASSERT_EQUAL(R"({"message":5.5})", json::dump(x)); + + json::wvalue y; + y["scores"][0] = 1; + y["scores"][1] = "king"; + y["scores"][2] = 3.5; + ASSERT_EQUAL(R"({"scores":[1,"king",3.5]})", json::dump(y)); + + y["scores"][2][0] = "real"; + y["scores"][2][1] = false; + 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)); +} + +TEST(template_basic) +{ + auto t = crow::mustache::compile(R"---(attack of {{name}})---"); + crow::mustache::context ctx; + ctx["name"] = "killer tomatoes"; + auto result = t.render(ctx); + ASSERT_EQUAL("attack of killer tomatoes", result); + //crow::mustache::load("basic.mustache"); +} + +TEST(template_load) +{ + crow::mustache::set_base("."); + ofstream("test.mustache") << R"---(attack of {{name}})---"; + auto t = crow::mustache::load("test.mustache"); + crow::mustache::context ctx; + ctx["name"] = "killer tomatoes"; + auto result = t.render(ctx); + ASSERT_EQUAL("attack of killer tomatoes", result); + unlink("test.mustache"); +} + +int testmain() +{ + bool failed = false; + for(auto t:tests) + { + failed__ = false; + try + { + //cerr << typeid(*t).name() << endl; + t->test(); + } + catch(std::exception& e) + { + fail(e.what()); + } + if (failed__) + { + cerr << "F"; + cerr << '\t' << typeid(*t).name() << endl; + failed = true; + } + else + cerr << "."; + } + cerr<