From 2d10fa33071d52d7a35ce3b13bc459cd16a0aa33 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Thu, 26 Jun 2014 20:24:32 -0700 Subject: Sync from internal Google development. --- tests/bindings/lua/test.lua | 303 ----------------- tests/bindings/lua/upb.lua | 757 ++++++++++++++++++++++++++++++++++++++++++ tests/bindings/lua/upb.pb.lua | 70 ++++ tests/pb/test_decoder.cc | 50 ++- tests/test_cpp.cc | 38 +++ tests/test_def.c | 34 +- tests/test_handlers.c | 5 +- tests/test_table.cc | 23 +- tests/test_vs_proto2.cc | 5 +- 9 files changed, 952 insertions(+), 333 deletions(-) delete mode 100644 tests/bindings/lua/test.lua create mode 100644 tests/bindings/lua/upb.lua create mode 100644 tests/bindings/lua/upb.pb.lua (limited to 'tests') diff --git a/tests/bindings/lua/test.lua b/tests/bindings/lua/test.lua deleted file mode 100644 index 99f58f2..0000000 --- a/tests/bindings/lua/test.lua +++ /dev/null @@ -1,303 +0,0 @@ - -local upb = require "upb" -local lunit = require "lunit" - -if _VERSION >= 'Lua 5.2' then - _ENV = lunit.module("testupb", "seeall") -else - module("testupb", lunit.testcase, package.seeall) -end - -function test_fielddef() - local f = upb.FieldDef() - assert_false(f:is_frozen()) - assert_nil(f:number()) - assert_nil(f:name()) - assert_nil(f:type()) - assert_equal(upb.LABEL_OPTIONAL, f:label()) - - f:set_name("foo_field") - f:set_number(3) - f:set_label(upb.LABEL_REPEATED) - f:set_type(upb.TYPE_FLOAT) - - assert_equal("foo_field", f:name()) - assert_equal(3, f:number()) - assert_equal(upb.LABEL_REPEATED, f:label()) - assert_equal(upb.TYPE_FLOAT, f:type()) - - local f2 = upb.FieldDef{ - name = "foo", number = 5, type = upb.TYPE_DOUBLE, label = upb.LABEL_REQUIRED - } - - assert_equal("foo", f2:name()) - assert_equal(5, f2:number()) - assert_equal(upb.TYPE_DOUBLE, f2:type()) - assert_equal(upb.LABEL_REQUIRED, f2:label()) -end - -function test_enumdef() - local e = upb.EnumDef() - assert_equal(0, #e) - assert_nil(e:value(5)) - assert_nil(e:value("NONEXISTENT_NAME")) - - for name, value in e:values() do - fail() - end - - e:add("VAL1", 1) - e:add("VAL2", 2) - - local values = {} - for name, value in e:values() do - values[name] = value - end - - assert_equal(1, values["VAL1"]) - assert_equal(2, values["VAL2"]) - - local e2 = upb.EnumDef{ - values = { - {"FOO", 1}, - {"BAR", 77}, - } - } - - assert_equal(1, e2:value("FOO")) - assert_equal(77, e2:value("BAR")) - assert_equal("FOO", e2:value(1)) - assert_equal("BAR", e2:value(77)) -end - -function test_empty_msgdef() - local md = upb.MessageDef() - assert_nil(md:full_name()) -- Def without name is anonymous. - assert_false(md:is_frozen()) - assert_equal(0, #md) - assert_nil(md:field("nonexistent_field")) - assert_nil(md:field(3)) - for field in md:fields() do - fail() - end - - upb.freeze(md) - assert_true(md:is_frozen()) - assert_equal(0, #md) - assert_nil(md:field("nonexistent_field")) - assert_nil(md:field(3)) - for field in md:fields() do - fail() - end -end - -function test_msgdef_constructor() - local f1 = upb.FieldDef{name = "field1", number = 7, type = upb.TYPE_INT32} - local f2 = upb.FieldDef{name = "field2", number = 8, type = upb.TYPE_INT32} - local md = upb.MessageDef{ - full_name = "TestMessage", - fields = {f1, f2} - } - assert_equal("TestMessage", md:full_name()) - assert_false(md:is_frozen()) - assert_equal(2, #md) - assert_equal(f1, md:field("field1")) - assert_equal(f2, md:field("field2")) - assert_equal(f1, md:field(7)) - assert_equal(f2, md:field(8)) - local count = 0 - local found = {} - for field in md:fields() do - count = count + 1 - found[field] = true - end - assert_equal(2, count) - assert_true(found[f1]) - assert_true(found[f2]) - - upb.freeze(md) -end - -function test_msgdef_setters() - local md = upb.MessageDef() - md:set_full_name("Message1") - assert_equal("Message1", md:full_name()) - local f = upb.FieldDef{name = "field1", number = 3, type = upb.TYPE_DOUBLE} - md:add{f} - assert_equal(1, #md) - assert_equal(f, md:field("field1")) -end - -function test_msgdef_errors() - assert_error(function() upb.MessageDef{bad_initializer_key = 5} end) - local md = upb.MessageDef() - assert_error(function() - -- Duplicate field number. - upb.MessageDef{ - fields = { - upb.FieldDef{name = "field1", number = 1, type = upb.TYPE_INT32}, - upb.FieldDef{name = "field2", number = 1, type = upb.TYPE_INT32} - } - } - end) - assert_error(function() - -- Duplicate field name. - upb.MessageDef{ - fields = { - upb.FieldDef{name = "field1", number = 1, type = upb.TYPE_INT32}, - upb.FieldDef{name = "field1", number = 2, type = upb.TYPE_INT32} - } - } - end) - - -- attempt to set a name with embedded NULLs. - assert_error_match("names cannot have embedded NULLs", function() - md:set_full_name("abc\0def") - end) - - upb.freeze(md) - -- Attempt to mutate frozen MessageDef. - -- TODO(haberman): better error message and test for message. - assert_error(function() - md:add{upb.FieldDef{name = "field1", number = 1, type = upb.TYPE_INT32}} - end) - assert_error(function() - md:set_full_name("abc") - end) - - -- Attempt to freeze a msgdef without freezing its subdef. - assert_error_match("is not frozen or being frozen", function() - m1 = upb.MessageDef() - upb.freeze( - upb.MessageDef{ - fields = { - upb.FieldDef{name = "f1", number = 1, type = upb.TYPE_MESSAGE, - subdef = m1} - } - } - ) - end) -end - -function test_symtab() - local empty = upb.SymbolTable() - assert_equal(0, #empty:getdefs(upb.DEF_ANY)) - - local symtab = upb.SymbolTable{ - upb.MessageDef{full_name = "TestMessage"}, - upb.MessageDef{full_name = "ContainingMessage", fields = { - upb.FieldDef{name = "field1", number = 1, type = upb.TYPE_INT32}, - upb.FieldDef{name = "field2", number = 2, type = upb.TYPE_MESSAGE, - subdef_name = ".TestMessage"} - } - } - } - - local msgdef1 = symtab:lookup("TestMessage") - local msgdef2 = symtab:lookup("ContainingMessage") - assert_not_nil(msgdef1) - assert_not_nil(msgdef2) - assert_equal(msgdef1, msgdef2:field("field2"):subdef()) - assert_true(msgdef1:is_frozen()) - assert_true(msgdef2:is_frozen()) - - symtab:add{ - upb.MessageDef{full_name = "ContainingMessage2", fields = { - upb.FieldDef{name = "field5", number = 5, type = upb.TYPE_MESSAGE, - subdef = msgdef2} - } - } - } - - local msgdef3 = symtab:lookup("ContainingMessage2") - assert_not_nil(msgdef3) - assert_equal(msgdef3:field("field5"):subdef(), msgdef2) -end - -function test_symtab_add_extension() - -- Adding an extension at the same time as the extendee. - local symtab = upb.SymbolTable{ - upb.MessageDef{full_name = "M1"}, - upb.FieldDef{name = "extension1", is_extension = true, number = 1, - type = upb.TYPE_INT32, containing_type_name = "M1"} - } - - local m1 = symtab:lookup("M1") - assert_not_nil(m1) - assert_equal(1, #m1) - - local f1 = m1:field("extension1") - assert_not_nil(f1) - assert_true(f1:is_extension()) - assert_true(f1:is_frozen()) - assert_equal(1, f1:number()) - - -- Adding an extension to an existing extendee. - symtab:add{ - upb.FieldDef{name = "extension2", is_extension = true, number = 2, - type = upb.TYPE_INT32, containing_type_name = "M1"} - } - - local m1_2 = symtab:lookup("M1") - assert_not_nil(m1_2) - assert_true(m1 ~= m1_2) - assert_equal(2, #m1_2) - - local f2 = m1_2:field("extension2") - assert_not_nil(f2) - assert_true(f2:is_extension()) - assert_true(f2:is_frozen()) - assert_equal(2, f2:number()) -end - --- Lua 5.1 and 5.2 have slightly different semantics for how a finalizer --- can be defined in Lua. -if _VERSION >= 'Lua 5.2' then - function defer(fn) - setmetatable({}, { __gc = fn }) - end -else - function defer(fn) - getmetatable(newproxy(true)).__gc = fn - end -end - -function test_finalizer() - -- Tests that we correctly handle a call into an already-finalized object. - -- Collectible objects are finalized in the opposite order of creation. - do - local t = {} - defer(function() - assert_error_match("called into dead def", function() - -- Generic def call. - t[1]:full_name() - end) - assert_error_match("called into dead msgdef", function() - -- Specific msgdef call. - t[1]:add() - end) - assert_error_match("called into dead enumdef", function() - t[2]:values() - end) - assert_error_match("called into dead fielddef", function() - t[3]:number() - end) - assert_error_match("called into dead symtab", - function() t[4]:lookup() - end) - end) - t = { - upb.MessageDef(), - upb.EnumDef(), - upb.FieldDef(), - upb.SymbolTable(), - } - end - collectgarbage() -end - -local stats = lunit.main() - -if stats.failed > 0 or stats.errors > 0 then - error("One or more errors in test suite") -end diff --git a/tests/bindings/lua/upb.lua b/tests/bindings/lua/upb.lua new file mode 100644 index 0000000..f32a690 --- /dev/null +++ b/tests/bindings/lua/upb.lua @@ -0,0 +1,757 @@ + +local upb = require "upb" +local lunit = require "lunit" + +if _VERSION >= 'Lua 5.2' then + _ENV = lunit.module("testupb", "seeall") +else + module("testupb", lunit.testcase, package.seeall) +end + +function iter_to_array(iter) + local arr = {} + for v in iter do + arr[#arr + 1] = v + end + return arr +end + +function test_fielddef() + local f = upb.FieldDef() + assert_false(f:is_frozen()) + assert_nil(f:number()) + assert_nil(f:name()) + assert_nil(f:type()) + assert_equal(upb.LABEL_OPTIONAL, f:label()) + + f:set_name("foo_field") + f:set_number(3) + f:set_label(upb.LABEL_REPEATED) + f:set_type(upb.TYPE_FLOAT) + + assert_equal("foo_field", f:name()) + assert_equal(3, f:number()) + assert_equal(upb.LABEL_REPEATED, f:label()) + assert_equal(upb.TYPE_FLOAT, f:type()) + + local f2 = upb.FieldDef{ + name = "foo", number = 5, type = upb.TYPE_DOUBLE, label = upb.LABEL_REQUIRED + } + + assert_equal("foo", f2:name()) + assert_equal(5, f2:number()) + assert_equal(upb.TYPE_DOUBLE, f2:type()) + assert_equal(upb.LABEL_REQUIRED, f2:label()) +end + +function test_enumdef() + local e = upb.EnumDef() + assert_equal(0, #e) + assert_nil(e:value(5)) + assert_nil(e:value("NONEXISTENT_NAME")) + + for name, value in e:values() do + fail() + end + + e:add("VAL1", 1) + e:add("VAL2", 2) + + local values = {} + for name, value in e:values() do + values[name] = value + end + + assert_equal(1, values["VAL1"]) + assert_equal(2, values["VAL2"]) + + local e2 = upb.EnumDef{ + values = { + {"FOO", 1}, + {"BAR", 77}, + } + } + + assert_equal(1, e2:value("FOO")) + assert_equal(77, e2:value("BAR")) + assert_equal("FOO", e2:value(1)) + assert_equal("BAR", e2:value(77)) + + e2:freeze() + + local f = upb.FieldDef{type = upb.TYPE_ENUM} + + -- No default set and no EnumDef to get a default from. + assert_equal(f:default(), nil) + + f:set_subdef(upb.EnumDef()) + -- No default to pull in from the EnumDef. + assert_equal(f:default(), nil) + + f:set_subdef(e2) + -- First member added to e2. + assert_equal(f:default(), "FOO") + + f:set_subdef(nil) + assert_equal(f:default(), nil) + + f:set_default(1) + assert_equal(f:default(), 1) + + f:set_default("YOYOYO") + assert_equal(f:default(), "YOYOYO") + + f:set_subdef(e2) + f:set_default(1) + -- It prefers to return a string, and could resolve the explicit "1" we set + -- it to to the string value. + assert_equal(f:default(), "FOO") + + -- FieldDef can specify default value by name or number, but the value must + -- exist at freeze time. + local m1 = upb.build_defs{ + upb.MessageDef{ + full_name = "A", + fields = { + upb.FieldDef{ + name = "f1", + number = 1, + type = upb.TYPE_ENUM, + subdef = e2, + default = "BAR" + }, + upb.FieldDef{ + name = "f2", + number = 2, + type = upb.TYPE_ENUM, + subdef = e2, + default = 77 + } + } + } + } + + assert_equal(m1:field("f1"):default(), "BAR") + assert_equal(m1:field("f1"):default(), "BAR") + + assert_error_match( + "enum default for field A.f1 .DOESNT_EXIST. is not in the enum", + function() + local m1 = upb.build_defs{ + upb.MessageDef{ + full_name = "A", + fields = { + upb.FieldDef{ + name = "f1", + number = 1, + type = upb.TYPE_ENUM, + subdef = e2, + default = "DOESNT_EXIST" + } + } + } + } + end + ) + + assert_error_match( + "enum default for field A.f1 .142. is not in the enum", + function() + local m1 = upb.build_defs{ + upb.MessageDef{ + full_name = "A", + fields = { + upb.FieldDef{ + name = "f1", + number = 1, + type = upb.TYPE_ENUM, + subdef = e2, + default = 142 + } + } + } + } + end + ) +end + +function test_empty_msgdef() + local md = upb.MessageDef() + assert_nil(md:full_name()) -- Def without name is anonymous. + assert_false(md:is_frozen()) + assert_equal(0, #md) + assert_nil(md:field("nonexistent_field")) + assert_nil(md:field(3)) + for field in md:fields() do + fail() + end + + upb.freeze(md) + assert_true(md:is_frozen()) + assert_equal(0, #md) + assert_nil(md:field("nonexistent_field")) + assert_nil(md:field(3)) + for field in md:fields() do + fail() + end +end + +function test_msgdef_constructor() + local f1 = upb.FieldDef{name = "field1", number = 7, type = upb.TYPE_INT32} + local f2 = upb.FieldDef{name = "field2", number = 8, type = upb.TYPE_INT32} + local md = upb.MessageDef{ + full_name = "TestMessage", + fields = {f1, f2} + } + assert_equal("TestMessage", md:full_name()) + assert_false(md:is_frozen()) + assert_equal(2, #md) + assert_equal(f1, md:field("field1")) + assert_equal(f2, md:field("field2")) + assert_equal(f1, md:field(7)) + assert_equal(f2, md:field(8)) + local count = 0 + local found = {} + for field in md:fields() do + count = count + 1 + found[field] = true + end + assert_equal(2, count) + assert_true(found[f1]) + assert_true(found[f2]) + + upb.freeze(md) +end + +function test_iteration() + -- Test that we cannot crash the process even if we modify the set of fields + -- during iteration. + local md = upb.MessageDef{full_name = "TestMessage"} + + for i=1,10 do + md:add(upb.FieldDef{ + name = "field" .. tostring(i), + number = 1000 - i, + type = upb.TYPE_INT32 + }) + end + + local add = #md + for f in md:fields() do + if add > 0 then + add = add - 1 + for i=10000,11000 do + local field_name = "field" .. tostring(i) + -- We want to add fields to the table to trigger a table resize, + -- but we must skip it if the field name or number already exists + -- otherwise it will raise an error. + if md:field(field_name) == nil and + md:field(i) == nil then + md:add(upb.FieldDef{ + name = field_name, + number = i, + type = upb.TYPE_INT32 + }) + end + end + end + end + + -- Test that iterators don't crash the process even if the MessageDef goes + -- out of scope. + -- + -- Note: have previously verified that this can indeed crash the process if + -- we do not explicitly add a reference from the iterator to the underlying + -- MessageDef. + local iter = md:fields() + md = nil + collectgarbage() + while iter() do + end + + local ed = upb.EnumDef{ + values = { + {"FOO", 1}, + {"BAR", 77}, + } + } + iter = ed:values() + ed = nil + collectgarbage() + while iter() do + end +end + +function test_msgdef_setters() + local md = upb.MessageDef() + md:set_full_name("Message1") + assert_equal("Message1", md:full_name()) + local f = upb.FieldDef{name = "field1", number = 3, type = upb.TYPE_DOUBLE} + md:add(f) + assert_equal(1, #md) + assert_equal(f, md:field("field1")) +end + +function test_msgdef_errors() + assert_error(function() upb.MessageDef{bad_initializer_key = 5} end) + local md = upb.MessageDef() + assert_error(function() + -- Duplicate field number. + upb.MessageDef{ + fields = { + upb.FieldDef{name = "field1", number = 1, type = upb.TYPE_INT32}, + upb.FieldDef{name = "field2", number = 1, type = upb.TYPE_INT32} + } + } + end) + assert_error(function() + -- Duplicate field name. + upb.MessageDef{ + fields = { + upb.FieldDef{name = "field1", number = 1, type = upb.TYPE_INT32}, + upb.FieldDef{name = "field1", number = 2, type = upb.TYPE_INT32} + } + } + end) + + -- attempt to set a name with embedded NULLs. + assert_error_match("names cannot have embedded NULLs", function() + md:set_full_name("abc\0def") + end) + + upb.freeze(md) + -- Attempt to mutate frozen MessageDef. + assert_error_match("frozen", function() + md:add(upb.FieldDef{name = "field1", number = 1, type = upb.TYPE_INT32}) + end) + assert_error_match("frozen", function() + md:set_full_name("abc") + end) + + -- Attempt to freeze a msgdef without freezing its subdef. + assert_error_match("is not frozen or being frozen", function() + m1 = upb.MessageDef() + upb.freeze( + upb.MessageDef{ + fields = { + upb.FieldDef{name = "f1", number = 1, type = upb.TYPE_MESSAGE, + subdef = m1} + } + } + ) + end) +end + +function test_symtab() + local empty = upb.SymbolTable() + assert_equal(0, #iter_to_array(empty:defs(upb.DEF_ANY))) + assert_equal(0, #iter_to_array(empty:defs(upb.DEF_MSG))) + assert_equal(0, #iter_to_array(empty:defs(upb.DEF_ENUM))) + + local symtab = upb.SymbolTable{ + upb.MessageDef{full_name = "TestMessage"}, + upb.MessageDef{full_name = "ContainingMessage", fields = { + upb.FieldDef{name = "field1", number = 1, type = upb.TYPE_INT32}, + upb.FieldDef{name = "field2", number = 2, type = upb.TYPE_MESSAGE, + subdef_name = ".TestMessage"} + } + } + } + + local msgdef1 = symtab:lookup("TestMessage") + local msgdef2 = symtab:lookup("ContainingMessage") + assert_not_nil(msgdef1) + assert_not_nil(msgdef2) + assert_equal(msgdef1, msgdef2:field("field2"):subdef()) + assert_true(msgdef1:is_frozen()) + assert_true(msgdef2:is_frozen()) + + symtab:add{ + upb.MessageDef{full_name = "ContainingMessage2", fields = { + upb.FieldDef{name = "field5", number = 5, type = upb.TYPE_MESSAGE, + subdef = msgdef2} + } + } + } + + local msgdef3 = symtab:lookup("ContainingMessage2") + assert_not_nil(msgdef3) + assert_equal(msgdef3:field("field5"):subdef(), msgdef2) + + -- Freeze the symtab and verify that mutating operations are not allowed. + assert_false(symtab:is_frozen()) + symtab:freeze() + assert_true(symtab:is_frozen()) + assert_error_match("frozen", function() symtab:freeze() end) + assert_error_match("frozen", function() + symtab:add{ + upb.MessageDef{full_name = "Foo"} + } + end) +end + +function test_symtab_add_extension() + -- Adding an extension at the same time as the extendee. + local symtab = upb.SymbolTable{ + upb.MessageDef{full_name = "M1"}, + upb.FieldDef{name = "extension1", is_extension = true, number = 1, + type = upb.TYPE_INT32, containing_type_name = "M1"} + } + + local m1 = symtab:lookup("M1") + assert_not_nil(m1) + assert_equal(1, #m1) + + local f1 = m1:field("extension1") + assert_not_nil(f1) + assert_true(f1:is_extension()) + assert_true(f1:is_frozen()) + assert_equal(1, f1:number()) + + -- Adding an extension to an existing extendee. + symtab:add{ + upb.FieldDef{name = "extension2", is_extension = true, number = 2, + type = upb.TYPE_INT32, containing_type_name = "M1"} + } + + local m1_2 = symtab:lookup("M1") + assert_not_nil(m1_2) + assert_true(m1 ~= m1_2) + assert_equal(2, #m1_2) + + local f2 = m1_2:field("extension2") + assert_not_nil(f2) + assert_true(f2:is_extension()) + assert_true(f2:is_frozen()) + assert_equal(2, f2:number()) +end + +function test_numeric_array() + local function test_for_numeric_type(upb_type, val, too_big, too_small, bad3) + local array = upb.Array(upb_type) + assert_equal(0, #array) + + -- 0 is never a valid index in Lua. + assert_error_match("array index", function() return array[0] end) + -- Past the end of the array. + assert_error_match("array index", function() return array[1] end) + + array[1] = val + assert_equal(val, array[1]) + assert_equal(1, #array) + -- Past the end of the array. + assert_error_match("array index", function() return array[2] end) + + array[2] = 10 + assert_equal(val, array[1]) + assert_equal(10, array[2]) + assert_equal(2, #array) + -- Past the end of the array. + assert_error_match("array index", function() return array[3] end) + + local n = 1 + for i, val in upb.ipairs(array) do + assert_equal(n, i) + n = n + 1 + assert_equal(array[i], val) + end + + -- Values that are out of range. + local errmsg = "not an integer or out of range" + if too_small then + assert_error_match(errmsg, function() array[3] = too_small end) + end + if too_big then + assert_error_match(errmsg, function() array[3] = too_big end) + end + if bad3 then + assert_error_match(errmsg, function() array[3] = bad3 end) + end + + -- Can't assign other Lua types. + errmsg = "bad argument #3" + assert_error_match(errmsg, function() array[3] = "abc" end) + assert_error_match(errmsg, function() array[3] = true end) + assert_error_match(errmsg, function() array[3] = false end) + assert_error_match(errmsg, function() array[3] = nil end) + assert_error_match(errmsg, function() array[3] = {} end) + assert_error_match(errmsg, function() array[3] = print end) + assert_error_match(errmsg, function() array[3] = array end) + end + + -- in-range of 64-bit types but not exactly representable as double + local bad64 = 2^68 - 1 + + test_for_numeric_type(upb.TYPE_UINT32, 2^32 - 1, 2^32, -1, 5.1) + test_for_numeric_type(upb.TYPE_UINT64, 2^63, 2^64, -1, bad64) + test_for_numeric_type(upb.TYPE_INT32, 2^31 - 1, 2^31, -2^31 - 1, 5.1) + -- Enums don't exist at a language level in Lua, so we just represent enum + -- values as int32s. + test_for_numeric_type(upb.TYPE_ENUM, 2^31 - 1, 2^31, -2^31 - 1, 5.1) + test_for_numeric_type(upb.TYPE_INT64, 2^62, 2^63, -2^64, bad64) + test_for_numeric_type(upb.TYPE_FLOAT, 10^38) + test_for_numeric_type(upb.TYPE_DOUBLE, 10^101) +end + +function test_string_array() + local function test_for_string_type(upb_type) + local array = upb.Array(upb_type) + assert_equal(0, #array) + + -- 0 is never a valid index in Lua. + assert_error_match("array index", function() return array[0] end) + -- Past the end of the array. + assert_error_match("array index", function() return array[1] end) + + array[1] = "foo" + assert_equal("foo", array[1]) + assert_equal(1, #array) + -- Past the end of the array. + assert_error_match("array index", function() return array[2] end) + + local array2 = upb.Array(upb_type) + assert_equal(0, #array2) + + array[2] = "bar" + assert_equal("foo", array[1]) + assert_equal("bar", array[2]) + assert_equal(2, #array) + -- Past the end of the array. + assert_error_match("array index", function() return array[3] end) + + local n = 1 + for i, val in upb.ipairs(array) do + assert_equal(n, i) + n = n + 1 + assert_equal(array[i], val) + end + assert_equal(3, n) + + -- Can't assign other Lua types. + assert_error_match("Expected string", function() array[3] = 123 end) + assert_error_match("Expected string", function() array[3] = true end) + assert_error_match("Expected string", function() array[3] = false end) + assert_error_match("Expected string", function() array[3] = nil end) + assert_error_match("Expected string", function() array[3] = {} end) + assert_error_match("Expected string", function() array[3] = print end) + assert_error_match("Expected string", function() array[3] = array end) + end + + test_for_string_type(upb.TYPE_STRING) + test_for_string_type(upb.TYPE_BYTES) +end + +function test_msg_primitives() + local function test_for_numeric_type(upb_type, val, too_big, too_small, bad3) + + msg = upb.Message( + upb.build_defs{ + upb.MessageDef{full_name = "TestMessage", fields = { + upb.FieldDef{name = "f", number = 1, type = upb_type}, + } + } + } + ) + + -- Defaults to nil + assert_nil(msg.f) + + msg.f = 0 + assert_equal(0, msg.f) + + msg.f = val + assert_equal(val, msg.f) + + local errmsg = "not an integer or out of range" + if too_small then + assert_error_match(errmsg, function() msg.f = too_small end) + end + if too_big then + assert_error_match(errmsg, function() msg.f = too_big end) + end + if bad3 then + assert_error_match(errmsg, function() msg.f = bad3 end) + end + + -- Can't assign other Lua types. + errmsg = "bad argument #3" + assert_error_match(errmsg, function() msg.f = "abc" end) + assert_error_match(errmsg, function() msg.f = true end) + assert_error_match(errmsg, function() msg.f = false end) + assert_error_match(errmsg, function() msg.f = nil end) + assert_error_match(errmsg, function() msg.f = {} end) + assert_error_match(errmsg, function() msg.f = print end) + assert_error_match(errmsg, function() msg.f = array end) + end + + local msgdef = upb.build_defs{ + upb.MessageDef{full_name = "TestMessage", fields = { + upb.FieldDef{name = "i32", number = 1, type = upb.TYPE_INT32}, + upb.FieldDef{name = "u32", number = 2, type = upb.TYPE_UINT32}, + upb.FieldDef{name = "i64", number = 3, type = upb.TYPE_INT64}, + upb.FieldDef{name = "u64", number = 4, type = upb.TYPE_UINT64}, + upb.FieldDef{name = "dbl", number = 5, type = upb.TYPE_DOUBLE}, + upb.FieldDef{name = "flt", number = 6, type = upb.TYPE_FLOAT}, + upb.FieldDef{name = "bool", number = 7, type = upb.TYPE_BOOL}, + } + } + } + + msg = upb.Message(msgdef) + + -- Unset member returns nil. This is unlike C++/Java, but is more + -- Lua-like behavior. + assert_equal(nil, msg.i32) + assert_equal(nil, msg.u32) + assert_equal(nil, msg.i64) + assert_equal(nil, msg.u64) + assert_equal(nil, msg.dbl) + assert_equal(nil, msg.flt) + assert_equal(nil, msg.bool) + + -- Attempts to access non-existent fields fail. + assert_error_match("no such field", function() msg.no_such = 1 end) + + msg.i32 = 10 + msg.u32 = 20 + msg.i64 = 30 + msg.u64 = 40 + msg.dbl = 50 + msg.flt = 60 + msg.bool = true + + assert_equal(10, msg.i32) + assert_equal(20, msg.u32) + assert_equal(30, msg.i64) + assert_equal(40, msg.u64) + assert_equal(50, msg.dbl) + assert_equal(60, msg.flt) + assert_equal(true, msg.bool) + + test_for_numeric_type(upb.TYPE_UINT32, 2^32 - 1, 2^32, -1, 5.1) + test_for_numeric_type(upb.TYPE_UINT64, 2^62, 2^64, -1, bad64) + test_for_numeric_type(upb.TYPE_INT32, 2^31 - 1, 2^31, -2^31 - 1, 5.1) + test_for_numeric_type(upb.TYPE_INT64, 2^61, 2^63, -2^64, bad64) + test_for_numeric_type(upb.TYPE_FLOAT, 2^20) + test_for_numeric_type(upb.TYPE_DOUBLE, 10^101) +end + +function test_msg_array() + local msgdef = upb.build_defs{ + upb.MessageDef{full_name = "TestMessage", fields = { + upb.FieldDef{name = "i32_array", number = 1, type = upb.TYPE_INT32, + label = upb.LABEL_REPEATED}, + } + } + } + + msg = upb.Message(msgdef) + + assert_nil(msg.i32_array) + + -- Can't assign a scalar; array is expected. + assert_error_match("lupb.array expected", function() msg.i32_array = 5 end) + + -- Can't assign array of the wrong type. + local function assign_int64() + msg.i32_array = upb.Array(upb.TYPE_INT64) + end + assert_error_match("Array type mismatch", assign_int64) + + local arr = upb.Array(upb.TYPE_INT32) + msg.i32_array = arr + assert_equal(arr, msg.i32_array) + + -- Can't assign other Lua types. + assert_error_match("array expected", function() msg.i32_array = "abc" end) + assert_error_match("array expected", function() msg.i32_array = true end) + assert_error_match("array expected", function() msg.i32_array = false end) + assert_error_match("array expected", function() msg.i32_array = nil end) + assert_error_match("array expected", function() msg.i32_array = {} end) + assert_error_match("array expected", function() msg.i32_array = print end) +end + +function test_msg_submsg() + local test_msgdef, submsg_msgdef = upb.build_defs{ + upb.MessageDef{full_name = "TestMessage", fields = { + upb.FieldDef{name = "submsg", number = 1, type = upb.TYPE_MESSAGE, + subdef_name = ".SubMessage"}, + } + }, + upb.MessageDef{full_name = "SubMessage"} + } + + msg = upb.Message(test_msgdef) + + assert_nil(msg.submsg) + + -- Can't assign message of the wrong type. + local function assign_int64() + msg.submsg = upb.Message(test_msgdef) + end + assert_error_match("Message type mismatch", assign_int64) + + local sub = upb.Message(submsg_msgdef) + msg.submsg = sub + assert_equal(sub, msg.submsg) + + -- Can't assign other Lua types. + assert_error_match("msg expected", function() msg.submsg = "abc" end) + assert_error_match("msg expected", function() msg.submsg = true end) + assert_error_match("msg expected", function() msg.submsg = false end) + assert_error_match("msg expected", function() msg.submsg = nil end) + assert_error_match("msg expected", function() msg.submsg = {} end) + assert_error_match("msg expected", function() msg.submsg = print end) +end + +-- Lua 5.1 and 5.2 have slightly different semantics for how a finalizer +-- can be defined in Lua. +if _VERSION >= 'Lua 5.2' then + function defer(fn) + setmetatable({}, { __gc = fn }) + end +else + function defer(fn) + getmetatable(newproxy(true)).__gc = fn + end +end + +function test_finalizer() + -- Tests that we correctly handle a call into an already-finalized object. + -- Collectible objects are finalized in the opposite order of creation. + do + local t = {} + defer(function() + assert_error_match("called into dead object", function() + -- Generic def call. + t[1]:full_name() + end) + assert_error_match("called into dead object", function() + -- Specific msgdef call. + t[1]:add() + end) + assert_error_match("called into dead object", function() + t[2]:values() + end) + assert_error_match("called into dead object", function() + t[3]:number() + end) + assert_error_match("called into dead object", + function() t[4]:lookup() + end) + end) + t = { + upb.MessageDef(), + upb.EnumDef(), + upb.FieldDef(), + upb.SymbolTable(), + } + end + collectgarbage() +end + +local stats = lunit.main() + +if stats.failed > 0 or stats.errors > 0 then + error("One or more errors in test suite") +end diff --git a/tests/bindings/lua/upb.pb.lua b/tests/bindings/lua/upb.pb.lua new file mode 100644 index 0000000..02b443a --- /dev/null +++ b/tests/bindings/lua/upb.pb.lua @@ -0,0 +1,70 @@ + +local upb = require "upb" +local pb = require "upb.pb" +local lunit = require "lunit" + +if _VERSION >= 'Lua 5.2' then + _ENV = lunit.module("testupb_pb", "seeall") +else + module("testupb_pb", lunit.testcase, package.seeall) +end + +local primitive_types_msg = upb.build_defs{ + upb.MessageDef{full_name = "TestMessage", fields = { + upb.FieldDef{name = "i32", number = 1, type = upb.TYPE_INT32}, + upb.FieldDef{name = "u32", number = 2, type = upb.TYPE_UINT32}, + upb.FieldDef{name = "i64", number = 3, type = upb.TYPE_INT64}, + upb.FieldDef{name = "u64", number = 4, type = upb.TYPE_UINT64}, + upb.FieldDef{name = "dbl", number = 5, type = upb.TYPE_DOUBLE}, + upb.FieldDef{name = "flt", number = 6, type = upb.TYPE_FLOAT}, + upb.FieldDef{name = "bool", number = 7, type = upb.TYPE_BOOL}, + } + } +} + +function test_decodermethod() + local dm = pb.DecoderMethod(primitive_types_msg) + + assert_error( + function() + -- Needs at least one argument to construct. + pb.DecoderMethod() + end) +end + +function test_parse_primitive() + local binary_pb = + "\008\128\128\128\128\002\016\128\128\128\128\004\024\128\128" + .. "\128\128\128\128\128\002\032\128\128\128\128\128\128\128\001\041\000" + .. "\000\000\000\000\000\248\063\053\000\000\096\064\056\001" + local dm = pb.DecoderMethod(primitive_types_msg) + msg = dm:parse(binary_pb) + assert_equal(536870912, msg.i32) + assert_equal(1073741824, msg.u32) + assert_equal(1125899906842624, msg.i64) + assert_equal(562949953421312, msg.u64) + assert_equal(1.5, msg.dbl) + assert_equal(3.5, msg.flt) + assert_equal(true, msg.bool) +end + +function test_parse_string() + local msgdef = upb.build_defs{ + upb.MessageDef{full_name = "TestMessage", fields = { + upb.FieldDef{name = "str", number = 1, type = upb.TYPE_STRING}, + } + } + } + + local binary_pb = "\010\005Hello" + local dm = pb.DecoderMethod(msgdef) + msg = dm:parse(binary_pb) + assert_equal("Hello", msg.str) +end + + +local stats = lunit.main() + +if stats.failed > 0 or stats.errors > 0 then + error("One or more errors in test suite") +end diff --git a/tests/pb/test_decoder.cc b/tests/pb/test_decoder.cc index 1660436..e016632 100644 --- a/tests/pb/test_decoder.cc +++ b/tests/pb/test_decoder.cc @@ -297,7 +297,7 @@ template void doreg(upb_handlers *h, uint32_t num) { const upb_fielddef *f = upb_msgdef_itof(upb_handlers_msgdef(h), num); ASSERT(f); - ASSERT(h->SetValueHandler(f, UpbBindT(&F, new uint32_t(num)))); + ASSERT(h->SetValueHandler(f, UpbBindT(F, new uint32_t(num)))); if (f->IsSequence()) { ASSERT(h->SetStartSequenceHandler(f, UpbBind(startseq, new uint32_t(num)))); ASSERT(h->SetEndSequenceHandler(f, UpbBind(endseq, new uint32_t(num)))); @@ -488,8 +488,22 @@ uint32_t Hash(const string& proto, const string* expected_output, size_t seam1, return hash; } -bool parse(upb::BytesSink* s, void* subc, const char* buf, size_t start, - size_t end, size_t* ofs, upb::Status* status) { +void CheckBytesParsed(const upb::pb::Decoder& decoder, size_t ofs) { + // We could have parsed as many as 10 bytes fewer than what the decoder + // previously accepted, since we can buffer up to 10 partial bytes internally + // before accumulating an entire value. + const int MAX_BUFFERED = 10; + + // We can't have parsed more data than the decoder callback is telling us it + // parsed. + ASSERT(decoder.BytesParsed() <= ofs); + ASSERT(ofs <= (decoder.BytesParsed() + MAX_BUFFERED)); +} + +bool parse(upb::pb::Decoder* decoder, void* subc, const char* buf, + size_t start, size_t end, size_t* ofs, upb::Status* status) { + CheckBytesParsed(*decoder, *ofs); + upb::BytesSink* s = decoder->input(); start = UPB_MAX(start, *ofs); if (start <= end) { size_t len = end - start; @@ -532,6 +546,7 @@ bool parse(upb::BytesSink* s, void* subc, const char* buf, size_t start, if (!status->ok()) return false; *ofs += parsed; + CheckBytesParsed(*decoder, *ofs); } return true; } @@ -569,12 +584,12 @@ void run_decoder(const string& proto, const string* expected_output) { fprintf(stderr, "Calling start()\n"); } - bool ok = - input->Start(proto.size(), &sub) && - parse(input, sub, proto.c_str(), 0, i, &ofs, &status) && - parse(input, sub, proto.c_str(), i, j, &ofs, &status) && - parse(input, sub, proto.c_str(), j, proto.size(), &ofs, &status) && - ofs == proto.size(); + 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, + &status) && + ofs == proto.size(); if (ok) { if (filter_hash) { @@ -940,6 +955,22 @@ void test_valid() { LINE("%u:1") LINE(">"), UPB_DESCRIPTOR_TYPE_INT32); + // String inside submsg. + uint32_t msg_fn = UPB_DESCRIPTOR_TYPE_MESSAGE; + assert_successful_parse( + submsg(msg_fn, + cat ( tag(UPB_DESCRIPTOR_TYPE_STRING, UPB_WIRE_TYPE_DELIMITED), + delim(string("abcde")) + ) + ), + LINE("<") + LINE("%u:{") + LINE(" <") + LINE(" %u:(5)\"abcde\"") + LINE(" >") + LINE("}") + LINE(">"), msg_fn, UPB_DESCRIPTOR_TYPE_STRING); + // Test implicit startseq/endseq. uint32_t repfl_fn = rep_fn(UPB_DESCRIPTOR_TYPE_FLOAT); uint32_t repdb_fn = rep_fn(UPB_DESCRIPTOR_TYPE_DOUBLE); @@ -956,7 +987,6 @@ void test_valid() { LINE(">"), repfl_fn, repfl_fn, repdb_fn, repdb_fn); // Submessage tests. - uint32_t msg_fn = UPB_DESCRIPTOR_TYPE_MESSAGE; assert_successful_parse( submsg(msg_fn, submsg(msg_fn, submsg(msg_fn, string()))), LINE("<") diff --git a/tests/test_cpp.cc b/tests/test_cpp.cc index 60d6527..fe0695f 100644 --- a/tests/test_cpp.cc +++ b/tests/test_cpp.cc @@ -153,6 +153,9 @@ static void TestSymbolTable(const char *descriptor_file) { std::cerr << "Couldn't load descriptor: " << status.error_message(); exit(1); } + ASSERT(!s->IsFrozen()); + s->Freeze(); + ASSERT(s->IsFrozen()); upb::reffed_ptr md(s->LookupMessage("C")); ASSERT(md.get()); @@ -1038,6 +1041,39 @@ void TestMismatchedTypes() { // match top-level closure of sub-handlers. } +class IntIncrementer { + public: + IntIncrementer(int* x) : x_(x) { (*x_)++; } + ~IntIncrementer() { (*x_)--; } + + static void Handler(void* closure, const IntIncrementer* incrementer, + int32_t x) {} + + private: + int* x_; +}; + + +void TestHandlerDataDestruction() { + upb::reffed_ptr md(upb::MessageDef::New()); + upb::reffed_ptr f(upb::FieldDef::New()); + f->set_type(UPB_TYPE_INT32); + ASSERT(f->set_name("test", NULL)); + ASSERT(f->set_number(1, NULL)); + ASSERT(md->AddField(f, NULL)); + ASSERT(md->Freeze(NULL)); + + int x = 0; + { + upb::reffed_ptr h(upb::Handlers::New(md.get())); + h->SetInt32Handler( + f.get(), UpbBind(&IntIncrementer::Handler, new IntIncrementer(&x))); + ASSERT(x == 1); + } + + ASSERT(x == 0); +} + extern "C" { int run_tests(int argc, char *argv[]) { @@ -1091,6 +1127,8 @@ int run_tests(int argc, char *argv[]) { TestMismatchedTypes(); + TestHandlerDataDestruction(); + #ifdef UPB_CXX11 #define ASSERT_STD_LAYOUT(type) \ static_assert(std::is_standard_layout::value, \ diff --git a/tests/test_def.c b/tests/test_def.c index bf45a73..7efd2b0 100644 --- a/tests/test_def.c +++ b/tests/test_def.c @@ -17,10 +17,11 @@ 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, UPB_DEF_ANY, NULL, &count); - ASSERT(count == 0); - free(defs); + upb_symtab_iter i; + for (upb_symtab_begin(&i, s, UPB_DEF_ANY); !upb_symtab_done(&i); + upb_symtab_next(&i)) { + ASSERT(false); // Should not get here. + } upb_symtab_unref(s, &s); } @@ -33,6 +34,9 @@ static upb_symtab *load_test_proto(void *owner) { upb_status_errmsg(&status)); ASSERT(false); } + ASSERT(!upb_symtab_isfrozen(s)); + upb_symtab_freeze(s); + ASSERT(upb_symtab_isfrozen(s)); return s; } @@ -41,7 +45,8 @@ static void test_cycles() { // 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); + const upb_def *def = upb_symtab_lookup(s, "A"); + upb_def_ref(def, &def); ASSERT(def); ASSERT(upb_def_isfrozen(def)); upb_symtab_unref(s, &s); @@ -65,14 +70,12 @@ static void test_cycles() { static void test_fielddef_unref() { upb_symtab *s = load_test_proto(&s); - const upb_msgdef *md = upb_symtab_lookupmsg(s, "A", &md); + const upb_msgdef *md = upb_symtab_lookupmsg(s, "A"); 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 - // alive. + // Unref symtab; now fielddef is the only thing keeping the msgdef alive. upb_symtab_unref(s, &s); - upb_msgdef_unref(md, &md); // Check that md is still alive. ASSERT(strcmp(upb_msgdef_fullname(md), "A") == 0); @@ -141,29 +144,28 @@ static void test_replacement() { &s, NULL); upb_msgdef *m2 = upb_msgdef_newnamed("MyMessage2", &s); upb_enumdef *e = upb_enumdef_newnamed("MyEnum", &s); + upb_status status = UPB_STATUS_INIT; + ASSERT_STATUS(upb_enumdef_addval(e, "VAL1", 1, &status), &status); 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_enumdef_setfullname(e2, "MyEnum", NULL); + upb_enumdef *e2 = upb_enumdef_newnamed("MyEnum", &s); + ASSERT_STATUS(upb_enumdef_addval(e2, "VAL1", 1, &status), &status); 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); + const upb_msgdef *m3 = upb_symtab_lookupmsg(s, "MyMessage"); 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); + m3 = upb_symtab_lookupmsg(s, "MyMessage2"); // 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, &s); } diff --git a/tests/test_handlers.c b/tests/test_handlers.c index df22b8a..ad59465 100644 --- a/tests/test_handlers.c +++ b/tests/test_handlers.c @@ -18,7 +18,10 @@ static bool startmsg(void *c, const void *hd) { } static void test_error() { - upb_handlers *h = upb_handlers_new(GOOGLE_PROTOBUF_DESCRIPTORPROTO, &h); + const upb_symtab *s = upbdefs_google_protobuf_descriptor(&s); + upb_handlers *h = + upb_handlers_new(upbdefs_google_protobuf_DescriptorProto(s), &h); + upb_symtab_unref(s, &s); // Attempt to set the same handler twice causes error. ASSERT(upb_ok(upb_handlers_status(h))); diff --git a/tests/test_table.cc b/tests/test_table.cc index 747a97b..2d08abb 100644 --- a/tests/test_table.cc +++ b/tests/test_table.cc @@ -69,6 +69,25 @@ void test_strtable(const vector& keys, uint32_t num_to_insert) { } ASSERT(all.empty()); + // Test iteration with resizes. + + for (int i = 0; i < 10; i++) { + for(upb_strtable_begin(&iter, &table); !upb_strtable_done(&iter); + upb_strtable_next(&iter)) { + // Even if we invalidate the iterator it should only return real elements. + const char *key = upb_strtable_iter_key(&iter); + std::string tmp(key, strlen(key)); + ASSERT(upb_value_getint32(upb_strtable_iter_value(&iter)) == m[tmp]); + + // Force a resize even though the size isn't changing. + // Also forces the table size to grow so some new buckets end up empty. + int new_lg2 = table.t.size_lg2 + 1; + // Don't use more than 64k tables, to avoid exhausting memory. + new_lg2 = UPB_MIN(new_lg2, 16); + upb_strtable_resize(&table, new_lg2); + } + } + upb_strtable_uninit(&table); } @@ -292,7 +311,9 @@ int run_tests(int argc, char *argv[]) { keys.push_back("google.protobuf.UninterpretedOption"); keys.push_back("google.protobuf.UninterpretedOption.NamePart"); - test_strtable(keys, 18); + for (int i = 0; i < 10; i++) { + test_strtable(keys, 18); + } int32_t *keys1 = get_contiguous_keys(8); test_inttable(keys1, 8, "Table size: 8, keys: 1-8 ===="); diff --git a/tests/test_vs_proto2.cc b/tests/test_vs_proto2.cc index dd20381..ed44a73 100644 --- a/tests/test_vs_proto2.cc +++ b/tests/test_vs_proto2.cc @@ -129,7 +129,8 @@ int run_tests(int argc, char *argv[]) MESSAGE_CIDENT msg1; MESSAGE_CIDENT msg2; - upb::reffed_ptr h(upb::googlepb::NewWriteHandlers(msg1)); + upb::reffed_ptr h( + upb::googlepb::WriteHandlers::New(msg1)); compare_metadata(msg1.GetDescriptor(), h->message_def()); @@ -146,7 +147,7 @@ int run_tests(int argc, char *argv[]) factory->GetPrototype(msg1.descriptor()); google::protobuf::Message* dyn_msg1 = prototype->New(); google::protobuf::Message* dyn_msg2 = prototype->New(); - h = upb::googlepb::NewWriteHandlers(*dyn_msg1); + h = upb::googlepb::WriteHandlers::New(*dyn_msg1); parse_and_compare(dyn_msg1, dyn_msg2, h.get(), str, len, false); parse_and_compare(dyn_msg1, dyn_msg2, h.get(), str, len, true); delete dyn_msg1; -- cgit v1.2.3