test: add recv module unit tests

This commit is contained in:
lohhiiccc 2026-01-26 20:14:24 +01:00
parent d938d0ca4d
commit a3c60158e9
5 changed files with 300 additions and 0 deletions

View file

@ -0,0 +1,51 @@
#include <criterion/criterion.h>
#include "icmp.h"
#include "internal/icmp_recv.h"
#include <arpa/inet.h>
#include <string.h>
Test(build_reply, basic_reply)
{
icmp_reply_t reply;
uint8_t buffer[64];
struct in_addr src;
const char *payload_data = "test";
memset(buffer, 0, sizeof(buffer));
inet_pton(AF_INET, "192.168.1.1", &src);
recv_build_reply(&reply, 0, 0, 64, src, payload_data, 4, buffer, 20);
cr_assert_eq(reply.type, 0);
cr_assert_eq(reply.code, 0);
cr_assert_eq(reply.ttl, 64);
cr_assert_eq(reply.from.s_addr, src.s_addr);
cr_assert_eq(reply.payload, payload_data);
cr_assert_eq(reply.payload_len, 4);
cr_assert_not_null(reply.ip_payload);
}
Test(build_reply, different_types)
{
icmp_reply_t reply;
uint8_t buffer[64];
struct in_addr src;
inet_pton(AF_INET, "8.8.8.8", &src);
recv_build_reply(&reply, 3, 1, 128, src, NULL, 0, buffer, 20);
cr_assert_eq(reply.type, 3);
cr_assert_eq(reply.code, 1);
cr_assert_eq(reply.ttl, 128);
cr_assert_null(reply.payload);
cr_assert_eq(reply.payload_len, 0);
}
Test(build_reply, timestamp_set)
{
icmp_reply_t reply;
uint8_t buffer[64];
struct in_addr src;
inet_pton(AF_INET, "127.0.0.1", &src);
recv_build_reply(&reply, 0, 0, 64, src, NULL, 0, buffer, 20);
cr_assert(reply.timestamp.tv_sec > 0 || reply.timestamp.tv_nsec > 0,
"Timestamp should be set");
}

View file

@ -0,0 +1,74 @@
#include <criterion/criterion.h>
#include "icmp.h"
#include "internal/icmp_recv.h"
#include "internal/icmp_packet.h"
#include <arpa/inet.h>
#include <string.h>
static void
build_test_packet(uint8_t *buffer, size_t *len)
{
struct ip_header *ip;
struct icmp_header *icmp;
memset(buffer, 0, 64);
ip = (struct ip_header *)buffer;
ip->version_ihl = 0x45;
ip->ttl = 64;
ip->protocol = 1;
inet_pton(AF_INET, "192.168.1.1", &ip->saddr);
icmp = (struct icmp_header *)(buffer + 20);
icmp->type = 0;
icmp->code = 0;
*len = 28;
}
Test(parse_packet, valid_packet)
{
uint8_t buffer[64];
size_t buffer_len;
uint8_t type, code, ttl;
struct in_addr src_addr;
const void *payload;
size_t payload_len, ip_hdr_len;
int ret;
build_test_packet(buffer, &buffer_len);
ret = recv_parse_packet(buffer, buffer_len, &type, &code, &ttl,
&src_addr, &payload, &payload_len, &ip_hdr_len);
cr_assert_eq(ret, 0);
cr_assert_eq(type, 0);
cr_assert_eq(code, 0);
cr_assert_eq(ttl, 64);
cr_assert_eq(ip_hdr_len, 20);
}
Test(parse_packet, buffer_too_small)
{
uint8_t buffer[10];
uint8_t type, code, ttl;
struct in_addr src_addr;
const void *payload;
size_t payload_len, ip_hdr_len;
int ret;
ret = recv_parse_packet(buffer, sizeof(buffer), &type, &code, &ttl,
&src_addr, &payload, &payload_len, &ip_hdr_len);
cr_assert_eq(ret, -1);
}
Test(parse_packet, invalid_ip_version)
{
uint8_t buffer[64];
uint8_t type, code, ttl;
struct in_addr src_addr;
const void *payload;
size_t payload_len, ip_hdr_len;
int ret;
memset(buffer, 0, sizeof(buffer));
buffer[0] = 0x35;
ret = recv_parse_packet(buffer, 40, &type, &code, &ttl,
&src_addr, &payload, &payload_len, &ip_hdr_len);
cr_assert_eq(ret, -1);
}

82
tests/recv/test_process.c Normal file
View file

@ -0,0 +1,82 @@
#include <criterion/criterion.h>
#include "icmp.h"
#include "test_helpers.h"
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
static void
dummy_callback(const icmp_reply_t *reply, void *userdata)
{
(void)reply;
(void)userdata;
}
static void
counter_callback(const icmp_reply_t *reply, void *userdata)
{
int *count;
(void)reply;
count = (int *)userdata;
(*count)++;
}
Test(process, null_handle)
{
int ret;
ret = icmp_process(NULL, dummy_callback, NULL);
cr_assert_eq(ret, -1);
}
Test(process, null_callback)
{
icmp_handle_t *h;
int ret;
if (0 == has_net_raw_capability())
cr_skip("Test requires CAP_NET_RAW or root privileges");
h = icmp_create();
cr_assert_not_null(h);
ret = icmp_process(h, NULL, NULL);
cr_assert_eq(ret, -1);
cr_assert_str_eq(icmp_strerror(h), "Callback cannot be NULL");
icmp_destroy(h);
}
Test(process, no_packets_available)
{
icmp_handle_t *h;
int ret;
if (0 == has_net_raw_capability())
cr_skip("Test requires CAP_NET_RAW or root privileges");
h = icmp_create();
cr_assert_not_null(h);
ret = icmp_process(h, dummy_callback, NULL);
cr_assert_eq(ret, 0);
icmp_destroy(h);
}
Test(process, echo_loopback, .disabled = true)
{
icmp_handle_t *h;
struct in_addr dest;
int ret;
int count;
if (0 == has_net_raw_capability())
cr_skip("Test requires CAP_NET_RAW or root privileges");
h = icmp_create();
cr_assert_not_null(h);
inet_pton(AF_INET, "127.0.0.1", &dest);
ret = icmp_send_echo(h, dest, 1234, 1, 64);
cr_assert_eq(ret, 0);
sleep(1);
count = 0;
ret = icmp_process(h, counter_callback, &count);
cr_assert_eq(ret, 0);
cr_assert_geq(count, 1, "Should receive at least one packet");
icmp_destroy(h);
}

View file

@ -0,0 +1,32 @@
#include <criterion/criterion.h>
#include "icmp.h"
#include "internal/icmp_internal.h"
#include "internal/icmp_recv.h"
#include "test_helpers.h"
Test(receive_packet, invalid_fd)
{
uint8_t buffer[64];
struct sockaddr_in from;
ssize_t ret;
ret = recv_receive_packet(-1, buffer, sizeof(buffer), &from);
cr_assert_eq(ret, -1);
}
Test(receive_packet, no_data_available)
{
icmp_handle_t *h;
uint8_t buffer[64];
struct sockaddr_in from;
ssize_t ret;
if (0 == has_net_raw_capability())
cr_skip("Test requires CAP_NET_RAW or root privileges");
h = icmp_create();
cr_assert_not_null(h);
ret = recv_receive_packet(((struct icmp_handle *)h)->fd, buffer,
sizeof(buffer), &from);
cr_assert_eq(ret, 0, "Should return 0 when no data (EAGAIN)");
icmp_destroy(h);
}

View file

@ -0,0 +1,61 @@
#include <criterion/criterion.h>
#include "icmp.h"
#include "internal/icmp_internal.h"
#include "internal/icmp_recv.h"
#include "test_helpers.h"
static void
dummy_callback(const icmp_reply_t *reply, void *userdata)
{
(void)reply;
(void)userdata;
}
Test(validate_params, null_handle)
{
int ret;
ret = recv_validate_params(NULL, dummy_callback);
cr_assert_eq(ret, 0);
}
Test(validate_params, null_callback)
{
icmp_handle_t *h;
int ret;
if (0 == has_net_raw_capability())
cr_skip("Test requires CAP_NET_RAW or root privileges");
h = icmp_create();
cr_assert_not_null(h);
ret = recv_validate_params((struct icmp_handle *)h, NULL);
cr_assert_eq(ret, 0);
icmp_destroy(h);
}
Test(validate_params, invalid_fd)
{
struct icmp_handle h;
int ret;
h.fd = -1;
h.last_error = ICMP_OK;
h.error_msg[0] = '\0';
ret = recv_validate_params(&h, dummy_callback);
cr_assert_eq(ret, 0);
cr_assert_eq(h.last_error, ICMP_ERR_INVALID);
}
Test(validate_params, valid_params)
{
icmp_handle_t *h;
int ret;
if (0 == has_net_raw_capability())
cr_skip("Test requires CAP_NET_RAW or root privileges");
h = icmp_create();
cr_assert_not_null(h);
ret = recv_validate_params((struct icmp_handle *)h, dummy_callback);
cr_assert_eq(ret, 1);
icmp_destroy(h);
}