Files
cKit/Foundation/c_BinaryOutStream.t.c
T
2026-09-07 21:22:01 +08:00

132 lines
5.5 KiB
C

#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;
}