• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/ruby
2
3# generated_code.rb is in the same directory as this test.
4$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
5
6require 'basic_test_proto2_pb'
7require 'generated_code_pb'
8require 'google/protobuf/well_known_types'
9require 'test/unit'
10
11module CaptureWarnings
12  @@warnings = nil
13
14  module_function
15
16  def warn(message, category: nil, **kwargs)
17    if @@warnings
18      @@warnings << message
19    else
20      super
21    end
22  end
23
24  def capture
25    @@warnings = []
26    yield
27    @@warnings
28  ensure
29    @@warnings = nil
30  end
31end
32
33Warning.extend CaptureWarnings
34
35def hex2bin(s)
36  s.scan(/../).map { |x| x.hex.chr }.join
37end
38
39class NonConformantNumericsTest < Test::Unit::TestCase
40  def test_empty_json_numerics
41    if defined? JRUBY_VERSION and Google::Protobuf::IMPLEMENTATION != :FFI
42      # In a future version, CRuby and JRuby FFI will also have this behavior.
43      assert_raises Google::Protobuf::ParseError do
44        msg = ::BasicTestProto2::TestMessage.decode_json('{"optionalInt32":""}')
45      end
46    else
47      warnings = CaptureWarnings.capture {
48        msg = ::BasicTestProto2::TestMessage.decode_json('{"optionalInt32":""}')
49        assert_equal 0, msg.optional_int32
50        assert msg.has_optional_int32?
51      }
52      assert_equal 1, warnings.size
53      assert_match "Empty string is not a valid number (field: basic_test_proto2.TestMessage.optional_int32)", warnings[0]
54    end
55  end
56
57  def test_trailing_non_numeric_characters
58    if defined? JRUBY_VERSION and Google::Protobuf::IMPLEMENTATION != :FFI
59      # In a future version, CRuby and JRuby FFI will also have this behavior.
60      assert_raises Google::Protobuf::ParseError do
61        msg = ::BasicTestProto2::TestMessage.decode_json('{"optionalDouble":"123abc"}')
62      end
63    else
64      warnings = CaptureWarnings.capture {
65        msg = ::BasicTestProto2::TestMessage.decode_json('{"optionalDouble":"123abc"}')
66        assert_equal 123, msg.optional_double
67        assert msg.has_optional_double?
68      }
69      assert_equal 1, warnings.size
70      assert_match "Non-number characters in quoted number (field: basic_test_proto2.TestMessage.optional_double)", warnings[0]
71    end
72  end
73end
74
75class EncodeDecodeTest < Test::Unit::TestCase
76  def test_discard_unknown
77    # Test discard unknown in message.
78    unknown_msg = A::B::C::TestUnknown.new(:unknown_field => 1)
79    from = A::B::C::TestUnknown.encode(unknown_msg)
80    m = A::B::C::TestMessage.decode(from)
81    Google::Protobuf.discard_unknown(m)
82    to = A::B::C::TestMessage.encode(m)
83    assert_empty to
84    # Test discard unknown for singular message field.
85    unknown_msg = A::B::C::TestUnknown.new(
86            :optional_unknown =>
87            A::B::C::TestUnknown.new(:unknown_field => 1))
88    from = A::B::C::TestUnknown.encode(unknown_msg)
89    m = A::B::C::TestMessage.decode(from)
90    Google::Protobuf.discard_unknown(m)
91    to = A::B::C::TestMessage.encode(m.optional_msg)
92    assert_empty to
93    # Test discard unknown for repeated message field.
94    unknown_msg = A::B::C::TestUnknown.new(
95            :repeated_unknown =>
96            [A::B::C::TestUnknown.new(:unknown_field => 1)])
97    from = A::B::C::TestUnknown.encode(unknown_msg)
98    m = A::B::C::TestMessage.decode(from)
99    Google::Protobuf.discard_unknown(m)
100    to = A::B::C::TestMessage.encode(m.repeated_msg[0])
101    assert_empty to
102    # Test discard unknown for map value message field.
103    unknown_msg = A::B::C::TestUnknown.new(
104            :map_unknown =>
105            {"" => A::B::C::TestUnknown.new(:unknown_field => 1)})
106    from = A::B::C::TestUnknown.encode(unknown_msg)
107    m = A::B::C::TestMessage.decode(from)
108    Google::Protobuf.discard_unknown(m)
109    to = A::B::C::TestMessage.encode(m.map_string_msg[''])
110    assert_empty to
111    # Test discard unknown for oneof message field.
112    unknown_msg = A::B::C::TestUnknown.new(
113            :oneof_unknown =>
114            A::B::C::TestUnknown.new(:unknown_field => 1))
115    from = A::B::C::TestUnknown.encode(unknown_msg)
116    m = A::B::C::TestMessage.decode(from)
117    Google::Protobuf.discard_unknown(m)
118    to = A::B::C::TestMessage.encode(m.oneof_msg)
119    assert_empty to
120  end
121
122  def test_encode_json
123    msg = A::B::C::TestMessage.new({ optional_int32: 22 })
124    json = msg.to_json
125
126    to = A::B::C::TestMessage.decode_json(json)
127    assert_equal 22, to.optional_int32
128    msg = A::B::C::TestMessage.new({ optional_int32: 22 })
129    json = msg.to_json({ preserve_proto_fieldnames: true })
130
131    assert_match 'optional_int32', json
132
133    to = A::B::C::TestMessage.decode_json(json)
134    assert_equal 22, to.optional_int32
135
136    msg = A::B::C::TestMessage.new({ optional_int32: 22 })
137    json = A::B::C::TestMessage.encode_json(
138      msg,
139      { preserve_proto_fieldnames: true, emit_defaults: true }
140    )
141
142    assert_match 'optional_int32', json
143
144
145    # Test for enums printing as ints.
146    msg = A::B::C::TestMessage.new({ optional_enum: 1 })
147    json = A::B::C::TestMessage.encode_json(
148      msg,
149      { :format_enums_as_integers => true }
150    )
151
152    assert_match '"optionalEnum":1', json
153
154    # Test for default enum being printed as int.
155    msg = A::B::C::TestMessage.new({ optional_enum: 0 })
156    json = A::B::C::TestMessage.encode_json(
157      msg,
158      { :format_enums_as_integers => true, :emit_defaults => true }
159    )
160
161    assert_match '"optionalEnum":0', json
162
163    # Test for repeated enums printing as ints.
164    msg = A::B::C::TestMessage.new({ repeated_enum: [0,1,2,3] })
165    json = A::B::C::TestMessage.encode_json(
166      msg,
167      { :format_enums_as_integers => true }
168    )
169
170    assert_match '"repeatedEnum":[0,1,2,3]', json
171  end
172
173  def test_encode_wrong_msg
174    assert_raises ::ArgumentError do
175      m = A::B::C::TestMessage.new(
176          :optional_int32 => 1,
177      )
178      Google::Protobuf::Any.encode(m)
179    end
180  end
181
182  def test_json_name
183    msg = A::B::C::TestJsonName.new(:value => 42)
184    json = msg.to_json
185    assert_match json, "{\"CustomJsonName\":42}"
186  end
187
188  def test_decode_depth_limit
189    msg = A::B::C::TestMessage.new(
190      optional_msg: A::B::C::TestMessage.new(
191        optional_msg: A::B::C::TestMessage.new(
192          optional_msg: A::B::C::TestMessage.new(
193            optional_msg: A::B::C::TestMessage.new(
194              optional_msg: A::B::C::TestMessage.new(
195              )
196            )
197          )
198        )
199      )
200    )
201    msg_encoded = A::B::C::TestMessage.encode(msg)
202    msg_out = A::B::C::TestMessage.decode(msg_encoded)
203    assert_match msg.to_json, msg_out.to_json
204
205    assert_raises Google::Protobuf::ParseError do
206      A::B::C::TestMessage.decode(msg_encoded, { recursion_limit: 4 })
207    end
208
209    msg_out = A::B::C::TestMessage.decode(msg_encoded, { recursion_limit: 5 })
210    assert_match msg.to_json, msg_out.to_json
211  end
212
213  def test_encode_depth_limit
214    msg = A::B::C::TestMessage.new(
215      optional_msg: A::B::C::TestMessage.new(
216        optional_msg: A::B::C::TestMessage.new(
217          optional_msg: A::B::C::TestMessage.new(
218            optional_msg: A::B::C::TestMessage.new(
219              optional_msg: A::B::C::TestMessage.new(
220              )
221            )
222          )
223        )
224      )
225    )
226    msg_encoded = A::B::C::TestMessage.encode(msg)
227    msg_out = A::B::C::TestMessage.decode(msg_encoded)
228    assert_match msg.to_json, msg_out.to_json
229
230    assert_raises RuntimeError do
231      A::B::C::TestMessage.encode(msg, { recursion_limit: 5 })
232    end
233
234    msg_encoded = A::B::C::TestMessage.encode(msg, { recursion_limit: 6 })
235    msg_out = A::B::C::TestMessage.decode(msg_encoded)
236    assert_match msg.to_json, msg_out.to_json
237  end
238
239end
240