1#!/usr/bin/ruby
2
3require 'google/protobuf'
4require 'test/unit'
5
6# ------------- generated code --------------
7
8module BasicTest
9  pool = Google::Protobuf::DescriptorPool.new
10  pool.build do
11    add_message "Foo" do
12      optional :bar, :message, 1, "Bar"
13      repeated :baz, :message, 2, "Baz"
14    end
15
16    add_message "Bar" do
17      optional :msg, :string, 1
18    end
19
20    add_message "Baz" do
21      optional :msg, :string, 1
22    end
23
24    add_message "TestMessage" do
25      optional :optional_int32,  :int32,        1
26      optional :optional_int64,  :int64,        2
27      optional :optional_uint32, :uint32,       3
28      optional :optional_uint64, :uint64,       4
29      optional :optional_bool,   :bool,         5
30      optional :optional_float,  :float,        6
31      optional :optional_double, :double,       7
32      optional :optional_string, :string,       8
33      optional :optional_bytes,  :bytes,        9
34      optional :optional_msg,    :message,      10, "TestMessage2"
35      optional :optional_enum,   :enum,         11, "TestEnum"
36
37      repeated :repeated_int32,  :int32,        12
38      repeated :repeated_int64,  :int64,        13
39      repeated :repeated_uint32, :uint32,       14
40      repeated :repeated_uint64, :uint64,       15
41      repeated :repeated_bool,   :bool,         16
42      repeated :repeated_float,  :float,        17
43      repeated :repeated_double, :double,       18
44      repeated :repeated_string, :string,       19
45      repeated :repeated_bytes,  :bytes,        20
46      repeated :repeated_msg,    :message,      21, "TestMessage2"
47      repeated :repeated_enum,   :enum,         22, "TestEnum"
48    end
49    add_message "TestMessage2" do
50      optional :foo, :int32, 1
51    end
52
53    add_message "Recursive1" do
54      optional :foo, :message, 1, "Recursive2"
55    end
56    add_message "Recursive2" do
57      optional :foo, :message, 1, "Recursive1"
58    end
59
60    add_enum "TestEnum" do
61      value :Default, 0
62      value :A, 1
63      value :B, 2
64      value :C, 3
65    end
66
67    add_message "BadFieldNames" do
68      optional :dup, :int32, 1
69      optional :class, :int32, 2
70      optional :"a.b", :int32, 3
71    end
72
73    add_message "MapMessage" do
74      map :map_string_int32, :string, :int32, 1
75      map :map_string_msg, :string, :message, 2, "TestMessage2"
76    end
77    add_message "MapMessageWireEquiv" do
78      repeated :map_string_int32, :message, 1, "MapMessageWireEquiv_entry1"
79      repeated :map_string_msg, :message, 2, "MapMessageWireEquiv_entry2"
80    end
81    add_message "MapMessageWireEquiv_entry1" do
82      optional :key, :string, 1
83      optional :value, :int32, 2
84    end
85    add_message "MapMessageWireEquiv_entry2" do
86      optional :key, :string, 1
87      optional :value, :message, 2, "TestMessage2"
88    end
89
90    add_message "OneofMessage" do
91      oneof :my_oneof do
92        optional :a, :string, 1
93        optional :b, :int32, 2
94        optional :c, :message, 3, "TestMessage2"
95        optional :d, :enum, 4, "TestEnum"
96      end
97    end
98  end
99
100  Foo = pool.lookup("Foo").msgclass
101  Bar = pool.lookup("Bar").msgclass
102  Baz = pool.lookup("Baz").msgclass
103  TestMessage = pool.lookup("TestMessage").msgclass
104  TestMessage2 = pool.lookup("TestMessage2").msgclass
105  Recursive1 = pool.lookup("Recursive1").msgclass
106  Recursive2 = pool.lookup("Recursive2").msgclass
107  TestEnum = pool.lookup("TestEnum").enummodule
108  BadFieldNames = pool.lookup("BadFieldNames").msgclass
109  MapMessage = pool.lookup("MapMessage").msgclass
110  MapMessageWireEquiv = pool.lookup("MapMessageWireEquiv").msgclass
111  MapMessageWireEquiv_entry1 =
112    pool.lookup("MapMessageWireEquiv_entry1").msgclass
113  MapMessageWireEquiv_entry2 =
114    pool.lookup("MapMessageWireEquiv_entry2").msgclass
115  OneofMessage = pool.lookup("OneofMessage").msgclass
116
117# ------------ test cases ---------------
118
119  class MessageContainerTest < Test::Unit::TestCase
120
121    def test_defaults
122      m = TestMessage.new
123      assert m.optional_int32 == 0
124      assert m.optional_int64 == 0
125      assert m.optional_uint32 == 0
126      assert m.optional_uint64 == 0
127      assert m.optional_bool == false
128      assert m.optional_float == 0.0
129      assert m.optional_double == 0.0
130      assert m.optional_string == ""
131      assert m.optional_bytes == ""
132      assert m.optional_msg == nil
133      assert m.optional_enum == :Default
134    end
135
136    def test_setters
137      m = TestMessage.new
138      m.optional_int32 = -42
139      assert m.optional_int32 == -42
140      m.optional_int64 = -0x1_0000_0000
141      assert m.optional_int64 == -0x1_0000_0000
142      m.optional_uint32 = 0x9000_0000
143      assert m.optional_uint32 == 0x9000_0000
144      m.optional_uint64 = 0x9000_0000_0000_0000
145      assert m.optional_uint64 == 0x9000_0000_0000_0000
146      m.optional_bool = true
147      assert m.optional_bool == true
148      m.optional_float = 0.5
149      assert m.optional_float == 0.5
150      m.optional_double = 0.5
151      m.optional_string = "hello"
152      assert m.optional_string == "hello"
153      m.optional_bytes = "world".encode!('ASCII-8BIT')
154      assert m.optional_bytes == "world"
155      m.optional_msg = TestMessage2.new(:foo => 42)
156      assert m.optional_msg == TestMessage2.new(:foo => 42)
157      m.optional_msg = nil
158      assert m.optional_msg == nil
159    end
160
161    def test_ctor_args
162      m = TestMessage.new(:optional_int32 => -42,
163                          :optional_msg => TestMessage2.new,
164                          :optional_enum => :C,
165                          :repeated_string => ["hello", "there", "world"])
166      assert m.optional_int32 == -42
167      assert m.optional_msg.class == TestMessage2
168      assert m.repeated_string.length == 3
169      assert m.optional_enum == :C
170      assert m.repeated_string[0] == "hello"
171      assert m.repeated_string[1] == "there"
172      assert m.repeated_string[2] == "world"
173    end
174
175    def test_inspect
176      m = TestMessage.new(:optional_int32 => -42,
177                          :optional_enum => :A,
178                          :optional_msg => TestMessage2.new,
179                          :repeated_string => ["hello", "there", "world"])
180      expected = '<BasicTest::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: <BasicTest::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: []>'
181      assert_equal expected, m.inspect
182    end
183
184    def test_hash
185      m1 = TestMessage.new(:optional_int32 => 42)
186      m2 = TestMessage.new(:optional_int32 => 102)
187      assert m1.hash != 0
188      assert m2.hash != 0
189      # relying on the randomness here -- if hash function changes and we are
190      # unlucky enough to get a collision, then change the values above.
191      assert m1.hash != m2.hash
192    end
193
194    def test_unknown_field_errors
195      e = assert_raise NoMethodError do
196        TestMessage.new.hello
197      end
198      assert_match(/hello/, e.message)
199
200      e = assert_raise NoMethodError do
201        TestMessage.new.hello = "world"
202      end
203      assert_match(/hello/, e.message)
204    end
205
206    def test_initialization_map_errors
207      e = assert_raise ArgumentError do
208        TestMessage.new(:hello => "world")
209      end
210      assert_match(/hello/, e.message)
211
212      e = assert_raise ArgumentError do
213        MapMessage.new(:map_string_int32 => "hello")
214      end
215      assert_equal e.message, "Expected Hash object as initializer value for map field 'map_string_int32'."
216
217      e = assert_raise ArgumentError do
218        TestMessage.new(:repeated_uint32 => "hello")
219      end
220      assert_equal e.message, "Expected array as initializer value for repeated field 'repeated_uint32'."
221    end
222
223    def test_type_errors
224      m = TestMessage.new
225      assert_raise TypeError do
226        m.optional_int32 = "hello"
227      end
228      assert_raise TypeError do
229        m.optional_string = 42
230      end
231      assert_raise TypeError do
232        m.optional_string = nil
233      end
234      assert_raise TypeError do
235        m.optional_bool = 42
236      end
237      assert_raise TypeError do
238        m.optional_msg = TestMessage.new  # expects TestMessage2
239      end
240
241      assert_raise TypeError do
242        m.repeated_int32 = []  # needs RepeatedField
243      end
244
245      assert_raise TypeError do
246        m.repeated_int32.push "hello"
247      end
248
249      assert_raise TypeError do
250        m.repeated_msg.push TestMessage.new
251      end
252    end
253
254    def test_string_encoding
255      m = TestMessage.new
256
257      # Assigning a normal (ASCII or UTF8) string to a bytes field, or
258      # ASCII-8BIT to a string field will convert to the proper encoding.
259      m.optional_bytes = "Test string ASCII".encode!('ASCII')
260      assert m.optional_bytes.frozen?
261      assert_equal Encoding::ASCII_8BIT, m.optional_bytes.encoding
262      assert_equal "Test string ASCII", m.optional_bytes
263
264      assert_raise Encoding::UndefinedConversionError do
265        m.optional_bytes = "Test string UTF-8 \u0100".encode!('UTF-8')
266      end
267
268      assert_raise Encoding::UndefinedConversionError do
269        m.optional_string = ["FFFF"].pack('H*')
270      end
271
272      # "Ordinary" use case.
273      m.optional_bytes = ["FFFF"].pack('H*')
274      m.optional_string = "\u0100"
275
276      # strings are immutable so we can't do this, but serialize should catch it.
277      m.optional_string = "asdf".encode!('UTF-8')
278      assert_raise RuntimeError do
279        m.optional_string.encode!('ASCII-8BIT')
280      end
281    end
282
283    def test_rptfield_int32
284      l = Google::Protobuf::RepeatedField.new(:int32)
285      assert l.count == 0
286      l = Google::Protobuf::RepeatedField.new(:int32, [1, 2, 3])
287      assert l.count == 3
288      assert_equal [1, 2, 3], l
289      assert_equal l, [1, 2, 3]
290      l.push 4
291      assert l == [1, 2, 3, 4]
292      dst_list = []
293      l.each { |val| dst_list.push val }
294      assert dst_list == [1, 2, 3, 4]
295      assert l.to_a == [1, 2, 3, 4]
296      assert l[0] == 1
297      assert l[3] == 4
298      l[0] = 5
299      assert l == [5, 2, 3, 4]
300
301      l2 = l.dup
302      assert l == l2
303      assert l.object_id != l2.object_id
304      l2.push 6
305      assert l.count == 4
306      assert l2.count == 5
307
308      assert l.inspect == '[5, 2, 3, 4]'
309
310      l.concat([7, 8, 9])
311      assert l == [5, 2, 3, 4, 7, 8, 9]
312      assert l.pop == 9
313      assert l == [5, 2, 3, 4, 7, 8]
314
315      assert_raise TypeError do
316        m = TestMessage.new
317        l.push m
318      end
319
320      m = TestMessage.new
321      m.repeated_int32 = l
322      assert m.repeated_int32 == [5, 2, 3, 4, 7, 8]
323      assert m.repeated_int32.object_id == l.object_id
324      l.push 42
325      assert m.repeated_int32.pop == 42
326
327      l3 = l + l.dup
328      assert l3.count == l.count * 2
329      l.count.times do |i|
330        assert l3[i] == l[i]
331        assert l3[l.count + i] == l[i]
332      end
333
334      l.clear
335      assert l.count == 0
336      l += [1, 2, 3, 4]
337      l.replace([5, 6, 7, 8])
338      assert l == [5, 6, 7, 8]
339
340      l4 = Google::Protobuf::RepeatedField.new(:int32)
341      l4[5] = 42
342      assert l4 == [0, 0, 0, 0, 0, 42]
343
344      l4 << 100
345      assert l4 == [0, 0, 0, 0, 0, 42, 100]
346      l4 << 101 << 102
347      assert l4 == [0, 0, 0, 0, 0, 42, 100, 101, 102]
348    end
349
350    def test_parent_rptfield
351      #make sure we set the RepeatedField and can add to it
352      m = TestMessage.new
353      assert m.repeated_string == []
354      m.repeated_string << 'ok'
355      m.repeated_string.push('ok2')
356      assert m.repeated_string == ['ok', 'ok2']
357      m.repeated_string += ['ok3']
358      assert m.repeated_string == ['ok', 'ok2', 'ok3']
359    end
360
361    def test_rptfield_msg
362      l = Google::Protobuf::RepeatedField.new(:message, TestMessage)
363      l.push TestMessage.new
364      assert l.count == 1
365      assert_raise TypeError do
366        l.push TestMessage2.new
367      end
368      assert_raise TypeError do
369        l.push 42
370      end
371
372      l2 = l.dup
373      assert l2[0] == l[0]
374      assert l2[0].object_id == l[0].object_id
375
376      l2 = Google::Protobuf.deep_copy(l)
377      assert l2[0] == l[0]
378      assert l2[0].object_id != l[0].object_id
379
380      l3 = l + l2
381      assert l3.count == 2
382      assert l3[0] == l[0]
383      assert l3[1] == l2[0]
384      l3[0].optional_int32 = 1000
385      assert l[0].optional_int32 == 1000
386
387      new_msg = TestMessage.new(:optional_int32 => 200)
388      l4 = l + [new_msg]
389      assert l4.count == 2
390      new_msg.optional_int32 = 1000
391      assert l4[1].optional_int32 == 1000
392    end
393
394    def test_rptfield_enum
395      l = Google::Protobuf::RepeatedField.new(:enum, TestEnum)
396      l.push :A
397      l.push :B
398      l.push :C
399      assert l.count == 3
400      assert_raise RangeError do
401        l.push :D
402      end
403      assert l[0] == :A
404
405      l.push 4
406      assert l[3] == 4
407    end
408
409    def test_rptfield_initialize
410      assert_raise ArgumentError do
411        l = Google::Protobuf::RepeatedField.new
412      end
413      assert_raise ArgumentError do
414        l = Google::Protobuf::RepeatedField.new(:message)
415      end
416      assert_raise ArgumentError do
417        l = Google::Protobuf::RepeatedField.new([1, 2, 3])
418      end
419      assert_raise ArgumentError do
420        l = Google::Protobuf::RepeatedField.new(:message, [TestMessage2.new])
421      end
422    end
423
424    def test_rptfield_array_ducktyping
425      l = Google::Protobuf::RepeatedField.new(:int32)
426      length_methods = %w(count length size)
427      length_methods.each do |lm|
428        assert l.send(lm)  == 0
429      end
430      # out of bounds returns a nil
431      assert l[0] == nil
432      assert l[1] == nil
433      assert l[-1] == nil
434      l.push 4
435      length_methods.each do |lm|
436        assert l.send(lm) == 1
437      end
438      assert l[0] == 4
439      assert l[1] == nil
440      assert l[-1] == 4
441      assert l[-2] == nil
442
443      l.push 2
444      length_methods.each do |lm|
445        assert l.send(lm) == 2
446      end
447      assert l[0] == 4
448      assert l[1] == 2
449      assert l[2] == nil
450      assert l[-1] == 2
451      assert l[-2] == 4
452      assert l[-3] == nil
453
454      #adding out of scope will backfill with empty objects
455    end
456
457    def test_map_basic
458      # allowed key types:
459      # :int32, :int64, :uint32, :uint64, :bool, :string, :bytes.
460
461      m = Google::Protobuf::Map.new(:string, :int32)
462      m["asdf"] = 1
463      assert m["asdf"] == 1
464      m["jkl;"] = 42
465      assert m == { "jkl;" => 42, "asdf" => 1 }
466      assert m.has_key?("asdf")
467      assert !m.has_key?("qwerty")
468      assert m.length == 2
469
470      m2 = m.dup
471      assert m == m2
472      assert m.hash != 0
473      assert m.hash == m2.hash
474
475      collected = {}
476      m.each { |k,v| collected[v] = k }
477      assert collected == { 42 => "jkl;", 1 => "asdf" }
478
479      assert m.delete("asdf") == 1
480      assert !m.has_key?("asdf")
481      assert m["asdf"] == nil
482      assert !m.has_key?("asdf")
483
484      # We only assert on inspect value when there is one map entry because the
485      # order in which elements appear is unspecified (depends on the internal
486      # hash function). We don't want a brittle test.
487      assert m.inspect == "{\"jkl;\"=>42}"
488
489      assert m.keys == ["jkl;"]
490      assert m.values == [42]
491
492      m.clear
493      assert m.length == 0
494      assert m == {}
495
496      assert_raise TypeError do
497        m[1] = 1
498      end
499      assert_raise RangeError do
500        m["asdf"] = 0x1_0000_0000
501      end
502    end
503
504    def test_map_ctor
505      m = Google::Protobuf::Map.new(:string, :int32,
506                                    {"a" => 1, "b" => 2, "c" => 3})
507      assert m == {"a" => 1, "c" => 3, "b" => 2}
508    end
509
510    def test_map_keytypes
511      m = Google::Protobuf::Map.new(:int32, :int32)
512      m[1] = 42
513      m[-1] = 42
514      assert_raise RangeError do
515        m[0x8000_0000] = 1
516      end
517      assert_raise TypeError do
518        m["asdf"] = 1
519      end
520
521      m = Google::Protobuf::Map.new(:int64, :int32)
522      m[0x1000_0000_0000_0000] = 1
523      assert_raise RangeError do
524        m[0x1_0000_0000_0000_0000] = 1
525      end
526      assert_raise TypeError do
527        m["asdf"] = 1
528      end
529
530      m = Google::Protobuf::Map.new(:uint32, :int32)
531      m[0x8000_0000] = 1
532      assert_raise RangeError do
533        m[0x1_0000_0000] = 1
534      end
535      assert_raise RangeError do
536        m[-1] = 1
537      end
538
539      m = Google::Protobuf::Map.new(:uint64, :int32)
540      m[0x8000_0000_0000_0000] = 1
541      assert_raise RangeError do
542        m[0x1_0000_0000_0000_0000] = 1
543      end
544      assert_raise RangeError do
545        m[-1] = 1
546      end
547
548      m = Google::Protobuf::Map.new(:bool, :int32)
549      m[true] = 1
550      m[false] = 2
551      assert_raise TypeError do
552        m[1] = 1
553      end
554      assert_raise TypeError do
555        m["asdf"] = 1
556      end
557
558      m = Google::Protobuf::Map.new(:string, :int32)
559      m["asdf"] = 1
560      assert_raise TypeError do
561        m[1] = 1
562      end
563      assert_raise Encoding::UndefinedConversionError do
564        bytestring = ["FFFF"].pack("H*")
565        m[bytestring] = 1
566      end
567
568      m = Google::Protobuf::Map.new(:bytes, :int32)
569      bytestring = ["FFFF"].pack("H*")
570      m[bytestring] = 1
571      # Allowed -- we will automatically convert to ASCII-8BIT.
572      m["asdf"] = 1
573      assert_raise TypeError do
574        m[1] = 1
575      end
576    end
577
578    def test_map_msg_enum_valuetypes
579      m = Google::Protobuf::Map.new(:string, :message, TestMessage)
580      m["asdf"] = TestMessage.new
581      assert_raise TypeError do
582        m["jkl;"] = TestMessage2.new
583      end
584
585      m = Google::Protobuf::Map.new(
586        :string, :message, TestMessage,
587        { "a" => TestMessage.new(:optional_int32 => 42),
588          "b" => TestMessage.new(:optional_int32 => 84) })
589      assert m.length == 2
590      assert m.values.map{|msg| msg.optional_int32}.sort == [42, 84]
591
592      m = Google::Protobuf::Map.new(:string, :enum, TestEnum,
593                                    { "x" => :A, "y" => :B, "z" => :C })
594      assert m.length == 3
595      assert m["z"] == :C
596      m["z"] = 2
597      assert m["z"] == :B
598      m["z"] = 4
599      assert m["z"] == 4
600      assert_raise RangeError do
601        m["z"] = :Z
602      end
603      assert_raise TypeError do
604        m["z"] = "z"
605      end
606    end
607
608    def test_map_dup_deep_copy
609      m = Google::Protobuf::Map.new(
610        :string, :message, TestMessage,
611        { "a" => TestMessage.new(:optional_int32 => 42),
612          "b" => TestMessage.new(:optional_int32 => 84) })
613
614      m2 = m.dup
615      assert m == m2
616      assert m.object_id != m2.object_id
617      assert m["a"].object_id == m2["a"].object_id
618      assert m["b"].object_id == m2["b"].object_id
619
620      m2 = Google::Protobuf.deep_copy(m)
621      assert m == m2
622      assert m.object_id != m2.object_id
623      assert m["a"].object_id != m2["a"].object_id
624      assert m["b"].object_id != m2["b"].object_id
625    end
626
627    def test_map_field
628      m = MapMessage.new
629      assert m.map_string_int32 == {}
630      assert m.map_string_msg == {}
631
632      m = MapMessage.new(
633        :map_string_int32 => {"a" => 1, "b" => 2},
634        :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
635                            "b" => TestMessage2.new(:foo => 2)})
636      assert m.map_string_int32.keys.sort == ["a", "b"]
637      assert m.map_string_int32["a"] == 1
638      assert m.map_string_msg["b"].foo == 2
639
640      m.map_string_int32["c"] = 3
641      assert m.map_string_int32["c"] == 3
642      m.map_string_msg["c"] = TestMessage2.new(:foo => 3)
643      assert m.map_string_msg["c"] == TestMessage2.new(:foo => 3)
644      m.map_string_msg.delete("b")
645      m.map_string_msg.delete("c")
646      assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) }
647
648      assert_raise TypeError do
649        m.map_string_msg["e"] = TestMessage.new # wrong value type
650      end
651      # ensure nothing was added by the above
652      assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) }
653
654      m.map_string_int32 = Google::Protobuf::Map.new(:string, :int32)
655      assert_raise TypeError do
656        m.map_string_int32 = Google::Protobuf::Map.new(:string, :int64)
657      end
658      assert_raise TypeError do
659        m.map_string_int32 = {}
660      end
661
662      assert_raise TypeError do
663        m = MapMessage.new(:map_string_int32 => { 1 => "I am not a number" })
664      end
665    end
666
667    def test_map_encode_decode
668      m = MapMessage.new(
669        :map_string_int32 => {"a" => 1, "b" => 2},
670        :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
671                            "b" => TestMessage2.new(:foo => 2)})
672      m2 = MapMessage.decode(MapMessage.encode(m))
673      assert m == m2
674
675      m3 = MapMessageWireEquiv.decode(MapMessage.encode(m))
676      assert m3.map_string_int32.length == 2
677
678      kv = {}
679      m3.map_string_int32.map { |msg| kv[msg.key] = msg.value }
680      assert kv == {"a" => 1, "b" => 2}
681
682      kv = {}
683      m3.map_string_msg.map { |msg| kv[msg.key] = msg.value }
684      assert kv == {"a" => TestMessage2.new(:foo => 1),
685                    "b" => TestMessage2.new(:foo => 2)}
686    end
687
688    def test_oneof_descriptors
689      d = OneofMessage.descriptor
690      o = d.lookup_oneof("my_oneof")
691      assert o != nil
692      assert o.class == Google::Protobuf::OneofDescriptor
693      assert o.name == "my_oneof"
694      oneof_count = 0
695      d.each_oneof{ |oneof|
696        oneof_count += 1
697        assert oneof == o
698      }
699      assert oneof_count == 1
700      assert o.count == 4
701      field_names = o.map{|f| f.name}.sort
702      assert field_names == ["a", "b", "c", "d"]
703    end
704
705    def test_oneof
706      d = OneofMessage.new
707      assert d.a == ""
708      assert d.b == 0
709      assert d.c == nil
710      assert d.d == :Default
711      assert d.my_oneof == nil
712
713      d.a = "hi"
714      assert d.a == "hi"
715      assert d.b == 0
716      assert d.c == nil
717      assert d.d == :Default
718      assert d.my_oneof == :a
719
720      d.b = 42
721      assert d.a == ""
722      assert d.b == 42
723      assert d.c == nil
724      assert d.d == :Default
725      assert d.my_oneof == :b
726
727      d.c = TestMessage2.new(:foo => 100)
728      assert d.a == ""
729      assert d.b == 0
730      assert d.c.foo == 100
731      assert d.d == :Default
732      assert d.my_oneof == :c
733
734      d.d = :C
735      assert d.a == ""
736      assert d.b == 0
737      assert d.c == nil
738      assert d.d == :C
739      assert d.my_oneof == :d
740
741      d2 = OneofMessage.decode(OneofMessage.encode(d))
742      assert d2 == d
743
744      encoded_field_a = OneofMessage.encode(OneofMessage.new(:a => "string"))
745      encoded_field_b = OneofMessage.encode(OneofMessage.new(:b => 1000))
746      encoded_field_c = OneofMessage.encode(
747        OneofMessage.new(:c => TestMessage2.new(:foo => 1)))
748      encoded_field_d = OneofMessage.encode(OneofMessage.new(:d => :B))
749
750      d3 = OneofMessage.decode(
751        encoded_field_c + encoded_field_a + encoded_field_d)
752      assert d3.a == ""
753      assert d3.b == 0
754      assert d3.c == nil
755      assert d3.d == :B
756
757      d4 = OneofMessage.decode(
758        encoded_field_c + encoded_field_a + encoded_field_d +
759        encoded_field_c)
760      assert d4.a == ""
761      assert d4.b == 0
762      assert d4.c.foo == 1
763      assert d4.d == :Default
764
765      d5 = OneofMessage.new(:a => "hello")
766      assert d5.a == "hello"
767      d5.a = nil
768      assert d5.a == ""
769      assert OneofMessage.encode(d5) == ''
770      assert d5.my_oneof == nil
771    end
772
773    def test_enum_field
774      m = TestMessage.new
775      assert m.optional_enum == :Default
776      m.optional_enum = :A
777      assert m.optional_enum == :A
778      assert_raise RangeError do
779        m.optional_enum = :ASDF
780      end
781      m.optional_enum = 1
782      assert m.optional_enum == :A
783      m.optional_enum = 100
784      assert m.optional_enum == 100
785    end
786
787    def test_dup
788      m = TestMessage.new
789      m.optional_string = "hello"
790      m.optional_int32 = 42
791      tm1 = TestMessage2.new(:foo => 100)
792      tm2 = TestMessage2.new(:foo => 200)
793      m.repeated_msg.push tm1
794      assert m.repeated_msg[-1] == tm1
795      m.repeated_msg.push tm2
796      assert m.repeated_msg[-1] == tm2
797      m2 = m.dup
798      assert m == m2
799      m.optional_int32 += 1
800      assert m != m2
801      assert m.repeated_msg[0] == m2.repeated_msg[0]
802      assert m.repeated_msg[0].object_id == m2.repeated_msg[0].object_id
803    end
804
805    def test_deep_copy
806      m = TestMessage.new(:optional_int32 => 42,
807                          :repeated_msg => [TestMessage2.new(:foo => 100)])
808      m2 = Google::Protobuf.deep_copy(m)
809      assert m == m2
810      assert m.repeated_msg == m2.repeated_msg
811      assert m.repeated_msg.object_id != m2.repeated_msg.object_id
812      assert m.repeated_msg[0].object_id != m2.repeated_msg[0].object_id
813    end
814
815    def test_eq
816      m = TestMessage.new(:optional_int32 => 42,
817                          :repeated_int32 => [1, 2, 3])
818      m2 = TestMessage.new(:optional_int32 => 43,
819                           :repeated_int32 => [1, 2, 3])
820      assert m != m2
821    end
822
823    def test_enum_lookup
824      assert TestEnum::A == 1
825      assert TestEnum::B == 2
826      assert TestEnum::C == 3
827
828      assert TestEnum::lookup(1) == :A
829      assert TestEnum::lookup(2) == :B
830      assert TestEnum::lookup(3) == :C
831
832      assert TestEnum::resolve(:A) == 1
833      assert TestEnum::resolve(:B) == 2
834      assert TestEnum::resolve(:C) == 3
835    end
836
837    def test_parse_serialize
838      m = TestMessage.new(:optional_int32 => 42,
839                          :optional_string => "hello world",
840                          :optional_enum => :B,
841                          :repeated_string => ["a", "b", "c"],
842                          :repeated_int32 => [42, 43, 44],
843                          :repeated_enum => [:A, :B, :C, 100],
844                          :repeated_msg => [TestMessage2.new(:foo => 1),
845                                            TestMessage2.new(:foo => 2)])
846      data = TestMessage.encode m
847      m2 = TestMessage.decode data
848      assert m == m2
849
850      data = Google::Protobuf.encode m
851      m2 = Google::Protobuf.decode(TestMessage, data)
852      assert m == m2
853    end
854
855    def test_encode_decode_helpers
856      m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
857      assert_equal 'foo', m.optional_string
858      assert_equal ['bar1', 'bar2'], m.repeated_string
859
860      json = m.to_json
861      m2 = TestMessage.decode_json(json)
862      assert_equal 'foo', m2.optional_string
863      assert_equal ['bar1', 'bar2'], m2.repeated_string
864      if RUBY_PLATFORM != "java"
865        assert m2.optional_string.frozen?
866        assert m2.repeated_string[0].frozen?
867      end
868
869      proto = m.to_proto
870      m2 = TestMessage.decode(proto)
871      assert_equal 'foo', m2.optional_string
872      assert_equal ['bar1', 'bar2'], m2.repeated_string
873    end
874
875    def test_protobuf_encode_decode_helpers
876      m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
877      encoded_msg = Google::Protobuf.encode(m)
878      assert_equal m.to_proto, encoded_msg
879
880      decoded_msg = Google::Protobuf.decode(TestMessage, encoded_msg)
881      assert_equal TestMessage.decode(m.to_proto), decoded_msg
882    end
883
884    def test_protobuf_encode_decode_json_helpers
885      m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
886      encoded_msg = Google::Protobuf.encode_json(m)
887      assert_equal m.to_json, encoded_msg
888
889      decoded_msg = Google::Protobuf.decode_json(TestMessage, encoded_msg)
890      assert_equal TestMessage.decode_json(m.to_json), decoded_msg
891    end
892
893    def test_to_h
894      m = TestMessage.new(:optional_bool => true, :optional_double => -10.100001, :optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
895      expected_result = {
896        :optional_bool=>true,
897        :optional_bytes=>"",
898        :optional_double=>-10.100001,
899        :optional_enum=>:Default,
900        :optional_float=>0.0,
901        :optional_int32=>0,
902        :optional_int64=>0,
903        :optional_msg=>nil,
904        :optional_string=>"foo",
905        :optional_uint32=>0,
906        :optional_uint64=>0,
907        :repeated_bool=>[],
908        :repeated_bytes=>[],
909        :repeated_double=>[],
910        :repeated_enum=>[],
911        :repeated_float=>[],
912        :repeated_int32=>[],
913        :repeated_int64=>[],
914        :repeated_msg=>[],
915        :repeated_string=>["bar1", "bar2"],
916        :repeated_uint32=>[],
917        :repeated_uint64=>[]
918      }
919      assert_equal expected_result, m.to_h
920    end
921
922
923    def test_def_errors
924      s = Google::Protobuf::DescriptorPool.new
925      assert_raise TypeError do
926        s.build do
927          # enum with no default (integer value 0)
928          add_enum "MyEnum" do
929            value :A, 1
930          end
931        end
932      end
933      assert_raise TypeError do
934        s.build do
935          # message with required field (unsupported in proto3)
936          add_message "MyMessage" do
937            required :foo, :int32, 1
938          end
939        end
940      end
941    end
942
943    def test_corecursive
944      # just be sure that we can instantiate types with corecursive field-type
945      # references.
946      m = Recursive1.new(:foo => Recursive2.new(:foo => Recursive1.new))
947      assert Recursive1.descriptor.lookup("foo").subtype ==
948        Recursive2.descriptor
949      assert Recursive2.descriptor.lookup("foo").subtype ==
950        Recursive1.descriptor
951
952      serialized = Recursive1.encode(m)
953      m2 = Recursive1.decode(serialized)
954      assert m == m2
955    end
956
957    def test_serialize_cycle
958      m = Recursive1.new(:foo => Recursive2.new)
959      m.foo.foo = m
960      assert_raise RuntimeError do
961        serialized = Recursive1.encode(m)
962      end
963    end
964
965    def test_bad_field_names
966      m = BadFieldNames.new(:dup => 1, :class => 2)
967      m2 = m.dup
968      assert m == m2
969      assert m['dup'] == 1
970      assert m['class'] == 2
971      m['dup'] = 3
972      assert m['dup'] == 3
973      m['a.b'] = 4
974      assert m['a.b'] == 4
975    end
976
977    def test_int_ranges
978      m = TestMessage.new
979
980      m.optional_int32 = 0
981      m.optional_int32 = -0x8000_0000
982      m.optional_int32 = +0x7fff_ffff
983      m.optional_int32 = 1.0
984      m.optional_int32 = -1.0
985      m.optional_int32 = 2e9
986      assert_raise RangeError do
987        m.optional_int32 = -0x8000_0001
988      end
989      assert_raise RangeError do
990        m.optional_int32 = +0x8000_0000
991      end
992      assert_raise RangeError do
993        m.optional_int32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
994      end
995      assert_raise RangeError do
996        m.optional_int32 = 1e12
997      end
998      assert_raise RangeError do
999        m.optional_int32 = 1.5
1000      end
1001
1002      m.optional_uint32 = 0
1003      m.optional_uint32 = +0xffff_ffff
1004      m.optional_uint32 = 1.0
1005      m.optional_uint32 = 4e9
1006      assert_raise RangeError do
1007        m.optional_uint32 = -1
1008      end
1009      assert_raise RangeError do
1010        m.optional_uint32 = -1.5
1011      end
1012      assert_raise RangeError do
1013        m.optional_uint32 = -1.5e12
1014      end
1015      assert_raise RangeError do
1016        m.optional_uint32 = -0x1000_0000_0000_0000
1017      end
1018      assert_raise RangeError do
1019        m.optional_uint32 = +0x1_0000_0000
1020      end
1021      assert_raise RangeError do
1022        m.optional_uint32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
1023      end
1024      assert_raise RangeError do
1025        m.optional_uint32 = 1e12
1026      end
1027      assert_raise RangeError do
1028        m.optional_uint32 = 1.5
1029      end
1030
1031      m.optional_int64 = 0
1032      m.optional_int64 = -0x8000_0000_0000_0000
1033      m.optional_int64 = +0x7fff_ffff_ffff_ffff
1034      m.optional_int64 = 1.0
1035      m.optional_int64 = -1.0
1036      m.optional_int64 = 8e18
1037      m.optional_int64 = -8e18
1038      assert_raise RangeError do
1039        m.optional_int64 = -0x8000_0000_0000_0001
1040      end
1041      assert_raise RangeError do
1042        m.optional_int64 = +0x8000_0000_0000_0000
1043      end
1044      assert_raise RangeError do
1045        m.optional_int64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
1046      end
1047      assert_raise RangeError do
1048        m.optional_int64 = 1e50
1049      end
1050      assert_raise RangeError do
1051        m.optional_int64 = 1.5
1052      end
1053
1054      m.optional_uint64 = 0
1055      m.optional_uint64 = +0xffff_ffff_ffff_ffff
1056      m.optional_uint64 = 1.0
1057      m.optional_uint64 = 16e18
1058      assert_raise RangeError do
1059        m.optional_uint64 = -1
1060      end
1061      assert_raise RangeError do
1062        m.optional_uint64 = -1.5
1063      end
1064      assert_raise RangeError do
1065        m.optional_uint64 = -1.5e12
1066      end
1067      assert_raise RangeError do
1068        m.optional_uint64 = -0x1_0000_0000_0000_0000
1069      end
1070      assert_raise RangeError do
1071        m.optional_uint64 = +0x1_0000_0000_0000_0000
1072      end
1073      assert_raise RangeError do
1074        m.optional_uint64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
1075      end
1076      assert_raise RangeError do
1077        m.optional_uint64 = 1e50
1078      end
1079      assert_raise RangeError do
1080        m.optional_uint64 = 1.5
1081      end
1082    end
1083
1084    def test_stress_test
1085      m = TestMessage.new
1086      m.optional_int32 = 42
1087      m.optional_int64 = 0x100000000
1088      m.optional_string = "hello world"
1089      10.times do m.repeated_msg.push TestMessage2.new(:foo => 42) end
1090      10.times do m.repeated_string.push "hello world" end
1091
1092      data = TestMessage.encode(m)
1093
1094      l = 0
1095      10_000.times do
1096        m = TestMessage.decode(data)
1097        data_new = TestMessage.encode(m)
1098        assert data_new == data
1099        data = data_new
1100      end
1101    end
1102
1103    def test_reflection
1104      m = TestMessage.new(:optional_int32 => 1234)
1105      msgdef = m.class.descriptor
1106      assert msgdef.class == Google::Protobuf::Descriptor
1107      assert msgdef.any? {|field| field.name == "optional_int32"}
1108      optional_int32 = msgdef.lookup "optional_int32"
1109      assert optional_int32.class == Google::Protobuf::FieldDescriptor
1110      assert optional_int32 != nil
1111      assert optional_int32.name == "optional_int32"
1112      assert optional_int32.type == :int32
1113      optional_int32.set(m, 5678)
1114      assert m.optional_int32 == 5678
1115      m.optional_int32 = 1000
1116      assert optional_int32.get(m) == 1000
1117
1118      optional_msg = msgdef.lookup "optional_msg"
1119      assert optional_msg.subtype == TestMessage2.descriptor
1120
1121      optional_msg.set(m, optional_msg.subtype.msgclass.new)
1122
1123      assert msgdef.msgclass == TestMessage
1124
1125      optional_enum = msgdef.lookup "optional_enum"
1126      assert optional_enum.subtype == TestEnum.descriptor
1127      assert optional_enum.subtype.class == Google::Protobuf::EnumDescriptor
1128      optional_enum.subtype.each do |k, v|
1129        # set with integer, check resolution to symbolic name
1130        optional_enum.set(m, v)
1131        assert optional_enum.get(m) == k
1132      end
1133    end
1134
1135    def test_json
1136      # TODO: Fix JSON in JRuby version.
1137      return if RUBY_PLATFORM == "java"
1138      m = TestMessage.new(:optional_int32 => 1234,
1139                          :optional_int64 => -0x1_0000_0000,
1140                          :optional_uint32 => 0x8000_0000,
1141                          :optional_uint64 => 0xffff_ffff_ffff_ffff,
1142                          :optional_bool => true,
1143                          :optional_float => 1.0,
1144                          :optional_double => -1e100,
1145                          :optional_string => "Test string",
1146                          :optional_bytes => ["FFFFFFFF"].pack('H*'),
1147                          :optional_msg => TestMessage2.new(:foo => 42),
1148                          :repeated_int32 => [1, 2, 3, 4],
1149                          :repeated_string => ["a", "b", "c"],
1150                          :repeated_bool => [true, false, true, false],
1151                          :repeated_msg => [TestMessage2.new(:foo => 1),
1152                                            TestMessage2.new(:foo => 2)])
1153
1154      json_text = TestMessage.encode_json(m)
1155      m2 = TestMessage.decode_json(json_text)
1156      assert m == m2
1157
1158      # Crash case from GitHub issue 283.
1159      bar = Bar.new(msg: "bar")
1160      baz1 = Baz.new(msg: "baz")
1161      baz2 = Baz.new(msg: "quux")
1162      Foo.encode_json(Foo.new)
1163      Foo.encode_json(Foo.new(bar: bar))
1164      Foo.encode_json(Foo.new(bar: bar, baz: [baz1, baz2]))
1165    end
1166
1167    def test_json_maps
1168      # TODO: Fix JSON in JRuby version.
1169      return if RUBY_PLATFORM == "java"
1170      m = MapMessage.new(:map_string_int32 => {"a" => 1})
1171      expected = '{"mapStringInt32":{"a":1},"mapStringMsg":{}}'
1172      expected_preserve = '{"map_string_int32":{"a":1},"map_string_msg":{}}'
1173      assert MapMessage.encode_json(m) == expected
1174
1175      json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true)
1176      assert json == expected_preserve
1177
1178      m2 = MapMessage.decode_json(MapMessage.encode_json(m))
1179      assert m == m2
1180    end
1181  end
1182end
1183