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