test: add send module unit tests

This commit is contained in:
lohhiiccc 2026-01-26 20:14:11 +01:00
parent 3c56ea024b
commit d938d0ca4d
5 changed files with 456 additions and 0 deletions

View file

@ -0,0 +1,62 @@
#include <criterion/criterion.h>
#include <arpa/inet.h>
#include <string.h>
#include "internal/icmp_send.h"
/* Test 1: Basic destination preparation */
Test(send_prepare_destination, basic)
{
struct sockaddr_in addr;
struct in_addr dest;
dest.s_addr = inet_addr("192.168.1.1");
send_prepare_destination(&addr, dest);
cr_assert_eq(addr.sin_family, AF_INET, "Family should be AF_INET");
cr_assert_eq(addr.sin_addr.s_addr, dest.s_addr,
"Address should match destination");
}
/* Test 2: Verify sin_port is 0 for ICMP */
Test(send_prepare_destination, port_is_zero)
{
struct sockaddr_in addr;
struct in_addr dest;
dest.s_addr = inet_addr("127.0.0.1");
send_prepare_destination(&addr, dest);
cr_assert_eq(addr.sin_port, 0, "Port should be 0 for ICMP");
}
/* Test 3: Verify struct is zeroed */
Test(send_prepare_destination, struct_zeroed)
{
struct sockaddr_in addr;
memset(&addr, 0xFF, sizeof(addr)); /* Fill with garbage */
struct in_addr dest;
dest.s_addr = inet_addr("10.0.0.1");
send_prepare_destination(&addr, dest);
/* Check sin_zero is zeroed */
for (size_t i = 0; i < sizeof(addr.sin_zero); i++)
{
cr_assert_eq(addr.sin_zero[i], 0,
"sin_zero[%zu] should be 0", i);
}
}
/* Test 4: Localhost address */
Test(send_prepare_destination, localhost)
{
struct sockaddr_in addr;
struct in_addr dest;
dest.s_addr = inet_addr("127.0.0.1");
send_prepare_destination(&addr, dest);
cr_assert_eq(addr.sin_addr.s_addr, inet_addr("127.0.0.1"),
"Should handle localhost");
}

View file

@ -0,0 +1,98 @@
#include <criterion/criterion.h>
#include <arpa/inet.h>
#include "icmp.h"
#include "internal/icmp_internal.h"
#include "test_helpers.h"
/* Test 1: Send echo request successfully */
Test(send_echo, simple_echo)
{
if (0 == has_net_raw_capability())
{
cr_skip("Test requires CAP_NET_RAW or root privileges");
}
icmp_handle_t *h = icmp_create();
cr_assert_not_null(h);
struct in_addr dest;
dest.s_addr = inet_addr("127.0.0.1");
int ret = icmp_send_echo(h, dest, 0x1234, 1, 64);
cr_assert_eq(ret, 0, "Expected success (0)");
cr_assert_str_eq(icmp_strerror(h), "No error");
icmp_destroy(h);
}
/* Test 2: NULL handle returns -1 */
Test(send_echo, null_handle)
{
struct in_addr dest;
dest.s_addr = inet_addr("127.0.0.1");
int ret = icmp_send_echo(NULL, dest, 1, 1, 64);
cr_assert_eq(ret, -1, "Expected -1 for NULL handle");
}
/* Test 3: Invalid FD returns -1 */
Test(send_echo, invalid_fd)
{
struct icmp_handle h = {0};
h.fd = -1;
struct in_addr dest;
dest.s_addr = inet_addr("127.0.0.1");
int ret = icmp_send_echo((icmp_handle_t *)&h, dest, 1, 1, 64);
cr_assert_eq(ret, -1, "Expected -1 for invalid fd");
}
/* Test 4: Different TTL values */
Test(send_echo, different_ttl)
{
if (0 == has_net_raw_capability())
{
cr_skip("Test requires CAP_NET_RAW or root privileges");
}
icmp_handle_t *h = icmp_create();
cr_assert_not_null(h);
struct in_addr dest;
dest.s_addr = inet_addr("127.0.0.1");
int ret1 = icmp_send_echo(h, dest, 1, 1, 1);
cr_assert_eq(ret1, 0, "Expected success with TTL=1");
int ret2 = icmp_send_echo(h, dest, 1, 2, 255);
cr_assert_eq(ret2, 0, "Expected success with TTL=255");
icmp_destroy(h);
}
/* Test 5: Different id and seq values */
Test(send_echo, different_id_seq)
{
if (0 == has_net_raw_capability())
{
cr_skip("Test requires CAP_NET_RAW or root privileges");
}
icmp_handle_t *h = icmp_create();
cr_assert_not_null(h);
struct in_addr dest;
dest.s_addr = inet_addr("127.0.0.1");
int ret1 = icmp_send_echo(h, dest, 0xABCD, 42, 64);
cr_assert_eq(ret1, 0, "Expected success with id=0xABCD, seq=42");
int ret2 = icmp_send_echo(h, dest, 0, 0, 64);
cr_assert_eq(ret2, 0, "Expected success with id=0, seq=0");
icmp_destroy(h);
}

View file

@ -0,0 +1,92 @@
#include <criterion/criterion.h>
#include <arpa/inet.h>
#include <string.h>
#include "icmp.h"
#include "internal/icmp_internal.h"
#include "internal/icmp_send.h"
#include "test_helpers.h"
/* Test 1: Send simple packet successfully */
Test(send_packet, success)
{
if (0 == has_net_raw_capability())
{
cr_skip("Test requires CAP_NET_RAW or root privileges");
}
icmp_handle_t *h = icmp_create();
cr_assert_not_null(h);
struct icmp_handle *handle = (struct icmp_handle *)h;
/* Simple ICMP packet (type=8, code=0) */
uint8_t packet[] = {
0x08, 0x00, 0x00, 0x00, /* type, code, checksum */
0x00, 0x00, 0x00, 0x00 /* id, seq */
};
struct sockaddr_in dest;
memset(&dest, 0, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr("127.0.0.1");
int ret = send_packet(handle, packet, sizeof(packet), &dest);
cr_assert_eq(ret, 0, "Expected success (0)");
icmp_destroy(h);
}
/* Test 2: Invalid FD returns -1 */
Test(send_packet, invalid_fd)
{
struct icmp_handle h = {0};
h.fd = -1;
h.last_error = ICMP_OK;
h.error_msg[0] = '\0';
uint8_t packet[8] = {0};
struct sockaddr_in dest;
memset(&dest, 0, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr("127.0.0.1");
int ret = send_packet(&h, packet, sizeof(packet), &dest);
cr_assert_eq(ret, -1, "Expected -1 for invalid FD");
cr_assert_eq(h.last_error, ICMP_ERR_SEND,
"Error code should be ICMP_ERR_SEND");
}
/* Test 3: Send with payload */
Test(send_packet, with_payload)
{
if (0 == has_net_raw_capability())
{
cr_skip("Test requires CAP_NET_RAW or root privileges");
}
icmp_handle_t *h = icmp_create();
cr_assert_not_null(h);
struct icmp_handle *handle = (struct icmp_handle *)h;
/* ICMP packet with payload */
uint8_t packet[16] = {
0x08, 0x00, 0x00, 0x00, /* type, code, checksum */
0x00, 0x00, 0x00, 0x00, /* id, seq */
'H', 'E', 'L', 'L', 'O', 0, 0, 0 /* payload */
};
struct sockaddr_in dest;
memset(&dest, 0, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr("127.0.0.1");
int ret = send_packet(handle, packet, sizeof(packet), &dest);
cr_assert_eq(ret, 0, "Expected success with payload");
icmp_destroy(h);
}

140
tests/send/test_send_raw.c Normal file
View file

@ -0,0 +1,140 @@
#include <criterion/criterion.h>
#include <string.h>
#include <arpa/inet.h>
#include "icmp.h"
#include "internal/icmp_internal.h"
#include "icmp_types.h"
#include "test_helpers.h"
/* Test 1: Send simple ICMP packet (type 8, no payload) */
Test(send_raw, simple_packet)
{
if (0 == has_net_raw_capability())
{
cr_skip("Test requires CAP_NET_RAW or root privileges");
}
icmp_handle_t *h = icmp_create();
cr_assert_not_null(h);
struct in_addr dest;
dest.s_addr = inet_addr("127.0.0.1");
int ret = icmp_send_raw(h, ICMP_TYPE_ECHO_REQUEST, 0, NULL, 0, dest, 64);
cr_assert_eq(ret, 0, "Expected success (0)");
cr_assert_str_eq(icmp_strerror(h), "No error");
icmp_destroy(h);
}
/* Test 2: Send packet with payload */
Test(send_raw, with_payload)
{
if (0 == has_net_raw_capability())
{
cr_skip("Test requires CAP_NET_RAW or root privileges");
}
icmp_handle_t *h = icmp_create();
cr_assert_not_null(h);
struct in_addr dest;
dest.s_addr = inet_addr("127.0.0.1");
const char payload[] = "HELLO";
int ret = icmp_send_raw(h, ICMP_TYPE_ECHO_REQUEST, 0,
payload, 5, dest, 64);
cr_assert_eq(ret, 0, "Expected success (0)");
cr_assert_str_eq(icmp_strerror(h), "No error");
icmp_destroy(h);
}
/* Test 3: NULL handle returns -1 */
Test(send_raw, null_handle)
{
struct in_addr dest;
dest.s_addr = inet_addr("127.0.0.1");
int ret = icmp_send_raw(NULL, ICMP_TYPE_ECHO_REQUEST, 0,
NULL, 0, dest, 64);
cr_assert_eq(ret, -1, "Expected -1 for NULL handle");
}
/* Test 4: NULL payload with len > 0 returns -1 */
Test(send_raw, null_payload_with_length)
{
if (0 == has_net_raw_capability())
{
cr_skip("Test requires CAP_NET_RAW or root privileges");
}
icmp_handle_t *h = icmp_create();
cr_assert_not_null(h);
struct in_addr dest;
dest.s_addr = inet_addr("127.0.0.1");
int ret = icmp_send_raw(h, ICMP_TYPE_ECHO_REQUEST, 0,
NULL, 10, dest, 64);
cr_assert_eq(ret, -1, "Expected -1 for NULL payload with len > 0");
const char *err = icmp_strerror(h);
cr_assert(NULL != strstr(err, "Payload") || NULL != strstr(err, "NULL"),
"Error message should mention payload or NULL");
icmp_destroy(h);
}
/* Test 5: Payload too large returns -1 */
Test(send_raw, payload_too_large)
{
if (0 == has_net_raw_capability())
{
cr_skip("Test requires CAP_NET_RAW or root privileges");
}
icmp_handle_t *h = icmp_create();
cr_assert_not_null(h);
struct in_addr dest;
dest.s_addr = inet_addr("127.0.0.1");
uint8_t large_payload[2000];
memset(large_payload, 0xAA, sizeof(large_payload));
int ret = icmp_send_raw(h, ICMP_TYPE_ECHO_REQUEST, 0,
large_payload, sizeof(large_payload), dest, 64);
cr_assert_eq(ret, -1, "Expected -1 for payload too large");
const char *err = icmp_strerror(h);
cr_assert(NULL != strstr(err, "large") || NULL != strstr(err, "too"),
"Error message should mention 'large' or 'too'");
icmp_destroy(h);
}
/* Test 6: Invalid FD returns -1 */
Test(send_raw, invalid_fd)
{
struct icmp_handle h = {0};
h.fd = -1;
h.last_error = ICMP_OK;
h.error_msg[0] = '\0';
struct in_addr dest;
dest.s_addr = inet_addr("127.0.0.1");
int ret = icmp_send_raw((icmp_handle_t *)&h, ICMP_TYPE_ECHO_REQUEST, 0,
NULL, 0, dest, 64);
cr_assert_eq(ret, -1, "Expected -1 for invalid FD");
cr_assert(NULL != strstr(h.error_msg, "Invalid") ||
NULL != strstr(h.error_msg, "socket"),
"Error message should mention 'Invalid' or 'socket'");
}

View file

@ -0,0 +1,64 @@
#include <criterion/criterion.h>
#include "icmp.h"
#include "internal/icmp_internal.h"
#include "internal/icmp_send.h"
#include "test_helpers.h"
/* Test 1: Set TTL successfully */
Test(send_set_socket_ttl, success)
{
if (0 == has_net_raw_capability())
{
cr_skip("Test requires CAP_NET_RAW or root privileges");
}
icmp_handle_t *h = icmp_create();
cr_assert_not_null(h);
struct icmp_handle *handle = (struct icmp_handle *)h;
int ret = send_set_socket_ttl(handle, 64);
cr_assert_eq(ret, 0, "Expected success (0)");
icmp_destroy(h);
}
/* Test 2: Invalid FD returns -1 */
Test(send_set_socket_ttl, invalid_fd)
{
struct icmp_handle h = {0};
h.fd = -1;
h.last_error = ICMP_OK;
h.error_msg[0] = '\0';
int ret = send_set_socket_ttl(&h, 64);
cr_assert_eq(ret, -1, "Expected -1 for invalid FD");
cr_assert_eq(h.last_error, ICMP_ERR_SOCKET,
"Error code should be ICMP_ERR_SOCKET");
}
/* Test 3: Different TTL values */
Test(send_set_socket_ttl, different_values)
{
if (0 == has_net_raw_capability())
{
cr_skip("Test requires CAP_NET_RAW or root privileges");
}
icmp_handle_t *h = icmp_create();
cr_assert_not_null(h);
struct icmp_handle *handle = (struct icmp_handle *)h;
/* TTL=1 */
int ret = send_set_socket_ttl(handle, 1);
cr_assert_eq(ret, 0, "Expected success with TTL=1");
/* TTL=255 */
ret = send_set_socket_ttl(handle, 255);
cr_assert_eq(ret, 0, "Expected success with TTL=255");
icmp_destroy(h);
}