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