#include "c_FastByteRingBuffer.h" #include #include #define RUN_TEST_CASE(test_func) \ do { \ printf("[RUNNING] %-40s ... ", #test_func); \ fflush(stdout); \ test_func(); \ printf("[PASSED]\n"); \ } while (0) void test_ring_buffer_behavior(void) { c_FastByteRingBuffer_t ring; // Capacity initialization must be a power of two assert(c_FastByteRingBuffer_Init(&ring, 4) == C_SUCCESS); uint8_t input_stream[] = {0x11, 0x22, 0x33}; // 1. Verify standard incremental writing actions assert(c_FastByteRingBuffer_WriteBuffer(&ring, input_stream, 3) == 3); assert(c_FastByteRingBuffer_GetSize(&ring) == 3); // 2. Verify overflow rejection clamping protection uint8_t flood_stream[] = {0x44, 0x55}; // Only 1 byte of free space remains out of total capacity 4 assert(c_FastByteRingBuffer_WriteBuffer(&ring, flood_stream, 2) == 1); assert(c_FastByteRingBuffer_IsFull(&ring) == C_TRUE); // Check data integrity via peek operations uint8_t output_peek[4] = {0}; c_FastByteRingBuffer_PeekBuffer(&ring, output_peek, 4); assert(output_peek[0] == 0x11); assert(output_peek[3] == 0x44); // 0x44 filled the last slot; 0x55 was cleanly rejected c_FastByteRingBuffer_Destroy(&ring); } static void test_overwrite_and_peek_mechanics(void) { c_FastByteRingBuffer_t ring; assert(c_FastByteRingBuffer_Init(&ring, 4) == C_SUCCESS); // Capacity = 4 // 1. Validate Single Overwrite c_FastByteRingBuffer_WriteByte(&ring, 0x01); c_FastByteRingBuffer_WriteByte(&ring, 0x02); c_FastByteRingBuffer_WriteByte(&ring, 0x03); c_FastByteRingBuffer_WriteByte(&ring, 0x04); // Buffer now full: [0x01, 0x02, 0x03, 0x04] assert(c_FastByteRingBuffer_IsFull(&ring) == C_TRUE); c_FastByteRingBuffer_WriteByteOverwrite(&ring, 0x05); // 0x01 gets evicted. Head shifts to 0x02 uint8_t peek_check = 0; assert(c_FastByteRingBuffer_PeekByte(&ring, &peek_check) == C_SUCCESS); assert(peek_check == 0x02); // FIFO rules dictate oldest remaining byte is 0x02 // 2. Validate Bulk Overwrite Loops uint8_t incoming_stream[3] = {0x06, 0x07, 0x08}; // Ring has 4 bytes capacity. Writing 3 bytes over an already full buffer evicts [0x02, 0x03, 0x04] assert(c_FastByteRingBuffer_WriteBufferOverwrite(&ring, incoming_stream, 3) == 3); uint8_t verification_dump[4] = {0}; c_size_t read_out = c_FastByteRingBuffer_PeekBuffer(&ring, verification_dump, 4); assert(read_out == 4); assert(verification_dump[0] == 0x05); // Preserved from previous transaction assert(verification_dump[1] == 0x06); assert(verification_dump[2] == 0x07); assert(verification_dump[3] == 0x08); // 3. Confirm Peek leaves data sequence entirely untouched assert(c_FastByteRingBuffer_GetSize(&ring) == 4); c_FastByteRingBuffer_Destroy(&ring); } static void test_dma_and_discard_mechanics(void) { c_FastByteRingBuffer_t ring; assert(c_FastByteRingBuffer_Init(&ring, 8) == C_SUCCESS); // Capacity = 8 // Force initialization of data that loops around the internal ring memory map uint8_t payload[] = {0xA1, 0xA2, 0xA3, 0xA4, 0xA5}; c_FastByteRingBuffer_WriteBuffer(&ring, payload, 5); // Discard oldest 2 items: drops 0xA1, 0xA2. Cursors shift. assert(c_FastByteRingBuffer_Discard(&ring, 2) == 2); assert(c_FastByteRingBuffer_GetSize(&ring) == 3); // Write some more to force a wrap-around layout uint8_t wrap_payload[] = {0xB1, 0xB2, 0xB3, 0xB4}; c_FastByteRingBuffer_WriteBuffer(&ring, wrap_payload, 4); // Total size now = 7 bytes // Validate GetReadPtr isolates Block Segment 1 cleanly c_size_t read_chunk_len = 0; const uint8_t* read_ptr = c_FastByteRingBuffer_GetReadPtr(&ring, &read_chunk_len); assert(read_ptr != NULL); // Head was shifted to index 2. 8 - 2 = 6 available linearly up to memory array edge assert(read_chunk_len == 6); assert(read_ptr[0] == 0xA3); // First remaining item // Clear those processed items via direct execution tracking c_FastByteRingBuffer_Discard(&ring, read_chunk_len); // Call secondary pass to capture remaining wrapped bytes read_ptr = c_FastByteRingBuffer_GetReadPtr(&ring, &read_chunk_len); assert(read_chunk_len == 1); assert(read_ptr[0] == 0xB4); // Wrapped character check c_FastByteRingBuffer_Destroy(&ring); } static void test_ring_buffer_index_searching(void) { c_FastByteRingBuffer_t ring; assert(c_FastByteRingBuffer_Init(&ring, 8) == C_SUCCESS); // Capacity = 8 // Force a data write footprint that wraps around the buffer margins uint8_t standard_fill[] = {0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44}; c_FastByteRingBuffer_WriteBuffer(&ring, standard_fill, 8); // Discard 4 elements to position head cursor at absolute index 4 c_FastByteRingBuffer_Discard(&ring, 4); // Append sequence to cross edge wrap boundaries cleanly uint8_t wrap_fill[] = {0x55, 0x66, 0x77}; c_FastByteRingBuffer_WriteBuffer(&ring, wrap_fill, 3); // Dynamic ring content layout from head: [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77] // 1. Single byte search lookup match assert(c_FastByteRingBuffer_IndexOfByte(&ring, 0x33) == 2); // Relative offset index 2 from head assert(c_FastByteRingBuffer_IndexOfByte(&ring, 0x99) == C_ERR_NOT_FOUND); // 2. Pattern buffer sequence scan (testing across structural wrap-around edge boundaries) uint8_t search_pattern[] = {0x44, 0x55, 0x66}; c_index_t match_offset = c_FastByteRingBuffer_IndexOfBuffer(&ring, search_pattern, 3); assert(match_offset == 3); // 0x44 sits exactly at relative offset position 3 // Application Workflow Integration: Cleanly discard up to token match prefix point c_FastByteRingBuffer_Discard(&ring, (c_size_t)match_offset); uint8_t current_head_byte = 0; c_FastByteRingBuffer_PeekByte(&ring, ¤t_head_byte); assert(current_head_byte == 0x44); // The buffer head has been successfully synchronized to the token location c_FastByteRingBuffer_Destroy(&ring); } static void test_reverse_search_and_token_stream(void) { c_FastByteRingBuffer_t ring; assert(c_FastByteRingBuffer_Init(&ring, 8) == C_SUCCESS); // Capacity = 8 uint8_t raw_payload[] = {0xAA, 0x11, 0x22, 0xBB, 0x11, 0x22, 0xCC, 0xDD}; c_FastByteRingBuffer_WriteBuffer(&ring, raw_payload, 8); uint8_t pattern[] = {0x11, 0x22}; // 1. Verify Reverse Pattern Detection Matches Latest Occurrence assert(c_FastByteRingBuffer_IndexOfBuffer(&ring, pattern, 2) == 1); // First pair starts at offset 1 assert(c_FastByteRingBuffer_LastIndexOfBuffer(&ring, pattern, 2) == 4); // Latest pair starts at offset 4 // 2. Clear out buffer to run frame serialization test c_FastByteRingBuffer_Discard(&ring, 8); uint8_t stream_data[] = {'P', 'a', 'c', 'k', 'e', 't', '\r', '\n'}; c_FastByteRingBuffer_WriteBuffer(&ring, stream_data, 8); uint8_t frame_terminator[] = {'\r', '\n'}; uint8_t output_staging[16] = {0}; // Fail Case: Pass a staging array that is structurally too cramped to hold the payload safely assert(c_FastByteRingBuffer_ReadUntilToken(&ring, frame_terminator, 2, output_staging, 5) == 0); assert(c_FastByteRingBuffer_GetSize(&ring) == 8); // Data remains locked safely inside the ring // Success Case: Pass a valid container size to execute frame extraction c_size_t read_bytes = c_FastByteRingBuffer_ReadUntilToken(&ring, frame_terminator, 2, output_staging, 16); assert(read_bytes == 8); assert(memcmp(output_staging, "Packet\r\n", 8) == 0); assert(c_FastByteRingBuffer_IsEmpty(&ring) == C_TRUE); // Frame has been cleanly consumed from the queue c_FastByteRingBuffer_Destroy(&ring); } static void test_relative_random_access(void) { c_FastByteRingBuffer_t ring; assert(c_FastByteRingBuffer_Init(&ring, 4) == C_SUCCESS); // Capacity = 4 uint8_t seed_data[] = {0x10, 0x20, 0x30}; c_FastByteRingBuffer_WriteBuffer(&ring, seed_data, 3); // Shift the head pointer downstream via a single byte consumption uint8_t discard_sink = 0; c_FastByteRingBuffer_ReadByte(&ring, &discard_sink); // 0x10 dropped. Head points to 0x20 // Append items to cross physical wrapping thresholds cleanly c_FastByteRingBuffer_WriteByte(&ring, 0x40); c_FastByteRingBuffer_WriteByte(&ring, 0x50); // Buffer contents: [0x20, 0x30, 0x40, 0x50] uint8_t extracted_byte = 0; // 1. Verify standard random read coordinates relative to the head position assert(c_FastByteRingBuffer_GetAtRelative(&ring, 0, &extracted_byte) == C_SUCCESS); assert(extracted_byte == 0x20); // Relative 0 points directly to the current head assert(c_FastByteRingBuffer_GetAtRelative(&ring, 2, &extracted_byte) == C_SUCCESS); assert(extracted_byte == 0x40); // Wrapped index check assert(c_FastByteRingBuffer_GetAtRelative(&ring, 3, &extracted_byte) == C_SUCCESS); assert(extracted_byte == 0x50); // Newest unread byte check // 2. Validate bounds-checking flags assert(c_FastByteRingBuffer_GetAtRelative(&ring, 4, &extracted_byte) == C_ERR_OUT_OF_BOUNDS); assert(c_FastByteRingBuffer_GetAtRelative(&ring, 99, &extracted_byte) == C_ERR_OUT_OF_BOUNDS); assert(c_FastByteRingBuffer_GetAtRelative(NULL, 0, &extracted_byte) == C_ERR_INVALID_PARAM); c_FastByteRingBuffer_Destroy(&ring); } static void test_conditional_is_validator(void) { c_FastByteRingBuffer_t ring; assert(c_FastByteRingBuffer_Init(&ring, 4) == C_SUCCESS); uint8_t input_stream[] = {0xAA, 0xBB, 0xCC}; c_FastByteRingBuffer_WriteBuffer(&ring, input_stream, 3); // 1. Validate clean true/false matches relative to the head assert(c_FastByteRingBuffer_Is(&ring, 0, 0xAA) == C_TRUE); // Oldest byte at head matches assert(c_FastByteRingBuffer_Is(&ring, 1, 0xBB) == C_TRUE); // Next element matches assert(c_FastByteRingBuffer_Is(&ring, 1, 0x99) == C_FALSE); // Mismatch returns false // Consume 1 byte to advance the head pointer and test wrapping boundaries uint8_t sink = 0; c_FastByteRingBuffer_ReadByte(&ring, &sink); // Head now points to 0xBB c_FastByteRingBuffer_WriteByte(&ring, 0xDD); // Layout: [..., 0xBB, 0xCC, 0xDD] // 2. Re-verify offsets after structural pointer wrap shifts assert(c_FastByteRingBuffer_Is(&ring, 0, 0xBB) == C_TRUE); // Head index position 0 is now 0xBB assert(c_FastByteRingBuffer_Is(&ring, 2, 0xDD) == C_TRUE); // Wrapped index element match // 3. Confirm error/bounds conditions return false instead of blowing up memory layout boundaries assert(c_FastByteRingBuffer_Is(&ring, 3, 0x00) == C_FALSE); // Out of bounds index assert(c_FastByteRingBuffer_Is(&ring, -5, 0xBB) == C_FALSE); // Negative index handling protection assert(c_FastByteRingBuffer_Is(NULL, 0, 0xBB) == C_FALSE); // NULL safety check c_FastByteRingBuffer_Destroy(&ring); } static void test_ring_buffer_memcmp(void) { c_FastByteRingBuffer_t ring; assert(c_FastByteRingBuffer_Init(&ring, 6) == C_SUCCESS); // Capacity = 6 uint8_t payload[] = {0x00, 0x11, 0x22, 0x33}; c_FastByteRingBuffer_WriteBuffer(&ring, payload, 4); // Consume 2 bytes to step the head pointer forward to absolute index 2 uint8_t sink = 0; c_FastByteRingBuffer_ReadByte(&ring, &sink); c_FastByteRingBuffer_ReadByte(&ring, &sink); // Buffer active layout from head: [0x22, 0x33] // Append data to trigger an explicit physical wrap-around edge split layout uint8_t wrap_payload[] = {0x44, 0x55, 0x66}; c_FastByteRingBuffer_WriteBuffer(&ring, wrap_payload, 3); // Buffer dynamic content path tracking from head: [0x22, 0x33, 0x44, 0x55, 0x66] // Physical layout behind indices inside array: [0x55, 0x66, 0x22, 0x33, 0x44, ...] // 1. Validate contiguous segment match comparisons uint8_t check_a[] = {0x22, 0x33}; assert(c_FastByteRingBuffer_Memcmp(&ring, 0, check_a, 2) == 0); // Perfect contiguous match // 2. Validate multi-segment wrap-around comparison mechanics uint8_t check_b[] = {0x33, 0x44, 0x55, 0x66}; assert(c_FastByteRingBuffer_Memcmp(&ring, 1, check_b, 4) == 0); // Perfect split wrap-around match // 3. Mismatch checks uint8_t check_mismatch[] = {0x33, 0x44, 0x99, 0x66}; assert(c_FastByteRingBuffer_Memcmp(&ring, 1, check_mismatch, 4) != 0); // Identifies internal divergence // 4. Bounds and parameter checks assert(c_FastByteRingBuffer_Memcmp(&ring, 0, check_b, 100) == C_ERR_OUT_OF_BOUNDS); // Request width overflows content assert(c_FastByteRingBuffer_Memcmp(&ring, 99, check_b, 1) == C_ERR_OUT_OF_BOUNDS); // Start pointer invalid assert(c_FastByteRingBuffer_Memcmp(NULL, 0, check_b, 1) == C_ERR_INVALID_PARAM); c_FastByteRingBuffer_Destroy(&ring); } static void test_ring_buffer_strtoul(void) { c_FastByteRingBuffer_t ring; assert(c_FastByteRingBuffer_Init(&ring, 8) == C_SUCCESS); // Capacity = 8 // 1. Standard Linear Base-10 Parsing uint8_t input_a[] = {'1', '2', '3', '4', ' ', 'A', 'B', 'C'}; c_FastByteRingBuffer_WriteBuffer(&ring, input_a, 8); unsigned long parsed_val = 0; c_size_t end_offset = 0; assert(c_FastByteRingBuffer_Strtoul(&ring, 0, 10, &parsed_val, &end_offset) == C_SUCCESS); assert(parsed_val == 1234); assert(end_offset == 4); // Points exactly to the trailing space character offset // Reset buffer tracking lines c_FastByteRingBuffer_Discard(&ring, 8); // 2. Fragmented Wrap Hex Parsing // Pre-fill 5 elements to push cursor indices near wrapping layout boundaries uint8_t pre_fill[] = {0, 0, 0, 0, 0}; c_FastByteRingBuffer_WriteBuffer(&ring, pre_fill, 5); c_FastByteRingBuffer_Discard(&ring, 5); // Head pointer sits at physical index 5 // Write Hex parameter payload string ("0x2F") across memory boundaries uint8_t input_hex[] = {'0', 'x', '2', 'F'}; c_FastByteRingBuffer_WriteBuffer(&ring, input_hex, 4); assert(c_FastByteRingBuffer_Strtoul(&ring, 0, 16, &parsed_val, &end_offset) == C_SUCCESS); assert(parsed_val == 47); // 0x2F translates to decimal 47 assert(end_offset == 4); c_FastByteRingBuffer_Destroy(&ring); } int main() { printf("==================================================\n"); printf(" Starting c_FastByteRingBuffer Unit Testing Suite\n"); printf("==================================================\n\n"); RUN_TEST_CASE(test_ring_buffer_behavior); RUN_TEST_CASE(test_overwrite_and_peek_mechanics); RUN_TEST_CASE(test_dma_and_discard_mechanics); RUN_TEST_CASE(test_ring_buffer_index_searching); RUN_TEST_CASE(test_reverse_search_and_token_stream); RUN_TEST_CASE(test_relative_random_access); RUN_TEST_CASE(test_conditional_is_validator); RUN_TEST_CASE(test_ring_buffer_memcmp); RUN_TEST_CASE(test_ring_buffer_strtoul); printf("\n==================================================\n"); printf(" Success! Byte RingBuffer tests passed!\n"); printf("==================================================\n"); return 0; }