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