unittest.cpp 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228
  1. //#define CROW_ENABLE_LOGGING
  2. #define CROW_LOG_LEVEL 0
  3. #define CROW_ENABLE_DEBUG
  4. #include <iostream>
  5. #include <sstream>
  6. #include <vector>
  7. #include "crow.h"
  8. using namespace std;
  9. using namespace crow;
  10. struct Test { Test(); virtual void test() = 0; };
  11. vector<Test*> tests;
  12. Test::Test() { tests.push_back(this); }
  13. bool failed__ = false;
  14. void error_print()
  15. {
  16. cerr << endl;
  17. }
  18. template <typename A, typename ...Args>
  19. void error_print(const A& a, Args...args)
  20. {
  21. cerr<<a;
  22. error_print(args...);
  23. }
  24. template <typename ...Args>
  25. void fail(Args...args) { error_print(args...);failed__ = true; }
  26. #define ASSERT_TRUE(x) if (!(x)) fail(__FILE__ ":", __LINE__, ": Assert fail: expected ", #x, " is true, at " __FILE__ ":",__LINE__)
  27. #define ASSERT_EQUAL(a, b) if ((a) != (b)) fail(__FILE__ ":", __LINE__, ": Assert fail: expected ", (a), " actual ", (b), ", " #a " == " #b ", at " __FILE__ ":",__LINE__)
  28. #define ASSERT_NOTEQUAL(a, b) if ((a) == (b)) fail(__FILE__ ":", __LINE__, ": Assert fail: not expected ", (a), ", " #a " != " #b ", at " __FILE__ ":",__LINE__)
  29. #define ASSERT_THROW(x) \
  30. try \
  31. { \
  32. x; \
  33. fail(__FILE__ ":", __LINE__, ": Assert fail: exception should be thrown"); \
  34. } \
  35. catch(std::exception&) \
  36. { \
  37. }
  38. #define TEST(x) struct test##x:public Test{void test();}x##_; \
  39. void test##x::test()
  40. #define DISABLE_TEST(x) struct test##x{void test();}x##_; \
  41. void test##x::test()
  42. #define LOCALHOST_ADDRESS "127.0.0.1"
  43. TEST(Rule)
  44. {
  45. TaggedRule<> r("/http/");
  46. r.name("abc");
  47. // empty handler - fail to validate
  48. try
  49. {
  50. r.validate();
  51. fail("empty handler should fail to validate");
  52. }
  53. catch(runtime_error& e)
  54. {
  55. }
  56. int x = 0;
  57. // registering handler
  58. r([&x]{x = 1;return "";});
  59. r.validate();
  60. response res;
  61. // executing handler
  62. ASSERT_EQUAL(0, x);
  63. r.handle(request(), res, routing_params());
  64. ASSERT_EQUAL(1, x);
  65. // registering handler with request argument
  66. r([&x](const crow::request&){x = 2;return "";});
  67. r.validate();
  68. // executing handler
  69. ASSERT_EQUAL(1, x);
  70. r.handle(request(), res, routing_params());
  71. ASSERT_EQUAL(2, x);
  72. }
  73. TEST(ParameterTagging)
  74. {
  75. static_assert(black_magic::is_valid("<int><int><int>"), "valid url");
  76. static_assert(!black_magic::is_valid("<int><int<<int>"), "invalid url");
  77. static_assert(!black_magic::is_valid("nt>"), "invalid url");
  78. ASSERT_EQUAL(1, black_magic::get_parameter_tag("<int>"));
  79. ASSERT_EQUAL(2, black_magic::get_parameter_tag("<uint>"));
  80. ASSERT_EQUAL(3, black_magic::get_parameter_tag("<float>"));
  81. ASSERT_EQUAL(3, black_magic::get_parameter_tag("<double>"));
  82. ASSERT_EQUAL(4, black_magic::get_parameter_tag("<str>"));
  83. ASSERT_EQUAL(4, black_magic::get_parameter_tag("<string>"));
  84. ASSERT_EQUAL(5, black_magic::get_parameter_tag("<path>"));
  85. ASSERT_EQUAL(6*6+6+1, black_magic::get_parameter_tag("<int><int><int>"));
  86. ASSERT_EQUAL(6*6+6+2, black_magic::get_parameter_tag("<uint><int><int>"));
  87. ASSERT_EQUAL(6*6+6*3+2, black_magic::get_parameter_tag("<uint><double><int>"));
  88. // url definition parsed in compile time, build into *one number*, and given to template argument
  89. static_assert(std::is_same<black_magic::S<uint64_t, double, int64_t>, black_magic::arguments<6*6+6*3+2>::type>::value, "tag to type container");
  90. }
  91. TEST(PathRouting)
  92. {
  93. SimpleApp app;
  94. CROW_ROUTE(app, "/file")
  95. ([]{
  96. return "file";
  97. });
  98. CROW_ROUTE(app, "/path/")
  99. ([]{
  100. return "path";
  101. });
  102. app.validate();
  103. {
  104. request req;
  105. response res;
  106. req.url = "/file";
  107. app.handle(req, res);
  108. ASSERT_EQUAL(200, res.code);
  109. }
  110. {
  111. request req;
  112. response res;
  113. req.url = "/file/";
  114. app.handle(req, res);
  115. ASSERT_EQUAL(404, res.code);
  116. }
  117. {
  118. request req;
  119. response res;
  120. req.url = "/path";
  121. app.handle(req, res);
  122. ASSERT_NOTEQUAL(404, res.code);
  123. }
  124. {
  125. request req;
  126. response res;
  127. req.url = "/path/";
  128. app.handle(req, res);
  129. ASSERT_EQUAL(200, res.code);
  130. }
  131. }
  132. TEST(RoutingTest)
  133. {
  134. SimpleApp app;
  135. int A{};
  136. uint32_t B{};
  137. double C{};
  138. string D{};
  139. string E{};
  140. CROW_ROUTE(app, "/0/<uint>")
  141. ([&](uint32_t b){
  142. B = b;
  143. return "OK";
  144. });
  145. CROW_ROUTE(app, "/1/<int>/<uint>")
  146. ([&](int a, uint32_t b){
  147. A = a; B = b;
  148. return "OK";
  149. });
  150. CROW_ROUTE(app, "/4/<int>/<uint>/<double>/<string>")
  151. ([&](int a, uint32_t b, double c, string d){
  152. A = a; B = b; C = c; D = d;
  153. return "OK";
  154. });
  155. CROW_ROUTE(app, "/5/<int>/<uint>/<double>/<string>/<path>")
  156. ([&](int a, uint32_t b, double c, string d, string e){
  157. A = a; B = b; C = c; D = d; E = e;
  158. return "OK";
  159. });
  160. app.validate();
  161. //app.debug_print();
  162. {
  163. request req;
  164. response res;
  165. req.url = "/-1";
  166. app.handle(req, res);
  167. ASSERT_EQUAL(404, res.code);
  168. }
  169. {
  170. request req;
  171. response res;
  172. req.url = "/0/1001999";
  173. app.handle(req, res);
  174. ASSERT_EQUAL(200, res.code);
  175. ASSERT_EQUAL(1001999, B);
  176. }
  177. {
  178. request req;
  179. response res;
  180. req.url = "/1/-100/1999";
  181. app.handle(req, res);
  182. ASSERT_EQUAL(200, res.code);
  183. ASSERT_EQUAL(-100, A);
  184. ASSERT_EQUAL(1999, B);
  185. }
  186. {
  187. request req;
  188. response res;
  189. req.url = "/4/5000/3/-2.71828/hellhere";
  190. req.add_header("TestHeader", "Value");
  191. app.handle(req, res);
  192. ASSERT_EQUAL(200, res.code);
  193. ASSERT_EQUAL(5000, A);
  194. ASSERT_EQUAL(3, B);
  195. ASSERT_EQUAL(-2.71828, C);
  196. ASSERT_EQUAL("hellhere", D);
  197. }
  198. {
  199. request req;
  200. response res;
  201. req.url = "/5/-5/999/3.141592/hello_there/a/b/c/d";
  202. req.add_header("TestHeader", "Value");
  203. app.handle(req, res);
  204. ASSERT_EQUAL(200, res.code);
  205. ASSERT_EQUAL(-5, A);
  206. ASSERT_EQUAL(999, B);
  207. ASSERT_EQUAL(3.141592, C);
  208. ASSERT_EQUAL("hello_there", D);
  209. ASSERT_EQUAL("a/b/c/d", E);
  210. }
  211. }
  212. TEST(simple_response_routing_params)
  213. {
  214. ASSERT_EQUAL(100, response(100).code);
  215. ASSERT_EQUAL(200, response("Hello there").code);
  216. ASSERT_EQUAL(500, response(500, "Internal Error?").code);
  217. routing_params rp;
  218. rp.int_params.push_back(1);
  219. rp.int_params.push_back(5);
  220. rp.uint_params.push_back(2);
  221. rp.double_params.push_back(3);
  222. rp.string_params.push_back("hello");
  223. ASSERT_EQUAL(1, rp.get<int64_t>(0));
  224. ASSERT_EQUAL(5, rp.get<int64_t>(1));
  225. ASSERT_EQUAL(2, rp.get<uint64_t>(0));
  226. ASSERT_EQUAL(3, rp.get<double>(0));
  227. ASSERT_EQUAL("hello", rp.get<string>(0));
  228. }
  229. TEST(handler_with_response)
  230. {
  231. SimpleApp app;
  232. CROW_ROUTE(app, "/")([](const crow::request&, crow::response&)
  233. {
  234. });
  235. }
  236. TEST(http_method)
  237. {
  238. SimpleApp app;
  239. CROW_ROUTE(app, "/")
  240. .methods("POST"_method, "GET"_method)
  241. ([](const request& req){
  242. if (req.method == "GET"_method)
  243. return "2";
  244. else
  245. return "1";
  246. });
  247. CROW_ROUTE(app, "/get_only")
  248. .methods("GET"_method)
  249. ([](const request& /*req*/){
  250. return "get";
  251. });
  252. CROW_ROUTE(app, "/post_only")
  253. .methods("POST"_method)
  254. ([](const request& /*req*/){
  255. return "post";
  256. });
  257. CROW_ROUTE(app, "/patch_only")
  258. .methods("PATCH"_method)
  259. ([](const request& /*req*/){
  260. return "patch";
  261. });
  262. CROW_ROUTE(app, "/purge_only")
  263. .methods("PURGE"_method)
  264. ([](const request& /*req*/){
  265. return "purge";
  266. });
  267. app.validate();
  268. app.debug_print();
  269. // cannot have multiple handlers for the same url
  270. //CROW_ROUTE(app, "/")
  271. //.methods("GET"_method)
  272. //([]{ return "2"; });
  273. {
  274. request req;
  275. response res;
  276. req.url = "/";
  277. app.handle(req, res);
  278. ASSERT_EQUAL("2", res.body);
  279. }
  280. {
  281. request req;
  282. response res;
  283. req.url = "/";
  284. req.method = "POST"_method;
  285. app.handle(req, res);
  286. ASSERT_EQUAL("1", res.body);
  287. }
  288. {
  289. request req;
  290. response res;
  291. req.url = "/get_only";
  292. app.handle(req, res);
  293. ASSERT_EQUAL("get", res.body);
  294. }
  295. {
  296. request req;
  297. response res;
  298. req.url = "/patch_only";
  299. req.method = "PATCH"_method;
  300. app.handle(req, res);
  301. ASSERT_EQUAL("patch", res.body);
  302. }
  303. {
  304. request req;
  305. response res;
  306. req.url = "/purge_only";
  307. req.method = "PURGE"_method;
  308. app.handle(req, res);
  309. ASSERT_EQUAL("purge", res.body);
  310. }
  311. {
  312. request req;
  313. response res;
  314. req.url = "/get_only";
  315. req.method = "POST"_method;
  316. app.handle(req, res);
  317. ASSERT_NOTEQUAL("get", res.body);
  318. }
  319. }
  320. TEST(server_handling_error_request)
  321. {
  322. static char buf[2048];
  323. SimpleApp app;
  324. CROW_ROUTE(app, "/")([]{return "A";});
  325. //Server<SimpleApp> server(&app, LOCALHOST_ADDRESS, 45451);
  326. //auto _ = async(launch::async, [&]{server.run();});
  327. auto _ = async(launch::async, [&]{app.bindaddr(LOCALHOST_ADDRESS).port(45451).run();});
  328. app.wait_for_server_start();
  329. std::string sendmsg = "POX";
  330. asio::io_service is;
  331. {
  332. asio::ip::tcp::socket c(is);
  333. c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
  334. c.send(asio::buffer(sendmsg));
  335. try
  336. {
  337. c.receive(asio::buffer(buf, 2048));
  338. fail();
  339. }
  340. catch(std::exception& e)
  341. {
  342. //std::cerr << e.what() << std::endl;
  343. }
  344. }
  345. app.stop();
  346. }
  347. TEST(multi_server)
  348. {
  349. static char buf[2048];
  350. SimpleApp app1, app2;
  351. CROW_ROUTE(app1, "/").methods("GET"_method, "POST"_method)([]{return "A";});
  352. CROW_ROUTE(app2, "/").methods("GET"_method, "POST"_method)([]{return "B";});
  353. //Server<SimpleApp> server1(&app1, LOCALHOST_ADDRESS, 45451);
  354. //Server<SimpleApp> server2(&app2, LOCALHOST_ADDRESS, 45452);
  355. //auto _ = async(launch::async, [&]{server1.run();});
  356. //auto _2 = async(launch::async, [&]{server2.run();});
  357. auto _ = async(launch::async, [&]{app1.bindaddr(LOCALHOST_ADDRESS).port(45451).run();});
  358. auto _2 = async(launch::async, [&]{app2.bindaddr(LOCALHOST_ADDRESS).port(45452).run();});
  359. app1.wait_for_server_start();
  360. app2.wait_for_server_start();
  361. std::string sendmsg = "POST /\r\nContent-Length:3\r\nX-HeaderTest: 123\r\n\r\nA=B\r\n";
  362. asio::io_service is;
  363. {
  364. asio::ip::tcp::socket c(is);
  365. c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
  366. c.send(asio::buffer(sendmsg));
  367. size_t recved = c.receive(asio::buffer(buf, 2048));
  368. ASSERT_EQUAL('A', buf[recved-1]);
  369. }
  370. {
  371. asio::ip::tcp::socket c(is);
  372. c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string(LOCALHOST_ADDRESS), 45452));
  373. for(auto ch:sendmsg)
  374. {
  375. char buf[1] = {ch};
  376. c.send(asio::buffer(buf));
  377. }
  378. size_t recved = c.receive(asio::buffer(buf, 2048));
  379. ASSERT_EQUAL('B', buf[recved-1]);
  380. }
  381. app1.stop();
  382. app2.stop();
  383. }
  384. TEST(json_read)
  385. {
  386. {
  387. const char* json_error_tests[] =
  388. {
  389. "{} 3", "{{}", "{3}",
  390. "3.4.5", "+3", "3-2", "00", "03", "1e3e3", "1e+.3",
  391. "nll", "f", "t",
  392. "{\"x\":3,}",
  393. "{\"x\"}",
  394. "{\"x\":3 q}",
  395. "{\"x\":[3 4]}",
  396. "{\"x\":[\"",
  397. "{\"x\":[[], 4],\"y\",}",
  398. "{\"x\":[3",
  399. "{\"x\":[ null, false, true}",
  400. };
  401. for(auto s:json_error_tests)
  402. {
  403. auto x = json::load(s);
  404. if (x)
  405. {
  406. fail("should fail to parse ", s);
  407. return;
  408. }
  409. }
  410. }
  411. auto x = json::load(R"({"message":"hello, world"})");
  412. if (!x)
  413. fail("fail to parse");
  414. ASSERT_EQUAL("hello, world", x["message"]);
  415. ASSERT_EQUAL(1, x.size());
  416. ASSERT_EQUAL(false, x.has("mess"));
  417. ASSERT_THROW(x["mess"]);
  418. // TODO returning false is better than exception
  419. //ASSERT_THROW(3 == x["message"]);
  420. ASSERT_EQUAL(12, x["message"].size());
  421. std::string s = R"({"int":3, "ints" :[1,2,3,4,5], "bigint":1234567890 })";
  422. auto y = json::load(s);
  423. ASSERT_EQUAL(3, y["int"]);
  424. ASSERT_EQUAL(3.0, y["int"]);
  425. ASSERT_NOTEQUAL(3.01, y["int"]);
  426. ASSERT_EQUAL(5, y["ints"].size());
  427. ASSERT_EQUAL(1, y["ints"][0]);
  428. ASSERT_EQUAL(2, y["ints"][1]);
  429. ASSERT_EQUAL(3, y["ints"][2]);
  430. ASSERT_EQUAL(4, y["ints"][3]);
  431. ASSERT_EQUAL(5, y["ints"][4]);
  432. ASSERT_EQUAL(1u, y["ints"][0]);
  433. ASSERT_EQUAL(1.f, y["ints"][0]);
  434. int q = (int)y["ints"][1];
  435. ASSERT_EQUAL(2, q);
  436. q = y["ints"][2].i();
  437. ASSERT_EQUAL(3, q);
  438. ASSERT_EQUAL(1234567890, y["bigint"]);
  439. std::string s2 = R"({"bools":[true, false], "doubles":[1.2, -3.4]})";
  440. auto z = json::load(s2);
  441. ASSERT_EQUAL(2, z["bools"].size());
  442. ASSERT_EQUAL(2, z["doubles"].size());
  443. ASSERT_EQUAL(true, z["bools"][0].b());
  444. ASSERT_EQUAL(false, z["bools"][1].b());
  445. ASSERT_EQUAL(1.2, z["doubles"][0].d());
  446. ASSERT_EQUAL(-3.4, z["doubles"][1].d());
  447. std::string s3 = R"({"uint64": 18446744073709551615})";
  448. auto z1 = json::load(s3);
  449. ASSERT_EQUAL(18446744073709551615ull, z1["uint64"].u());
  450. std::ostringstream os;
  451. os << z1["uint64"];
  452. ASSERT_EQUAL("18446744073709551615", os.str());
  453. }
  454. TEST(json_read_real)
  455. {
  456. vector<std::string> v{"0.036303908355795146", "0.18320417789757412",
  457. "0.05319940476190476", "0.15224702380952382", "0", "0.3296201145552561",
  458. "0.47921580188679247", "0.05873511904761905", "0.1577827380952381",
  459. "0.4996841307277628", "0.6425412735849056", "0.052113095238095236",
  460. "0.12830357142857143", "0.7871041105121294", "0.954220013477089",
  461. "0.05869047619047619", "0.1625", "0.8144794474393531",
  462. "0.9721613881401617", "0.1399404761904762", "0.24470238095238095",
  463. "0.04527459568733154", "0.2096950808625337", "0.35267857142857145",
  464. "0.42791666666666667", "0.855731974393531", "0.9352467991913747",
  465. "0.3816220238095238", "0.4282886904761905", "0.39414167789757415",
  466. "0.5316079851752021", "0.3809375", "0.4571279761904762",
  467. "0.03522995283018868", "0.1915641846361186", "0.6164136904761904",
  468. "0.7192708333333333", "0.05675117924528302", "0.21308541105121293",
  469. "0.7045386904761904", "0.8016815476190476"};
  470. for(auto x:v)
  471. {
  472. CROW_LOG_DEBUG << x;
  473. ASSERT_EQUAL(json::load(x).d(), boost::lexical_cast<double>(x));
  474. }
  475. auto ret = json::load(R"---({"balloons":[{"mode":"ellipse","left":0.036303908355795146,"right":0.18320417789757412,"top":0.05319940476190476,"bottom":0.15224702380952382,"index":"0"},{"mode":"ellipse","left":0.3296201145552561,"right":0.47921580188679247,"top":0.05873511904761905,"bottom":0.1577827380952381,"index":"1"},{"mode":"ellipse","left":0.4996841307277628,"right":0.6425412735849056,"top":0.052113095238095236,"bottom":0.12830357142857143,"index":"2"},{"mode":"ellipse","left":0.7871041105121294,"right":0.954220013477089,"top":0.05869047619047619,"bottom":0.1625,"index":"3"},{"mode":"ellipse","left":0.8144794474393531,"right":0.9721613881401617,"top":0.1399404761904762,"bottom":0.24470238095238095,"index":"4"},{"mode":"ellipse","left":0.04527459568733154,"right":0.2096950808625337,"top":0.35267857142857145,"bottom":0.42791666666666667,"index":"5"},{"mode":"ellipse","left":0.855731974393531,"right":0.9352467991913747,"top":0.3816220238095238,"bottom":0.4282886904761905,"index":"6"},{"mode":"ellipse","left":0.39414167789757415,"right":0.5316079851752021,"top":0.3809375,"bottom":0.4571279761904762,"index":"7"},{"mode":"ellipse","left":0.03522995283018868,"right":0.1915641846361186,"top":0.6164136904761904,"bottom":0.7192708333333333,"index":"8"},{"mode":"ellipse","left":0.05675117924528302,"right":0.21308541105121293,"top":0.7045386904761904,"bottom":0.8016815476190476,"index":"9"}]})---");
  476. ASSERT_TRUE(ret);
  477. }
  478. TEST(json_read_unescaping)
  479. {
  480. {
  481. auto x = json::load(R"({"data":"\ud55c\n\t\r"})");
  482. if (!x)
  483. {
  484. fail("fail to parse");
  485. return;
  486. }
  487. ASSERT_EQUAL(6, x["data"].size());
  488. ASSERT_EQUAL("한\n\t\r", x["data"]);
  489. }
  490. {
  491. // multiple r_string instance
  492. auto x = json::load(R"({"data":"\ud55c\n\t\r"})");
  493. auto a = x["data"].s();
  494. auto b = x["data"].s();
  495. ASSERT_EQUAL(6, a.size());
  496. ASSERT_EQUAL(6, b.size());
  497. ASSERT_EQUAL(6, x["data"].size());
  498. }
  499. }
  500. TEST(json_write)
  501. {
  502. json::wvalue x;
  503. x["message"] = "hello world";
  504. ASSERT_EQUAL(R"({"message":"hello world"})", json::dump(x));
  505. x["message"] = std::string("string value");
  506. ASSERT_EQUAL(R"({"message":"string value"})", json::dump(x));
  507. x["message"]["x"] = 3;
  508. ASSERT_EQUAL(R"({"message":{"x":3}})", json::dump(x));
  509. x["message"]["y"] = 5;
  510. ASSERT_TRUE(R"({"message":{"x":3,"y":5}})" == json::dump(x) || R"({"message":{"y":5,"x":3}})" == json::dump(x));
  511. x["message"] = 5.5;
  512. ASSERT_EQUAL(R"({"message":5.5})", json::dump(x));
  513. x["message"] = 1234567890;
  514. ASSERT_EQUAL(R"({"message":1234567890})", json::dump(x));
  515. json::wvalue y;
  516. y["scores"][0] = 1;
  517. y["scores"][1] = "king";
  518. y["scores"][2] = 3.5;
  519. ASSERT_EQUAL(R"({"scores":[1,"king",3.5]})", json::dump(y));
  520. y["scores"][2][0] = "real";
  521. y["scores"][2][1] = false;
  522. y["scores"][2][2] = true;
  523. ASSERT_EQUAL(R"({"scores":[1,"king",["real",false,true]]})", json::dump(y));
  524. y["scores"]["a"]["b"]["c"] = nullptr;
  525. ASSERT_EQUAL(R"({"scores":{"a":{"b":{"c":null}}}})", json::dump(y));
  526. y["scores"] = std::vector<int>{1,2,3};
  527. ASSERT_EQUAL(R"({"scores":[1,2,3]})", json::dump(y));
  528. }
  529. TEST(json_copy_r_to_w_to_r)
  530. {
  531. json::rvalue r = json::load(R"({"smallint":2,"bigint":2147483647,"fp":23.43,"fpsc":2.343e1,"str":"a string","trueval":true,"falseval":false,"nullval":null,"listval":[1,2,"foo","bar"],"obj":{"member":23,"other":"baz"}})");
  532. json::wvalue w{r};
  533. json::rvalue x = json::load(json::dump(w)); // why no copy-ctor wvalue -> rvalue?
  534. ASSERT_EQUAL(2, x["smallint"]);
  535. ASSERT_EQUAL(2147483647, x["bigint"]);
  536. ASSERT_EQUAL(23.43, x["fp"]);
  537. ASSERT_EQUAL(23.43, x["fpsc"]);
  538. ASSERT_EQUAL("a string", x["str"]);
  539. ASSERT_TRUE(true == x["trueval"].b());
  540. ASSERT_TRUE(false == x["falseval"].b());
  541. ASSERT_TRUE(json::type::Null == x["nullval"].t());
  542. ASSERT_EQUAL(4u, x["listval"].size());
  543. ASSERT_EQUAL(1, x["listval"][0]);
  544. ASSERT_EQUAL(2, x["listval"][1]);
  545. ASSERT_EQUAL("foo", x["listval"][2]);
  546. ASSERT_EQUAL("bar", x["listval"][3]);
  547. ASSERT_EQUAL(23, x["obj"]["member"]);
  548. ASSERT_EQUAL("member", x["obj"]["member"].key());
  549. ASSERT_EQUAL("baz", x["obj"]["other"]);
  550. ASSERT_EQUAL("other", x["obj"]["other"].key());
  551. }
  552. TEST(template_basic)
  553. {
  554. auto t = crow::mustache::compile(R"---(attack of {{name}})---");
  555. crow::mustache::context ctx;
  556. ctx["name"] = "killer tomatoes";
  557. auto result = t.render(ctx);
  558. ASSERT_EQUAL("attack of killer tomatoes", result);
  559. //crow::mustache::load("basic.mustache");
  560. }
  561. TEST(template_load)
  562. {
  563. crow::mustache::set_base(".");
  564. ofstream("test.mustache") << R"---(attack of {{name}})---";
  565. auto t = crow::mustache::load("test.mustache");
  566. crow::mustache::context ctx;
  567. ctx["name"] = "killer tomatoes";
  568. auto result = t.render(ctx);
  569. ASSERT_EQUAL("attack of killer tomatoes", result);
  570. unlink("test.mustache");
  571. }
  572. int testmain()
  573. {
  574. bool failed = false;
  575. for(auto t:tests)
  576. {
  577. failed__ = false;
  578. try
  579. {
  580. //cerr << typeid(*t).name() << endl;
  581. t->test();
  582. }
  583. catch(std::exception& e)
  584. {
  585. fail(e.what());
  586. }
  587. if (failed__)
  588. {
  589. cerr << "F";
  590. cerr << '\t' << typeid(*t).name() << endl;
  591. failed = true;
  592. }
  593. else
  594. cerr << ".";
  595. }
  596. cerr<<endl;
  597. return failed ? -1 : 0;
  598. }
  599. TEST(black_magic)
  600. {
  601. using namespace black_magic;
  602. static_assert(std::is_same<void, last_element_type<int, char, void>::type>::value, "last_element_type");
  603. static_assert(std::is_same<char, pop_back<int, char, void>::rebind<last_element_type>::type>::value, "pop_back");
  604. static_assert(std::is_same<int, pop_back<int, char, void>::rebind<pop_back>::rebind<last_element_type>::type>::value, "pop_back");
  605. }
  606. struct NullMiddleware
  607. {
  608. struct context {};
  609. template <typename AllContext>
  610. void before_handle(request&, response&, context&, AllContext&)
  611. {}
  612. template <typename AllContext>
  613. void after_handle(request&, response&, context&, AllContext&)
  614. {}
  615. };
  616. struct NullSimpleMiddleware
  617. {
  618. struct context {};
  619. void before_handle(request& /*req*/, response& /*res*/, context& /*ctx*/)
  620. {}
  621. void after_handle(request& /*req*/, response& /*res*/, context& /*ctx*/)
  622. {}
  623. };
  624. TEST(middleware_simple)
  625. {
  626. App<NullMiddleware, NullSimpleMiddleware> app;
  627. decltype(app)::server_t server(&app, LOCALHOST_ADDRESS, 45451);
  628. CROW_ROUTE(app, "/")([&](const crow::request& req)
  629. {
  630. app.get_context<NullMiddleware>(req);
  631. app.get_context<NullSimpleMiddleware>(req);
  632. return "";
  633. });
  634. }
  635. struct IntSettingMiddleware
  636. {
  637. struct context { int val; };
  638. template <typename AllContext>
  639. void before_handle(request&, response&, context& ctx, AllContext& )
  640. {
  641. ctx.val = 1;
  642. }
  643. template <typename AllContext>
  644. void after_handle(request&, response&, context& ctx, AllContext& )
  645. {
  646. ctx.val = 2;
  647. }
  648. };
  649. std::vector<std::string> test_middleware_context_vector;
  650. struct FirstMW
  651. {
  652. struct context
  653. {
  654. std::vector<string> v;
  655. };
  656. void before_handle(request& /*req*/, response& /*res*/, context& ctx)
  657. {
  658. ctx.v.push_back("1 before");
  659. }
  660. void after_handle(request& /*req*/, response& /*res*/, context& ctx)
  661. {
  662. ctx.v.push_back("1 after");
  663. test_middleware_context_vector = ctx.v;
  664. }
  665. };
  666. struct SecondMW
  667. {
  668. struct context {};
  669. template <typename AllContext>
  670. void before_handle(request& req, response& res, context&, AllContext& all_ctx)
  671. {
  672. all_ctx.template get<FirstMW>().v.push_back("2 before");
  673. if (req.url == "/break")
  674. res.end();
  675. }
  676. template <typename AllContext>
  677. void after_handle(request&, response&, context&, AllContext& all_ctx)
  678. {
  679. all_ctx.template get<FirstMW>().v.push_back("2 after");
  680. }
  681. };
  682. struct ThirdMW
  683. {
  684. struct context {};
  685. template <typename AllContext>
  686. void before_handle(request&, response&, context&, AllContext& all_ctx)
  687. {
  688. all_ctx.template get<FirstMW>().v.push_back("3 before");
  689. }
  690. template <typename AllContext>
  691. void after_handle(request&, response&, context&, AllContext& all_ctx)
  692. {
  693. all_ctx.template get<FirstMW>().v.push_back("3 after");
  694. }
  695. };
  696. TEST(middleware_context)
  697. {
  698. static char buf[2048];
  699. // SecondMW depends on FirstMW (it uses all_ctx.get<FirstMW>)
  700. // so it leads to compile error if we remove FirstMW from definition
  701. // App<IntSettingMiddleware, SecondMW> app;
  702. // or change the order of FirstMW and SecondMW
  703. // App<IntSettingMiddleware, SecondMW, FirstMW> app;
  704. App<IntSettingMiddleware, FirstMW, SecondMW, ThirdMW> app;
  705. int x{};
  706. CROW_ROUTE(app, "/")([&](const request& req){
  707. {
  708. auto& ctx = app.get_context<IntSettingMiddleware>(req);
  709. x = ctx.val;
  710. }
  711. {
  712. auto& ctx = app.get_context<FirstMW>(req);
  713. ctx.v.push_back("handle");
  714. }
  715. return "";
  716. });
  717. CROW_ROUTE(app, "/break")([&](const request& req){
  718. {
  719. auto& ctx = app.get_context<FirstMW>(req);
  720. ctx.v.push_back("handle");
  721. }
  722. return "";
  723. });
  724. //decltype(app)::server_t server(&app, LOCALHOST_ADDRESS, 45451);
  725. //auto _ = async(launch::async, [&]{server.run();});
  726. auto _ = async(launch::async, [&]{app.bindaddr(LOCALHOST_ADDRESS).port(45451).run();});
  727. app.wait_for_server_start();
  728. std::string sendmsg = "GET /\r\n\r\n";
  729. asio::io_service is;
  730. {
  731. asio::ip::tcp::socket c(is);
  732. c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
  733. c.send(asio::buffer(sendmsg));
  734. c.receive(asio::buffer(buf, 2048));
  735. c.close();
  736. }
  737. {
  738. auto& out = test_middleware_context_vector;
  739. ASSERT_EQUAL(1, x);
  740. ASSERT_EQUAL(7, out.size());
  741. ASSERT_EQUAL("1 before", out[0]);
  742. ASSERT_EQUAL("2 before", out[1]);
  743. ASSERT_EQUAL("3 before", out[2]);
  744. ASSERT_EQUAL("handle", out[3]);
  745. ASSERT_EQUAL("3 after", out[4]);
  746. ASSERT_EQUAL("2 after", out[5]);
  747. ASSERT_EQUAL("1 after", out[6]);
  748. }
  749. std::string sendmsg2 = "GET /break\r\n\r\n";
  750. {
  751. asio::ip::tcp::socket c(is);
  752. c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
  753. c.send(asio::buffer(sendmsg2));
  754. c.receive(asio::buffer(buf, 2048));
  755. c.close();
  756. }
  757. {
  758. auto& out = test_middleware_context_vector;
  759. ASSERT_EQUAL(4, out.size());
  760. ASSERT_EQUAL("1 before", out[0]);
  761. ASSERT_EQUAL("2 before", out[1]);
  762. ASSERT_EQUAL("2 after", out[2]);
  763. ASSERT_EQUAL("1 after", out[3]);
  764. }
  765. app.stop();
  766. }
  767. TEST(middleware_cookieparser)
  768. {
  769. static char buf[2048];
  770. App<CookieParser> app;
  771. std::string value1;
  772. std::string value2;
  773. std::string value3;
  774. std::string value4;
  775. CROW_ROUTE(app, "/")([&](const request& req){
  776. {
  777. auto& ctx = app.get_context<CookieParser>(req);
  778. value1 = ctx.get_cookie("key1");
  779. value2 = ctx.get_cookie("key2");
  780. value3 = ctx.get_cookie("key3");
  781. value4 = ctx.get_cookie("key4");
  782. }
  783. return "";
  784. });
  785. //decltype(app)::server_t server(&app, LOCALHOST_ADDRESS, 45451);
  786. //auto _ = async(launch::async, [&]{server.run();});
  787. auto _ = async(launch::async, [&]{app.bindaddr(LOCALHOST_ADDRESS).port(45451).run();});
  788. app.wait_for_server_start();
  789. std::string sendmsg = "GET /\r\nCookie: key1=value1; key2=\"val=ue2\"; key3=\"val\"ue3\"; key4=\"val\"ue4\"\r\n\r\n";
  790. asio::io_service is;
  791. {
  792. asio::ip::tcp::socket c(is);
  793. c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
  794. c.send(asio::buffer(sendmsg));
  795. c.receive(asio::buffer(buf, 2048));
  796. c.close();
  797. }
  798. {
  799. ASSERT_EQUAL("value1", value1);
  800. ASSERT_EQUAL("val=ue2", value2);
  801. ASSERT_EQUAL("val\"ue3", value3);
  802. ASSERT_EQUAL("val\"ue4", value4);
  803. }
  804. app.stop();
  805. }
  806. TEST(bug_quick_repeated_request)
  807. {
  808. static char buf[2048];
  809. SimpleApp app;
  810. CROW_ROUTE(app, "/")([&]{
  811. return "hello";
  812. });
  813. //decltype(app)::server_t server(&app, LOCALHOST_ADDRESS, 45451);
  814. //auto _ = async(launch::async, [&]{server.run();});
  815. auto _ = async(launch::async, [&]{app.bindaddr(LOCALHOST_ADDRESS).port(45451).run();});
  816. app.wait_for_server_start();
  817. std::string sendmsg = "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n";
  818. asio::io_service is;
  819. {
  820. std::vector<std::future<void>> v;
  821. for(int i = 0; i < 5; i++)
  822. {
  823. v.push_back(async(launch::async,
  824. [&]
  825. {
  826. asio::ip::tcp::socket c(is);
  827. c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
  828. for(int j = 0; j < 5; j ++)
  829. {
  830. c.send(asio::buffer(sendmsg));
  831. size_t received = c.receive(asio::buffer(buf, 2048));
  832. ASSERT_EQUAL("hello", std::string(buf + received - 5, buf + received));
  833. }
  834. c.close();
  835. }));
  836. }
  837. }
  838. app.stop();
  839. }
  840. TEST(simple_url_params)
  841. {
  842. static char buf[2048];
  843. SimpleApp app;
  844. query_string last_url_params;
  845. CROW_ROUTE(app, "/params")
  846. ([&last_url_params](const crow::request& req){
  847. last_url_params = std::move(req.url_params);
  848. return "OK";
  849. });
  850. ///params?h=1&foo=bar&lol&count[]=1&count[]=4&pew=5.2
  851. //decltype(app)::server_t server(&app, LOCALHOST_ADDRESS, 45451);
  852. //auto _ = async(launch::async, [&]{server.run();});
  853. auto _ = async(launch::async, [&]{app.bindaddr(LOCALHOST_ADDRESS).port(45451).run();});
  854. app.wait_for_server_start();
  855. asio::io_service is;
  856. std::string sendmsg;
  857. // check empty params
  858. sendmsg = "GET /params\r\n\r\n";
  859. {
  860. asio::ip::tcp::socket c(is);
  861. c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
  862. c.send(asio::buffer(sendmsg));
  863. c.receive(asio::buffer(buf, 2048));
  864. c.close();
  865. stringstream ss;
  866. ss << last_url_params;
  867. ASSERT_EQUAL("[ ]", ss.str());
  868. }
  869. // check single presence
  870. sendmsg = "GET /params?foobar\r\n\r\n";
  871. {
  872. asio::ip::tcp::socket c(is);
  873. c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
  874. c.send(asio::buffer(sendmsg));
  875. c.receive(asio::buffer(buf, 2048));
  876. c.close();
  877. ASSERT_TRUE(last_url_params.get("missing") == nullptr);
  878. ASSERT_TRUE(last_url_params.get("foobar") != nullptr);
  879. ASSERT_TRUE(last_url_params.get_list("missing").empty());
  880. }
  881. // check multiple presence
  882. sendmsg = "GET /params?foo&bar&baz\r\n\r\n";
  883. {
  884. asio::ip::tcp::socket c(is);
  885. c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
  886. c.send(asio::buffer(sendmsg));
  887. c.receive(asio::buffer(buf, 2048));
  888. c.close();
  889. ASSERT_TRUE(last_url_params.get("missing") == nullptr);
  890. ASSERT_TRUE(last_url_params.get("foo") != nullptr);
  891. ASSERT_TRUE(last_url_params.get("bar") != nullptr);
  892. ASSERT_TRUE(last_url_params.get("baz") != nullptr);
  893. }
  894. // check single value
  895. sendmsg = "GET /params?hello=world\r\n\r\n";
  896. {
  897. asio::ip::tcp::socket c(is);
  898. c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
  899. c.send(asio::buffer(sendmsg));
  900. c.receive(asio::buffer(buf, 2048));
  901. c.close();
  902. ASSERT_EQUAL(string(last_url_params.get("hello")), "world");
  903. }
  904. // check multiple value
  905. sendmsg = "GET /params?hello=world&left=right&up=down\r\n\r\n";
  906. {
  907. asio::ip::tcp::socket c(is);
  908. c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
  909. c.send(asio::buffer(sendmsg));
  910. c.receive(asio::buffer(buf, 2048));
  911. c.close();
  912. ASSERT_EQUAL(string(last_url_params.get("hello")), "world");
  913. ASSERT_EQUAL(string(last_url_params.get("left")), "right");
  914. ASSERT_EQUAL(string(last_url_params.get("up")), "down");
  915. }
  916. // check multiple value, multiple types
  917. sendmsg = "GET /params?int=100&double=123.45&boolean=1\r\n\r\n";
  918. {
  919. asio::ip::tcp::socket c(is);
  920. c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
  921. c.send(asio::buffer(sendmsg));
  922. c.receive(asio::buffer(buf, 2048));
  923. c.close();
  924. ASSERT_EQUAL(boost::lexical_cast<int>(last_url_params.get("int")), 100);
  925. ASSERT_EQUAL(boost::lexical_cast<double>(last_url_params.get("double")), 123.45);
  926. ASSERT_EQUAL(boost::lexical_cast<bool>(last_url_params.get("boolean")), true);
  927. }
  928. // check single array value
  929. sendmsg = "GET /params?tmnt[]=leonardo\r\n\r\n";
  930. {
  931. asio::ip::tcp::socket c(is);
  932. c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
  933. c.send(asio::buffer(sendmsg));
  934. c.receive(asio::buffer(buf, 2048));
  935. c.close();
  936. ASSERT_TRUE(last_url_params.get("tmnt") == nullptr);
  937. ASSERT_EQUAL(last_url_params.get_list("tmnt").size(), 1);
  938. ASSERT_EQUAL(string(last_url_params.get_list("tmnt")[0]), "leonardo");
  939. }
  940. // check multiple array value
  941. sendmsg = "GET /params?tmnt[]=leonardo&tmnt[]=donatello&tmnt[]=raphael\r\n\r\n";
  942. {
  943. asio::ip::tcp::socket c(is);
  944. c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
  945. c.send(asio::buffer(sendmsg));
  946. c.receive(asio::buffer(buf, 2048));
  947. c.close();
  948. ASSERT_EQUAL(last_url_params.get_list("tmnt").size(), 3);
  949. ASSERT_EQUAL(string(last_url_params.get_list("tmnt")[0]), "leonardo");
  950. ASSERT_EQUAL(string(last_url_params.get_list("tmnt")[1]), "donatello");
  951. ASSERT_EQUAL(string(last_url_params.get_list("tmnt")[2]), "raphael");
  952. }
  953. app.stop();
  954. }
  955. TEST(route_dynamic)
  956. {
  957. SimpleApp app;
  958. int x = 1;
  959. app.route_dynamic("/")
  960. ([&]{
  961. x = 2;
  962. return "";
  963. });
  964. app.route_dynamic("/set4")
  965. ([&](const request&){
  966. x = 4;
  967. return "";
  968. });
  969. app.route_dynamic("/set5")
  970. ([&](const request&, response& res){
  971. x = 5;
  972. res.end();
  973. });
  974. app.route_dynamic("/set_int/<int>")
  975. ([&](int y){
  976. x = y;
  977. return "";
  978. });
  979. try
  980. {
  981. app.route_dynamic("/invalid_test/<double>/<path>")
  982. ([](){
  983. return "";
  984. });
  985. fail();
  986. }
  987. catch(std::exception&)
  988. {
  989. }
  990. // app is in an invalid state when route_dynamic throws an exception.
  991. try
  992. {
  993. app.validate();
  994. fail();
  995. }
  996. catch(std::exception&)
  997. {
  998. }
  999. {
  1000. request req;
  1001. response res;
  1002. req.url = "/";
  1003. app.handle(req, res);
  1004. ASSERT_EQUAL(x, 2);
  1005. }
  1006. {
  1007. request req;
  1008. response res;
  1009. req.url = "/set_int/42";
  1010. app.handle(req, res);
  1011. ASSERT_EQUAL(x, 42);
  1012. }
  1013. {
  1014. request req;
  1015. response res;
  1016. req.url = "/set5";
  1017. app.handle(req, res);
  1018. ASSERT_EQUAL(x, 5);
  1019. }
  1020. {
  1021. request req;
  1022. response res;
  1023. req.url = "/set4";
  1024. app.handle(req, res);
  1025. ASSERT_EQUAL(x, 4);
  1026. }
  1027. }
  1028. int main()
  1029. {
  1030. return testmain();
  1031. }