Rewrote the server in cpp with the frontend in svelte

This commit is contained in:
2023-10-20 13:02:21 +02:00
commit 03b22ebb61
4168 changed files with 831370 additions and 0 deletions

View File

@@ -0,0 +1,177 @@
//System Includes
#include <map>
#include <string>
//Project Includes
#include <corvusoft/restbed/request.hpp>
//External Includes
#include <catch.hpp>
//System Namespaces
using std::map;
using std::string;
using std::multimap;
//Project Namespaces
using restbed::Request;
//External Namespaces
TEST_CASE( "validate default instance values", "[request]" )
{
const Request request;
REQUIRE( request.get_port( ) == 80 );
REQUIRE( request.get_host( ) == "" );
REQUIRE( request.get_version( ) == 1.1 );
REQUIRE( request.get_path( ) == "/" );
REQUIRE( request.get_body( ).empty( ) );
REQUIRE( request.get_method( ) == "GET" );
REQUIRE( request.get_protocol( ) == "HTTP" );
REQUIRE( request.get_headers( ).empty( ) );
REQUIRE( request.get_response( ) == nullptr );
REQUIRE( request.get_path_parameters( ).empty( ) );
REQUIRE( request.get_query_parameters( ).empty( ) );
REQUIRE( request.has_query_parameter( "q" ) == false );
REQUIRE( request.has_path_parameter( "id" ) == false );
REQUIRE( request.has_header( "Content-Type" ) == false );
}
TEST_CASE( "confirm default destructor throws no exceptions", "[request]" )
{
auto request = new Request;
REQUIRE_NOTHROW( delete request );
}
TEST_CASE( "validate setters modify default values", "[request]" )
{
Request request;
request.set_body( "abc" );
request.set_port( 1984 );
request.set_version( 1.0 );
request.set_path( "/test case" );
request.set_host( "www.google.co.uk" );
request.set_method( "CONNECT" );
request.set_protocol( "HTTPS" );
multimap< string, string > headers { { "X-CUST", "1223" } };
request.set_headers( headers );
multimap< string, string > parameters { { "q", "search" } };
request.set_query_parameters( parameters );
REQUIRE( request.get_port( ) == 1984 );
REQUIRE( request.get_host( ) == "www.google.co.uk" );
REQUIRE( request.get_version( ) == 1.0 );
REQUIRE( request.get_path( ) == "/test case" );
REQUIRE( request.get_body( ).empty( ) == false );
REQUIRE( request.get_method( ) == "CONNECT" );
REQUIRE( request.get_protocol( ) == "HTTPS" );
REQUIRE( request.get_headers( ) == headers );
REQUIRE( request.get_response( ) == nullptr );
REQUIRE( request.get_path_parameters( ).empty( ) );
REQUIRE( request.get_query_parameters( ) == parameters );
REQUIRE( request.has_query_parameter( "q" ) == true );
REQUIRE( request.has_header( "X-CUST" ) == true );
}
TEST_CASE( "validate getter default value", "[request]" )
{
const Request request;
SECTION( "integer" )
{
int value = request.get_header( "Var", 12 );
REQUIRE( value == 12 );
}
SECTION( "unsigned integer" )
{
unsigned int value = request.get_header( "Var", 6 );
REQUIRE( value == 6 );
}
SECTION( "long" )
{
long value = request.get_header( "Var", 54 );
REQUIRE( value == 54 );
}
SECTION( "long long" )
{
long long value = request.get_header( "Var", 66 );
REQUIRE( value == 66 );
}
SECTION( "unsigned long" )
{
unsigned long default_value = static_cast< unsigned long >( -33 );
unsigned long value = request.get_header( "Var", default_value );
REQUIRE( value == default_value );
}
SECTION( "unsigned long long" )
{
long long value = request.get_header( "Var", -6 );
REQUIRE( value == -6 );
}
SECTION( "float" )
{
float value = request.get_header( "Var", 3.14f );
REQUIRE( value == 3.14f );
}
SECTION( "double" )
{
double value = request.get_header( "Var", 34.999443 );
REQUIRE( value == 34.999443 );
}
SECTION( "string" )
{
string header = request.get_header( "Var", "open" );
REQUIRE( header == "open" );
}
}
TEST_CASE( "validate set_header overrides previous value", "[request]" )
{
Request request;
request.set_header( "Content-Type", "application/json" );
REQUIRE( "application/json" == request.get_header( "Content-Type" ) );
request.set_header( "Content-Type", "application/xml" );
REQUIRE( "application/xml" == request.get_header( "Content-Type" ) );
const auto headers = request.get_headers( );
REQUIRE( headers.size( ) == 1 );
const auto expectation = multimap< string, string >
{
{ "Content-Type", "application/xml" }
};
REQUIRE( headers == expectation );
}
TEST_CASE( "validate add_header does not override a previous value", "[request]" )
{
Request request;
request.add_header( "Content-Type", "application/json" );
REQUIRE( "application/json" == request.get_header( "Content-Type" ) );
request.add_header( "Content-Type", "application/xml" );
REQUIRE( "application/json" == request.get_header( "Content-Type" ) );
const auto headers = request.get_headers( );
REQUIRE( headers.size( ) == 2 );
const auto expectation = multimap< string, string >
{
{ "Content-Type", "application/json" },
{ "Content-Type", "application/xml" }
};
REQUIRE( headers == expectation );
}

View File

@@ -0,0 +1,27 @@
//System Includes
#include <memory>
//Project Includes
#include <corvusoft/restbed/resource.hpp>
//External Includes
#include <catch.hpp>
//System Namespaces
//Project Namespaces
using restbed::Resource;
//External Namespaces
TEST_CASE( "confirm default constructor throws no exceptions", "[resource]" )
{
REQUIRE_NOTHROW( std::unique_ptr<Resource> (new Resource) );
}
TEST_CASE( "confirm default destructor throws no exceptions", "[resource]" )
{
auto resource = new Resource;
REQUIRE_NOTHROW( delete resource );
}

View File

@@ -0,0 +1,152 @@
//System Includes
#include <map>
#include <string>
//Project Includes
#include <corvusoft/restbed/response.hpp>
//External Includes
#include <catch.hpp>
//System Namespaces
using std::string;
using std::multimap;
//Project Namespaces
using restbed::Response;
//External Namespaces
TEST_CASE( "validate default instance values", "[response]" )
{
const Response response;
REQUIRE( response.get_version( ) == 1.1 );
REQUIRE( response.get_status_code( ) == 0 );
REQUIRE( response.get_protocol( ) == "HTTP" );
REQUIRE( response.get_headers( ).empty( ) );
REQUIRE( response.get_status_message( ).empty( ) );
}
TEST_CASE( "confirm default destructor throws no exceptions", "[response]" )
{
auto response = new Response;
REQUIRE_NOTHROW( delete response );
}
TEST_CASE( "validate setters modify default values", "[response]" )
{
Response response;
response.set_body( "ab" );
response.set_version( 1.0 );
response.set_status_code( 400 );
response.set_protocol( "SPDY" );
response.set_status_message( "corvusoft ltd" );
multimap< string, string > headers
{
{ "Connection", "keep-alive" }
};
response.set_headers( headers );
REQUIRE( response.get_version( ) == 1.0 );
REQUIRE( response.get_status_code( ) == 400 );
REQUIRE( response.get_protocol( ) == "SPDY" );
REQUIRE( response.get_headers( ) == headers );
REQUIRE( response.get_status_message( ) == "corvusoft ltd" );
}
TEST_CASE( "validate getter default value", "[response]" )
{
const Response response;
SECTION( "integer" )
{
int value = response.get_header( "Var", 12 );
REQUIRE( value == 12 );
}
SECTION( "unsigned integer" )
{
unsigned int value = response.get_header( "Var", 6 );
REQUIRE( value == 6 );
}
SECTION( "long" )
{
long value = response.get_header( "Var", 54 );
REQUIRE( value == 54 );
}
SECTION( "long long" )
{
long long value = response.get_header( "Var", 66 );
REQUIRE( value == 66 );
}
SECTION( "unsigned long" )
{
unsigned long default_value = static_cast< unsigned long >( -33 );
unsigned long value = response.get_header( "Var", default_value );
REQUIRE( value == default_value );
}
SECTION( "unsigned long long" )
{
long long value = response.get_header( "Var", -6 );
REQUIRE( value == -6 );
}
SECTION( "double" )
{
double value = response.get_header( "Var", 34443 );
REQUIRE( value == 34443 );
}
SECTION( "string" )
{
string header = response.get_header( "Var", "open" );
REQUIRE( header == "open" );
}
}
TEST_CASE( "validate set_header overrides previous value", "[request]" )
{
Response response;
response.set_header( "Content-Type", "application/json" );
REQUIRE( "application/json" == response.get_header( "Content-Type" ) );
response.set_header( "Content-Type", "application/xml" );
REQUIRE( "application/xml" == response.get_header( "Content-Type" ) );
const auto headers = response.get_headers( );
REQUIRE( headers.size( ) == 1 );
const auto expectation = multimap< string, string >
{
{ "Content-Type", "application/xml" }
};
REQUIRE( headers == expectation );
}
TEST_CASE( "validate add_header does not override a previous value", "[request]" )
{
Response response;
response.add_header( "Content-Type", "application/json" );
REQUIRE( "application/json" == response.get_header( "Content-Type" ) );
response.add_header( "Content-Type", "application/xml" );
REQUIRE( "application/json" == response.get_header( "Content-Type" ) );
const auto headers = response.get_headers( );
REQUIRE( headers.size( ) == 2 );
const auto expectation = multimap< string, string >
{
{ "Content-Type", "application/json" },
{ "Content-Type", "application/xml" }
};
REQUIRE( headers == expectation );
}

View File

@@ -0,0 +1,45 @@
//System Includes
#include <chrono>
//Project Includes
#include <corvusoft/restbed/service.hpp>
//External Includes
#include <catch.hpp>
//System Namespaces
using std::chrono::seconds;
using std::chrono::steady_clock;
//Project Namespaces
using restbed::Service;
//External Namespaces
TEST_CASE( "confirm default constructor throws no exceptions", "[service]" )
{
REQUIRE_NOTHROW( std::unique_ptr<Service> (new Service) );
}
TEST_CASE( "confirm default destructor throws no exceptions", "[service]" )
{
auto service = new Service;
REQUIRE_NOTHROW( delete service );
}
TEST_CASE( "confirm calling stop before start throws no exceptions", "[service]" )
{
Service service;
REQUIRE_NOTHROW( service.stop( ) );
}
TEST_CASE( "confirm default service state", "[service]" )
{
Service service;
REQUIRE( service.is_down( ) );
REQUIRE_FALSE( service.is_up( ) );
REQUIRE( service.get_uptime( ) == seconds( 0 ) );
}

View File

@@ -0,0 +1,179 @@
//System Includes
#include <set>
#include <map>
#include <memory>
#include <string>
#include <stdexcept>
//Project Includes
#include <corvusoft/restbed/session.hpp>
//External Includes
#include <catch.hpp>
//System Namespaces
using std::set;
using std::string;
using std::bad_cast;
using std::multimap;
using std::shared_ptr;
using std::make_shared;
using std::out_of_range;
using std::invalid_argument;
//Project Namespaces
using restbed::Session;
//External Namespaces
TEST_CASE( "validate default instance values", "[session]" )
{
const Session session( "f47ac10b-58cc-4372-a567-0e02b2c3d479" );
REQUIRE( session.is_open( ) == false );
REQUIRE( session.is_closed( ) == true );
REQUIRE( session.get_origin( ) == "" );
REQUIRE( session.get_destination( ) == "" );
REQUIRE( session.get_headers( ).empty( ) );
REQUIRE( session.get_id( ) == "f47ac10b-58cc-4372-a567-0e02b2c3d479" );
}
TEST_CASE( "confirm empty session id throws no exceptions", "[session]" )
{
REQUIRE_NOTHROW( Session( "" ) );
}
TEST_CASE( "confirm default destructor throws no exceptions", "[session]" )
{
auto session = new Session( "f47ac10b-58cc-4372-a567-0e02b2c3d479" );
REQUIRE_NOTHROW( delete session );
}
TEST_CASE( "validate setters modify default values", "[session]" )
{
Session session( "" );
session.set_id( "f47ac10b-58cc-4372-a567-0e02b2c3d479" );
REQUIRE( session.get_id( ) == "f47ac10b-58cc-4372-a567-0e02b2c3d479" );
session.set_header( "Connection", "close" );
multimap< string, string > expectation = { { "Connection", "close" } };
REQUIRE( session.get_headers( ) == expectation );
expectation =
{
{ "Content-Type", "application/yaml" },
{ "Content-Encoding", "" }
};
session.set_headers( expectation );
REQUIRE( session.get_headers( ) == expectation );
}
TEST_CASE( "validate session context functionality", "[session]" )
{
Session session( "f47ac10b-58cc-4372-a567-0e02b2c3d479" );
session.set( "Connection", string( "close" ) );
const string connection = session.get( "Connection" );
REQUIRE( connection == "close" );
REQUIRE( session.has( "Connection" ) );
REQUIRE( not session.has( "connection" ) );
REQUIRE( session.keys( ) == set< string >( { "Connection" } ) );
session.erase( "Connection" );
REQUIRE( not session.has( "Connection" ) );
const string keep_alive = session.get( "Connection", string( "keep-alive" ) );
REQUIRE( keep_alive == "keep-alive" );
REQUIRE( session.keys( ) == set< string >( ) );
session.set( "Connection", string( "close" ) );
session.set( "Connection", string( "keep-alive" ) );
const string header = session.get( "Connection" );
REQUIRE( header == "keep-alive" );
try
{
int type = session.get( "Connection" );
REQUIRE( type == 0 );
}
catch ( const bad_cast& )
{
REQUIRE( true );
}
session.erase( );
REQUIRE( session.keys( ) == set< string >( ) );
REQUIRE_THROWS_AS( session.get( "Connection" ), out_of_range );
}
TEST_CASE( "invoke close on uninitialised instance", "[session]" )
{
auto session = make_shared< Session >( "" );
REQUIRE( session->is_closed( ) == true );
REQUIRE_NOTHROW( session->close( ) );
REQUIRE( session->is_closed( ) == true );
}
TEST_CASE( "invoke yield on uninitialised instance", "[session]" )
{
auto session = make_shared< Session >( "" );
REQUIRE( session->is_closed( ) == true );
REQUIRE_NOTHROW( session->yield( "test data", [ ]( const shared_ptr< Session > )
{
return;
} ) );
REQUIRE_NOTHROW( session->yield( 200, "test data", [ ]( const shared_ptr< Session > )
{
return;
} ) );
REQUIRE_NOTHROW( session->yield( 200, "test data", { { "Content-Type", "text" } }, [ ]( const shared_ptr< Session > )
{
return;
} ) );
REQUIRE_NOTHROW( session->yield( 200, { { "Content-Type", "text" } }, [ ]( const shared_ptr< Session > )
{
return;
} ) );
}
TEST_CASE( "validate set_header overrides previous value", "[request]" )
{
Session session( "" );
session.set_header( "Content-Type", "application/json" );
session.set_header( "Content-Type", "application/xml" );
const auto headers = session.get_headers( );
REQUIRE( headers.size( ) == 1 );
const auto expectation = multimap< string, string >
{
{ "Content-Type", "application/xml" }
};
REQUIRE( headers == expectation );
}
TEST_CASE( "validate add_header does not override a previous value", "[request]" )
{
Session session( "" );
session.add_header( "Content-Type", "application/json" );
session.add_header( "Content-Type", "application/xml" );
const auto headers = session.get_headers( );
REQUIRE( headers.size( ) == 2 );
const auto expectation = multimap< string, string >
{
{ "Content-Type", "application/json" },
{ "Content-Type", "application/xml" }
};
REQUIRE( headers == expectation );
}

View File

@@ -0,0 +1,280 @@
//System Includes
#include <map>
#include <string>
#include <chrono>
//Project Includes
#include <corvusoft/restbed/settings.hpp>
//External Includes
#include <catch.hpp>
//System Namespaces
using std::map;
using std::string;
using std::multimap;
using std::chrono::milliseconds;
//Project Namespaces
using restbed::Settings;
//External Namespaces
TEST_CASE( "validate default instance values", "[settings]" )
{
const Settings settings;
REQUIRE( settings.get_port( ) == 80 );
REQUIRE( settings.get_root( ) == "/" );
REQUIRE( settings.get_worker_limit( ) == 0 );
REQUIRE( settings.get_properties( ).empty( ) );
REQUIRE( settings.get_bind_address( ).empty( ) );
REQUIRE( settings.get_reuse_address( ) == true );
REQUIRE( settings.get_connection_limit( ) == 128 );
REQUIRE( settings.get_default_headers( ).empty( ) );
REQUIRE( settings.get_case_insensitive_uris( ) == true );
REQUIRE( settings.get_keep_alive( ) == true );
REQUIRE( settings.get_keep_alive_cnt( ) == 3 );
REQUIRE( settings.get_keep_alive_start( ) == 900 );
REQUIRE( settings.get_keep_alive_interval( ) == 900 );
REQUIRE( settings.get_connection_timeout( ) == milliseconds( 5000 ) );
map< int, string > expectation =
{
{ 100, "Continue" },
{ 101, "Switching Protocols" },
{ 102, "Processing" },
{ 200, "OK" },
{ 201, "Created" },
{ 202, "Accepted" },
{ 203, "Non-Authoritative Information" },
{ 204, "No Content" },
{ 205, "Reset Content" },
{ 206, "Partial Content" },
{ 207, "Multi-Status" },
{ 208, "Already Reported" },
{ 226, "IM Used" },
{ 300, "Multiple Choices" },
{ 301, "Moved Permanently" },
{ 302, "Found" },
{ 303, "See Other" },
{ 304, "Not Modified" },
{ 305, "Use Proxy" },
{ 306, "Reserved" },
{ 307, "Temporary Redirect" },
{ 308, "Permanent Redirect" },
{ 400, "Bad Request" },
{ 401, "Unauthorized" },
{ 402, "Payment Required" },
{ 403, "Forbidden" },
{ 404, "Not Found" },
{ 405, "Method Not Allowed" },
{ 406, "Not Acceptable" },
{ 407, "Proxy Authentication Required" },
{ 408, "Request Timeout" },
{ 409, "Conflict" },
{ 410, "Gone" },
{ 411, "Length Required" },
{ 412, "Precondition Failed" },
{ 413, "Request Entity Too Large" },
{ 414, "Request URI Too Long" },
{ 415, "Unsupported Media Type" },
{ 416, "Requested Range Not Satisfiable" },
{ 417, "Expectation Failed" },
{ 422, "Unprocessable Entity" },
{ 423, "Locked" },
{ 424, "Failed Dependency" },
{ 426, "Upgrade Required" },
{ 428, "Precondition Required" },
{ 429, "Too Many Requests" },
{ 431, "Request Header Fields Too Large" },
{ 500, "Internal Server Error" },
{ 501, "Not Implemented" },
{ 502, "Bad Gateway" },
{ 503, "Service Unavailable" },
{ 504, "Gateway Timeout" },
{ 505, "HTTP Version Not Supported" },
{ 506, "Variant Also Negotiates" },
{ 507, "Insufficient Storage" },
{ 508, "Loop Detected" },
{ 510, "Not Extended" },
{ 511, "Network Authentication Required" }
};
REQUIRE( settings.get_status_messages( ) == expectation );
}
TEST_CASE( "confirm default destructor throws no exceptions", "[settings]" )
{
auto settings = new Settings;
REQUIRE_NOTHROW( delete settings );
}
TEST_CASE( "validate setters modify default values", "[settings]" )
{
Settings settings;
settings.set_port( 1984 );
settings.set_worker_limit( 4 );
settings.set_root( "/resources" );
settings.set_connection_limit( 1 );
settings.set_bind_address( "::1" );
settings.set_reuse_address( false );
settings.set_case_insensitive_uris( false );
settings.set_keep_alive( false );
settings.set_keep_alive_cnt( 45 );
settings.set_keep_alive_start( 501 );
settings.set_keep_alive_interval( 425 );
settings.set_connection_timeout( milliseconds( 30 ) );
settings.set_properties( { { "name", "value" } } );
settings.set_default_headers( { { "Connection", "close" } } );
REQUIRE( settings.get_port( ) == 1984 );
REQUIRE( settings.get_root( ) == "/resources" );
REQUIRE( settings.get_worker_limit( ) == 4 );
REQUIRE( settings.get_bind_address( ) == "::1" );
REQUIRE( settings.get_reuse_address( ) == false );
REQUIRE( settings.get_connection_limit( ) == 1 );
REQUIRE( settings.get_keep_alive( ) == false );
REQUIRE( settings.get_keep_alive_cnt( ) == 45 );
REQUIRE( settings.get_keep_alive_start( ) == 501 );
REQUIRE( settings.get_keep_alive_interval( ) == 425 );
REQUIRE( settings.get_case_insensitive_uris( ) == false );
REQUIRE( settings.get_connection_timeout( ) == milliseconds( 30 ) );
map< string, string > properties_expectation = { { "name", "value" } };
REQUIRE( settings.get_properties( ) == properties_expectation );
multimap< string, string > headers_expectation = { { "Connection", "close" } };
REQUIRE( settings.get_default_headers( ) == headers_expectation );
}
TEST_CASE( "manipulating status messages", "[settings]" )
{
Settings settings;
settings.set_status_message( 418, "I'm a teapot" );
SECTION( "read individual status message from valid status code" )
{
REQUIRE( settings.get_status_message( 418 ) == "I'm a teapot" );
}
SECTION( "read individual status message from invalid status code" )
{
REQUIRE( settings.get_status_message( -2 ) == "No Appropriate Status Message Found" );
}
SECTION( "read individual status message from unknown status code" )
{
REQUIRE( settings.get_status_message( 888 ) == "No Appropriate Status Message Found" );
}
SECTION( "read all status messages" )
{
map< int, string > expectation =
{
{ 100, "Continue" },
{ 101, "Switching Protocols" },
{ 102, "Processing" },
{ 200, "OK" },
{ 201, "Created" },
{ 202, "Accepted" },
{ 203, "Non-Authoritative Information" },
{ 204, "No Content" },
{ 205, "Reset Content" },
{ 206, "Partial Content" },
{ 207, "Multi-Status" },
{ 208, "Already Reported" },
{ 226, "IM Used" },
{ 300, "Multiple Choices" },
{ 301, "Moved Permanently" },
{ 302, "Found" },
{ 303, "See Other" },
{ 304, "Not Modified" },
{ 305, "Use Proxy" },
{ 306, "Reserved" },
{ 307, "Temporary Redirect" },
{ 308, "Permanent Redirect" },
{ 400, "Bad Request" },
{ 401, "Unauthorized" },
{ 402, "Payment Required" },
{ 403, "Forbidden" },
{ 404, "Not Found" },
{ 405, "Method Not Allowed" },
{ 406, "Not Acceptable" },
{ 407, "Proxy Authentication Required" },
{ 408, "Request Timeout" },
{ 409, "Conflict" },
{ 410, "Gone" },
{ 411, "Length Required" },
{ 412, "Precondition Failed" },
{ 413, "Request Entity Too Large" },
{ 414, "Request URI Too Long" },
{ 415, "Unsupported Media Type" },
{ 416, "Requested Range Not Satisfiable" },
{ 417, "Expectation Failed" },
{ 418, "I'm a teapot" },
{ 422, "Unprocessable Entity" },
{ 423, "Locked" },
{ 424, "Failed Dependency" },
{ 426, "Upgrade Required" },
{ 428, "Precondition Required" },
{ 429, "Too Many Requests" },
{ 431, "Request Header Fields Too Large" },
{ 500, "Internal Server Error" },
{ 501, "Not Implemented" },
{ 502, "Bad Gateway" },
{ 503, "Service Unavailable" },
{ 504, "Gateway Timeout" },
{ 505, "HTTP Version Not Supported" },
{ 506, "Variant Also Negotiates" },
{ 507, "Insufficient Storage" },
{ 508, "Loop Detected" },
{ 510, "Not Extended" },
{ 511, "Network Authentication Required" }
};
REQUIRE( settings.get_status_messages( ) == expectation );
}
}
TEST_CASE( "manipulation generic properties", "[settings]" )
{
Settings settings;
settings.set_property( "security-seed", "de305d54-75b4-431b-adb2-eb6b9e546014" );
SECTION( "read individual property from valid name" )
{
REQUIRE( settings.get_property( "security-seed" ) == "de305d54-75b4-431b-adb2-eb6b9e546014" );
}
SECTION( "read individual property from uppercase name" )
{
REQUIRE( settings.get_property( "SECURITY-SEED" ) == "" );
}
SECTION( "read individual property from mixedcase name" )
{
REQUIRE( settings.get_property( "SEcURiTY-SeeD" ) == "" );
}
SECTION( "read individual propety from invalid name" )
{
REQUIRE( settings.get_property( "" ) == "" );
}
SECTION( "read individual property from unknown name" )
{
REQUIRE( settings.get_property( "realm" ) == "" );
}
SECTION( "read all properties" )
{
map< string, string > expectation =
{
{ "security-seed", "de305d54-75b4-431b-adb2-eb6b9e546014" }
};
REQUIRE( settings.get_properties( ) == expectation );
}
}

View File

@@ -0,0 +1,78 @@
//System Includes
#include <string>
#include <ciso646>
//Project Includes
#include <corvusoft/restbed/ssl_settings.hpp>
//External Includes
#include <catch.hpp>
//System Namespaces
using std::string;
//Project Namespaces
using restbed::SSLSettings;
//External Namespaces
TEST_CASE( "validate default instance values", "[ssl-settings]" )
{
const SSLSettings settings;
REQUIRE( settings.get_port( ) == 443 );
REQUIRE( settings.has_enabled_sslv2( ) );
REQUIRE( settings.has_enabled_sslv3( ) );
REQUIRE( settings.has_enabled_tlsv1( ) );
REQUIRE( settings.has_enabled_tlsv11( ) );
REQUIRE( settings.has_enabled_tlsv12( ) );
REQUIRE( settings.has_enabled_compression( ) );
REQUIRE( settings.has_enabled_default_workarounds( ) );
REQUIRE( settings.has_enabled_single_diffie_hellman_use( ) );
REQUIRE( settings.get_bind_address( ).empty( ) );
REQUIRE( settings.get_passphrase( ).empty( ) );
REQUIRE( settings.get_certificate( ).empty( ) );
REQUIRE( settings.get_private_key( ).empty( ) );
REQUIRE( settings.get_private_rsa_key( ).empty( ) );
REQUIRE( settings.get_certificate_chain( ).empty( ) );
REQUIRE( settings.get_temporary_diffie_hellman( ).empty( ) );
REQUIRE( settings.get_certificate_authority_pool( ).empty( ) );
REQUIRE( settings.has_disabled_http( ) == false );
}
TEST_CASE( "confirm default destructor throws no exceptions", "[ssl-settings]" )
{
auto settings = new SSLSettings;
REQUIRE_NOTHROW( delete settings );
}
TEST_CASE( "validate setters modify default values", "[settings]" )
{
SSLSettings settings;
settings.set_port( 8080 );
settings.set_sslv2_enabled( false );
settings.set_sslv3_enabled( false );
settings.set_tlsv1_enabled( false );
settings.set_tlsv11_enabled( false );
settings.set_tlsv12_enabled( false );
settings.set_http_disabled( true );
settings.set_compression_enabled( false );
settings.set_default_workarounds_enabled( false );
settings.set_single_diffie_hellman_use_enabled( false );
settings.set_bind_address( "127.0.0.1" );
settings.set_passphrase( "my-passphrase" );
REQUIRE( settings.get_port( ) == 8080 );
REQUIRE( not settings.has_enabled_sslv2( ) );
REQUIRE( not settings.has_enabled_sslv3( ) );
REQUIRE( not settings.has_enabled_tlsv1( ) );
REQUIRE( not settings.has_enabled_tlsv11( ) );
REQUIRE( not settings.has_enabled_tlsv12( ) );
REQUIRE( not settings.has_enabled_compression( ) );
REQUIRE( not settings.has_enabled_default_workarounds( ) );
REQUIRE( not settings.has_enabled_single_diffie_hellman_use( ) );
REQUIRE( settings.get_bind_address( ) == "127.0.0.1" );
REQUIRE( settings.get_passphrase( ) == "my-passphrase" );
REQUIRE( settings.has_disabled_http( ) == true );
}

View File

@@ -0,0 +1,221 @@
//System Includes
#include <map>
#include <string>
#include <vector>
//Project Includes
#include "corvusoft/restbed/string.hpp"
//External Includes
#include <catch.hpp>
//System Namespaces
using std::string;
using std::vector;
using std::multimap;
//Project Namespaces
using restbed::String;
//External Namespaces
TEST_CASE( "uppercase to lowercase", "[string]" )
{
REQUIRE( String::lowercase( "CORVUSOFT" ) == "corvusoft" );
}
TEST_CASE( "lowercase to lowercase", "[string]" )
{
REQUIRE( String::lowercase( "corvusoft" ) == "corvusoft" );
}
TEST_CASE( "mixedcase to lowercase", "[string]" )
{
REQUIRE( String::lowercase( "CoRvUSoFt" ) == "corvusoft" );
}
TEST_CASE( "empty to lowercase", "[string]" )
{
REQUIRE( String::lowercase( "" ) == "" );
}
TEST_CASE( "uppercase to uppercase", "[string]" )
{
REQUIRE( String::uppercase( "corvusoft" ) == "CORVUSOFT" );
}
TEST_CASE( "lowercase to uppercase", "[string]" )
{
REQUIRE( String::uppercase( "corvusoft" ) == "CORVUSOFT" );
}
TEST_CASE( "mixedcase to uppercase", "[string]" )
{
REQUIRE( String::uppercase( "CoRvUSoFt" ) == "CORVUSOFT" );
}
TEST_CASE( "empty to uppercase", "[string]" )
{
REQUIRE( String::uppercase( "" ) == "" );
}
TEST_CASE( "format", "[string]" )
{
REQUIRE( String::format( "Corvusoft %s", "Solutions" ) == "Corvusoft Solutions" );
}
TEST_CASE( "format with no specifiers", "[string]" )
{
REQUIRE( String::format( "Corvusoft" ) == "Corvusoft" );
}
TEST_CASE( "format with empty", "[string]" )
{
REQUIRE( String::format( "" ) == "" );
}
TEST_CASE( "format with string length equal to initial buffer length", "[string]" )
{
size_t length = String::FORMAT_BUFFER_INITIAL_LENGTH;
string str( length, ' ' );
for ( size_t i = 0; i < length; i++ ) {
str[ i ] = ( i % 95 ) + 32;
}
REQUIRE( String::format( "%s", str.c_str() ) == str );
}
TEST_CASE( "format with string length equal to initial buffer length + 1", "[string]" )
{
size_t length = String::FORMAT_BUFFER_INITIAL_LENGTH + 1;
string str( length, ' ' );
for ( size_t i = 0; i < length; i++ ) {
str[ i ] = ( i % 95 ) + 32;
}
REQUIRE( String::format( "%s", str.c_str() ) == str );
}
TEST_CASE( "split", "[string]" )
{
REQUIRE( String::split( "Corvusoft Solutions", ' ' ) == vector< string >( { "Corvusoft", "Solutions" } ) );
}
TEST_CASE( "split with missing delimiter", "[string]" )
{
REQUIRE( String::split( "Corvusoft Solutions", '+' ) == vector< string >( { "Corvusoft Solutions" } ) );
}
TEST_CASE( "split with empty delimiter", "[string]" )
{
char expectation = 0;
REQUIRE( String::split( "Corvusoft Solutions", expectation ) == vector< string >( { "Corvusoft Solutions" } ) );
}
TEST_CASE( "join map to string", "[string]" )
{
multimap< string, string > values = { { "fields", "id,rev" }, { "sort", "rev" } };
REQUIRE( String::join( values, "=", "&" ) == "fields=id,rev&sort=rev" );
}
TEST_CASE( "join map to string with missing value & pair delimiters", "[string]" )
{
multimap< string, string > values = { { "fields", "id,rev" }, { "sort", "rev" } };
REQUIRE( String::join( values, "", "" ) == "fieldsid,revsortrev" );
}
TEST_CASE( "join empty map to string", "[string]" )
{
multimap< string, string > values;
REQUIRE( String::join( values, "=", "&" ) == "" );
}
TEST_CASE( "join map to string with missing value delimiter", "[string]" )
{
multimap< string, string > values = { { "fields", "id,rev" }, { "sort", "rev" } };
REQUIRE( String::join( values, "", "&" ) == "fieldsid,rev&sortrev" );
}
TEST_CASE( "join map to string with missing pair delimiter", "[string]" )
{
multimap< string, string > values = { { "fields", "id,rev" }, { "sort", "rev" } };
REQUIRE( String::join( values, "=", "" ) == "fields=id,revsort=rev" );
}
TEST_CASE( "remove", "[string]" )
{
REQUIRE( String::remove( "Solutions", "Corvusoft Solutions" ) == "Corvusoft " );
}
TEST_CASE( "remove multiple", "[string]" )
{
REQUIRE( String::remove( "dot", "dot dash dot dash dash" ) == " dash dash dash" );
}
TEST_CASE( "remove with missing target", "[string]" )
{
REQUIRE( String::remove( "ltd", "Corvusoft Solutions" ) == "Corvusoft Solutions" );
}
TEST_CASE( "remove with empty target", "[string]" )
{
REQUIRE( String::remove( "", "Corvusoft Solutions" ) == "Corvusoft Solutions" );
}
TEST_CASE( "remove with empty value", "[string]" )
{
REQUIRE( String::remove( " Solutions", "" ) == "" );
}
TEST_CASE( "remove with empty arguments", "[string]" )
{
REQUIRE( String::remove( "", "" ) == "" );
}
TEST_CASE( "replace", "[string]" )
{
REQUIRE( String::replace( "ltd", "Solutions", "Corvusoft ltd" ) == "Corvusoft Solutions" );
}
TEST_CASE( "replace multiple", "[string]" )
{
REQUIRE( String::replace( "dot", "ping", "dot dash dot dash dash" ) == "ping dash ping dash dash" );
}
TEST_CASE( "replace with missing target", "[string]" )
{
REQUIRE( String::replace( "ltd", "Solutions", "Corvusoft Solutions" ) == "Corvusoft Solutions" );
}
TEST_CASE( "replace with empty target", "[string]" )
{
REQUIRE( String::replace( "", "Solutions", "Corvusoft ltd" ) == "Corvusoft ltd" );
}
TEST_CASE( "replace with empty substitute", "[string]" )
{
REQUIRE( String::replace( "ltd", "", "Corvusoft ltd" ) == "Corvusoft " );
}
TEST_CASE( "replace with empty value", "[string]" )
{
REQUIRE( String::replace( "ltd", "Solutions", "" ) == "" );
}
TEST_CASE( "replace with empty target and substitute", "[string]" )
{
REQUIRE( String::replace( "", "", "Corvusoft ltd" ) == "Corvusoft ltd" );
}
TEST_CASE( "replace with empty target and value", "[string]" )
{
REQUIRE( String::replace( "", "Solutions", "" ) == "" );
}
TEST_CASE( "replace with empty substitue and value", "[string]" )
{
REQUIRE( String::replace( "ltd", "", "" ) == "" );
}
TEST_CASE( "replace with empty arguments", "[string]" )
{
REQUIRE( String::replace( "", "", "" ) == "" );
}

View File

@@ -0,0 +1,187 @@
//System Includes
#include <string>
#include <ciso646>
#include <stdexcept>
//Project Includes
#include "corvusoft/restbed/uri.hpp"
//External Includes
#include <catch.hpp>
//System Namespaces
using std::string;
using std::invalid_argument;
//Project Namespaces
using restbed::Uri;
//External Namespaces
TEST_CASE( "default constructor", "[uri]" )
{
Uri uri( "http://crowhurst.ben:ASDFFDSA1234@code.google.com:80/resources/index.html?q=bear&b=cubs#frag1" );
REQUIRE( uri.get_port( ) == 80 );
REQUIRE( uri.get_path( ) == "/resources/index.html" );
REQUIRE( uri.get_query( ) == "q=bear&b=cubs" );
REQUIRE( uri.get_scheme( ) == "http" );
REQUIRE( uri.get_fragment( ) == "frag1" );
REQUIRE( uri.get_username( ) == "crowhurst.ben" );
REQUIRE( uri.get_password( ) == "ASDFFDSA1234" );
REQUIRE( uri.get_authority( ) == "code.google.com" );
const string value = uri.to_string( );
REQUIRE( value == "http://crowhurst.ben:ASDFFDSA1234@code.google.com:80/resources/index.html?q=bear&b=cubs#frag1" );
}
TEST_CASE( "ipv4 constructor", "[uri]" )
{
Uri uri( "http://username:password@127.1.1.1:80/resources/index.html?q=bear&b=cubs#frag1" );
REQUIRE( uri.get_port( ) == 80 );
REQUIRE( uri.get_path( ) == "/resources/index.html" );
REQUIRE( uri.get_query( ) == "q=bear&b=cubs" );
REQUIRE( uri.get_scheme( ) == "http" );
REQUIRE( uri.get_fragment( ) == "frag1" );
REQUIRE( uri.get_username( ) == "username" );
REQUIRE( uri.get_password( ) == "password" );
REQUIRE( uri.get_authority( ) == "127.1.1.1" );
const string value = uri.to_string( );
REQUIRE( value == "http://username:password@127.1.1.1:80/resources/index.html?q=bear&b=cubs#frag1" );
}
TEST_CASE( "ipv6 constructor", "[uri]" )
{
Uri uri( "http://username:password@[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:80/resources/index.html?q=bear&b=cubs#frag1" );
REQUIRE( uri.get_port( ) == 80 );
REQUIRE( uri.get_path( ) == "/resources/index.html" );
REQUIRE( uri.get_query( ) == "q=bear&b=cubs" );
REQUIRE( uri.get_scheme( ) == "http" );
REQUIRE( uri.get_fragment( ) == "frag1" );
REQUIRE( uri.get_username( ) == "username" );
REQUIRE( uri.get_password( ) == "password" );
REQUIRE( uri.get_authority( ) == "2001:0db8:85a3:0000:0000:8a2e:0370:7334" );
const string value = uri.to_string( );
REQUIRE( value == "http://username:password@[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:80/resources/index.html?q=bear&b=cubs#frag1" );
}
TEST_CASE( "invalid constructor", "[uri]" )
{
REQUIRE_THROWS_AS( Uri( "---_)(*&" ), invalid_argument );
}
TEST_CASE( "empty constructor", "[uri]" )
{
REQUIRE_THROWS_AS( Uri( "" ), invalid_argument );
}
TEST_CASE( "copy constructor", "[uri]" )
{
Uri uri( "ftp://code.google.com/p/application-on" );
Uri copy( uri );
REQUIRE( copy.to_string( ) == uri.to_string( ) );
}
TEST_CASE( "destructor", "[uri]" )
{
Uri* uri = new Uri( "ftp://code.google.com/p/application-on" );
REQUIRE_NOTHROW( delete uri );
}
TEST_CASE( "assignment-operator", "[uri]" )
{
Uri uri( "http://code.google.com/p/application-on/source/detail?r=73aa44eefc85407545b11ff30abbcd980030aab1" );
Uri copy = uri;
REQUIRE( copy.to_string( ) == uri.to_string( ) );
}
TEST_CASE( "less-than-operator", "[uri]" )
{
Uri lhs( "http://restbed.corvusoft.co.uk" );
Uri rhs( "http://restule.corvusoft.co.uk/index.html" );
REQUIRE( lhs < rhs );
}
TEST_CASE( "greater-than-operator", "[uri]" )
{
Uri lhs( "http://restbed.corvusoft.co.uk/index.html" );
Uri rhs( "http://restbed.corvusoft.co.uk" );
REQUIRE( lhs > rhs );
}
TEST_CASE( "equality-operator", "[uri]" )
{
Uri lhs( "http://restq.corvusoft.co.uk" );
Uri rhs( "http://restq.corvusoft.co.uk" );
REQUIRE( lhs == rhs );
}
TEST_CASE( "inequality-operator", "[uri]" )
{
Uri lhs( "http://restbed.corvusoft.co.uk" );
Uri rhs( "http://restule.corvusoft.co.uk" );
REQUIRE( lhs not_eq rhs );
}
TEST_CASE( "to_string", "[uri]" )
{
Uri uri( "https://source.corvusoft.co.uk" );
REQUIRE( uri.to_string( ) == "https://source.corvusoft.co.uk" );
}
TEST_CASE( "valid is_valid", "[uri]" )
{
REQUIRE( Uri::is_valid( "ws://restq.corvusoft.co.uk:443/queues" ) );
}
TEST_CASE( "invalid is_valid", "[uri]" )
{
REQUIRE( Uri::is_valid( "---_)(*&" ) == false );
}
TEST_CASE( "parse", "[uri]" )
{
Uri uri = Uri::parse( "http://shard.corvusoft.co.uk" );
const string value = uri.to_string( );
REQUIRE( value == "http://shard.corvusoft.co.uk" );
}
TEST_CASE( "invalid parse", "[uri]" )
{
REQUIRE_THROWS_AS( Uri::parse( "---_)(*&" ), invalid_argument );
}
TEST_CASE( "empty parse", "[uri]" )
{
REQUIRE_THROWS_AS( Uri::parse( "" ), invalid_argument );
}
TEST_CASE( "decode", "[uri]" )
{
REQUIRE( Uri::decode( "file:///tmp/a%2Eb/tmp_20482932.txt" ) == "file:///tmp/a.b/tmp_20482932.txt" );
}
TEST_CASE( "decode_parameter", "[uri]" )
{
REQUIRE( Uri::decode_parameter( "Corvusoft+Solutions" ) == "Corvusoft Solutions" );
}
TEST_CASE( "encode", "[uri]" )
{
REQUIRE( Uri::encode( "a=b" ) == "a%3Db" );
}
TEST_CASE( "encode parameter", "[uri]" )
{
REQUIRE( Uri::encode_parameter( "a=b" ) == "a%3Db" );
}

View File

@@ -0,0 +1,81 @@
//System Includes
#include <tuple>
//Project Includes
#include <corvusoft/restbed/web_socket_message.hpp>
//External Includes
#include <catch.hpp>
//System Namespaces
using std::tuple;
using std::make_tuple;
//Project Namespaces
using restbed::WebSocketMessage;
//External Namespaces
TEST_CASE( "validate default instance values", "[web_socket_message]" )
{
const WebSocketMessage message;
REQUIRE( message.get_mask( ) == 0 );
REQUIRE( message.get_length( ) == 0 );
REQUIRE( message.get_extended_length( ) == 0 );
REQUIRE( message.get_mask_flag( ) == false );
REQUIRE( message.get_final_frame_flag( ) == true );
REQUIRE( message.get_reserved_flags( ) == make_tuple( false, false, false ) );
}
TEST_CASE( "validate copy constructor", "[web_socket_message]" )
{
WebSocketMessage message;
message.set_mask( 45454 );
message.set_length( 127 );
message.set_extended_length( 654 );
message.set_mask_flag( false );
message.set_final_frame_flag( false );
message.set_reserved_flags( true, false, true );
REQUIRE( message.get_mask( ) == 45454 );
REQUIRE( message.get_length( ) == 127 );
REQUIRE( message.get_extended_length( ) == 654 );
REQUIRE( message.get_mask_flag( ) == false );
REQUIRE( message.get_final_frame_flag( ) == false );
REQUIRE( message.get_reserved_flags( ) == make_tuple( true, false, true ) );
}
TEST_CASE( "confirm default destructor throws no exceptions", "[web_socket_message]" )
{
auto message = new WebSocketMessage( );
REQUIRE_NOTHROW( delete message );
}
TEST_CASE( "validate setters modify default values", "[web_socket_message]" )
{
WebSocketMessage message;
message.set_mask( 1234567 );
message.set_length( 125 );
message.set_extended_length( 654 );
message.set_mask_flag( false );
message.set_final_frame_flag( false );
message.set_reserved_flags( true, true, true );
REQUIRE( message.get_mask( ) == 1234567 );
REQUIRE( message.get_length( ) == 125 );
REQUIRE( message.get_extended_length( ) == 654 );
REQUIRE( message.get_mask_flag( ) == false );
REQUIRE( message.get_final_frame_flag( ) == false );
REQUIRE( message.get_reserved_flags( ) == make_tuple( true, true, true ) );
}
TEST_CASE( "validate mask and mask_flag setter logic", "[web_socket_message]" )
{
WebSocketMessage message;
message.set_mask( 123424 );
REQUIRE( message.get_mask( ) == 123424 );
REQUIRE( message.get_mask_flag( ) == true );
}