• 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 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    m['a.b'] = 4
906    assert m['a.b'] == 4
907  end
908
909  def test_int_ranges
910    m = proto_module::TestMessage.new
911
912    m.optional_int32 = 0
913    m.optional_int32 = -0x8000_0000
914    m.optional_int32 = +0x7fff_ffff
915    m.optional_int32 = 1.0
916    m.optional_int32 = -1.0
917    m.optional_int32 = 2e9
918    assert_raise RangeError do
919      m.optional_int32 = -0x8000_0001
920    end
921    assert_raise RangeError do
922      m.optional_int32 = +0x8000_0000
923    end
924    assert_raise RangeError do
925      m.optional_int32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
926    end
927    assert_raise RangeError do
928      m.optional_int32 = 1e12
929    end
930    assert_raise RangeError do
931      m.optional_int32 = 1.5
932    end
933
934    m.optional_uint32 = 0
935    m.optional_uint32 = +0xffff_ffff
936    m.optional_uint32 = 1.0
937    m.optional_uint32 = 4e9
938    assert_raise RangeError do
939      m.optional_uint32 = -1
940    end
941    assert_raise RangeError do
942      m.optional_uint32 = -1.5
943    end
944    assert_raise RangeError do
945      m.optional_uint32 = -1.5e12
946    end
947    assert_raise RangeError do
948      m.optional_uint32 = -0x1000_0000_0000_0000
949    end
950    assert_raise RangeError do
951      m.optional_uint32 = +0x1_0000_0000
952    end
953    assert_raise RangeError do
954      m.optional_uint32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
955    end
956    assert_raise RangeError do
957      m.optional_uint32 = 1e12
958    end
959    assert_raise RangeError do
960      m.optional_uint32 = 1.5
961    end
962
963    m.optional_int64 = 0
964    m.optional_int64 = -0x8000_0000_0000_0000
965    m.optional_int64 = +0x7fff_ffff_ffff_ffff
966    m.optional_int64 = 1.0
967    m.optional_int64 = -1.0
968    m.optional_int64 = 8e18
969    m.optional_int64 = -8e18
970    assert_raise RangeError do
971      m.optional_int64 = -0x8000_0000_0000_0001
972    end
973    assert_raise RangeError do
974      m.optional_int64 = +0x8000_0000_0000_0000
975    end
976    assert_raise RangeError do
977      m.optional_int64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
978    end
979    assert_raise RangeError do
980      m.optional_int64 = 1e50
981    end
982    assert_raise RangeError do
983      m.optional_int64 = 1.5
984    end
985
986    m.optional_uint64 = 0
987    m.optional_uint64 = +0xffff_ffff_ffff_ffff
988    m.optional_uint64 = 1.0
989    m.optional_uint64 = 16e18
990    assert_raise RangeError do
991      m.optional_uint64 = -1
992    end
993    assert_raise RangeError do
994      m.optional_uint64 = -1.5
995    end
996    assert_raise RangeError do
997      m.optional_uint64 = -1.5e12
998    end
999    assert_raise RangeError do
1000      m.optional_uint64 = -0x1_0000_0000_0000_0000
1001    end
1002    assert_raise RangeError do
1003      m.optional_uint64 = +0x1_0000_0000_0000_0000
1004    end
1005    assert_raise RangeError do
1006      m.optional_uint64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
1007    end
1008    assert_raise RangeError do
1009      m.optional_uint64 = 1e50
1010    end
1011    assert_raise RangeError do
1012      m.optional_uint64 = 1.5
1013    end
1014  end
1015
1016  def test_stress_test
1017    m = proto_module::TestMessage.new
1018    m.optional_int32 = 42
1019    m.optional_int64 = 0x100000000
1020    m.optional_string = "hello world"
1021    10.times do m.repeated_msg.push proto_module::TestMessage2.new(:foo => 42) end
1022    10.times do m.repeated_string.push "hello world" end
1023
1024    data = proto_module::TestMessage.encode(m)
1025
1026    10_000.times do
1027      m = proto_module::TestMessage.decode(data)
1028      data_new = proto_module::TestMessage.encode(m)
1029      assert data_new == data
1030      data = data_new
1031    end
1032  end
1033
1034  def test_reflection
1035    m = proto_module::TestMessage.new(:optional_int32 => 1234)
1036    msgdef = m.class.descriptor
1037    assert msgdef.class == Google::Protobuf::Descriptor
1038    assert msgdef.any? {|field| field.name == "optional_int32"}
1039    optional_int32 = msgdef.lookup "optional_int32"
1040    assert optional_int32.class == Google::Protobuf::FieldDescriptor
1041    assert optional_int32 != nil
1042    assert optional_int32.name == "optional_int32"
1043    assert optional_int32.type == :int32
1044    optional_int32.set(m, 5678)
1045    assert m.optional_int32 == 5678
1046    m.optional_int32 = 1000
1047    assert optional_int32.get(m) == 1000
1048
1049    optional_msg = msgdef.lookup "optional_msg"
1050    assert optional_msg.subtype == proto_module::TestMessage2.descriptor
1051
1052    optional_msg.set(m, optional_msg.subtype.msgclass.new)
1053
1054    assert msgdef.msgclass == proto_module::TestMessage
1055
1056    optional_enum = msgdef.lookup "optional_enum"
1057    assert optional_enum.subtype == proto_module::TestEnum.descriptor
1058    assert optional_enum.subtype.class == Google::Protobuf::EnumDescriptor
1059    optional_enum.subtype.each do |k, v|
1060      # set with integer, check resolution to symbolic name
1061      optional_enum.set(m, v)
1062      assert optional_enum.get(m) == k
1063    end
1064  end
1065
1066  def test_json
1067    # TODO: Fix JSON in JRuby version.
1068    return if RUBY_PLATFORM == "java"
1069    m = proto_module::TestMessage.new(:optional_int32 => 1234,
1070                                      :optional_int64 => -0x1_0000_0000,
1071                                      :optional_uint32 => 0x8000_0000,
1072                                      :optional_uint64 => 0xffff_ffff_ffff_ffff,
1073                                      :optional_bool => true,
1074                                      :optional_float => 1.0,
1075                                      :optional_double => -1e100,
1076                                      :optional_string => "Test string",
1077                                      :optional_bytes => ["FFFFFFFF"].pack('H*'),
1078                                      :optional_msg => proto_module::TestMessage2.new(:foo => 42),
1079                                      :repeated_int32 => [1, 2, 3, 4],
1080                                      :repeated_string => ["a", "b", "c"],
1081                                      :repeated_bool => [true, false, true, false],
1082                                      :repeated_msg => [proto_module::TestMessage2.new(:foo => 1),
1083                                                        proto_module::TestMessage2.new(:foo => 2)])
1084
1085    json_text = proto_module::TestMessage.encode_json(m)
1086    m2 = proto_module::TestMessage.decode_json(json_text)
1087    puts m.inspect
1088    puts m2.inspect
1089    assert m == m2
1090
1091    # Crash case from GitHub issue 283.
1092    bar = proto_module::Bar.new(msg: "bar")
1093    baz1 = proto_module::Baz.new(msg: "baz")
1094    baz2 = proto_module::Baz.new(msg: "quux")
1095    proto_module::Foo.encode_json(proto_module::Foo.new)
1096    proto_module::Foo.encode_json(proto_module::Foo.new(bar: bar))
1097    proto_module::Foo.encode_json(proto_module::Foo.new(bar: bar, baz: [baz1, baz2]))
1098  end
1099
1100  def test_json_empty
1101    assert proto_module::TestMessage.encode_json(proto_module::TestMessage.new) == '{}'
1102  end
1103
1104  def test_json_emit_defaults
1105    # TODO: Fix JSON in JRuby version.
1106    return if RUBY_PLATFORM == "java"
1107    m = proto_module::TestMessage.new
1108
1109    expected = {
1110      optionalInt32: 0,
1111      optionalInt64: "0",
1112      optionalUint32: 0,
1113      optionalUint64: "0",
1114      optionalBool: false,
1115      optionalFloat: 0,
1116      optionalDouble: 0,
1117      optionalString: "",
1118      optionalBytes: "",
1119      optionalEnum: "Default",
1120      repeatedInt32: [],
1121      repeatedInt64: [],
1122      repeatedUint32: [],
1123      repeatedUint64: [],
1124      repeatedBool: [],
1125      repeatedFloat: [],
1126      repeatedDouble: [],
1127      repeatedString: [],
1128      repeatedBytes: [],
1129      repeatedMsg: [],
1130      repeatedEnum: []
1131    }
1132
1133    actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true)
1134
1135    assert JSON.parse(actual, :symbolize_names => true) == expected
1136  end
1137
1138  def test_json_emit_defaults_submsg
1139    # TODO: Fix JSON in JRuby version.
1140    return if RUBY_PLATFORM == "java"
1141    m = proto_module::TestMessage.new(optional_msg: proto_module::TestMessage2.new)
1142
1143    expected = {
1144      optionalInt32: 0,
1145      optionalInt64: "0",
1146      optionalUint32: 0,
1147      optionalUint64: "0",
1148      optionalBool: false,
1149      optionalFloat: 0,
1150      optionalDouble: 0,
1151      optionalString: "",
1152      optionalBytes: "",
1153      optionalMsg: {foo: 0},
1154      optionalEnum: "Default",
1155      repeatedInt32: [],
1156      repeatedInt64: [],
1157      repeatedUint32: [],
1158      repeatedUint64: [],
1159      repeatedBool: [],
1160      repeatedFloat: [],
1161      repeatedDouble: [],
1162      repeatedString: [],
1163      repeatedBytes: [],
1164      repeatedMsg: [],
1165      repeatedEnum: []
1166    }
1167
1168    actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true)
1169
1170    assert JSON.parse(actual, :symbolize_names => true) == expected
1171  end
1172
1173  def test_json_emit_defaults_repeated_submsg
1174    # TODO: Fix JSON in JRuby version.
1175    return if RUBY_PLATFORM == "java"
1176    m = proto_module::TestMessage.new(repeated_msg: [proto_module::TestMessage2.new])
1177
1178    expected = {
1179      optionalInt32: 0,
1180      optionalInt64: "0",
1181      optionalUint32: 0,
1182      optionalUint64: "0",
1183      optionalBool: false,
1184      optionalFloat: 0,
1185      optionalDouble: 0,
1186      optionalString: "",
1187      optionalBytes: "",
1188      optionalEnum: "Default",
1189      repeatedInt32: [],
1190      repeatedInt64: [],
1191      repeatedUint32: [],
1192      repeatedUint64: [],
1193      repeatedBool: [],
1194      repeatedFloat: [],
1195      repeatedDouble: [],
1196      repeatedString: [],
1197      repeatedBytes: [],
1198      repeatedMsg: [{foo: 0}],
1199      repeatedEnum: []
1200    }
1201
1202    actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true)
1203
1204    assert JSON.parse(actual, :symbolize_names => true) == expected
1205  end
1206
1207  def value_from_ruby(value)
1208    ret = Google::Protobuf::Value.new
1209    case value
1210    when String
1211      ret.string_value = value
1212    when Google::Protobuf::Struct
1213      ret.struct_value = value
1214    when Hash
1215      ret.struct_value = struct_from_ruby(value)
1216    when Google::Protobuf::ListValue
1217      ret.list_value = value
1218    when Array
1219      ret.list_value = list_from_ruby(value)
1220    else
1221      @log.error "Unknown type: #{value.class}"
1222      raise Google::Protobuf::Error, "Unknown type: #{value.class}"
1223    end
1224    ret
1225  end
1226
1227  def list_from_ruby(arr)
1228    ret = Google::Protobuf::ListValue.new
1229    arr.each do |v|
1230      ret.values << value_from_ruby(v)
1231    end
1232    ret
1233  end
1234
1235  def struct_from_ruby(hash)
1236    ret = Google::Protobuf::Struct.new
1237    hash.each do |k, v|
1238      ret.fields[k] ||= value_from_ruby(v)
1239    end
1240    ret
1241  end
1242
1243  def test_deep_json
1244    # will not overflow
1245    json = '{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":'\
1246           '{"a":{"a":{"a":{"a":{}}}}}}}}}}}}}}}}'
1247
1248    struct = struct_from_ruby(JSON.parse(json))
1249    assert_equal json, struct.to_json
1250
1251    encoded = proto_module::MyRepeatedStruct.encode(
1252      proto_module::MyRepeatedStruct.new(structs: [proto_module::MyStruct.new(struct: struct)]))
1253    assert_equal json, proto_module::MyRepeatedStruct.decode(encoded).structs[0].struct.to_json
1254
1255    # will overflow
1256    json = '{"a":{"a":{"a":[{"a":{"a":[{"a":[{"a":{"a":[{"a":[{"a":'\
1257           '{"a":[{"a":[{"a":{"a":{"a":[{"a":"a"}]}}}]}]}}]}]}}]}]}}]}}}'
1258
1259    struct = struct_from_ruby(JSON.parse(json))
1260    assert_equal json, struct.to_json
1261
1262    assert_raise(RuntimeError, "Maximum recursion depth exceeded during encoding") do
1263      proto_module::MyRepeatedStruct.encode(
1264        proto_module::MyRepeatedStruct.new(structs: [proto_module::MyStruct.new(struct: struct)]))
1265    end
1266  end
1267
1268  def test_comparison_with_arbitrary_object
1269    assert proto_module::TestMessage.new != nil
1270  end
1271
1272  def test_wrapper_getters
1273    m = proto_module::Wrapper.new(
1274      double: Google::Protobuf::DoubleValue.new(value: 2.0),
1275      float: Google::Protobuf::FloatValue.new(value: 4.0),
1276      int32: Google::Protobuf::Int32Value.new(value: 3),
1277      int64: Google::Protobuf::Int64Value.new(value: 4),
1278      uint32: Google::Protobuf::UInt32Value.new(value: 5),
1279      uint64: Google::Protobuf::UInt64Value.new(value: 6),
1280      bool: Google::Protobuf::BoolValue.new(value: true),
1281      string: Google::Protobuf::StringValue.new(value: 'str'),
1282      bytes: Google::Protobuf::BytesValue.new(value: 'fun'),
1283      real_string: '100'
1284    )
1285
1286    assert_equal 2.0, m.double_as_value
1287    assert_equal 2.0, m.double.value
1288    assert_equal 4.0, m.float_as_value
1289    assert_equal 4.0, m.float.value
1290    assert_equal 3, m.int32_as_value
1291    assert_equal 3, m.int32.value
1292    assert_equal 4, m.int64_as_value
1293    assert_equal 4, m.int64.value
1294    assert_equal 5, m.uint32_as_value
1295    assert_equal 5, m.uint32.value
1296    assert_equal 6, m.uint64_as_value
1297    assert_equal 6, m.uint64.value
1298    assert_equal true, m.bool_as_value
1299    assert_equal true, m.bool.value
1300    assert_equal 'str', m.string_as_value
1301    assert_equal 'str', m.string.value
1302    assert_equal 'fun', m.bytes_as_value
1303    assert_equal 'fun', m.bytes.value
1304  end
1305
1306  def test_wrapper_setters_as_value
1307    m = proto_module::Wrapper.new
1308
1309    m.double_as_value = 4.8
1310    assert_equal 4.8, m.double_as_value
1311    assert_equal Google::Protobuf::DoubleValue.new(value: 4.8), m.double
1312    m.float_as_value = 2.4
1313    assert_in_delta 2.4, m.float_as_value
1314    assert_in_delta Google::Protobuf::FloatValue.new(value: 2.4).value, m.float.value
1315    m.int32_as_value = 5
1316    assert_equal 5, m.int32_as_value
1317    assert_equal Google::Protobuf::Int32Value.new(value: 5), m.int32
1318    m.int64_as_value = 15
1319    assert_equal 15, m.int64_as_value
1320    assert_equal Google::Protobuf::Int64Value.new(value: 15), m.int64
1321    m.uint32_as_value = 50
1322    assert_equal 50, m.uint32_as_value
1323    assert_equal Google::Protobuf::UInt32Value.new(value: 50), m.uint32
1324    m.uint64_as_value = 500
1325    assert_equal 500, m.uint64_as_value
1326    assert_equal Google::Protobuf::UInt64Value.new(value: 500), m.uint64
1327    m.bool_as_value = false
1328    assert_equal false, m.bool_as_value
1329    assert_equal Google::Protobuf::BoolValue.new(value: false), m.bool
1330    m.string_as_value = 'xy'
1331    assert_equal 'xy', m.string_as_value
1332    assert_equal Google::Protobuf::StringValue.new(value: 'xy'), m.string
1333    m.bytes_as_value = '123'
1334    assert_equal '123', m.bytes_as_value
1335    assert_equal Google::Protobuf::BytesValue.new(value: '123'), m.bytes
1336
1337    m.double_as_value = nil
1338    assert_nil m.double
1339    assert_nil m.double_as_value
1340    m.float_as_value = nil
1341    assert_nil m.float
1342    assert_nil m.float_as_value
1343    m.int32_as_value = nil
1344    assert_nil m.int32
1345    assert_nil m.int32_as_value
1346    m.int64_as_value = nil
1347    assert_nil m.int64
1348    assert_nil m.int64_as_value
1349    m.uint32_as_value = nil
1350    assert_nil m.uint32
1351    assert_nil m.uint32_as_value
1352    m.uint64_as_value = nil
1353    assert_nil m.uint64
1354    assert_nil m.uint64_as_value
1355    m.bool_as_value = nil
1356    assert_nil m.bool
1357    assert_nil m.bool_as_value
1358    m.string_as_value = nil
1359    assert_nil m.string
1360    assert_nil m.string_as_value
1361    m.bytes_as_value = nil
1362    assert_nil m.bytes
1363    assert_nil m.bytes_as_value
1364  end
1365
1366  def test_wrapper_setters
1367    m = proto_module::Wrapper.new
1368
1369    m.double = Google::Protobuf::DoubleValue.new(value: 4.8)
1370    assert_equal 4.8, m.double_as_value
1371    assert_equal Google::Protobuf::DoubleValue.new(value: 4.8), m.double
1372    m.float = Google::Protobuf::FloatValue.new(value: 2.4)
1373    assert_in_delta 2.4, m.float_as_value
1374    assert_in_delta Google::Protobuf::FloatValue.new(value: 2.4).value, m.float.value
1375    m.int32 = Google::Protobuf::Int32Value.new(value: 5)
1376    assert_equal 5, m.int32_as_value
1377    assert_equal Google::Protobuf::Int32Value.new(value: 5), m.int32
1378    m.int64 = Google::Protobuf::Int64Value.new(value: 15)
1379    assert_equal 15, m.int64_as_value
1380    assert_equal Google::Protobuf::Int64Value.new(value: 15), m.int64
1381    m.uint32 = Google::Protobuf::UInt32Value.new(value: 50)
1382    assert_equal 50, m.uint32_as_value
1383    assert_equal Google::Protobuf::UInt32Value.new(value: 50), m.uint32
1384    m.uint64 = Google::Protobuf::UInt64Value.new(value: 500)
1385    assert_equal 500, m.uint64_as_value
1386    assert_equal Google::Protobuf::UInt64Value.new(value: 500), m.uint64
1387    m.bool = Google::Protobuf::BoolValue.new(value: false)
1388    assert_equal false, m.bool_as_value
1389    assert_equal Google::Protobuf::BoolValue.new(value: false), m.bool
1390    m.string = Google::Protobuf::StringValue.new(value: 'xy')
1391    assert_equal 'xy', m.string_as_value
1392    assert_equal Google::Protobuf::StringValue.new(value: 'xy'), m.string
1393    m.bytes = Google::Protobuf::BytesValue.new(value: '123')
1394    assert_equal '123', m.bytes_as_value
1395    assert_equal Google::Protobuf::BytesValue.new(value: '123'), m.bytes
1396
1397    m.double = nil
1398    assert_nil m.double
1399    assert_nil m.double_as_value
1400    m.float = nil
1401    assert_nil m.float
1402    assert_nil m.float_as_value
1403    m.int32 = nil
1404    assert_nil m.int32
1405    assert_nil m.int32_as_value
1406    m.int64 = nil
1407    assert_nil m.int64
1408    assert_nil m.int64_as_value
1409    m.uint32 = nil
1410    assert_nil m.uint32
1411    assert_nil m.uint32_as_value
1412    m.uint64 = nil
1413    assert_nil m.uint64
1414    assert_nil m.uint64_as_value
1415    m.bool = nil
1416    assert_nil m.bool
1417    assert_nil m.bool_as_value
1418    m.string = nil
1419    assert_nil m.string
1420    assert_nil m.string_as_value
1421    m.bytes = nil
1422    assert_nil m.bytes
1423    assert_nil m.bytes_as_value
1424  end
1425
1426  def test_wrappers_only
1427    m = proto_module::Wrapper.new(real_string: 'hi', oneof_string: 'there')
1428
1429    assert_raise(NoMethodError) { m.real_string_as_value }
1430    assert_raise(NoMethodError) { m.as_value }
1431    assert_raise(NoMethodError) { m._as_value }
1432    assert_raise(NoMethodError) { m.oneof_string_as_value }
1433
1434    m = proto_module::Wrapper.new
1435    m.string_as_value = 'you'
1436    assert_equal 'you', m.string.value
1437    assert_equal 'you', m.string_as_value
1438    assert_raise(NoMethodError) { m.string_ }
1439    assert_raise(NoMethodError) { m.string_X }
1440    assert_raise(NoMethodError) { m.string_XX }
1441    assert_raise(NoMethodError) { m.string_XXX }
1442    assert_raise(NoMethodError) { m.string_XXXX }
1443    assert_raise(NoMethodError) { m.string_XXXXX }
1444    assert_raise(NoMethodError) { m.string_XXXXXX }
1445    assert_raise(NoMethodError) { m.string_XXXXXXX }
1446    assert_raise(NoMethodError) { m.string_XXXXXXXX }
1447    assert_raise(NoMethodError) { m.string_XXXXXXXXX }
1448    assert_raise(NoMethodError) { m.string_XXXXXXXXXX }
1449  end
1450
1451  def test_converts_time
1452    m = proto_module::TimeMessage.new
1453
1454    m.timestamp = Google::Protobuf::Timestamp.new(seconds: 5, nanos: 6)
1455    assert_kind_of Google::Protobuf::Timestamp, m.timestamp
1456    assert_equal 5, m.timestamp.seconds
1457    assert_equal 6, m.timestamp.nanos
1458
1459    m.timestamp = Time.at(9466, 123456.789)
1460    assert_equal Google::Protobuf::Timestamp.new(seconds: 9466, nanos: 123456789), m.timestamp
1461
1462    m = proto_module::TimeMessage.new(timestamp: Time.at(1))
1463    assert_equal Google::Protobuf::Timestamp.new(seconds: 1, nanos: 0), m.timestamp
1464
1465    assert_raise(Google::Protobuf::TypeError) { m.timestamp = 2 }
1466    assert_raise(Google::Protobuf::TypeError) { m.timestamp = 2.4 }
1467    assert_raise(Google::Protobuf::TypeError) { m.timestamp = '4' }
1468    assert_raise(Google::Protobuf::TypeError) { m.timestamp = proto_module::TimeMessage.new }
1469  end
1470
1471  def test_converts_duration
1472    m = proto_module::TimeMessage.new
1473
1474    m.duration = Google::Protobuf::Duration.new(seconds: 2, nanos: 22)
1475    assert_kind_of Google::Protobuf::Duration, m.duration
1476    assert_equal 2, m.duration.seconds
1477    assert_equal 22, m.duration.nanos
1478
1479    m.duration = 10.5
1480    assert_equal Google::Protobuf::Duration.new(seconds: 10, nanos: 500_000_000), m.duration
1481
1482    m.duration = 200
1483    assert_equal Google::Protobuf::Duration.new(seconds: 200, nanos: 0), m.duration
1484
1485    m.duration = Rational(3, 2)
1486    assert_equal Google::Protobuf::Duration.new(seconds: 1, nanos: 500_000_000), m.duration
1487
1488    m.duration = BigDecimal.new("5")
1489    assert_equal Google::Protobuf::Duration.new(seconds: 5, nanos: 0), m.duration
1490
1491    m = proto_module::TimeMessage.new(duration: 1.1)
1492    assert_equal Google::Protobuf::Duration.new(seconds: 1, nanos: 100_000_000), m.duration
1493
1494    assert_raise(Google::Protobuf::TypeError) { m.duration = '2' }
1495    assert_raise(Google::Protobuf::TypeError) { m.duration = proto_module::TimeMessage.new }
1496  end
1497
1498  def test_freeze
1499    m = proto_module::TestMessage.new
1500    m.optional_int32 = 10
1501    m.freeze
1502
1503    frozen_error = assert_raise(FrozenErrorType) { m.optional_int32 = 20 }
1504    assert_equal "can't modify frozen #{proto_module}::TestMessage", frozen_error.message
1505    assert_equal 10, m.optional_int32
1506    assert_equal true, m.frozen?
1507
1508    assert_raise(FrozenErrorType) { m.optional_int64 = 2 }
1509    assert_raise(FrozenErrorType) { m.optional_uint32 = 3 }
1510    assert_raise(FrozenErrorType) { m.optional_uint64 = 4 }
1511    assert_raise(FrozenErrorType) { m.optional_bool = true }
1512    assert_raise(FrozenErrorType) { m.optional_float = 6.0 }
1513    assert_raise(FrozenErrorType) { m.optional_double = 7.0 }
1514    assert_raise(FrozenErrorType) { m.optional_string = '8' }
1515    assert_raise(FrozenErrorType) { m.optional_bytes = nil }
1516    assert_raise(FrozenErrorType) { m.optional_msg = proto_module::TestMessage2.new }
1517    assert_raise(FrozenErrorType) { m.optional_enum = :A }
1518    assert_raise(FrozenErrorType) { m.repeated_int32 = 1 }
1519    assert_raise(FrozenErrorType) { m.repeated_int64 = 2 }
1520    assert_raise(FrozenErrorType) { m.repeated_uint32 = 3 }
1521    assert_raise(FrozenErrorType) { m.repeated_uint64 = 4 }
1522    assert_raise(FrozenErrorType) { m.repeated_bool = true }
1523    assert_raise(FrozenErrorType) { m.repeated_float = 6.0 }
1524    assert_raise(FrozenErrorType) { m.repeated_double = 7.0 }
1525    assert_raise(FrozenErrorType) { m.repeated_string = '8' }
1526    assert_raise(FrozenErrorType) { m.repeated_bytes = nil }
1527    assert_raise(FrozenErrorType) { m.repeated_msg = proto_module::TestMessage2.new }
1528    assert_raise(FrozenErrorType) { m.repeated_enum = :A }
1529  end
1530
1531  def test_eq
1532    m1 = proto_module::TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
1533    m2 = proto_module::TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
1534
1535    h = {}
1536    h[m1] = :yes
1537
1538    assert m1 == m2
1539    assert m1.eql?(m2)
1540    assert m1.hash == m2.hash
1541    assert h[m1] == :yes
1542    assert h[m2] == :yes
1543
1544    m1.optional_int32 = 2
1545
1546    assert m1 != m2
1547    assert !m1.eql?(m2)
1548    assert m1.hash != m2.hash
1549    assert_nil h[m2]
1550  end
1551end
1552