summaryrefslogtreecommitdiff
path: root/tests/test_def.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_def.c')
-rw-r--r--tests/test_def.c171
1 files changed, 163 insertions, 8 deletions
diff --git a/tests/test_def.c b/tests/test_def.c
index 3ca3064..698532e 100644
--- a/tests/test_def.c
+++ b/tests/test_def.c
@@ -1,19 +1,174 @@
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2011 Google Inc. See LICENSE for details.
+ *
+ * Test of defs and symtab. There should be far more tests of edge conditions
+ * (like attempts to link defs that don't have required properties set).
+ */
-#undef NDEBUG /* ensure tests always assert. */
#include "upb/def.h"
+#include "upb/pb/glue.h"
+#include "upb_test.h"
#include <stdlib.h>
+#include <string.h>
-int main() {
- upb_symtab *s = upb_symtab_new();
+const char *descriptor_file;
- // Will be empty atm since we haven't added anything to the symtab.
+static void test_empty_symtab() {
+ upb_symtab *s = upb_symtab_new();
int count;
- const upb_def **defs = upb_symtab_getdefs(s, &count, UPB_DEF_ANY);
- for (int i = 0; i < count; i++) {
- upb_def_unref(defs[i]);
- }
+ const upb_def **defs = upb_symtab_getdefs(s, &count, UPB_DEF_ANY, NULL);
+ ASSERT(count == 0);
free(defs);
+ upb_symtab_unref(s);
+}
+static upb_symtab *load_test_proto() {
+ upb_symtab *s = upb_symtab_new();
+ ASSERT(s);
+ upb_status status = UPB_STATUS_INIT;
+ 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);
+ }
+ upb_status_uninit(&status);
+ return s;
+}
+
+static void test_cycles() {
+ upb_symtab *s = load_test_proto();
+
+ // Test cycle detection by making a cyclic def's main refcount go to zero
+ // and then be incremented to one again.
+ const upb_def *def = upb_symtab_lookup(s, "A", &def);
+ ASSERT(def);
+ ASSERT(upb_def_isfinalized(def));
upb_symtab_unref(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);
+ ASSERT(f);
+ ASSERT(upb_hassubdef(f));
+ const upb_def *def2 = upb_fielddef_subdef(f);
+ ASSERT(upb_downcast_msgdef_const(def2));
+ ASSERT(strcmp(upb_def_fullname(def2), "B") == 0);
+
+ upb_def_ref(def2, &def2);
+ upb_def_unref(def, &def);
+ upb_def_unref(def2, &def2);
+}
+
+static void test_fielddef_unref() {
+ upb_symtab *s = load_test_proto();
+ const upb_msgdef *md = upb_symtab_lookupmsg(s, "A", &md);
+ 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
+ // alive.
+ upb_symtab_unref(s);
+ upb_msgdef_unref(md, &md);
+ // Check that md is still alive.
+ 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);
+}
+
+static void test_fielddef_accessors() {
+ upb_fielddef *f1 = upb_fielddef_new(&f1);
+ upb_fielddef *f2 = upb_fielddef_new(&f2);
+
+ ASSERT(upb_fielddef_ismutable(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));
+ upb_fielddef_setname(f2, "f2");
+ upb_fielddef_setnumber(f2, 1572);
+ upb_fielddef_settype(f2, UPB_TYPE(BYTES));
+ upb_fielddef_setlabel(f2, UPB_LABEL(REPEATED));
+ ASSERT(upb_fielddef_number(f2) == 1572);
+
+ upb_fielddef_unref(f1, &f1);
+ upb_fielddef_unref(f2, &f2);
+}
+
+static upb_fielddef *newfield(
+ const char *name, int32_t num, uint8_t type, uint8_t label,
+ const char *type_name, void *owner) {
+ upb_fielddef *f = upb_fielddef_new(owner);
+ upb_fielddef_setname(f, name);
+ upb_fielddef_setnumber(f, num);
+ upb_fielddef_settype(f, type);
+ upb_fielddef_setlabel(f, label);
+ upb_fielddef_setsubtypename(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);
+ 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);
+ return e;
+}
+
+void test_replacement() {
+ upb_symtab *s = upb_symtab_new();
+
+ upb_msgdef *m = upb_msgdef_newnamed("MyMessage", &s);
+ upb_msgdef_addfield(m, newfield(
+ "field1", 1, UPB_TYPE(ENUM), UPB_LABEL(OPTIONAL), ".MyEnum", &s), &s);
+ 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_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)};
+ ASSERT_STATUS(upb_symtab_add(s, newdefs2, 1, &s, &status), &status);
+
+ const upb_msgdef *m3 = upb_symtab_lookupmsg(s, "MyMessage", &m3);
+ ASSERT(m3);
+ // Must be different because it points to MyEnum which was replaced.
+ ASSERT(m3 != m);
+ upb_msgdef_unref(m3, &m3);
+
+ m3 = upb_symtab_lookupmsg(s, "MyMessage2", &m3);
+ // Should be the same because it was not replaced, nor were any defs that
+ // are reachable from it.
+ ASSERT(m3 == m2);
+ upb_msgdef_unref(m3, &m3);
+
+ upb_symtab_unref(s);
+}
+
+int main(int argc, char *argv[]) {
+ if (argc < 2) {
+ fprintf(stderr, "Usage: test_def <test.proto.pb>\n");
+ return 1;
+ }
+ descriptor_file = argv[1];
+ test_empty_symtab();
+ test_cycles();
+ test_fielddef_accessors();
+ test_fielddef_unref();
+ test_replacement();
return 0;
}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback