#ifndef RESPONSE_TEST #define RESPONSE_TEST value #include #include #include #include #include #include #include #include #include #include "munit/munit.h" #ifndef READLINE_C #define READLINE_C #include "../src/readline.c" #endif #ifndef REQUESTRESPONSE_C #define REQUESTRESPONSE_C #include "../src/requestresponse.c" #endif /* ifndef REQUESTRESPONSE_C */ #include "../src/response.c" typedef struct { char *fullLine; float version; int statusCode; char *statusMessage; } firstLine; static firstLine line1Examples[] = { //Full Line, version status Code Status Message { "HTTP/1.1 200 OK", 1.1, 200, "OK" }, { "HTTP/2.0 404 Not Found", 2.0, 404, "Not Found" }, { NULL, 0, 0, NULL } }; MunitResult testResponseNewStatus(const MunitParameter params[], void* user_data_or_fixture){ Response *rsp = newResponse(); responseBarebones(rsp); munit_assert_int( rsp->statusCode, ==, 200 ); return MUNIT_OK; } MunitResult testResponseNewStatusMessage(const MunitParameter params[], void* user_data_or_fixture){ Response *rsp = newResponse(); responseBarebones(rsp); munit_assert_string_equal( rsp->statusMessage, "OK" ); return MUNIT_OK; } MunitResult testResponseNewVersion(const MunitParameter params[], void* user_data_or_fixture){ Response *rsp = newResponse(); responseBarebones(rsp); munit_assert_float( rsp->version, ==, 1.1 ); return MUNIT_OK; } MunitResult testResponseSetBody(const MunitParameter params[], void* user_data_or_fixture){ Response *rsp = newResponse(); responseBarebones(rsp); responseSetBody( rsp, "Testing", 1 ); munit_assert_string_equal( rsp->body, "Testing" ); munit_assert_string_equal( getHeader( rsp->headers, "content-length" )->value, "7" ); return MUNIT_OK; } MunitResult testResponseToString(const MunitParameter params[], void* user_data_or_fixture){ Response *rsp = newResponse(); responseBarebones(rsp); munit_assert_string_equal( responseToString( rsp ), "HTTP/1.1 200 OK\r\nContent-Length: 0\r\nContent-Type: text/plain\r\n\r\n" ); responseSetBody( rsp, "Testing", 1 ); munit_assert_string_equal( responseToString( rsp ), "HTTP/1.1 200 OK\r\nContent-Length: 7\r\nContent-Type: text/plain\r\n\r\nTesting\r\n" ); return MUNIT_OK; } MunitResult testResponseFirstLineStatusCode(const MunitParameter params[], void* user_data_or_fixture){ Response *rsp; for ( firstLine *line = line1Examples; line->fullLine != NULL; line++ ){ rsp = newResponse(); responseFirstLine( rsp, line->fullLine ); munit_assert_int( rsp->statusCode, ==, line->statusCode ); free( rsp ); } return MUNIT_OK; } MunitResult testResponseFirstLineStatusMessage(const MunitParameter params[], void* user_data_or_fixture){ Response *rsp; for ( firstLine *line = line1Examples; line->fullLine != NULL; line++ ){ rsp = newResponse(); responseFirstLine( rsp, line->fullLine ); munit_assert_string_equal( rsp->statusMessage, line->statusMessage ); free( rsp ); } return MUNIT_OK; } MunitResult testResponseFirstLineVersion(const MunitParameter params[], void* user_data_or_fixture){ Response *rsp; for ( firstLine *line = line1Examples; line->fullLine != NULL; line++ ){ rsp = newResponse(); responseFirstLine( rsp, line->fullLine ); munit_assert_float( rsp->version, ==, line->version ); free( rsp ); } return MUNIT_OK; } static void* setupSocketTests(const MunitParameter params[], void* user_data) { int client_fd = 0; struct sockaddr_in address; memset( &address, 0, sizeof(address) ); struct hostent *host = gethostbyname("example.com"); Response *rsp = NULL; if ((client_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0){ perror("socket failed"); return NULL; } address.sin_family = AF_INET; address.sin_port = htons( 80 ); // We want the request to go out to whatever the host was resolved to memcpy( &address.sin_addr, host->h_addr_list[0], host->h_length ); if((connect(client_fd, (struct sockaddr *)&address, sizeof(address)))<0) { perror("connect failed"); return NULL; } char *toSend = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"; if ( write( client_fd, toSend, strlen(toSend) ) != strlen(toSend) ){ perror( "Write Error" ); return NULL; } rsp = newResponseFromSocket( client_fd ); return rsp; } MunitResult testResponseFromSocketHeaderLength(const MunitParameter params[], void* user_data_or_fixture){ Response *rsp = ( Response * )user_data_or_fixture; if ( rsp == NULL ) return MUNIT_ERROR; //Check there are the right nubmer of haeders // Unfortunately it changes from request to request so this is a "loose" // check munit_assert_int( countHeaders( rsp->headers ), >, 7 ); return MUNIT_OK; } MunitResult testResponseFromSocketStatusCode(const MunitParameter params[], void* user_data_or_fixture){ Response *rsp = ( Response * )user_data_or_fixture; if ( rsp == NULL ) return MUNIT_ERROR; //Check there are the right nubmer of haeders munit_assert_int( rsp->statusCode, ==, 200 ); return MUNIT_OK; } MunitResult testResponseFromSocketBody(const MunitParameter params[], void* user_data_or_fixture){ Response *rsp = ( Response * )user_data_or_fixture; Header *contentLength = getHeader( rsp->headers, "content-length" ); unsigned int length = 0; if ( contentLength == NULL ) return MUNIT_ERROR; munit_assert_int( atoi( contentLength->value ), ==, strlen( (char *)rsp->body ) ); //Check there are the right nubmer of haeders munit_assert_int( rsp->statusCode, ==, 200 ); return MUNIT_OK; } static MunitTest response_tests[] = { { "/new/status", /* name */ testResponseNewStatus, /* test */ NULL, /* setup */ NULL, /* tear_down */ MUNIT_TEST_OPTION_NONE, /* options */ NULL /* parameters */ }, { "/new/statusMessage", /* name */ testResponseNewStatusMessage, /* test */ NULL, /* setup */ NULL, /* tear_down */ MUNIT_TEST_OPTION_NONE, /* options */ NULL /* parameters */ }, { "/new/version", /* name */ testResponseNewVersion, /* test */ NULL, /* setup */ NULL, /* tear_down */ MUNIT_TEST_OPTION_NONE, /* options */ NULL /* parameters */ }, { "/set/body", /* name */ testResponseSetBody, /* test */ NULL, /* setup */ NULL, /* tear_down */ MUNIT_TEST_OPTION_NONE, /* options */ NULL /* parameters */ }, { "/to/string", /* name */ testResponseToString, /* test */ NULL, /* setup */ NULL, /* tear_down */ MUNIT_TEST_OPTION_NONE, /* options */ NULL /* parameters */ }, { "/line1/statusCode", /* name */ testResponseFirstLineStatusCode, /* test */ NULL, /* setup */ NULL, /* tear_down */ MUNIT_TEST_OPTION_NONE, /* options */ NULL /* parameters */ }, { "/line1/statusMessage", /* name */ testResponseFirstLineStatusMessage, /* test */ NULL, /* setup */ NULL, /* tear_down */ MUNIT_TEST_OPTION_NONE, /* options */ NULL /* parameters */ }, { "/line1/version", /* name */ testResponseFirstLineVersion, /* test */ NULL, /* setup */ NULL, /* tear_down */ MUNIT_TEST_OPTION_NONE, /* options */ NULL /* parameters */ }, { "/fromSocket/headerLength", /* name */ testResponseFromSocketHeaderLength, /* test */ setupSocketTests, /* setup */ NULL, /* tear_down */ MUNIT_TEST_OPTION_NONE, /* options */ NULL /* parameters */ }, { "/fromSocket/statusCode", /* name */ testResponseFromSocketStatusCode, /* test */ setupSocketTests, /* setup */ NULL, /* tear_down */ MUNIT_TEST_OPTION_NONE, /* options */ NULL /* parameters */ }, { "/fromSocket/body", /* name */ testResponseFromSocketBody, /* test */ setupSocketTests, /* setup */ NULL, /* tear_down */ MUNIT_TEST_OPTION_NONE, /* options */ NULL /* parameters */ }, /* Mark the end of the array with an entry where the test * function is NULL */ { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } }; MunitSuite response_test_suite = { "/response", /* name */ response_tests, /* tests */ NULL, /* suites */ 1, /* iterations */ MUNIT_SUITE_OPTION_NONE /* options */ }; #ifndef MAINTEST #define MAINTEST int main (int argc, char* argv[]) { return munit_suite_main(&response_test_suite, NULL, argc, argv); } #endif /* ifndef MAINTEST */ #endif /* ifndef RESPONSE_TEST */