diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 542f93d..0e3df0a 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -5,10 +5,9 @@ add_executable(unit_tests) target_sources(unit_tests PRIVATE - "http_request_test.cpp" - "http_response_test.cpp" - "http_utils_test.cpp" - "thread_pool_test.cpp" + "http_request_tests.cpp" + "http_response_tests.cpp" + "http_tests.cpp" "unit_tests.cpp" ) diff --git a/tests/unit/http_request_test.cpp b/tests/unit/http_request_test.cpp deleted file mode 100644 index 800c972..0000000 --- a/tests/unit/http_request_test.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include -#include -#include -#include -#include -#include "error.h" -#include "http.h" -#include "http_request.h" - -TEST(HttpRequestTest, ParseValidRequest) -{ - std::string request = "GET /api/users HTTP/1.1\r\n" - "Host: example.com\r\n" - "User-Agent: Mozilla/5.0\r\n" - "Content-Length: 10\r\n" - "\r\n" - "Hello World"; - - std::error_code ec; - pine::http_request parsedRequest = pine::http_request::parse(request, ec); - - ASSERT_FALSE(ec); - ASSERT_EQ(pine::http_method::get, parsedRequest.get_method()); - ASSERT_EQ("/api/users", parsedRequest.get_uri()); - ASSERT_EQ(pine::http_version::http_1_1, parsedRequest.get_version()); - - std::map expectedHeaders = { - {"Host", "example.com"}, - {"User-Agent", "Mozilla/5.0"}, - {"Content-Length", "10"} - }; - ASSERT_EQ(expectedHeaders, parsedRequest.get_headers()); - - ASSERT_EQ("Hello World", parsedRequest.get_body()); -} - -TEST(HttpRequestTest, ParseInvalidRequest) -{ - std::string request = "INVALID REQUEST"; - - std::error_code ec; - pine::http_request parsedRequest = pine::http_request::parse(request, ec); - - ASSERT_TRUE(ec); - ASSERT_EQ(static_cast(pine::error::parse_error_method), ec.value()); - ASSERT_EQ(pine::http_method{}, parsedRequest.get_method()); - ASSERT_TRUE(parsedRequest.get_uri().empty()); - ASSERT_EQ(pine::http_version{}, parsedRequest.get_version()); - ASSERT_TRUE(parsedRequest.get_headers().empty()); - ASSERT_TRUE(parsedRequest.get_body().empty()); -} - -TEST(HttpRequestTest, GetHeaderExisting) -{ - std::map headers = { - {"Content-Type", "application/json"}, - {"Authorization", "Bearer token"} - }; - pine::http_request request(pine::http_method::get, "/api/users", pine::http_version::http_1_1, headers, ""); - - std::string headerValue = request.get_header("Content-Type"); - - ASSERT_EQ("application/json", headerValue); -} - -TEST(HttpRequestTest, GetHeaderNonExisting) -{ - std::map headers = { - {"Authorization", "Bearer token"}, - {"Content-Type", "application/json"} - }; - pine::http_request request(pine::http_method::get, "/api/users", pine::http_version::http_1_1, headers, ""); - - std::string headerValue = request.get_header("Accept"); - - ASSERT_TRUE(headerValue.empty()); -} - -TEST(HttpRequestTest, ToString) -{ - std::map headers = { - {"Authorization", "Bearer token"}, - {"Content-Type", "application/json"} - }; - pine::http_request request(pine::http_method::post, "/api/users", pine::http_version::http_1_1, headers, "Hello World"); - - std::string expectedString = "POST /api/users HTTP/1.1\r\n" - "Authorization: Bearer token\r\n" - "Content-Type: application/json\r\n" - "\r\n" - "Hello World"; - - std::string toStringResult = request.to_string(); - - ASSERT_EQ(expectedString, toStringResult); -} diff --git a/tests/unit/http_request_tests.cpp b/tests/unit/http_request_tests.cpp new file mode 100644 index 0000000..35a53b7 --- /dev/null +++ b/tests/unit/http_request_tests.cpp @@ -0,0 +1,80 @@ +#include +#include "error.h" +#include "http_request.h" + +TEST(HttpRequestTests, DefaultConstructor) +{ + pine::http_request request; + EXPECT_EQ(pine::http_method::get, request.get_method()); + EXPECT_EQ("", request.get_uri()); + EXPECT_EQ(pine::http_version::http_1_1, request.get_version()); + EXPECT_TRUE(request.get_headers().empty()); + EXPECT_EQ("", request.get_body()); +} + +TEST(HttpRequestTests, ParameterizedConstructor) +{ + pine::http_request request(pine::http_method::post, "/api/users", pine::http_version::http_1_1, + {{"Content-Type", "application/json"}, {"Authorization", "Bearer token"}}, + R"({"name": "John Doe", "age": 30})"); + + EXPECT_EQ(pine::http_method::post, request.get_method()); + EXPECT_EQ("/api/users", request.get_uri()); + EXPECT_EQ(pine::http_version::http_1_1, request.get_version()); + EXPECT_EQ(2, request.get_headers().size()); + EXPECT_EQ("application/json", request.get_header("Content-Type")); + EXPECT_EQ("Bearer token", request.get_header("Authorization")); + EXPECT_EQ(R"({"name": "John Doe", "age": 30})", request.get_body()); +} + +TEST(HttpRequestTests, SettersAndGetters) +{ + pine::http_request request; + + request.set_method(pine::http_method::post); + request.set_uri("/api/products"); + request.set_version(pine::http_version::http_1_1); + request.set_header("Content-Type", "application/xml"); + request.set_body("Widget9.99"); + + EXPECT_EQ(pine::http_method::post, request.get_method()); + EXPECT_EQ("/api/products", request.get_uri()); + EXPECT_EQ(pine::http_version::http_1_1, request.get_version()); + EXPECT_EQ(1, request.get_headers().size()); + EXPECT_EQ("application/xml", request.get_header("Content-Type")); + EXPECT_EQ("Widget9.99", request.get_body()); +} + +TEST(HttpRequestTests, ParseValidRequest) +{ + std::string requestStr = "GET /api/users HTTP/1.1\r\n" + "Host: example.com\r\n" + "User-Agent: Mozilla/5.0\r\n" + "Accept: application/json\r\n" + "\r\n"; + + auto result = pine::http_request::parse(requestStr); + ASSERT_TRUE(result.has_value()); + + pine::http_request request = result.value(); + + EXPECT_EQ(pine::http_method::get, request.get_method()); + EXPECT_EQ("/api/users", request.get_uri()); + EXPECT_EQ(pine::http_version::http_1_1, request.get_version()); + EXPECT_EQ(3, request.get_headers().size()); + EXPECT_EQ("example.com", request.get_header("Host")); + EXPECT_EQ("Mozilla/5.0", request.get_header("User-Agent")); + EXPECT_EQ("application/json", request.get_header("Accept")); + EXPECT_EQ("", request.get_body()); +} + +TEST(HttpRequestTests, ParseInvalidRequest) +{ + std::string requestStr = "INVALID REQUEST"; + + auto result = pine::http_request::parse(requestStr); + ASSERT_FALSE(result.has_value()); + + std::error_code error = result.error(); + EXPECT_EQ(pine::make_error_code(pine::error::parse_error_method), error); +} diff --git a/tests/unit/http_response_test.cpp b/tests/unit/http_response_test.cpp deleted file mode 100644 index 5f36a12..0000000 --- a/tests/unit/http_response_test.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include -#include "http_response.h" - -TEST(HttpResponseTest, Parse_ValidResponse_ReturnsExpectedValues) -{ - std::string response = "HTTP/1.1 200 OK\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 100\r\n" - "\r\n" - "Hello, World!"; - - std::error_code ec; - pine::http_response result = pine::http_response::parse(response, ec); - - ASSERT_FALSE(ec); - EXPECT_EQ(pine::http_version::http_1_1, result.get_version()); - EXPECT_EQ(pine::http_status::ok, result.get_status()); - EXPECT_EQ("text/html", result.get_header("Content-Type")); - EXPECT_EQ("100", result.get_header("Content-Length")); - EXPECT_EQ("Hello, World!", result.get_body()); -} - -TEST(HttpResponseTest, Parse_InvalidResponse_ReturnsEmptyResponse) -{ - std::string response = "Invalid Response"; - - std::error_code ec; - pine::http_response result = pine::http_response::parse(response, ec); - - ASSERT_TRUE(ec); - EXPECT_EQ(pine::http_version::http_1_1, result.get_version()); - EXPECT_EQ(pine::http_status::ok, result.get_status()); - EXPECT_EQ("", result.get_header("Content-Type")); - EXPECT_EQ("", result.get_header("Content-Length")); - EXPECT_EQ("", result.get_body()); -} - -TEST(HttpResponseTest, GetHeader_ValidHeader_ReturnsExpectedValue) -{ - std::string response = "HTTP/1.1 200 OK\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 100\r\n" - "\r\n" - "Hello, World!"; - - std::error_code ec; - pine::http_response result = pine::http_response::parse(response, ec); - - ASSERT_FALSE(ec); - EXPECT_EQ("text/html", result.get_header("Content-Type")); - EXPECT_EQ("100", result.get_header("Content-Length")); -} - -TEST(HttpResponseTest, GetHeader_InvalidHeader_ReturnsEmptyString) -{ - std::string response = "HTTP/1.1 200 OK\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 100\r\n" - "\r\n" - "Hello, World!"; - - std::error_code ec; - pine::http_response result = pine::http_response::parse(response, ec); - - ASSERT_FALSE(ec); - EXPECT_EQ("", result.get_header("Invalid-Header")); -} - -TEST(HttpResponseTest, ToString_ReturnsExpectedString) -{ - std::string response = "HTTP/1.1 200 OK\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 100\r\n" - "\r\n" - "Hello, World!"; - - std::error_code ec; - pine::http_response result = pine::http_response::parse(response, ec); - - ASSERT_FALSE(ec); - - std::string expectedString = "HTTP/1.1 200 OK\r\n" - "Content-Length: 100\r\n" - "Content-Type: text/html\r\n" - "\r\n" - "Hello, World!"; - - EXPECT_EQ(expectedString, result.to_string()); -} diff --git a/tests/unit/http_response_tests.cpp b/tests/unit/http_response_tests.cpp new file mode 100644 index 0000000..a80b550 --- /dev/null +++ b/tests/unit/http_response_tests.cpp @@ -0,0 +1,65 @@ +#include +#include "http_response.h" + +using namespace pine; + +TEST(HttpResponseTests, GetBody_ReturnsCorrectValue) +{ + http_response response; + response.set_body("Hello, World!"); + + EXPECT_EQ("Hello, World!", response.get_body()); +} + +TEST(HttpResponseTests, GetHeader_ReturnsCorrectValue) +{ + http_response response; + response.set_header("Content-Type", "application/json"); + + EXPECT_EQ("application/json", response.get_header("Content-Type")); +} + +TEST(HttpResponseTests, GetHeaders_ReturnsCorrectValue) +{ + http_response response; + response.set_header("Content-Type", "application/json"); + response.set_header("Content-Length", "100"); + + const auto& headers = response.get_headers(); + + EXPECT_EQ("application/json", headers.at("Content-Type")); + EXPECT_EQ("100", headers.at("Content-Length")); +} + +TEST(HttpResponseTests, GetStatus_ReturnsCorrectValue) +{ + http_response response; + response.set_status(http_status::ok); + + EXPECT_EQ(http_status::ok, response.get_status()); +} + +TEST(HttpResponseTests, GetVersion_ReturnsCorrectValue) +{ + http_response response; + response.set_version(http_version::http_1_1); + + EXPECT_EQ(http_version::http_1_1, response.get_version()); +} + +TEST(HttpResponseTests, ToString_ReturnsCorrectValue) +{ + http_response response; + response.set_status(http_status::ok); + response.set_version(http_version::http_1_1); + response.set_header("Content-Type", "application/json"); + response.set_body("Hello, World!"); + + std::string expected = "HTTP/1.1 200 OK\r\n"; + expected += "Content-Length: 13\r\n"; + expected += "Content-Type: application/json\r\n"; + expected += "\r\n"; + expected += "Hello, World!"; + + EXPECT_EQ(expected, response.to_string()); +} diff --git a/tests/unit/http_tests.cpp b/tests/unit/http_tests.cpp new file mode 100644 index 0000000..d39c51d --- /dev/null +++ b/tests/unit/http_tests.cpp @@ -0,0 +1,91 @@ +#include +#include "error.h" +#include "http.h" + +using namespace pine; + +TEST(HttpTests, HttpMethodStrings) +{ + EXPECT_EQ("GET", http_method_strings.at(http_method::get)); + EXPECT_EQ("HEAD", http_method_strings.at(http_method::head)); + EXPECT_EQ("POST", http_method_strings.at(http_method::post)); +} + +TEST(HttpTests, HttpStatusStrings) +{ + EXPECT_EQ("OK", http_status_strings.at(http_status::ok)); + EXPECT_EQ("Bad Request", http_status_strings.at(http_status::bad_request)); + EXPECT_EQ("Not Found", http_status_strings.at(http_status::not_found)); + EXPECT_EQ("Internal Server Error", http_status_strings.at(http_status::internal_server_error)); +} + +TEST(HttpTests, HttpVersionStrings) +{ + EXPECT_EQ("HTTP/1.1", http_version_strings.at(http_version::http_1_1)); +} + +TEST(HttpUtilsTests, TryGetBody) +{ + std::string_view request = "GET /index.html HTTP/1.1\r\nHost: example.com\r\n\r\nHello World"; + size_t offset = 47; + auto result = http_utils::try_get_body(request, offset); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ("Hello World", result.value()); +} + +TEST(HttpUtilsTests, TryGetHeaders) +{ + std::string request = "GET /index.html HTTP/1.1\r\nHost: example.com\r\nContent-Type: text/html\r\n\r\n"; + size_t offset = 26; + auto result = http_utils::try_get_headers(request, offset); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(2, result.value().size()); + EXPECT_EQ("example.com", result.value().at("Host")); + EXPECT_EQ("text/html", result.value().at("Content-Type")); +} + +TEST(HttpUtilsTests, TryGetHeader) +{ + std::string_view request = "GET /index.html HTTP/1.1\r\nHost: example.com\r\n\r\n"; + size_t offset = 26; + auto result = http_utils::try_get_header(request, offset); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ("Host", result.value().first); + EXPECT_EQ("example.com", result.value().second); +} + +TEST(HttpUtilsTests, TryGetMethod) +{ + std::string_view request = "GET /index.html HTTP/1.1\r\nHost: example.com\r\n\r\n"; + size_t offset = 0; + auto result = http_utils::try_get_method(request, offset); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(http_method::get, result.value()); +} + +TEST(HttpUtilsTests, TryGetStatus) +{ + std::string_view response = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"; + size_t offset = 9; + auto result = http_utils::try_get_status(response, offset); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(http_status::ok, result.value()); +} + +TEST(HttpUtilsTests, TryGetUri) +{ + std::string_view request = "GET /index.html HTTP/1.1\r\nHost: example.com\r\n\r\n"; + size_t offset = 4; + auto result = http_utils::try_get_uri(request, offset); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ("/index.html", result.value()); +} + +TEST(HttpUtilsTests, TryGetVersion) +{ + std::string_view request = "GET /index.html HTTP/1.1\r\nHost: example.com\r\n\r\n"; + size_t offset = 16; + auto result = http_utils::try_get_version(request, offset); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(http_version::http_1_1, result.value()); +} diff --git a/tests/unit/http_utils_test.cpp b/tests/unit/http_utils_test.cpp deleted file mode 100644 index 45f79e3..0000000 --- a/tests/unit/http_utils_test.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include -#include -#include -#include -#include -#include "http.h" - -using namespace pine; -using namespace pine::http_utils; - -TEST(HttpUtilsTest, FindBody) -{ - std::string_view request = "GET /api/users HTTP/1.1\r\n" - "Host: example.com\r\n" - "Content-Type: application/json\r\n" - "\r\n" - "{\"name\":\"John\",\"age\":30}"; - - // index of the first character of the body - size_t offset = request.find("{\"name"); - std::error_code ec; - std::string body = try_get_body(request, offset, ec); - - EXPECT_EQ(ec, std::error_code{}); - EXPECT_EQ(body, "{\"name\":\"John\",\"age\":30}"); -} - -TEST(HttpUtilsTest, FindHeader) -{ - std::string_view request = "GET /api/users HTTP/1.1\r\n" - "Host: example.com\r\n" - "Content-Type: application/json\r\n" - "\r\n" - "{\"name\":\"John\",\"age\":30}"; - - size_t offset = request.find("Host:"); - std::error_code ec; - auto [name, value] = try_get_header(request, offset, ec); - - EXPECT_EQ(ec, std::error_code{}); - EXPECT_EQ(name, "Host"); - EXPECT_EQ(value, "example.com"); -} - -TEST(HttpUtilsTest, FindHeaders) -{ - std::string request = "GET /api/users HTTP/1.1\r\n" - "Host: example.com\r\n" - "Content-Type: application/json\r\n" - "\r\n" - "{\"name\":\"John\",\"age\":30}"; - - size_t offset = request.find("Host"); - std::error_code ec; - std::map headers = try_get_headers(request, offset, ec); - - EXPECT_EQ(ec, std::error_code{}); - EXPECT_EQ(headers.size(), 2); - EXPECT_EQ(headers["Host"], "example.com"); - EXPECT_EQ(headers["Content-Type"], "application/json"); -} - -TEST(HttpUtilsTest, FindMethod) -{ - std::string_view request = "GET /api/users HTTP/1.1\r\n" - "Host: example.com\r\n" - "Content-Type: application/json\r\n" - "\r\n" - "{\"name\":\"John\",\"age\":30}"; - - size_t offset = 0; - std::error_code ec; - http_method method = try_get_method(request, offset, ec); - - EXPECT_EQ(ec, std::error_code{}); - EXPECT_EQ(method, http_method::get); -} - -TEST(HttpUtilsTest, FindStatus) -{ - std::string_view request = "HTTP/1.1 200 OK\r\n" - "Content-Type: application/json\r\n" - "\r\n" - "{\"name\":\"John\",\"age\":30}"; - - size_t offset = request.find("200"); - std::error_code ec; - http_status status = try_get_status(request, offset, ec); - - EXPECT_EQ(ec, std::error_code{}); - EXPECT_EQ(status, http_status::ok); -} - -TEST(HttpUtilsTest, FindUri) -{ - std::string_view request = "GET /api/users HTTP/1.1\r\n" - "Host: example.com\r\n" - "Content-Type: application/json\r\n" - "\r\n" - "{\"name\":\"John\",\"age\":30}"; - - size_t offset = request.find("/api/users"); - std::error_code ec; - std::string uri = try_get_uri(request, offset, ec); - - EXPECT_EQ(ec, std::error_code{}); - EXPECT_EQ(uri, "/api/users"); -} - -TEST(HttpUtilsTest, FindVersion) -{ - std::string_view request = "GET /api/users HTTP/1.1\r\n" - "Host: example.com\r\n" - "Content-Type: application/json\r\n" - "\r\n" - "{\"name\":\"John\",\"age\":30}"; - - size_t offset = request.find("HTTP/1.1"); - std::error_code ec; - http_version version = try_get_version(request, offset, ec); - - EXPECT_EQ(ec, std::error_code{}); - EXPECT_EQ(version, http_version::http_1_1); -} diff --git a/tests/unit/thread_pool_test.cpp b/tests/unit/thread_pool_test.cpp deleted file mode 100644 index 7167f13..0000000 --- a/tests/unit/thread_pool_test.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include -#include -#include -#include -#include "gtest/gtest.h" -#include "thread_pool.h" - -TEST(ThreadPoolTests, EnqueueTask) -{ - pine::thread_pool& pool = pine::thread_pool::get_instance(); - - int result = 0; - auto task = [&result]() { result = 42; }; - - pool.enqueue(task); - - // Wait for the task to be executed - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - - EXPECT_EQ(result, 42); -} - -TEST(ThreadPoolTests, EnqueueMultipleTasks) -{ - pine::thread_pool& pool = pine::thread_pool::get_instance(); - - std::vector results(5, 0); - std::vector> tasks; - - for (int i = 0; i < 5; ++i) - { - tasks.emplace_back([i, &results]() { results[i] = i * 10; }); - pool.enqueue(tasks.back()); - } - - // Wait for the tasks to be executed - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - - for (int i = 0; i < 5; ++i) - { - EXPECT_EQ(results[i], i * 10); - } -} - -TEST(ThreadPoolTests, EnqueueLambdaTask) -{ - pine::thread_pool& pool = pine::thread_pool::get_instance(); - - int result = 0; - - pool.enqueue([&result]() { result = 100; }); - - // Wait for the task to be executed - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - - EXPECT_EQ(result, 100); -} - -TEST(ThreadPoolTests, EnqueueFunctionObjectTask) -{ - pine::thread_pool& pool = pine::thread_pool::get_instance(); - - struct Task - { - int& result; - - Task(int& r) : result(r) {} - - void operator()() - { - result = 200; - } - }; - - int result = 0; - Task task(result); - - pool.enqueue(task); - - // Wait for the task to be executed - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - - EXPECT_EQ(result, 200); -}