Add serialize library for binary serialization with dynamic allocation
- serialize.h/c: universal binary serialization for structures with variable-length fields (ASCIIZ, ARRAY) using pointers - Auto allocation via u_malloc during deserialization - Support for header (arbitrary bytes at buffer start) - serialize_encode(): serialize structure to buffer - serialize_decode(): deserialize from buffer (without header) - serialize_free(): free structure and all its pointers - tests/test_serialize.c: unit tests
This commit is contained in:
1 parent
3b31821316
commit
dba092d88b
3 files changed
+510
No files matched your search
@@ -0,0 +1,174 @@
|
||||
// test_serialize.c - Unit tests for serialize library with dynamic allocation
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "../lib/serialize.h"
|
||||
|
||||
#define TEST(name) do { \
|
||||
printf("TEST: %-40s ", name); fflush(stdout); \
|
||||
} while(0)
|
||||
|
||||
#define PASS() do { puts("PASS"); } while(0)
|
||||
#define FAIL(msg) do { printf("FAIL: %s\n", msg); exit(1); } while(0)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint8_t id;
|
||||
uint16_t port;
|
||||
uint32_t ip;
|
||||
uint64_t big_val;
|
||||
int8_t signed_val;
|
||||
int32_t signed32;
|
||||
uint8_t name_len;
|
||||
char* name;
|
||||
uint8_t addr_cnt;
|
||||
uint8_t* addrs;
|
||||
} TestStruct;
|
||||
#pragma pack(pop)
|
||||
|
||||
static const struct SerializeField test_fields[] = {
|
||||
{offsetof(TestStruct, id), 0, 0, 0, 0, 0},
|
||||
{offsetof(TestStruct, port), 0, 0, 0, 0, 0},
|
||||
{offsetof(TestStruct, ip), 0, 0, 0, 0, 0},
|
||||
{offsetof(TestStruct, big_val), 0, 0, 0, 0, 0},
|
||||
{offsetof(TestStruct, signed_val), 0, 0, 0, 0, 0},
|
||||
{offsetof(TestStruct, signed32), 0, 0, 0, 0, 0},
|
||||
{offsetof(TestStruct, name), 1, 64, 1, 1, offsetof(TestStruct, name_len)},
|
||||
{offsetof(TestStruct, addrs), 1, 16, 1, 1, offsetof(TestStruct, addr_cnt)},
|
||||
};
|
||||
|
||||
static const struct SerializeSchema test_schema = {
|
||||
.field_count = sizeof(test_fields) / sizeof(test_fields[0]),
|
||||
.struct_size = sizeof(TestStruct),
|
||||
.header_len = 4,
|
||||
.fields = test_fields
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
static void test_alloc_roundtrip(void) {
|
||||
uint8_t* buf = NULL;
|
||||
size_t len;
|
||||
|
||||
TestStruct orig = {
|
||||
.id = 1,
|
||||
.port = 443,
|
||||
.ip = 0x01020304,
|
||||
.big_val = 100,
|
||||
.signed_val = 10,
|
||||
.signed32 = 5000,
|
||||
};
|
||||
orig.name = strdup("hello");
|
||||
orig.name_len = 5;
|
||||
orig.addrs = u_malloc(8);
|
||||
orig.addrs[0] = 192;
|
||||
orig.addrs[1] = 168;
|
||||
orig.addrs[2] = 1;
|
||||
orig.addrs[3] = 1;
|
||||
orig.addrs[4] = 10;
|
||||
orig.addrs[5] = 0;
|
||||
orig.addrs[6] = 0;
|
||||
orig.addrs[7] = 1;
|
||||
orig.addr_cnt = 8;
|
||||
|
||||
uint8_t header[] = {0x01, 0x02, 0x03, 0x04};
|
||||
TEST("serialize_encode with header");
|
||||
int r = serialize_encode(&orig, &test_schema, header, &buf, &len);
|
||||
if (r != SERIALIZE_ERR_OK) FAIL("serialize_encode failed");
|
||||
PASS();
|
||||
|
||||
TestStruct* restored = NULL;
|
||||
TEST("serialize_decode (data without header)");
|
||||
uint8_t* data_ptr = buf + test_schema.header_len;
|
||||
r = serialize_decode(data_ptr, len - test_schema.header_len, &test_schema, (void**)&restored);
|
||||
if (r != SERIALIZE_ERR_OK) FAIL("serialize_decode failed");
|
||||
PASS();
|
||||
|
||||
TEST("check restored not NULL");
|
||||
if (!restored) FAIL("restored is NULL");
|
||||
PASS();
|
||||
|
||||
TEST("check id");
|
||||
if (restored->id != orig.id) FAIL("id mismatch");
|
||||
PASS();
|
||||
|
||||
TEST("check port");
|
||||
if (restored->port != orig.port) FAIL("port mismatch");
|
||||
PASS();
|
||||
|
||||
TEST("check asciiz");
|
||||
if (!restored->name || strcmp(restored->name, "hello") != 0) FAIL("name mismatch");
|
||||
PASS();
|
||||
|
||||
TEST("check array");
|
||||
if (!restored->addrs || restored->addrs[0] != 192) FAIL("addrs[0] mismatch");
|
||||
PASS();
|
||||
|
||||
TEST("check name_len");
|
||||
if (restored->name_len != 5) FAIL("name_len mismatch");
|
||||
PASS();
|
||||
|
||||
TEST("check addr_cnt");
|
||||
if (restored->addr_cnt != 8) FAIL("addr_cnt mismatch");
|
||||
PASS();
|
||||
|
||||
TEST("serialize_free");
|
||||
serialize_free(&test_schema, (void**)&restored);
|
||||
if (restored) FAIL("ptr should be NULL");
|
||||
PASS();
|
||||
|
||||
u_free(buf);
|
||||
}
|
||||
|
||||
static void test_free(void) {
|
||||
uint8_t* buf = NULL;
|
||||
size_t len;
|
||||
|
||||
TestStruct orig = {
|
||||
.id = 2,
|
||||
.port = 9000,
|
||||
};
|
||||
orig.name = strdup("test");
|
||||
orig.name_len = 4;
|
||||
orig.addrs = u_malloc(4);
|
||||
orig.addrs[0] = 10;
|
||||
orig.addrs[1] = 0;
|
||||
orig.addrs[2] = 0;
|
||||
orig.addrs[3] = 1;
|
||||
orig.addr_cnt = 4;
|
||||
|
||||
uint8_t header2[] = {0xFF, 0xEE, 0xDD, 0xCC};
|
||||
TEST("serialize_encode for free");
|
||||
int r = serialize_encode(&orig, &test_schema, header2, &buf, &len);
|
||||
if (r != SERIALIZE_ERR_OK) FAIL("serialize_encode failed");
|
||||
PASS();
|
||||
|
||||
TestStruct* restored = NULL;
|
||||
TEST("serialize_decode for free");
|
||||
uint8_t* data_ptr2 = buf + test_schema.header_len;
|
||||
r = serialize_decode(data_ptr2, len - test_schema.header_len, &test_schema, (void**)&restored);
|
||||
if (r != SERIALIZE_ERR_OK) FAIL("serialize_decode failed");
|
||||
PASS();
|
||||
|
||||
TEST("serialize_free");
|
||||
serialize_free(&test_schema, (void**)&restored);
|
||||
if (restored) FAIL("ptr should be NULL");
|
||||
PASS();
|
||||
|
||||
u_free(buf);
|
||||
free(orig.name);
|
||||
u_free(orig.addrs);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
int main(void) {
|
||||
printf("=== Serialize Library Tests ===\n\n");
|
||||
|
||||
test_alloc_roundtrip();
|
||||
test_free();
|
||||
|
||||
printf("\n=== All tests passed ===\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user