t: Add tests for oneoffs

Add test cases for parsing multiple fields of the same oneof from the wire
Add more tests for submessage merging, including oneofs
This commit is contained in:
Ilya Lipnitskiy 2014-11-05 01:00:02 -08:00
parent 9db84a3b90
commit 6090d9a924
3 changed files with 495 additions and 14 deletions

View File

@ -35,24 +35,34 @@ using namespace foo;
#include "common-test-arrays.h"
#define N_ELEMENTS(arr) (sizeof(arr)/sizeof((arr)[0]))
static void
dump_messages_bytes(size_t n_msgs,
google::protobuf::Message **messages,
const char *label)
{
printf ("static const uint8_t %s[] = { ", label);
for (unsigned m = 0; m < n_msgs; m++) {
std::string rv;
google::protobuf::Message *message = messages[m];
if (m)
printf (", ");
if (!message->SerializeToString(&rv))
assert(0);
unsigned char *bytes = (unsigned char *) rv.data();
for (unsigned i = 0; i < rv.size(); i++) {
if (i)
printf (", ");
printf ("0x%02x", bytes[i]);
}
}
printf (" };\n");
}
static void
dump_message_bytes(google::protobuf::Message *message,
const char *label)
{
std::string rv;
unsigned char *bytes;
unsigned len;
if (!message->SerializeToString(&rv))
assert(0);
bytes = (unsigned char *) rv.data();
len = rv.size();
printf ("static const uint8_t %s[%u] = { ", label, len);
for (unsigned i = 0; i < len; i++) {
if (i)
printf (", ");
printf ("0x%02x", bytes[i]);
}
printf (" };\n");
dump_messages_bytes (1, &message, label);
}
static void
@ -564,6 +574,33 @@ static void dump_test_optional_message (void)
opt.mutable_test_message()->set_test(42);
dump_message_bytes (&opt, "test_optional_submess_42");
}
static void dump_test_oneof_merge (void)
{
#define SWAP(a, b) temp = a, a = b, b = temp
google::protobuf::Message *temp;
TestMessOptional opt[6];
google::protobuf::Message *msgs[6] = { &opt[0], &opt[1], &opt[2], &opt[3],
&opt[4], &opt[5] };
opt[0].set_test_bytes ("hello");
opt[1].mutable_test_message()->set_test (42);
opt[2].set_test_string ("");
opt[3].set_test_int32 (666);
opt[4].set_test_float (333);
opt[5].set_test_double (444455555);
dump_messages_bytes (6, msgs, "test_oneof_merge_double");
SWAP (msgs[5], msgs[4]);
dump_messages_bytes (6, msgs, "test_oneof_merge_float");
SWAP (msgs[5], msgs[3]);
dump_messages_bytes (6, msgs, "test_oneof_merge_int32");
SWAP (msgs[5], msgs[2]);
dump_messages_bytes (6, msgs, "test_oneof_merge_string");
SWAP (msgs[5], msgs[1]);
dump_messages_bytes (6, msgs, "test_oneof_merge_submess");
SWAP (msgs[5], msgs[0]);
dump_messages_bytes (6, msgs, "test_oneof_merge_bytes");
#undef SWAP
}
#define DUMP_STATIC_ARRAY_GENERIC(member, static_array, output_array_name) \
do{ \
@ -978,6 +1015,65 @@ static void dump_test_unknown_fields (void)
dump_message_bytes (&mess, "test_unknown_fields_1");
}
static void dump_test_submess_merge (void)
{
TestMessSubMess mess1, mess2, merged1, merged2;
/* Repeated merge */
mess1.mutable_rep_mess()->add_test_int32(1);
mess1.mutable_rep_mess()->add_test_int32(2);
mess2.mutable_rep_mess()->add_test_int32(3);
mess2.mutable_rep_mess()->add_test_int32(4);
mess1.mutable_rep_mess()->add_test_string("hello ");
mess2.mutable_rep_mess()->add_test_string("world");
mess1.mutable_rep_mess()->add_test_bytes("\001\002\003");
mess2.mutable_rep_mess()->add_test_bytes("\004\005\006");
mess1.mutable_rep_mess()->add_test_message()->set_test(111);
mess2.mutable_rep_mess()->add_test_message()->set_test(222);
/* Optional merge */
mess1.mutable_opt_mess()->set_test_sint32(-1);
mess2.mutable_opt_mess()->set_test_sint32(-2);
mess1.mutable_opt_mess()->set_test_float(333);
mess2.mutable_opt_mess()->set_test_double(444);
mess1.mutable_opt_mess()->set_test_bytes("\001\002\003");
mess1.mutable_opt_mess()->mutable_test_message()->set_test(111);
mess2.mutable_opt_mess()->set_test_string("hello");
/* Oneof merge */
mess1.mutable_oneof_mess()->set_opt_int (1);
mess2.mutable_oneof_mess()->mutable_test_message()->set_test(111);
/* Required merge */
mess1.mutable_req_mess()->set_test(1);
mess2.mutable_req_mess()->set_test(2);
/* Default value merge */
mess1.mutable_def_mess()->set_v_int32(111);
mess1.mutable_def_mess()->set_v_string("hello");
mess2.mutable_def_mess()->set_v_bytes("\001\002\003");
mess2.mutable_def_mess()->set_v_double(444);
/* Merge both ways and encode the merged and unmerged messages */
merged1.CopyFrom(mess1);
merged1.MergeFrom(mess2);
merged2.CopyFrom(mess2);
merged2.MergeFrom(mess1);
google::protobuf::Message *msgs[] = { &mess1, &mess2 };
dump_messages_bytes (2, msgs, "test_submess_unmerged1");
msgs[0] = &mess2;
msgs[1] = &mess1;
dump_messages_bytes (2, msgs, "test_submess_unmerged2");
dump_message_bytes(&merged1, "test_submess_merged1");
dump_message_bytes(&merged2, "test_submess_merged2");
}
int main()
{
dump_test_enum_small ();
@ -1019,6 +1115,7 @@ int main()
dump_test_optional_string ();
dump_test_optional_bytes ();
dump_test_optional_message ();
dump_test_oneof_merge ();
dump_test_repeated_int32 ();
dump_test_repeated_sint32 ();
dump_test_repeated_uint32 ();
@ -1053,5 +1150,6 @@ int main()
dump_test_packed_repeated_enum_small ();
dump_test_packed_repeated_enum ();
dump_test_unknown_fields ();
dump_test_submess_merge ();
return 0;
}

View File

@ -82,9 +82,14 @@ test_compare_pack_methods (ProtobufCMessage *message,
return rv;
}
#define GENERIC_ASSIGN(dst,src) ((dst) = (src))
#define NUMERIC_EQUALS(a,b) ((a) == (b))
#define STRING_EQUALS(a,b) (strcmp((a),(b))==0)
#define CHECK_NONE(a)
#define CHECK_NOT_NULL(a) assert( (a) != NULL )
static protobuf_c_boolean
binary_data_equals (ProtobufCBinaryData a, ProtobufCBinaryData b)
{
@ -681,6 +686,297 @@ static void test_optional_SubMess (void)
DO_TEST (&submess, test_optional_submess_42);
#undef DO_TEST
}
/* === Oneof type fields === */
static void test_empty_oneof (void)
{
Foo__TestMessOneof mess = FOO__TEST_MESS_ONEOF__INIT;
size_t len;
uint8_t *data;
Foo__TestMessOneof *mess2 = test_compare_pack_methods (&mess.base, &len, &data);
assert (len == 0);
free (data);
foo__test_mess_oneof__free_unpacked (mess2, NULL);
}
#define DO_TEST_GENERIC_ONEOF(type, init, free_unpacked, case_member, case_enum, member, value, example_packed_data, assign, equal_func, result_check) \
do{ \
type opt = init; \
type *mess; \
size_t len; uint8_t *data; \
opt.case_member = case_enum; \
assign(opt.member, value); \
mess = test_compare_pack_methods (&opt.base, &len, &data); \
TEST_VERSUS_STATIC_ARRAY (len, data, example_packed_data); \
assert (mess->case_member == case_enum); \
result_check(mess->member); \
assert (equal_func (mess->member, value)); \
free_unpacked (mess, NULL); \
free (data); \
}while(0)
#define DO_TEST_ONEOF(member, MEMBER, value, example_packed_data, assign, equal_func) \
DO_TEST_GENERIC_ONEOF(Foo__TestMessOneof, \
FOO__TEST_MESS_ONEOF__INIT, \
foo__test_mess_oneof__free_unpacked, \
test_oneof_case, \
FOO__TEST_MESS_ONEOF__TEST_ONEOF_##MEMBER, \
member, \
value, example_packed_data, assign, equal_func, CHECK_NONE)
#define DO_TEST_ONEOF_REF_VAL(member, MEMBER, value, example_packed_data, assign, equal_func) \
DO_TEST_GENERIC_ONEOF(Foo__TestMessOneof, \
FOO__TEST_MESS_ONEOF__INIT, \
foo__test_mess_oneof__free_unpacked, \
test_oneof_case, \
FOO__TEST_MESS_ONEOF__TEST_ONEOF_##MEMBER, \
member, \
value, example_packed_data, assign, equal_func, CHECK_NOT_NULL)
static void test_oneof_int32 (void)
{
#define DO_TEST(value, example_packed_data) \
DO_TEST_ONEOF(test_int32, TEST_INT32, value, example_packed_data, GENERIC_ASSIGN, NUMERIC_EQUALS)
DO_TEST (INT32_MIN, test_optional_int32_min);
DO_TEST (-1, test_optional_int32_m1);
DO_TEST (0, test_optional_int32_0);
DO_TEST (666, test_optional_int32_666);
DO_TEST (INT32_MAX, test_optional_int32_max);
#undef DO_TEST
}
static void test_oneof_sint32 (void)
{
#define DO_TEST(value, example_packed_data) \
DO_TEST_ONEOF(test_sint32, TEST_SINT32, value, example_packed_data, GENERIC_ASSIGN, NUMERIC_EQUALS)
DO_TEST (INT32_MIN, test_optional_sint32_min);
DO_TEST (-1, test_optional_sint32_m1);
DO_TEST (0, test_optional_sint32_0);
DO_TEST (666, test_optional_sint32_666);
DO_TEST (INT32_MAX, test_optional_sint32_max);
#undef DO_TEST
}
static void test_oneof_sfixed32 (void)
{
#define DO_TEST(value, example_packed_data) \
DO_TEST_ONEOF(test_sfixed32, TEST_SFIXED32, value, example_packed_data, GENERIC_ASSIGN, NUMERIC_EQUALS)
DO_TEST (INT32_MIN, test_optional_sfixed32_min);
DO_TEST (-1, test_optional_sfixed32_m1);
DO_TEST (0, test_optional_sfixed32_0);
DO_TEST (666, test_optional_sfixed32_666);
DO_TEST (INT32_MAX, test_optional_sfixed32_max);
#undef DO_TEST
}
static void test_oneof_int64 (void)
{
#define DO_TEST(value, example_packed_data) \
DO_TEST_ONEOF(test_int64, TEST_INT64, value, example_packed_data, GENERIC_ASSIGN, NUMERIC_EQUALS)
DO_TEST (INT64_MIN, test_optional_int64_min);
DO_TEST (-1111111111LL, test_optional_int64_m1111111111LL);
DO_TEST (0, test_optional_int64_0);
DO_TEST (QUINTILLION, test_optional_int64_quintillion);
DO_TEST (INT64_MAX, test_optional_int64_max);
#undef DO_TEST
}
static void test_oneof_sint64 (void)
{
#define DO_TEST(value, example_packed_data) \
DO_TEST_ONEOF(test_sint64, TEST_SINT64, value, example_packed_data, GENERIC_ASSIGN, NUMERIC_EQUALS)
DO_TEST (INT64_MIN, test_optional_sint64_min);
DO_TEST (-1111111111LL, test_optional_sint64_m1111111111LL);
DO_TEST (0, test_optional_sint64_0);
DO_TEST (QUINTILLION, test_optional_sint64_quintillion);
DO_TEST (INT64_MAX, test_optional_sint64_max);
#undef DO_TEST
}
static void test_oneof_sfixed64 (void)
{
#define DO_TEST(value, example_packed_data) \
DO_TEST_ONEOF(test_sfixed64, TEST_SFIXED64, value, example_packed_data, GENERIC_ASSIGN, NUMERIC_EQUALS)
DO_TEST (INT64_MIN, test_optional_sfixed64_min);
DO_TEST (-1111111111LL, test_optional_sfixed64_m1111111111LL);
DO_TEST (0, test_optional_sfixed64_0);
DO_TEST (QUINTILLION, test_optional_sfixed64_quintillion);
DO_TEST (INT64_MAX, test_optional_sfixed64_max);
#undef DO_TEST
}
static void test_oneof_uint32 (void)
{
#define DO_TEST(value, example_packed_data) \
DO_TEST_ONEOF(test_uint32, TEST_UINT32, value, example_packed_data, GENERIC_ASSIGN, NUMERIC_EQUALS)
DO_TEST (0, test_optional_uint32_0);
DO_TEST (669, test_optional_uint32_669);
DO_TEST (UINT32_MAX, test_optional_uint32_max);
#undef DO_TEST
}
static void test_oneof_fixed32 (void)
{
#define DO_TEST(value, example_packed_data) \
DO_TEST_ONEOF(test_fixed32, TEST_FIXED32, value, example_packed_data, GENERIC_ASSIGN, NUMERIC_EQUALS)
DO_TEST (0, test_optional_fixed32_0);
DO_TEST (669, test_optional_fixed32_669);
DO_TEST (UINT32_MAX, test_optional_fixed32_max);
#undef DO_TEST
}
static void test_oneof_uint64 (void)
{
#define DO_TEST(value, example_packed_data) \
DO_TEST_ONEOF(test_uint64, TEST_UINT64, value, example_packed_data, GENERIC_ASSIGN, NUMERIC_EQUALS)
DO_TEST (0, test_optional_uint64_0);
DO_TEST (669669669669669ULL, test_optional_uint64_669669669669669);
DO_TEST (UINT64_MAX, test_optional_uint64_max);
#undef DO_TEST
}
static void test_oneof_fixed64 (void)
{
#define DO_TEST(value, example_packed_data) \
DO_TEST_ONEOF(test_fixed64, TEST_FIXED64, value, example_packed_data, GENERIC_ASSIGN, NUMERIC_EQUALS)
DO_TEST (0, test_optional_fixed64_0);
DO_TEST (669669669669669ULL, test_optional_fixed64_669669669669669);
DO_TEST (UINT64_MAX, test_optional_fixed64_max);
#undef DO_TEST
}
static void test_oneof_float (void)
{
#define DO_TEST(value, example_packed_data) \
DO_TEST_ONEOF(test_float, TEST_FLOAT, value, example_packed_data, GENERIC_ASSIGN, NUMERIC_EQUALS)
DO_TEST (-100, test_optional_float_m100);
DO_TEST (0, test_optional_float_0);
DO_TEST (141243, test_optional_float_141243);
#undef DO_TEST
}
static void test_oneof_double (void)
{
#define DO_TEST(value, example_packed_data) \
DO_TEST_ONEOF(test_double, TEST_DOUBLE, value, example_packed_data, GENERIC_ASSIGN, NUMERIC_EQUALS)
DO_TEST (-100, test_optional_double_m100);
DO_TEST (0, test_optional_double_0);
DO_TEST (141243, test_optional_double_141243);
#undef DO_TEST
}
static void test_oneof_bool (void)
{
#define DO_TEST(value, example_packed_data) \
DO_TEST_ONEOF(test_boolean, TEST_BOOLEAN, value, example_packed_data, GENERIC_ASSIGN, NUMERIC_EQUALS)
DO_TEST (0, test_optional_bool_0);
DO_TEST (1, test_optional_bool_1);
#undef DO_TEST
}
static void test_oneof_TestEnumSmall (void)
{
#define DO_TEST(value, example_packed_data) \
DO_TEST_ONEOF(test_enum_small, TEST_ENUM_SMALL, value, example_packed_data, GENERIC_ASSIGN, NUMERIC_EQUALS)
DO_TEST (0, test_optional_enum_small_0);
DO_TEST (1, test_optional_enum_small_1);
#undef DO_TEST
}
static void test_oneof_TestEnum (void)
{
#define DO_TEST(value, example_packed_data) \
DO_TEST_ONEOF(test_enum, TEST_ENUM, value, example_packed_data, GENERIC_ASSIGN, NUMERIC_EQUALS)
DO_TEST (FOO__TEST_ENUM__VALUE0, test_optional_enum_0);
DO_TEST (FOO__TEST_ENUM__VALUE1, test_optional_enum_1);
DO_TEST (FOO__TEST_ENUM__VALUE127, test_optional_enum_127);
DO_TEST (FOO__TEST_ENUM__VALUE128, test_optional_enum_128);
DO_TEST (FOO__TEST_ENUM__VALUE16383, test_optional_enum_16383);
DO_TEST (FOO__TEST_ENUM__VALUE16384, test_optional_enum_16384);
DO_TEST (FOO__TEST_ENUM__VALUE2097151, test_optional_enum_2097151);
DO_TEST (FOO__TEST_ENUM__VALUE2097152, test_optional_enum_2097152);
DO_TEST (FOO__TEST_ENUM__VALUE268435455, test_optional_enum_268435455);
DO_TEST (FOO__TEST_ENUM__VALUE268435456, test_optional_enum_268435456);
#undef DO_TEST
}
static void test_oneof_string (void)
{
#define DO_TEST(value, example_packed_data) \
DO_TEST_ONEOF_REF_VAL (test_string, TEST_STRING, value, example_packed_data, GENERIC_ASSIGN, STRING_EQUALS)
DO_TEST ("", test_optional_string_empty);
DO_TEST ("hello", test_optional_string_hello);
#undef DO_TEST
}
static void test_oneof_bytes (void)
{
static ProtobufCBinaryData bd_empty = { 0, (uint8_t*)"" };
static ProtobufCBinaryData bd_hello = { 5, (uint8_t*)"hello" };
static ProtobufCBinaryData bd_random = { 5, (uint8_t*)"\1\0\375\2\4" };
#define DO_TEST(value, example_packed_data) \
DO_TEST_ONEOF (test_bytes, TEST_BYTES, value, example_packed_data, GENERIC_ASSIGN, binary_data_equals)
DO_TEST (bd_empty, test_optional_bytes_empty);
DO_TEST (bd_hello, test_optional_bytes_hello);
DO_TEST (bd_random, test_optional_bytes_random);
#undef DO_TEST
}
static void test_oneof_SubMess (void)
{
Foo__SubMess submess = FOO__SUB_MESS__INIT;
#define DO_TEST(value, example_packed_data) \
DO_TEST_ONEOF_REF_VAL (test_message, TEST_MESSAGE, value, example_packed_data, GENERIC_ASSIGN, submesses_equals)
submess.test = 0;
DO_TEST (&submess, test_optional_submess_0);
submess.test = 42;
DO_TEST (&submess, test_optional_submess_42);
#undef DO_TEST
}
static void test_oneof_merge (void)
{
Foo__TestMessOneof *msg;
#define DO_TEST(value, member, MEMBER, equals_func, example_packed_data) \
msg = foo__test_mess_oneof__unpack (NULL, sizeof (example_packed_data), example_packed_data); \
assert (msg); \
assert (msg->test_oneof_case == FOO__TEST_MESS_ONEOF__TEST_ONEOF_##MEMBER); \
assert (equals_func (msg->member, value)); \
foo__test_mess_oneof__free_unpacked (msg, NULL);
DO_TEST (444455555, test_double, TEST_DOUBLE, NUMERIC_EQUALS, test_oneof_merge_double);
DO_TEST (333, test_float, TEST_FLOAT, NUMERIC_EQUALS, test_oneof_merge_float);
DO_TEST (666, test_int32, TEST_INT32, NUMERIC_EQUALS, test_oneof_merge_int32);
DO_TEST ("", test_string, TEST_STRING, STRING_EQUALS, test_oneof_merge_string);
Foo__SubMess submess = FOO__SUB_MESS__INIT;
submess.test = 42;
DO_TEST (&submess, test_message, TEST_MESSAGE, submesses_equals, test_oneof_merge_submess);
ProtobufCBinaryData bd_hello = { 5, (uint8_t*)"hello" };
DO_TEST(bd_hello, test_bytes, TEST_BYTES, binary_data_equals, test_oneof_merge_bytes);
#undef DO_TEST
}
/* === repeated type fields === */
#define DO_TEST_REPEATED(lc_member_name, cast, \
static_array, example_packed_data, \
@ -1514,6 +1810,40 @@ test_field_merge (void)
foo__test_mess_optional__free_unpacked (merged, NULL);
}
static void
test_submessage_merge (void)
{
Foo__TestMessSubMess *merged;
size_t size;
uint8_t *packed;
merged = foo__test_mess_sub_mess__unpack
(NULL, sizeof (test_submess_unmerged1), test_submess_unmerged1);
size = foo__test_mess_sub_mess__get_packed_size(merged);
packed = malloc (size);
foo__test_mess_sub_mess__pack (merged, packed);
assert (size == sizeof (test_submess_merged1));
assert (memcmp (packed, test_submess_merged1, size) == 0);
foo__test_mess_sub_mess__free_unpacked (merged, NULL);
free (packed);
merged = foo__test_mess_sub_mess__unpack
(NULL, sizeof (test_submess_unmerged2), test_submess_unmerged2);
size = foo__test_mess_sub_mess__get_packed_size(merged);
packed = malloc (size);
foo__test_mess_sub_mess__pack (merged, packed);
assert (size == sizeof (test_submess_merged2));
assert (memcmp (packed, test_submess_merged2, size) == 0);
foo__test_mess_sub_mess__free_unpacked (merged, NULL);
free (packed);
}
static struct alloc_data {
uint32_t alloc_count;
int32_t allocs_left;
@ -1821,6 +2151,27 @@ static Test tests[] =
{ "test optional string", test_optional_string },
{ "test optional bytes", test_optional_bytes },
{ "test optional SubMess", test_optional_SubMess },
{ "test empty oneof" ,test_empty_oneof },
{ "test oneof int32", test_oneof_int32 },
{ "test oneof sint32", test_oneof_sint32 },
{ "test oneof sfixed32", test_oneof_sfixed32 },
{ "test oneof int64", test_oneof_int64 },
{ "test oneof sint64", test_oneof_sint64 },
{ "test oneof sfixed64", test_oneof_sfixed64 },
{ "test oneof uint32", test_oneof_uint32 },
{ "test oneof fixed32", test_oneof_fixed32 },
{ "test oneof uint64", test_oneof_uint64 },
{ "test oneof fixed64", test_oneof_fixed64 },
{ "test oneof float", test_oneof_float },
{ "test oneof double", test_oneof_double },
{ "test oneof bool", test_oneof_bool },
{ "test oneof TestEnumSmall", test_oneof_TestEnumSmall },
{ "test oneof TestEnum", test_oneof_TestEnum },
{ "test oneof string", test_oneof_string },
{ "test oneof bytes", test_oneof_bytes },
{ "test oneof SubMess", test_oneof_SubMess },
{ "test merged oneof unpack", test_oneof_merge },
{ "test empty repeated" ,test_empty_repeated },
{ "test repeated int32" ,test_repeated_int32 },
@ -1869,6 +2220,7 @@ static Test tests[] =
{ "test optional lowercase enum default value", test_optional_lowercase_enum_default_value },
{ "test field merge", test_field_merge },
{ "test submessage merge", test_submessage_merge },
{ "test free unpacked", test_alloc_free_all },
{ "test alloc failure", test_alloc_fail },

View File

@ -132,6 +132,30 @@ message TestMessOptional {
optional SubMess test_message = 18;
}
message TestMessOneof {
oneof test_oneof {
int32 test_int32 = 1;
sint32 test_sint32 = 2;
sfixed32 test_sfixed32 = 3;
int64 test_int64 = 4;
sint64 test_sint64 = 5;
sfixed64 test_sfixed64 = 6;
uint32 test_uint32 = 7;
fixed32 test_fixed32 = 8;
uint64 test_uint64 = 9;
fixed64 test_fixed64 = 10;
float test_float = 11;
double test_double = 12;
bool test_boolean = 13;
TestEnumSmall test_enum_small = 14;
TestEnum test_enum = 15;
string test_string = 16;
bytes test_bytes = 17;
SubMess test_message = 18;
}
optional int32 opt_int = 19;
}
message TestMessRequiredInt32 {
required int32 test = 42;
}
@ -379,3 +403,10 @@ message TestMessageCheck {
optional bytes optional_bytes = 9;
}
message TestMessSubMess {
required TestMess rep_mess = 1;
required TestMessOptional opt_mess = 2;
required TestMessOneof oneof_mess = 3;
required SubMess req_mess = 4;
required DefaultOptionalValues def_mess = 5;
}