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