From 3bd691a4975b2267ff04611507e766a7f9f87e83 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Fri, 8 May 2015 16:56:29 -0700 Subject: Google-internal development. --- tests/bindings/googlepb/test_vs_proto2.cc | 13 ++-- tests/json/test_json.cc | 110 +++++++++++++++++++++++++++--- tests/pb/test_decoder.cc | 51 +++++++++----- tests/test_cpp.cc | 103 +++++++++++++++++++++++++++- tests/test_def.c | 91 +++++++++++++++++++++++- 5 files changed, 334 insertions(+), 34 deletions(-) (limited to 'tests') diff --git a/tests/bindings/googlepb/test_vs_proto2.cc b/tests/bindings/googlepb/test_vs_proto2.cc index c89339a..8e68791 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()); @@ -77,13 +77,14 @@ void parse_and_compare(google::protobuf::Message *msg1, cache.GetDecoderMethod(upb::pb::DecoderMethodOptions(protomsg_handlers))); upb::Status status; - upb::pb::Decoder decoder(decoder_method.get(), &status); + upb::Environment env; + env.ReportErrorsTo(&status); upb::Sink protomsg_sink(protomsg_handlers, msg2); - - decoder.ResetOutput(&protomsg_sink); + upb::pb::Decoder* decoder = + upb::pb::Decoder::Create(&env, decoder_method.get(), &protomsg_sink); msg2->Clear(); - bool ok = upb::BufferSource::PutBuffer(str, len, decoder.input()); + bool ok = upb::BufferSource::PutBuffer(str, len, decoder->input()); if (!ok) { fprintf(stderr, "error parsing: %s\n", status.error_message()); print_diff(*msg1, *msg2); diff --git a/tests/json/test_json.cc b/tests/json/test_json.cc index f1e2304..f2e26b8 100644 --- a/tests/json/test_json.cc +++ b/tests/json/test_json.cc @@ -85,6 +85,33 @@ static TestCase kTestRoundtripMessages[] = { TEST("{\"optional_string\":\"\\uFFFF\"}"), EXPECT("{\"optional_string\":\"\xEF\xBF\xBF\"}") }, + // map-field tests + { + TEST("{\"map_string_string\":{\"a\":\"value1\",\"b\":\"value2\"," + "\"c\":\"value3\"}}"), + EXPECT_SAME + }, + { + TEST("{\"map_int32_string\":{\"1\":\"value1\",\"-1\":\"value2\"," + "\"1234\":\"value3\"}}"), + EXPECT_SAME + }, + { + TEST("{\"map_bool_string\":{\"false\":\"value1\",\"true\":\"value2\"}}"), + EXPECT_SAME + }, + { + TEST("{\"map_string_int32\":{\"asdf\":1234,\"jkl;\":-1}}"), + EXPECT_SAME + }, + { + TEST("{\"map_string_bool\":{\"asdf\":true,\"jkl;\":false}}"), + EXPECT_SAME + }, + { + TEST("{\"map_string_msg\":{\"asdf\":{\"foo\":42},\"jkl;\":{\"foo\":84}}}"), + EXPECT_SAME + }, TEST_SENTINEL }; @@ -115,6 +142,53 @@ static const upb::MessageDef* BuildTestMessage( submsg->set_full_name("SubMessage", &st); AddField(submsg.get(), 1, "foo", UPB_TYPE_INT32, false); + // Create MapEntryStringString. + upb::reffed_ptr mapentry_string_string( + upb::MessageDef::New()); + mapentry_string_string->set_full_name("MapEntry_String_String", &st); + mapentry_string_string->setmapentry(true); + AddField(mapentry_string_string.get(), 1, "key", UPB_TYPE_STRING, false); + AddField(mapentry_string_string.get(), 2, "value", UPB_TYPE_STRING, false); + + // Create MapEntryInt32String. + upb::reffed_ptr mapentry_int32_string( + upb::MessageDef::New()); + mapentry_int32_string->set_full_name("MapEntry_Int32_String", &st); + mapentry_int32_string->setmapentry(true); + AddField(mapentry_int32_string.get(), 1, "key", UPB_TYPE_INT32, false); + AddField(mapentry_int32_string.get(), 2, "value", UPB_TYPE_STRING, false); + + // Create MapEntryBoolString. + upb::reffed_ptr mapentry_bool_string( + upb::MessageDef::New()); + mapentry_bool_string->set_full_name("MapEntry_Bool_String", &st); + mapentry_bool_string->setmapentry(true); + AddField(mapentry_bool_string.get(), 1, "key", UPB_TYPE_BOOL, false); + AddField(mapentry_bool_string.get(), 2, "value", UPB_TYPE_STRING, false); + + // Create MapEntryStringInt32. + upb::reffed_ptr mapentry_string_int32( + upb::MessageDef::New()); + mapentry_string_int32->set_full_name("MapEntry_String_Int32", &st); + mapentry_string_int32->setmapentry(true); + AddField(mapentry_string_int32.get(), 1, "key", UPB_TYPE_STRING, false); + AddField(mapentry_string_int32.get(), 2, "value", UPB_TYPE_INT32, false); + + // Create MapEntryStringBool. + upb::reffed_ptr mapentry_string_bool(upb::MessageDef::New()); + mapentry_string_bool->set_full_name("MapEntry_String_Bool", &st); + mapentry_string_bool->setmapentry(true); + AddField(mapentry_string_bool.get(), 1, "key", UPB_TYPE_STRING, false); + AddField(mapentry_string_bool.get(), 2, "value", UPB_TYPE_BOOL, false); + + // Create MapEntryStringMessage. + upb::reffed_ptr mapentry_string_msg(upb::MessageDef::New()); + mapentry_string_msg->set_full_name("MapEntry_String_Message", &st); + mapentry_string_msg->setmapentry(true); + AddField(mapentry_string_msg.get(), 1, "key", UPB_TYPE_STRING, false); + AddField(mapentry_string_msg.get(), 2, "value", UPB_TYPE_MESSAGE, false, + upb::upcast(submsg.get())); + // Create MyEnum. upb::reffed_ptr myenum(upb::EnumDef::New()); myenum->set_full_name("MyEnum", &st); @@ -150,13 +224,33 @@ static const upb::MessageDef* BuildTestMessage( AddField(md.get(), 19, "optional_enum", UPB_TYPE_ENUM, true, upb::upcast(myenum.get())); + AddField(md.get(), 20, "map_string_string", UPB_TYPE_MESSAGE, true, + upb::upcast(mapentry_string_string.get())); + AddField(md.get(), 21, "map_int32_string", UPB_TYPE_MESSAGE, true, + upb::upcast(mapentry_int32_string.get())); + AddField(md.get(), 22, "map_bool_string", UPB_TYPE_MESSAGE, true, + upb::upcast(mapentry_bool_string.get())); + AddField(md.get(), 23, "map_string_int32", UPB_TYPE_MESSAGE, true, + upb::upcast(mapentry_string_int32.get())); + AddField(md.get(), 24, "map_string_bool", UPB_TYPE_MESSAGE, true, + upb::upcast(mapentry_string_bool.get())); + AddField(md.get(), 25, "map_string_msg", UPB_TYPE_MESSAGE, true, + upb::upcast(mapentry_string_msg.get())); + // Add both to our symtab. - upb::Def* defs[3] = { + upb::Def* defs[9] = { upb::upcast(submsg.ReleaseTo(&defs)), upb::upcast(myenum.ReleaseTo(&defs)), upb::upcast(md.ReleaseTo(&defs)), + upb::upcast(mapentry_string_string.ReleaseTo(&defs)), + upb::upcast(mapentry_int32_string.ReleaseTo(&defs)), + upb::upcast(mapentry_bool_string.ReleaseTo(&defs)), + upb::upcast(mapentry_string_int32.ReleaseTo(&defs)), + upb::upcast(mapentry_string_bool.ReleaseTo(&defs)), + upb::upcast(mapentry_string_msg.ReleaseTo(&defs)), }; - symtab->Add(defs, 3, &defs, &st); + symtab->Add(defs, 9, &defs, &st); + ASSERT(st.ok()); // Return TestMessage. return symtab->LookupMessage("TestMessage"); @@ -198,14 +292,14 @@ void test_json_roundtrip_message(const char* json_src, const upb::Handlers* serialize_handlers, int seam) { upb::Status st; - upb::json::Parser parser(&st); - upb::json::Printer printer(serialize_handlers); + upb::Environment env; + env.ReportErrorsTo(&st); StringSink data_sink; + upb::json::Printer* printer = + upb::json::Printer::Create(&env, serialize_handlers, data_sink.Sink()); + upb::json::Parser* parser = upb::json::Parser::Create(&env, printer->input()); - parser.ResetOutput(printer.input()); - printer.ResetOutput(data_sink.Sink()); - - upb::BytesSink* input = parser.input(); + upb::BytesSink* input = parser->input(); void *sub; size_t len = strlen(json_src); size_t ofs = 0; diff --git a/tests/pb/test_decoder.cc b/tests/pb/test_decoder.cc index 3aea777..98926a6 100644 --- a/tests/pb/test_decoder.cc +++ b/tests/pb/test_decoder.cc @@ -64,6 +64,8 @@ (float)completed * 100 / total); \ } +#define MAX_NESTING 64 + uint32_t filter_hash = 0; double completed; double total; @@ -210,7 +212,7 @@ string submsg(uint32_t fn, const string& buf) { // using the closure depth to test that the stack of closures is properly // handled. -int closures[UPB_DECODER_MAX_NESTING]; +int closures[MAX_NESTING]; string output; void indentbuf(string *buf, int depth) { @@ -508,6 +510,15 @@ upb::reffed_ptr NewHandlers(TestMode mode) { const upb::Handlers *global_handlers; const upb::pb::DecoderMethod *global_method; +upb::pb::Decoder* CreateDecoder(upb::Environment* env, + const upb::pb::DecoderMethod* method, + upb::Sink* sink) { + upb::pb::Decoder *ret = upb::pb::Decoder::Create(env, method, sink); + ASSERT(ret != NULL); + ret->set_max_nesting(MAX_NESTING); + return ret; +} + uint32_t Hash(const string& proto, const string* expected_output, size_t seam1, size_t seam2) { uint32_t hash = MurmurHash2(proto.c_str(), proto.size(), 0); @@ -545,19 +556,21 @@ static bool parse(upb::pb::Decoder* decoder, void* subc, const char* buf, #define LINE(x) x "\n" void run_decoder(const string& proto, const string* expected_output) { upb::Status status; - upb::pb::Decoder decoder(global_method, &status); upb::Sink sink(global_handlers, &closures[0]); - decoder.ResetOutput(&sink); for (size_t i = 0; i < proto.size(); i++) { for (size_t j = i; j < UPB_MIN(proto.size(), i + 5); j++) { + // TODO(haberman): hoist this again once the environment supports reset. + upb::Environment env; + env.ReportErrorsTo(&status); + upb::pb::Decoder *decoder = CreateDecoder(&env, global_method, &sink); + testhash = Hash(proto, expected_output, i, j); if (filter_hash && testhash != filter_hash) continue; if (test_mode != COUNT_ONLY) { - decoder.Reset(); output.clear(); status.Clear(); size_t ofs = 0; - upb::BytesSink* input = decoder.input(); + upb::BytesSink* input = decoder->input(); void *sub; if (filter_hash) { @@ -576,9 +589,9 @@ void run_decoder(const string& proto, const string* expected_output) { } bool ok = input->Start(proto.size(), &sub) && - parse(&decoder, sub, proto.c_str(), 0, i, &ofs, &status) && - parse(&decoder, sub, proto.c_str(), i, j, &ofs, &status) && - parse(&decoder, sub, proto.c_str(), j, proto.size(), &ofs, + parse(decoder, sub, proto.c_str(), 0, i, &ofs, &status) && + parse(decoder, sub, proto.c_str(), i, j, &ofs, &status) && + parse(decoder, sub, proto.c_str(), j, proto.size(), &ofs, &status) && ofs == proto.size(); @@ -852,7 +865,7 @@ void test_invalid() { // Test exceeding the resource limit of stack depth. string buf; - for (int i = 0; i <= UPB_DECODER_MAX_NESTING; i++) { + for (int i = 0; i <= MAX_NESTING; i++) { buf.assign(submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, buf)); } assert_does_not_parse(buf); @@ -871,11 +884,12 @@ void test_valid() { if (!filter_hash || filter_hash == testhash) { testhash = emptyhash; upb::Status status; - upb::pb::Decoder decoder(global_method, &status); + upb::Environment env; + env.ReportErrorsTo(&status); upb::Sink sink(global_handlers, &closures[0]); - decoder.ResetOutput(&sink); + upb::pb::Decoder* decoder = CreateDecoder(&env, global_method, &sink); output.clear(); - bool ok = upb::BufferSource::PutBuffer("", 0, decoder.input()); + bool ok = upb::BufferSource::PutBuffer("", 0, decoder->input()); ASSERT(ok); ASSERT(status.ok()); if (test_mode == ALL_HANDLERS) { @@ -1076,7 +1090,7 @@ void test_valid() { // Staying within the stack limit should work properly. string buf; string textbuf; - int total = UPB_DECODER_MAX_NESTING - 1; + int total = MAX_NESTING - 1; for (int i = 0; i < total; i++) { buf.assign(submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, buf)); indentbuf(&textbuf, i); @@ -1135,11 +1149,12 @@ upb::reffed_ptr method = { NULL, 0 }, }; for (int i = 0; testdata[i].data; i++) { + upb::Environment env; upb::Status status; - upb::pb::Decoder decoder(method.get(), &status); - upb::Sink sink(global_handlers, &closures[0]); - decoder.ResetOutput(&sink); - upb::BytesSink* input = decoder.input(); + env.ReportErrorsTo(&status); + upb::Sink sink(method->dest_handlers(), &closures[0]); + upb::pb::Decoder* decoder = CreateDecoder(&env, method.get(), &sink); + upb::BytesSink* input = decoder->input(); void* subc; ASSERT(input->Start(0, &subc)); size_t ofs = 0; @@ -1182,7 +1197,7 @@ extern "C" { int run_tests(int argc, char *argv[]) { if (argc > 1) filter_hash = strtol(argv[1], NULL, 16); - for (int i = 0; i < UPB_DECODER_MAX_NESTING; i++) { + for (int i = 0; i < MAX_NESTING; i++) { closures[i] = i; } diff --git a/tests/test_cpp.cc b/tests/test_cpp.cc index 55bb4b3..c2de6c3 100644 --- a/tests/test_cpp.cc +++ b/tests/test_cpp.cc @@ -12,8 +12,10 @@ #include #include +#include #include "upb/def.h" +#include "upb/env.h" #include "upb/descriptor/reader.h" #include "upb/handlers.h" #include "upb/pb/decoder.h" @@ -164,7 +166,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 +1119,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 +1272,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..800d685 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,91 @@ static void test_descriptor_flags() { upb_msgdef_unref(m2, &m2); } +static void test_mapentry_check() { + upb_status s = UPB_STATUS_INIT; + + upb_msgdef *m = upb_msgdef_new(&m); + upb_msgdef_setfullname(m, "TestMessage", &s); + upb_fielddef *f = upb_fielddef_new(&f); + upb_fielddef_setname(f, "field1", &s); + upb_fielddef_setnumber(f, 1, &s); + upb_fielddef_setlabel(f, UPB_LABEL_OPTIONAL); + upb_fielddef_settype(f, UPB_TYPE_MESSAGE); + upb_fielddef_setsubdefname(f, ".MapEntry", &s); + upb_msgdef_addfield(m, f, &f, &s); + ASSERT(upb_ok(&s)); + + upb_msgdef *subm = upb_msgdef_new(&subm); + upb_msgdef_setfullname(subm, "MapEntry", &s); + upb_msgdef_setmapentry(subm, true); + + upb_symtab *symtab = upb_symtab_new(&symtab); + upb_def *defs[] = {UPB_UPCAST(m), UPB_UPCAST(subm)}; + upb_symtab_add(symtab, defs, 2, NULL, &s); + // Should not have succeeded: non-repeated field pointing to a MapEntry. + ASSERT(!upb_ok(&s)); + + upb_fielddef_setlabel(f, UPB_LABEL_REPEATED); + upb_symtab_add(symtab, defs, 2, NULL, &s); + ASSERT(upb_ok(&s)); + + upb_symtab_unref(symtab, &symtab); + upb_msgdef_unref(subm, &subm); + upb_msgdef_unref(m, &m); +} + +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 +445,7 @@ int run_tests(int argc, char *argv[]) { test_partial_freeze(); test_noreftracking(); test_descriptor_flags(); + test_mapentry_check(); + test_oneofs(); return 0; } -- cgit v1.2.3