blob: 86c74c2a0917cf133b3c21e8b2d30b31b83a020c [file] [log] [blame]
Chris Fallin973f4252014-11-18 14:19:58 -08001#!/usr/bin/ruby
2
Chris Fallin91473dc2014-12-12 15:58:26 -08003require 'google/protobuf'
Chris Fallin973f4252014-11-18 14:19:58 -08004require 'test/unit'
5
6# ------------- generated code --------------
7
8module BasicTest
9 pool = Google::Protobuf::DescriptorPool.new
10 pool.build do
Chris Falline9abbd22015-04-13 14:01:54 -070011 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
Chris Fallin973f4252014-11-18 14:19:58 -080024 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
Chris Fallinfd1a3ff2015-01-06 15:44:09 -080052
Chris Fallin973f4252014-11-18 14:19:58 -080053 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
Chris Fallinfd1a3ff2015-01-06 15:44:09 -080059
Chris Fallin973f4252014-11-18 14:19:58 -080060 add_enum "TestEnum" do
61 value :Default, 0
62 value :A, 1
63 value :B, 2
64 value :C, 3
65 end
Chris Fallinfd1a3ff2015-01-06 15:44:09 -080066
Chris Fallin973f4252014-11-18 14:19:58 -080067 add_message "BadFieldNames" do
68 optional :dup, :int32, 1
69 optional :class, :int32, 2
70 optional :"a.b", :int32, 3
71 end
Chris Fallinfd1a3ff2015-01-06 15:44:09 -080072
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
Chris Fallinfcd88892015-01-13 18:14:39 -080089
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
Chris Fallin973f4252014-11-18 14:19:58 -080098 end
99
Chris Falline9abbd22015-04-13 14:01:54 -0700100 Foo = pool.lookup("Foo").msgclass
101 Bar = pool.lookup("Bar").msgclass
102 Baz = pool.lookup("Baz").msgclass
Chris Fallin973f4252014-11-18 14:19:58 -0800103 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
Chris Fallinfd1a3ff2015-01-06 15:44:09 -0800109 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
Chris Fallinfcd88892015-01-13 18:14:39 -0800115 OneofMessage = pool.lookup("OneofMessage").msgclass
Chris Fallin973f4252014-11-18 14:19:58 -0800116
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)
Adam Greene64678262015-05-02 13:48:23 -0700157 m.optional_msg = nil
158 assert m.optional_msg == nil
Chris Fallin973f4252014-11-18 14:19:58 -0800159 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: []>'
Adam Greenecd7ebbe2015-05-03 20:42:11 -0700181 assert_equal expected, m.inspect
Chris Fallin973f4252014-11-18 14:19:58 -0800182 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
Anders Carling0df1e392015-11-20 21:55:13 +0100194 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
Anders Carling0559f3e2015-11-20 21:57:28 +0100206 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
Chris Fallin973f4252014-11-18 14:19:58 -0800223 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, raises an error.
259 assert_raise TypeError do
260 m.optional_bytes = "Test string ASCII".encode!('ASCII')
261 end
262 assert_raise TypeError do
263 m.optional_bytes = "Test string UTF-8 \u0100".encode!('UTF-8')
264 end
265 assert_raise TypeError do
266 m.optional_string = ["FFFF"].pack('H*')
267 end
268
269 # "Ordinary" use case.
270 m.optional_bytes = ["FFFF"].pack('H*')
271 m.optional_string = "\u0100"
272
273 # strings are mutable so we can do this, but serialize should catch it.
274 m.optional_string = "asdf".encode!('UTF-8')
275 m.optional_string.encode!('ASCII-8BIT')
276 assert_raise TypeError do
277 data = TestMessage.encode(m)
278 end
279 end
280
281 def test_rptfield_int32
282 l = Google::Protobuf::RepeatedField.new(:int32)
283 assert l.count == 0
284 l = Google::Protobuf::RepeatedField.new(:int32, [1, 2, 3])
285 assert l.count == 3
Isaiah Pengee5f6e92015-02-03 16:45:12 +0100286 assert_equal [1, 2, 3], l
287 assert_equal l, [1, 2, 3]
Chris Fallin973f4252014-11-18 14:19:58 -0800288 l.push 4
289 assert l == [1, 2, 3, 4]
290 dst_list = []
291 l.each { |val| dst_list.push val }
292 assert dst_list == [1, 2, 3, 4]
293 assert l.to_a == [1, 2, 3, 4]
294 assert l[0] == 1
295 assert l[3] == 4
296 l[0] = 5
297 assert l == [5, 2, 3, 4]
298
299 l2 = l.dup
300 assert l == l2
301 assert l.object_id != l2.object_id
302 l2.push 6
303 assert l.count == 4
304 assert l2.count == 5
305
306 assert l.inspect == '[5, 2, 3, 4]'
307
Adam Greenecd7ebbe2015-05-03 20:42:11 -0700308 l.concat([7, 8, 9])
Chris Fallin973f4252014-11-18 14:19:58 -0800309 assert l == [5, 2, 3, 4, 7, 8, 9]
310 assert l.pop == 9
311 assert l == [5, 2, 3, 4, 7, 8]
312
313 assert_raise TypeError do
314 m = TestMessage.new
315 l.push m
316 end
317
318 m = TestMessage.new
319 m.repeated_int32 = l
320 assert m.repeated_int32 == [5, 2, 3, 4, 7, 8]
321 assert m.repeated_int32.object_id == l.object_id
322 l.push 42
323 assert m.repeated_int32.pop == 42
324
325 l3 = l + l.dup
326 assert l3.count == l.count * 2
327 l.count.times do |i|
328 assert l3[i] == l[i]
329 assert l3[l.count + i] == l[i]
330 end
331
332 l.clear
333 assert l.count == 0
334 l += [1, 2, 3, 4]
335 l.replace([5, 6, 7, 8])
336 assert l == [5, 6, 7, 8]
337
338 l4 = Google::Protobuf::RepeatedField.new(:int32)
339 l4[5] = 42
340 assert l4 == [0, 0, 0, 0, 0, 42]
341
342 l4 << 100
343 assert l4 == [0, 0, 0, 0, 0, 42, 100]
344 l4 << 101 << 102
345 assert l4 == [0, 0, 0, 0, 0, 42, 100, 101, 102]
346 end
347
Adam Greened55733c2015-05-01 11:54:29 -0700348 def test_parent_rptfield
349 #make sure we set the RepeatedField and can add to it
350 m = TestMessage.new
351 assert m.repeated_string == []
352 m.repeated_string << 'ok'
353 m.repeated_string.push('ok2')
354 assert m.repeated_string == ['ok', 'ok2']
355 m.repeated_string += ['ok3']
356 assert m.repeated_string == ['ok', 'ok2', 'ok3']
357 end
358
Chris Fallin973f4252014-11-18 14:19:58 -0800359 def test_rptfield_msg
360 l = Google::Protobuf::RepeatedField.new(:message, TestMessage)
361 l.push TestMessage.new
362 assert l.count == 1
363 assert_raise TypeError do
364 l.push TestMessage2.new
365 end
366 assert_raise TypeError do
367 l.push 42
368 end
369
370 l2 = l.dup
371 assert l2[0] == l[0]
372 assert l2[0].object_id == l[0].object_id
373
374 l2 = Google::Protobuf.deep_copy(l)
375 assert l2[0] == l[0]
376 assert l2[0].object_id != l[0].object_id
377
378 l3 = l + l2
379 assert l3.count == 2
380 assert l3[0] == l[0]
381 assert l3[1] == l2[0]
382 l3[0].optional_int32 = 1000
383 assert l[0].optional_int32 == 1000
384
385 new_msg = TestMessage.new(:optional_int32 => 200)
386 l4 = l + [new_msg]
387 assert l4.count == 2
388 new_msg.optional_int32 = 1000
389 assert l4[1].optional_int32 == 1000
390 end
391
392 def test_rptfield_enum
393 l = Google::Protobuf::RepeatedField.new(:enum, TestEnum)
394 l.push :A
395 l.push :B
396 l.push :C
397 assert l.count == 3
Chris Fallinfd1a3ff2015-01-06 15:44:09 -0800398 assert_raise RangeError do
Chris Fallin973f4252014-11-18 14:19:58 -0800399 l.push :D
400 end
401 assert l[0] == :A
402
403 l.push 4
404 assert l[3] == 4
405 end
406
407 def test_rptfield_initialize
408 assert_raise ArgumentError do
409 l = Google::Protobuf::RepeatedField.new
410 end
411 assert_raise ArgumentError do
412 l = Google::Protobuf::RepeatedField.new(:message)
413 end
414 assert_raise ArgumentError do
415 l = Google::Protobuf::RepeatedField.new([1, 2, 3])
416 end
417 assert_raise ArgumentError do
418 l = Google::Protobuf::RepeatedField.new(:message, [TestMessage2.new])
419 end
420 end
421
Adam Greenec70b6052015-05-01 08:54:18 -0700422 def test_rptfield_array_ducktyping
423 l = Google::Protobuf::RepeatedField.new(:int32)
424 length_methods = %w(count length size)
425 length_methods.each do |lm|
426 assert l.send(lm) == 0
427 end
Adam Greened55733c2015-05-01 11:54:29 -0700428 # out of bounds returns a nil
429 assert l[0] == nil
430 assert l[1] == nil
431 assert l[-1] == nil
Adam Greenec70b6052015-05-01 08:54:18 -0700432 l.push 4
433 length_methods.each do |lm|
Adam Greened55733c2015-05-01 11:54:29 -0700434 assert l.send(lm) == 1
Adam Greenec70b6052015-05-01 08:54:18 -0700435 end
Adam Greened55733c2015-05-01 11:54:29 -0700436 assert l[0] == 4
437 assert l[1] == nil
438 assert l[-1] == 4
439 assert l[-2] == nil
440
441 l.push 2
442 length_methods.each do |lm|
443 assert l.send(lm) == 2
444 end
445 assert l[0] == 4
446 assert l[1] == 2
447 assert l[2] == nil
448 assert l[-1] == 2
449 assert l[-2] == 4
450 assert l[-3] == nil
451
452 #adding out of scope will backfill with empty objects
Adam Greenec70b6052015-05-01 08:54:18 -0700453 end
454
Chris Fallinfd1a3ff2015-01-06 15:44:09 -0800455 def test_map_basic
456 # allowed key types:
457 # :int32, :int64, :uint32, :uint64, :bool, :string, :bytes.
458
459 m = Google::Protobuf::Map.new(:string, :int32)
460 m["asdf"] = 1
461 assert m["asdf"] == 1
462 m["jkl;"] = 42
463 assert m == { "jkl;" => 42, "asdf" => 1 }
464 assert m.has_key?("asdf")
465 assert !m.has_key?("qwerty")
466 assert m.length == 2
467
468 m2 = m.dup
469 assert m == m2
470 assert m.hash != 0
471 assert m.hash == m2.hash
472
473 collected = {}
474 m.each { |k,v| collected[v] = k }
475 assert collected == { 42 => "jkl;", 1 => "asdf" }
476
477 assert m.delete("asdf") == 1
478 assert !m.has_key?("asdf")
479 assert m["asdf"] == nil
480 assert !m.has_key?("asdf")
481
482 # We only assert on inspect value when there is one map entry because the
483 # order in which elements appear is unspecified (depends on the internal
484 # hash function). We don't want a brittle test.
Isaiah Peng45026262015-02-14 22:08:01 +0100485 assert m.inspect == "{\"jkl;\"=>42}"
Chris Fallinfd1a3ff2015-01-06 15:44:09 -0800486
487 assert m.keys == ["jkl;"]
488 assert m.values == [42]
489
490 m.clear
491 assert m.length == 0
492 assert m == {}
493
494 assert_raise TypeError do
495 m[1] = 1
496 end
497 assert_raise RangeError do
498 m["asdf"] = 0x1_0000_0000
499 end
500 end
501
502 def test_map_ctor
503 m = Google::Protobuf::Map.new(:string, :int32,
504 {"a" => 1, "b" => 2, "c" => 3})
505 assert m == {"a" => 1, "c" => 3, "b" => 2}
506 end
507
508 def test_map_keytypes
509 m = Google::Protobuf::Map.new(:int32, :int32)
510 m[1] = 42
511 m[-1] = 42
512 assert_raise RangeError do
513 m[0x8000_0000] = 1
514 end
515 assert_raise TypeError do
516 m["asdf"] = 1
517 end
518
519 m = Google::Protobuf::Map.new(:int64, :int32)
520 m[0x1000_0000_0000_0000] = 1
521 assert_raise RangeError do
522 m[0x1_0000_0000_0000_0000] = 1
523 end
524 assert_raise TypeError do
525 m["asdf"] = 1
526 end
527
528 m = Google::Protobuf::Map.new(:uint32, :int32)
529 m[0x8000_0000] = 1
530 assert_raise RangeError do
531 m[0x1_0000_0000] = 1
532 end
533 assert_raise RangeError do
534 m[-1] = 1
535 end
536
537 m = Google::Protobuf::Map.new(:uint64, :int32)
538 m[0x8000_0000_0000_0000] = 1
539 assert_raise RangeError do
540 m[0x1_0000_0000_0000_0000] = 1
541 end
542 assert_raise RangeError do
543 m[-1] = 1
544 end
545
546 m = Google::Protobuf::Map.new(:bool, :int32)
547 m[true] = 1
548 m[false] = 2
549 assert_raise TypeError do
550 m[1] = 1
551 end
552 assert_raise TypeError do
553 m["asdf"] = 1
554 end
555
556 m = Google::Protobuf::Map.new(:string, :int32)
557 m["asdf"] = 1
558 assert_raise TypeError do
559 m[1] = 1
560 end
561 assert_raise TypeError do
562 bytestring = ["FFFF"].pack("H*")
563 m[bytestring] = 1
564 end
565
566 m = Google::Protobuf::Map.new(:bytes, :int32)
567 bytestring = ["FFFF"].pack("H*")
568 m[bytestring] = 1
569 assert_raise TypeError do
570 m["asdf"] = 1
571 end
572 assert_raise TypeError do
573 m[1] = 1
574 end
575 end
576
577 def test_map_msg_enum_valuetypes
578 m = Google::Protobuf::Map.new(:string, :message, TestMessage)
579 m["asdf"] = TestMessage.new
580 assert_raise TypeError do
581 m["jkl;"] = TestMessage2.new
582 end
583
Chris Fallinace42122015-01-13 13:47:58 -0800584 m = Google::Protobuf::Map.new(
585 :string, :message, TestMessage,
586 { "a" => TestMessage.new(:optional_int32 => 42),
587 "b" => TestMessage.new(:optional_int32 => 84) })
Chris Fallinfd1a3ff2015-01-06 15:44:09 -0800588 assert m.length == 2
589 assert m.values.map{|msg| msg.optional_int32}.sort == [42, 84]
590
591 m = Google::Protobuf::Map.new(:string, :enum, TestEnum,
592 { "x" => :A, "y" => :B, "z" => :C })
593 assert m.length == 3
594 assert m["z"] == :C
595 m["z"] = 2
596 assert m["z"] == :B
597 m["z"] = 4
598 assert m["z"] == 4
599 assert_raise RangeError do
600 m["z"] = :Z
601 end
602 assert_raise TypeError do
603 m["z"] = "z"
604 end
605 end
606
607 def test_map_dup_deep_copy
Chris Fallinace42122015-01-13 13:47:58 -0800608 m = Google::Protobuf::Map.new(
609 :string, :message, TestMessage,
610 { "a" => TestMessage.new(:optional_int32 => 42),
611 "b" => TestMessage.new(:optional_int32 => 84) })
Chris Fallinfd1a3ff2015-01-06 15:44:09 -0800612
613 m2 = m.dup
614 assert m == m2
615 assert m.object_id != m2.object_id
616 assert m["a"].object_id == m2["a"].object_id
617 assert m["b"].object_id == m2["b"].object_id
618
619 m2 = Google::Protobuf.deep_copy(m)
620 assert m == m2
621 assert m.object_id != m2.object_id
622 assert m["a"].object_id != m2["a"].object_id
623 assert m["b"].object_id != m2["b"].object_id
624 end
625
626 def test_map_field
627 m = MapMessage.new
628 assert m.map_string_int32 == {}
629 assert m.map_string_msg == {}
630
Chris Fallinace42122015-01-13 13:47:58 -0800631 m = MapMessage.new(
632 :map_string_int32 => {"a" => 1, "b" => 2},
633 :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
634 "b" => TestMessage2.new(:foo => 2)})
Chris Fallinfd1a3ff2015-01-06 15:44:09 -0800635 assert m.map_string_int32.keys.sort == ["a", "b"]
636 assert m.map_string_int32["a"] == 1
637 assert m.map_string_msg["b"].foo == 2
638
639 m.map_string_int32["c"] = 3
640 assert m.map_string_int32["c"] == 3
641 m.map_string_msg["c"] = TestMessage2.new(:foo => 3)
642 assert m.map_string_msg["c"] == TestMessage2.new(:foo => 3)
643 m.map_string_msg.delete("b")
644 m.map_string_msg.delete("c")
645 assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) }
646
647 assert_raise TypeError do
648 m.map_string_msg["e"] = TestMessage.new # wrong value type
649 end
650 # ensure nothing was added by the above
651 assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) }
652
653 m.map_string_int32 = Google::Protobuf::Map.new(:string, :int32)
654 assert_raise TypeError do
655 m.map_string_int32 = Google::Protobuf::Map.new(:string, :int64)
656 end
657 assert_raise TypeError do
658 m.map_string_int32 = {}
659 end
660
661 assert_raise TypeError do
662 m = MapMessage.new(:map_string_int32 => { 1 => "I am not a number" })
663 end
664 end
665
666 def test_map_encode_decode
Chris Fallinace42122015-01-13 13:47:58 -0800667 m = MapMessage.new(
668 :map_string_int32 => {"a" => 1, "b" => 2},
669 :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
670 "b" => TestMessage2.new(:foo => 2)})
Chris Fallinfd1a3ff2015-01-06 15:44:09 -0800671 m2 = MapMessage.decode(MapMessage.encode(m))
672 assert m == m2
673
674 m3 = MapMessageWireEquiv.decode(MapMessage.encode(m))
675 assert m3.map_string_int32.length == 2
676
677 kv = {}
678 m3.map_string_int32.map { |msg| kv[msg.key] = msg.value }
679 assert kv == {"a" => 1, "b" => 2}
680
681 kv = {}
682 m3.map_string_msg.map { |msg| kv[msg.key] = msg.value }
683 assert kv == {"a" => TestMessage2.new(:foo => 1),
684 "b" => TestMessage2.new(:foo => 2)}
685 end
686
Chris Fallinfcd88892015-01-13 18:14:39 -0800687 def test_oneof_descriptors
688 d = OneofMessage.descriptor
689 o = d.lookup_oneof("my_oneof")
690 assert o != nil
691 assert o.class == Google::Protobuf::OneofDescriptor
692 assert o.name == "my_oneof"
Chris Falline1b7d382015-01-14 17:14:05 -0800693 oneof_count = 0
694 d.each_oneof{ |oneof|
695 oneof_count += 1
696 assert oneof == o
697 }
698 assert oneof_count == 1
Chris Fallinfcd88892015-01-13 18:14:39 -0800699 assert o.count == 4
700 field_names = o.map{|f| f.name}.sort
701 assert field_names == ["a", "b", "c", "d"]
702 end
703
704 def test_oneof
705 d = OneofMessage.new
706 assert d.a == nil
707 assert d.b == nil
708 assert d.c == nil
709 assert d.d == nil
Chris Falline2debef2015-01-14 18:02:27 -0800710 assert d.my_oneof == nil
Chris Fallinfcd88892015-01-13 18:14:39 -0800711
712 d.a = "hi"
713 assert d.a == "hi"
714 assert d.b == nil
715 assert d.c == nil
716 assert d.d == nil
Chris Falline2debef2015-01-14 18:02:27 -0800717 assert d.my_oneof == :a
Chris Fallinfcd88892015-01-13 18:14:39 -0800718
719 d.b = 42
720 assert d.a == nil
721 assert d.b == 42
722 assert d.c == nil
723 assert d.d == nil
Chris Falline2debef2015-01-14 18:02:27 -0800724 assert d.my_oneof == :b
Chris Fallinfcd88892015-01-13 18:14:39 -0800725
726 d.c = TestMessage2.new(:foo => 100)
727 assert d.a == nil
728 assert d.b == nil
729 assert d.c.foo == 100
730 assert d.d == nil
Chris Falline2debef2015-01-14 18:02:27 -0800731 assert d.my_oneof == :c
Chris Fallinfcd88892015-01-13 18:14:39 -0800732
733 d.d = :C
734 assert d.a == nil
735 assert d.b == nil
736 assert d.c == nil
737 assert d.d == :C
Chris Falline2debef2015-01-14 18:02:27 -0800738 assert d.my_oneof == :d
Chris Fallinfcd88892015-01-13 18:14:39 -0800739
740 d2 = OneofMessage.decode(OneofMessage.encode(d))
741 assert d2 == d
742
743 encoded_field_a = OneofMessage.encode(OneofMessage.new(:a => "string"))
744 encoded_field_b = OneofMessage.encode(OneofMessage.new(:b => 1000))
745 encoded_field_c = OneofMessage.encode(
746 OneofMessage.new(:c => TestMessage2.new(:foo => 1)))
747 encoded_field_d = OneofMessage.encode(OneofMessage.new(:d => :B))
748
749 d3 = OneofMessage.decode(
750 encoded_field_c + encoded_field_a + encoded_field_d)
751 assert d3.a == nil
752 assert d3.b == nil
753 assert d3.c == nil
754 assert d3.d == :B
755
756 d4 = OneofMessage.decode(
757 encoded_field_c + encoded_field_a + encoded_field_d +
758 encoded_field_c)
759 assert d4.a == nil
760 assert d4.b == nil
761 assert d4.c.foo == 1
762 assert d4.d == nil
763
764 d5 = OneofMessage.new(:a => "hello")
765 assert d5.a != nil
766 d5.a = nil
767 assert d5.a == nil
768 assert OneofMessage.encode(d5) == ''
Chris Falline2debef2015-01-14 18:02:27 -0800769 assert d5.my_oneof == nil
Chris Fallinfcd88892015-01-13 18:14:39 -0800770 end
771
Chris Fallin973f4252014-11-18 14:19:58 -0800772 def test_enum_field
773 m = TestMessage.new
774 assert m.optional_enum == :Default
775 m.optional_enum = :A
776 assert m.optional_enum == :A
Chris Fallinfd1a3ff2015-01-06 15:44:09 -0800777 assert_raise RangeError do
Chris Fallin973f4252014-11-18 14:19:58 -0800778 m.optional_enum = :ASDF
779 end
780 m.optional_enum = 1
781 assert m.optional_enum == :A
782 m.optional_enum = 100
783 assert m.optional_enum == 100
784 end
785
786 def test_dup
787 m = TestMessage.new
788 m.optional_string = "hello"
789 m.optional_int32 = 42
Adam Greened55733c2015-05-01 11:54:29 -0700790 tm1 = TestMessage2.new(:foo => 100)
791 tm2 = TestMessage2.new(:foo => 200)
792 m.repeated_msg.push tm1
793 assert m.repeated_msg[-1] == tm1
794 m.repeated_msg.push tm2
795 assert m.repeated_msg[-1] == tm2
Chris Fallin973f4252014-11-18 14:19:58 -0800796 m2 = m.dup
797 assert m == m2
798 m.optional_int32 += 1
799 assert m != m2
800 assert m.repeated_msg[0] == m2.repeated_msg[0]
801 assert m.repeated_msg[0].object_id == m2.repeated_msg[0].object_id
802 end
803
804 def test_deep_copy
805 m = TestMessage.new(:optional_int32 => 42,
806 :repeated_msg => [TestMessage2.new(:foo => 100)])
807 m2 = Google::Protobuf.deep_copy(m)
808 assert m == m2
809 assert m.repeated_msg == m2.repeated_msg
810 assert m.repeated_msg.object_id != m2.repeated_msg.object_id
811 assert m.repeated_msg[0].object_id != m2.repeated_msg[0].object_id
812 end
813
Chris Fallinfcd88892015-01-13 18:14:39 -0800814 def test_eq
815 m = TestMessage.new(:optional_int32 => 42,
816 :repeated_int32 => [1, 2, 3])
817 m2 = TestMessage.new(:optional_int32 => 43,
818 :repeated_int32 => [1, 2, 3])
819 assert m != m2
820 end
821
Chris Fallin973f4252014-11-18 14:19:58 -0800822 def test_enum_lookup
823 assert TestEnum::A == 1
824 assert TestEnum::B == 2
825 assert TestEnum::C == 3
826
827 assert TestEnum::lookup(1) == :A
828 assert TestEnum::lookup(2) == :B
829 assert TestEnum::lookup(3) == :C
830
831 assert TestEnum::resolve(:A) == 1
832 assert TestEnum::resolve(:B) == 2
833 assert TestEnum::resolve(:C) == 3
834 end
835
836 def test_parse_serialize
837 m = TestMessage.new(:optional_int32 => 42,
838 :optional_string => "hello world",
839 :optional_enum => :B,
840 :repeated_string => ["a", "b", "c"],
841 :repeated_int32 => [42, 43, 44],
842 :repeated_enum => [:A, :B, :C, 100],
Chris Fallinace42122015-01-13 13:47:58 -0800843 :repeated_msg => [TestMessage2.new(:foo => 1),
844 TestMessage2.new(:foo => 2)])
Chris Fallin973f4252014-11-18 14:19:58 -0800845 data = TestMessage.encode m
846 m2 = TestMessage.decode data
847 assert m == m2
848
849 data = Google::Protobuf.encode m
850 m2 = Google::Protobuf.decode(TestMessage, data)
851 assert m == m2
852 end
853
Adam Greened1b52a02015-05-03 10:55:10 -0700854 def test_encode_decode_helpers
855 m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
856 json = m.to_json
857 m2 = TestMessage.decode_json(json)
858 assert m2.optional_string == 'foo'
859 assert m2.repeated_string == ['bar1', 'bar2']
860
861 proto = m.to_proto
862 m2 = TestMessage.decode(proto)
863 assert m2.optional_string == 'foo'
864 assert m2.repeated_string == ['bar1', 'bar2']
865 end
866
867 def test_protobuf_encode_decode_helpers
868 m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
869 encoded_msg = Google::Protobuf.encode(m)
870 assert_equal m.to_proto, encoded_msg
871
872 decoded_msg = Google::Protobuf.decode(TestMessage, encoded_msg)
873 assert_equal TestMessage.decode(m.to_proto), decoded_msg
874 end
875
876 def test_protobuf_encode_decode_json_helpers
877 m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
878 encoded_msg = Google::Protobuf.encode_json(m)
879 assert_equal m.to_json, encoded_msg
880
881 decoded_msg = Google::Protobuf.decode_json(TestMessage, encoded_msg)
882 assert_equal TestMessage.decode_json(m.to_json), decoded_msg
883 end
884
885 def test_to_h
886 m = TestMessage.new(:optional_bool => true, :optional_double => -10.100001, :optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
887 expected_result = {
888 :optional_bool=>true,
889 :optional_bytes=>"",
890 :optional_double=>-10.100001,
891 :optional_enum=>:Default,
892 :optional_float=>0.0,
893 :optional_int32=>0,
894 :optional_int64=>0,
895 :optional_msg=>nil,
896 :optional_string=>"foo",
897 :optional_uint32=>0,
898 :optional_uint64=>0,
899 :repeated_bool=>[],
900 :repeated_bytes=>[],
901 :repeated_double=>[],
902 :repeated_enum=>[],
903 :repeated_float=>[],
904 :repeated_int32=>[],
905 :repeated_int64=>[],
906 :repeated_msg=>[],
907 :repeated_string=>["bar1", "bar2"],
908 :repeated_uint32=>[],
909 :repeated_uint64=>[]
910 }
911 assert_equal expected_result, m.to_h
912 end
913
914
Chris Fallin973f4252014-11-18 14:19:58 -0800915 def test_def_errors
916 s = Google::Protobuf::DescriptorPool.new
917 assert_raise TypeError do
918 s.build do
919 # enum with no default (integer value 0)
920 add_enum "MyEnum" do
921 value :A, 1
922 end
923 end
924 end
925 assert_raise TypeError do
926 s.build do
927 # message with required field (unsupported in proto3)
928 add_message "MyMessage" do
929 required :foo, :int32, 1
930 end
931 end
932 end
933 end
934
935 def test_corecursive
936 # just be sure that we can instantiate types with corecursive field-type
937 # references.
938 m = Recursive1.new(:foo => Recursive2.new(:foo => Recursive1.new))
939 assert Recursive1.descriptor.lookup("foo").subtype ==
940 Recursive2.descriptor
941 assert Recursive2.descriptor.lookup("foo").subtype ==
942 Recursive1.descriptor
943
944 serialized = Recursive1.encode(m)
945 m2 = Recursive1.decode(serialized)
946 assert m == m2
947 end
948
949 def test_serialize_cycle
950 m = Recursive1.new(:foo => Recursive2.new)
951 m.foo.foo = m
952 assert_raise RuntimeError do
953 serialized = Recursive1.encode(m)
954 end
955 end
956
957 def test_bad_field_names
958 m = BadFieldNames.new(:dup => 1, :class => 2)
959 m2 = m.dup
960 assert m == m2
961 assert m['dup'] == 1
962 assert m['class'] == 2
963 m['dup'] = 3
964 assert m['dup'] == 3
965 m['a.b'] = 4
966 assert m['a.b'] == 4
967 end
968
Chris Fallin973f4252014-11-18 14:19:58 -0800969 def test_int_ranges
970 m = TestMessage.new
971
972 m.optional_int32 = 0
973 m.optional_int32 = -0x8000_0000
974 m.optional_int32 = +0x7fff_ffff
975 m.optional_int32 = 1.0
976 m.optional_int32 = -1.0
977 m.optional_int32 = 2e9
978 assert_raise RangeError do
979 m.optional_int32 = -0x8000_0001
980 end
981 assert_raise RangeError do
982 m.optional_int32 = +0x8000_0000
983 end
984 assert_raise RangeError do
985 m.optional_int32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
986 end
987 assert_raise RangeError do
988 m.optional_int32 = 1e12
989 end
990 assert_raise RangeError do
991 m.optional_int32 = 1.5
992 end
993
994 m.optional_uint32 = 0
995 m.optional_uint32 = +0xffff_ffff
996 m.optional_uint32 = 1.0
997 m.optional_uint32 = 4e9
998 assert_raise RangeError do
999 m.optional_uint32 = -1
1000 end
1001 assert_raise RangeError do
1002 m.optional_uint32 = -1.5
1003 end
1004 assert_raise RangeError do
1005 m.optional_uint32 = -1.5e12
1006 end
1007 assert_raise RangeError do
1008 m.optional_uint32 = -0x1000_0000_0000_0000
1009 end
1010 assert_raise RangeError do
1011 m.optional_uint32 = +0x1_0000_0000
1012 end
1013 assert_raise RangeError do
1014 m.optional_uint32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
1015 end
1016 assert_raise RangeError do
1017 m.optional_uint32 = 1e12
1018 end
1019 assert_raise RangeError do
1020 m.optional_uint32 = 1.5
1021 end
1022
1023 m.optional_int64 = 0
1024 m.optional_int64 = -0x8000_0000_0000_0000
1025 m.optional_int64 = +0x7fff_ffff_ffff_ffff
1026 m.optional_int64 = 1.0
1027 m.optional_int64 = -1.0
1028 m.optional_int64 = 8e18
1029 m.optional_int64 = -8e18
1030 assert_raise RangeError do
1031 m.optional_int64 = -0x8000_0000_0000_0001
1032 end
1033 assert_raise RangeError do
1034 m.optional_int64 = +0x8000_0000_0000_0000
1035 end
1036 assert_raise RangeError do
1037 m.optional_int64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
1038 end
1039 assert_raise RangeError do
1040 m.optional_int64 = 1e50
1041 end
1042 assert_raise RangeError do
1043 m.optional_int64 = 1.5
1044 end
1045
1046 m.optional_uint64 = 0
1047 m.optional_uint64 = +0xffff_ffff_ffff_ffff
1048 m.optional_uint64 = 1.0
1049 m.optional_uint64 = 16e18
1050 assert_raise RangeError do
1051 m.optional_uint64 = -1
1052 end
1053 assert_raise RangeError do
1054 m.optional_uint64 = -1.5
1055 end
1056 assert_raise RangeError do
1057 m.optional_uint64 = -1.5e12
1058 end
1059 assert_raise RangeError do
1060 m.optional_uint64 = -0x1_0000_0000_0000_0000
1061 end
1062 assert_raise RangeError do
1063 m.optional_uint64 = +0x1_0000_0000_0000_0000
1064 end
1065 assert_raise RangeError do
1066 m.optional_uint64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
1067 end
1068 assert_raise RangeError do
1069 m.optional_uint64 = 1e50
1070 end
1071 assert_raise RangeError do
1072 m.optional_uint64 = 1.5
1073 end
Chris Fallin973f4252014-11-18 14:19:58 -08001074 end
1075
1076 def test_stress_test
1077 m = TestMessage.new
1078 m.optional_int32 = 42
1079 m.optional_int64 = 0x100000000
1080 m.optional_string = "hello world"
1081 10.times do m.repeated_msg.push TestMessage2.new(:foo => 42) end
1082 10.times do m.repeated_string.push "hello world" end
1083
1084 data = TestMessage.encode(m)
1085
1086 l = 0
1087 10_000.times do
1088 m = TestMessage.decode(data)
1089 data_new = TestMessage.encode(m)
1090 assert data_new == data
1091 data = data_new
1092 end
1093 end
1094
1095 def test_reflection
1096 m = TestMessage.new(:optional_int32 => 1234)
1097 msgdef = m.class.descriptor
1098 assert msgdef.class == Google::Protobuf::Descriptor
1099 assert msgdef.any? {|field| field.name == "optional_int32"}
1100 optional_int32 = msgdef.lookup "optional_int32"
1101 assert optional_int32.class == Google::Protobuf::FieldDescriptor
1102 assert optional_int32 != nil
1103 assert optional_int32.name == "optional_int32"
1104 assert optional_int32.type == :int32
1105 optional_int32.set(m, 5678)
1106 assert m.optional_int32 == 5678
1107 m.optional_int32 = 1000
1108 assert optional_int32.get(m) == 1000
1109
1110 optional_msg = msgdef.lookup "optional_msg"
1111 assert optional_msg.subtype == TestMessage2.descriptor
1112
1113 optional_msg.set(m, optional_msg.subtype.msgclass.new)
1114
1115 assert msgdef.msgclass == TestMessage
1116
1117 optional_enum = msgdef.lookup "optional_enum"
1118 assert optional_enum.subtype == TestEnum.descriptor
1119 assert optional_enum.subtype.class == Google::Protobuf::EnumDescriptor
1120 optional_enum.subtype.each do |k, v|
1121 # set with integer, check resolution to symbolic name
1122 optional_enum.set(m, v)
1123 assert optional_enum.get(m) == k
1124 end
1125 end
1126
1127 def test_json
Chris Fallineb375512015-05-13 14:58:48 -07001128 # TODO: Fix JSON in JRuby version.
1129 return if RUBY_PLATFORM == "java"
Chris Fallin973f4252014-11-18 14:19:58 -08001130 m = TestMessage.new(:optional_int32 => 1234,
1131 :optional_int64 => -0x1_0000_0000,
1132 :optional_uint32 => 0x8000_0000,
1133 :optional_uint64 => 0xffff_ffff_ffff_ffff,
1134 :optional_bool => true,
1135 :optional_float => 1.0,
1136 :optional_double => -1e100,
1137 :optional_string => "Test string",
1138 :optional_bytes => ["FFFFFFFF"].pack('H*'),
1139 :optional_msg => TestMessage2.new(:foo => 42),
1140 :repeated_int32 => [1, 2, 3, 4],
1141 :repeated_string => ["a", "b", "c"],
1142 :repeated_bool => [true, false, true, false],
1143 :repeated_msg => [TestMessage2.new(:foo => 1),
1144 TestMessage2.new(:foo => 2)])
1145
1146 json_text = TestMessage.encode_json(m)
1147 m2 = TestMessage.decode_json(json_text)
1148 assert m == m2
Chris Falline9abbd22015-04-13 14:01:54 -07001149
1150 # Crash case from GitHub issue 283.
1151 bar = Bar.new(msg: "bar")
1152 baz1 = Baz.new(msg: "baz")
1153 baz2 = Baz.new(msg: "quux")
1154 Foo.encode_json(Foo.new)
1155 Foo.encode_json(Foo.new(bar: bar))
1156 Foo.encode_json(Foo.new(bar: bar, baz: [baz1, baz2]))
Chris Fallin973f4252014-11-18 14:19:58 -08001157 end
Chris Fallina5075922015-02-02 15:07:34 -08001158
1159 def test_json_maps
Chris Fallineb375512015-05-13 14:58:48 -07001160 # TODO: Fix JSON in JRuby version.
1161 return if RUBY_PLATFORM == "java"
Chris Fallina5075922015-02-02 15:07:34 -08001162 m = MapMessage.new(:map_string_int32 => {"a" => 1})
Josh Haberman78da6662016-01-13 19:05:43 -08001163 expected = '{"mapStringInt32":{"a":1},"mapStringMsg":{}}'
Chris Fallina5075922015-02-02 15:07:34 -08001164 assert MapMessage.encode_json(m) == expected
1165 m2 = MapMessage.decode_json(MapMessage.encode_json(m))
1166 assert m == m2
1167 end
Chris Fallin973f4252014-11-18 14:19:58 -08001168 end
1169end