From 87a18f37743efde6f66f77209c98400cdec67cbe Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Wed, 14 Jan 2015 11:18:20 -0800 Subject: Support oneof defs in upb. This change adds support for a OneofDef (upb_oneofdef), which represents a 'oneof' as introduced by Protocol Buffers. This is semantically a union type that contains fields and in turn may be added to a MessageDef. This change does not alter parsing or the handler abstraction in any way, because a oneof has impact only at a higher semantic level (i.e., any sort of storage of the fields in a message object), which is user-specific with respect to upb. --- tests/bindings/googlepb/test_vs_proto2.cc | 4 +- tests/test_cpp.cc | 102 +++++++++++++++++++++++++++++- tests/test_def.c | 57 ++++++++++++++++- 3 files changed, 159 insertions(+), 4 deletions(-) (limited to 'tests') diff --git a/tests/bindings/googlepb/test_vs_proto2.cc b/tests/bindings/googlepb/test_vs_proto2.cc index c89339a..49dfe49 100644 --- a/tests/bindings/googlepb/test_vs_proto2.cc +++ b/tests/bindings/googlepb/test_vs_proto2.cc @@ -40,8 +40,8 @@ const unsigned char message2_data[] = { void compare_metadata(const google::protobuf::Descriptor* d, const upb::MessageDef *upb_md) { ASSERT(d->field_count() == upb_md->field_count()); - for (upb::MessageDef::const_iterator i = upb_md->begin(); i != upb_md->end(); - ++i) { + for (upb::MessageDef::const_field_iterator i = upb_md->field_begin(); + i != upb_md->field_end(); ++i) { const upb::FieldDef* upb_f = *i; const google::protobuf::FieldDescriptor *proto2_f = d->FindFieldByNumber(upb_f->number()); diff --git a/tests/test_cpp.cc b/tests/test_cpp.cc index 55bb4b3..71f354c 100644 --- a/tests/test_cpp.cc +++ b/tests/test_cpp.cc @@ -12,6 +12,7 @@ #include #include +#include #include "upb/def.h" #include "upb/descriptor/reader.h" @@ -164,7 +165,7 @@ static void TestSymbolTable(const char *descriptor_file) { #ifdef UPB_CXX11 // Test range-based for. std::set fielddefs; - for (const upb::FieldDef* f : *md.get()) { + for (const upb::FieldDef* f : md.get()->fields()) { AssertInsert(&fielddefs, f); ASSERT(f->containing_type() == md.get()); } @@ -1117,6 +1118,103 @@ void TestHandlerDataDestruction() { ASSERT(x == 0); } +void TestOneofs() { + upb::Status status; + upb::reffed_ptr md(upb::MessageDef::New()); + upb::reffed_ptr o(upb::OneofDef::New()); + + o->set_name("test_oneof", &status); + ASSERT(status.ok()); + + for (int i = 0; i < 5; i++) { + std::ostringstream fieldname; + fieldname << "field_" << i; + upb::reffed_ptr f(upb::FieldDef::New()); + f->set_name(fieldname.str(), &status); + ASSERT(status.ok()); + f->set_type(UPB_TYPE_INT32); + f->set_number(i + 1, &status); + ASSERT(status.ok()); + f->set_label(UPB_LABEL_OPTIONAL); + + o->AddField(f.get(), &status); + ASSERT(status.ok()); + } + + md->AddOneof(o.get(), &status); + ASSERT(status.ok()); + + int field_count = 0; + for (upb::OneofDef::iterator it = o->begin(); it != o->end(); ++it) { + upb::FieldDef* f = *it; + ASSERT(f->type() == UPB_TYPE_INT32); + field_count++; + } + ASSERT(field_count == 5); + + upb::MessageDef::oneof_iterator msg_it = md->oneof_begin(); + ASSERT(msg_it != md->oneof_end()); + ASSERT((*msg_it) == o.get()); + +#ifdef UPB_CXX11 + // Test range-based for on both fields and oneofs (with the iterator adaptor). + field_count = 0; + for (auto* field : md->fields()) { + UPB_UNUSED(field); + field_count++; + } + ASSERT(field_count == 5); + + int oneof_count = 0; + for (auto* oneof : md->oneofs()) { + UPB_UNUSED(oneof); + oneof_count++; + } + ASSERT(oneof_count == 1); +#endif // UPB_CXX11 + + // Test that we can add a new field to the oneof and that it becomes a member + // of the msgdef as well. + upb::reffed_ptr newf(upb::FieldDef::New()); + newf->set_name("new_field_10", &status); + ASSERT(status.ok()); + newf->set_number(10, &status); + ASSERT(status.ok()); + newf->set_label(UPB_LABEL_OPTIONAL); + newf->set_type(UPB_TYPE_INT32); + o->AddField(newf.get(), &status); + ASSERT(status.ok()); + ASSERT(newf->containing_type() == md.get()); + + // Test that we can add a new field to the msgdef first and then to the oneof. + upb::reffed_ptr newf2(upb::FieldDef::New()); + newf2->set_name("new_field_11", &status); + ASSERT(status.ok()); + newf2->set_number(11, &status); + ASSERT(status.ok()); + newf2->set_label(UPB_LABEL_OPTIONAL); + newf2->set_type(UPB_TYPE_INT32); + md->AddField(newf2.get(), &status); + ASSERT(status.ok()); + o->AddField(newf2.get(), &status); + ASSERT(status.ok()); + ASSERT(newf2->containing_oneof() == o.get()); + + // Test that we cannot add REQUIRED or REPEATED fields to the oneof. + upb::reffed_ptr newf3(upb::FieldDef::New()); + newf3->set_name("new_field_12", &status); + ASSERT(status.ok()); + newf3->set_number(12, &status); + ASSERT(status.ok()); + newf3->set_label(UPB_LABEL_REQUIRED); + newf3->set_type(UPB_TYPE_INT32); + o->AddField(newf3.get(), &status); + ASSERT(!status.ok()); + newf->set_label(UPB_LABEL_REPEATED); + o->AddField(newf3.get(), &status); + ASSERT(!status.ok()); +} + extern "C" { int run_tests(int argc, char *argv[]) { @@ -1173,6 +1271,8 @@ int run_tests(int argc, char *argv[]) { TestHandlerDataDestruction(); + TestOneofs(); + return 0; } diff --git a/tests/test_def.c b/tests/test_def.c index dcf80c0..b85b031 100644 --- a/tests/test_def.c +++ b/tests/test_def.c @@ -189,7 +189,9 @@ static upb_fielddef *newfield( ASSERT(upb_fielddef_setnumber(f, num, NULL)); upb_fielddef_settype(f, type); upb_fielddef_setlabel(f, label); - ASSERT(upb_fielddef_setsubdefname(f, type_name, NULL)); + if (type_name) { + ASSERT(upb_fielddef_setsubdefname(f, type_name, NULL)); + } return f; } @@ -342,6 +344,58 @@ static void test_descriptor_flags() { upb_msgdef_unref(m2, &m2); } +static void test_oneofs() { + upb_status s = UPB_STATUS_INIT; + bool ok = true; + + upb_symtab *symtab = upb_symtab_new(&symtab); + ASSERT(symtab != NULL); + + // Create a test message for fields to refer to. + upb_msgdef *subm = upb_msgdef_newnamed("SubMessage", &symtab); + upb_msgdef_addfield(subm, newfield("field1", 1, UPB_TYPE_INT32, + UPB_LABEL_OPTIONAL, NULL, &symtab), + &symtab, NULL); + upb_def *subm_defs[] = {UPB_UPCAST(subm)}; + ASSERT_STATUS(upb_symtab_add(symtab, subm_defs, 1, &symtab, &s), &s); + + upb_msgdef *m = upb_msgdef_newnamed("TestMessage", &symtab); + ASSERT(upb_msgdef_numoneofs(m) == 0); + + upb_oneofdef *o = upb_oneofdef_new(&o); + ASSERT(upb_oneofdef_numfields(o) == 0); + ASSERT(upb_oneofdef_name(o) == NULL); + + ok = upb_oneofdef_setname(o, "test_oneof", &s); + ASSERT_STATUS(ok, &s); + + ok = upb_oneofdef_addfield(o, newfield("field1", 1, UPB_TYPE_INT32, + UPB_LABEL_OPTIONAL, NULL, &symtab), + &symtab, NULL); + ASSERT_STATUS(ok, &s); + ok = upb_oneofdef_addfield(o, newfield("field2", 2, UPB_TYPE_MESSAGE, + UPB_LABEL_OPTIONAL, ".SubMessage", + &symtab), + &symtab, NULL); + ASSERT_STATUS(ok, &s); + + ok = upb_msgdef_addoneof(m, o, NULL, &s); + ASSERT_STATUS(ok, &s); + + upb_def *defs[] = {UPB_UPCAST(m)}; + ASSERT_STATUS(upb_symtab_add(symtab, defs, 1, &symtab, &s), &s); + + ASSERT(upb_msgdef_numoneofs(m) == 1); + const upb_oneofdef *lookup_o = upb_msgdef_ntooz(m, "test_oneof"); + ASSERT(lookup_o == o); + + const upb_fielddef *lookup_field = upb_oneofdef_ntofz(o, "field1"); + ASSERT(lookup_field != NULL && upb_fielddef_number(lookup_field) == 1); + + upb_symtab_unref(symtab, &symtab); + upb_oneofdef_unref(o, &o); +} + int run_tests(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "Usage: test_def \n"); @@ -358,5 +412,6 @@ int run_tests(int argc, char *argv[]) { test_partial_freeze(); test_noreftracking(); test_descriptor_flags(); + test_oneofs(); return 0; } -- cgit v1.2.3