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