Files
cAI/cKit/Foundation/c_FastByteRingBuffer.t.c
2026-08-10 12:05:34 +08:00

338 lines
15 KiB
C

#include "c_FastByteRingBuffer.h"
#include <stdlib.h>
#include <stdio.h>
#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, &current_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_ERR_INVALID_PARAM); // Capacity = 6
assert(c_FastByteRingBuffer_Init(&ring, 8) == 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;
}