2020-10-18 16:59:15 +00:00
# define CATCH_CONFIG_MAIN
2021-08-21 01:49:17 +00:00
# define CROW_ENABLE_DEBUG
2020-10-20 06:23:40 +00:00
# define CROW_LOG_LEVEL 0
2021-03-31 17:30:32 +00:00
# define CROW_MAIN
2020-10-19 08:02:57 +00:00
# include <sys/stat.h>
2014-04-14 15:31:51 +00:00
# include <iostream>
2015-05-01 00:56:28 +00:00
# include <sstream>
2014-04-14 18:02:48 +00:00
# include <vector>
2020-10-27 19:53:58 +00:00
# include <thread>
# include <chrono>
2020-10-19 08:02:57 +00:00
2020-10-18 16:59:15 +00:00
# include "catch.hpp"
2020-10-19 08:02:57 +00:00
# include "crow.h"
2020-11-11 20:43:57 +00:00
# include "crow/middlewares/cookie_parser.h"
2014-09-10 21:32:41 +00:00
2014-04-14 15:31:51 +00:00
using namespace std ;
2014-04-26 17:19:59 +00:00
using namespace crow ;
2014-04-14 18:02:48 +00:00
2016-03-19 15:05:48 +00:00
# define LOCALHOST_ADDRESS "127.0.0.1"
2020-10-18 16:59:15 +00:00
TEST_CASE ( " Rule " )
2014-04-14 18:02:48 +00:00
{
2020-10-19 08:02:57 +00:00
TaggedRule < > r ( " /http/ " ) ;
r . name ( " abc " ) ;
2014-04-14 20:11:37 +00:00
2020-10-19 08:02:57 +00:00
// empty handler - fail to validate
try {
r . validate ( ) ;
FAIL_CHECK ( " empty handler should fail to validate " ) ;
} catch ( runtime_error & e ) {
}
2014-04-14 18:02:48 +00:00
2020-10-19 08:02:57 +00:00
int x = 0 ;
2014-04-14 18:02:48 +00:00
2020-10-19 08:02:57 +00:00
// registering handler
r ( [ & x ] {
x = 1 ;
return " " ;
} ) ;
2014-04-14 20:11:37 +00:00
2020-10-19 08:02:57 +00:00
r . validate ( ) ;
2014-04-14 20:11:37 +00:00
2020-10-19 08:02:57 +00:00
response res ;
2014-08-05 18:54:38 +00:00
2020-10-19 08:02:57 +00:00
// executing handler
2020-10-26 23:43:36 +00:00
CHECK ( 0 = = x ) ;
2020-10-19 08:02:57 +00:00
r . handle ( request ( ) , res , routing_params ( ) ) ;
2020-10-26 23:43:36 +00:00
CHECK ( 1 = = x ) ;
2014-04-21 18:27:53 +00:00
2020-10-19 08:02:57 +00:00
// registering handler with request argument
r ( [ & x ] ( const crow : : request & ) {
x = 2 ;
return " " ;
} ) ;
2014-04-21 18:27:53 +00:00
2020-10-19 08:02:57 +00:00
r . validate ( ) ;
2014-04-21 18:27:53 +00:00
2020-10-19 08:02:57 +00:00
// executing handler
2020-10-26 23:43:36 +00:00
CHECK ( 1 = = x ) ;
2020-10-19 08:02:57 +00:00
r . handle ( request ( ) , res , routing_params ( ) ) ;
2020-10-26 23:43:36 +00:00
CHECK ( 2 = = x ) ;
2014-04-14 20:11:37 +00:00
}
2020-10-18 16:59:15 +00:00
TEST_CASE ( " ParameterTagging " )
2014-04-14 20:11:37 +00:00
{
2020-10-19 08:02:57 +00:00
static_assert ( black_magic : : is_valid ( " <int><int><int> " ) , " valid url " ) ;
static_assert ( ! black_magic : : is_valid ( " <int><int<<int> " ) , " invalid url " ) ;
static_assert ( ! black_magic : : is_valid ( " nt> " ) , " invalid url " ) ;
2020-10-26 23:43:36 +00:00
CHECK ( 1 = = black_magic : : get_parameter_tag ( " <int> " ) ) ;
CHECK ( 2 = = black_magic : : get_parameter_tag ( " <uint> " ) ) ;
CHECK ( 3 = = black_magic : : get_parameter_tag ( " <float> " ) ) ;
CHECK ( 3 = = black_magic : : get_parameter_tag ( " <double> " ) ) ;
CHECK ( 4 = = black_magic : : get_parameter_tag ( " <str> " ) ) ;
CHECK ( 4 = = black_magic : : get_parameter_tag ( " <string> " ) ) ;
CHECK ( 5 = = black_magic : : get_parameter_tag ( " <path> " ) ) ;
CHECK ( 6 * 6 + 6 + 1 = = black_magic : : get_parameter_tag ( " <int><int><int> " ) ) ;
CHECK ( 6 * 6 + 6 + 2 = = black_magic : : get_parameter_tag ( " <uint><int><int> " ) ) ;
CHECK ( 6 * 6 + 6 * 3 + 2 = =
2020-10-19 08:02:57 +00:00
black_magic : : get_parameter_tag ( " <uint><double><int> " ) ) ;
// url definition parsed in compile time, build into *one number*, and given
// to template argument
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 " ) ;
2014-04-14 20:11:37 +00:00
}
2014-04-14 18:02:48 +00:00
2020-10-18 16:59:15 +00:00
TEST_CASE ( " PathRouting " )
2015-01-19 10:03:06 +00:00
{
2020-10-19 08:02:57 +00:00
SimpleApp app ;
2015-01-19 10:03:06 +00:00
2020-10-19 08:02:57 +00:00
CROW_ROUTE ( app , " /file " )
( [ ] { return " file " ; } ) ;
2015-01-19 10:03:06 +00:00
2020-10-19 08:02:57 +00:00
CROW_ROUTE ( app , " /path/ " )
( [ ] { return " path " ; } ) ;
2015-01-19 10:03:06 +00:00
2020-10-19 08:02:57 +00:00
app . validate ( ) ;
2017-12-24 15:40:39 +00:00
2020-10-19 08:02:57 +00:00
{
request req ;
response res ;
2015-01-19 10:03:06 +00:00
2020-10-19 08:02:57 +00:00
req . url = " /file " ;
2015-01-19 10:03:06 +00:00
2020-10-19 08:02:57 +00:00
app . handle ( req , res ) ;
2015-01-19 10:03:06 +00:00
2020-10-26 23:43:36 +00:00
CHECK ( 200 = = res . code ) ;
2020-10-19 08:02:57 +00:00
}
{
request req ;
response res ;
2015-01-19 10:03:06 +00:00
2020-10-19 08:02:57 +00:00
req . url = " /file/ " ;
2015-01-19 10:03:06 +00:00
2020-10-19 08:02:57 +00:00
app . handle ( req , res ) ;
2020-10-26 23:43:36 +00:00
CHECK ( 404 = = res . code ) ;
2020-10-19 08:02:57 +00:00
}
{
request req ;
response res ;
2015-01-19 10:03:06 +00:00
2020-10-19 08:02:57 +00:00
req . url = " /path " ;
2015-01-19 10:03:06 +00:00
2020-10-19 08:02:57 +00:00
app . handle ( req , res ) ;
2020-10-26 23:43:36 +00:00
CHECK ( 404 ! = res . code ) ;
2020-10-19 08:02:57 +00:00
}
{
request req ;
response res ;
2015-01-19 10:03:06 +00:00
2020-10-19 08:02:57 +00:00
req . url = " /path/ " ;
2015-01-19 10:03:06 +00:00
2020-10-19 08:02:57 +00:00
app . handle ( req , res ) ;
2020-10-26 23:43:36 +00:00
CHECK ( 200 = = res . code ) ;
2020-10-19 08:02:57 +00:00
}
2015-01-19 10:03:06 +00:00
}
2020-10-18 16:59:15 +00:00
TEST_CASE ( " RoutingTest " )
2014-04-15 17:57:18 +00:00
{
2020-10-19 08:02:57 +00:00
SimpleApp app ;
int A { } ;
uint32_t B { } ;
double C { } ;
string D { } ;
string E { } ;
CROW_ROUTE ( app , " /0/<uint> " )
( [ & ] ( uint32_t b ) {
B = b ;
return " OK " ;
} ) ;
CROW_ROUTE ( app , " /1/<int>/<uint> " )
( [ & ] ( int a , uint32_t b ) {
A = a ;
B = b ;
return " OK " ;
} ) ;
CROW_ROUTE ( app , " /4/<int>/<uint>/<double>/<string> " )
( [ & ] ( int a , uint32_t b , double c , string d ) {
A = a ;
B = b ;
C = c ;
D = d ;
return " OK " ;
} ) ;
CROW_ROUTE ( app , " /5/<int>/<uint>/<double>/<string>/<path> " )
( [ & ] ( 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 ;
2014-08-05 18:54:38 +00:00
2020-10-19 08:02:57 +00:00
req . url = " /-1 " ;
2014-08-05 18:54:38 +00:00
2020-10-19 08:02:57 +00:00
app . handle ( req , res ) ;
2014-08-05 18:54:38 +00:00
2020-10-26 23:43:36 +00:00
CHECK ( 404 = = res . code ) ;
2020-10-19 08:02:57 +00:00
}
2014-04-15 17:57:18 +00:00
2020-10-19 08:02:57 +00:00
{
request req ;
response res ;
2014-04-15 17:57:18 +00:00
2020-10-19 08:02:57 +00:00
req . url = " /0/1001999 " ;
2014-04-15 17:57:18 +00:00
2020-10-19 08:02:57 +00:00
app . handle ( req , res ) ;
2014-04-15 17:57:18 +00:00
2020-10-26 23:43:36 +00:00
CHECK ( 200 = = res . code ) ;
2014-04-15 17:57:18 +00:00
2020-10-26 23:43:36 +00:00
CHECK ( 1001999 = = B ) ;
2020-10-19 08:02:57 +00:00
}
2014-04-15 17:57:18 +00:00
2020-10-19 08:02:57 +00:00
{
request req ;
response res ;
2014-04-15 17:57:18 +00:00
2020-10-19 08:02:57 +00:00
req . url = " /1/-100/1999 " ;
2014-04-15 17:57:18 +00:00
2020-10-19 08:02:57 +00:00
app . handle ( req , res ) ;
2014-04-15 17:57:18 +00:00
2020-10-26 23:43:36 +00:00
CHECK ( 200 = = res . code ) ;
2014-04-15 17:57:18 +00:00
2020-10-26 23:43:36 +00:00
CHECK ( - 100 = = A ) ;
CHECK ( 1999 = = B ) ;
2020-10-19 08:02:57 +00:00
}
{
request req ;
response res ;
2014-04-15 17:57:18 +00:00
2020-10-19 08:02:57 +00:00
req . url = " /4/5000/3/-2.71828/hellhere " ;
req . add_header ( " TestHeader " , " Value " ) ;
2014-04-15 17:57:18 +00:00
2020-10-19 08:02:57 +00:00
app . handle ( req , res ) ;
2014-04-15 17:57:18 +00:00
2020-10-26 23:43:36 +00:00
CHECK ( 200 = = res . code ) ;
2014-04-15 17:57:18 +00:00
2020-10-26 23:43:36 +00:00
CHECK ( 5000 = = A ) ;
CHECK ( 3 = = B ) ;
CHECK ( - 2.71828 = = C ) ;
CHECK ( " hellhere " = = D ) ;
2020-10-19 08:02:57 +00:00
}
{
request req ;
response res ;
2014-04-15 17:57:18 +00:00
2020-10-19 08:02:57 +00:00
req . url = " /5/-5/999/3.141592/hello_there/a/b/c/d " ;
req . add_header ( " TestHeader " , " Value " ) ;
2014-04-15 17:57:18 +00:00
2020-10-19 08:02:57 +00:00
app . handle ( req , res ) ;
2014-04-15 17:57:18 +00:00
2020-10-26 23:43:36 +00:00
CHECK ( 200 = = res . code ) ;
2014-04-15 17:57:18 +00:00
2020-10-26 23:43:36 +00:00
CHECK ( - 5 = = A ) ;
CHECK ( 999 = = B ) ;
CHECK ( 3.141592 = = C ) ;
CHECK ( " hello_there " = = D ) ;
CHECK ( " a/b/c/d " = = E ) ;
2020-10-19 08:02:57 +00:00
}
2014-04-15 17:57:18 +00:00
}
2020-10-18 16:59:15 +00:00
TEST_CASE ( " simple_response_routing_params " )
2014-04-14 20:11:37 +00:00
{
2020-10-26 23:43:36 +00:00
CHECK ( 100 = = response ( 100 ) . code ) ;
CHECK ( 200 = = response ( " Hello there " ) . code ) ;
CHECK ( 500 = = response ( 500 , " Internal Error? " ) . code ) ;
2020-10-19 08:02:57 +00:00
2021-08-30 06:47:08 +00:00
CHECK ( 100 = = response ( 100 , " xml " , " " ) . code ) ;
2021-08-30 10:13:33 +00:00
CHECK ( " text/xml " = = response ( 100 , " xml " , " " ) . get_header_value ( " Content-Type " ) ) ;
2021-08-30 06:47:08 +00:00
CHECK ( 200 = = response ( 200 , " html " , " " ) . code ) ;
2021-08-30 10:13:33 +00:00
CHECK ( " text/html " = = response ( 200 , " html " , " " ) . get_header_value ( " Content-Type " ) ) ;
2021-08-30 06:47:08 +00:00
CHECK ( 500 = = response ( 500 , " html " , " Internal Error? " ) . code ) ;
2021-08-30 10:13:33 +00:00
CHECK ( " text/css " = = response ( 500 , " css " , " Internal Error? " ) . get_header_value ( " Content-Type " ) ) ;
2021-08-30 06:47:08 +00:00
2020-10-19 08:02:57 +00:00
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 " ) ;
2020-10-26 23:43:36 +00:00
CHECK ( 1 = = rp . get < int64_t > ( 0 ) ) ;
CHECK ( 5 = = rp . get < int64_t > ( 1 ) ) ;
CHECK ( 2 = = rp . get < uint64_t > ( 0 ) ) ;
CHECK ( 3 = = rp . get < double > ( 0 ) ) ;
CHECK ( " hello " = = rp . get < string > ( 0 ) ) ;
2014-04-14 18:02:48 +00:00
}
2020-10-18 16:59:15 +00:00
TEST_CASE ( " handler_with_response " )
2014-08-05 13:38:51 +00:00
{
2020-10-19 08:02:57 +00:00
SimpleApp app ;
CROW_ROUTE ( app , " / " ) ( [ ] ( const crow : : request & , crow : : response & ) { } ) ;
2014-08-05 13:38:51 +00:00
}
2020-10-18 16:59:15 +00:00
TEST_CASE ( " http_method " )
2014-10-07 12:51:24 +00:00
{
2020-10-19 08:02:57 +00:00
SimpleApp app ;
CROW_ROUTE ( app , " / " ) . methods ( " POST " _method ,
" GET " _method ) ( [ ] ( const request & req ) {
if ( req . method = = " GET " _method )
return " 2 " ;
else
return " 1 " ;
} ) ;
CROW_ROUTE ( app , " /get_only " )
. methods ( " GET " _method ) ( [ ] ( const request & /*req*/ ) { return " get " ; } ) ;
CROW_ROUTE ( app , " /post_only " )
. methods ( " POST " _method ) ( [ ] ( const request & /*req*/ ) { return " post " ; } ) ;
CROW_ROUTE ( app , " /patch_only " )
. methods ( " PATCH " _method ) ( [ ] ( const request & /*req*/ ) { return " patch " ; } ) ;
CROW_ROUTE ( app , " /purge_only " )
. methods ( " PURGE " _method ) ( [ ] ( const request & /*req*/ ) { return " purge " ; } ) ;
app . validate ( ) ;
app . debug_print ( ) ;
// cannot have multiple handlers for the same url
// CROW_ROUTE(app, "/")
//.methods("GET"_method)
//([]{ return "2"; });
{
request req ;
response res ;
2014-10-07 12:51:24 +00:00
2020-10-19 08:02:57 +00:00
req . url = " / " ;
app . handle ( req , res ) ;
2014-10-07 12:51:24 +00:00
2020-10-26 23:43:36 +00:00
CHECK ( " 2 " = = res . body ) ;
2020-10-19 08:02:57 +00:00
}
{
request req ;
response res ;
2014-10-07 12:51:24 +00:00
2020-10-19 08:02:57 +00:00
req . url = " / " ;
req . method = " POST " _method ;
app . handle ( req , res ) ;
2014-10-07 12:51:24 +00:00
2020-10-26 23:43:36 +00:00
CHECK ( " 1 " = = res . body ) ;
2020-10-19 08:02:57 +00:00
}
2014-10-07 12:51:24 +00:00
2020-10-19 08:02:57 +00:00
{
request req ;
response res ;
2014-10-07 12:51:24 +00:00
2020-10-19 08:02:57 +00:00
req . url = " /get_only " ;
app . handle ( req , res ) ;
2014-10-07 12:51:24 +00:00
2020-10-26 23:43:36 +00:00
CHECK ( " get " = = res . body ) ;
2020-10-19 08:02:57 +00:00
}
2014-10-07 12:51:24 +00:00
2020-10-19 08:02:57 +00:00
{
request req ;
response res ;
2017-10-05 15:13:40 +00:00
2020-10-19 08:02:57 +00:00
req . url = " /patch_only " ;
req . method = " PATCH " _method ;
app . handle ( req , res ) ;
2017-10-05 15:13:40 +00:00
2020-10-26 23:43:36 +00:00
CHECK ( " patch " = = res . body ) ;
2020-10-19 08:02:57 +00:00
}
2017-10-05 15:13:40 +00:00
2020-10-19 08:02:57 +00:00
{
request req ;
response res ;
2017-10-21 12:20:07 +00:00
2020-10-19 08:02:57 +00:00
req . url = " /purge_only " ;
req . method = " PURGE " _method ;
app . handle ( req , res ) ;
2017-10-21 12:20:07 +00:00
2020-10-26 23:43:36 +00:00
CHECK ( " purge " = = res . body ) ;
2020-10-19 08:02:57 +00:00
}
2017-10-21 12:20:07 +00:00
2020-10-19 08:02:57 +00:00
{
request req ;
response res ;
2014-10-07 12:51:24 +00:00
2020-10-19 08:02:57 +00:00
req . url = " /get_only " ;
req . method = " POST " _method ;
app . handle ( req , res ) ;
2014-10-07 12:51:24 +00:00
2020-10-26 23:43:36 +00:00
CHECK ( " get " ! = res . body ) ;
2020-10-19 08:02:57 +00:00
}
2014-10-07 12:51:24 +00:00
2020-10-19 08:02:57 +00:00
{
request req ;
response res ;
2020-10-14 22:24:26 +00:00
2020-10-19 08:02:57 +00:00
req . url = " /get_only " ;
req . method = " POST " _method ;
app . handle ( req , res ) ;
2020-10-14 22:24:26 +00:00
2020-10-26 23:43:36 +00:00
CHECK ( 405 = = res . code ) ;
2020-10-19 08:02:57 +00:00
}
2021-04-03 03:00:23 +00:00
{
request req ;
response res ;
req . url = " /get_only " ;
req . method = " HEAD " _method ;
app . handle ( req , res ) ;
CHECK ( 200 = = res . code ) ;
CHECK ( " " = = res . body ) ;
}
{
request req ;
response res ;
req . url = " / " ;
req . method = " OPTIONS " _method ;
app . handle ( req , res ) ;
CHECK ( 204 = = res . code ) ;
CHECK ( " OPTIONS, HEAD, GET, POST " = = res . get_header_value ( " Allow " ) ) ;
}
{
request req ;
response res ;
req . url = " /does_not_exist " ;
req . method = " OPTIONS " _method ;
app . handle ( req , res ) ;
CHECK ( 404 = = res . code ) ;
}
{
request req ;
response res ;
req . url = " /* " ;
req . method = " OPTIONS " _method ;
app . handle ( req , res ) ;
CHECK ( 204 = = res . code ) ;
CHECK ( " OPTIONS, HEAD, GET, POST, PATCH, PURGE " = = res . get_header_value ( " Allow " ) ) ;
}
2014-10-07 12:51:24 +00:00
}
2020-10-18 16:59:15 +00:00
TEST_CASE ( " server_handling_error_request " )
2014-04-22 11:19:03 +00:00
{
2020-10-19 08:02:57 +00:00
static char buf [ 2048 ] ;
SimpleApp app ;
CROW_ROUTE ( app , " / " ) ( [ ] { return " A " ; } ) ;
// Server<SimpleApp> server(&app, LOCALHOST_ADDRESS, 45451);
// auto _ = async(launch::async, [&]{server.run();});
auto _ = async ( launch : : async ,
[ & ] { app . bindaddr ( LOCALHOST_ADDRESS ) . port ( 45451 ) . run ( ) ; } ) ;
app . wait_for_server_start ( ) ;
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 ( LOCALHOST_ADDRESS ) , 45451 ) ) ;
c . send ( asio : : buffer ( sendmsg ) ) ;
try {
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
FAIL_CHECK ( ) ;
} catch ( std : : exception & e ) {
// std::cerr << e.what() << std::endl;
2014-04-22 11:19:03 +00:00
}
2020-10-19 08:02:57 +00:00
}
app . stop ( ) ;
2014-04-22 11:19:03 +00:00
}
2020-10-18 16:59:15 +00:00
TEST_CASE ( " multi_server " )
2014-04-15 13:08:23 +00:00
{
2020-10-19 08:02:57 +00:00
static char buf [ 2048 ] ;
SimpleApp app1 , app2 ;
CROW_ROUTE ( app1 , " / " ) . methods ( " GET " _method ,
" POST " _method ) ( [ ] { return " A " ; } ) ;
CROW_ROUTE ( app2 , " / " ) . methods ( " GET " _method ,
" POST " _method ) ( [ ] { return " B " ; } ) ;
auto _ = async ( launch : : async ,
[ & ] { app1 . bindaddr ( LOCALHOST_ADDRESS ) . port ( 45451 ) . run ( ) ; } ) ;
auto _2 = async ( launch : : async ,
[ & ] { app2 . bindaddr ( LOCALHOST_ADDRESS ) . port ( 45452 ) . run ( ) ; } ) ;
app1 . wait_for_server_start ( ) ;
app2 . wait_for_server_start ( ) ;
std : : string sendmsg =
" POST / \r \n Content-Length:3 \r \n X-HeaderTest: 123 \r \n \r \n A=B \r \n " ;
asio : : io_service is ;
{
asio : : ip : : tcp : : socket c ( is ) ;
c . connect ( asio : : ip : : tcp : : endpoint (
asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45451 ) ) ;
c . send ( asio : : buffer ( sendmsg ) ) ;
size_t recved = c . receive ( asio : : buffer ( buf , 2048 ) ) ;
2020-10-26 23:43:36 +00:00
CHECK ( ' A ' = = buf [ recved - 1 ] ) ;
2020-10-19 08:02:57 +00:00
}
{
asio : : ip : : tcp : : socket c ( is ) ;
c . connect ( asio : : ip : : tcp : : endpoint (
asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45452 ) ) ;
for ( auto ch : sendmsg ) {
char buf [ 1 ] = { ch } ;
c . send ( asio : : buffer ( buf ) ) ;
2014-04-15 13:08:23 +00:00
}
2020-10-19 08:02:57 +00:00
size_t recved = c . receive ( asio : : buffer ( buf , 2048 ) ) ;
2020-10-26 23:43:36 +00:00
CHECK ( ' B ' = = buf [ recved - 1 ] ) ;
2020-10-19 08:02:57 +00:00
}
2014-04-15 13:08:23 +00:00
2020-10-19 08:02:57 +00:00
app1 . stop ( ) ;
app2 . stop ( ) ;
2014-04-15 13:08:23 +00:00
}
2020-10-18 16:59:15 +00:00
TEST_CASE ( " json_read " )
2014-04-18 22:12:56 +00:00
{
2020-10-19 08:02:57 +00:00
{
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_CHECK ( std : : string ( " should fail to parse " ) + s ) ;
return ;
}
}
}
auto x = json : : load ( R " ({ " message " : " hello , world " }) " ) ;
if ( ! x ) FAIL_CHECK ( " fail to parse " ) ;
2020-10-26 23:43:36 +00:00
CHECK ( " hello, world " = = x [ " message " ] ) ;
CHECK ( 1 = = x . size ( ) ) ;
CHECK ( false = = x . has ( " mess " ) ) ;
2020-10-19 08:02:57 +00:00
REQUIRE_THROWS ( x [ " mess " ] ) ;
// TODO returning false is better than exception
// ASSERT_THROW(3 == x["message"]);
2020-10-26 23:43:36 +00:00
CHECK ( 12 = = x [ " message " ] . size ( ) ) ;
2020-10-19 08:02:57 +00:00
std : : string s =
R " ({ " int " :3, " ints " :[1,2,3,4,5], " bigint " :1234567890 }) " ;
auto y = json : : load ( s ) ;
2020-10-26 23:43:36 +00:00
CHECK ( 3 = = y [ " int " ] ) ;
CHECK ( 3.0 = = y [ " int " ] ) ;
CHECK ( 3.01 ! = y [ " int " ] ) ;
CHECK ( 5 = = y [ " ints " ] . size ( ) ) ;
CHECK ( 1 = = y [ " ints " ] [ 0 ] ) ;
CHECK ( 2 = = y [ " ints " ] [ 1 ] ) ;
CHECK ( 3 = = y [ " ints " ] [ 2 ] ) ;
CHECK ( 4 = = y [ " ints " ] [ 3 ] ) ;
CHECK ( 5 = = y [ " ints " ] [ 4 ] ) ;
CHECK ( 1u = = y [ " ints " ] [ 0 ] ) ;
CHECK ( 1.f = = y [ " ints " ] [ 0 ] ) ;
2020-10-19 08:02:57 +00:00
int q = ( int ) y [ " ints " ] [ 1 ] ;
2020-10-26 23:43:36 +00:00
CHECK ( 2 = = q ) ;
2020-10-19 08:02:57 +00:00
q = y [ " ints " ] [ 2 ] . i ( ) ;
2020-10-26 23:43:36 +00:00
CHECK ( 3 = = q ) ;
CHECK ( 1234567890 = = y [ " bigint " ] ) ;
2020-10-19 08:02:57 +00:00
std : : string s2 = R " ({ " bools " :[true, false], " doubles " :[1.2, -3.4]}) " ;
auto z = json : : load ( s2 ) ;
2020-10-26 23:43:36 +00:00
CHECK ( 2 = = z [ " bools " ] . size ( ) ) ;
CHECK ( 2 = = z [ " doubles " ] . size ( ) ) ;
CHECK ( true = = z [ " bools " ] [ 0 ] . b ( ) ) ;
CHECK ( false = = z [ " bools " ] [ 1 ] . b ( ) ) ;
CHECK ( 1.2 = = z [ " doubles " ] [ 0 ] . d ( ) ) ;
CHECK ( - 3.4 = = z [ " doubles " ] [ 1 ] . d ( ) ) ;
2020-10-19 08:02:57 +00:00
std : : string s3 = R " ({ " uint64 " : 18446744073709551615}) " ;
auto z1 = json : : load ( s3 ) ;
2020-10-26 23:43:36 +00:00
CHECK ( 18446744073709551615ull = = z1 [ " uint64 " ] . u ( ) ) ;
2020-10-19 08:02:57 +00:00
std : : ostringstream os ;
os < < z1 [ " uint64 " ] ;
2020-10-26 23:43:36 +00:00
CHECK ( " 18446744073709551615 " = = os . str ( ) ) ;
2014-04-18 22:12:56 +00:00
}
2020-10-18 16:59:15 +00:00
TEST_CASE ( " json_read_real " )
2014-11-08 23:47:45 +00:00
{
2020-10-19 08:02:57 +00:00
vector < std : : string > v { " 0.036303908355795146 " ,
" 0.18320417789757412 " ,
" 0.05319940476190476 " ,
" 0.15224702380952382 " ,
" 0 " ,
" 0.3296201145552561 " ,
" 0.47921580188679247 " ,
" 0.05873511904761905 " ,
" 0.1577827380952381 " ,
" 0.4996841307277628 " ,
" 0.6425412735849056 " ,
" 0.052113095238095236 " ,
" 0.12830357142857143 " ,
" 0.7871041105121294 " ,
" 0.954220013477089 " ,
" 0.05869047619047619 " ,
" 0.1625 " ,
" 0.8144794474393531 " ,
" 0.9721613881401617 " ,
" 0.1399404761904762 " ,
" 0.24470238095238095 " ,
" 0.04527459568733154 " ,
" 0.2096950808625337 " ,
" 0.35267857142857145 " ,
" 0.42791666666666667 " ,
" 0.855731974393531 " ,
" 0.9352467991913747 " ,
" 0.3816220238095238 " ,
" 0.4282886904761905 " ,
" 0.39414167789757415 " ,
" 0.5316079851752021 " ,
" 0.3809375 " ,
" 0.4571279761904762 " ,
" 0.03522995283018868 " ,
" 0.1915641846361186 " ,
" 0.6164136904761904 " ,
" 0.7192708333333333 " ,
" 0.05675117924528302 " ,
" 0.21308541105121293 " ,
" 0.7045386904761904 " ,
" 0.8016815476190476 " } ;
for ( auto x : v ) {
CROW_LOG_DEBUG < < x ;
2020-10-26 23:43:36 +00:00
CHECK ( json : : load ( x ) . d ( ) = = boost : : lexical_cast < double > ( x ) ) ;
2020-10-19 08:02:57 +00:00
}
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 " }]})--- " ) ;
2020-10-26 23:43:36 +00:00
CHECK ( ret ) ;
2014-11-08 23:47:45 +00:00
}
2020-10-18 16:59:15 +00:00
TEST_CASE ( " json_read_unescaping " )
2014-08-01 21:30:36 +00:00
{
2020-10-19 08:02:57 +00:00
{
auto x = json : : load ( R " ({ " data " : " \ ud55c \ n \ t \ r " }) " ) ;
if ( ! x ) {
FAIL_CHECK ( " fail to parse " ) ;
return ;
2014-08-01 21:30:36 +00:00
}
2020-10-26 23:43:36 +00:00
CHECK ( 6 = = x [ " data " ] . size ( ) ) ;
CHECK ( " 한 \n \t \r " = = x [ " data " ] ) ;
2020-10-19 08:02:57 +00:00
}
{
// multiple r_string instance
auto x = json : : load ( R " ({ " data " : " \ ud55c \ n \ t \ r " }) " ) ;
auto a = x [ " data " ] . s ( ) ;
auto b = x [ " data " ] . s ( ) ;
2020-10-26 23:43:36 +00:00
CHECK ( 6 = = a . size ( ) ) ;
CHECK ( 6 = = b . size ( ) ) ;
CHECK ( 6 = = x [ " data " ] . size ( ) ) ;
2020-10-19 08:02:57 +00:00
}
2014-08-01 21:30:36 +00:00
}
2021-05-12 12:45:55 +00:00
TEST_CASE ( " json_read_string " )
{
auto x = json : : load ( R " ({ " message " : 53}) " ) ;
int y ( x [ " message " ] ) ;
std : : string z ( x [ " message " ] ) ;
CHECK ( 53 = = y ) ;
CHECK ( " 53 " = = z ) ;
}
TEST_CASE ( " json_read_container " )
{
auto x = json : : load ( R " ({ " first " : 53, " second " : " 55 " , " third " : [5,6,7,8,3,2,1,4]}) " ) ;
CHECK ( std : : vector < std : : string > ( { " first " , " second " , " third " } ) = = x . keys ( ) ) ;
CHECK ( 53 = = int ( x . lo ( ) [ 0 ] ) ) ;
CHECK ( " 55 " = = std : : string ( x . lo ( ) [ 1 ] ) ) ;
CHECK ( 8 = = int ( x . lo ( ) [ 2 ] . lo ( ) [ 3 ] ) ) ;
}
2020-10-18 16:59:15 +00:00
TEST_CASE ( " json_write " )
2014-04-17 13:32:21 +00:00
{
2020-10-19 08:02:57 +00:00
json : : wvalue x ;
x [ " message " ] = " hello world " ;
2021-01-05 14:49:10 +00:00
CHECK ( R " ({ " message " : " hello world " }) " = = x . dump ( ) ) ;
2020-10-19 08:02:57 +00:00
x [ " message " ] = std : : string ( " string value " ) ;
2021-01-05 14:49:10 +00:00
CHECK ( R " ({ " message " : " string value " }) " = = x . dump ( ) ) ;
2020-10-19 08:02:57 +00:00
x [ " message " ] [ " x " ] = 3 ;
2021-01-05 14:49:10 +00:00
CHECK ( R " ({ " message " :{ " x " :3}}) " = = x . dump ( ) ) ;
2020-10-19 08:02:57 +00:00
x [ " message " ] [ " y " ] = 5 ;
2021-01-05 14:49:10 +00:00
CHECK ( ( R " ({ " message " :{ " x " :3, " y " :5}}) " = = x . dump ( ) | |
R " ({ " message " :{ " y " :5, " x " :3}}) " = = x . dump ( ) ) ) ;
2020-10-19 08:02:57 +00:00
x [ " message " ] = 5.5 ;
2021-01-05 14:49:10 +00:00
CHECK ( R " ({ " message " :5.5}) " = = x . dump ( ) ) ;
2020-10-19 08:02:57 +00:00
x [ " message " ] = 1234567890 ;
2021-01-05 14:49:10 +00:00
CHECK ( R " ({ " message " :1234567890}) " = = x . dump ( ) ) ;
2020-10-19 08:02:57 +00:00
json : : wvalue y ;
y [ " scores " ] [ 0 ] = 1 ;
y [ " scores " ] [ 1 ] = " king " ;
y [ " scores " ] [ 2 ] = 3.5 ;
2021-01-05 14:49:10 +00:00
CHECK ( R " ({ " scores " :[1, " king " ,3.5]}) " = = y . dump ( ) ) ;
2020-10-19 08:02:57 +00:00
y [ " scores " ] [ 2 ] [ 0 ] = " real " ;
y [ " scores " ] [ 2 ] [ 1 ] = false ;
y [ " scores " ] [ 2 ] [ 2 ] = true ;
2021-01-05 14:49:10 +00:00
CHECK ( R " ({ " scores " :[1, " king " ,[ " real " ,false,true]]}) " = = y . dump ( ) ) ;
2020-10-19 08:02:57 +00:00
y [ " scores " ] [ " a " ] [ " b " ] [ " c " ] = nullptr ;
2021-01-05 14:49:10 +00:00
CHECK ( R " ({ " scores " :{ " a " :{ " b " :{ " c " :null}}}}) " = = y . dump ( ) ) ;
2020-10-19 08:02:57 +00:00
y [ " scores " ] = std : : vector < int > { 1 , 2 , 3 } ;
2021-01-05 14:49:10 +00:00
CHECK ( R " ({ " scores " :[1,2,3]}) " = = y . dump ( ) ) ;
2014-04-17 13:32:21 +00:00
}
2021-05-12 12:45:55 +00:00
TEST_CASE ( " json_copy_r_to_w_to_w_to_r " )
2017-10-22 11:31:17 +00:00
{
2020-10-19 08:02:57 +00:00
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 " }}) " ) ;
2021-05-12 12:45:55 +00:00
json : : wvalue v { r } ;
json : : wvalue w ( v ) ;
2020-10-19 08:02:57 +00:00
json : : rvalue x =
2021-01-05 14:49:10 +00:00
json : : load ( w . dump ( ) ) ; // why no copy-ctor wvalue -> rvalue?
2020-10-26 23:43:36 +00:00
CHECK ( 2 = = x [ " smallint " ] ) ;
CHECK ( 2147483647 = = x [ " bigint " ] ) ;
CHECK ( 23.43 = = x [ " fp " ] ) ;
CHECK ( 23.43 = = x [ " fpsc " ] ) ;
CHECK ( " a string " = = x [ " str " ] ) ;
CHECK ( x [ " trueval " ] . b ( ) ) ;
2020-10-18 16:59:15 +00:00
REQUIRE_FALSE ( x [ " falseval " ] . b ( ) ) ;
2020-10-26 23:43:36 +00:00
CHECK ( json : : type : : Null = = x [ " nullval " ] . t ( ) ) ;
CHECK ( 4u = = x [ " listval " ] . size ( ) ) ;
CHECK ( 1 = = x [ " listval " ] [ 0 ] ) ;
CHECK ( 2 = = x [ " listval " ] [ 1 ] ) ;
CHECK ( " foo " = = x [ " listval " ] [ 2 ] ) ;
CHECK ( " bar " = = x [ " listval " ] [ 3 ] ) ;
CHECK ( 23 = = x [ " obj " ] [ " member " ] ) ;
CHECK ( " member " = = x [ " obj " ] [ " member " ] . key ( ) ) ;
CHECK ( " baz " = = x [ " obj " ] [ " other " ] ) ;
CHECK ( " other " = = x [ " obj " ] [ " other " ] . key ( ) ) ;
2017-10-22 11:31:17 +00:00
}
2021-08-20 00:57:21 +00:00
//TODO maybe combine these
2021-08-09 12:31:28 +00:00
TEST_CASE ( " json::wvalue::wvalue(bool) " ) {
CHECK ( json : : wvalue ( true ) . t ( ) = = json : : type : : True ) ;
CHECK ( json : : wvalue ( false ) . t ( ) = = json : : type : : False ) ;
}
TEST_CASE ( " json::wvalue::wvalue(std::uint8_t) " ) {
std : : uint8_t i = 42 ;
json : : wvalue value = i ;
CHECK ( value . t ( ) = = json : : type : : Number ) ;
CHECK ( value . dump ( ) = = " 42 " ) ;
}
TEST_CASE ( " json::wvalue::wvalue(std::uint16_t) " ) {
std : : uint16_t i = 42 ;
json : : wvalue value = i ;
CHECK ( value . t ( ) = = json : : type : : Number ) ;
CHECK ( value . dump ( ) = = " 42 " ) ;
}
TEST_CASE ( " json::wvalue::wvalue(std::uint32_t) " ) {
std : : uint32_t i = 42 ;
json : : wvalue value = i ;
CHECK ( value . t ( ) = = json : : type : : Number ) ;
CHECK ( value . dump ( ) = = " 42 " ) ;
}
TEST_CASE ( " json::wvalue::wvalue(std::uint64_t) " ) {
std : : uint64_t i = 42 ;
json : : wvalue value = i ;
CHECK ( value . t ( ) = = json : : type : : Number ) ;
CHECK ( value . dump ( ) = = " 42 " ) ;
}
TEST_CASE ( " json::wvalue::wvalue(std::int8_t) " ) {
std : : int8_t i = - 42 ;
json : : wvalue value = i ;
CHECK ( value . t ( ) = = json : : type : : Number ) ;
CHECK ( value . dump ( ) = = " -42 " ) ;
}
TEST_CASE ( " json::wvalue::wvalue(std::int16_t) " ) {
std : : int16_t i = - 42 ;
json : : wvalue value = i ;
CHECK ( value . t ( ) = = json : : type : : Number ) ;
CHECK ( value . dump ( ) = = " -42 " ) ;
}
TEST_CASE ( " json::wvalue::wvalue(std::int32_t) " ) {
std : : int32_t i = - 42 ;
json : : wvalue value = i ;
CHECK ( value . t ( ) = = json : : type : : Number ) ;
CHECK ( value . dump ( ) = = " -42 " ) ;
}
TEST_CASE ( " json::wvalue::wvalue(std::int64_t) " ) {
std : : int64_t i = - 42 ;
json : : wvalue value = i ;
CHECK ( value . t ( ) = = json : : type : : Number ) ;
CHECK ( value . dump ( ) = = " -42 " ) ;
}
TEST_CASE ( " json::wvalue::wvalue(float) " ) {
float f = 4.2 ;
json : : wvalue value = f ;
CHECK ( value . t ( ) = = json : : type : : Number ) ;
CHECK ( value . dump ( ) = = " 4.2 " ) ;
}
TEST_CASE ( " json::wvalue::wvalue(double) " ) {
double d = 4.2 ;
json : : wvalue value = d ;
CHECK ( value . t ( ) = = json : : type : : Number ) ;
CHECK ( value . dump ( ) = = " 4.2 " ) ;
}
TEST_CASE ( " json::wvalue::wvalue(char const*) " ) {
char const * str = " Hello world! " ;
json : : wvalue value = str ;
CHECK ( value . t ( ) = = json : : type : : String ) ;
CHECK ( value . dump ( ) = = " \" Hello world! \" " ) ;
}
TEST_CASE ( " json::wvalue::wvalue(std::string const&) " ) {
std : : string str = " Hello world! " ;
json : : wvalue value = str ;
CHECK ( value . t ( ) = = json : : type : : String ) ;
CHECK ( value . dump ( ) = = " \" Hello world! \" " ) ;
}
TEST_CASE ( " json::wvalue::wvalue(std::string&&) " ) {
std : : string str = " Hello world! " ;
json : : wvalue value = std : : move ( str ) ;
CHECK ( value . t ( ) = = json : : type : : String ) ;
CHECK ( value . dump ( ) = = " \" Hello world! \" " ) ;
}
2021-08-06 16:37:18 +00:00
TEST_CASE ( " json::wvalue::wvalue(std::initializer_list<std::pair<std::string const, json::wvalue>>) " ) {
json : : wvalue integer , number , truth , lie , null ;
integer = 2147483647 ;
number = 23.43 ;
truth = true ;
lie = false ;
/* initializer-list constructor. */
json : : wvalue value ( {
{ " integer " , integer } ,
{ " number " , number } ,
{ " truth " , truth } ,
{ " lie " , lie } ,
{ " null " , null }
} ) ;
CHECK ( value [ " integer " ] . dump ( ) = = integer . dump ( ) ) ;
CHECK ( value [ " number " ] . dump ( ) = = number . dump ( ) ) ;
CHECK ( value [ " truth " ] . dump ( ) = = truth . dump ( ) ) ;
CHECK ( value [ " lie " ] . dump ( ) = = lie . dump ( ) ) ;
CHECK ( value [ " null " ] . dump ( ) = = null . dump ( ) ) ;
}
TEST_CASE ( " json::wvalue::wvalue(std::[unordered_]map<std::string, json::wvalue> const&) " ) {
json : : wvalue integer , number , truth , lie , null ;
integer = 2147483647 ;
number = 23.43 ;
truth = true ;
lie = false ;
2021-08-20 00:57:21 +00:00
json : : wvalue : : object map ( {
2021-08-06 16:37:18 +00:00
{ " integer " , integer } ,
{ " number " , number } ,
{ " truth " , truth } ,
{ " lie " , lie } ,
{ " null " , null }
} ) ;
json : : wvalue value ( map ) ; /* copy-constructor. */
CHECK ( value [ " integer " ] . dump ( ) = = integer . dump ( ) ) ;
CHECK ( value [ " number " ] . dump ( ) = = number . dump ( ) ) ;
CHECK ( value [ " truth " ] . dump ( ) = = truth . dump ( ) ) ;
CHECK ( value [ " lie " ] . dump ( ) = = lie . dump ( ) ) ;
CHECK ( value [ " null " ] . dump ( ) = = null . dump ( ) ) ;
}
TEST_CASE ( " json::wvalue::wvalue(std::[unordered_]map<std::string, json::wvalue>&&) " ) {
json : : wvalue integer , number , truth , lie , null ;
integer = 2147483647 ;
number = 23.43 ;
truth = true ;
lie = false ;
2021-08-20 00:57:21 +00:00
json : : wvalue : : object map = { {
2021-08-06 16:37:18 +00:00
{ " integer " , integer } ,
{ " number " , number } ,
{ " truth " , truth } ,
{ " lie " , lie } ,
{ " null " , null }
} } ;
json : : wvalue value ( std : : move ( map ) ) ; /* move constructor. */
// json::wvalue value = std::move(map); /* move constructor. */
CHECK ( value [ " integer " ] . dump ( ) = = integer . dump ( ) ) ;
CHECK ( value [ " number " ] . dump ( ) = = number . dump ( ) ) ;
CHECK ( value [ " truth " ] . dump ( ) = = truth . dump ( ) ) ;
CHECK ( value [ " lie " ] . dump ( ) = = lie . dump ( ) ) ;
CHECK ( value [ " null " ] . dump ( ) = = null . dump ( ) ) ;
}
TEST_CASE ( " json::wvalue::operator=(std::initializer_list<std::pair<std::string const, json::wvalue>>) " ) {
json : : wvalue integer , number , truth , lie , null ;
integer = 2147483647 ;
number = 23.43 ;
truth = true ;
lie = false ;
json : : wvalue value ;
/* initializer-list assignment. */
value = {
{ " integer " , integer } ,
{ " number " , number } ,
{ " truth " , truth } ,
{ " lie " , lie } ,
{ " null " , null }
} ;
CHECK ( value [ " integer " ] . dump ( ) = = integer . dump ( ) ) ;
CHECK ( value [ " number " ] . dump ( ) = = number . dump ( ) ) ;
CHECK ( value [ " truth " ] . dump ( ) = = truth . dump ( ) ) ;
CHECK ( value [ " lie " ] . dump ( ) = = lie . dump ( ) ) ;
CHECK ( value [ " null " ] . dump ( ) = = null . dump ( ) ) ;
}
TEST_CASE ( " json::wvalue::operator=(std::[unordered_]map<std::string, json::wvalue> const&) " ) {
json : : wvalue integer , number , truth , lie , null ;
integer = 2147483647 ;
number = 23.43 ;
truth = true ;
lie = false ;
2021-08-20 00:57:21 +00:00
json : : wvalue : : object map ( {
2021-08-06 16:37:18 +00:00
{ " integer " , integer } ,
{ " number " , number } ,
{ " truth " , truth } ,
{ " lie " , lie } ,
{ " null " , null }
} ) ;
json : : wvalue value ;
value = map ; /* copy assignment. */
CHECK ( value [ " integer " ] . dump ( ) = = integer . dump ( ) ) ;
CHECK ( value [ " number " ] . dump ( ) = = number . dump ( ) ) ;
CHECK ( value [ " truth " ] . dump ( ) = = truth . dump ( ) ) ;
CHECK ( value [ " lie " ] . dump ( ) = = lie . dump ( ) ) ;
CHECK ( value [ " null " ] . dump ( ) = = null . dump ( ) ) ;
}
TEST_CASE ( " json::wvalue::operator=(std::[unordered_]map<std::string, json::wvalue>&&) " ) {
json : : wvalue integer , number , truth , lie , null ;
integer = 2147483647 ;
number = 23.43 ;
truth = true ;
lie = false ;
2021-08-20 00:57:21 +00:00
json : : wvalue : : object map ( {
2021-08-06 16:37:18 +00:00
{ " integer " , integer } ,
{ " number " , number } ,
{ " truth " , truth } ,
{ " lie " , lie } ,
{ " null " , null }
} ) ;
json : : wvalue value ;
value = std : : move ( map ) ; /* move assignment. */
CHECK ( value [ " integer " ] . dump ( ) = = integer . dump ( ) ) ;
CHECK ( value [ " number " ] . dump ( ) = = number . dump ( ) ) ;
CHECK ( value [ " truth " ] . dump ( ) = = truth . dump ( ) ) ;
CHECK ( value [ " lie " ] . dump ( ) = = lie . dump ( ) ) ;
CHECK ( value [ " null " ] . dump ( ) = = null . dump ( ) ) ;
}
2021-05-12 12:45:55 +00:00
TEST_CASE ( " json_vector " )
2021-08-20 00:57:21 +00:00
{
2021-05-12 12:45:55 +00:00
json : : wvalue a ;
json : : wvalue b ;
json : : wvalue c ;
json : : wvalue d ;
json : : wvalue e ;
json : : wvalue f ;
json : : wvalue g ;
json : : wvalue h ;
a = 5 ;
b = 6 ;
c = 7 ;
d = 8 ;
e = 4 ;
f = 3 ;
g = 2 ;
h = 1 ;
std : : vector < json : : wvalue > nums ;
nums . emplace_back ( a ) ;
nums . emplace_back ( b ) ;
nums . emplace_back ( c ) ;
nums . emplace_back ( d ) ;
nums . emplace_back ( e ) ;
nums . emplace_back ( f ) ;
nums . emplace_back ( g ) ;
nums . emplace_back ( h ) ;
json : : wvalue x ( nums ) ;
CHECK ( 8 = = x . size ( ) ) ;
CHECK ( " [5,6,7,8,4,3,2,1] " = = x . dump ( ) ) ;
}
2021-08-20 00:57:21 +00:00
TEST_CASE ( " json_list " )
{
json : : wvalue x ( json : : wvalue : : list ( { 5 , 6 , 7 , 8 , 4 , 3 , 2 , 1 } ) ) ;
CHECK ( 8 = = x . size ( ) ) ;
CHECK ( " [5,6,7,8,4,3,2,1] " = = x . dump ( ) ) ;
}
2020-10-18 16:59:15 +00:00
TEST_CASE ( " template_basic " )
2014-07-30 15:50:38 +00:00
{
2020-10-19 08:02:57 +00:00
auto t = crow : : mustache : : compile ( R " ---(attack of {{name}})--- " ) ;
crow : : mustache : : context ctx ;
ctx [ " name " ] = " killer tomatoes " ;
auto result = t . render ( ctx ) ;
2020-10-26 23:43:36 +00:00
CHECK ( " attack of killer tomatoes " = = result ) ;
2014-07-30 15:50:38 +00:00
}
2020-10-18 16:59:15 +00:00
TEST_CASE ( " template_load " )
2014-08-02 01:46:00 +00:00
{
2020-10-19 08:02:57 +00:00
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 ) ;
2020-10-26 23:43:36 +00:00
CHECK ( " attack of killer tomatoes " = = result ) ;
2020-10-19 08:02:57 +00:00
unlink ( " test.mustache " ) ;
2014-08-02 01:46:00 +00:00
}
2020-10-18 16:59:15 +00:00
TEST_CASE ( " black_magic " )
2014-09-07 22:07:53 +00:00
{
2020-10-19 08:02:57 +00:00
using namespace black_magic ;
static_assert (
std : : is_same < void , last_element_type < int , char , void > : : type > : : value ,
" last_element_type " ) ;
static_assert ( std : : is_same < char , pop_back < int , char , void > : : rebind <
last_element_type > : : type > : : value ,
" pop_back " ) ;
static_assert (
std : : is_same < int , pop_back < int , char , void > : : rebind < pop_back > : : rebind <
last_element_type > : : type > : : value ,
" pop_back " ) ;
2014-09-07 22:07:53 +00:00
}
2014-09-06 19:30:53 +00:00
struct NullMiddleware
{
2020-10-19 08:02:57 +00:00
struct context
{ } ;
2014-09-06 19:30:53 +00:00
2020-10-19 08:02:57 +00:00
template < typename AllContext >
void before_handle ( request & , response & , context & , AllContext & )
{ }
2014-09-06 19:30:53 +00:00
2020-10-19 08:02:57 +00:00
template < typename AllContext >
void after_handle ( request & , response & , context & , AllContext & )
{ }
2014-09-06 19:30:53 +00:00
} ;
2014-09-07 22:07:53 +00:00
struct NullSimpleMiddleware
{
2020-10-19 08:02:57 +00:00
struct context
{ } ;
2014-09-07 22:07:53 +00:00
2020-10-19 08:02:57 +00:00
void before_handle ( request & /*req*/ , response & /*res*/ , context & /*ctx*/ ) { }
2014-09-07 22:07:53 +00:00
2020-10-19 08:02:57 +00:00
void after_handle ( request & /*req*/ , response & /*res*/ , context & /*ctx*/ ) { }
2014-09-07 22:07:53 +00:00
} ;
2020-10-18 16:59:15 +00:00
TEST_CASE ( " middleware_simple " )
2014-09-06 19:30:53 +00:00
{
2020-10-19 08:02:57 +00:00
App < NullMiddleware , NullSimpleMiddleware > app ;
decltype ( app ) : : server_t server ( & app , LOCALHOST_ADDRESS , 45451 ) ;
CROW_ROUTE ( app , " / " )
( [ & ] ( const crow : : request & req ) {
app . get_context < NullMiddleware > ( req ) ;
app . get_context < NullSimpleMiddleware > ( req ) ;
return " " ;
} ) ;
2014-09-06 19:30:53 +00:00
}
struct IntSettingMiddleware
{
2020-10-19 08:02:57 +00:00
struct context
{
int val ;
} ;
template < typename AllContext >
void before_handle ( request & , response & , context & ctx , AllContext & )
{
ctx . val = 1 ;
}
template < typename AllContext >
void after_handle ( request & , response & , context & ctx , AllContext & )
{
ctx . val = 2 ;
}
2014-09-06 19:30:53 +00:00
} ;
2014-09-07 22:07:53 +00:00
std : : vector < std : : string > test_middleware_context_vector ;
struct FirstMW
{
2020-10-19 08:02:57 +00:00
struct context
{
std : : vector < string > v ;
} ;
void before_handle ( request & /*req*/ , response & /*res*/ , context & ctx )
{
ctx . v . push_back ( " 1 before " ) ;
}
void after_handle ( request & /*req*/ , response & /*res*/ , context & ctx )
{
ctx . v . push_back ( " 1 after " ) ;
test_middleware_context_vector = ctx . v ;
}
2014-09-07 22:07:53 +00:00
} ;
struct SecondMW
{
2020-10-19 08:02:57 +00:00
struct context
{ } ;
template < typename AllContext >
void before_handle ( request & req , response & res , context & , AllContext & all_ctx )
{
all_ctx . template get < FirstMW > ( ) . v . push_back ( " 2 before " ) ;
if ( req . url = = " /break " ) res . end ( ) ;
}
template < typename AllContext >
void after_handle ( request & , response & , context & , AllContext & all_ctx )
{
all_ctx . template get < FirstMW > ( ) . v . push_back ( " 2 after " ) ;
}
2014-09-07 22:07:53 +00:00
} ;
struct ThirdMW
{
2020-10-19 08:02:57 +00:00
struct context
{ } ;
template < typename AllContext >
void before_handle ( request & , response & , context & , AllContext & all_ctx )
{
all_ctx . template get < FirstMW > ( ) . v . push_back ( " 3 before " ) ;
}
template < typename AllContext >
void after_handle ( request & , response & , context & , AllContext & all_ctx )
{
all_ctx . template get < FirstMW > ( ) . v . push_back ( " 3 after " ) ;
}
2014-09-07 22:07:53 +00:00
} ;
2020-10-18 16:59:15 +00:00
TEST_CASE ( " middleware_context " )
2014-09-06 19:30:53 +00:00
{
2020-10-19 08:02:57 +00:00
static char buf [ 2048 ] ;
// SecondMW depends on FirstMW (it uses all_ctx.get<FirstMW>)
// so it leads to compile error if we remove FirstMW from definition
// App<IntSettingMiddleware, SecondMW> app;
// or change the order of FirstMW and SecondMW
// App<IntSettingMiddleware, SecondMW, FirstMW> app;
App < IntSettingMiddleware , FirstMW , SecondMW , ThirdMW > app ;
int x { } ;
CROW_ROUTE ( app , " / " )
( [ & ] ( const request & req ) {
2014-09-06 19:30:53 +00:00
{
2020-10-19 08:02:57 +00:00
auto & ctx = app . get_context < IntSettingMiddleware > ( req ) ;
x = ctx . val ;
2014-09-07 22:07:53 +00:00
}
{
2020-10-19 08:02:57 +00:00
auto & ctx = app . get_context < FirstMW > ( req ) ;
ctx . v . push_back ( " handle " ) ;
2014-09-07 22:07:53 +00:00
}
2020-10-19 08:02:57 +00:00
return " " ;
} ) ;
CROW_ROUTE ( app , " /break " )
( [ & ] ( const request & req ) {
2014-09-07 22:07:53 +00:00
{
2020-10-19 08:02:57 +00:00
auto & ctx = app . get_context < FirstMW > ( req ) ;
ctx . v . push_back ( " handle " ) ;
2014-09-06 19:30:53 +00:00
}
2020-10-19 08:02:57 +00:00
return " " ;
} ) ;
auto _ = async ( launch : : async ,
[ & ] { app . bindaddr ( LOCALHOST_ADDRESS ) . port ( 45451 ) . run ( ) ; } ) ;
app . wait_for_server_start ( ) ;
std : : string sendmsg = " GET / \r \n \r \n " ;
asio : : io_service is ;
{
asio : : ip : : tcp : : socket c ( is ) ;
c . connect ( asio : : ip : : tcp : : endpoint (
asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45451 ) ) ;
c . send ( asio : : buffer ( sendmsg ) ) ;
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
c . close ( ) ;
}
{
auto & out = test_middleware_context_vector ;
2020-10-26 23:43:36 +00:00
CHECK ( 1 = = x ) ;
CHECK ( 7 = = out . size ( ) ) ;
CHECK ( " 1 before " = = out [ 0 ] ) ;
CHECK ( " 2 before " = = out [ 1 ] ) ;
CHECK ( " 3 before " = = out [ 2 ] ) ;
CHECK ( " handle " = = out [ 3 ] ) ;
CHECK ( " 3 after " = = out [ 4 ] ) ;
CHECK ( " 2 after " = = out [ 5 ] ) ;
CHECK ( " 1 after " = = out [ 6 ] ) ;
2020-10-19 08:02:57 +00:00
}
std : : string sendmsg2 = " GET /break \r \n \r \n " ;
{
asio : : ip : : tcp : : socket c ( is ) ;
c . connect ( asio : : ip : : tcp : : endpoint (
asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45451 ) ) ;
c . send ( asio : : buffer ( sendmsg2 ) ) ;
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
c . close ( ) ;
}
{
auto & out = test_middleware_context_vector ;
2020-10-26 23:43:36 +00:00
CHECK ( 4 = = out . size ( ) ) ;
CHECK ( " 1 before " = = out [ 0 ] ) ;
CHECK ( " 2 before " = = out [ 1 ] ) ;
CHECK ( " 2 after " = = out [ 2 ] ) ;
CHECK ( " 1 after " = = out [ 3 ] ) ;
2020-10-19 08:02:57 +00:00
}
app . stop ( ) ;
2014-09-06 19:30:53 +00:00
}
2020-10-18 16:59:15 +00:00
TEST_CASE ( " middleware_cookieparser " )
2014-09-10 21:32:41 +00:00
{
2020-10-19 08:02:57 +00:00
static char buf [ 2048 ] ;
2014-09-10 21:32:41 +00:00
2020-10-19 08:02:57 +00:00
App < CookieParser > app ;
2014-09-10 21:32:41 +00:00
2020-10-19 08:02:57 +00:00
std : : string value1 ;
std : : string value2 ;
std : : string value3 ;
std : : string value4 ;
2014-09-10 21:32:41 +00:00
2020-10-19 08:02:57 +00:00
CROW_ROUTE ( app , " / " )
( [ & ] ( const request & req ) {
2014-09-10 21:32:41 +00:00
{
2020-10-19 08:02:57 +00:00
auto & ctx = app . get_context < CookieParser > ( req ) ;
value1 = ctx . get_cookie ( " key1 " ) ;
value2 = ctx . get_cookie ( " key2 " ) ;
value3 = ctx . get_cookie ( " key3 " ) ;
value4 = ctx . get_cookie ( " key4 " ) ;
2014-09-10 21:32:41 +00:00
}
2014-09-13 23:16:49 +00:00
2020-10-19 08:02:57 +00:00
return " " ;
} ) ;
auto _ = async ( launch : : async ,
[ & ] { app . bindaddr ( LOCALHOST_ADDRESS ) . port ( 45451 ) . run ( ) ; } ) ;
app . wait_for_server_start ( ) ;
std : : string sendmsg =
" GET / \r \n Cookie: key1=value1; key2= \" val=ue2 \" ; key3= \" val \" ue3 \" ; "
" key4= \" val \" ue4 \" \r \n \r \n " ;
asio : : io_service is ;
{
asio : : ip : : tcp : : socket c ( is ) ;
c . connect ( asio : : ip : : tcp : : endpoint (
asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45451 ) ) ;
c . send ( asio : : buffer ( sendmsg ) ) ;
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
c . close ( ) ;
}
{
2020-10-26 23:43:36 +00:00
CHECK ( " value1 " = = value1 ) ;
CHECK ( " val=ue2 " = = value2 ) ;
CHECK ( " val \" ue3 " = = value3 ) ;
CHECK ( " val \" ue4 " = = value4 ) ;
2020-10-19 08:02:57 +00:00
}
app . stop ( ) ;
2014-09-13 23:16:49 +00:00
}
2020-10-19 08:02:57 +00:00
TEST_CASE ( " bug_quick_repeated_request " )
2014-10-14 08:48:35 +00:00
{
2020-10-19 08:02:57 +00:00
static char buf [ 2048 ] ;
2014-10-14 08:48:35 +00:00
2020-10-19 08:02:57 +00:00
SimpleApp app ;
2014-10-14 08:48:35 +00:00
2020-10-19 08:02:57 +00:00
CROW_ROUTE ( app , " / " ) ( [ & ] { return " hello " ; } ) ;
2014-10-14 08:48:35 +00:00
2020-10-19 08:02:57 +00:00
auto _ = async ( launch : : async ,
[ & ] { app . bindaddr ( LOCALHOST_ADDRESS ) . port ( 45451 ) . run ( ) ; } ) ;
app . wait_for_server_start ( ) ;
std : : string sendmsg = " GET / HTTP/1.1 \r \n Host: localhost \r \n \r \n " ;
asio : : io_service is ;
{
std : : vector < std : : future < void > > v ;
for ( int i = 0 ; i < 5 ; i + + ) {
v . push_back ( async ( launch : : async , [ & ] {
2014-10-14 08:48:35 +00:00
asio : : ip : : tcp : : socket c ( is ) ;
2020-10-19 08:02:57 +00:00
c . connect ( asio : : ip : : tcp : : endpoint (
asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45451 ) ) ;
2014-10-14 08:48:35 +00:00
2020-10-19 08:02:57 +00:00
for ( int j = 0 ; j < 5 ; j + + ) {
c . send ( asio : : buffer ( sendmsg ) ) ;
2014-10-14 08:48:35 +00:00
2020-10-19 08:02:57 +00:00
size_t received = c . receive ( asio : : buffer ( buf , 2048 ) ) ;
2020-10-26 23:43:36 +00:00
CHECK ( " hello " = = std : : string ( buf + received - 5 , buf + received ) ) ;
2020-10-19 08:02:57 +00:00
}
2016-03-19 15:05:48 +00:00
c . close ( ) ;
2020-10-19 08:02:57 +00:00
} ) ) ;
2014-10-14 08:48:35 +00:00
}
2020-10-19 08:02:57 +00:00
}
app . stop ( ) ;
}
2016-03-19 15:05:48 +00:00
2020-10-19 08:02:57 +00:00
TEST_CASE ( " simple_url_params " )
{
static char buf [ 2048 ] ;
SimpleApp app ;
query_string last_url_params ;
CROW_ROUTE ( app , " /params " )
( [ & last_url_params ] ( const crow : : request & req ) {
last_url_params = std : : move ( req . url_params ) ;
return " OK " ;
} ) ;
/// params?h=1&foo=bar&lol&count[]=1&count[]=4&pew=5.2
auto _ = async ( launch : : async ,
[ & ] { app . bindaddr ( LOCALHOST_ADDRESS ) . port ( 45451 ) . run ( ) ; } ) ;
app . wait_for_server_start ( ) ;
asio : : io_service is ;
std : : string sendmsg ;
// check empty params
sendmsg = " GET /params \r \n \r \n " ;
{
asio : : ip : : tcp : : socket c ( is ) ;
c . connect ( asio : : ip : : tcp : : endpoint (
asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45451 ) ) ;
c . send ( asio : : buffer ( sendmsg ) ) ;
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
c . close ( ) ;
stringstream ss ;
ss < < last_url_params ;
2020-10-26 23:43:36 +00:00
CHECK ( " [ ] " = = ss . str ( ) ) ;
2020-10-19 08:02:57 +00:00
}
// check single presence
sendmsg = " GET /params?foobar \r \n \r \n " ;
{
asio : : ip : : tcp : : socket c ( is ) ;
c . connect ( asio : : ip : : tcp : : endpoint (
asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45451 ) ) ;
c . send ( asio : : buffer ( sendmsg ) ) ;
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
c . close ( ) ;
2020-10-26 23:43:36 +00:00
CHECK ( last_url_params . get ( " missing " ) = = nullptr ) ;
CHECK ( last_url_params . get ( " foobar " ) ! = nullptr ) ;
CHECK ( last_url_params . get_list ( " missing " ) . empty ( ) ) ;
2020-10-19 08:02:57 +00:00
}
// check multiple presence
sendmsg = " GET /params?foo&bar&baz \r \n \r \n " ;
{
asio : : ip : : tcp : : socket c ( is ) ;
c . connect ( asio : : ip : : tcp : : endpoint (
asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45451 ) ) ;
c . send ( asio : : buffer ( sendmsg ) ) ;
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
c . close ( ) ;
2020-10-26 23:43:36 +00:00
CHECK ( last_url_params . get ( " missing " ) = = nullptr ) ;
CHECK ( last_url_params . get ( " foo " ) ! = nullptr ) ;
CHECK ( last_url_params . get ( " bar " ) ! = nullptr ) ;
CHECK ( last_url_params . get ( " baz " ) ! = nullptr ) ;
2020-10-19 08:02:57 +00:00
}
// check single value
sendmsg = " GET /params?hello=world \r \n \r \n " ;
{
asio : : ip : : tcp : : socket c ( is ) ;
c . connect ( asio : : ip : : tcp : : endpoint (
asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45451 ) ) ;
c . send ( asio : : buffer ( sendmsg ) ) ;
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
c . close ( ) ;
2020-10-26 23:43:36 +00:00
CHECK ( string ( last_url_params . get ( " hello " ) ) = = " world " ) ;
2020-10-19 08:02:57 +00:00
}
// check multiple value
sendmsg = " GET /params?hello=world&left=right&up=down \r \n \r \n " ;
{
asio : : ip : : tcp : : socket c ( is ) ;
c . connect ( asio : : ip : : tcp : : endpoint (
asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45451 ) ) ;
c . send ( asio : : buffer ( sendmsg ) ) ;
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
c . close ( ) ;
2021-05-12 12:45:55 +00:00
query_string mutable_params ( last_url_params ) ;
CHECK ( string ( mutable_params . get ( " hello " ) ) = = " world " ) ;
CHECK ( string ( mutable_params . get ( " left " ) ) = = " right " ) ;
CHECK ( string ( mutable_params . get ( " up " ) ) = = " down " ) ;
std : : string z = mutable_params . pop ( " left " ) ;
CHECK ( z = = " right " ) ;
CHECK ( mutable_params . get ( " left " ) = = nullptr ) ;
2020-10-19 08:02:57 +00:00
}
// check multiple value, multiple types
sendmsg = " GET /params?int=100&double=123.45&boolean=1 \r \n \r \n " ;
{
asio : : ip : : tcp : : socket c ( is ) ;
c . connect ( asio : : ip : : tcp : : endpoint (
asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45451 ) ) ;
c . send ( asio : : buffer ( sendmsg ) ) ;
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
c . close ( ) ;
2020-10-26 23:43:36 +00:00
CHECK ( boost : : lexical_cast < int > ( last_url_params . get ( " int " ) ) = = 100 ) ;
CHECK ( boost : : lexical_cast < double > ( last_url_params . get ( " double " ) ) = =
2020-10-19 08:02:57 +00:00
123.45 ) ;
2020-10-26 23:43:36 +00:00
CHECK ( boost : : lexical_cast < bool > ( last_url_params . get ( " boolean " ) ) ) ;
2020-10-19 08:02:57 +00:00
}
// check single array value
sendmsg = " GET /params?tmnt[]=leonardo \r \n \r \n " ;
{
asio : : ip : : tcp : : socket c ( is ) ;
c . connect ( asio : : ip : : tcp : : endpoint (
asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45451 ) ) ;
c . send ( asio : : buffer ( sendmsg ) ) ;
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
c . close ( ) ;
2020-10-26 23:43:36 +00:00
CHECK ( last_url_params . get ( " tmnt " ) = = nullptr ) ;
CHECK ( last_url_params . get_list ( " tmnt " ) . size ( ) = = 1 ) ;
CHECK ( string ( last_url_params . get_list ( " tmnt " ) [ 0 ] ) = = " leonardo " ) ;
2020-10-19 08:02:57 +00:00
}
// check multiple array value
2021-05-12 12:45:55 +00:00
sendmsg = " GET /params?tmnt[]=leonardo&tmnt[]=donatello&tmnt[]=raphael \r \n \r \n " ;
2020-10-19 08:02:57 +00:00
{
asio : : ip : : tcp : : socket c ( is ) ;
c . connect ( asio : : ip : : tcp : : endpoint (
asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45451 ) ) ;
c . send ( asio : : buffer ( sendmsg ) ) ;
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
c . close ( ) ;
2020-10-26 23:43:36 +00:00
CHECK ( last_url_params . get_list ( " tmnt " ) . size ( ) = = 3 ) ;
CHECK ( string ( last_url_params . get_list ( " tmnt " ) [ 0 ] ) = = " leonardo " ) ;
CHECK ( string ( last_url_params . get_list ( " tmnt " ) [ 1 ] ) = = " donatello " ) ;
CHECK ( string ( last_url_params . get_list ( " tmnt " ) [ 2 ] ) = = " raphael " ) ;
2021-05-12 12:45:55 +00:00
CHECK ( last_url_params . pop_list ( " tmnt " ) . size ( ) = = 3 ) ;
CHECK ( last_url_params . get_list ( " tmnt " ) . size ( ) = = 0 ) ;
}
// check dictionary value
sendmsg = " GET /params?kees[one]=vee1&kees[two]=vee2&kees[three]=vee3 \r \n \r \n " ;
{
asio : : ip : : tcp : : socket c ( is ) ;
c . connect ( asio : : ip : : tcp : : endpoint ( asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45451 ) ) ;
c . send ( asio : : buffer ( sendmsg ) ) ;
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
c . close ( ) ;
CHECK ( last_url_params . get_dict ( " kees " ) . size ( ) = = 3 ) ;
CHECK ( string ( last_url_params . get_dict ( " kees " ) [ " one " ] ) = = " vee1 " ) ;
CHECK ( string ( last_url_params . get_dict ( " kees " ) [ " two " ] ) = = " vee2 " ) ;
CHECK ( string ( last_url_params . get_dict ( " kees " ) [ " three " ] ) = = " vee3 " ) ;
CHECK ( last_url_params . pop_dict ( " kees " ) . size ( ) = = 3 ) ;
CHECK ( last_url_params . get_dict ( " kees " ) . size ( ) = = 0 ) ;
2020-10-19 08:02:57 +00:00
}
app . stop ( ) ;
2014-10-14 08:48:35 +00:00
}
2020-10-18 16:59:15 +00:00
TEST_CASE ( " route_dynamic " )
2015-02-18 15:57:01 +00:00
{
2020-10-19 08:02:57 +00:00
SimpleApp app ;
int x = 1 ;
app . route_dynamic ( " / " ) ( [ & ] {
x = 2 ;
return " " ;
} ) ;
app . route_dynamic ( " /set4 " ) ( [ & ] ( const request & ) {
x = 4 ;
return " " ;
} ) ;
app . route_dynamic ( " /set5 " ) ( [ & ] ( const request & , response & res ) {
x = 5 ;
res . end ( ) ;
} ) ;
app . route_dynamic ( " /set_int/<int> " ) ( [ & ] ( int y ) {
x = y ;
return " " ;
} ) ;
try {
app . route_dynamic ( " /invalid_test/<double>/<path> " ) ( [ ] ( ) { return " " ; } ) ;
FAIL_CHECK ( ) ;
} catch ( std : : exception & ) {
}
// app is in an invalid state when route_dynamic throws an exception.
try {
app . validate ( ) ;
FAIL_CHECK ( ) ;
} catch ( std : : exception & ) {
}
2015-02-19 03:16:28 +00:00
2020-10-19 08:02:57 +00:00
{
request req ;
response res ;
req . url = " / " ;
app . handle ( req , res ) ;
2020-10-26 23:43:36 +00:00
CHECK ( x = = 2 ) ;
2020-10-19 08:02:57 +00:00
}
{
request req ;
response res ;
req . url = " /set_int/42 " ;
app . handle ( req , res ) ;
2020-10-26 23:43:36 +00:00
CHECK ( x = = 42 ) ;
2020-10-19 08:02:57 +00:00
}
{
request req ;
response res ;
req . url = " /set5 " ;
app . handle ( req , res ) ;
2020-10-26 23:43:36 +00:00
CHECK ( x = = 5 ) ;
2020-10-19 08:02:57 +00:00
}
{
request req ;
response res ;
req . url = " /set4 " ;
app . handle ( req , res ) ;
2020-10-26 23:43:36 +00:00
CHECK ( x = = 4 ) ;
2020-10-19 08:02:57 +00:00
}
2015-02-18 15:57:01 +00:00
}
2020-10-31 00:05:24 +00:00
TEST_CASE ( " multipart " )
{
std : : string test_string = " --CROW-BOUNDARY \r \n Content-Disposition: form-data; name= \" hello \" \r \n \r \n world \r \n --CROW-BOUNDARY \r \n Content-Disposition: form-data; name= \" world \" \r \n \r \n hello \r \n --CROW-BOUNDARY \r \n Content-Disposition: form-data; name= \" multiline \" \r \n \r \n text \n text \n text \r \n --CROW-BOUNDARY-- \r \n " ;
SimpleApp app ;
CROW_ROUTE ( app , " /multipart " )
( [ ] ( const crow : : request & req , crow : : response & res )
{
multipart : : message msg ( req ) ;
res . add_header ( " Content-Type " , " multipart/form-data; boundary=CROW-BOUNDARY " ) ;
res . body = msg . dump ( ) ;
res . end ( ) ;
} ) ;
app . validate ( ) ;
{
request req ;
response res ;
req . url = " /multipart " ;
req . add_header ( " Content-Type " , " multipart/form-data; boundary=CROW-BOUNDARY " ) ;
req . body = test_string ;
app . handle ( req , res ) ;
CHECK ( test_string = = res . body ) ;
}
}
2020-10-18 16:59:15 +00:00
TEST_CASE ( " send_file " )
2020-10-12 21:52:15 +00:00
{
2020-10-31 00:05:24 +00:00
struct stat statbuf ;
stat ( " tests/img/cat.jpg " , & statbuf ) ;
2020-10-19 08:02:57 +00:00
SimpleApp app ;
2020-10-12 21:52:15 +00:00
2020-10-19 08:02:57 +00:00
CROW_ROUTE ( app , " /jpg " )
( [ ] ( const crow : : request & , crow : : response & res ) {
res . set_static_file_info ( " tests/img/cat.jpg " ) ;
res . end ( ) ;
} ) ;
2020-10-12 21:52:15 +00:00
2020-10-19 08:02:57 +00:00
CROW_ROUTE ( app , " /jpg2 " )
( [ ] ( const crow : : request & , crow : : response & res ) {
res . set_static_file_info (
" tests/img/cat2.jpg " ) ; // This file is nonexistent on purpose
res . end ( ) ;
} ) ;
2020-10-12 21:52:15 +00:00
2020-10-19 08:02:57 +00:00
app . validate ( ) ;
2020-10-12 21:52:15 +00:00
2020-10-26 23:41:29 +00:00
//File not found check
{
request req ;
response res ;
req . url = " /jpg2 " ;
app . handle ( req , res ) ;
2020-10-26 23:43:36 +00:00
CHECK ( 404 = = res . code ) ;
2020-10-26 23:41:29 +00:00
}
//Headers check
2020-10-19 08:02:57 +00:00
{
request req ;
response res ;
2020-10-12 21:52:15 +00:00
2020-10-19 08:02:57 +00:00
req . url = " /jpg " ;
2020-10-12 21:52:15 +00:00
2020-10-19 08:02:57 +00:00
app . handle ( req , res ) ;
2020-10-12 21:52:15 +00:00
2020-10-26 23:43:36 +00:00
CHECK ( 200 = = res . code ) ;
CHECK ( " image/jpeg " = = res . headers . find ( " Content-Type " ) - > second ) ;
CHECK ( to_string ( statbuf . st_size ) = =
2020-10-19 08:02:57 +00:00
res . headers . find ( " Content-Length " ) - > second ) ;
}
2020-10-12 21:52:15 +00:00
2020-10-31 00:05:24 +00:00
//TODO test content
2020-10-12 21:52:15 +00:00
}
2020-10-21 01:02:09 +00:00
TEST_CASE ( " stream_response " )
{
SimpleApp app ;
2021-07-28 19:31:08 +00:00
2021-10-06 10:51:17 +00:00
const std : : string keyword_ = " hello " ;
const size_t repetitions = 250000 ;
const size_t key_response_size = keyword_ . length ( ) * repetitions ;
2021-07-28 19:31:08 +00:00
std : : string key_response ;
2021-10-06 10:32:35 +00:00
2021-10-06 10:51:17 +00:00
for ( size_t i = 0 ; i < repetitions ; i + + )
2021-07-28 19:31:08 +00:00
key_response + = keyword_ ;
2020-10-21 01:02:09 +00:00
CROW_ROUTE ( app , " /test " )
2021-07-28 19:31:08 +00:00
( [ & key_response ] ( const crow : : request & , crow : : response & res )
2020-10-21 01:02:09 +00:00
{
res . body = key_response ;
res . end ( ) ;
} ) ;
app . validate ( ) ;
2020-10-31 00:05:24 +00:00
//running the test on a separate thread to allow the client to sleep
2021-10-06 10:32:35 +00:00
std : : thread runTest ( [ & app , & key_response , key_response_size ] ( ) {
2020-10-27 19:53:58 +00:00
2020-10-26 23:39:20 +00:00
auto _ = async ( launch : : async ,
[ & ] { app . bindaddr ( LOCALHOST_ADDRESS ) . port ( 45451 ) . run ( ) ; } ) ;
app . wait_for_server_start ( ) ;
asio : : io_service is ;
std : : string sendmsg ;
2020-10-21 01:02:09 +00:00
2020-10-31 00:05:24 +00:00
//Total bytes received
unsigned int received = 0 ;
2020-10-26 23:39:20 +00:00
sendmsg = " GET /test \r \n \r \n " ;
{
2020-10-31 00:05:24 +00:00
asio : : streambuf b ;
2020-10-26 23:39:20 +00:00
asio : : ip : : tcp : : socket c ( is ) ;
c . connect ( asio : : ip : : tcp : : endpoint (
asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45451 ) ) ;
c . send ( asio : : buffer ( sendmsg ) ) ;
2020-10-31 00:05:24 +00:00
//consuming the headers, since we don't need those for the test
static char buf [ 2048 ] ;
2021-10-06 10:32:35 +00:00
size_t received_headers_bytes = 0 ;
2021-10-05 12:13:38 +00:00
// magic number is 102 (it's the size of the headers, which is how much this line below needs to read)
2021-10-06 10:32:35 +00:00
const size_t headers_bytes = 102 ;
while ( received_headers_bytes < headers_bytes )
received_headers_bytes + = c . receive ( asio : : buffer ( buf , 2048 ) ) ;
received + = received_headers_bytes - headers_bytes ; //add any extra that might have been received to the proper received count
2021-10-05 12:13:38 +00:00
2020-10-27 19:53:58 +00:00
2021-10-06 10:32:35 +00:00
while ( received < key_response_size )
2020-10-27 19:53:58 +00:00
{
2020-10-31 00:05:24 +00:00
asio : : streambuf : : mutable_buffers_type bufs = b . prepare ( 16384 ) ;
2021-10-05 12:13:38 +00:00
2020-10-31 00:05:24 +00:00
size_t n = c . receive ( bufs ) ;
b . commit ( n ) ;
received + = n ;
2021-10-05 12:13:38 +00:00
2020-10-31 00:05:24 +00:00
std : : istream is ( & b ) ;
std : : string s ;
is > > s ;
2020-10-27 19:53:58 +00:00
2021-10-05 12:13:38 +00:00
CHECK ( key_response . substr ( received - n , n ) = = s ) ;
2020-10-21 01:02:09 +00:00
2021-10-05 12:13:38 +00:00
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 20 ) ) ;
2020-10-31 00:05:24 +00:00
}
2020-10-21 01:02:09 +00:00
}
2020-10-26 23:39:20 +00:00
app . stop ( ) ;
2020-10-27 19:53:58 +00:00
} ) ;
runTest . join ( ) ;
2020-10-21 01:02:09 +00:00
}
2020-11-09 01:47:41 +00:00
TEST_CASE ( " websocket " )
{
static std : : string http_message = " GET /ws HTTP/1.1 \r \n Connection: keep-alive, Upgrade \r \n upgrade: websocket \r \n Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== \r \n Sec-WebSocket-Version: 13 \r \n \r \n " ;
static bool connected { false } ;
SimpleApp app ;
CROW_ROUTE ( app , " /ws " ) . websocket ( )
. onopen ( [ & ] ( websocket : : connection & ) {
connected = true ;
CROW_LOG_INFO < < " Connected websocket and value is " < < connected ;
} )
. onmessage ( [ & ] ( websocket : : connection & conn , const std : : string & message , bool isbin ) {
CROW_LOG_INFO < < " Message is \" " < < message < < ' \" ' ;
if ( ! isbin & & message = = " PINGME " )
conn . send_ping ( " " ) ;
else if ( ! isbin & & message = = " Hello " )
conn . send_text ( " Hello back " ) ;
else if ( isbin & & message = = " Hello bin " )
conn . send_binary ( " Hello back bin " ) ;
} )
. onclose ( [ & ] ( websocket : : connection & , const std : : string & ) {
CROW_LOG_INFO < < " Closing websocket " ;
} ) ;
app . validate ( ) ;
auto _ = async ( launch : : async ,
[ & ] { app . bindaddr ( LOCALHOST_ADDRESS ) . port ( 45451 ) . run ( ) ; } ) ;
app . wait_for_server_start ( ) ;
asio : : io_service is ;
asio : : ip : : tcp : : socket c ( is ) ;
c . connect ( asio : : ip : : tcp : : endpoint (
asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45451 ) ) ;
char buf [ 2048 ] ;
//----------Handshake----------
{
std : : fill_n ( buf , 2048 , 0 ) ;
c . send ( asio : : buffer ( http_message ) ) ;
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 5 ) ) ;
CHECK ( connected ) ;
}
//----------Pong----------
{
std : : fill_n ( buf , 2048 , 0 ) ;
char ping_message [ 2 ] ( " \x89 " ) ;
c . send ( asio : : buffer ( ping_message , 2 ) ) ;
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 5 ) ) ;
CHECK ( ( int ) ( unsigned char ) buf [ 0 ] = = 0x8A ) ;
}
//----------Ping----------
{
std : : fill_n ( buf , 2048 , 0 ) ;
char not_ping_message [ 2 + 6 + 1 ] ( " \x81 \x06 "
" PINGME " ) ;
c . send ( asio : : buffer ( not_ping_message , 8 ) ) ;
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 5 ) ) ;
CHECK ( ( int ) ( unsigned char ) buf [ 0 ] = = 0x89 ) ;
}
//----------Text----------
{
std : : fill_n ( buf , 2048 , 0 ) ;
char text_message [ 2 + 5 + 1 ] ( " \x81 \x05 "
" Hello " ) ;
c . send ( asio : : buffer ( text_message , 7 ) ) ;
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 5 ) ) ;
std : : string checkstring ( std : : string ( buf ) . substr ( 0 , 12 ) ) ;
CHECK ( checkstring = = " \x81 \x0A Hello back " ) ;
}
//----------Binary----------
{
std : : fill_n ( buf , 2048 , 0 ) ;
char bin_message [ 2 + 9 + 1 ] ( " \x82 \x09 "
" Hello bin " ) ;
c . send ( asio : : buffer ( bin_message , 11 ) ) ;
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 5 ) ) ;
std : : string checkstring2 ( std : : string ( buf ) . substr ( 0 , 16 ) ) ;
CHECK ( checkstring2 = = " \x82 \x0E Hello back bin " ) ;
}
//----------Masked Text----------
{
std : : fill_n ( buf , 2048 , 0 ) ;
char text_masked_message [ 2 + 4 + 5 + 1 ] ( " \x81 \x85 "
" \x67 \xc6 \x69 \x73 "
" \x2f \xa3 \x05 \x1f \x08 " ) ;
c . send ( asio : : buffer ( text_masked_message , 11 ) ) ;
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 5 ) ) ;
std : : string checkstring3 ( std : : string ( buf ) . substr ( 0 , 12 ) ) ;
CHECK ( checkstring3 = = " \x81 \x0A Hello back " ) ;
}
//----------Masked Binary----------
{
std : : fill_n ( buf , 2048 , 0 ) ;
char bin_masked_message [ 2 + 4 + 9 + 1 ] ( " \x82 \x89 "
" \x67 \xc6 \x69 \x73 "
" \x2f \xa3 \x05 \x1f \x08 \xe6 \x0b \x1a \x09 " ) ;
c . send ( asio : : buffer ( bin_masked_message , 15 ) ) ;
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 5 ) ) ;
std : : string checkstring4 ( std : : string ( buf ) . substr ( 0 , 16 ) ) ;
CHECK ( checkstring4 = = " \x82 \x0E Hello back bin " ) ;
}
//----------Close----------
{
std : : fill_n ( buf , 2048 , 0 ) ;
char close_message [ 10 ] ( " \x88 " ) ; //I do not know why, but the websocket code does not read this unless it's longer than 4 or so bytes
c . send ( asio : : buffer ( close_message , 10 ) ) ;
c . receive ( asio : : buffer ( buf , 2048 ) ) ;
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 5 ) ) ;
CHECK ( ( int ) ( unsigned char ) buf [ 0 ] = = 0x88 ) ;
}
app . stop ( ) ;
}
2021-01-02 19:12:04 +00:00
2021-08-30 00:25:30 +00:00
# ifdef CROW_ENABLE_COMPRESSION
2021-01-02 19:12:04 +00:00
TEST_CASE ( " zlib_compression " )
{
static char buf_deflate [ 2048 ] ;
static char buf_gzip [ 2048 ] ;
SimpleApp app_deflate , app_gzip ;
std : : string expected_string = " Although moreover mistaken kindness me feelings do be marianne. Son over own nay with tell they cold upon are. "
" Cordial village and settled she ability law herself. Finished why bringing but sir bachelor unpacked any thoughts. "
" Unpleasing unsatiable particular inquietude did nor sir. Get his declared appetite distance his together now families. "
" Friends am himself at on norland it viewing. Suspected elsewhere you belonging continued commanded she. " ;
// test deflate
CROW_ROUTE ( app_deflate , " /test_compress " ) ( [ & ] ( ) {
return expected_string ;
} ) ;
CROW_ROUTE ( app_deflate , " /test " ) ( [ & ] ( const request & , response & res ) {
res . compressed = false ;
res . body = expected_string ;
res . end ( ) ;
} ) ;
// test gzip
CROW_ROUTE ( app_gzip , " /test_compress " ) ( [ & ] ( ) {
return expected_string ;
} ) ;
CROW_ROUTE ( app_gzip , " /test " ) ( [ & ] ( const request & , response & res ) {
res . compressed = false ;
res . body = expected_string ;
res . end ( ) ;
} ) ;
auto t1 = async ( launch : : async , [ & ] { app_deflate . bindaddr ( LOCALHOST_ADDRESS ) . port ( 45451 ) . use_compression ( compression : : algorithm : : DEFLATE ) . run ( ) ; } ) ;
auto t2 = async ( launch : : async , [ & ] { app_gzip . bindaddr ( LOCALHOST_ADDRESS ) . port ( 45452 ) . use_compression ( compression : : algorithm : : GZIP ) . run ( ) ; } ) ;
app_deflate . wait_for_server_start ( ) ;
app_gzip . wait_for_server_start ( ) ;
std : : string test_compress_msg = " GET /test_compress \r \n Accept-Encoding: gzip, deflate \r \n \r \n " ;
std : : string test_compress_no_header_msg = " GET /test_compress \r \n \r \n " ;
std : : string test_none_msg = " GET /test \r \n \r \n " ;
auto inflate_string = [ ] ( std : : string const & deflated_string ) - > const std : : string
{
std : : string inflated_string ;
Bytef tmp [ 8192 ] ;
z_stream zstream { } ;
zstream . avail_in = deflated_string . size ( ) ;
// Nasty const_cast but zlib won't alter its contents
zstream . next_in = const_cast < Bytef * > ( reinterpret_cast < Bytef const * > ( deflated_string . c_str ( ) ) ) ;
// Initialize with automatic header detection, for gzip support
if ( : : inflateInit2 ( & zstream , MAX_WBITS | 32 ) = = Z_OK )
{
do
{
zstream . avail_out = sizeof ( tmp ) ;
zstream . next_out = & tmp [ 0 ] ;
auto ret = : : inflate ( & zstream , Z_NO_FLUSH ) ;
if ( ret = = Z_OK | | ret = = Z_STREAM_END )
{
std : : copy ( & tmp [ 0 ] , & tmp [ sizeof ( tmp ) - zstream . avail_out ] , std : : back_inserter ( inflated_string ) ) ;
}
else
{
// Something went wrong with inflate; make sure we return an empty string
inflated_string . clear ( ) ;
break ;
}
} while ( zstream . avail_out = = 0 ) ;
// Free zlib's internal memory
: : inflateEnd ( & zstream ) ;
}
return inflated_string ;
} ;
std : : string response_deflate ;
std : : string response_gzip ;
std : : string response_deflate_no_header ;
std : : string response_gzip_no_header ;
std : : string response_deflate_none ;
std : : string response_gzip_none ;
auto on_body = [ ] ( http_parser * parser , const char * body , size_t body_length ) - > int
{
std : : string * body_ptr = reinterpret_cast < std : : string * > ( parser - > data ) ;
* body_ptr = std : : string ( body , body + body_length ) ;
return 0 ;
} ;
http_parser_settings settings { } ;
settings . on_body = on_body ;
asio : : io_service is ;
{
// Compression
{
asio : : ip : : tcp : : socket socket [ 2 ] = { asio : : ip : : tcp : : socket ( is ) , asio : : ip : : tcp : : socket ( is ) } ;
socket [ 0 ] . connect ( asio : : ip : : tcp : : endpoint ( asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45451 ) ) ;
socket [ 1 ] . connect ( asio : : ip : : tcp : : endpoint ( asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45452 ) ) ;
socket [ 0 ] . send ( asio : : buffer ( test_compress_msg ) ) ;
socket [ 1 ] . send ( asio : : buffer ( test_compress_msg ) ) ;
size_t bytes_deflate = socket [ 0 ] . receive ( asio : : buffer ( buf_deflate , 2048 ) ) ;
size_t bytes_gzip = socket [ 1 ] . receive ( asio : : buffer ( buf_gzip , 2048 ) ) ;
http_parser parser [ 2 ] = { { } , { } } ;
http_parser_init ( & parser [ 0 ] , HTTP_RESPONSE ) ;
http_parser_init ( & parser [ 1 ] , HTTP_RESPONSE ) ;
parser [ 0 ] . data = reinterpret_cast < void * > ( & response_deflate ) ;
parser [ 1 ] . data = reinterpret_cast < void * > ( & response_gzip ) ;
http_parser_execute ( & parser [ 0 ] , & settings , buf_deflate , bytes_deflate ) ;
http_parser_execute ( & parser [ 1 ] , & settings , buf_gzip , bytes_gzip ) ;
response_deflate = inflate_string ( response_deflate ) ;
response_gzip = inflate_string ( response_gzip ) ;
socket [ 0 ] . close ( ) ;
socket [ 1 ] . close ( ) ;
}
// No Header (thus no compression)
{
asio : : ip : : tcp : : socket socket [ 2 ] = { asio : : ip : : tcp : : socket ( is ) , asio : : ip : : tcp : : socket ( is ) } ;
socket [ 0 ] . connect ( asio : : ip : : tcp : : endpoint ( asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45451 ) ) ;
socket [ 1 ] . connect ( asio : : ip : : tcp : : endpoint ( asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45452 ) ) ;
socket [ 0 ] . send ( asio : : buffer ( test_compress_no_header_msg ) ) ;
socket [ 1 ] . send ( asio : : buffer ( test_compress_no_header_msg ) ) ;
size_t bytes_deflate = socket [ 0 ] . receive ( asio : : buffer ( buf_deflate , 2048 ) ) ;
size_t bytes_gzip = socket [ 1 ] . receive ( asio : : buffer ( buf_gzip , 2048 ) ) ;
http_parser parser [ 2 ] = { { } , { } } ;
http_parser_init ( & parser [ 0 ] , HTTP_RESPONSE ) ;
http_parser_init ( & parser [ 1 ] , HTTP_RESPONSE ) ;
parser [ 0 ] . data = reinterpret_cast < void * > ( & response_deflate_no_header ) ;
parser [ 1 ] . data = reinterpret_cast < void * > ( & response_gzip_no_header ) ;
http_parser_execute ( & parser [ 0 ] , & settings , buf_deflate , bytes_deflate ) ;
http_parser_execute ( & parser [ 1 ] , & settings , buf_gzip , bytes_gzip ) ;
socket [ 0 ] . close ( ) ;
socket [ 1 ] . close ( ) ;
}
// No compression
{
asio : : ip : : tcp : : socket socket [ 2 ] = { asio : : ip : : tcp : : socket ( is ) , asio : : ip : : tcp : : socket ( is ) } ;
socket [ 0 ] . connect ( asio : : ip : : tcp : : endpoint ( asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45451 ) ) ;
socket [ 1 ] . connect ( asio : : ip : : tcp : : endpoint ( asio : : ip : : address : : from_string ( LOCALHOST_ADDRESS ) , 45452 ) ) ;
socket [ 0 ] . send ( asio : : buffer ( test_none_msg ) ) ;
socket [ 1 ] . send ( asio : : buffer ( test_none_msg ) ) ;
size_t bytes_deflate = socket [ 0 ] . receive ( asio : : buffer ( buf_deflate , 2048 ) ) ;
size_t bytes_gzip = socket [ 1 ] . receive ( asio : : buffer ( buf_gzip , 2048 ) ) ;
http_parser parser [ 2 ] = { { } , { } } ;
http_parser_init ( & parser [ 0 ] , HTTP_RESPONSE ) ;
http_parser_init ( & parser [ 1 ] , HTTP_RESPONSE ) ;
parser [ 0 ] . data = reinterpret_cast < void * > ( & response_deflate_none ) ;
parser [ 1 ] . data = reinterpret_cast < void * > ( & response_gzip_none ) ;
http_parser_execute ( & parser [ 0 ] , & settings , buf_deflate , bytes_deflate ) ;
http_parser_execute ( & parser [ 1 ] , & settings , buf_gzip , bytes_gzip ) ;
socket [ 0 ] . close ( ) ;
socket [ 1 ] . close ( ) ;
}
}
{
CHECK ( expected_string = = response_deflate ) ;
CHECK ( expected_string = = response_gzip ) ;
CHECK ( expected_string = = response_deflate_no_header ) ;
CHECK ( expected_string = = response_gzip_no_header ) ;
CHECK ( expected_string = = response_deflate_none ) ;
CHECK ( expected_string = = response_gzip_none ) ;
}
app_deflate . stop ( ) ;
app_gzip . stop ( ) ;
}
2021-08-30 00:25:30 +00:00
# endif
2021-04-12 05:25:09 +00:00
TEST_CASE ( " catchall " )
{
SimpleApp app ;
SimpleApp app2 ;
CROW_ROUTE ( app , " /place " ) ( [ ] ( ) { return " place " ; } ) ;
2021-08-21 01:49:17 +00:00
CROW_CATCHALL_ROUTE ( app ) ( [ ] ( response & res ) { res . body = " !place " ; } ) ;
2021-04-12 05:25:09 +00:00
CROW_ROUTE ( app2 , " /place " ) ( [ ] ( ) { return " place " ; } ) ;
app . validate ( ) ;
app2 . validate ( ) ;
{
request req ;
response res ;
req . url = " /place " ;
app . handle ( req , res ) ;
CHECK ( 200 = = res . code ) ;
}
{
request req ;
response res ;
req . url = " /another_place " ;
app . handle ( req , res ) ;
2021-08-21 01:49:17 +00:00
CHECK ( 404 = = res . code ) ;
2021-04-12 05:25:09 +00:00
CHECK ( " !place " = = res . body ) ;
}
{
request req ;
response res ;
req . url = " /place " ;
app2 . handle ( req , res ) ;
CHECK ( 200 = = res . code ) ;
}
{
request req ;
response res ;
req . url = " /another_place " ;
app2 . handle ( req , res ) ;
CHECK ( 404 = = res . code ) ;
}
}
2021-07-28 19:31:08 +00:00
TEST_CASE ( " blueprint " )
{
SimpleApp app ;
crow : : Blueprint bp ( " bp_prefix " , " cstat " , " ctemplate " ) ;
crow : : Blueprint bp_not_sub ( " bp_prefix_second " ) ;
crow : : Blueprint sub_bp ( " bp2 " , " csstat " , " cstemplate " ) ;
crow : : Blueprint sub_sub_bp ( " bp3 " ) ;
CROW_BP_ROUTE ( sub_bp , " /hello " )
( [ ] ( ) {
return " Hello world! " ;
} ) ;
CROW_BP_ROUTE ( bp_not_sub , " /hello " )
( [ ] ( ) {
return " Hello world! " ;
} ) ;
CROW_BP_ROUTE ( sub_sub_bp , " /hi " )
( [ ] ( ) {
return " Hi world! " ;
} ) ;
CROW_BP_CATCHALL_ROUTE ( sub_bp ) ( [ ] ( ) { return response ( 200 , " WRONG!! " ) ; } ) ;
app . register_blueprint ( bp ) ;
app . register_blueprint ( bp_not_sub ) ;
bp . register_blueprint ( sub_bp ) ;
sub_bp . register_blueprint ( sub_sub_bp ) ;
app . validate ( ) ;
{
request req ;
response res ;
req . url = " /bp_prefix/bp2/hello " ;
app . handle ( req , res ) ;
CHECK ( " Hello world! " = = res . body ) ;
}
{
request req ;
response res ;
req . url = " /bp_prefix_second/hello " ;
app . handle ( req , res ) ;
CHECK ( " Hello world! " = = res . body ) ;
}
{
request req ;
response res ;
req . url = " /bp_prefix/bp2/bp3/hi " ;
app . handle ( req , res ) ;
CHECK ( " Hi world! " = = res . body ) ;
}
{
request req ;
response res ;
req . url = " /bp_prefix/nonexistent " ;
app . handle ( req , res ) ;
CHECK ( 404 = = res . code ) ;
}
{
request req ;
response res ;
req . url = " /bp_prefix_second/nonexistent " ;
app . handle ( req , res ) ;
CHECK ( 404 = = res . code ) ;
}
{
request req ;
response res ;
req . url = " /bp_prefix/bp2/nonexistent " ;
app . handle ( req , res ) ;
CHECK ( 200 = = res . code ) ;
CHECK ( " WRONG!! " = = res . body ) ;
}
{
request req ;
response res ;
req . url = " /bp_prefix/bp2/bp3/nonexistent " ;
app . handle ( req , res ) ;
CHECK ( 200 = = res . code ) ;
CHECK ( " WRONG!! " = = res . body ) ;
}
}
2021-10-30 23:50:19 +00:00
TEST_CASE ( " base64 " )
{
unsigned char sample_bin [ ] = { 0x14 , 0xfb , 0x9c , 0x03 , 0xd9 , 0x7e } ;
std : : string sample_bin_enc = " FPucA9l+ " ;
std : : string sample_bin_enc_url = " FPucA9l- " ;
unsigned char sample_bin1 [ ] = { 0x14 , 0xfb , 0x9c , 0x03 , 0xd9 } ;
std : : string sample_bin1_enc = " FPucA9k= " ;
std : : string sample_bin1_enc_np = " FPucA9k " ;
unsigned char sample_bin2 [ ] = { 0x14 , 0xfb , 0x9c , 0x03 } ;
std : : string sample_bin2_enc = " FPucAw== " ;
std : : string sample_bin2_enc_np = " FPucAw " ;
std : : string sample_text = " Crow Allows users to handle requests that may not come from the network. This is done by calling the handle(req, res) method and providing a request and response objects. Which causes crow to identify and run the appropriate handler, returning the resulting response. " ;
std : : string sample_base64 = " Q3JvdyBBbGxvd3MgdXNlcnMgdG8gaGFuZGxlIHJlcXVlc3RzIHRoYXQgbWF5IG5vdCBjb21lIGZyb20gdGhlIG5ldHdvcmsuIFRoaXMgaXMgZG9uZSBieSBjYWxsaW5nIHRoZSBoYW5kbGUocmVxLCByZXMpIG1ldGhvZCBhbmQgcHJvdmlkaW5nIGEgcmVxdWVzdCBhbmQgcmVzcG9uc2Ugb2JqZWN0cy4gV2hpY2ggY2F1c2VzIGNyb3cgdG8gaWRlbnRpZnkgYW5kIHJ1biB0aGUgYXBwcm9wcmlhdGUgaGFuZGxlciwgcmV0dXJuaW5nIHRoZSByZXN1bHRpbmcgcmVzcG9uc2Uu " ;
CHECK ( crow : : utility : : base64encode ( sample_text , sample_text . length ( ) ) = = sample_base64 ) ;
CHECK ( crow : : utility : : base64encode ( ( unsigned char * ) sample_bin , 6 ) = = sample_bin_enc ) ;
CHECK ( crow : : utility : : base64encode_urlsafe ( ( unsigned char * ) sample_bin , 6 ) = = sample_bin_enc_url ) ;
CHECK ( crow : : utility : : base64encode ( ( unsigned char * ) sample_bin1 , 5 ) = = sample_bin1_enc ) ;
CHECK ( crow : : utility : : base64encode ( ( unsigned char * ) sample_bin2 , 4 ) = = sample_bin2_enc ) ;
CHECK ( crow : : utility : : base64decode ( sample_base64 , sample_base64 . length ( ) ) = = sample_text ) ;
CHECK ( crow : : utility : : base64decode ( sample_bin_enc , 8 ) = = std : : string ( reinterpret_cast < char const * > ( sample_bin ) ) ) ;
CHECK ( crow : : utility : : base64decode ( sample_bin_enc_url , 8 , true ) = = std : : string ( reinterpret_cast < char const * > ( sample_bin ) ) ) ;
CHECK ( crow : : utility : : base64decode ( sample_bin1_enc , 8 ) = = std : : string ( reinterpret_cast < char const * > ( sample_bin1 ) ) . substr ( 0 , 5 ) ) ;
CHECK ( crow : : utility : : base64decode ( sample_bin1_enc_np , 7 ) = = std : : string ( reinterpret_cast < char const * > ( sample_bin1 ) ) . substr ( 0 , 5 ) ) ;
CHECK ( crow : : utility : : base64decode ( sample_bin2_enc , 8 ) = = std : : string ( reinterpret_cast < char const * > ( sample_bin2 ) ) . substr ( 0 , 4 ) ) ;
CHECK ( crow : : utility : : base64decode ( sample_bin2_enc_np , 6 ) = = std : : string ( reinterpret_cast < char const * > ( sample_bin2 ) ) . substr ( 0 , 4 ) ) ;
}