summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/test_cpp.cc20
-rw-r--r--tests/test_decoder.cc258
-rw-r--r--tests/test_decoder_schema.proto64
-rw-r--r--tests/test_def.c137
-rw-r--r--tests/test_table.cc13
-rw-r--r--tests/test_varint.c13
-rw-r--r--tests/test_vs_proto2.cc39
-rw-r--r--tests/testmain.cc18
-rw-r--r--tests/upb_test.h21
9 files changed, 429 insertions, 154 deletions
diff --git a/tests/test_cpp.cc b/tests/test_cpp.cc
index fb0916d..59603d9 100644
--- a/tests/test_cpp.cc
+++ b/tests/test_cpp.cc
@@ -8,20 +8,20 @@
*/
#include <stdio.h>
+#include <string.h>
#include <iostream>
-#include "upb/bytestream.hpp"
-#include "upb/def.hpp"
-#include "upb/handlers.hpp"
-#include "upb/upb.hpp"
-#include "upb/pb/decoder.hpp"
-#include "upb/pb/glue.hpp"
+#include "upb/bytestream.h"
+#include "upb/def.h"
+#include "upb/handlers.h"
+#include "upb/pb/glue.h"
#include "upb_test.h"
+#include "upb/upb.h"
static void TestSymbolTable(const char *descriptor_file) {
upb::SymbolTable *s = upb::SymbolTable::New(&s);
upb::Status status;
if (!upb::LoadDescriptorFileIntoSymtab(s, descriptor_file, &status)) {
- std::cerr << "Couldn't load descriptor: " << status;
+ std::cerr << "Couldn't load descriptor: " << status.GetString();
exit(1);
}
const upb::MessageDef *md = s->LookupMessage("A", &md);
@@ -41,7 +41,9 @@ static void TestByteStream() {
free(str);
}
-int main(int argc, char *argv[]) {
+extern "C" {
+
+int run_tests(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: test_cpp <descriptor file>\n");
return 1;
@@ -50,3 +52,5 @@ int main(int argc, char *argv[]) {
TestByteStream();
return 0;
}
+
+}
diff --git a/tests/test_decoder.cc b/tests/test_decoder.cc
index 13403bb..d42c0fe 100644
--- a/tests/test_decoder.cc
+++ b/tests/test_decoder.cc
@@ -7,6 +7,7 @@
* input, with buffer breaks in arbitrary places.
*
* Tests to add:
+ * - string/bytes
* - unknown field handler called appropriately
* - unknown fields can be inserted in random places
* - fuzzing of valid input
@@ -35,6 +36,9 @@
#include "upb/pb/varint.h"
#include "upb/upb.h"
#include "upb_test.h"
+#include "third_party/upb/tests/test_decoder_schema.upb.h"
+
+uint32_t filter_hash = 0;
// Copied from decoder.c, since this is not a public interface.
typedef struct {
@@ -186,66 +190,78 @@ void indent(void *depth) {
indentbuf(&output, *(int*)depth);
}
-#define VALUE_HANDLER(member, fmt) \
- upb_flow_t value_ ## member(void *closure, upb_value fval, upb_value val) { \
- indent(closure); \
- output.appendf("%" PRIu32 ":%" fmt "\n", \
- upb_value_getuint32(fval), upb_value_get ## member(val)); \
- return UPB_CONTINUE; \
+#define NUMERIC_VALUE_HANDLER(member, ctype, fmt) \
+ bool value_ ## member(void *closure, void *fval, ctype val) { \
+ indent(closure); \
+ uint32_t *num = static_cast<uint32_t*>(fval); \
+ output.appendf("%" PRIu32 ":%" fmt "\n", *num, val); \
+ return true; \
}
-VALUE_HANDLER(uint32, PRIu32)
-VALUE_HANDLER(uint64, PRIu64)
-VALUE_HANDLER(int32, PRId32)
-VALUE_HANDLER(int64, PRId64)
-VALUE_HANDLER(float, "g")
-VALUE_HANDLER(double, "g")
+NUMERIC_VALUE_HANDLER(uint32, uint32_t, PRIu32)
+NUMERIC_VALUE_HANDLER(uint64, uint64_t, PRIu64)
+NUMERIC_VALUE_HANDLER(int32, int32_t, PRId32)
+NUMERIC_VALUE_HANDLER(int64, int64_t, PRId64)
+NUMERIC_VALUE_HANDLER(float, float, "g")
+NUMERIC_VALUE_HANDLER(double, double, "g")
-upb_flow_t value_bool(void *closure, upb_value fval, upb_value val) {
+bool value_bool(void *closure, void *fval, bool val) {
indent(closure);
- output.appendf("%" PRIu32 ":%s\n",
- upb_value_getuint32(fval),
- upb_value_getbool(val) ? "true" : "false");
- return UPB_CONTINUE;
+ uint32_t *num = static_cast<uint32_t*>(fval);
+ output.appendf("%" PRIu32 ":%s\n", *num, val ? "true" : "false");
+ return true;
}
-upb_flow_t value_string(void *closure, upb_value fval, upb_value val) {
- // Note: won't work with strings that contain NULL.
+void* startstr(void *closure, void *fval, size_t size_hint) {
indent(closure);
- char *str = upb_byteregion_strdup(upb_value_getbyteregion(val));
- output.appendf("%" PRIu32 ":%s\n", upb_value_getuint32(fval), str);
- free(str);
- return UPB_CONTINUE;
+ uint32_t *num = static_cast<uint32_t*>(fval);
+ output.appendf("%" PRIu32 ":(%zu)\"", *num, size_hint);
+ return ((int*)closure) + 1;
+}
+
+size_t value_string(void *closure, void *fval, const char *buf, size_t n) {
+ output.append(buf, n);
+ return n;
+}
+
+bool endstr(void *closure, void *fval) {
+ UPB_UNUSED(fval);
+ output.append("\"\n");
+ return true;
}
-upb_sflow_t startsubmsg(void *closure, upb_value fval) {
+void* startsubmsg(void *closure, void *fval) {
indent(closure);
- output.appendf("%" PRIu32 ":{\n", upb_value_getuint32(fval));
- return UPB_CONTINUE_WITH(((int*)closure) + 1);
+ uint32_t *num = static_cast<uint32_t*>(fval);
+ output.appendf("%" PRIu32 ":{\n", *num);
+ return ((int*)closure) + 1;
}
-upb_flow_t endsubmsg(void *closure, upb_value fval) {
+bool endsubmsg(void *closure, void *fval) {
+ UPB_UNUSED(fval);
indent(closure);
output.append("}\n");
- return UPB_CONTINUE;
+ return true;
}
-upb_sflow_t startseq(void *closure, upb_value fval) {
+void* startseq(void *closure, void *fval) {
indent(closure);
- output.appendf("%" PRIu32 ":[\n", upb_value_getuint32(fval));
- return UPB_CONTINUE_WITH(((int*)closure) + 1);
+ uint32_t *num = static_cast<uint32_t*>(fval);
+ output.appendf("%" PRIu32 ":[\n", *num);
+ return ((int*)closure) + 1;
}
-upb_flow_t endseq(void *closure, upb_value fval) {
+bool endseq(void *closure, void *fval) {
+ UPB_UNUSED(fval);
indent(closure);
output.append("]\n");
- return UPB_CONTINUE;
+ return true;
}
-upb_flow_t startmsg(void *closure) {
+bool startmsg(void *closure) {
indent(closure);
output.append("<\n");
- return UPB_CONTINUE;
+ return true;
}
void endmsg(void *closure, upb_status *status) {
@@ -254,14 +270,23 @@ void endmsg(void *closure, upb_status *status) {
output.append(">\n");
}
-void doreg(upb_mhandlers *m, uint32_t num, upb_fieldtype_t type, bool repeated,
- upb_value_handler *handler) {
- upb_fhandlers *f = upb_mhandlers_newfhandlers(m, num, type, repeated);
+void free_uint32(void *val) {
+ uint32_t *u32 = static_cast<uint32_t*>(val);
+ delete u32;
+}
+
+template<class T>
+void doreg(upb_handlers *h, uint32_t num,
+ typename upb::Handlers::Value<T>::Handler *handler) {
+ const upb_fielddef *f = upb_msgdef_itof(upb_handlers_msgdef(h), num);
ASSERT(f);
- upb_fhandlers_setvalue(f, handler);
- upb_fhandlers_setstartseq(f, &startseq);
- upb_fhandlers_setendseq(f, &endseq);
- upb_fhandlers_setfval(f, upb_value_uint32(num));
+ ASSERT(h->SetValueHandler<T>(f, handler, new uint32_t(num), free_uint32));
+ if (f->IsSequence()) {
+ ASSERT(h->SetStartSequenceHandler(
+ f, &startseq, new uint32_t(num), free_uint32));
+ ASSERT(h->SetEndSequenceHandler(
+ f, &endseq, new uint32_t(num), free_uint32));
+ }
}
// The repeated field number to correspond to the given non-repeated field
@@ -273,57 +298,81 @@ uint32_t rep_fn(uint32_t fn) {
#define NOP_FIELD 40
#define UNKNOWN_FIELD 666
-void reg(upb_mhandlers *m, upb_fieldtype_t type, upb_value_handler *handler) {
+template <class T>
+void reg(upb_handlers *h, upb_fieldtype_t type,
+ typename upb::Handlers::Value<T>::Handler *handler) {
// We register both a repeated and a non-repeated field for every type.
// For the non-repeated field we make the field number the same as the
// type. For the repeated field we make it a function of the type.
- doreg(m, type, type, false, handler);
- doreg(m, rep_fn(type), type, true, handler);
+ doreg<T>(h, type, handler);
+ doreg<T>(h, rep_fn(type), handler);
}
-void reg_subm(upb_mhandlers *m, uint32_t num, upb_fieldtype_t type,
- bool repeated) {
- upb_fhandlers *f =
- upb_mhandlers_newfhandlers_subm(m, num, type, repeated, m);
+void reg_subm(upb_handlers *h, uint32_t num) {
+ const upb_fielddef *f = upb_msgdef_itof(upb_handlers_msgdef(h), num);
ASSERT(f);
- upb_fhandlers_setstartseq(f, &startseq);
- upb_fhandlers_setendseq(f, &endseq);
- upb_fhandlers_setstartsubmsg(f, &startsubmsg);
- upb_fhandlers_setendsubmsg(f, &endsubmsg);
- upb_fhandlers_setfval(f, upb_value_uint32(num));
+ if (f->IsSequence()) {
+ ASSERT(h->SetStartSequenceHandler(
+ f, &startseq, new uint32_t(num), free_uint32));
+ ASSERT(h->SetEndSequenceHandler(
+ f, &endseq, new uint32_t(num), free_uint32));
+ }
+ ASSERT(h->SetStartSubMessageHandler(
+ f, &startsubmsg, new uint32_t(num), free_uint32));
+ ASSERT(h->SetEndSubMessageHandler(
+ f, &endsubmsg, new uint32_t(num), free_uint32));
+ ASSERT(upb_handlers_setsubhandlers(h, f, h));
}
-void reghandlers(upb_mhandlers *m) {
- upb_mhandlers_setstartmsg(m, &startmsg);
- upb_mhandlers_setendmsg(m, &endmsg);
+void reg_str(upb_handlers *h, uint32_t num) {
+ const upb_fielddef *f = upb_msgdef_itof(upb_handlers_msgdef(h), num);
+ ASSERT(f);
+ if (f->IsSequence()) {
+ ASSERT(h->SetStartSequenceHandler(
+ f, &startseq, new uint32_t(num), free_uint32));
+ ASSERT(h->SetEndSequenceHandler(
+ f, &endseq, new uint32_t(num), free_uint32));
+ }
+ ASSERT(h->SetStartStringHandler(
+ f, &startstr, new uint32_t(num), free_uint32));
+ ASSERT(h->SetEndStringHandler(
+ f, &endstr, new uint32_t(num), free_uint32));
+ ASSERT(h->SetStringHandler(
+ f, &value_string, new uint32_t(num), free_uint32));
+}
+
+void reghandlers(upb_handlers *h) {
+ upb_handlers_setstartmsg(h, &startmsg);
+ upb_handlers_setendmsg(h, &endmsg);
// Register handlers for each type.
- reg(m, UPB_TYPE(DOUBLE), &value_double);
- reg(m, UPB_TYPE(FLOAT), &value_float);
- reg(m, UPB_TYPE(INT64), &value_int64);
- reg(m, UPB_TYPE(UINT64), &value_uint64);
- reg(m, UPB_TYPE(INT32) , &value_int32);
- reg(m, UPB_TYPE(FIXED64), &value_uint64);
- reg(m, UPB_TYPE(FIXED32), &value_uint32);
- reg(m, UPB_TYPE(BOOL), &value_bool);
- reg(m, UPB_TYPE(STRING), &value_string);
- reg(m, UPB_TYPE(BYTES), &value_string);
- reg(m, UPB_TYPE(UINT32), &value_uint32);
- reg(m, UPB_TYPE(ENUM), &value_int32);
- reg(m, UPB_TYPE(SFIXED32), &value_int32);
- reg(m, UPB_TYPE(SFIXED64), &value_int64);
- reg(m, UPB_TYPE(SINT32), &value_int32);
- reg(m, UPB_TYPE(SINT64), &value_int64);
+ reg<double> (h, UPB_TYPE(DOUBLE), &value_double);
+ reg<float> (h, UPB_TYPE(FLOAT), &value_float);
+ reg<int64_t> (h, UPB_TYPE(INT64), &value_int64);
+ reg<uint64_t>(h, UPB_TYPE(UINT64), &value_uint64);
+ reg<int32_t> (h, UPB_TYPE(INT32) , &value_int32);
+ reg<uint64_t>(h, UPB_TYPE(FIXED64), &value_uint64);
+ reg<uint32_t>(h, UPB_TYPE(FIXED32), &value_uint32);
+ reg<bool> (h, UPB_TYPE(BOOL), &value_bool);
+ reg<uint32_t>(h, UPB_TYPE(UINT32), &value_uint32);
+ reg<int32_t> (h, UPB_TYPE(ENUM), &value_int32);
+ reg<int32_t> (h, UPB_TYPE(SFIXED32), &value_int32);
+ reg<int64_t> (h, UPB_TYPE(SFIXED64), &value_int64);
+ reg<int32_t> (h, UPB_TYPE(SINT32), &value_int32);
+ reg<int64_t> (h, UPB_TYPE(SINT64), &value_int64);
+
+ reg_str(h, UPB_TYPE(STRING));
+ reg_str(h, UPB_TYPE(BYTES));
+ reg_str(h, rep_fn(UPB_TYPE(STRING)));
+ reg_str(h, rep_fn(UPB_TYPE(BYTES)));
// Register submessage/group handlers that are self-recursive
// to this type, eg: message M { optional M m = 1; }
- reg_subm(m, UPB_TYPE(MESSAGE), UPB_TYPE(MESSAGE), false);
- reg_subm(m, UPB_TYPE(GROUP), UPB_TYPE(GROUP), false);
- reg_subm(m, rep_fn(UPB_TYPE(MESSAGE)), UPB_TYPE(MESSAGE), true);
- reg_subm(m, rep_fn(UPB_TYPE(GROUP)), UPB_TYPE(GROUP), true);
+ reg_subm(h, UPB_TYPE(MESSAGE));
+ reg_subm(h, rep_fn(UPB_TYPE(MESSAGE)));
- // Register a no-op string field so we can pad the proto wherever we want.
- upb_mhandlers_newfhandlers(m, NOP_FIELD, UPB_TYPE(STRING), false);
+ // For NOP_FIELD we register no handlers, so we can pad a proto freely without
+ // changing the output.
}
@@ -413,22 +462,32 @@ upb_byteregion *upb_seamsrc_allbytes(upb_seamsrc *s) {
/* Running of test cases ******************************************************/
upb_decoderplan *plan;
+
+uint32_t Hash(const buffer& proto, const buffer* expected_output) {
+ uint32_t hash = MurmurHash2(proto.buf(), proto.len(), 0);
+ if (expected_output)
+ hash = MurmurHash2(expected_output->buf(), expected_output->len(), hash);
+ bool hasjit = upb_decoderplan_hasjitcode(plan);
+ hash = MurmurHash2(&hasjit, 1, hash);
+ return hash;
+}
+
#define LINE(x) x "\n"
void run_decoder(const buffer& proto, const buffer* expected_output) {
+ testhash = Hash(proto, expected_output);
+ if (filter_hash && testhash != filter_hash) return;
upb_seamsrc src;
upb_seamsrc_init(&src, proto.buf(), proto.len());
upb_decoder d;
upb_decoder_init(&d);
- upb_decoder_resetplan(&d, plan, 0);
+ upb_decoder_resetplan(&d, plan);
for (size_t i = 0; i < proto.len(); i++) {
for (size_t j = i; j < UPB_MIN(proto.len(), i + 5); j++) {
upb_seamsrc_resetseams(&src, i, j);
upb_byteregion *input = upb_seamsrc_allbytes(&src);
output.clear();
upb_decoder_resetinput(&d, input, &closures[0]);
- upb_success_t success = UPB_SUSPENDED;
- while (success == UPB_SUSPENDED)
- success = upb_decoder_decode(&d);
+ upb_success_t success = upb_decoder_decode(&d);
ASSERT(upb_ok(upb_decoder_status(&d)) == (success == UPB_OK));
if (expected_output) {
ASSERT_STATUS(success == UPB_OK, upb_decoder_status(&d));
@@ -448,6 +507,7 @@ void run_decoder(const buffer& proto, const buffer* expected_output) {
}
upb_decoder_uninit(&d);
upb_seamsrc_uninit(&src);
+ testhash = 0;
}
const static buffer thirty_byte_nop = buffer(cat(
@@ -777,35 +837,47 @@ void run_tests() {
test_valid();
}
-int main() {
+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_MAX_NESTING; i++) {
closures[i] = i;
}
- // Construct decoder plan.
- upb_handlers *h = upb_handlers_new();
- reghandlers(upb_handlers_newmhandlers(h));
// Create an empty handlers to make sure that the decoder can handle empty
// messages.
- upb_handlers_newmhandlers(h);
+ upb_handlers *h = upb_handlers_new(UPB_TEST_DECODER_EMPTYMESSAGE, &h);
+ bool ok = upb_handlers_freeze(&h, 1, NULL);
+ ASSERT(ok);
+ plan = upb_decoderplan_new(h, true);
+ upb_handlers_unref(h, &h);
+ upb_decoderplan_unref(plan);
+
+ // Construct decoder plan.
+ h = upb_handlers_new(UPB_TEST_DECODER_DECODERTEST, &h);
+ reghandlers(h);
+ ok = upb_handlers_freeze(&h, 1, NULL);
// Test without JIT.
plan = upb_decoderplan_new(h, false);
+ ASSERT(!upb_decoderplan_hasjitcode(plan));
run_tests();
upb_decoderplan_unref(plan);
+#ifdef UPB_USE_JIT_X64
// Test JIT.
plan = upb_decoderplan_new(h, true);
-#ifdef UPB_USE_JIT_X64
ASSERT(upb_decoderplan_hasjitcode(plan));
-#else
- ASSERT(!upb_decoderplan_hasjitcode(plan));
-#endif
run_tests();
upb_decoderplan_unref(plan);
+#endif
plan = NULL;
printf("All tests passed, %d assertions.\n", num_assertions);
- upb_handlers_unref(h);
+ upb_handlers_unref(h, &h);
return 0;
}
+
+}
diff --git a/tests/test_decoder_schema.proto b/tests/test_decoder_schema.proto
new file mode 100644
index 0000000..50bfca9
--- /dev/null
+++ b/tests/test_decoder_schema.proto
@@ -0,0 +1,64 @@
+//
+// upb - a minimalist implementation of protocol buffers.
+//
+// Copyright (c) 2012 Google Inc. See LICENSE for details.
+// Author: Josh Haberman <jhaberman@gmail.com>
+//
+// Schema used in test_decoder.cc. It contains two fields (one optional
+// and one repeated) for each type.
+
+package upb.test_decoder;
+
+message M {
+ optional M m = 1;
+}
+
+enum E {
+ FOO = 1;
+}
+
+message EmptyMessage {}
+
+message DecoderTest {
+ optional double f_double = 1;
+ optional float f_float = 2;
+ optional int64 f_int64 = 3;
+ optional uint64 f_uint64 = 4;
+ optional int32 f_int32 = 5;
+ optional fixed64 f_fixed64 = 6;
+ optional fixed32 f_fixed32 = 7;
+ optional bool f_bool = 8;
+ optional string f_string = 9;
+ optional bytes f_bytes = 12;
+ optional uint32 f_uint32 = 13;
+ optional sfixed32 f_sfixed32 = 15;
+ optional sfixed64 f_sfixed64 = 16;
+ optional sint32 f_sint32 = 17;
+ optional sint64 f_sint64 = 18;
+
+ optional DecoderTest f_message = 11;
+ optional E f_enum = 14;
+
+
+ repeated double r_double = 536869912;
+ repeated float r_float = 536869913;
+ repeated int64 r_int64 = 536869914;
+ repeated uint64 r_uint64 = 536869915;
+ repeated int32 r_int32 = 536869916;
+ repeated fixed64 r_fixed64 = 536869917;
+ repeated fixed32 r_fixed32 = 536869918;
+ repeated bool r_bool = 536869919;
+ repeated string r_string = 536869920;
+ repeated bytes r_bytes = 536869923;
+ repeated uint32 r_uint32 = 536869924;
+ repeated sfixed32 r_sfixed32 = 536869926;
+ repeated sfixed64 r_sfixed64 = 536869927;
+ repeated sint32 r_sint32 = 536869928;
+ repeated sint64 r_sint64 = 536869929;
+
+ repeated DecoderTest r_message = 536869922;
+ repeated E r_enum = 536869925;
+
+ // To allow arbitrary padding.
+ optional string nop_field = 40;
+}
diff --git a/tests/test_def.c b/tests/test_def.c
index f60d556..7f089d7 100644
--- a/tests/test_def.c
+++ b/tests/test_def.c
@@ -18,7 +18,7 @@ const char *descriptor_file;
static void test_empty_symtab() {
upb_symtab *s = upb_symtab_new(&s);
int count;
- const upb_def **defs = upb_symtab_getdefs(s, &count, UPB_DEF_ANY, NULL);
+ const upb_def **defs = upb_symtab_getdefs(s, UPB_DEF_ANY, NULL, &count);
ASSERT(count == 0);
free(defs);
upb_symtab_unref(s, &s);
@@ -31,7 +31,7 @@ static upb_symtab *load_test_proto(void *owner) {
if (!upb_load_descriptor_file_into_symtab(s, descriptor_file, &status)) {
fprintf(stderr, "Error loading descriptor file: %s\n",
upb_status_getstr(&status));
- exit(1);
+ ASSERT(false);
}
upb_status_uninit(&status);
return s;
@@ -44,27 +44,30 @@ static void test_cycles() {
// and then be incremented to one again.
const upb_def *def = upb_symtab_lookup(s, "A", &def);
ASSERT(def);
- ASSERT(upb_def_isfinalized(def));
+ ASSERT(upb_def_isfrozen(def));
upb_symtab_unref(s, &s);
// Message A has only one subfield: "optional B b = 1".
- const upb_msgdef *m = upb_downcast_msgdef_const(def);
- upb_fielddef *f = upb_msgdef_itof(m, 1);
+ const upb_msgdef *m = upb_downcast_msgdef(def);
+ const upb_fielddef *f = upb_msgdef_itof(m, 1);
ASSERT(f);
- ASSERT(upb_hassubdef(f));
+ ASSERT(upb_fielddef_hassubdef(f));
const upb_def *def2 = upb_fielddef_subdef(f);
- ASSERT(upb_downcast_msgdef_const(def2));
+ ASSERT(upb_downcast_msgdef(def2));
ASSERT(strcmp(upb_def_fullname(def2), "B") == 0);
upb_def_ref(def2, &def2);
upb_def_unref(def, &def);
+
+ // We know "def" is still alive because it's reachable from def2.
+ ASSERT(strcmp(upb_def_fullname(def), "A") == 0);
upb_def_unref(def2, &def2);
}
static void test_fielddef_unref() {
upb_symtab *s = load_test_proto(&s);
const upb_msgdef *md = upb_symtab_lookupmsg(s, "A", &md);
- upb_fielddef *f = upb_msgdef_itof(md, 1);
+ const upb_fielddef *f = upb_msgdef_itof(md, 1);
upb_fielddef_ref(f, &f);
// Unref symtab and msgdef; now fielddef is the only thing keeping the msgdef
@@ -72,7 +75,7 @@ static void test_fielddef_unref() {
upb_symtab_unref(s, &s);
upb_msgdef_unref(md, &md);
// Check that md is still alive.
- ASSERT(strcmp(upb_def_fullname(UPB_UPCAST(md)), "A") == 0);
+ ASSERT(strcmp(upb_def_fullname(upb_upcast(md)), "A") == 0);
// Check that unref of fielddef frees the whole remaining graph.
upb_fielddef_unref(f, &f);
@@ -82,14 +85,14 @@ static void test_fielddef_accessors() {
upb_fielddef *f1 = upb_fielddef_new(&f1);
upb_fielddef *f2 = upb_fielddef_new(&f2);
- ASSERT(upb_fielddef_ismutable(f1));
+ ASSERT(!upb_fielddef_isfrozen(f1));
upb_fielddef_setname(f1, "f1");
upb_fielddef_setnumber(f1, 1937);
upb_fielddef_settype(f1, UPB_TYPE(FIXED64));
upb_fielddef_setlabel(f1, UPB_LABEL(REPEATED));
ASSERT(upb_fielddef_number(f1) == 1937);
- ASSERT(upb_fielddef_ismutable(f2));
+ ASSERT(!upb_fielddef_isfrozen(f2));
upb_fielddef_setname(f2, "f2");
upb_fielddef_setnumber(f2, 1572);
upb_fielddef_settype(f2, UPB_TYPE(BYTES));
@@ -98,6 +101,12 @@ static void test_fielddef_accessors() {
upb_fielddef_unref(f1, &f1);
upb_fielddef_unref(f2, &f2);
+
+ // Test that we don't leak an unresolved subdef name.
+ f1 = upb_fielddef_new(&f1);
+ upb_fielddef_settype(f1, UPB_TYPE(MESSAGE));
+ upb_fielddef_setsubdefname(f1, "YO");
+ upb_fielddef_unref(f1, &f1);
}
static upb_fielddef *newfield(
@@ -108,23 +117,23 @@ static upb_fielddef *newfield(
upb_fielddef_setnumber(f, num);
upb_fielddef_settype(f, type);
upb_fielddef_setlabel(f, label);
- upb_fielddef_setsubtypename(f, type_name);
+ upb_fielddef_setsubdefname(f, type_name);
return f;
}
static upb_msgdef *upb_msgdef_newnamed(const char *name, void *owner) {
upb_msgdef *m = upb_msgdef_new(owner);
- upb_def_setfullname(UPB_UPCAST(m), name);
+ upb_def_setfullname(upb_upcast(m), name);
return m;
}
INLINE upb_enumdef *upb_enumdef_newnamed(const char *name, void *owner) {
upb_enumdef *e = upb_enumdef_new(owner);
- upb_def_setfullname(UPB_UPCAST(e), name);
+ upb_def_setfullname(upb_upcast(e), name);
return e;
}
-void test_replacement() {
+static void test_replacement() {
upb_symtab *s = upb_symtab_new(&s);
upb_msgdef *m = upb_msgdef_newnamed("MyMessage", &s);
@@ -133,15 +142,15 @@ void test_replacement() {
upb_msgdef *m2 = upb_msgdef_newnamed("MyMessage2", &s);
upb_enumdef *e = upb_enumdef_newnamed("MyEnum", &s);
- upb_def *newdefs[] = {UPB_UPCAST(m), UPB_UPCAST(m2), UPB_UPCAST(e)};
+ upb_def *newdefs[] = {upb_upcast(m), upb_upcast(m2), upb_upcast(e)};
upb_status status = UPB_STATUS_INIT;
ASSERT_STATUS(upb_symtab_add(s, newdefs, 3, &s, &status), &status);
// Try adding a new definition of MyEnum, MyMessage should get replaced with
// a new version.
upb_enumdef *e2 = upb_enumdef_new(&s);
- upb_def_setfullname(UPB_UPCAST(e2), "MyEnum");
- upb_def *newdefs2[] = {UPB_UPCAST(e2)};
+ upb_def_setfullname(upb_upcast(e2), "MyEnum");
+ upb_def *newdefs2[] = {upb_upcast(e2)};
ASSERT_STATUS(upb_symtab_add(s, newdefs2, 1, &s, &status), &status);
const upb_msgdef *m3 = upb_symtab_lookupmsg(s, "MyMessage", &m3);
@@ -159,7 +168,95 @@ void test_replacement() {
upb_symtab_unref(s, &s);
}
-int main(int argc, char *argv[]) {
+static void test_freeze_free() {
+ // Test that freeze frees defs that were only being kept alive by virtue of
+ // sharing a group with other defs that are being frozen.
+ upb_msgdef *m1 = upb_msgdef_newnamed("M1", &m1);
+ upb_msgdef *m2 = upb_msgdef_newnamed("M2", &m2);
+ upb_msgdef *m3 = upb_msgdef_newnamed("M3", &m3);
+ upb_msgdef *m4 = upb_msgdef_newnamed("M4", &m4);
+
+ // Freeze M4 and make M1 point to it.
+ upb_def_freeze((upb_def*const*)&m4, 1, NULL);
+
+ upb_fielddef *f = upb_fielddef_new(&f);
+ upb_fielddef_settype(f, UPB_TYPE_MESSAGE);
+ ASSERT(upb_fielddef_setnumber(f, 1));
+ ASSERT(upb_fielddef_setname(f, "foo"));
+ ASSERT(upb_fielddef_setsubdef(f, upb_upcast(m4)));
+
+ ASSERT(upb_msgdef_addfield(m1, f, &f));
+
+ // After this unref, M1 is the only thing keeping M4 alive.
+ upb_msgdef_unref(m4, &m4);
+
+ // Force M1/M2/M3 into a single mutable refcounting group.
+ f = upb_fielddef_new(&f);
+ upb_fielddef_settype(f, UPB_TYPE_MESSAGE);
+ ASSERT(upb_fielddef_setnumber(f, 1));
+ ASSERT(upb_fielddef_setname(f, "foo"));
+
+ ASSERT(upb_fielddef_setsubdef(f, upb_upcast(m1)));
+ ASSERT(upb_fielddef_setsubdef(f, upb_upcast(m2)));
+ ASSERT(upb_fielddef_setsubdef(f, upb_upcast(m3)));
+
+ // Make M3 cyclic with itself.
+ ASSERT(upb_msgdef_addfield(m3, f, &f));
+
+ // These will be kept alive since they are in the same refcounting group as
+ // M3, which still has a ref. Note: this behavior is not guaranteed by the
+ // API, but true in practice with its current implementation.
+ upb_msgdef_unref(m1, &m1);
+ upb_msgdef_unref(m2, &m2);
+
+ // Test that they are still alive (NOT allowed by the API).
+ ASSERT(strcmp("M1", upb_def_fullname(upb_upcast(m1))) == 0);
+ ASSERT(strcmp("M2", upb_def_fullname(upb_upcast(m2))) == 0);
+
+ // Freeze M3. If the test leaked no memory, then freeing m1 and m2 was
+ // successful.
+ ASSERT(upb_def_freeze((upb_def*const*)&m3, 1, NULL));
+
+ upb_msgdef_unref(m3, &m3);
+}
+
+static void test_partial_freeze() {
+ // Test that freeze of only part of the graph correctly adjusts objects that
+ // point to the newly-frozen objects.
+ upb_msgdef *m1 = upb_msgdef_newnamed("M1", &m1);
+ upb_msgdef *m2 = upb_msgdef_newnamed("M2", &m2);
+ upb_msgdef *m3 = upb_msgdef_newnamed("M3", &m3);
+
+ upb_fielddef *f1 = upb_fielddef_new(&f1);
+ upb_fielddef_settype(f1, UPB_TYPE_MESSAGE);
+ ASSERT(upb_fielddef_setnumber(f1, 1));
+ ASSERT(upb_fielddef_setname(f1, "f1"));
+ ASSERT(upb_fielddef_setsubdef(f1, upb_upcast(m1)));
+
+ upb_fielddef *f2 = upb_fielddef_new(&f2);
+ upb_fielddef_settype(f2, UPB_TYPE_MESSAGE);
+ ASSERT(upb_fielddef_setnumber(f2, 2));
+ ASSERT(upb_fielddef_setname(f2, "f2"));
+ ASSERT(upb_fielddef_setsubdef(f2, upb_upcast(m2)));
+
+ ASSERT(upb_msgdef_addfield(m3, f1, &f1));
+ ASSERT(upb_msgdef_addfield(m3, f2, &f2));
+
+ // Freeze M1 and M2, which should cause the group to be split
+ // and m3 (left mutable) to take references on m1 and m2.
+ upb_def *defs[] = {upb_upcast(m1), upb_upcast(m2)};
+ ASSERT(upb_def_freeze(defs, 2, NULL));
+
+ ASSERT(upb_msgdef_isfrozen(m1));
+ ASSERT(upb_msgdef_isfrozen(m2));
+ ASSERT(!upb_msgdef_isfrozen(m3));
+
+ upb_msgdef_unref(m1, &m1);
+ upb_msgdef_unref(m2, &m2);
+ upb_msgdef_unref(m3, &m3);
+}
+
+int run_tests(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: test_def <test.proto.pb>\n");
return 1;
@@ -170,5 +267,7 @@ int main(int argc, char *argv[]) {
test_fielddef_accessors();
test_fielddef_unref();
test_replacement();
+ test_freeze_free();
+ test_partial_freeze();
return 0;
}
diff --git a/tests/test_table.cc b/tests/test_table.cc
index 2538e35..bb75fc4 100644
--- a/tests/test_table.cc
+++ b/tests/test_table.cc
@@ -34,7 +34,7 @@ void test_strtable(const vector<std::string>& keys, uint32_t num_to_insert) {
/* Initialize structures. */
upb_strtable table;
std::map<std::string, int32_t> m;
- upb_strtable_init(&table);
+ upb_strtable_init(&table, UPB_CTYPE_INT32);
std::set<std::string> all;
for(size_t i = 0; i < num_to_insert; i++) {
const std::string& key = keys[i];
@@ -77,7 +77,7 @@ void test_inttable(int32_t *keys, uint16_t num_entries, const char *desc) {
uint32_t largest_key = 0;
std::map<uint32_t, uint32_t> m;
__gnu_cxx::hash_map<uint32_t, uint32_t> hm;
- upb_inttable_init(&table);
+ upb_inttable_init(&table, UPB_CTYPE_UINT32);
for(size_t i = 0; i < num_entries; i++) {
int32_t key = keys[i];
largest_key = UPB_MAX((int32_t)largest_key, key);
@@ -103,7 +103,7 @@ void test_inttable(int32_t *keys, uint16_t num_entries, const char *desc) {
upb_value val;
bool ret = upb_inttable_remove(&table, keys[i], &val);
ASSERT(ret == (m.erase(keys[i]) == 1));
- if (ret) ASSERT(upb_value_getuint32(val) == keys[i] * 2);
+ if (ret) ASSERT(upb_value_getuint32(val) == (uint32_t)keys[i] * 2);
hm.erase(keys[i]);
m.erase(keys[i]);
}
@@ -244,7 +244,9 @@ int32_t *get_contiguous_keys(int32_t num) {
return buf;
}
-int main(int argc, char *argv[]) {
+extern "C" {
+
+int run_tests(int argc, char *argv[]) {
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--benchmark") == 0) benchmark = true;
}
@@ -292,4 +294,7 @@ int main(int argc, char *argv[]) {
}
test_inttable(keys4, 64, "Table size: 64, keys: 1-32 and 10133-10164 ====\n");
delete[] keys4;
+ return 0;
+}
+
}
diff --git a/tests/test_varint.c b/tests/test_varint.c
index 0fc93f0..bdbc573 100644
--- a/tests/test_varint.c
+++ b/tests/test_varint.c
@@ -86,16 +86,19 @@ static void test_varint_decoder(upb_decoderet (*decoder)(const char*)) {
printf("ok.\n"); \
} \
-TEST_VARINT_DECODER(branch32);
-TEST_VARINT_DECODER(branch64);
+TEST_VARINT_DECODER(check2_branch32);
+TEST_VARINT_DECODER(check2_branch64);
TEST_VARINT_DECODER(check2_wright);
TEST_VARINT_DECODER(check2_massimino);
-int main() {
- test_branch32();
- test_branch64();
+int run_tests(int argc, char *argv[]) {
+ UPB_UNUSED(argc);
+ UPB_UNUSED(argv);
+ test_check2_branch32();
+ test_check2_branch64();
test_check2_wright();
test_check2_massimino();
+ return 0;
}
#if 0
diff --git a/tests/test_vs_proto2.cc b/tests/test_vs_proto2.cc
index 020dca5..5eca399 100644
--- a/tests/test_vs_proto2.cc
+++ b/tests/test_vs_proto2.cc
@@ -10,19 +10,19 @@
#define __STDC_LIMIT_MACROS // So we get UINT32_MAX
#include <assert.h>
#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
#include <google/protobuf/wire_format_lite.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "benchmarks/google_messages.pb.h"
-#include "upb/def.hpp"
-#include "upb/handlers.hpp"
-#include "upb/msg.hpp"
-#include "upb/pb/decoder.hpp"
+#include "bindings/cpp/upb/pb/decoder.hpp"
+#include "upb/def.h"
+#include "upb/google/bridge.h"
+#include "upb/handlers.h"
#include "upb/pb/glue.h"
#include "upb/pb/varint.h"
-#include "upb/proto2_bridge.hpp"
#include "upb_test.h"
void compare_metadata(const google::protobuf::Descriptor* d,
@@ -36,28 +36,25 @@ void compare_metadata(const google::protobuf::Descriptor* d,
ASSERT(proto2_f);
ASSERT(upb_f->number() == proto2_f->number());
ASSERT(std::string(upb_f->name()) == proto2_f->name());
- ASSERT(upb_f->type() == static_cast<upb::FieldType>(proto2_f->type()));
+ ASSERT(upb_f->type() == static_cast<upb::FieldDef::Type>(proto2_f->type()));
ASSERT(upb_f->IsSequence() == proto2_f->is_repeated());
}
}
void parse_and_compare(MESSAGE_CIDENT *msg1, MESSAGE_CIDENT *msg2,
- const upb::MessageDef *upb_md,
+ const upb::Handlers *handlers,
const char *str, size_t len, bool allow_jit) {
// Parse to both proto2 and upb.
ASSERT(msg1->ParseFromArray(str, len));
- upb::Handlers* handlers = upb::Handlers::New();
- upb::RegisterWriteHandlers(handlers, upb_md);
upb::DecoderPlan* plan = upb::DecoderPlan::New(handlers, allow_jit);
upb::StringSource src(str, len);
upb::Decoder decoder;
- decoder.ResetPlan(plan, 0);
+ decoder.ResetPlan(plan);
decoder.ResetInput(src.AllBytes(), msg2);
msg2->Clear();
ASSERT(decoder.Decode() == UPB_OK);
plan->Unref();
- handlers->Unref();
// Would like to just compare the message objects themselves, but
// unfortunately MessageDifferencer is not part of the open-source release of
@@ -83,7 +80,9 @@ void test_zig_zag() {
}
-int main(int argc, char *argv[])
+extern "C" {
+
+int run_tests(int argc, char *argv[])
{
if (argc < 2) {
fprintf(stderr, "Usage: test_vs_proto2 <message file>\n");
@@ -102,18 +101,18 @@ int main(int argc, char *argv[])
MESSAGE_CIDENT msg1;
MESSAGE_CIDENT msg2;
- const upb::MessageDef* m = upb::proto2_bridge::NewFinalMessageDef(msg1, &m);
+ const upb::Handlers* h = upb::google::NewWriteHandlers(msg1, &h);
- compare_metadata(msg1.GetDescriptor(), m);
+ compare_metadata(msg1.GetDescriptor(), h->message_def());
// Run twice to test proper object reuse.
- parse_and_compare(&msg1, &msg2, m, str, len, true);
- parse_and_compare(&msg1, &msg2, m, str, len, false);
- parse_and_compare(&msg1, &msg2, m, str, len, true);
- parse_and_compare(&msg1, &msg2, m, str, len, false);
+ parse_and_compare(&msg1, &msg2, h, str, len, false);
+ parse_and_compare(&msg1, &msg2, h, str, len, true);
+ parse_and_compare(&msg1, &msg2, h, str, len, false);
+ parse_and_compare(&msg1, &msg2, h, str, len, true);
printf("All tests passed, %d assertions.\n", num_assertions);
- m->Unref(&m);
+ h->Unref(&h);
free((void*)str);
test_zig_zag();
@@ -121,3 +120,5 @@ int main(int argc, char *argv[])
google::protobuf::ShutdownProtobufLibrary();
return 0;
}
+
+}
diff --git a/tests/testmain.cc b/tests/testmain.cc
new file mode 100644
index 0000000..ac0b313
--- /dev/null
+++ b/tests/testmain.cc
@@ -0,0 +1,18 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+// Author: haberman@google.com (Josh Haberman)
+
+#include <stdlib.h>
+#ifdef USE_GOOGLE
+#include "base/init_google.h"
+#endif
+
+extern "C" {
+int run_tests(int argc, char *argv[]);
+}
+
+int main(int argc, char *argv[]) {
+#ifdef USE_GOOGLE
+ InitGoogle(NULL, &argc, &argv, true);
+#endif
+ run_tests(argc, argv);
+}
diff --git a/tests/upb_test.h b/tests/upb_test.h
index 652977b..60714ba 100644
--- a/tests/upb_test.h
+++ b/tests/upb_test.h
@@ -9,25 +9,35 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
int num_assertions = 0;
+uint32_t testhash = 0;
+
+#define PRINT_FAILURE(expr) \
+ fprintf(stderr, "Assertion failed: %s:%d\n", __FILE__, __LINE__); \
+ fprintf(stderr, "expr: %s\n", #expr); \
+ if (testhash) { \
+ fprintf(stderr, "assertion failed running test %x. " \
+ "Run with the arg %x to run only this test.\n", \
+ testhash, testhash); \
+ }
+
#define ASSERT(expr) do { \
++num_assertions; \
if (!(expr)) { \
- fprintf(stderr, "Assertion failed: %s:%d\n", __FILE__, __LINE__); \
- fprintf(stderr, "expr: %s\n", #expr); \
+ PRINT_FAILURE(expr) \
abort(); \
} \
} while (0)
#define ASSERT_NOCOUNT(expr) do { \
if (!(expr)) { \
- fprintf(stderr, "Assertion failed: %s:%d\n", __FILE__, __LINE__); \
- fprintf(stderr, "expr: %s\n", #expr); \
+ PRINT_FAILURE(expr) \
abort(); \
} \
} while (0)
@@ -35,8 +45,7 @@ int num_assertions = 0;
#define ASSERT_STATUS(expr, status) do { \
++num_assertions; \
if (!(expr)) { \
- fprintf(stderr, "Assertion failed: %s:%d\n", __FILE__, __LINE__); \
- fprintf(stderr, "expr: %s\n", #expr); \
+ PRINT_FAILURE(expr) \
fprintf(stderr, "failed status: %s\n", upb_status_getstr(status)); \
abort(); \
} \
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback