aboutsummaryrefslogtreecommitdiffhomepage
path: root/ruby/tests/basic.rb
diff options
context:
space:
mode:
Diffstat (limited to 'ruby/tests/basic.rb')
-rw-r--r--ruby/tests/basic.rb324
1 files changed, 279 insertions, 45 deletions
diff --git a/ruby/tests/basic.rb b/ruby/tests/basic.rb
index da85520f..ad34d53d 100644
--- a/ruby/tests/basic.rb
+++ b/ruby/tests/basic.rb
@@ -1,6 +1,7 @@
#!/usr/bin/ruby
require 'google/protobuf'
+require 'json'
require 'test/unit'
# ------------- generated code --------------
@@ -50,6 +51,17 @@ module BasicTest
optional :foo, :int32, 1
end
+ add_message "TestEmbeddedMessageParent" do
+ optional :child_msg, :message, 1, "TestEmbeddedMessageChild"
+ optional :number, :int32, 2
+
+ repeated :repeated_msg, :message, 3, "TestEmbeddedMessageChild"
+ repeated :repeated_number, :int32, 4
+ end
+ add_message "TestEmbeddedMessageChild" do
+ optional :sub_child, :message, 1, "TestMessage"
+ end
+
add_message "Recursive1" do
optional :foo, :message, 1, "Recursive2"
end
@@ -95,13 +107,25 @@ module BasicTest
optional :d, :enum, 4, "TestEnum"
end
end
+
+ add_message "repro.Outer" do
+ map :items, :int32, :message, 1, "repro.Inner"
+ end
+
+ add_message "repro.Inner" do
+ end
end
+
+ Outer = pool.lookup("repro.Outer").msgclass
+ Inner = pool.lookup("repro.Inner").msgclass
Foo = pool.lookup("Foo").msgclass
Bar = pool.lookup("Bar").msgclass
Baz = pool.lookup("Baz").msgclass
TestMessage = pool.lookup("TestMessage").msgclass
TestMessage2 = pool.lookup("TestMessage2").msgclass
+ TestEmbeddedMessageParent = pool.lookup("TestEmbeddedMessageParent").msgclass
+ TestEmbeddedMessageChild = pool.lookup("TestEmbeddedMessageChild").msgclass
Recursive1 = pool.lookup("Recursive1").msgclass
Recursive2 = pool.lookup("Recursive2").msgclass
TestEnum = pool.lookup("TestEnum").enummodule
@@ -150,12 +174,18 @@ module BasicTest
m.optional_double = 0.5
m.optional_string = "hello"
assert m.optional_string == "hello"
+ m.optional_string = :hello
+ assert m.optional_string == "hello"
m.optional_bytes = "world".encode!('ASCII-8BIT')
assert m.optional_bytes == "world"
m.optional_msg = TestMessage2.new(:foo => 42)
assert m.optional_msg == TestMessage2.new(:foo => 42)
m.optional_msg = nil
assert m.optional_msg == nil
+ m.optional_enum = :C
+ assert m.optional_enum == :C
+ m.optional_enum = 'C'
+ assert m.optional_enum == :C
end
def test_ctor_args
@@ -172,6 +202,34 @@ module BasicTest
assert m.repeated_string[2] == "world"
end
+ def test_ctor_string_symbol_args
+ m = TestMessage.new(:optional_enum => 'C', :repeated_enum => ['A', 'B'])
+ assert_equal :C, m.optional_enum
+ assert_equal [:A, :B], m.repeated_enum
+
+ m = TestMessage.new(:optional_string => :foo, :repeated_string => [:foo, :bar])
+ assert_equal 'foo', m.optional_string
+ assert_equal ['foo', 'bar'], m.repeated_string
+ end
+
+ def test_embeddedmsg_hash_init
+ m = TestEmbeddedMessageParent.new(:child_msg => {sub_child: {optional_int32: 1}},
+ :number => 2,
+ :repeated_msg => [{sub_child: {optional_int32: 3}}],
+ :repeated_number => [10, 20, 30])
+
+ assert_equal 2, m.number
+ assert_equal [10, 20, 30], m.repeated_number
+
+ assert_not_nil m.child_msg
+ assert_not_nil m.child_msg.sub_child
+ assert_equal m.child_msg.sub_child.optional_int32, 1
+
+ assert_not_nil m.repeated_msg
+ assert_equal 1, m.repeated_msg.length
+ assert_equal 3, m.repeated_msg.first.sub_child.optional_int32
+ end
+
def test_inspect
m = TestMessage.new(:optional_int32 => -42,
:optional_enum => :A,
@@ -183,12 +241,15 @@ module BasicTest
def test_hash
m1 = TestMessage.new(:optional_int32 => 42)
- m2 = TestMessage.new(:optional_int32 => 102)
+ m2 = TestMessage.new(:optional_int32 => 102, repeated_string: ['please', 'work', 'ok?'])
+ m3 = TestMessage.new(:optional_int32 => 102, repeated_string: ['please', 'work', 'ok?'])
assert m1.hash != 0
assert m2.hash != 0
+ assert m3.hash != 0
# relying on the randomness here -- if hash function changes and we are
# unlucky enough to get a collision, then change the values above.
assert m1.hash != m2.hash
+ assert_equal m2.hash, m3.hash
end
def test_unknown_field_errors
@@ -255,14 +316,17 @@ module BasicTest
m = TestMessage.new
# Assigning a normal (ASCII or UTF8) string to a bytes field, or
- # ASCII-8BIT to a string field, raises an error.
- assert_raise TypeError do
- m.optional_bytes = "Test string ASCII".encode!('ASCII')
- end
- assert_raise TypeError do
+ # ASCII-8BIT to a string field will convert to the proper encoding.
+ m.optional_bytes = "Test string ASCII".encode!('ASCII')
+ assert m.optional_bytes.frozen?
+ assert_equal Encoding::ASCII_8BIT, m.optional_bytes.encoding
+ assert_equal "Test string ASCII", m.optional_bytes
+
+ assert_raise Encoding::UndefinedConversionError do
m.optional_bytes = "Test string UTF-8 \u0100".encode!('UTF-8')
end
- assert_raise TypeError do
+
+ assert_raise Encoding::UndefinedConversionError do
m.optional_string = ["FFFF"].pack('H*')
end
@@ -270,11 +334,10 @@ module BasicTest
m.optional_bytes = ["FFFF"].pack('H*')
m.optional_string = "\u0100"
- # strings are mutable so we can do this, but serialize should catch it.
+ # strings are immutable so we can't do this, but serialize should catch it.
m.optional_string = "asdf".encode!('UTF-8')
- m.optional_string.encode!('ASCII-8BIT')
- assert_raise TypeError do
- data = TestMessage.encode(m)
+ assert_raise RuntimeError do
+ m.optional_string.encode!('ASCII-8BIT')
end
end
@@ -466,9 +529,9 @@ module BasicTest
assert m.length == 2
m2 = m.dup
- assert m == m2
+ assert_equal m, m2
assert m.hash != 0
- assert m.hash == m2.hash
+ assert_equal m.hash, m2.hash
collected = {}
m.each { |k,v| collected[v] = k }
@@ -558,7 +621,7 @@ module BasicTest
assert_raise TypeError do
m[1] = 1
end
- assert_raise TypeError do
+ assert_raise Encoding::UndefinedConversionError do
bytestring = ["FFFF"].pack("H*")
m[bytestring] = 1
end
@@ -566,9 +629,8 @@ module BasicTest
m = Google::Protobuf::Map.new(:bytes, :int32)
bytestring = ["FFFF"].pack("H*")
m[bytestring] = 1
- assert_raise TypeError do
- m["asdf"] = 1
- end
+ # Allowed -- we will automatically convert to ASCII-8BIT.
+ m["asdf"] = 1
assert_raise TypeError do
m[1] = 1
end
@@ -599,7 +661,7 @@ module BasicTest
assert_raise RangeError do
m["z"] = :Z
end
- assert_raise TypeError do
+ assert_raise RangeError do
m["z"] = "z"
end
end
@@ -663,6 +725,28 @@ module BasicTest
end
end
+ def test_map_corruption
+ # This pattern led to a crash in a previous version of upb/protobuf.
+ m = MapMessage.new(map_string_int32: { "aaa" => 1 })
+ m.map_string_int32['podid'] = 2
+ m.map_string_int32['aaa'] = 3
+ end
+
+ def test_concurrent_decoding
+ o = Outer.new
+ o.items[0] = Inner.new
+ raw = Outer.encode(o)
+
+ thds = 2.times.map do
+ Thread.new do
+ 100000.times do
+ assert_equal o, Outer.decode(raw)
+ end
+ end
+ end
+ thds.map(&:join)
+ end
+
def test_map_encode_decode
m = MapMessage.new(
:map_string_int32 => {"a" => 1, "b" => 2},
@@ -703,36 +787,36 @@ module BasicTest
def test_oneof
d = OneofMessage.new
- assert d.a == nil
- assert d.b == nil
+ assert d.a == ""
+ assert d.b == 0
assert d.c == nil
- assert d.d == nil
+ assert d.d == :Default
assert d.my_oneof == nil
d.a = "hi"
assert d.a == "hi"
- assert d.b == nil
+ assert d.b == 0
assert d.c == nil
- assert d.d == nil
+ assert d.d == :Default
assert d.my_oneof == :a
d.b = 42
- assert d.a == nil
+ assert d.a == ""
assert d.b == 42
assert d.c == nil
- assert d.d == nil
+ assert d.d == :Default
assert d.my_oneof == :b
d.c = TestMessage2.new(:foo => 100)
- assert d.a == nil
- assert d.b == nil
+ assert d.a == ""
+ assert d.b == 0
assert d.c.foo == 100
- assert d.d == nil
+ assert d.d == :Default
assert d.my_oneof == :c
d.d = :C
- assert d.a == nil
- assert d.b == nil
+ assert d.a == ""
+ assert d.b == 0
assert d.c == nil
assert d.d == :C
assert d.my_oneof == :d
@@ -748,23 +832,23 @@ module BasicTest
d3 = OneofMessage.decode(
encoded_field_c + encoded_field_a + encoded_field_d)
- assert d3.a == nil
- assert d3.b == nil
+ assert d3.a == ""
+ assert d3.b == 0
assert d3.c == nil
assert d3.d == :B
d4 = OneofMessage.decode(
encoded_field_c + encoded_field_a + encoded_field_d +
encoded_field_c)
- assert d4.a == nil
- assert d4.b == nil
+ assert d4.a == ""
+ assert d4.b == 0
assert d4.c.foo == 1
- assert d4.d == nil
+ assert d4.d == :Default
d5 = OneofMessage.new(:a => "hello")
- assert d5.a != nil
+ assert d5.a == "hello"
d5.a = nil
- assert d5.a == nil
+ assert d5.a == ""
assert OneofMessage.encode(d5) == ''
assert d5.my_oneof == nil
end
@@ -853,15 +937,22 @@ module BasicTest
def test_encode_decode_helpers
m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
+ assert_equal 'foo', m.optional_string
+ assert_equal ['bar1', 'bar2'], m.repeated_string
+
json = m.to_json
m2 = TestMessage.decode_json(json)
- assert m2.optional_string == 'foo'
- assert m2.repeated_string == ['bar1', 'bar2']
+ assert_equal 'foo', m2.optional_string
+ assert_equal ['bar1', 'bar2'], m2.repeated_string
+ if RUBY_PLATFORM != "java"
+ assert m2.optional_string.frozen?
+ assert m2.repeated_string[0].frozen?
+ end
proto = m.to_proto
m2 = TestMessage.decode(proto)
- assert m2.optional_string == 'foo'
- assert m2.repeated_string == ['bar1', 'bar2']
+ assert_equal 'foo', m2.optional_string
+ assert_equal ['bar1', 'bar2'], m2.repeated_string
end
def test_protobuf_encode_decode_helpers
@@ -883,7 +974,7 @@ module BasicTest
end
def test_to_h
- m = TestMessage.new(:optional_bool => true, :optional_double => -10.100001, :optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
+ m = TestMessage.new(:optional_bool => true, :optional_double => -10.100001, :optional_string => 'foo', :repeated_string => ['bar1', 'bar2'], :repeated_msg => [TestMessage2.new(:foo => 100)])
expected_result = {
:optional_bool=>true,
:optional_bytes=>"",
@@ -903,12 +994,22 @@ module BasicTest
:repeated_float=>[],
:repeated_int32=>[],
:repeated_int64=>[],
- :repeated_msg=>[],
+ :repeated_msg=>[{:foo => 100}],
:repeated_string=>["bar1", "bar2"],
:repeated_uint32=>[],
:repeated_uint64=>[]
}
assert_equal expected_result, m.to_h
+
+ m = MapMessage.new(
+ :map_string_int32 => {"a" => 1, "b" => 2},
+ :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
+ "b" => TestMessage2.new(:foo => 2)})
+ expected_result = {
+ :map_string_int32 => {"a" => 1, "b" => 2},
+ :map_string_msg => {"a" => {:foo => 1}, "b" => {:foo => 2}}
+ }
+ assert_equal expected_result, m.to_h
end
@@ -1145,6 +1246,8 @@ module BasicTest
json_text = TestMessage.encode_json(m)
m2 = TestMessage.decode_json(json_text)
+ puts m.inspect
+ puts m2.inspect
assert m == m2
# Crash case from GitHub issue 283.
@@ -1156,14 +1259,145 @@ module BasicTest
Foo.encode_json(Foo.new(bar: bar, baz: [baz1, baz2]))
end
+ def test_json_emit_defaults
+ # TODO: Fix JSON in JRuby version.
+ return if RUBY_PLATFORM == "java"
+ m = TestMessage.new
+
+ expected = {
+ optionalInt32: 0,
+ optionalInt64: 0,
+ optionalUint32: 0,
+ optionalUint64: 0,
+ optionalBool: false,
+ optionalFloat: 0,
+ optionalDouble: 0,
+ optionalString: "",
+ optionalBytes: "",
+ optionalEnum: "Default",
+ repeatedInt32: [],
+ repeatedInt64: [],
+ repeatedUint32: [],
+ repeatedUint64: [],
+ repeatedBool: [],
+ repeatedFloat: [],
+ repeatedDouble: [],
+ repeatedString: [],
+ repeatedBytes: [],
+ repeatedMsg: [],
+ repeatedEnum: []
+ }
+
+ actual = TestMessage.encode_json(m, :emit_defaults => true)
+
+ assert JSON.parse(actual, :symbolize_names => true) == expected
+ end
+
+ def test_json_emit_defaults_submsg
+ # TODO: Fix JSON in JRuby version.
+ return if RUBY_PLATFORM == "java"
+ m = TestMessage.new(optional_msg: TestMessage2.new)
+
+ expected = {
+ optionalInt32: 0,
+ optionalInt64: 0,
+ optionalUint32: 0,
+ optionalUint64: 0,
+ optionalBool: false,
+ optionalFloat: 0,
+ optionalDouble: 0,
+ optionalString: "",
+ optionalBytes: "",
+ optionalMsg: {foo: 0},
+ optionalEnum: "Default",
+ repeatedInt32: [],
+ repeatedInt64: [],
+ repeatedUint32: [],
+ repeatedUint64: [],
+ repeatedBool: [],
+ repeatedFloat: [],
+ repeatedDouble: [],
+ repeatedString: [],
+ repeatedBytes: [],
+ repeatedMsg: [],
+ repeatedEnum: []
+ }
+
+ actual = TestMessage.encode_json(m, :emit_defaults => true)
+
+ assert JSON.parse(actual, :symbolize_names => true) == expected
+ end
+
+ def test_json_emit_defaults_repeated_submsg
+ # TODO: Fix JSON in JRuby version.
+ return if RUBY_PLATFORM == "java"
+ m = TestMessage.new(repeated_msg: [TestMessage2.new])
+
+ expected = {
+ optionalInt32: 0,
+ optionalInt64: 0,
+ optionalUint32: 0,
+ optionalUint64: 0,
+ optionalBool: false,
+ optionalFloat: 0,
+ optionalDouble: 0,
+ optionalString: "",
+ optionalBytes: "",
+ optionalEnum: "Default",
+ repeatedInt32: [],
+ repeatedInt64: [],
+ repeatedUint32: [],
+ repeatedUint64: [],
+ repeatedBool: [],
+ repeatedFloat: [],
+ repeatedDouble: [],
+ repeatedString: [],
+ repeatedBytes: [],
+ repeatedMsg: [{foo: 0}],
+ repeatedEnum: []
+ }
+
+ actual = TestMessage.encode_json(m, :emit_defaults => true)
+
+ assert JSON.parse(actual, :symbolize_names => true) == expected
+ end
+
def test_json_maps
# TODO: Fix JSON in JRuby version.
return if RUBY_PLATFORM == "java"
m = MapMessage.new(:map_string_int32 => {"a" => 1})
- expected = '{"map_string_int32":{"a":1},"map_string_msg":{}}'
- assert MapMessage.encode_json(m) == expected
+ expected = {mapStringInt32: {a: 1}, mapStringMsg: {}}
+ expected_preserve = {map_string_int32: {a: 1}, map_string_msg: {}}
+ assert JSON.parse(MapMessage.encode_json(m), :symbolize_names => true) == expected
+
+ json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true)
+ assert JSON.parse(json, :symbolize_names => true) == expected_preserve
+
m2 = MapMessage.decode_json(MapMessage.encode_json(m))
assert m == m2
end
+
+ def test_json_maps_emit_defaults_submsg
+ # TODO: Fix JSON in JRuby version.
+ return if RUBY_PLATFORM == "java"
+ m = MapMessage.new(:map_string_msg => {"a" => TestMessage2.new})
+ expected = {mapStringInt32: {}, mapStringMsg: {a: {foo: 0}}}
+
+ actual = MapMessage.encode_json(m, :emit_defaults => true)
+
+ assert JSON.parse(actual, :symbolize_names => true) == expected
+ end
+
+ def test_comparison_with_arbitrary_object
+ assert MapMessage.new != nil
+ end
+
+ def test_respond_to
+ # This test fails with JRuby 1.7.23, likely because of an old JRuby bug.
+ return if RUBY_PLATFORM == "java"
+ msg = MapMessage.new
+ assert msg.respond_to?(:map_string_int32)
+ assert !msg.respond_to?(:bacon)
+ end
end
end