#include "check.h" #include "../../src/femtotcp.c" #include /* for random() */ /* pseudo random number generator to mock the random number generator */ uint32_t ipstack_getrandom(void) { unsigned int seed = 0xDAC0FFEE; srandom(seed); return random(); } uint8_t mem[8 * 1024]; uint32_t memsz = 8 * 1024; START_TEST(test_fifo_init) { struct fifo f; fifo_init(&f, mem, memsz); ck_assert_int_eq(fifo_len(&f), 0); ck_assert_int_eq(fifo_space(&f), memsz); ck_assert_int_eq(fifo_len(&f), 0); } END_TEST START_TEST(test_fifo_push_and_pop) { struct fifo f; struct pkt_desc *desc, *desc2; uint8_t data[] = {1, 2, 3, 4, 5}; fifo_init(&f, mem, memsz); ck_assert_int_eq(fifo_space(&f), memsz); // Test push ck_assert_int_eq(fifo_push(&f, data, sizeof(data)), 0); // Test peek desc = fifo_peek(&f); ck_assert_ptr_nonnull(desc); ck_assert_int_eq(desc->len, sizeof(data)); ck_assert_mem_eq(f.data + desc->pos + sizeof(struct pkt_desc), data, sizeof(data)); desc2 = fifo_peek(&f); ck_assert_ptr_nonnull(desc2); ck_assert_ptr_eq(desc, desc2); ck_assert_int_eq(fifo_len(&f), desc->len + sizeof(struct pkt_desc)); // Test pop desc = fifo_pop(&f); ck_assert_int_eq(fifo_space(&f), memsz); ck_assert_ptr_nonnull(desc); ck_assert_int_eq(desc->len, sizeof(data)); ck_assert_mem_eq(f.data + desc->pos + sizeof(struct pkt_desc), data, sizeof(data)); ck_assert_int_eq(fifo_len(&f), 0); } END_TEST START_TEST(test_fifo_push_and_pop_multiple) { struct fifo f; uint8_t data[] = {1, 2, 3, 4, 5}; uint8_t data2[] = {6, 7, 8, 9, 10}; fifo_init(&f, mem, memsz); ck_assert_int_eq(fifo_space(&f), memsz); // Test push ck_assert_int_eq(fifo_push(&f, data, sizeof(data)), 0); ck_assert_int_eq(fifo_len(&f), sizeof(data) + sizeof(struct pkt_desc)); ck_assert_int_eq(fifo_space(&f), f.size - (sizeof(data) + sizeof(struct pkt_desc))); ck_assert_int_eq(fifo_push(&f, data2, sizeof(data2)), 0); // Test pop struct pkt_desc *desc = fifo_pop(&f); ck_assert_ptr_nonnull(desc); ck_assert_int_eq(desc->len, sizeof(data)); ck_assert_mem_eq(f.data + desc->pos + sizeof(struct pkt_desc), data, sizeof(data)); desc = fifo_pop(&f); ck_assert_ptr_nonnull(desc); ck_assert_int_eq(desc->len, sizeof(data2)); ck_assert_mem_eq(f.data + desc->pos + sizeof(struct pkt_desc), data2, sizeof(data2)); } END_TEST START_TEST(test_fifo_pop_success) { struct fifo f; uint8_t data[] = {1, 2, 3, 4}; fifo_init(&f, mem, memsz); fifo_push(&f, data, sizeof(data)); // Add data to FIFO struct pkt_desc *desc = fifo_pop(&f); ck_assert_ptr_nonnull(desc); // Ensure we got a valid descriptor ck_assert_int_eq(desc->len, sizeof(data)); // Check length ck_assert_mem_eq(f.data + desc->pos + sizeof(struct pkt_desc), data, sizeof(data)); // Check data } START_TEST(test_fifo_pop_empty) { struct fifo f; fifo_init(&f, mem, memsz); struct pkt_desc *desc = fifo_pop(&f); ck_assert_ptr_eq(desc, NULL); // Ensure pop returns NULL on empty FIFO } START_TEST(test_fifo_push_full) { struct fifo f; uint8_t data[8 * 1024] = {1, 2, 3, 4}; int ret; fifo_init(&f, mem, memsz); fifo_push(&f, data, sizeof(data)); // Add data to FIFO ret = fifo_push(&f, data, sizeof(data)); ck_assert_int_eq(ret, -1); // Ensure push returns -1 when FIFO is full } END_TEST START_TEST(test_fifo_push_wrap) { struct fifo f; uint8_t buffer[100]; uint8_t data[] = {1, 2, 3, 4}; int ret; fifo_init(&f, buffer, sizeof(buffer)); fifo_push(&f, data, sizeof(data)); // Add data to FIFO // Pop the data to make space struct pkt_desc *desc = fifo_pop(&f); ck_assert_ptr_nonnull(desc); // Push data to wrap around the buffer ret = fifo_push(&f, data, sizeof(data)); ck_assert_int_eq(ret, 0); ck_assert_int_eq(desc->len, sizeof(data)); ck_assert_mem_eq(f.data + desc->pos + sizeof(struct pkt_desc), data, sizeof(data)); } END_TEST START_TEST(test_fifo_push_wrap_multiple) { struct fifo f; uint8_t data[] = {1, 2, 3, 4}; uint8_t data2[] = {5, 6, 7, 8, 9}; int ret; fifo_init(&f, mem, memsz); fifo_push(&f, data, sizeof(data)); // Add data to FIFO // Pop the data to make space struct pkt_desc *desc = fifo_pop(&f); ck_assert_ptr_nonnull(desc); // Push data to wrap around the buffer ret = fifo_push(&f, data, sizeof(data)); ck_assert_int_eq(ret, 0); ck_assert_int_eq(desc->len, sizeof(data)); ck_assert_mem_eq(f.data + desc->pos + sizeof(struct pkt_desc), data, sizeof(data)); // Push more data to wrap around the buffer ret = fifo_push(&f, data2, sizeof(data2)); ck_assert_int_eq(ret, 0); ck_assert_int_eq(fifo_len(&f), sizeof(data2) + sizeof(data) + 2 * sizeof(struct pkt_desc)); } END_TEST START_TEST(test_fifo_next_success) { struct fifo f; uint8_t data1[] = {1, 2, 3, 4}; uint8_t data2[] = {5, 6, 7, 8, 9}; fifo_init(&f, mem, memsz); // Add two packets to the FIFO fifo_push(&f, data1, sizeof(data1)); fifo_push(&f, data2, sizeof(data2)); ck_assert_int_eq(fifo_len(&f), sizeof(data1) + sizeof(data2) + 2 * sizeof(struct pkt_desc)); // Get the first packet descriptor struct pkt_desc *desc = fifo_peek(&f); ck_assert_ptr_nonnull(desc); // Get the next packet descriptor using fifo_next struct pkt_desc *next_desc = fifo_next(&f, desc); ck_assert_ptr_nonnull(next_desc); // Ensure next descriptor is valid ck_assert_int_eq(next_desc->len, sizeof(data2)); // Check length of next packet } START_TEST(test_fifo_next_empty_fifo) { struct fifo f; fifo_init(&f, mem, memsz); // Start with an empty FIFO struct pkt_desc *desc = NULL; struct pkt_desc *next_desc = fifo_next(&f, desc); ck_assert_ptr_eq(next_desc, NULL); // Ensure next returns NULL on empty FIFO } START_TEST(test_fifo_next_end_of_fifo) { struct fifo f; uint8_t data[] = {1, 2, 3, 4}; fifo_init(&f, mem, memsz); fifo_push(&f, data, sizeof(data)); struct pkt_desc *desc = fifo_peek(&f); // Get first packet fifo_pop(&f); // Simulate removing the packet struct pkt_desc *next_desc = fifo_next(&f, desc); ck_assert_ptr_eq(next_desc, NULL); // Should return NULL as there are no more packets } END_TEST START_TEST(test_queue_init) { struct queue q; queue_init(&q, mem, memsz, 0x12345678); ck_assert_int_eq(q.size, memsz); ck_assert_ptr_eq(q.data, mem); ck_assert_int_eq(q.head, 0); ck_assert_int_eq(q.tail, 0); ck_assert_int_eq(q.seq_base, 0x12345678); } END_TEST START_TEST(test_queue_space_empty) { struct queue q; queue_init(&q, mem, memsz, 0x12345678); ck_assert_int_eq(queue_space(&q), memsz); // Full space should be available } END_TEST START_TEST(test_queue_len_empty) { struct queue q; queue_init(&q, mem, memsz, 0x12345678); ck_assert_int_eq(queue_len(&q), 0); // No bytes should be in use } END_TEST START_TEST(test_queue_partial_fill) { struct queue q; queue_init(&q, mem, memsz, 0x12345678); q.head = 256; // Simulate adding 256 bytes of data ck_assert_int_eq(queue_space(&q), memsz - 256); ck_assert_int_eq(queue_len(&q), 256); } END_TEST START_TEST(test_queue_wrap_around) { struct queue q; queue_init(&q, mem, memsz, 0x12345678); q.head = 800; q.tail = 200; // Head has wrapped around, so 600 bytes are filled ck_assert_int_eq(queue_space(&q), q.size - 600); ck_assert_int_eq(queue_len(&q), 600); // 600 bytes filled } END_TEST START_TEST(test_queue_insert_empty) { struct queue q; queue_init(&q, mem, memsz, 0x12345678); uint8_t data[] = {1, 2, 3, 4}; int res = queue_insert(&q, data, 0, sizeof(data)); ck_assert_int_eq(res, 0); ck_assert_int_eq(queue_len(&q), sizeof(data)); ck_assert_int_eq(q.head, sizeof(data)); ck_assert_mem_eq(q.data, data, sizeof(data)); } END_TEST START_TEST(test_queue_insert_sequential) { struct queue q; queue_init(&q, mem, memsz, 0x12345678); uint8_t data1[] = {1, 2}; uint8_t data2[] = {3, 4}; int res1 = queue_insert(&q, data1, 0, sizeof(data1)); int res2 = queue_insert(&q, data2, 2, sizeof(data2)); ck_assert_int_eq(res1, 0); ck_assert_int_eq(res2, 0); ck_assert_int_eq(queue_len(&q), sizeof(data1) + sizeof(data2)); ck_assert_mem_eq(q.data, data1, sizeof(data1)); ck_assert_mem_eq(q.data + 2, data2, sizeof(data2)); } END_TEST START_TEST(test_queue_pop) { struct queue q; queue_init(&q, mem, memsz, 0x12345678); uint8_t data[] = {5, 6, 7, 8}; uint8_t out[4]; queue_insert(&q, data, 0, sizeof(data)); int len = queue_pop(&q, out, sizeof(out)); ck_assert_int_eq(len, sizeof(out)); ck_assert_mem_eq(out, data, sizeof(data)); ck_assert_int_eq(queue_len(&q), 0); ck_assert_int_eq(q.tail, 4); } END_TEST START_TEST(test_queue_pop_wraparound) { struct queue q; queue_init(&q, mem, memsz, 0x12345678); uint8_t data[] = {9, 10, 11, 12}; uint8_t out[4]; q.head = memsz - 1; q.tail = memsz - 1; queue_insert(&q, data, 0, sizeof(data)); int len = queue_pop(&q, out, sizeof(out)); ck_assert_int_eq(len, sizeof(out)); ck_assert_mem_eq(out, data, sizeof(data)); ck_assert_int_eq(queue_len(&q), 0); } END_TEST Suite *femto_suite(void) { Suite *s; TCase *tc_core, *tc_proto; s = suite_create("FemtoTCP"); tc_core = tcase_create("Core"); tc_proto = tcase_create("Protocols"); tcase_add_test(tc_core, test_fifo_init); suite_add_tcase(s, tc_core); suite_add_tcase(s, tc_proto); tcase_add_test(tc_core, test_fifo_push_and_pop); suite_add_tcase(s, tc_core); tcase_add_test(tc_core, test_fifo_push_and_pop_multiple); suite_add_tcase(s, tc_core); tcase_add_test(tc_core, test_fifo_pop_success); suite_add_tcase(s, tc_core); tcase_add_test(tc_core, test_fifo_pop_empty); suite_add_tcase(s, tc_core); tcase_add_test(tc_core, test_fifo_push_full); suite_add_tcase(s, tc_core); tcase_add_test(tc_core, test_fifo_push_wrap); suite_add_tcase(s, tc_core); tcase_add_test(tc_core, test_fifo_push_wrap_multiple); suite_add_tcase(s, tc_core); tcase_add_test(tc_core, test_fifo_next_success); suite_add_tcase(s, tc_core); tcase_add_test(tc_core, test_fifo_next_empty_fifo); suite_add_tcase(s, tc_core); tcase_add_test(tc_core, test_fifo_next_end_of_fifo); suite_add_tcase(s, tc_core); tcase_add_test(tc_core, test_queue_init); suite_add_tcase(s, tc_core); tcase_add_test(tc_core, test_queue_space_empty); suite_add_tcase(s, tc_core); tcase_add_test(tc_core, test_queue_len_empty); suite_add_tcase(s, tc_core); tcase_add_test(tc_core, test_queue_partial_fill); suite_add_tcase(s, tc_core); tcase_add_test(tc_core, test_queue_wrap_around); suite_add_tcase(s, tc_core); tcase_add_test(tc_core, test_queue_insert_empty); suite_add_tcase(s, tc_core); tcase_add_test(tc_core, test_queue_insert_sequential); suite_add_tcase(s, tc_core); tcase_add_test(tc_core, test_queue_pop); suite_add_tcase(s, tc_core); tcase_add_test(tc_core, test_queue_pop_wraparound); suite_add_tcase(s, tc_core); return s; } int main(void) { int n_fail = 0; Suite *s; SRunner *sr; s = femto_suite(); sr = srunner_create(s); srunner_run_all(sr, CK_NORMAL); n_fail = srunner_ntests_failed(sr); srunner_free(sr); return (n_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE; }