test: add send module unit tests
This commit is contained in:
parent
3c56ea024b
commit
d938d0ca4d
5 changed files with 456 additions and 0 deletions
62
tests/send/test_prepare_destination.c
Normal file
62
tests/send/test_prepare_destination.c
Normal 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");
|
||||
}
|
||||
98
tests/send/test_send_echo.c
Normal file
98
tests/send/test_send_echo.c
Normal 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);
|
||||
}
|
||||
92
tests/send/test_send_packet.c
Normal file
92
tests/send/test_send_packet.c
Normal 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
140
tests/send/test_send_raw.c
Normal 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'");
|
||||
}
|
||||
64
tests/send/test_set_socket_ttl.c
Normal file
64
tests/send/test_set_socket_ttl.c
Normal 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);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue