#include "c_BinaryOutStream.h" #include "c_BufferOutputStream.h" #include "c_Float.h" #include "c_Test.h" #include "c_Hex.h" typedef struct { const unsigned char* data; c_size_t size; c_size_t byte_ptr; int buffer; int n; } c_BinaryInHelper_t; static inline void c_BinaryInHelper_Init(c_BinaryInHelper_t* self, const void* data, c_size_t size) { self->data = (const unsigned char*)data; self->size = size; self->byte_ptr = 0; self->buffer = 0; self->n = 0; } static inline uint32_t c_BinaryInHelper_ReadBits(c_BinaryInHelper_t* self, int bit_count) { uint32_t result = 0; for (int i = 0; i < bit_count; ++i) { if (self->n == 0) { self->buffer = self->data[self->byte_ptr++]; self->n = 8; } int bit = (self->buffer >> (self->n - 1)) & 1; self->n--; result = (result << 1) | bit; } return result; } TEST_CASE(test_binary_out_stream_extended_apis) { c_OutStream_t* mem_stream = NULL; /* 1. Spin up an in-memory dynamic serialization stream subclass */ c_err_t err = c_BufferOutputStream_Create(&mem_stream, 32, NULL); ASSERT_INT_EQ(C_SUCCESS, err); /* 2. Bind the expanded binary bit-packer onto the abstract handle */ c_BinaryOutStream_t bin_out; err = c_BinaryOutStream_Init(&bin_out, mem_stream); ASSERT_INT_EQ(C_SUCCESS, err); /* 3. Serialize a mixture of unaligned bits and primitive types */ ASSERT_INT_EQ(C_SUCCESS, c_BinaryOutStream_WriteBit(&bin_out, 1)); /* 1 bit */ ASSERT_INT_EQ(C_SUCCESS, c_BinaryOutStream_WriteBits(&bin_out, 0x0A, 4)); /* 4 bits */ ASSERT_INT_EQ(C_SUCCESS, c_BinaryOutStream_WriteByte(&bin_out, 0xFE)); /* 8 bits */ ASSERT_INT_EQ(C_SUCCESS, c_BinaryOutStream_WriteChar(&bin_out, 'C')); /* 8 bits */ ASSERT_INT_EQ(C_SUCCESS, c_BinaryOutStream_WriteUInt16(&bin_out, 0xABCD)); /* 16 bits */ ASSERT_INT_EQ(C_SUCCESS, c_BinaryOutStream_WriteUInt32(&bin_out, 0x12345678)); /* 32 bits */ ASSERT_INT_EQ(C_SUCCESS, c_BinaryOutStream_WriteUInt64(&bin_out, 0x1122334455667788ULL)); /* 64 bits */ ASSERT_INT_EQ(C_SUCCESS, c_BinaryOutStream_WriteFloat(&bin_out, -2.0f)); /* 32 bits (IEEE 754) */ ASSERT_INT_EQ(C_SUCCESS, c_BinaryOutStream_WriteDouble(&bin_out, 3.1415926535)); /* 64 bits (IEEE 754) */ ASSERT_INT_EQ(C_SUCCESS, c_BinaryOutStream_WriteString(&bin_out, "DAG")); /* 'D','A','G','\0' bytes */ /* Flush out the remaining bit cache down into the underlying memory stream buffer */ err = c_BinaryOutStream_Flush(&bin_out); ASSERT_INT_EQ(C_SUCCESS, err); /* 4. Intercept the written raw payload buffer to verify bit-level precision */ const void* raw_data = NULL; c_size_t total_bytes = 0; err = c_BufferOutputStream_GetBuffer(mem_stream, &raw_data, &total_bytes); ASSERT_INT_EQ(C_SUCCESS, err); ASSERT_TRUE(total_bytes > 0); c_Hex_Dump(raw_data, total_bytes); /* 5. Initialize our bit-level reader helper over the raw payload */ c_BinaryInHelper_t bin_in; c_BinaryInHelper_Init(&bin_in, raw_data, total_bytes); /* Verify unaligned bit configurations */ ASSERT_LL_EQ(1, c_BinaryInHelper_ReadBits(&bin_in, 1)); ASSERT_LL_EQ(0x0A, c_BinaryInHelper_ReadBits(&bin_in, 4)); /* Verify byte-aligned primitives */ ASSERT_LL_EQ(0xFE, c_BinaryInHelper_ReadBits(&bin_in, 8)); ASSERT_LL_EQ('C', c_BinaryInHelper_ReadBits(&bin_in, 8)); ASSERT_LL_EQ(0xABCD, c_BinaryInHelper_ReadBits(&bin_in, 16)); ASSERT_LL_EQ(0x12345678, c_BinaryInHelper_ReadBits(&bin_in, 32)); /* Reconstruct 64-bit unsigned integer splits */ uint64_t actual_u64 = ((uint64_t)c_BinaryInHelper_ReadBits(&bin_in, 32) << 32) | c_BinaryInHelper_ReadBits(&bin_in, 32); ASSERT_LL_EQ(0x1122334455667788ULL, actual_u64); /* Verify IEEE 754 Single-Precision Float using your bit-casting utilities */ uint32_t float_bits = c_BinaryInHelper_ReadBits(&bin_in, 32); c_float_t actual_float = c_Float_FromBits(float_bits); ASSERT_DOUBLE_EQ_MSG(-2.0, (double)actual_float, "Float stream serialization precision failed"); /* Verify IEEE 754 Double-Precision Float */ uint64_t double_bits = ((uint64_t)c_BinaryInHelper_ReadBits(&bin_in, 32) << 32) | c_BinaryInHelper_ReadBits(&bin_in, 32); c_double_t actual_double = c_Double_FromBits(double_bits); /* Float comparisons use your Epsilon tolerances helper pattern */ ASSERT_TRUE(fabs(actual_double - 3.1415926535) <= 1e-9); /* Verify null-terminated String extraction sequence loops */ char actual_str[4]; actual_str[0] = (char)c_BinaryInHelper_ReadBits(&bin_in, 8); actual_str[1] = (char)c_BinaryInHelper_ReadBits(&bin_in, 8); actual_str[2] = (char)c_BinaryInHelper_ReadBits(&bin_in, 8); actual_str[3] = (char)c_BinaryInHelper_ReadBits(&bin_in, 8); /* Should read the '\0' delimiter */ ASSERT_INT_EQ(0, strcmp("DAG", actual_str)); ASSERT_INT_EQ('\0', actual_str[3]); /* 6. Clean up polymorphic dynamic stream via virtual tables */ c_OutStream_Destroy(mem_stream); } int main(void) { /* Fire up the core testing wrapper suite */ TEST_START(BinaryOutStream_ExtendedAPIs_Suite); /* Run the specified data stream pipeline integration test */ RUN_TEST(test_binary_out_stream_extended_apis); /* Output summary metrics logs to console */ TEST_REPORT(); /* Unwind back with proper testing suite status codes */ RETURN_TEST_STATUS; }