#!/usr/bin/ruby # generated_code.rb is in the same directory as this test. $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) require 'basic_test_proto2_pb' require 'generated_code_pb' require 'google/protobuf/well_known_types' require 'test/unit' module CaptureWarnings @@warnings = nil module_function def warn(message, category: nil, **kwargs) if @@warnings @@warnings << message else super end end def capture @@warnings = [] yield @@warnings ensure @@warnings = nil end end Warning.extend CaptureWarnings def hex2bin(s) s.scan(/../).map { |x| x.hex.chr }.join end class NonConformantNumericsTest < Test::Unit::TestCase def test_empty_json_numerics if defined? JRUBY_VERSION and Google::Protobuf::IMPLEMENTATION != :FFI # In a future version, CRuby and JRuby FFI will also have this behavior. assert_raises Google::Protobuf::ParseError do msg = ::BasicTestProto2::TestMessage.decode_json('{"optionalInt32":""}') end else warnings = CaptureWarnings.capture { msg = ::BasicTestProto2::TestMessage.decode_json('{"optionalInt32":""}') assert_equal 0, msg.optional_int32 assert msg.has_optional_int32? } assert_equal 1, warnings.size assert_match "Empty string is not a valid number (field: basic_test_proto2.TestMessage.optional_int32)", warnings[0] end end def test_trailing_non_numeric_characters if defined? JRUBY_VERSION and Google::Protobuf::IMPLEMENTATION != :FFI # In a future version, CRuby and JRuby FFI will also have this behavior. assert_raises Google::Protobuf::ParseError do msg = ::BasicTestProto2::TestMessage.decode_json('{"optionalDouble":"123abc"}') end else warnings = CaptureWarnings.capture { msg = ::BasicTestProto2::TestMessage.decode_json('{"optionalDouble":"123abc"}') assert_equal 123, msg.optional_double assert msg.has_optional_double? } assert_equal 1, warnings.size assert_match "Non-number characters in quoted number (field: basic_test_proto2.TestMessage.optional_double)", warnings[0] end end end class EncodeDecodeTest < Test::Unit::TestCase def test_discard_unknown # Test discard unknown in message. unknown_msg = A::B::C::TestUnknown.new(:unknown_field => 1) from = A::B::C::TestUnknown.encode(unknown_msg) m = A::B::C::TestMessage.decode(from) Google::Protobuf.discard_unknown(m) to = A::B::C::TestMessage.encode(m) assert_empty to # Test discard unknown for singular message field. unknown_msg = A::B::C::TestUnknown.new( :optional_unknown => A::B::C::TestUnknown.new(:unknown_field => 1)) from = A::B::C::TestUnknown.encode(unknown_msg) m = A::B::C::TestMessage.decode(from) Google::Protobuf.discard_unknown(m) to = A::B::C::TestMessage.encode(m.optional_msg) assert_empty to # Test discard unknown for repeated message field. unknown_msg = A::B::C::TestUnknown.new( :repeated_unknown => [A::B::C::TestUnknown.new(:unknown_field => 1)]) from = A::B::C::TestUnknown.encode(unknown_msg) m = A::B::C::TestMessage.decode(from) Google::Protobuf.discard_unknown(m) to = A::B::C::TestMessage.encode(m.repeated_msg[0]) assert_empty to # Test discard unknown for map value message field. unknown_msg = A::B::C::TestUnknown.new( :map_unknown => {"" => A::B::C::TestUnknown.new(:unknown_field => 1)}) from = A::B::C::TestUnknown.encode(unknown_msg) m = A::B::C::TestMessage.decode(from) Google::Protobuf.discard_unknown(m) to = A::B::C::TestMessage.encode(m.map_string_msg['']) assert_empty to # Test discard unknown for oneof message field. unknown_msg = A::B::C::TestUnknown.new( :oneof_unknown => A::B::C::TestUnknown.new(:unknown_field => 1)) from = A::B::C::TestUnknown.encode(unknown_msg) m = A::B::C::TestMessage.decode(from) Google::Protobuf.discard_unknown(m) to = A::B::C::TestMessage.encode(m.oneof_msg) assert_empty to end def test_encode_json msg = A::B::C::TestMessage.new({ optional_int32: 22 }) json = msg.to_json to = A::B::C::TestMessage.decode_json(json) assert_equal 22, to.optional_int32 msg = A::B::C::TestMessage.new({ optional_int32: 22 }) json = msg.to_json({ preserve_proto_fieldnames: true }) assert_match 'optional_int32', json to = A::B::C::TestMessage.decode_json(json) assert_equal 22, to.optional_int32 msg = A::B::C::TestMessage.new({ optional_int32: 22 }) json = A::B::C::TestMessage.encode_json( msg, { preserve_proto_fieldnames: true, emit_defaults: true } ) assert_match 'optional_int32', json # Test for enums printing as ints. msg = A::B::C::TestMessage.new({ optional_enum: 1 }) json = A::B::C::TestMessage.encode_json( msg, { :format_enums_as_integers => true } ) assert_match '"optionalEnum":1', json # Test for default enum being printed as int. msg = A::B::C::TestMessage.new({ optional_enum: 0 }) json = A::B::C::TestMessage.encode_json( msg, { :format_enums_as_integers => true, :emit_defaults => true } ) assert_match '"optionalEnum":0', json # Test for repeated enums printing as ints. msg = A::B::C::TestMessage.new({ repeated_enum: [0,1,2,3] }) json = A::B::C::TestMessage.encode_json( msg, { :format_enums_as_integers => true } ) assert_match '"repeatedEnum":[0,1,2,3]', json end def test_encode_wrong_msg assert_raises ::ArgumentError do m = A::B::C::TestMessage.new( :optional_int32 => 1, ) Google::Protobuf::Any.encode(m) end end def test_json_name msg = A::B::C::TestJsonName.new(:value => 42) json = msg.to_json assert_match json, "{\"CustomJsonName\":42}" end def test_decode_depth_limit msg = A::B::C::TestMessage.new( optional_msg: A::B::C::TestMessage.new( optional_msg: A::B::C::TestMessage.new( optional_msg: A::B::C::TestMessage.new( optional_msg: A::B::C::TestMessage.new( optional_msg: A::B::C::TestMessage.new( ) ) ) ) ) ) msg_encoded = A::B::C::TestMessage.encode(msg) msg_out = A::B::C::TestMessage.decode(msg_encoded) assert_match msg.to_json, msg_out.to_json assert_raises Google::Protobuf::ParseError do A::B::C::TestMessage.decode(msg_encoded, { recursion_limit: 4 }) end msg_out = A::B::C::TestMessage.decode(msg_encoded, { recursion_limit: 5 }) assert_match msg.to_json, msg_out.to_json end def test_encode_depth_limit msg = A::B::C::TestMessage.new( optional_msg: A::B::C::TestMessage.new( optional_msg: A::B::C::TestMessage.new( optional_msg: A::B::C::TestMessage.new( optional_msg: A::B::C::TestMessage.new( optional_msg: A::B::C::TestMessage.new( ) ) ) ) ) ) msg_encoded = A::B::C::TestMessage.encode(msg) msg_out = A::B::C::TestMessage.decode(msg_encoded) assert_match msg.to_json, msg_out.to_json assert_raises RuntimeError do A::B::C::TestMessage.encode(msg, { recursion_limit: 5 }) end msg_encoded = A::B::C::TestMessage.encode(msg, { recursion_limit: 6 }) msg_out = A::B::C::TestMessage.decode(msg_encoded) assert_match msg.to_json, msg_out.to_json end end