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