• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1require 'google/protobuf/wrappers_pb.rb'
2
3# Defines tests which are common between proto2 and proto3 syntax.
4#
5# Requires that the proto messages are exactly the same in proto2 and proto3 syntax
6# and that the including class should define a 'proto_module' method which returns
7# the enclosing module of the proto message classes.
8
9require 'bigdecimal'
10
11module CommonTests
12  # Ruby 2.5 changed to raise FrozenError instead of RuntimeError
13  FrozenErrorType = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.5') ? RuntimeError : FrozenError
14
15  def test_defaults
16    m = proto_module::TestMessage.new
17    assert m.optional_int32 == 0
18    assert m.optional_int64 == 0
19    assert m.optional_uint32 == 0
20    assert m.optional_uint64 == 0
21    assert m.optional_bool == false
22    assert m.optional_float == 0.0
23    assert m.optional_double == 0.0
24    assert m.optional_string == ""
25    assert m.optional_bytes == ""
26    assert m.optional_msg == nil
27    assert m.optional_enum == :Default
28  end
29
30  def test_setters
31    m = proto_module::TestMessage.new
32    m.optional_int32 = -42
33    assert m.optional_int32 == -42
34    m.optional_int64 = -0x1_0000_0000
35    assert m.optional_int64 == -0x1_0000_0000
36    m.optional_uint32 = 0x9000_0000
37    assert m.optional_uint32 == 0x9000_0000
38    m.optional_uint64 = 0x9000_0000_0000_0000
39    assert m.optional_uint64 == 0x9000_0000_0000_0000
40    m.optional_bool = true
41    assert m.optional_bool == true
42    m.optional_float = 0.5
43    assert m.optional_float == 0.5
44    m.optional_double = 0.5
45    assert m.optional_double == 0.5
46    m.optional_string = "hello"
47    assert m.optional_string == "hello"
48    m.optional_string = :hello
49    assert m.optional_string == "hello"
50    m.optional_bytes = "world".encode!('ASCII-8BIT')
51    assert m.optional_bytes == "world"
52    m.optional_msg = proto_module::TestMessage2.new(:foo => 42)
53    assert m.optional_msg == proto_module::TestMessage2.new(:foo => 42)
54    m.optional_msg = nil
55    assert m.optional_msg == nil
56    m.optional_enum = :C
57    assert m.optional_enum == :C
58    m.optional_enum = 'C'
59    assert m.optional_enum == :C
60  end
61
62  def test_ctor_args
63    m = proto_module::TestMessage.new(:optional_int32 => -42,
64                                      :optional_msg => proto_module::TestMessage2.new,
65                                      :optional_enum => :C,
66                                      :repeated_string => ["hello", "there", "world"])
67    assert m.optional_int32 == -42
68    assert m.optional_msg.class == proto_module::TestMessage2
69    assert m.repeated_string.length == 3
70    assert m.optional_enum == :C
71    assert m.repeated_string[0] == "hello"
72    assert m.repeated_string[1] == "there"
73    assert m.repeated_string[2] == "world"
74  end
75
76  def test_ctor_string_symbol_args
77    m = proto_module::TestMessage.new(:optional_enum => 'C', :repeated_enum => ['A', 'B'])
78    assert_equal :C, m.optional_enum
79    assert_equal [:A, :B], m.repeated_enum
80
81    m = proto_module::TestMessage.new(:optional_string => :foo, :repeated_string => [:foo, :bar])
82    assert_equal 'foo', m.optional_string
83    assert_equal ['foo', 'bar'], m.repeated_string
84  end
85
86  def test_ctor_nil_args
87    m = proto_module::TestMessage.new(:optional_enum => nil, :optional_int32 => nil, :optional_string => nil, :optional_msg => nil)
88
89    assert_equal :Default, m.optional_enum
90    assert_equal 0, m.optional_int32
91    assert_equal "", m.optional_string
92    assert_nil m.optional_msg
93  end
94
95  def test_embeddedmsg_hash_init
96    m = proto_module::TestEmbeddedMessageParent.new(
97      :child_msg => {sub_child: {optional_int32: 1}},
98      :number => 2,
99      :repeated_msg => [{sub_child: {optional_int32: 3}}],
100      :repeated_number => [10, 20, 30])
101
102    assert_equal 2, m.number
103    assert_equal [10, 20, 30], m.repeated_number
104
105    assert_not_nil m.child_msg
106    assert_not_nil m.child_msg.sub_child
107    assert_equal m.child_msg.sub_child.optional_int32, 1
108
109    assert_not_nil m.repeated_msg
110    assert_equal 1, m.repeated_msg.length
111    assert_equal 3, m.repeated_msg.first.sub_child.optional_int32
112  end
113
114  def test_inspect_eq_to_s
115    m = proto_module::TestMessage.new(
116      :optional_int32 => -42,
117      :optional_enum => :A,
118      :optional_msg => proto_module::TestMessage2.new,
119      :repeated_string => ["hello", "there", "world"])
120    expected = "<#{proto_module}::TestMessage: optional_int32: -42, optional_int64: 0, optional_uint32: 0, optional_uint64: 0, optional_bool: false, optional_float: 0.0, optional_double: 0.0, optional_string: \"\", optional_bytes: \"\", optional_msg: <#{proto_module}::TestMessage2: foo: 0>, optional_enum: :A, repeated_int32: [], repeated_int64: [], repeated_uint32: [], repeated_uint64: [], repeated_bool: [], repeated_float: [], repeated_double: [], repeated_string: [\"hello\", \"there\", \"world\"], repeated_bytes: [], repeated_msg: [], repeated_enum: []>"
121    assert_equal expected, m.inspect
122    assert_equal expected, m.to_s
123
124    m = proto_module::OneofMessage.new(:b => -42)
125    expected = "<#{proto_module}::OneofMessage: a: \"\", b: -42, c: nil, d: :Default>"
126    assert_equal expected, m.inspect
127    assert_equal expected, m.to_s
128  end
129
130  def test_hash
131    m1 = proto_module::TestMessage.new(:optional_int32 => 42)
132    m2 = proto_module::TestMessage.new(:optional_int32 => 102, repeated_string: ['please', 'work', 'ok?'])
133    m3 = proto_module::TestMessage.new(:optional_int32 => 102, repeated_string: ['please', 'work', 'ok?'])
134    assert m1.hash != 0
135    assert m2.hash != 0
136    assert m3.hash != 0
137    # relying on the randomness here -- if hash function changes and we are
138    # unlucky enough to get a collision, then change the values above.
139    assert m1.hash != m2.hash
140    assert_equal m2.hash, m3.hash
141  end
142
143  def test_unknown_field_errors
144    e = assert_raise NoMethodError do
145      proto_module::TestMessage.new.hello
146    end
147    assert_match(/hello/, e.message)
148
149    e = assert_raise NoMethodError do
150      proto_module::TestMessage.new.hello = "world"
151    end
152    assert_match(/hello/, e.message)
153  end
154
155  def test_type_errors
156    m = proto_module::TestMessage.new
157    e = assert_raise Google::Protobuf::TypeError do
158      m.optional_int32 = "hello"
159    end
160
161    # Google::Protobuf::TypeError should inherit from TypeError for backwards compatibility
162    # TODO: This can be removed when we can safely migrate to Google::Protobuf::TypeError
163    assert e.is_a?(::TypeError)
164
165    assert_raise Google::Protobuf::TypeError do
166      m.optional_string = 42
167    end
168    assert_raise Google::Protobuf::TypeError do
169      m.optional_string = nil
170    end
171    assert_raise Google::Protobuf::TypeError do
172      m.optional_bool = 42
173    end
174    assert_raise Google::Protobuf::TypeError do
175      m.optional_msg = proto_module::TestMessage.new  # expects TestMessage2
176    end
177
178    assert_raise Google::Protobuf::TypeError do
179      m.repeated_int32 = []  # needs RepeatedField
180    end
181
182    assert_raise Google::Protobuf::TypeError do
183      m.repeated_int32.push "hello"
184    end
185
186    assert_raise Google::Protobuf::TypeError do
187      m.repeated_msg.push proto_module::TestMessage.new
188    end
189  end
190
191  def test_string_encoding
192    m = proto_module::TestMessage.new
193
194    # Assigning a normal (ASCII or UTF8) string to a bytes field, or
195    # ASCII-8BIT to a string field will convert to the proper encoding.
196    m.optional_bytes = "Test string ASCII".encode!('ASCII')
197    assert m.optional_bytes.frozen?
198    assert_equal Encoding::ASCII_8BIT, m.optional_bytes.encoding
199    assert_equal "Test string ASCII", m.optional_bytes
200
201    assert_raise Encoding::UndefinedConversionError do
202      m.optional_bytes = "Test string UTF-8 \u0100".encode!('UTF-8')
203    end
204
205    assert_raise Encoding::UndefinedConversionError do
206      m.optional_string = ["FFFF"].pack('H*')
207    end
208
209    # "Ordinary" use case.
210    m.optional_bytes = ["FFFF"].pack('H*')
211    m.optional_string = "\u0100"
212
213    # strings are immutable so we can't do this, but serialize should catch it.
214    m.optional_string = "asdf".encode!('UTF-8')
215    assert_raise(FrozenErrorType) { m.optional_string.encode!('ASCII-8BIT') }
216  end
217
218  def test_rptfield_int32
219    l = Google::Protobuf::RepeatedField.new(:int32)
220    assert l.count == 0
221    l = Google::Protobuf::RepeatedField.new(:int32, [1, 2, 3])
222    assert l.count == 3
223    assert_equal [1, 2, 3], l
224    assert_equal l, [1, 2, 3]
225    l.push 4
226    assert l == [1, 2, 3, 4]
227    dst_list = []
228    l.each { |val| dst_list.push val }
229    assert dst_list == [1, 2, 3, 4]
230    assert l.to_a == [1, 2, 3, 4]
231    assert l[0] == 1
232    assert l[3] == 4
233    l[0] = 5
234    assert l == [5, 2, 3, 4]
235
236    l2 = l.dup
237    assert l == l2
238    assert l.object_id != l2.object_id
239    l2.push 6
240    assert l.count == 4
241    assert l2.count == 5
242
243    assert l.inspect == '[5, 2, 3, 4]'
244
245    l.concat([7, 8, 9])
246    assert l == [5, 2, 3, 4, 7, 8, 9]
247    assert l.pop == 9
248    assert l == [5, 2, 3, 4, 7, 8]
249
250    assert_raise Google::Protobuf::TypeError do
251      m = proto_module::TestMessage.new
252      l.push m
253    end
254
255    m = proto_module::TestMessage.new
256    m.repeated_int32 = l
257    assert m.repeated_int32 == [5, 2, 3, 4, 7, 8]
258    assert m.repeated_int32.object_id == l.object_id
259    l.push 42
260    assert m.repeated_int32.pop == 42
261
262    l3 = l + l.dup
263    assert l3.count == l.count * 2
264    l.count.times do |i|
265      assert l3[i] == l[i]
266      assert l3[l.count + i] == l[i]
267    end
268
269    l.clear
270    assert l.count == 0
271    l += [1, 2, 3, 4]
272    l.replace([5, 6, 7, 8])
273    assert l == [5, 6, 7, 8]
274
275    l4 = Google::Protobuf::RepeatedField.new(:int32)
276    l4[5] = 42
277    assert l4 == [0, 0, 0, 0, 0, 42]
278
279    l4 << 100
280    assert l4 == [0, 0, 0, 0, 0, 42, 100]
281    l4 << 101 << 102
282    assert l4 == [0, 0, 0, 0, 0, 42, 100, 101, 102]
283  end
284
285  def test_parent_rptfield
286    #make sure we set the RepeatedField and can add to it
287    m = proto_module::TestMessage.new
288    assert m.repeated_string == []
289    m.repeated_string << 'ok'
290    m.repeated_string.push('ok2')
291    assert m.repeated_string == ['ok', 'ok2']
292    m.repeated_string += ['ok3']
293    assert m.repeated_string == ['ok', 'ok2', 'ok3']
294  end
295
296  def test_rptfield_msg
297    l = Google::Protobuf::RepeatedField.new(:message, proto_module::TestMessage)
298    l.push proto_module::TestMessage.new
299    assert l.count == 1
300    assert_raise Google::Protobuf::TypeError do
301      l.push proto_module::TestMessage2.new
302    end
303    assert_raise Google::Protobuf::TypeError do
304      l.push 42
305    end
306
307    l2 = l.dup
308    assert l2[0] == l[0]
309    assert l2[0].object_id == l[0].object_id
310
311    l2 = Google::Protobuf.deep_copy(l)
312    assert l2[0] == l[0]
313    assert l2[0].object_id != l[0].object_id
314
315    l3 = l + l2
316    assert l3.count == 2
317    assert l3[0] == l[0]
318    assert l3[1] == l2[0]
319    l3[0].optional_int32 = 1000
320    assert l[0].optional_int32 == 1000
321
322    new_msg = proto_module::TestMessage.new(:optional_int32 => 200)
323    l4 = l + [new_msg]
324    assert l4.count == 2
325    new_msg.optional_int32 = 1000
326    assert l4[1].optional_int32 == 1000
327  end
328
329  def test_rptfield_enum
330    l = Google::Protobuf::RepeatedField.new(:enum, proto_module::TestEnum)
331    l.push :A
332    l.push :B
333    l.push :C
334    assert l.count == 3
335    assert_raise RangeError do
336      l.push :D
337    end
338    assert l[0] == :A
339
340    l.push 4
341    assert l[3] == 4
342  end
343
344  def test_rptfield_initialize
345    assert_raise ArgumentError do
346      Google::Protobuf::RepeatedField.new
347    end
348    assert_raise ArgumentError do
349      Google::Protobuf::RepeatedField.new(:message)
350    end
351    assert_raise ArgumentError do
352      Google::Protobuf::RepeatedField.new([1, 2, 3])
353    end
354    assert_raise ArgumentError do
355      Google::Protobuf::RepeatedField.new(:message, [proto_module::TestMessage2.new])
356    end
357  end
358
359  def test_rptfield_array_ducktyping
360    l = Google::Protobuf::RepeatedField.new(:int32)
361    length_methods = %w(count length size)
362    length_methods.each do |lm|
363      assert l.send(lm)  == 0
364    end
365    # out of bounds returns a nil
366    assert l[0] == nil
367    assert l[1] == nil
368    assert l[-1] == nil
369    l.push 4
370    length_methods.each do |lm|
371      assert l.send(lm) == 1
372    end
373    assert l[0] == 4
374    assert l[1] == nil
375    assert l[-1] == 4
376    assert l[-2] == nil
377
378    l.push 2
379    length_methods.each do |lm|
380      assert l.send(lm) == 2
381    end
382    assert l[0] == 4
383    assert l[1] == 2
384    assert l[2] == nil
385    assert l[-1] == 2
386    assert l[-2] == 4
387    assert l[-3] == nil
388
389    #adding out of scope will backfill with empty objects
390  end
391
392  def test_map_basic
393    # allowed key types:
394    # :int32, :int64, :uint32, :uint64, :bool, :string, :bytes.
395
396    m = Google::Protobuf::Map.new(:string, :int32)
397    m["asdf"] = 1
398    assert m["asdf"] == 1
399    m["jkl;"] = 42
400    assert m == { "jkl;" => 42, "asdf" => 1 }
401    assert m.has_key?("asdf")
402    assert !m.has_key?("qwerty")
403    assert m.length == 2
404
405    m2 = m.dup
406    assert_equal m, m2
407    assert m.hash != 0
408    assert_equal m.hash, m2.hash
409
410    collected = {}
411    m.each { |k,v| collected[v] = k }
412    assert collected == { 42 => "jkl;", 1 => "asdf" }
413
414    assert m.delete("asdf") == 1
415    assert !m.has_key?("asdf")
416    assert m["asdf"] == nil
417    assert !m.has_key?("asdf")
418
419    # We only assert on inspect value when there is one map entry because the
420    # order in which elements appear is unspecified (depends on the internal
421    # hash function). We don't want a brittle test.
422    assert m.inspect == "{\"jkl;\"=>42}"
423
424    assert m.keys == ["jkl;"]
425    assert m.values == [42]
426
427    m.clear
428    assert m.length == 0
429    assert m == {}
430
431    assert_raise TypeError do
432      m[1] = 1
433    end
434    assert_raise RangeError do
435      m["asdf"] = 0x1_0000_0000
436    end
437  end
438
439  def test_map_ctor
440    m = Google::Protobuf::Map.new(:string, :int32,
441                                  {"a" => 1, "b" => 2, "c" => 3})
442    assert m == {"a" => 1, "c" => 3, "b" => 2}
443  end
444
445  def test_map_keytypes
446    m = Google::Protobuf::Map.new(:int32, :int32)
447    m[1] = 42
448    m[-1] = 42
449    assert_raise RangeError do
450      m[0x8000_0000] = 1
451    end
452    assert_raise Google::Protobuf::TypeError do
453      m["asdf"] = 1
454    end
455
456    m = Google::Protobuf::Map.new(:int64, :int32)
457    m[0x1000_0000_0000_0000] = 1
458    assert_raise RangeError do
459      m[0x1_0000_0000_0000_0000] = 1
460    end
461    assert_raise Google::Protobuf::TypeError do
462      m["asdf"] = 1
463    end
464
465    m = Google::Protobuf::Map.new(:uint32, :int32)
466    m[0x8000_0000] = 1
467    assert_raise RangeError do
468      m[0x1_0000_0000] = 1
469    end
470    assert_raise RangeError do
471      m[-1] = 1
472    end
473
474    m = Google::Protobuf::Map.new(:uint64, :int32)
475    m[0x8000_0000_0000_0000] = 1
476    assert_raise RangeError do
477      m[0x1_0000_0000_0000_0000] = 1
478    end
479    assert_raise RangeError do
480      m[-1] = 1
481    end
482
483    m = Google::Protobuf::Map.new(:bool, :int32)
484    m[true] = 1
485    m[false] = 2
486    assert_raise Google::Protobuf::TypeError do
487      m[1] = 1
488    end
489    assert_raise Google::Protobuf::TypeError do
490      m["asdf"] = 1
491    end
492
493    m = Google::Protobuf::Map.new(:string, :int32)
494    m["asdf"] = 1
495    assert_raise TypeError do
496      m[1] = 1
497    end
498    assert_raise Encoding::UndefinedConversionError do
499      bytestring = ["FFFF"].pack("H*")
500      m[bytestring] = 1
501    end
502
503    m = Google::Protobuf::Map.new(:bytes, :int32)
504    bytestring = ["FFFF"].pack("H*")
505    m[bytestring] = 1
506    # Allowed -- we will automatically convert to ASCII-8BIT.
507    m["asdf"] = 1
508    assert_raise TypeError do
509      m[1] = 1
510    end
511  end
512
513  def test_map_msg_enum_valuetypes
514    m = Google::Protobuf::Map.new(:string, :message, proto_module::TestMessage)
515    m["asdf"] = proto_module::TestMessage.new
516    assert_raise Google::Protobuf::TypeError do
517      m["jkl;"] = proto_module::TestMessage2.new
518    end
519
520    m = Google::Protobuf::Map.new(
521      :string, :message, proto_module::TestMessage,
522      { "a" => proto_module::TestMessage.new(:optional_int32 => 42),
523        "b" => proto_module::TestMessage.new(:optional_int32 => 84) })
524    assert m.length == 2
525    assert m.values.map{|msg| msg.optional_int32}.sort == [42, 84]
526
527    m = Google::Protobuf::Map.new(:string, :enum, proto_module::TestEnum,
528                                  { "x" => :A, "y" => :B, "z" => :C })
529    assert m.length == 3
530    assert m["z"] == :C
531    m["z"] = 2
532    assert m["z"] == :B
533    m["z"] = 4
534    assert m["z"] == 4
535    assert_raise RangeError do
536      m["z"] = :Z
537    end
538    assert_raise RangeError do
539      m["z"] = "z"
540    end
541  end
542
543  def test_map_dup_deep_copy
544    m = Google::Protobuf::Map.new(
545      :string, :message, proto_module::TestMessage,
546      { "a" => proto_module::TestMessage.new(:optional_int32 => 42),
547        "b" => proto_module::TestMessage.new(:optional_int32 => 84) })
548
549    m2 = m.dup
550    assert m == m2
551    assert m.object_id != m2.object_id
552    assert m["a"].object_id == m2["a"].object_id
553    assert m["b"].object_id == m2["b"].object_id
554
555    m2 = Google::Protobuf.deep_copy(m)
556    assert m == m2
557    assert m.object_id != m2.object_id
558    assert m["a"].object_id != m2["a"].object_id
559    assert m["b"].object_id != m2["b"].object_id
560  end
561
562  def test_oneof_descriptors
563    d = proto_module::OneofMessage.descriptor
564    o = d.lookup_oneof("my_oneof")
565    assert o != nil
566    assert o.class == Google::Protobuf::OneofDescriptor
567    assert o.name == "my_oneof"
568    oneof_count = 0
569    d.each_oneof{ |oneof|
570      oneof_count += 1
571      assert oneof == o
572    }
573    assert oneof_count == 1
574    assert o.count == 4
575    field_names = o.map{|f| f.name}.sort
576    assert field_names == ["a", "b", "c", "d"]
577  end
578
579  def test_oneof
580    d = proto_module::OneofMessage.new
581    assert d.a == ""
582    assert d.b == 0
583    assert d.c == nil
584    assert d.d == :Default
585    assert d.my_oneof == nil
586
587    d.a = "hi"
588    assert d.a == "hi"
589    assert d.b == 0
590    assert d.c == nil
591    assert d.d == :Default
592    assert d.my_oneof == :a
593
594    d.b = 42
595    assert d.a == ""
596    assert d.b == 42
597    assert d.c == nil
598    assert d.d == :Default
599    assert d.my_oneof == :b
600
601    d.c = proto_module::TestMessage2.new(:foo => 100)
602    assert d.a == ""
603    assert d.b == 0
604    assert d.c.foo == 100
605    assert d.d == :Default
606    assert d.my_oneof == :c
607
608    d.d = :C
609    assert d.a == ""
610    assert d.b == 0
611    assert d.c == nil
612    assert d.d == :C
613    assert d.my_oneof == :d
614
615    d2 = proto_module::OneofMessage.decode(proto_module::OneofMessage.encode(d))
616    assert d2 == d
617
618    encoded_field_a = proto_module::OneofMessage.encode(proto_module::OneofMessage.new(:a => "string"))
619    encoded_field_b = proto_module::OneofMessage.encode(proto_module::OneofMessage.new(:b => 1000))
620    encoded_field_c = proto_module::OneofMessage.encode(
621      proto_module::OneofMessage.new(:c => proto_module::TestMessage2.new(:foo => 1)))
622    encoded_field_d = proto_module::OneofMessage.encode(proto_module::OneofMessage.new(:d => :B))
623
624    d3 = proto_module::OneofMessage.decode(
625      encoded_field_c + encoded_field_a + encoded_field_b + encoded_field_d)
626    assert d3.a == ""
627    assert d3.b == 0
628    assert d3.c == nil
629    assert d3.d == :B
630
631    d4 = proto_module::OneofMessage.decode(
632      encoded_field_c + encoded_field_a + encoded_field_b + encoded_field_d +
633      encoded_field_c)
634    assert d4.a == ""
635    assert d4.b == 0
636    assert d4.c.foo == 1
637    assert d4.d == :Default
638
639    d5 = proto_module::OneofMessage.new(:a => "hello")
640    assert d5.a == "hello"
641    d5.a = nil
642    assert d5.a == ""
643    assert proto_module::OneofMessage.encode(d5) == ''
644    assert d5.my_oneof == nil
645  end
646
647  def test_enum_field
648    m = proto_module::TestMessage.new
649    assert m.optional_enum == :Default
650    m.optional_enum = :A
651    assert m.optional_enum == :A
652    assert_raise RangeError do
653      m.optional_enum = :ASDF
654    end
655    m.optional_enum = 1
656    assert m.optional_enum == :A
657    m.optional_enum = 100
658    assert m.optional_enum == 100
659  end
660
661  def test_dup
662    m = proto_module::TestMessage.new
663    m.optional_string = "hello"
664    m.optional_int32 = 42
665    tm1 = proto_module::TestMessage2.new(:foo => 100)
666    tm2 = proto_module::TestMessage2.new(:foo => 200)
667    m.repeated_msg.push tm1
668    assert m.repeated_msg[-1] == tm1
669    m.repeated_msg.push tm2
670    assert m.repeated_msg[-1] == tm2
671    m2 = m.dup
672    assert m == m2
673    m.optional_int32 += 1
674    assert m != m2
675    assert m.repeated_msg[0] == m2.repeated_msg[0]
676    assert m.repeated_msg[0].object_id == m2.repeated_msg[0].object_id
677  end
678
679  def test_deep_copy
680    m = proto_module::TestMessage.new(:optional_int32 => 42,
681                                      :repeated_msg => [proto_module::TestMessage2.new(:foo => 100)])
682    m2 = Google::Protobuf.deep_copy(m)
683    assert m == m2
684    assert m.repeated_msg == m2.repeated_msg
685    assert m.repeated_msg.object_id != m2.repeated_msg.object_id
686    assert m.repeated_msg[0].object_id != m2.repeated_msg[0].object_id
687  end
688
689  def test_eq
690    m = proto_module::TestMessage.new(:optional_int32 => 42,
691                                      :repeated_int32 => [1, 2, 3])
692    m2 = proto_module::TestMessage.new(:optional_int32 => 43,
693                                       :repeated_int32 => [1, 2, 3])
694    assert m != m2
695  end
696
697  def test_enum_lookup
698    assert proto_module::TestEnum::A == 1
699    assert proto_module::TestEnum::B == 2
700    assert proto_module::TestEnum::C == 3
701
702    assert proto_module::TestEnum::lookup(1) == :A
703    assert proto_module::TestEnum::lookup(2) == :B
704    assert proto_module::TestEnum::lookup(3) == :C
705
706    assert proto_module::TestEnum::resolve(:A) == 1
707    assert proto_module::TestEnum::resolve(:B) == 2
708    assert proto_module::TestEnum::resolve(:C) == 3
709  end
710
711  def test_enum_const_get_helpers
712    m = proto_module::TestMessage.new
713    assert_equal proto_module::TestEnum::Default, m.optional_enum_const
714    assert_equal proto_module::TestEnum.const_get(:Default), m.optional_enum_const
715
716    m = proto_module::TestMessage.new({optional_enum: proto_module::TestEnum::A})
717    assert_equal proto_module::TestEnum::A, m.optional_enum_const
718    assert_equal proto_module::TestEnum.const_get(:A), m.optional_enum_const
719
720    m = proto_module::TestMessage.new({optional_enum: proto_module::TestEnum::B})
721    assert_equal proto_module::TestEnum::B, m.optional_enum_const
722    assert_equal proto_module::TestEnum.const_get(:B), m.optional_enum_const
723
724    m = proto_module::TestMessage.new({optional_enum: proto_module::TestEnum::C})
725    assert_equal proto_module::TestEnum::C, m.optional_enum_const
726    assert_equal proto_module::TestEnum.const_get(:C), m.optional_enum_const
727
728    m = proto_module::TestMessage2.new({foo: 2})
729    assert_equal 2, m.foo
730    assert_raise(NoMethodError) { m.foo_ }
731    assert_raise(NoMethodError) { m.foo_X }
732    assert_raise(NoMethodError) { m.foo_XX }
733    assert_raise(NoMethodError) { m.foo_XXX }
734    assert_raise(NoMethodError) { m.foo_XXXX }
735    assert_raise(NoMethodError) { m.foo_XXXXX }
736    assert_raise(NoMethodError) { m.foo_XXXXXX }
737
738    m = proto_module::Enumer.new({optional_enum: :B})
739    assert_equal :B, m.optional_enum
740    assert_raise(NoMethodError) { m.optional_enum_ }
741    assert_raise(NoMethodError) { m.optional_enum_X }
742    assert_raise(NoMethodError) { m.optional_enum_XX }
743    assert_raise(NoMethodError) { m.optional_enum_XXX }
744    assert_raise(NoMethodError) { m.optional_enum_XXXX }
745    assert_raise(NoMethodError) { m.optional_enum_XXXXX }
746    assert_raise(NoMethodError) { m.optional_enum_XXXXXX }
747  end
748
749  def test_enum_getter
750    m = proto_module::Enumer.new(:optional_enum => :B, :repeated_enum => [:A, :C])
751
752    assert_equal :B, m.optional_enum
753    assert_equal 2, m.optional_enum_const
754    assert_equal proto_module::TestEnum::B, m.optional_enum_const
755    assert_equal [:A, :C], m.repeated_enum
756    assert_equal [1, 3], m.repeated_enum_const
757    assert_equal [proto_module::TestEnum::A, proto_module::TestEnum::C], m.repeated_enum_const
758  end
759
760  def test_enum_getter_oneof
761    m = proto_module::Enumer.new(:const => :C)
762
763    assert_equal :C, m.const
764    assert_equal 3, m.const_const
765    assert_equal proto_module::TestEnum::C, m.const_const
766  end
767
768  def test_enum_getter_only_enums
769    m = proto_module::Enumer.new(:optional_enum => :B, :a_const => 'thing')
770
771    assert_equal 'thing', m.a_const
772    assert_equal :B, m.optional_enum
773
774    assert_raise(NoMethodError) { m.a }
775    assert_raise(NoMethodError) { m.a_const_const }
776  end
777
778  def test_repeated_push
779    m = proto_module::TestMessage.new
780
781    m.repeated_string += ['one']
782    m.repeated_string += %w[two three]
783    assert_equal %w[one two three], m.repeated_string
784
785    m.repeated_string.push *['four', 'five']
786    assert_equal %w[one two three four five], m.repeated_string
787
788    m.repeated_string.push 'six', 'seven'
789    assert_equal %w[one two three four five six seven], m.repeated_string
790
791    m = proto_module::TestMessage.new
792
793    m.repeated_msg += [proto_module::TestMessage2.new(:foo => 1), proto_module::TestMessage2.new(:foo => 2)]
794    m.repeated_msg += [proto_module::TestMessage2.new(:foo => 3)]
795    m.repeated_msg.push proto_module::TestMessage2.new(:foo => 4), proto_module::TestMessage2.new(:foo => 5)
796    assert_equal [1, 2, 3, 4, 5], m.repeated_msg.map {|x| x.foo}
797  end
798
799  def test_parse_serialize
800    m = proto_module::TestMessage.new(:optional_int32 => 42,
801                                      :optional_string => "hello world",
802                                      :optional_enum => :B,
803                                      :repeated_string => ["a", "b", "c"],
804                                      :repeated_int32 => [42, 43, 44],
805                                      :repeated_enum => [:A, :B, :C, 100],
806                                      :repeated_msg => [proto_module::TestMessage2.new(:foo => 1),
807                                                        proto_module::TestMessage2.new(:foo => 2)])
808    data = proto_module::TestMessage.encode m
809    m2 = proto_module::TestMessage.decode data
810    assert_equal m, m2
811
812    data = Google::Protobuf.encode m
813    m2 = Google::Protobuf.decode(proto_module::TestMessage, data)
814    assert m == m2
815  end
816
817  def test_encode_decode_helpers
818    m = proto_module::TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
819    assert_equal 'foo', m.optional_string
820    assert_equal ['bar1', 'bar2'], m.repeated_string
821
822    json = m.to_json
823    m2 = proto_module::TestMessage.decode_json(json)
824    assert_equal 'foo', m2.optional_string
825    assert_equal ['bar1', 'bar2'], m2.repeated_string
826    if RUBY_PLATFORM != "java"
827      assert m2.optional_string.frozen?
828      assert m2.repeated_string[0].frozen?
829    end
830
831    proto = m.to_proto
832    m2 = proto_module::TestMessage.decode(proto)
833    assert_equal 'foo', m2.optional_string
834    assert_equal ['bar1', 'bar2'], m2.repeated_string
835  end
836
837  def test_protobuf_encode_decode_helpers
838    m = proto_module::TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
839    encoded_msg = Google::Protobuf.encode(m)
840    assert_equal m.to_proto, encoded_msg
841
842    decoded_msg = Google::Protobuf.decode(proto_module::TestMessage, encoded_msg)
843    assert_equal proto_module::TestMessage.decode(m.to_proto), decoded_msg
844  end
845
846  def test_protobuf_encode_decode_json_helpers
847    m = proto_module::TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
848    encoded_msg = Google::Protobuf.encode_json(m)
849    assert_equal m.to_json, encoded_msg
850
851    decoded_msg = Google::Protobuf.decode_json(proto_module::TestMessage, encoded_msg)
852    assert_equal proto_module::TestMessage.decode_json(m.to_json), decoded_msg
853  end
854
855  def test_def_errors
856    s = Google::Protobuf::DescriptorPool.new
857    assert_raise Google::Protobuf::TypeError do
858      s.build do
859        # enum with no default (integer value 0)
860        add_enum "MyEnum" do
861          value :A, 1
862        end
863      end
864    end
865    assert_raise Google::Protobuf::TypeError do
866      s.build do
867        # message with required field (unsupported in proto3)
868        add_message "MyMessage" do
869          required :foo, :int32, 1
870        end
871      end
872    end
873  end
874
875  def test_corecursive
876    # just be sure that we can instantiate types with corecursive field-type
877    # references.
878    m = proto_module::Recursive1.new(:foo => proto_module::Recursive2.new(:foo => proto_module::Recursive1.new))
879    assert proto_module::Recursive1.descriptor.lookup("foo").subtype ==
880           proto_module::Recursive2.descriptor
881    assert proto_module::Recursive2.descriptor.lookup("foo").subtype ==
882           proto_module::Recursive1.descriptor
883
884    serialized = proto_module::Recursive1.encode(m)
885    m2 = proto_module::Recursive1.decode(serialized)
886    assert m == m2
887  end
888
889  def test_serialize_cycle
890    m = proto_module::Recursive1.new(:foo => proto_module::Recursive2.new)
891    m.foo.foo = m
892    assert_raise RuntimeError do
893      proto_module::Recursive1.encode(m)
894    end
895  end
896
897  def test_bad_field_names
898    m = proto_module::BadFieldNames.new(:dup => 1, :class => 2)
899    m2 = m.dup
900    assert m == m2
901    assert m['dup'] == 1
902    assert m['class'] == 2
903    m['dup'] = 3
904    assert m['dup'] == 3
905  end
906
907  def test_int_ranges
908    m = proto_module::TestMessage.new
909
910    m.optional_int32 = 0
911    m.optional_int32 = -0x8000_0000
912    m.optional_int32 = +0x7fff_ffff
913    m.optional_int32 = 1.0
914    m.optional_int32 = -1.0
915    m.optional_int32 = 2e9
916    assert_raise RangeError do
917      m.optional_int32 = -0x8000_0001
918    end
919    assert_raise RangeError do
920      m.optional_int32 = +0x8000_0000
921    end
922    assert_raise RangeError do
923      m.optional_int32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
924    end
925    assert_raise RangeError do
926      m.optional_int32 = 1e12
927    end
928    assert_raise RangeError do
929      m.optional_int32 = 1.5
930    end
931
932    m.optional_uint32 = 0
933    m.optional_uint32 = +0xffff_ffff
934    m.optional_uint32 = 1.0
935    m.optional_uint32 = 4e9
936    assert_raise RangeError do
937      m.optional_uint32 = -1
938    end
939    assert_raise RangeError do
940      m.optional_uint32 = -1.5
941    end
942    assert_raise RangeError do
943      m.optional_uint32 = -1.5e12
944    end
945    assert_raise RangeError do
946      m.optional_uint32 = -0x1000_0000_0000_0000
947    end
948    assert_raise RangeError do
949      m.optional_uint32 = +0x1_0000_0000
950    end
951    assert_raise RangeError do
952      m.optional_uint32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
953    end
954    assert_raise RangeError do
955      m.optional_uint32 = 1e12
956    end
957    assert_raise RangeError do
958      m.optional_uint32 = 1.5
959    end
960
961    m.optional_int64 = 0
962    m.optional_int64 = -0x8000_0000_0000_0000
963    m.optional_int64 = +0x7fff_ffff_ffff_ffff
964    m.optional_int64 = 1.0
965    m.optional_int64 = -1.0
966    m.optional_int64 = 8e18
967    m.optional_int64 = -8e18
968    assert_raise RangeError do
969      m.optional_int64 = -0x8000_0000_0000_0001
970    end
971    assert_raise RangeError do
972      m.optional_int64 = +0x8000_0000_0000_0000
973    end
974    assert_raise RangeError do
975      m.optional_int64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
976    end
977    assert_raise RangeError do
978      m.optional_int64 = 1e50
979    end
980    assert_raise RangeError do
981      m.optional_int64 = 1.5
982    end
983
984    m.optional_uint64 = 0
985    m.optional_uint64 = +0xffff_ffff_ffff_ffff
986    m.optional_uint64 = 1.0
987    m.optional_uint64 = 16e18
988    assert_raise RangeError do
989      m.optional_uint64 = -1
990    end
991    assert_raise RangeError do
992      m.optional_uint64 = -1.5
993    end
994    assert_raise RangeError do
995      m.optional_uint64 = -1.5e12
996    end
997    assert_raise RangeError do
998      m.optional_uint64 = -0x1_0000_0000_0000_0000
999    end
1000    assert_raise RangeError do
1001      m.optional_uint64 = +0x1_0000_0000_0000_0000
1002    end
1003    assert_raise RangeError do
1004      m.optional_uint64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
1005    end
1006    assert_raise RangeError do
1007      m.optional_uint64 = 1e50
1008    end
1009    assert_raise RangeError do
1010      m.optional_uint64 = 1.5
1011    end
1012  end
1013
1014  def test_stress_test
1015    m = proto_module::TestMessage.new
1016    m.optional_int32 = 42
1017    m.optional_int64 = 0x100000000
1018    m.optional_string = "hello world"
1019    10.times do m.repeated_msg.push proto_module::TestMessage2.new(:foo => 42) end
1020    10.times do m.repeated_string.push "hello world" end
1021
1022    data = proto_module::TestMessage.encode(m)
1023
1024    10_000.times do
1025      m = proto_module::TestMessage.decode(data)
1026      data_new = proto_module::TestMessage.encode(m)
1027      assert data_new == data
1028      data = data_new
1029    end
1030  end
1031
1032  def test_reflection
1033    m = proto_module::TestMessage.new(:optional_int32 => 1234)
1034    msgdef = m.class.descriptor
1035    assert msgdef.class == Google::Protobuf::Descriptor
1036    assert msgdef.any? {|field| field.name == "optional_int32"}
1037    optional_int32 = msgdef.lookup "optional_int32"
1038    assert optional_int32.class == Google::Protobuf::FieldDescriptor
1039    assert optional_int32 != nil
1040    assert optional_int32.name == "optional_int32"
1041    assert optional_int32.type == :int32
1042    optional_int32.set(m, 5678)
1043    assert m.optional_int32 == 5678
1044    m.optional_int32 = 1000
1045    assert optional_int32.get(m) == 1000
1046
1047    optional_msg = msgdef.lookup "optional_msg"
1048    assert optional_msg.subtype == proto_module::TestMessage2.descriptor
1049
1050    optional_msg.set(m, optional_msg.subtype.msgclass.new)
1051
1052    assert msgdef.msgclass == proto_module::TestMessage
1053
1054    optional_enum = msgdef.lookup "optional_enum"
1055    assert optional_enum.subtype == proto_module::TestEnum.descriptor
1056    assert optional_enum.subtype.class == Google::Protobuf::EnumDescriptor
1057    optional_enum.subtype.each do |k, v|
1058      # set with integer, check resolution to symbolic name
1059      optional_enum.set(m, v)
1060      assert optional_enum.get(m) == k
1061    end
1062  end
1063
1064  def test_json
1065    # TODO: Fix JSON in JRuby version.
1066    return if RUBY_PLATFORM == "java"
1067    m = proto_module::TestMessage.new(:optional_int32 => 1234,
1068                                      :optional_int64 => -0x1_0000_0000,
1069                                      :optional_uint32 => 0x8000_0000,
1070                                      :optional_uint64 => 0xffff_ffff_ffff_ffff,
1071                                      :optional_bool => true,
1072                                      :optional_float => 1.0,
1073                                      :optional_double => -1e100,
1074                                      :optional_string => "Test string",
1075                                      :optional_bytes => ["FFFFFFFF"].pack('H*'),
1076                                      :optional_msg => proto_module::TestMessage2.new(:foo => 42),
1077                                      :repeated_int32 => [1, 2, 3, 4],
1078                                      :repeated_string => ["a", "b", "c"],
1079                                      :repeated_bool => [true, false, true, false],
1080                                      :repeated_msg => [proto_module::TestMessage2.new(:foo => 1),
1081                                                        proto_module::TestMessage2.new(:foo => 2)])
1082
1083    json_text = proto_module::TestMessage.encode_json(m)
1084    m2 = proto_module::TestMessage.decode_json(json_text)
1085    assert_equal m, m2
1086
1087    # Crash case from GitHub issue 283.
1088    bar = proto_module::Bar.new(msg: "bar")
1089    baz1 = proto_module::Baz.new(msg: "baz")
1090    baz2 = proto_module::Baz.new(msg: "quux")
1091    proto_module::Foo.encode_json(proto_module::Foo.new)
1092    proto_module::Foo.encode_json(proto_module::Foo.new(bar: bar))
1093    proto_module::Foo.encode_json(proto_module::Foo.new(bar: bar, baz: [baz1, baz2]))
1094  end
1095
1096  def test_json_empty
1097    assert proto_module::TestMessage.encode_json(proto_module::TestMessage.new) == '{}'
1098  end
1099
1100  def test_json_emit_defaults
1101    # TODO: Fix JSON in JRuby version.
1102    return if RUBY_PLATFORM == "java"
1103    m = proto_module::TestMessage.new
1104
1105    expected = {
1106      optionalInt32: 0,
1107      optionalInt64: "0",
1108      optionalUint32: 0,
1109      optionalUint64: "0",
1110      optionalBool: false,
1111      optionalFloat: 0,
1112      optionalDouble: 0,
1113      optionalString: "",
1114      optionalBytes: "",
1115      optionalEnum: "Default",
1116      repeatedInt32: [],
1117      repeatedInt64: [],
1118      repeatedUint32: [],
1119      repeatedUint64: [],
1120      repeatedBool: [],
1121      repeatedFloat: [],
1122      repeatedDouble: [],
1123      repeatedString: [],
1124      repeatedBytes: [],
1125      repeatedMsg: [],
1126      repeatedEnum: []
1127    }
1128
1129    actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true)
1130
1131    assert_equal expected, JSON.parse(actual, :symbolize_names => true)
1132  end
1133
1134  def test_json_emit_defaults_submsg
1135    # TODO: Fix JSON in JRuby version.
1136    return if RUBY_PLATFORM == "java"
1137    m = proto_module::TestMessage.new(optional_msg: proto_module::TestMessage2.new)
1138
1139    expected = {
1140      optionalInt32: 0,
1141      optionalInt64: "0",
1142      optionalUint32: 0,
1143      optionalUint64: "0",
1144      optionalBool: false,
1145      optionalFloat: 0,
1146      optionalDouble: 0,
1147      optionalString: "",
1148      optionalBytes: "",
1149      optionalMsg: {foo: 0},
1150      optionalEnum: "Default",
1151      repeatedInt32: [],
1152      repeatedInt64: [],
1153      repeatedUint32: [],
1154      repeatedUint64: [],
1155      repeatedBool: [],
1156      repeatedFloat: [],
1157      repeatedDouble: [],
1158      repeatedString: [],
1159      repeatedBytes: [],
1160      repeatedMsg: [],
1161      repeatedEnum: []
1162    }
1163
1164    actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true)
1165
1166    assert_equal expected, JSON.parse(actual, :symbolize_names => true)
1167  end
1168
1169  def test_json_emit_defaults_repeated_submsg
1170    # TODO: Fix JSON in JRuby version.
1171    return if RUBY_PLATFORM == "java"
1172    m = proto_module::TestMessage.new(repeated_msg: [proto_module::TestMessage2.new])
1173
1174    expected = {
1175      optionalInt32: 0,
1176      optionalInt64: "0",
1177      optionalUint32: 0,
1178      optionalUint64: "0",
1179      optionalBool: false,
1180      optionalFloat: 0,
1181      optionalDouble: 0,
1182      optionalString: "",
1183      optionalBytes: "",
1184      optionalEnum: "Default",
1185      repeatedInt32: [],
1186      repeatedInt64: [],
1187      repeatedUint32: [],
1188      repeatedUint64: [],
1189      repeatedBool: [],
1190      repeatedFloat: [],
1191      repeatedDouble: [],
1192      repeatedString: [],
1193      repeatedBytes: [],
1194      repeatedMsg: [{foo: 0}],
1195      repeatedEnum: []
1196    }
1197
1198    actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true)
1199
1200    assert_equal expected, JSON.parse(actual, :symbolize_names => true)
1201  end
1202
1203  def value_from_ruby(value)
1204    ret = Google::Protobuf::Value.new
1205    case value
1206    when String
1207      ret.string_value = value
1208    when Google::Protobuf::Struct
1209      ret.struct_value = value
1210    when Hash
1211      ret.struct_value = struct_from_ruby(value)
1212    when Google::Protobuf::ListValue
1213      ret.list_value = value
1214    when Array
1215      ret.list_value = list_from_ruby(value)
1216    else
1217      @log.error "Unknown type: #{value.class}"
1218      raise Google::Protobuf::Error, "Unknown type: #{value.class}"
1219    end
1220    ret
1221  end
1222
1223  def list_from_ruby(arr)
1224    ret = Google::Protobuf::ListValue.new
1225    arr.each do |v|
1226      ret.values << value_from_ruby(v)
1227    end
1228    ret
1229  end
1230
1231  def struct_from_ruby(hash)
1232    ret = Google::Protobuf::Struct.new
1233    hash.each do |k, v|
1234      ret.fields[k] ||= value_from_ruby(v)
1235    end
1236    ret
1237  end
1238
1239  def test_deep_json
1240    # will not overflow
1241    json = '{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":'\
1242           '{"a":{"a":{"a":{"a":{}}}}}}}}}}}}}}}}'
1243
1244    struct = struct_from_ruby(JSON.parse(json))
1245    assert_equal json, struct.to_json
1246
1247    encoded = proto_module::MyRepeatedStruct.encode(
1248      proto_module::MyRepeatedStruct.new(structs: [proto_module::MyStruct.new(struct: struct)]))
1249    assert_equal json, proto_module::MyRepeatedStruct.decode(encoded).structs[0].struct.to_json
1250
1251    # will overflow
1252    json = '{"a":{"a":{"a":[{"a":{"a":[{"a":[{"a":{"a":[{"a":[{"a":'\
1253           '{"a":[{"a":[{"a":{"a":{"a":[{"a":"a"}]}}}]}]}}]}]}}]}]}}]}}}'
1254
1255    struct = struct_from_ruby(JSON.parse(json))
1256    assert_equal json, struct.to_json
1257
1258    assert_raise(RuntimeError, "Maximum recursion depth exceeded during encoding") do
1259      proto_module::MyRepeatedStruct.encode(
1260        proto_module::MyRepeatedStruct.new(structs: [proto_module::MyStruct.new(struct: struct)]))
1261    end
1262  end
1263
1264  def test_comparison_with_arbitrary_object
1265    assert proto_module::TestMessage.new != nil
1266  end
1267
1268  def test_wrappers_set_to_default
1269    run_asserts = ->(m) {
1270      assert_equal 0.0, m.double.value
1271      assert_equal 0.0, m.float.value
1272      assert_equal 0, m.int32.value
1273      assert_equal 0, m.int64.value
1274      assert_equal 0, m.uint32.value
1275      assert_equal 0, m.uint64.value
1276      assert_equal false, m.bool.value
1277      assert_equal '', m.string.value
1278      assert_equal '', m.bytes.value
1279    }
1280
1281    m = proto_module::Wrapper.new(
1282      double: Google::Protobuf::DoubleValue.new(value: 0.0),
1283      float: Google::Protobuf::FloatValue.new(value: 0.0),
1284      int32: Google::Protobuf::Int32Value.new(value: 0),
1285      int64: Google::Protobuf::Int64Value.new(value: 0),
1286      uint32: Google::Protobuf::UInt32Value.new(value: 0),
1287      uint64: Google::Protobuf::UInt64Value.new(value: 0),
1288      bool: Google::Protobuf::BoolValue.new(value: false),
1289      string: Google::Protobuf::StringValue.new(value: ""),
1290      bytes: Google::Protobuf::BytesValue.new(value: ''),
1291    )
1292
1293    run_asserts.call(m)
1294    m2 = proto_module::Wrapper.decode(m.to_proto)
1295    run_asserts.call(m2)
1296    m3 = proto_module::Wrapper.decode_json(m.to_json)
1297  end
1298
1299  def test_wrapper_getters
1300    run_asserts = ->(m) {
1301      assert_equal 2.0, m.double_as_value
1302      assert_equal 2.0, m.double.value
1303      assert_equal 2.0, m.double_as_value
1304
1305      assert_equal 4.0, m.float_as_value
1306      assert_equal 4.0, m.float.value
1307      assert_equal 4.0, m.float_as_value
1308
1309      assert_equal 3, m.int32_as_value
1310      assert_equal 3, m.int32.value
1311      assert_equal 3, m.int32_as_value
1312
1313      assert_equal 4, m.int64_as_value
1314      assert_equal 4, m.int64.value
1315      assert_equal 4, m.int64_as_value
1316
1317      assert_equal 5, m.uint32_as_value
1318      assert_equal 5, m.uint32.value
1319      assert_equal 5, m.uint32_as_value
1320
1321      assert_equal 6, m.uint64_as_value
1322      assert_equal 6, m.uint64.value
1323      assert_equal 6, m.uint64_as_value
1324
1325      assert_equal true, m.bool_as_value
1326      assert_equal true, m.bool.value
1327      assert_equal true, m.bool_as_value
1328
1329      assert_equal "st\nr", m.string_as_value
1330      assert_equal "st\nr", m.string.value
1331      assert_equal "st\nr", m.string_as_value
1332
1333      assert_equal 'fun', m.bytes_as_value
1334      assert_equal 'fun', m.bytes.value
1335      assert_equal 'fun', m.bytes_as_value
1336    }
1337
1338    m = proto_module::Wrapper.new(
1339      double: Google::Protobuf::DoubleValue.new(value: 2.0),
1340      float: Google::Protobuf::FloatValue.new(value: 4.0),
1341      int32: Google::Protobuf::Int32Value.new(value: 3),
1342      int64: Google::Protobuf::Int64Value.new(value: 4),
1343      uint32: Google::Protobuf::UInt32Value.new(value: 5),
1344      uint64: Google::Protobuf::UInt64Value.new(value: 6),
1345      bool: Google::Protobuf::BoolValue.new(value: true),
1346      string: Google::Protobuf::StringValue.new(value: "st\nr"),
1347      bytes: Google::Protobuf::BytesValue.new(value: 'fun'),
1348      real_string: '100'
1349    )
1350
1351    run_asserts.call(m)
1352    serialized = proto_module::Wrapper::encode(m)
1353    m2 = proto_module::Wrapper::decode(serialized)
1354    run_asserts.call(m2)
1355
1356    # Test the case where we are serializing directly from the parsed form
1357    # (before anything lazy is materialized).
1358    m3 = proto_module::Wrapper::decode(serialized)
1359    serialized2 = proto_module::Wrapper::encode(m3)
1360    m4 = proto_module::Wrapper::decode(serialized2)
1361    run_asserts.call(m4)
1362
1363    # Test that the lazy form compares equal to the expanded form.
1364    m5 = proto_module::Wrapper::decode(serialized2)
1365    assert_equal m5, m
1366
1367    serialized_json = proto_module::Wrapper::encode_json(m)
1368    m6 = proto_module::Wrapper::decode_json(serialized_json)
1369    assert_equal m6, m
1370  end
1371
1372  def test_repeated_wrappers
1373    run_asserts = ->(m) {
1374      assert_equal 2.0, m.repeated_double[0].value
1375      assert_equal 4.0, m.repeated_float[0].value
1376      assert_equal 3, m.repeated_int32[0].value
1377      assert_equal 4, m.repeated_int64[0].value
1378      assert_equal 5, m.repeated_uint32[0].value
1379      assert_equal 6, m.repeated_uint64[0].value
1380      assert_equal true, m.repeated_bool[0].value
1381      assert_equal 'str', m.repeated_string[0].value
1382      assert_equal 'fun', m.repeated_bytes[0].value
1383    }
1384
1385    m = proto_module::Wrapper.new(
1386      repeated_double: [Google::Protobuf::DoubleValue.new(value: 2.0)],
1387      repeated_float: [Google::Protobuf::FloatValue.new(value: 4.0)],
1388      repeated_int32: [Google::Protobuf::Int32Value.new(value: 3)],
1389      repeated_int64: [Google::Protobuf::Int64Value.new(value: 4)],
1390      repeated_uint32: [Google::Protobuf::UInt32Value.new(value: 5)],
1391      repeated_uint64: [Google::Protobuf::UInt64Value.new(value: 6)],
1392      repeated_bool: [Google::Protobuf::BoolValue.new(value: true)],
1393      repeated_string: [Google::Protobuf::StringValue.new(value: 'str')],
1394      repeated_bytes: [Google::Protobuf::BytesValue.new(value: 'fun')],
1395    )
1396
1397    run_asserts.call(m)
1398    serialized = proto_module::Wrapper::encode(m)
1399    m2 = proto_module::Wrapper::decode(serialized)
1400    run_asserts.call(m2)
1401
1402    # Test the case where we are serializing directly from the parsed form
1403    # (before anything lazy is materialized).
1404    m3 = proto_module::Wrapper::decode(serialized)
1405    serialized2 = proto_module::Wrapper::encode(m3)
1406    m4 = proto_module::Wrapper::decode(serialized2)
1407    run_asserts.call(m4)
1408
1409    # Test that the lazy form compares equal to the expanded form.
1410    m5 = proto_module::Wrapper::decode(serialized2)
1411    assert_equal m5, m
1412
1413    # Test JSON.
1414    serialized_json = proto_module::Wrapper::encode_json(m5)
1415    m6 = proto_module::Wrapper::decode_json(serialized_json)
1416    run_asserts.call(m6)
1417    assert_equal m6, m
1418  end
1419
1420  def test_oneof_wrappers
1421    run_test = ->(m) {
1422      serialized = proto_module::Wrapper::encode(m)
1423      m2 = proto_module::Wrapper::decode(serialized)
1424
1425      # Encode directly from lazy form.
1426      serialized2 = proto_module::Wrapper::encode(m2)
1427
1428      assert_equal m, m2
1429      assert_equal serialized, serialized2
1430
1431      serialized_json = proto_module::Wrapper::encode_json(m)
1432      m3 = proto_module::Wrapper::decode_json(serialized_json)
1433      assert_equal m, m3
1434    }
1435
1436    m = proto_module::Wrapper.new()
1437
1438    run_test.call(m)
1439    m.oneof_double_as_value = 2.0
1440    run_test.call(m)
1441    m.oneof_float_as_value = 4.0
1442    run_test.call(m)
1443    m.oneof_int32_as_value = 3
1444    run_test.call(m)
1445    m.oneof_int64_as_value = 5
1446    run_test.call(m)
1447    m.oneof_uint32_as_value = 6
1448    run_test.call(m)
1449    m.oneof_uint64_as_value = 7
1450    run_test.call(m)
1451    m.oneof_string_as_value = 'str'
1452    run_test.call(m)
1453    m.oneof_bytes_as_value = 'fun'
1454    run_test.call(m)
1455  end
1456
1457  def test_top_level_wrappers
1458    # We don't expect anyone to do this, but we should also make sure it does
1459    # the right thing.
1460    run_test = ->(klass, val) {
1461      m = klass.new(value: val)
1462      serialized = klass::encode(m)
1463      m2 = klass::decode(serialized)
1464
1465      # Encode directly from lazy form.
1466      serialized2 = klass::encode(m2)
1467
1468      assert_equal m, m2
1469      assert_equal serialized, serialized2
1470
1471      serialized_json = klass::encode_json(m)
1472
1473      # This is nonsensical to do and does not work.  There is no good reason
1474      # to parse a wrapper type directly.
1475      assert_raise(RuntimeError) { klass::decode_json(serialized_json) }
1476    }
1477
1478    run_test.call(Google::Protobuf::DoubleValue, 2.0)
1479    run_test.call(Google::Protobuf::FloatValue, 4.0)
1480    run_test.call(Google::Protobuf::Int32Value, 3)
1481    run_test.call(Google::Protobuf::Int64Value, 4)
1482    run_test.call(Google::Protobuf::UInt32Value, 5)
1483    run_test.call(Google::Protobuf::UInt64Value, 6)
1484    run_test.call(Google::Protobuf::BoolValue, true)
1485    run_test.call(Google::Protobuf::StringValue, 'str')
1486    run_test.call(Google::Protobuf::BytesValue, 'fun')
1487  end
1488
1489  def test_wrapper_setters_as_value
1490    run_asserts = ->(m) {
1491      m.double_as_value = 4.8
1492      assert_equal 4.8, m.double_as_value
1493      assert_equal Google::Protobuf::DoubleValue.new(value: 4.8), m.double
1494      m.float_as_value = 2.4
1495      assert_in_delta 2.4, m.float_as_value
1496      assert_in_delta Google::Protobuf::FloatValue.new(value: 2.4).value, m.float.value
1497      m.int32_as_value = 5
1498      assert_equal 5, m.int32_as_value
1499      assert_equal Google::Protobuf::Int32Value.new(value: 5), m.int32
1500      m.int64_as_value = 15
1501      assert_equal 15, m.int64_as_value
1502      assert_equal Google::Protobuf::Int64Value.new(value: 15), m.int64
1503      m.uint32_as_value = 50
1504      assert_equal 50, m.uint32_as_value
1505      assert_equal Google::Protobuf::UInt32Value.new(value: 50), m.uint32
1506      m.uint64_as_value = 500
1507      assert_equal 500, m.uint64_as_value
1508      assert_equal Google::Protobuf::UInt64Value.new(value: 500), m.uint64
1509      m.bool_as_value = false
1510      assert_equal false, m.bool_as_value
1511      assert_equal Google::Protobuf::BoolValue.new(value: false), m.bool
1512      m.string_as_value = 'xy'
1513      assert_equal 'xy', m.string_as_value
1514      assert_equal Google::Protobuf::StringValue.new(value: 'xy'), m.string
1515      m.bytes_as_value = '123'
1516      assert_equal '123', m.bytes_as_value
1517      assert_equal Google::Protobuf::BytesValue.new(value: '123'), m.bytes
1518
1519      m.double_as_value = nil
1520      assert_nil m.double
1521      assert_nil m.double_as_value
1522      m.float_as_value = nil
1523      assert_nil m.float
1524      assert_nil m.float_as_value
1525      m.int32_as_value = nil
1526      assert_nil m.int32
1527      assert_nil m.int32_as_value
1528      m.int64_as_value = nil
1529      assert_nil m.int64
1530      assert_nil m.int64_as_value
1531      m.uint32_as_value = nil
1532      assert_nil m.uint32
1533      assert_nil m.uint32_as_value
1534      m.uint64_as_value = nil
1535      assert_nil m.uint64
1536      assert_nil m.uint64_as_value
1537      m.bool_as_value = nil
1538      assert_nil m.bool
1539      assert_nil m.bool_as_value
1540      m.string_as_value = nil
1541      assert_nil m.string
1542      assert_nil m.string_as_value
1543      m.bytes_as_value = nil
1544      assert_nil m.bytes
1545      assert_nil m.bytes_as_value
1546    }
1547
1548    m = proto_module::Wrapper.new
1549
1550    m2 = proto_module::Wrapper.new(
1551      double: Google::Protobuf::DoubleValue.new(value: 2.0),
1552      float: Google::Protobuf::FloatValue.new(value: 4.0),
1553      int32: Google::Protobuf::Int32Value.new(value: 3),
1554      int64: Google::Protobuf::Int64Value.new(value: 4),
1555      uint32: Google::Protobuf::UInt32Value.new(value: 5),
1556      uint64: Google::Protobuf::UInt64Value.new(value: 6),
1557      bool: Google::Protobuf::BoolValue.new(value: true),
1558      string: Google::Protobuf::StringValue.new(value: 'str'),
1559      bytes: Google::Protobuf::BytesValue.new(value: 'fun'),
1560      real_string: '100'
1561    )
1562
1563    run_asserts.call(m2)
1564
1565    serialized = proto_module::Wrapper::encode(m2)
1566    m3 = proto_module::Wrapper::decode(serialized)
1567    run_asserts.call(m3)
1568  end
1569
1570  def test_wrapper_setters
1571    run_asserts = ->(m) {
1572      m.double = Google::Protobuf::DoubleValue.new(value: 4.8)
1573      assert_equal 4.8, m.double_as_value
1574      assert_equal Google::Protobuf::DoubleValue.new(value: 4.8), m.double
1575      m.float = Google::Protobuf::FloatValue.new(value: 2.4)
1576      assert_in_delta 2.4, m.float_as_value
1577      assert_in_delta Google::Protobuf::FloatValue.new(value: 2.4).value, m.float.value
1578      m.int32 = Google::Protobuf::Int32Value.new(value: 5)
1579      assert_equal 5, m.int32_as_value
1580      assert_equal Google::Protobuf::Int32Value.new(value: 5), m.int32
1581      m.int64 = Google::Protobuf::Int64Value.new(value: 15)
1582      assert_equal 15, m.int64_as_value
1583      assert_equal Google::Protobuf::Int64Value.new(value: 15), m.int64
1584      m.uint32 = Google::Protobuf::UInt32Value.new(value: 50)
1585      assert_equal 50, m.uint32_as_value
1586      assert_equal Google::Protobuf::UInt32Value.new(value: 50), m.uint32
1587      m.uint64 = Google::Protobuf::UInt64Value.new(value: 500)
1588      assert_equal 500, m.uint64_as_value
1589      assert_equal Google::Protobuf::UInt64Value.new(value: 500), m.uint64
1590      m.bool = Google::Protobuf::BoolValue.new(value: false)
1591      assert_equal false, m.bool_as_value
1592      assert_equal Google::Protobuf::BoolValue.new(value: false), m.bool
1593      m.string = Google::Protobuf::StringValue.new(value: 'xy')
1594      assert_equal 'xy', m.string_as_value
1595      assert_equal Google::Protobuf::StringValue.new(value: 'xy'), m.string
1596      m.bytes = Google::Protobuf::BytesValue.new(value: '123')
1597      assert_equal '123', m.bytes_as_value
1598      assert_equal Google::Protobuf::BytesValue.new(value: '123'), m.bytes
1599
1600      m.double = nil
1601      assert_nil m.double
1602      assert_nil m.double_as_value
1603      m.float = nil
1604      assert_nil m.float
1605      assert_nil m.float_as_value
1606      m.int32 = nil
1607      assert_nil m.int32
1608      assert_nil m.int32_as_value
1609      m.int64 = nil
1610      assert_nil m.int64
1611      assert_nil m.int64_as_value
1612      m.uint32 = nil
1613      assert_nil m.uint32
1614      assert_nil m.uint32_as_value
1615      m.uint64 = nil
1616      assert_nil m.uint64
1617      assert_nil m.uint64_as_value
1618      m.bool = nil
1619      assert_nil m.bool
1620      assert_nil m.bool_as_value
1621      m.string = nil
1622      assert_nil m.string
1623      assert_nil m.string_as_value
1624      m.bytes = nil
1625      assert_nil m.bytes
1626      assert_nil m.bytes_as_value
1627    }
1628
1629    m = proto_module::Wrapper.new
1630    run_asserts.call(m)
1631
1632    m2 = proto_module::Wrapper.new(
1633      double: Google::Protobuf::DoubleValue.new(value: 2.0),
1634      float: Google::Protobuf::FloatValue.new(value: 4.0),
1635      int32: Google::Protobuf::Int32Value.new(value: 3),
1636      int64: Google::Protobuf::Int64Value.new(value: 4),
1637      uint32: Google::Protobuf::UInt32Value.new(value: 5),
1638      uint64: Google::Protobuf::UInt64Value.new(value: 6),
1639      bool: Google::Protobuf::BoolValue.new(value: true),
1640      string: Google::Protobuf::StringValue.new(value: 'str'),
1641      bytes: Google::Protobuf::BytesValue.new(value: 'fun'),
1642      real_string: '100'
1643    )
1644
1645    run_asserts.call(m2)
1646
1647    serialized = proto_module::Wrapper::encode(m2)
1648    m3 = proto_module::Wrapper::decode(serialized)
1649    run_asserts.call(m3)
1650  end
1651
1652  def test_wrappers_only
1653    m = proto_module::Wrapper.new(real_string: 'hi', string_in_oneof: 'there')
1654
1655    assert_raise(NoMethodError) { m.real_string_as_value }
1656    assert_raise(NoMethodError) { m.as_value }
1657    assert_raise(NoMethodError) { m._as_value }
1658    assert_raise(NoMethodError) { m.string_in_oneof_as_value }
1659
1660    m = proto_module::Wrapper.new
1661    m.string_as_value = 'you'
1662    assert_equal 'you', m.string.value
1663    assert_equal 'you', m.string_as_value
1664    assert_raise(NoMethodError) { m.string_ }
1665    assert_raise(NoMethodError) { m.string_X }
1666    assert_raise(NoMethodError) { m.string_XX }
1667    assert_raise(NoMethodError) { m.string_XXX }
1668    assert_raise(NoMethodError) { m.string_XXXX }
1669    assert_raise(NoMethodError) { m.string_XXXXX }
1670    assert_raise(NoMethodError) { m.string_XXXXXX }
1671    assert_raise(NoMethodError) { m.string_XXXXXXX }
1672    assert_raise(NoMethodError) { m.string_XXXXXXXX }
1673    assert_raise(NoMethodError) { m.string_XXXXXXXXX }
1674    assert_raise(NoMethodError) { m.string_XXXXXXXXXX }
1675  end
1676
1677  def test_converts_time
1678    m = proto_module::TimeMessage.new
1679
1680    m.timestamp = Google::Protobuf::Timestamp.new(seconds: 5, nanos: 6)
1681    assert_kind_of Google::Protobuf::Timestamp, m.timestamp
1682    assert_equal 5, m.timestamp.seconds
1683    assert_equal 6, m.timestamp.nanos
1684
1685    m.timestamp = Time.at(9466, 123456.789)
1686    assert_equal Google::Protobuf::Timestamp.new(seconds: 9466, nanos: 123456789), m.timestamp
1687
1688    m = proto_module::TimeMessage.new(timestamp: Time.at(1))
1689    assert_equal Google::Protobuf::Timestamp.new(seconds: 1, nanos: 0), m.timestamp
1690
1691    assert_raise(Google::Protobuf::TypeError) { m.timestamp = 2 }
1692    assert_raise(Google::Protobuf::TypeError) { m.timestamp = 2.4 }
1693    assert_raise(Google::Protobuf::TypeError) { m.timestamp = '4' }
1694    assert_raise(Google::Protobuf::TypeError) { m.timestamp = proto_module::TimeMessage.new }
1695
1696    def test_time(year, month, day)
1697      str = ("\"%04d-%02d-%02dT00:00:00.000+00:00\"" % [year, month, day])
1698      t = Google::Protobuf::Timestamp.decode_json(str)
1699      time = Time.new(year, month, day, 0, 0, 0, "+00:00")
1700      assert_equal t.seconds, time.to_i
1701    end
1702
1703    (1970..2010).each do |year|
1704      test_time(year, 2, 28)
1705      test_time(year, 3, 01)
1706    end
1707  end
1708
1709  def test_converts_duration
1710    m = proto_module::TimeMessage.new
1711
1712    m.duration = Google::Protobuf::Duration.new(seconds: 2, nanos: 22)
1713    assert_kind_of Google::Protobuf::Duration, m.duration
1714    assert_equal 2, m.duration.seconds
1715    assert_equal 22, m.duration.nanos
1716
1717    m.duration = 10.5
1718    assert_equal Google::Protobuf::Duration.new(seconds: 10, nanos: 500_000_000), m.duration
1719
1720    m.duration = 200
1721    assert_equal Google::Protobuf::Duration.new(seconds: 200, nanos: 0), m.duration
1722
1723    m.duration = Rational(3, 2)
1724    assert_equal Google::Protobuf::Duration.new(seconds: 1, nanos: 500_000_000), m.duration
1725
1726    m.duration = BigDecimal("5")
1727    assert_equal Google::Protobuf::Duration.new(seconds: 5, nanos: 0), m.duration
1728
1729    m = proto_module::TimeMessage.new(duration: 1.1)
1730    assert_equal Google::Protobuf::Duration.new(seconds: 1, nanos: 100_000_000), m.duration
1731
1732    assert_raise(Google::Protobuf::TypeError) { m.duration = '2' }
1733    assert_raise(Google::Protobuf::TypeError) { m.duration = proto_module::TimeMessage.new }
1734  end
1735
1736  def test_freeze
1737    m = proto_module::TestMessage.new
1738    m.optional_int32 = 10
1739    m.freeze
1740
1741    frozen_error = assert_raise(FrozenErrorType) { m.optional_int32 = 20 }
1742    assert_match "can't modify frozen #{proto_module}::TestMessage", frozen_error.message
1743    assert_equal 10, m.optional_int32
1744    assert_equal true, m.frozen?
1745
1746    assert_raise(FrozenErrorType) { m.optional_int64 = 2 }
1747    assert_raise(FrozenErrorType) { m.optional_uint32 = 3 }
1748    assert_raise(FrozenErrorType) { m.optional_uint64 = 4 }
1749    assert_raise(FrozenErrorType) { m.optional_bool = true }
1750    assert_raise(FrozenErrorType) { m.optional_float = 6.0 }
1751    assert_raise(FrozenErrorType) { m.optional_double = 7.0 }
1752    assert_raise(FrozenErrorType) { m.optional_string = '8' }
1753    assert_raise(FrozenErrorType) { m.optional_bytes = nil }
1754    assert_raise(FrozenErrorType) { m.optional_msg = proto_module::TestMessage2.new }
1755    assert_raise(FrozenErrorType) { m.optional_enum = :A }
1756    assert_raise(FrozenErrorType) { m.repeated_int32 = 1 }
1757    assert_raise(FrozenErrorType) { m.repeated_int64 = 2 }
1758    assert_raise(FrozenErrorType) { m.repeated_uint32 = 3 }
1759    assert_raise(FrozenErrorType) { m.repeated_uint64 = 4 }
1760    assert_raise(FrozenErrorType) { m.repeated_bool = true }
1761    assert_raise(FrozenErrorType) { m.repeated_float = 6.0 }
1762    assert_raise(FrozenErrorType) { m.repeated_double = 7.0 }
1763    assert_raise(FrozenErrorType) { m.repeated_string = '8' }
1764    assert_raise(FrozenErrorType) { m.repeated_bytes = nil }
1765    assert_raise(FrozenErrorType) { m.repeated_msg = proto_module::TestMessage2.new }
1766    assert_raise(FrozenErrorType) { m.repeated_enum = :A }
1767  end
1768
1769  def test_eq
1770    m1 = proto_module::TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
1771    m2 = proto_module::TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
1772
1773    h = {}
1774    h[m1] = :yes
1775
1776    assert m1 == m2
1777    assert m1.eql?(m2)
1778    assert m1.hash == m2.hash
1779    assert h[m1] == :yes
1780    assert h[m2] == :yes
1781
1782    m1.optional_int32 = 2
1783
1784    assert m1 != m2
1785    assert !m1.eql?(m2)
1786    assert m1.hash != m2.hash
1787    assert_nil h[m2]
1788  end
1789end
1790