blob: a4f3aab8152bed3ea18172f812ed18b71784d2c7 [file] [log] [blame]
Brian Silverman9c614bc2016-02-15 20:20:02 -05001#!/usr/bin/ruby
2
3require 'google/protobuf'
4require 'test/unit'
5
6class RepeatedFieldTest < Test::Unit::TestCase
7
8 def test_acts_like_enumerator
9 m = TestMessage.new
10 (Enumerable.instance_methods - TestMessage.new.repeated_string.methods).each do |method_name|
11 assert m.repeated_string.respond_to?(method_name) == true, "does not respond to #{method_name}"
12 end
13 end
14
15 def test_acts_like_an_array
16 m = TestMessage.new
17 arr_methods = ([].methods - TestMessage.new.repeated_string.methods)
18 # jRuby additions to the Array class that we can ignore
19 arr_methods -= [ :indices, :iter_for_each, :iter_for_each_index,
20 :iter_for_each_with_index, :dimensions, :copy_data, :copy_data_simple,
Austin Schuh40c16522018-10-28 20:27:54 -070021 :nitems, :iter_for_reverse_each, :indexes, :append, :prepend]
Brian Silverman9c614bc2016-02-15 20:20:02 -050022 arr_methods.each do |method_name|
23 assert m.repeated_string.respond_to?(method_name) == true, "does not respond to #{method_name}"
24 end
25 end
26
27 def test_first
28 m = TestMessage.new
29 repeated_field_names(TestMessage).each do |field_name|
30 assert_nil m.send(field_name).first
31 end
32 fill_test_msg(m)
33 assert_equal -10, m.repeated_int32.first
34 assert_equal -1_000_000, m.repeated_int64.first
35 assert_equal 10, m.repeated_uint32.first
36 assert_equal 1_000_000, m.repeated_uint64.first
37 assert_equal true, m.repeated_bool.first
38 assert_equal -1.01, m.repeated_float.first.round(2)
39 assert_equal -1.0000000000001, m.repeated_double.first
40 assert_equal 'foo', m.repeated_string.first
41 assert_equal "bar".encode!('ASCII-8BIT'), m.repeated_bytes.first
42 assert_equal TestMessage2.new(:foo => 1), m.repeated_msg.first
43 assert_equal :A, m.repeated_enum.first
44 end
45
46
47 def test_last
48 m = TestMessage.new
49 repeated_field_names(TestMessage).each do |field_name|
50 assert_nil m.send(field_name).first
51 end
52 fill_test_msg(m)
53 assert_equal -11, m.repeated_int32.last
54 assert_equal -1_000_001, m.repeated_int64.last
55 assert_equal 11, m.repeated_uint32.last
56 assert_equal 1_000_001, m.repeated_uint64.last
57 assert_equal false, m.repeated_bool.last
58 assert_equal -1.02, m.repeated_float.last.round(2)
59 assert_equal -1.0000000000002, m.repeated_double.last
60 assert_equal 'bar', m.repeated_string.last
61 assert_equal "foo".encode!('ASCII-8BIT'), m.repeated_bytes.last
62 assert_equal TestMessage2.new(:foo => 2), m.repeated_msg.last
63 assert_equal :B, m.repeated_enum.last
64 end
65
66
67 def test_pop
68 m = TestMessage.new
69 repeated_field_names(TestMessage).each do |field_name|
70 assert_nil m.send(field_name).pop
71 end
72 fill_test_msg(m)
73
74 assert_equal -11, m.repeated_int32.pop
75 assert_equal -10, m.repeated_int32.pop
76 assert_equal -1_000_001, m.repeated_int64.pop
77 assert_equal -1_000_000, m.repeated_int64.pop
78 assert_equal 11, m.repeated_uint32.pop
79 assert_equal 10, m.repeated_uint32.pop
80 assert_equal 1_000_001, m.repeated_uint64.pop
81 assert_equal 1_000_000, m.repeated_uint64.pop
82 assert_equal false, m.repeated_bool.pop
83 assert_equal true, m.repeated_bool.pop
84 assert_equal -1.02, m.repeated_float.pop.round(2)
85 assert_equal -1.01, m.repeated_float.pop.round(2)
86 assert_equal -1.0000000000002, m.repeated_double.pop
87 assert_equal -1.0000000000001, m.repeated_double.pop
88 assert_equal 'bar', m.repeated_string.pop
89 assert_equal 'foo', m.repeated_string.pop
90 assert_equal "foo".encode!('ASCII-8BIT'), m.repeated_bytes.pop
91 assert_equal "bar".encode!('ASCII-8BIT'), m.repeated_bytes.pop
92 assert_equal TestMessage2.new(:foo => 2), m.repeated_msg.pop
93 assert_equal TestMessage2.new(:foo => 1), m.repeated_msg.pop
94 assert_equal :B, m.repeated_enum.pop
95 assert_equal :A, m.repeated_enum.pop
96 repeated_field_names(TestMessage).each do |field_name|
97 assert_nil m.send(field_name).pop
98 end
99
100 fill_test_msg(m)
101 assert_equal ['bar', 'foo'], m.repeated_string.pop(2)
102 assert_nil m.repeated_string.pop
103 end
104
105
106 def test_each
107 m = TestMessage.new
108 5.times{|i| m.repeated_string << 'string' }
109 count = 0
110 m.repeated_string.each do |val|
111 assert_equal 'string', val
112 count += 1
113 end
114 assert_equal 5, count
115 result = m.repeated_string.each{|val| val + '_junk'}
116 assert_equal ['string'] * 5, result
117 end
118
119
120 def test_empty?
121 m = TestMessage.new
122 assert_equal true, m.repeated_string.empty?
123 m.repeated_string << 'foo'
124 assert_equal false, m.repeated_string.empty?
125 m.repeated_string << 'bar'
126 assert_equal false, m.repeated_string.empty?
127 end
128
Austin Schuh40c16522018-10-28 20:27:54 -0700129 def test_reassign
130 m = TestMessage.new
131 m.repeated_msg = Google::Protobuf::RepeatedField.new(:message, TestMessage2, [TestMessage2.new(:foo => 1)])
132 assert_equal m.repeated_msg.first, TestMessage2.new(:foo => 1)
133 end
134
Brian Silverman9c614bc2016-02-15 20:20:02 -0500135 def test_array_accessor
136 m = TestMessage.new
137 reference_arr = %w(foo bar baz)
138 m.repeated_string += reference_arr.clone
139 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
140 arr[1]
141 end
142 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
143 arr[-2]
144 end
145 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
146 arr[20]
147 end
148 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
149 arr[1, 2]
150 end
151 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
152 arr[0..2]
153 end
154 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
155 arr[-1, 1]
156 end
157 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
158 arr[10, 12]
159 end
160 end
161
162 def test_array_settor
163 m = TestMessage.new
164 reference_arr = %w(foo bar baz)
165 m.repeated_string += reference_arr.clone
166
167 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
168 arr[1] = 'junk'
169 end
170 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
171 arr[-2] = 'snappy'
172 end
173 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
174 arr[3] = ''
175 end
176 # slight deviation; we are strongly typed, and nil is not allowed
177 # for string types;
178 m.repeated_string[5] = 'spacious'
179 assert_equal ["foo", "snappy", "baz", "", "", "spacious"], m.repeated_string
180
181 #make sure it sests the default types for other fields besides strings
182 %w(repeated_int32 repeated_int64 repeated_uint32 repeated_uint64).each do |field_name|
183 m.send(field_name)[3] = 10
184 assert_equal [0,0,0,10], m.send(field_name)
185 end
186 m.repeated_float[3] = 10.1
187 #wonky mri float handling
188 assert_equal [0,0,0], m.repeated_float.to_a[0..2]
189 assert_equal 10.1, m.repeated_float[3].round(1)
190 m.repeated_double[3] = 10.1
191 assert_equal [0,0,0,10.1], m.repeated_double
192 m.repeated_bool[3] = true
193 assert_equal [false, false, false, true], m.repeated_bool
194 m.repeated_bytes[3] = "bar".encode!('ASCII-8BIT')
195 assert_equal ['', '', '', "bar".encode!('ASCII-8BIT')], m.repeated_bytes
196 m.repeated_msg[3] = TestMessage2.new(:foo => 1)
197 assert_equal [nil, nil, nil, TestMessage2.new(:foo => 1)], m.repeated_msg
198 m.repeated_enum[3] = :A
199 assert_equal [:Default, :Default, :Default, :A], m.repeated_enum
200
201 # check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
202 # arr[20] = 'spacious'
203 # end
204 # TODO: accessor doesn't allow other ruby-like methods
205 # check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
206 # arr[1, 2] = 'fizz'
207 # end
208 # check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
209 # arr[0..2] = 'buzz'
210 # end
211 end
212
213 def test_push
214 m = TestMessage.new
215 reference_arr = %w(foo bar baz)
216 m.repeated_string += reference_arr.clone
217
218 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
219 arr.push('fizz')
220 end
221 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
222 arr << 'fizz'
223 end
224 #TODO: push should support multiple
225 # check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
226 # arr.push('fizz', 'buzz')
227 # end
228 end
229
230 def test_clear
231 m = TestMessage.new
232 reference_arr = %w(foo bar baz)
233 m.repeated_string += reference_arr.clone
234
235 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
236 arr.clear
237 end
238 end
239
240 def test_concat
241 m = TestMessage.new
242 reference_arr = %w(foo bar baz)
243 m.repeated_string += reference_arr.clone
244 m.repeated_string.concat(['fizz', 'buzz'])
245 assert_equal %w(foo bar baz fizz buzz), m.repeated_string
246 #TODO: concat should return the orig array
247 # check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
248 # arr.concat(['fizz', 'buzz'])
249 # end
250 end
251
252 def test_equal
253 m = TestMessage.new
254 reference_arr = %w(foo bar baz)
255 m.repeated_string += reference_arr.clone
256 assert_equal reference_arr, m.repeated_string
257 reference_arr << 'fizz'
258 assert_not_equal reference_arr, m.repeated_string
259 m.repeated_string << 'fizz'
260 assert_equal reference_arr, m.repeated_string
261 end
262
263 def test_hash
264 # just a sanity check
265 m = TestMessage.new
266 reference_arr = %w(foo bar baz)
267 m.repeated_string += reference_arr.clone
268 assert m.repeated_string.hash.is_a?(Integer)
269 hash = m.repeated_string.hash
270 assert_equal hash, m.repeated_string.hash
271 m.repeated_string << 'j'
272 assert_not_equal hash, m.repeated_string.hash
273 end
274
275 def test_plus
276 m = TestMessage.new
277 reference_arr = %w(foo bar baz)
278 m.repeated_string += reference_arr.clone
279
280 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
281 arr + ['fizz', 'buzz']
282 end
283 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
284 arr += ['fizz', 'buzz']
285 end
286 end
287
288 def test_replace
289 m = TestMessage.new
290 reference_arr = %w(foo bar baz)
291 m.repeated_string += reference_arr.clone
292
293 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
294 arr.replace(['fizz', 'buzz'])
295 end
296 end
297
298 def test_to_a
299 m = TestMessage.new
300 reference_arr = %w(foo bar baz)
301 m.repeated_string += reference_arr.clone
302
303 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
304 arr.to_a
305 end
306 end
307
308 def test_to_ary
309 m = TestMessage.new
310 reference_arr = %w(foo bar baz)
311 m.repeated_string += reference_arr.clone
312
313 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
314 arr.to_ary
315 end
316 end
317
318 # emulate Array behavior
319 ##########################
320
321 def test_collect!
322 m = TestMessage.new
323 reference_arr = %w(foo bar baz)
324 m.repeated_string += reference_arr.clone
325 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
326 arr.collect!{|x| x + "!" }
327 end
328 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
329 arr.collect!.with_index{|x, i| x[0...i] }
330 end
331 end
332
333 def test_compact!
334 m = TestMessage.new
335 m.repeated_msg << TestMessage2.new(:foo => 1)
336 m.repeated_msg << nil
337 m.repeated_msg << TestMessage2.new(:foo => 2)
338 reference_arr = m.repeated_string.to_a
339
340 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
341 arr.compact!
342 end
343 end
344
345 def test_delete
346 m = TestMessage.new
347 reference_arr = %w(foo bar baz)
348 m.repeated_string += reference_arr.clone
349 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
350 arr.delete('bar')
351 end
352 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
353 arr.delete('nope')
354 end
355 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
356 arr.delete('nope'){'within'}
357 end
358 end
359
360 def test_delete_at
361 m = TestMessage.new
362 reference_arr = %w(foo bar baz)
363 m.repeated_string += reference_arr.clone
364 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
365 arr.delete_at(2)
366 end
367 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
368 arr.delete_at(10)
369 end
370 end
371
Austin Schuh40c16522018-10-28 20:27:54 -0700372 def test_delete_if
373 m = TestMessage.new
374 reference_arr = %w(foo bar baz)
375 m.repeated_string += reference_arr.clone
376 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
377 arr.delete_if { |v| v == "bar" }
378 end
379 end
380
Brian Silverman9c614bc2016-02-15 20:20:02 -0500381 def test_fill
382 m = TestMessage.new
383 reference_arr = %w(foo bar baz)
384 m.repeated_string += reference_arr.clone
385
386 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
387 arr.fill("x")
388 end
389 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
390 arr.fill("z", 2, 2)
391 end
392 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
393 arr.fill("y", 0..1)
394 end
395 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
396 arr.fill { |i| (i*i).to_s }
397 end
398 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
399 arr.fill(-2) { |i| (i*i*i).to_s }
400 end
401 end
402
403 def test_flatten!
404 m = TestMessage.new
405 reference_arr = %w(foo bar baz)
406 m.repeated_string += reference_arr.clone
407
408 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
409 arr.flatten!
410 end
411 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
412 arr.flatten!(1)
413 end
414 end
415
416 def test_insert
417 m = TestMessage.new
418 reference_arr = %w(foo bar baz)
419 m.repeated_string += reference_arr.clone
420 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
421 arr.insert(2, 'fizz')
422 end
423 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
424 arr.insert(3, 'fizz', 'buzz', 'bazz')
425 end
426 end
427
428 def test_inspect
429 m = TestMessage.new
430 assert_equal '[]', m.repeated_string.inspect
431 m.repeated_string << 'foo'
432 assert_equal m.repeated_string.to_a.inspect, m.repeated_string.inspect
433 m.repeated_string << 'bar'
434 assert_equal m.repeated_string.to_a.inspect, m.repeated_string.inspect
435 end
436
437 def test_reverse!
438 m = TestMessage.new
439 reference_arr = %w(foo bar baz)
440 m.repeated_string += reference_arr.clone
441
442 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
443 arr.reverse!
444 end
445 end
446
447 def test_rotate!
448 m = TestMessage.new
449 reference_arr = %w(foo bar baz)
450 m.repeated_string += reference_arr.clone
451
452 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
453 arr.rotate!
454 end
455 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
456 arr.rotate!(2)
457 end
458 end
459
460 def test_select!
461 m = TestMessage.new
462 reference_arr = %w(foo bar baz)
463 m.repeated_string += reference_arr.clone
464
465 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
466 arr.select! { |v| v =~ /[aeiou]/ }
467 end
468 end
469
470 def test_shift
471 m = TestMessage.new
472 reference_arr = %w(foo bar baz)
473 m.repeated_string += reference_arr.clone
474
475 # should return an element
476 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
477 arr.shift
478 end
479 # should return an array
480 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
481 arr.shift(2)
482 end
483 # should return nil
484 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
485 arr.shift
486 end
487 end
488
489 def test_shuffle!
490 m = TestMessage.new
491 m.repeated_string += %w(foo bar baz)
492 orig_repeated_string = m.repeated_string.clone
493 result = m.repeated_string.shuffle!
494 assert_equal m.repeated_string, result
495 # NOTE: sometimes it doesn't change the order...
496 # assert_not_equal m.repeated_string.to_a, orig_repeated_string.to_a
497 end
498
499 def test_slice!
500 m = TestMessage.new
501 reference_arr = %w(foo bar baz bar fizz buzz)
502 m.repeated_string += reference_arr.clone
503
504 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
505 arr.slice!(2)
506 end
507 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
508 arr.slice!(1,2)
509 end
510 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
511 arr.slice!(0..1)
512 end
513 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
514 arr.slice!(10)
515 end
516 end
517
518 def test_sort!
519 m = TestMessage.new
520 reference_arr = %w(foo bar baz)
521 m.repeated_string += reference_arr.clone
522
523 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
524 arr.sort!
525 end
526 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
527 arr.sort! { |x,y| y <=> x }
528 end
529 end
530
531 def test_sort_by!
532 m = TestMessage.new
533 reference_arr = %w(foo bar baz)
534 m.repeated_string += reference_arr.clone
535
536 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
537 arr.sort_by!
538 end
539 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
540 arr.sort_by!(&:hash)
541 end
542 end
543
544 def test_uniq!
545 m = TestMessage.new
546 reference_arr = %w(foo bar baz)
547 m.repeated_string += reference_arr.clone
548
549 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
550 arr.uniq!
551 end
552 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
553 arr.uniq!{|s| s[0] }
554 end
555 end
556
557 def test_unshift
558 m = TestMessage.new
559 reference_arr = %w(foo bar baz)
560 m.repeated_string += reference_arr.clone
561
562 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
563 arr.unshift('1')
564 end
565 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
566 arr.unshift('a', 'b')
567 end
568 check_self_modifying_method(m.repeated_string, reference_arr) do |arr|
569 arr.unshift('')
570 end
571 end
572
573
574 ##### HELPER METHODS
575
576 def check_self_modifying_method(repeated_field, ref_array)
577 expected_result = yield(ref_array)
578 actual_result = yield(repeated_field)
579 if expected_result.is_a?(Enumerator)
580 assert_equal expected_result.to_a, actual_result.to_a
581 else
582 assert_equal expected_result, actual_result
583 end
584 assert_equal ref_array, repeated_field
585 end
586
587
588 def repeated_field_names(klass)
589 klass.descriptor.find_all{|f| f.label == :repeated}.map(&:name)
590 end
591
592
593 def fill_test_msg(test_msg)
594 test_msg.repeated_int32 += [-10, -11]
595 test_msg.repeated_int64 += [-1_000_000, -1_000_001]
596 test_msg.repeated_uint32 += [10, 11]
597 test_msg.repeated_uint64 += [1_000_000, 1_000_001]
598 test_msg.repeated_bool += [true, false]
599 test_msg.repeated_float += [-1.01, -1.02]
600 test_msg.repeated_double += [-1.0000000000001, -1.0000000000002]
601 test_msg.repeated_string += %w(foo bar)
602 test_msg.repeated_bytes += ["bar".encode!('ASCII-8BIT'), "foo".encode!('ASCII-8BIT')]
603 test_msg.repeated_msg << TestMessage2.new(:foo => 1)
604 test_msg.repeated_msg << TestMessage2.new(:foo => 2)
605 test_msg.repeated_enum << :A
606 test_msg.repeated_enum << :B
607 end
608
609
610 pool = Google::Protobuf::DescriptorPool.new
611 pool.build do
612
613 add_message "TestMessage" do
614 optional :optional_int32, :int32, 1
615 optional :optional_int64, :int64, 2
616 optional :optional_uint32, :uint32, 3
617 optional :optional_uint64, :uint64, 4
618 optional :optional_bool, :bool, 5
619 optional :optional_float, :float, 6
620 optional :optional_double, :double, 7
621 optional :optional_string, :string, 8
622 optional :optional_bytes, :bytes, 9
623 optional :optional_msg, :message, 10, "TestMessage2"
624 optional :optional_enum, :enum, 11, "TestEnum"
625
626 repeated :repeated_int32, :int32, 12
627 repeated :repeated_int64, :int64, 13
628 repeated :repeated_uint32, :uint32, 14
629 repeated :repeated_uint64, :uint64, 15
630 repeated :repeated_bool, :bool, 16
631 repeated :repeated_float, :float, 17
632 repeated :repeated_double, :double, 18
633 repeated :repeated_string, :string, 19
634 repeated :repeated_bytes, :bytes, 20
635 repeated :repeated_msg, :message, 21, "TestMessage2"
636 repeated :repeated_enum, :enum, 22, "TestEnum"
637 end
638 add_message "TestMessage2" do
639 optional :foo, :int32, 1
640 end
641
642 add_enum "TestEnum" do
643 value :Default, 0
644 value :A, 1
645 value :B, 2
646 value :C, 3
647 end
648 end
649
650 TestMessage = pool.lookup("TestMessage").msgclass
651 TestMessage2 = pool.lookup("TestMessage2").msgclass
652 TestEnum = pool.lookup("TestEnum").enummodule
653
654
655end