/* * Copyright (c) Likewise Software. All rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the license, or (at * your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. You should have received a copy * of the GNU Lesser General Public License along with this program. If * not, see . * * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING * TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU * LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT * license@likewisesoftware.com */ /* * Module Name: * * test-marshal.c * * Abstract: * * Marshalling unit tests * * Authors: Brian Koropoff (bkoropoff@likewisesoftware.com) * */ #include #include #include #include #include "test-private.h" static LWMsgContext* context = NULL; static LWMsgDataContext* dcontext = NULL; static void allocate_buffer(LWMsgBuffer* buffer) { size_t length = 2047; buffer->base = malloc(length); buffer->cursor = buffer->base; buffer->end = buffer->base + length; buffer->wrap = NULL; buffer->data = NULL; } static void rewind_buffer(LWMsgBuffer* buffer) { buffer->cursor = buffer->base; } MU_FIXTURE_SETUP(marshal) { MU_TRY(lwmsg_context_new(NULL, &context)); MU_TRY(lwmsg_data_context_new(context, &dcontext)); } typedef struct basic_struct { short foo; unsigned int len; long *long_ptr; } basic_struct; static LWMsgStatus basic_verify_foo( LWMsgDataContext* dcontext, LWMsgBool unmarshalling, size_t object_size, void* object, void* data ) { short* fooptr = (short*) object; MU_ASSERT_EQUAL(MU_TYPE_INTEGER, object_size, sizeof(short)); if (*fooptr != -42) { return LWMSG_STATUS_MALFORMED; } else { return LWMSG_STATUS_SUCCESS; } } static LWMsgTypeSpec basic_spec[] = { LWMSG_STRUCT_BEGIN(basic_struct), LWMSG_MEMBER_INT16(basic_struct, foo), LWMSG_ATTR_VERIFY(basic_verify_foo, NULL), LWMSG_MEMBER_UINT32(basic_struct, len), LWMSG_ATTR_RANGE(1, 8), LWMSG_MEMBER_POINTER(basic_struct, long_ptr, LWMSG_INT64(long)), LWMSG_ATTR_NOT_NULL, LWMSG_ATTR_LENGTH_MEMBER(basic_struct, len), LWMSG_STRUCT_END, LWMSG_TYPE_END }; MU_TEST(marshal, basic) { static const unsigned char expected[] = { /* -42 */ 0xFF, 0xD6, /* 2 */ 0x00, 0x00, 0x00, 0x02, /* 1234 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD2, /* 4321 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xE1 }; LWMsgTypeSpec* type = basic_spec; void* buffer; size_t length; basic_struct basic; basic_struct *out; long longs[2]; basic.foo = (short) -42; basic.len = 2; basic.long_ptr = longs; longs[0] = 1234; longs[1] = 4321; MU_TRY_DCONTEXT(dcontext, lwmsg_data_marshal_flat_alloc(dcontext, type, &basic, &buffer, &length)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, sizeof(expected), length); MU_ASSERT(!memcmp(buffer, expected, sizeof(expected))); MU_TRY_DCONTEXT(dcontext, lwmsg_data_unmarshal_flat(dcontext, type, buffer, length, (void**) (void*) &out)); MU_ASSERT(basic.foo == out->foo); MU_ASSERT(basic.len == out->len); MU_ASSERT(basic.long_ptr[0] == out->long_ptr[0]); MU_ASSERT(basic.long_ptr[1] == out->long_ptr[1]); } MU_TEST(marshal, basic_verify_marshal_failure) { LWMsgTypeSpec* type = basic_spec; LWMsgBuffer buffer; basic_struct basic; long longs[2]; allocate_buffer(&buffer); basic.foo = (short) 12; basic.len = 2; basic.long_ptr = longs; longs[0] = 1234; longs[1] = 4321; MU_ASSERT_EQUAL( MU_TYPE_INTEGER, lwmsg_data_marshal(dcontext, type, &basic, &buffer), LWMSG_STATUS_MALFORMED); } MU_TEST(marshal, basic_verify_unmarshal_failure) { static const unsigned char bytes[] = { /* Implicit pointer set value */ 0xFF, /* 12 */ 0x00, 0x0C, /* 2 */ 0x00, 0x00, 0x00, 0x02, /* 1234 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD2, /* 4321 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xE1 }; LWMsgTypeSpec* type = basic_spec; LWMsgBuffer buffer = {0}; basic_struct *out; buffer.base = buffer.cursor = (void*) bytes; buffer.end = buffer.base + sizeof(bytes); MU_ASSERT_EQUAL( MU_TYPE_INTEGER, lwmsg_data_unmarshal(dcontext, type, &buffer, (void**) (void*) &out), LWMSG_STATUS_MALFORMED); } MU_TEST(marshal, basic_verify_range_failure) { static const unsigned char bytes[] = { /* -42 */ 0xFF, 0xD6, /* 9 */ 0x00, 0x00, 0x00, 0x09, /* pointer */ 0xFF, /* 1234 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD2, /* 4321 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xE1 }; LWMsgTypeSpec* type = basic_spec; LWMsgBuffer buffer = {0}; basic_struct *out; buffer.base = buffer.cursor = (void*) bytes; buffer.end = buffer.base + sizeof(bytes); MU_ASSERT_EQUAL( MU_TYPE_INTEGER, lwmsg_data_unmarshal(dcontext, type, &buffer, (void**) (void*) &out), LWMSG_STATUS_MALFORMED); } MU_TEST(marshal, basic_verify_null_failure) { static const unsigned char bytes[] = { /* -42 */ 0xFF, 0xD6, /* 2 */ 0x00, 0x00, 0x00, 0x02, }; LWMsgTypeSpec* type = basic_spec; LWMsgBuffer buffer = {0}; basic_struct *out; buffer.base = buffer.cursor = (void*) bytes; buffer.end = buffer.base + sizeof(bytes); MU_ASSERT_EQUAL( MU_TYPE_INTEGER, lwmsg_data_unmarshal(dcontext, type, &buffer, (void**) (void*) &out), LWMSG_STATUS_EOF); } typedef struct { const char* foo; const char* bar; } string_struct; static LWMsgTypeSpec string_spec[] = { LWMSG_STRUCT_BEGIN(string_struct), LWMSG_MEMBER_PSTR(string_struct, foo), LWMSG_MEMBER_PSTR(string_struct, bar), LWMSG_ATTR_SENSITIVE, LWMSG_STRUCT_END, LWMSG_TYPE_END }; MU_TEST(marshal, string) { static const unsigned char expected[] = { /* foo set */ 0xFF, /* foo length */ 0x00, 0x00, 0x00, 0x03, /* foo contents */ 'f', 'o', 'o', /* bar set */ 0xFF, /* bar length */ 0x00, 0x00, 0x00, 0x03, /* bar contents */ 'b', 'a', 'r' }; LWMsgTypeSpec* type = string_spec; LWMsgBuffer buffer; string_struct strings; string_struct* out; char* text = NULL; strings.foo = "foo"; strings.bar = "bar"; allocate_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_marshal(dcontext, type, &strings, &buffer)); MU_ASSERT(!memcmp(buffer.base, expected, sizeof(expected))); rewind_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_unmarshal(dcontext, type, &buffer, (void**) (void*) &out)); MU_TRY_DCONTEXT(dcontext, lwmsg_data_print_graph_alloc(dcontext, type, out, &text)); MU_DEBUG("%s", text); MU_ASSERT_EQUAL(MU_TYPE_STRING, strings.foo, out->foo); MU_ASSERT_EQUAL(MU_TYPE_STRING, strings.bar, out->bar); } typedef struct { unsigned int len; struct struct_array_inner { char a; char b; } *foo; } struct_array_struct; static LWMsgTypeSpec struct_array_spec[] = { LWMSG_STRUCT_BEGIN(struct_array_struct), LWMSG_MEMBER_UINT32(struct_array_struct, len), LWMSG_MEMBER_POINTER_BEGIN(struct_array_struct, foo), LWMSG_STRUCT_BEGIN(struct struct_array_inner), LWMSG_MEMBER_INT8(struct struct_array_inner, a), LWMSG_MEMBER_INT8(struct struct_array_inner, b), LWMSG_STRUCT_END, LWMSG_POINTER_END, LWMSG_ATTR_LENGTH_MEMBER(struct_array_struct, len), LWMSG_STRUCT_END, LWMSG_TYPE_END }; MU_TEST(marshal, struct_array) { static const unsigned char expected[] = { /* len = 2 */ 0x00, 0x00, 0x00, 0x02, /* foo set */ 0xFF, /* first struct */ 'a', 'b', /* second struct */ 'c', 'd' }; LWMsgTypeSpec* type = struct_array_spec; LWMsgBuffer buffer; struct_array_struct structs; struct_array_struct *out; struct struct_array_inner inner[2] = { {'a', 'b'}, {'c', 'd'} }; structs.len = 2; structs.foo = inner; allocate_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_marshal(dcontext, type, &structs, &buffer)); MU_ASSERT(!memcmp(buffer.base, expected, sizeof(expected))); rewind_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_unmarshal(dcontext, type, &buffer, (void**) (void*) &out)); MU_ASSERT(structs.len == out->len); MU_ASSERT(structs.foo[0].a == out->foo[0].a); MU_ASSERT(structs.foo[0].b == out->foo[0].b); MU_ASSERT(structs.foo[1].a == out->foo[1].a); MU_ASSERT(structs.foo[1].b == out->foo[1].b); } typedef struct { char ** strings; } string_array_struct; static LWMsgTypeSpec string_array_spec[] = { LWMSG_STRUCT_BEGIN(string_array_struct), LWMSG_MEMBER_POINTER_BEGIN(string_array_struct, strings), LWMSG_PSTR, LWMSG_POINTER_END, LWMSG_ATTR_ZERO_TERMINATED, LWMSG_STRUCT_END, LWMSG_TYPE_END }; MU_TEST(marshal, string_array) { static const unsigned char expected[] = { /* strings = (set) */ 0xFF, /* (implicit) length of "strings" = 2 */ 0x00, 0x00, 0x00, 0x02, /* strings[0] = set */ 0xFF, /* strings[0] len */ 0x00, 0x00, 0x00, 0x03, /* strings[0] value */ 'f', 'o', 'o', /* strings[1] = set */ 0xFF, /* strings[1] len */ 0x00, 0x00, 0x00, 0x03, /* strings[1] value */ 'b', 'a', 'r' }; LWMsgTypeSpec* type = string_array_spec; LWMsgBuffer buffer; string_array_struct strings; string_array_struct *out; char* inner[] = { "foo", "bar", NULL }; strings.strings = (char**) inner; allocate_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_marshal(dcontext, type, &strings, &buffer)); MU_ASSERT(!memcmp(buffer.base, expected, sizeof(expected))); rewind_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_unmarshal(dcontext, type, &buffer, (void**) (void*) &out)); MU_ASSERT_EQUAL(MU_TYPE_STRING, strings.strings[0], out->strings[0]); MU_ASSERT_EQUAL(MU_TYPE_STRING, strings.strings[1], out->strings[1]); MU_ASSERT(out->strings[2] == NULL); lwmsg_data_free_graph(dcontext, type, out); } MU_TEST(marshal, string_array_empty) { static const unsigned char expected[] = { /* strings = (set) */ 0xFF, /* (implicit) length of "strings" = 0 */ 0x00, 0x00, 0x00, 0x00 }; LWMsgTypeSpec* type = string_array_spec; LWMsgBuffer buffer; string_array_struct strings; string_array_struct *out; char* inner[] = { NULL }; strings.strings = (char**) inner; allocate_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_marshal(dcontext, type, &strings, &buffer)); MU_ASSERT(!memcmp(buffer.base, expected, sizeof(expected))); rewind_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_unmarshal(dcontext, type, &buffer, (void**) (void*) &out)); MU_ASSERT_EQUAL(MU_TYPE_POINTER, strings.strings[0], out->strings[0]); lwmsg_data_free_graph(dcontext, type, out); } MU_TEST(marshal, string_array_null) { static const unsigned char expected[] = { /* strings = (not set) */ 0x00 }; LWMsgTypeSpec* type = string_array_spec; LWMsgBuffer buffer; string_array_struct strings; string_array_struct *out; strings.strings = NULL; allocate_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_marshal(dcontext, type, &strings, &buffer)); MU_ASSERT(!memcmp(buffer.base, expected, sizeof(expected))); rewind_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_unmarshal(dcontext, type, &buffer, (void**) (void*) &out)); MU_ASSERT_EQUAL(MU_TYPE_POINTER, out->strings, NULL); lwmsg_data_free_graph(dcontext, type, out); } #define TAG_NUMBER 1 #define TAG_STRING 2 #define TAG_EMPTY 3 typedef union { int number; char* string; } number_string_union; static LWMsgTypeSpec number_string_spec[] = { LWMSG_UNION_BEGIN(number_string_union), LWMSG_MEMBER_INT32(number_string_union, number), LWMSG_ATTR_TAG(TAG_NUMBER), LWMSG_MEMBER_PSTR(number_string_union, string), LWMSG_ATTR_TAG(TAG_STRING), LWMSG_VOID, LWMSG_ATTR_TAG(TAG_EMPTY), LWMSG_UNION_END, LWMSG_TYPE_END }; typedef struct { int tag1; number_string_union* u1; int tag2; number_string_union* u2; } two_union_struct; static LWMsgTypeSpec two_union_spec[] = { LWMSG_STRUCT_BEGIN(two_union_struct), LWMSG_MEMBER_INT8(two_union_struct, tag1), LWMSG_MEMBER_POINTER_BEGIN(two_union_struct, u1), LWMSG_TYPESPEC(number_string_spec), LWMSG_ATTR_DISCRIM(two_union_struct, tag1), LWMSG_POINTER_END, LWMSG_MEMBER_INT8(two_union_struct, tag2), LWMSG_MEMBER_POINTER_BEGIN(two_union_struct, u2), LWMSG_TYPESPEC(number_string_spec), LWMSG_ATTR_DISCRIM(two_union_struct, tag2), LWMSG_POINTER_END, LWMSG_STRUCT_END, LWMSG_TYPE_END }; MU_TEST(marshal, two_union) { static const unsigned char expected[] = { /* tag1 = 1 */ 0x01, /* u1 = set */ 0xFF, /* u1->number = 42 */ 0x00, 0x00, 0x00, 0x2A, /* tag2 = 2 */ 0x02, /* u2 = set */ 0xFF, /* u2->string = set */ 0xFF, /* u2->string length is 3 (implicit) */ 0x00, 0x00, 0x00, 0x03, /* u2->string pointee */ 'f', 'o', 'o' }; LWMsgTypeSpec* type = two_union_spec; LWMsgBuffer buffer; two_union_struct unions; two_union_struct* out; number_string_union u1, u2; u1.number = 42; u2.string = (char*) "foo"; unions.tag1 = TAG_NUMBER; unions.u1 = &u1; unions.tag2 = TAG_STRING; unions.u2 = &u2; allocate_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_marshal(dcontext, type, &unions, &buffer)); MU_ASSERT(!memcmp(buffer.base, expected, sizeof(expected))); rewind_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_unmarshal(dcontext, type, &buffer, (void**) (void*) &out)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, unions.tag1, out->tag1); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, unions.tag2, out->tag2); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, unions.u1->number, out->u1->number); MU_ASSERT_EQUAL(MU_TYPE_STRING, unions.u2->string, out->u2->string); } typedef struct { int foo; struct inner_struct { int foo; const char* bar; } inner; int bar; } nested_struct_struct; static LWMsgTypeSpec nested_struct_spec[] = { LWMSG_STRUCT_BEGIN(nested_struct_struct), LWMSG_MEMBER_INT32(nested_struct_struct, foo), LWMSG_MEMBER_STRUCT_BEGIN(nested_struct_struct, inner), LWMSG_MEMBER_INT32(struct inner_struct, foo), LWMSG_MEMBER_PSTR(struct inner_struct, bar), LWMSG_STRUCT_END, LWMSG_MEMBER_INT32(nested_struct_struct, bar), LWMSG_STRUCT_END, LWMSG_TYPE_END }; MU_TEST(marshal, nested_struct) { static const unsigned char expected[] = { /* foo = 42 */ 0x00, 0x00, 0x00, 0x2A, /* inner.foo = 24 */ 0x00, 0x00, 0x00, 0x18, /* inner.bar = (set) */ 0xFF, /* inner.bar length (implicit) */ 0x00, 0x00, 0x00, 0x03, /* inner.bar value */ 'b', 'a', 'r', /* bar = -12 */ 0xFF, 0xFF, 0xFF, 0xF4, }; LWMsgTypeSpec* type = nested_struct_spec; LWMsgBuffer buffer; nested_struct_struct nested; nested_struct_struct* out; nested.foo = 42; nested.inner.foo = 24; nested.inner.bar = "bar"; nested.bar = -12; allocate_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_marshal(dcontext, type, &nested, &buffer)); MU_ASSERT(!memcmp(buffer.base, expected, sizeof(expected))); rewind_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_unmarshal(dcontext, type, &buffer, (void**) (void*) &out)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, nested.foo, out->foo); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, nested.inner.foo, out->inner.foo); MU_ASSERT_EQUAL(MU_TYPE_STRING, nested.inner.bar, out->inner.bar); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, nested.bar, out->bar); } typedef struct { int tag1; number_string_union u1; int tag2; number_string_union u2; } nested_union_struct; static LWMsgTypeSpec nested_union_spec[] = { LWMSG_STRUCT_BEGIN(nested_union_struct), LWMSG_MEMBER_INT8(nested_union_struct, tag1), LWMSG_MEMBER_TYPESPEC(nested_union_struct, u1, number_string_spec), LWMSG_ATTR_DISCRIM(nested_union_struct, tag1), LWMSG_MEMBER_INT8(nested_union_struct, tag2), LWMSG_MEMBER_TYPESPEC(nested_union_struct, u2, number_string_spec), LWMSG_ATTR_DISCRIM(nested_union_struct, tag2), LWMSG_STRUCT_END, LWMSG_TYPE_END }; MU_TEST(marshal, nested_union) { static const unsigned char expected[] = { /* tag1 = 2 */ 0x02, /* u1.string = (set) */ 0xFF, /* u1.string length is 3 (implicit) */ 0x00, 0x00, 0x00, 0x03, /* u1.string value */ 'f', 'o', 'o', /* tag2 = 1 */ 0x01, /* u2.number = 42 */ 0x00, 0x00, 0x00, 0x2A }; LWMsgTypeSpec* type = nested_union_spec; LWMsgBuffer buffer; nested_union_struct unions; nested_union_struct* out; unions.tag1 = TAG_STRING; unions.u1.string = (char*) "foo"; unions.tag2 = TAG_NUMBER; unions.u2.number = 42; allocate_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_marshal(dcontext, type, &unions, &buffer)); MU_ASSERT(!memcmp(buffer.base, expected, sizeof(expected))); rewind_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_unmarshal(dcontext, type, &buffer, (void**) (void*) &out)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, unions.tag1, out->tag1); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, unions.tag2, out->tag2); MU_ASSERT_EQUAL(MU_TYPE_STRING, unions.u1.string, out->u1.string); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, unions.u2.number, out->u2.number); } MU_TEST(marshal, nested_union_empty) { static const unsigned char expected[] = { /* tag1 = 3 (empty) */ 0x03, /* tag2 = 1 */ 0x01, /* u2.number = 42 */ 0x00, 0x00, 0x00, 0x2A }; LWMsgTypeSpec* type = nested_union_spec; LWMsgBuffer buffer; nested_union_struct unions; nested_union_struct* out; unions.tag1 = TAG_EMPTY; unions.tag2 = TAG_NUMBER; unions.u2.number = 42; allocate_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_marshal(dcontext, type, &unions, &buffer)); MU_ASSERT(!memcmp(buffer.base, expected, sizeof(expected))); rewind_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_unmarshal(dcontext, type, &buffer, (void**) (void*) &out)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, unions.tag1, out->tag1); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, unions.tag2, out->tag2); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, unions.u2.number, out->u2.number); } typedef struct { int foo; int array[2]; int bar; } inline_array_struct; static LWMsgTypeSpec inline_array_spec[] = { LWMSG_STRUCT_BEGIN(inline_array_struct), LWMSG_MEMBER_INT16(inline_array_struct, foo), LWMSG_MEMBER_ARRAY_BEGIN(inline_array_struct, array), LWMSG_INT16(int), LWMSG_ARRAY_END, LWMSG_ATTR_LENGTH_STATIC(2), LWMSG_MEMBER_INT16(inline_array_struct, bar), LWMSG_STRUCT_END, LWMSG_TYPE_END }; MU_TEST(marshal, inline_array) { static const unsigned char expected[] = { /* foo = 1 */ 0x00, 0x01, /* array[0] = 2 */ 0x00, 0x02, /* array[1] = 3 */ 0x00, 0x03, /* bar = 4 */ 0x00, 0x04 }; LWMsgTypeSpec* type = inline_array_spec; LWMsgBuffer buffer; inline_array_struct in; inline_array_struct* out; in.foo = 1; in.array[0] = 2; in.array[1] = 3; in.bar = 4; allocate_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_marshal(dcontext, type, &in, &buffer)); MU_ASSERT(!memcmp(buffer.base, expected, sizeof(expected))); rewind_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_unmarshal(dcontext, type, &buffer, (void**) (void*) &out)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, in.foo, out->foo); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, in.array[0], out->array[0]); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, in.array[1], out->array[1]); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, in.bar, out->bar); } typedef struct { int foo; char string[]; } flexible_string_struct; static LWMsgTypeSpec flexible_string_spec[] = { LWMSG_STRUCT_BEGIN(flexible_string_struct), LWMSG_MEMBER_INT16(flexible_string_struct, foo), LWMSG_MEMBER_ARRAY_BEGIN(flexible_string_struct, string), LWMSG_UINT8(char), LWMSG_ARRAY_END, LWMSG_ATTR_STRING, LWMSG_STRUCT_END, LWMSG_TYPE_END }; MU_TEST(marshal, flexible_string) { static const unsigned char expected[] = { /* foo = 42 */ 0x00, 0x2A, /* string length = 3 (implicit) */ 0x00, 0x00, 0x00, 0x03, /* string value */ 'f', 'o', 'o' }; LWMsgTypeSpec* type = flexible_string_spec; LWMsgBuffer buffer; flexible_string_struct* in; flexible_string_struct* out; in = malloc(sizeof(*in) + 4); in->foo = 42; strcpy(in->string, "foo"); allocate_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_marshal(dcontext, type, in, &buffer)); MU_ASSERT(!memcmp(buffer.base, expected, sizeof(expected))); rewind_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_unmarshal(dcontext, type, &buffer, (void**) (void*) &out)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, in->foo, out->foo); MU_ASSERT_EQUAL(MU_TYPE_STRING, in->string, out->string); free(in); } typedef struct { int len; int array[]; } flexible_array_struct; static LWMsgTypeSpec flexible_array_spec[] = { LWMSG_STRUCT_BEGIN(flexible_array_struct), LWMSG_MEMBER_INT16(flexible_array_struct, len), LWMSG_MEMBER_ARRAY_BEGIN(flexible_array_struct, array), LWMSG_INT16(int), LWMSG_ARRAY_END, LWMSG_ATTR_LENGTH_MEMBER(flexible_array_struct, len), LWMSG_STRUCT_END, LWMSG_TYPE_END }; MU_TEST(marshal, flexible_array) { static const unsigned char expected[] = { /* len = 2 */ 0x00, 0x02, /* array[0] = 1 */ 0x00, 0x01, /* array[1] = 2 */ 0x00, 0x02 }; LWMsgTypeSpec* type = flexible_array_spec; LWMsgBuffer buffer; flexible_array_struct* in; flexible_array_struct* out; in = malloc(sizeof(*in) + sizeof(int) * 2); in->len = 2; in->array[0] = 1; in->array[1] = 2; allocate_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_marshal(dcontext, type, in, &buffer)); MU_ASSERT(!memcmp(buffer.base, expected, sizeof(expected))); rewind_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_unmarshal(dcontext, type, &buffer, (void**) (void*) &out)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, in->len, out->len); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, in->array[0], out->array[0]); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, in->array[1], out->array[1]); free(in); } typedef struct info_level_struct { unsigned int length; int level; union level_union { struct level_1_struct { short number1; } *level_1; struct level_2_struct { short number1; short number2; } *level_2; } array; } info_level_struct; static LWMsgTypeSpec info_level_spec[] = { LWMSG_STRUCT_BEGIN(struct info_level_struct), LWMSG_MEMBER_UINT32(struct info_level_struct, length), LWMSG_MEMBER_INT8(struct info_level_struct, level), LWMSG_MEMBER_UNION_BEGIN(struct info_level_struct, array), LWMSG_MEMBER_POINTER_BEGIN(union level_union, level_1), LWMSG_STRUCT_BEGIN(struct level_1_struct), LWMSG_MEMBER_INT16(struct level_1_struct, number1), LWMSG_STRUCT_END, LWMSG_POINTER_END, LWMSG_ATTR_LENGTH_MEMBER(struct info_level_struct, length), LWMSG_ATTR_TAG(1), LWMSG_MEMBER_POINTER_BEGIN(union level_union, level_2), LWMSG_STRUCT_BEGIN(struct level_2_struct), LWMSG_MEMBER_INT16(struct level_2_struct, number1), LWMSG_MEMBER_INT16(struct level_2_struct, number2), LWMSG_STRUCT_END, LWMSG_POINTER_END, LWMSG_ATTR_LENGTH_MEMBER(struct info_level_struct, length), LWMSG_ATTR_TAG(2), LWMSG_UNION_END, LWMSG_ATTR_DISCRIM(struct info_level_struct, level), LWMSG_STRUCT_END, LWMSG_TYPE_END }; MU_TEST(marshal, info_level_1) { static const unsigned char expected[] = { /* length */ 0x00, 0x00, 0x00, 0x02, /* level */ 0x01, /* array.level_1 set */ 0xFF, /* array.level_1[0].number1 */ 0x00, 0x2A, /* array.level_1[1].number1 */ 0x00, 0x54 }; static struct level_1_struct array[] = { {42}, {84} }; LWMsgTypeSpec* type = info_level_spec; LWMsgBuffer buffer; info_level_struct in; info_level_struct* out; int i; in.length = sizeof(array) / sizeof(*array); in.level = 1; in.array.level_1 = array; allocate_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_marshal(dcontext, type, &in, &buffer)); MU_ASSERT(!memcmp(buffer.base, expected, sizeof(expected))); rewind_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_unmarshal(dcontext, type, &buffer, (void**) (void*) &out)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, in.length, out->length); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, in.level, out->level); for (i = 0; i < out->length; i++) { MU_ASSERT_EQUAL(MU_TYPE_INTEGER, in.array.level_1[0].number1, out->array.level_1[0].number1); } lwmsg_data_free_graph(dcontext, type, out); } MU_TEST(marshal, info_level_2) { static const unsigned char expected[] = { /* length */ 0x00, 0x00, 0x00, 0x02, /* level */ 0x02, /* array.level_2 set */ 0xFF, /* array.level_2[0].number1 */ 0x00, 0x2A, /* array.level_2[0].number2 */ 0xFF, 0xD6, /* array.level_2[1].number1 */ 0x00, 0x54, /* array.level_2[1].number2 */ 0xFF, 0xAC }; static struct level_2_struct array[] = { {42, -42}, {84, -84} }; LWMsgTypeSpec* type = info_level_spec; LWMsgBuffer buffer; info_level_struct in; info_level_struct* out; int i; in.length = sizeof(array) / sizeof(*array); in.level = 2; in.array.level_2 = array; allocate_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_marshal(dcontext, type, &in, &buffer)); MU_ASSERT(!memcmp(buffer.base, expected, sizeof(expected))); rewind_buffer(&buffer); MU_TRY_DCONTEXT(dcontext, lwmsg_data_unmarshal(dcontext, type, &buffer, (void**) (void*) &out)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, in.length, out->length); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, in.level, out->level); for (i = 0; i < out->length; i++) { MU_ASSERT_EQUAL(MU_TYPE_INTEGER, in.array.level_2[0].number1, out->array.level_2[0].number1); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, in.array.level_2[0].number2, out->array.level_2[0].number2); } }