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