237 lines
7.3 KiB
C
237 lines
7.3 KiB
C
#include "runner.h"
|
|
#include "../colla.h"
|
|
#include <stdio.h>
|
|
|
|
// Initialization Tests
|
|
UNIT_TEST(net_init_cleanup) {
|
|
net_init();
|
|
// Simple test to make sure initialization succeeds
|
|
ASSERT(net_get_last_error() == 0);
|
|
net_cleanup();
|
|
}
|
|
|
|
// HTTP Method/Status Tests
|
|
UNIT_TEST(http_method_strings) {
|
|
ASSERT(strcmp(http_get_method_string(HTTP_GET), "GET") == 0);
|
|
ASSERT(strcmp(http_get_method_string(HTTP_POST), "POST") == 0);
|
|
ASSERT(strcmp(http_get_method_string(HTTP_HEAD), "HEAD") == 0);
|
|
ASSERT(strcmp(http_get_method_string(HTTP_PUT), "PUT") == 0);
|
|
ASSERT(strcmp(http_get_method_string(HTTP_DELETE), "DELETE") == 0);
|
|
}
|
|
|
|
UNIT_TEST(http_status_strings) {
|
|
ASSERT(strcmp(http_get_status_string(200), "OK") == 0);
|
|
ASSERT(strcmp(http_get_status_string(404), "NOT FOUND") == 0);
|
|
ASSERT(strcmp(http_get_status_string(500), "INTERNAL SERVER ERROR") == 0);
|
|
}
|
|
|
|
// HTTP Headers Tests
|
|
UNIT_TEST(http_headers) {
|
|
arena_t arena = arena_make(ARENA_MALLOC, KB(4));
|
|
|
|
// Parse headers
|
|
strview_t header_str = strv_init("Content-Type: application/json\r\nUser-Agent: Colla\r\n");
|
|
http_header_t *headers = http_parse_headers(&arena, header_str);
|
|
|
|
// Check headers were parsed correctly
|
|
ASSERT(headers != NULL);
|
|
|
|
// Headers are parsed in reverse order
|
|
ASSERT(strv_equals(headers->key, strv_init("User-Agent")));
|
|
ASSERT(strv_equals(headers->value, strv_init("Colla")));
|
|
ASSERT(strv_equals(headers->next->key, strv_init("Content-Type")));
|
|
ASSERT(strv_equals(headers->next->value, strv_init("application/json")));
|
|
|
|
// Test header operations
|
|
ASSERT(http_has_header(headers, strv_init("Content-Type")));
|
|
ASSERT(!http_has_header(headers, strv_init("Accept")));
|
|
|
|
strview_t content_type = http_get_header(headers, strv_init("Content-Type"));
|
|
ASSERT(strv_equals(content_type, strv_init("application/json")));
|
|
|
|
// Don't try to free headers as they're allocated in the arena
|
|
arena_cleanup(&arena);
|
|
}
|
|
|
|
// HTTP Request/Response Parsing Tests
|
|
UNIT_TEST(http_request_parsing) {
|
|
arena_t arena = arena_make(ARENA_MALLOC, KB(4));
|
|
|
|
strview_t req_str = strv_init(
|
|
"GET /index.html HTTP/1.1\r\n"
|
|
"Host: example.com\r\n"
|
|
"User-Agent: Colla\r\n"
|
|
"\r\n"
|
|
);
|
|
|
|
http_req_t req = http_parse_req(&arena, req_str);
|
|
|
|
ASSERT(req.method == HTTP_GET);
|
|
ASSERT(req.version.major == 1);
|
|
ASSERT(req.version.minor == 1);
|
|
ASSERT(strv_equals(req.url, strv("index.html")));
|
|
|
|
ASSERT(http_has_header(req.headers, strv_init("Host")));
|
|
ASSERT(strv_equals(http_get_header(req.headers, strv_init("Host")), strv_init("example.com")));
|
|
|
|
// Convert back to string
|
|
str_t req_out = http_req_to_str(&arena, &req);
|
|
ASSERT(!str_is_empty(req_out));
|
|
|
|
arena_cleanup(&arena);
|
|
}
|
|
|
|
UNIT_TEST(http_response_parsing) {
|
|
arena_t arena = arena_make(ARENA_MALLOC, KB(4));
|
|
|
|
strview_t res_str = strv_init(
|
|
"HTTP/1.1 200 OK\r\n"
|
|
"Content-Type: text/html\r\n"
|
|
"Content-Length: 13\r\n"
|
|
"\r\n"
|
|
"Hello, World!"
|
|
);
|
|
|
|
http_res_t res = http_parse_res(&arena, res_str);
|
|
|
|
ASSERT(res.status_code == 200);
|
|
ASSERT(res.version.major == 1);
|
|
ASSERT(res.version.minor == 1);
|
|
ASSERT(strv_equals(res.body, strv_init("Hello, World!")));
|
|
|
|
ASSERT(http_has_header(res.headers, strv_init("Content-Type")));
|
|
ASSERT(strv_equals(http_get_header(res.headers, strv_init("Content-Type")), strv_init("text/html")));
|
|
|
|
// Convert back to string
|
|
str_t res_out = http_res_to_str(&arena, &res);
|
|
ASSERT(!str_is_empty(res_out));
|
|
|
|
arena_cleanup(&arena);
|
|
}
|
|
|
|
// URL Encoding/Decoding Tests
|
|
UNIT_TEST(http_url_encoding) {
|
|
arena_t arena = arena_make(ARENA_MALLOC, KB(4));
|
|
|
|
strview_t original = strv_init("hello world & special chars: ?=&/");
|
|
str_t encoded = http_make_url_safe(&arena, original);
|
|
str_t decoded = http_decode_url_safe(&arena, strv_init_str(encoded));
|
|
|
|
ASSERT(!str_is_empty(encoded));
|
|
ASSERT(str_equals(decoded, str_init(&arena, "hello world & special chars: ?=&/")));
|
|
|
|
arena_cleanup(&arena);
|
|
}
|
|
|
|
UNIT_TEST(http_url_splitting) {
|
|
strview_t url = strv_init("http://example.com/path?query=value");
|
|
http_url_t split = http_split_url(url);
|
|
|
|
ASSERT(strv_equals(split.host, strv_init("example.com")));
|
|
ASSERT(strv_equals(split.uri, strv_init("/path?query=value")));
|
|
}
|
|
|
|
// HTTP Request Tests
|
|
// Note: These tests would actually make network requests, so we should mock them
|
|
// for real unit tests. Here we'll just test the setup part.
|
|
UNIT_TEST(http_request_setup) {
|
|
arena_t arena = arena_make(ARENA_MALLOC, KB(4));
|
|
|
|
// Prepare headers
|
|
http_header_t headers[2] = {
|
|
{ .key = strv_init("Content-Type"), .value = strv_init("application/json"), .next = &headers[1] },
|
|
{ .key = strv_init("User-Agent"), .value = strv_init("Colla Test"), .next = NULL }
|
|
};
|
|
|
|
// Setup request descriptor
|
|
http_request_desc_t desc = {
|
|
.arena = &arena,
|
|
.url = strv_init("http://example.com"),
|
|
.version = { .major = 1, .minor = 1 },
|
|
.request_type = HTTP_GET,
|
|
.headers = headers,
|
|
.header_count = 2,
|
|
.body = strv_init("")
|
|
};
|
|
|
|
// We don't actually make the request, just verify the setup is correct
|
|
ASSERT(desc.arena == &arena);
|
|
ASSERT(strv_equals(desc.url, strv_init("http://example.com")));
|
|
ASSERT(desc.request_type == HTTP_GET);
|
|
ASSERT(desc.headers == headers);
|
|
ASSERT(desc.header_count == 2);
|
|
|
|
arena_cleanup(&arena);
|
|
}
|
|
|
|
// Socket Tests
|
|
UNIT_TEST(socket_basic) {
|
|
net_init();
|
|
|
|
// Open a socket
|
|
socket_t sock = sk_open(SOCK_TCP);
|
|
ASSERT(sk_is_valid(sock));
|
|
|
|
// Close the socket
|
|
ASSERT(sk_close(sock));
|
|
|
|
net_cleanup();
|
|
}
|
|
|
|
// SHA1 Tests
|
|
UNIT_TEST(sha1_hash) {
|
|
arena_t arena = arena_make(ARENA_MALLOC, KB(4));
|
|
|
|
sha1_t ctx = sha1_init();
|
|
|
|
const char *data = "Hello, World!";
|
|
str_t hash = sha1_str(&arena, &ctx, data, strlen(data));
|
|
|
|
// The SHA1 hash for "Hello, World!" is known
|
|
// But we'll just verify it's not empty and has the expected format (40 hex chars)
|
|
ASSERT(!str_is_empty(hash));
|
|
ASSERT(hash.len == 40);
|
|
|
|
arena_cleanup(&arena);
|
|
}
|
|
|
|
// Base64 Tests
|
|
UNIT_TEST(base64_encoding) {
|
|
arena_t arena = arena_make(ARENA_MALLOC, KB(4));
|
|
|
|
const char *original = "Hello, World!";
|
|
buffer_t input = { (u8*)original, strlen(original) };
|
|
|
|
// Encode
|
|
buffer_t encoded = base64_encode(&arena, input);
|
|
ASSERT(encoded.data != NULL);
|
|
ASSERT(encoded.len > 0);
|
|
|
|
// Decode
|
|
buffer_t decoded = base64_decode(&arena, encoded);
|
|
|
|
ASSERT(decoded.data != NULL);
|
|
ASSERT(decoded.len == input.len);
|
|
ASSERT(memcmp(decoded.data, input.data, input.len) == 0);
|
|
|
|
arena_cleanup(&arena);
|
|
}
|
|
|
|
// WebSocket Tests
|
|
UNIT_TEST(websocket_encoding) {
|
|
arena_t arena = arena_make(ARENA_MALLOC, KB(4));
|
|
|
|
strview_t message = strv_init("Hello, WebSocket!");
|
|
|
|
// Encode message to WebSocket format
|
|
buffer_t encoded = websocket_encode(&arena, message);
|
|
ASSERT(encoded.data != NULL);
|
|
ASSERT(encoded.len > 0);
|
|
|
|
// Decode WebSocket message
|
|
str_t decoded = websocket_decode(&arena, encoded);
|
|
ASSERT(!str_is_empty(decoded));
|
|
ASSERT(str_equals(decoded, str_init(&arena, "Hello, WebSocket!")));
|
|
|
|
arena_cleanup(&arena);
|
|
}
|