1#!/usr/bin/ruby 2 3require 'google/protobuf' 4require 'test/unit' 5 6# ------------- generated code -------------- 7 8module BasicTest 9 pool = Google::Protobuf::DescriptorPool.new 10 pool.build do 11 add_message "Foo" do 12 optional :bar, :message, 1, "Bar" 13 repeated :baz, :message, 2, "Baz" 14 end 15 16 add_message "Bar" do 17 optional :msg, :string, 1 18 end 19 20 add_message "Baz" do 21 optional :msg, :string, 1 22 end 23 24 add_message "TestMessage" do 25 optional :optional_int32, :int32, 1 26 optional :optional_int64, :int64, 2 27 optional :optional_uint32, :uint32, 3 28 optional :optional_uint64, :uint64, 4 29 optional :optional_bool, :bool, 5 30 optional :optional_float, :float, 6 31 optional :optional_double, :double, 7 32 optional :optional_string, :string, 8 33 optional :optional_bytes, :bytes, 9 34 optional :optional_msg, :message, 10, "TestMessage2" 35 optional :optional_enum, :enum, 11, "TestEnum" 36 37 repeated :repeated_int32, :int32, 12 38 repeated :repeated_int64, :int64, 13 39 repeated :repeated_uint32, :uint32, 14 40 repeated :repeated_uint64, :uint64, 15 41 repeated :repeated_bool, :bool, 16 42 repeated :repeated_float, :float, 17 43 repeated :repeated_double, :double, 18 44 repeated :repeated_string, :string, 19 45 repeated :repeated_bytes, :bytes, 20 46 repeated :repeated_msg, :message, 21, "TestMessage2" 47 repeated :repeated_enum, :enum, 22, "TestEnum" 48 end 49 add_message "TestMessage2" do 50 optional :foo, :int32, 1 51 end 52 53 add_message "Recursive1" do 54 optional :foo, :message, 1, "Recursive2" 55 end 56 add_message "Recursive2" do 57 optional :foo, :message, 1, "Recursive1" 58 end 59 60 add_enum "TestEnum" do 61 value :Default, 0 62 value :A, 1 63 value :B, 2 64 value :C, 3 65 end 66 67 add_message "BadFieldNames" do 68 optional :dup, :int32, 1 69 optional :class, :int32, 2 70 end 71 72 add_message "MapMessage" do 73 map :map_string_int32, :string, :int32, 1 74 map :map_string_msg, :string, :message, 2, "TestMessage2" 75 end 76 add_message "MapMessageWireEquiv" do 77 repeated :map_string_int32, :message, 1, "MapMessageWireEquiv_entry1" 78 repeated :map_string_msg, :message, 2, "MapMessageWireEquiv_entry2" 79 end 80 add_message "MapMessageWireEquiv_entry1" do 81 optional :key, :string, 1 82 optional :value, :int32, 2 83 end 84 add_message "MapMessageWireEquiv_entry2" do 85 optional :key, :string, 1 86 optional :value, :message, 2, "TestMessage2" 87 end 88 89 add_message "OneofMessage" do 90 oneof :my_oneof do 91 optional :a, :string, 1 92 optional :b, :int32, 2 93 optional :c, :message, 3, "TestMessage2" 94 optional :d, :enum, 4, "TestEnum" 95 end 96 end 97 end 98 99 Foo = pool.lookup("Foo").msgclass 100 Bar = pool.lookup("Bar").msgclass 101 Baz = pool.lookup("Baz").msgclass 102 TestMessage = pool.lookup("TestMessage").msgclass 103 TestMessage2 = pool.lookup("TestMessage2").msgclass 104 Recursive1 = pool.lookup("Recursive1").msgclass 105 Recursive2 = pool.lookup("Recursive2").msgclass 106 TestEnum = pool.lookup("TestEnum").enummodule 107 BadFieldNames = pool.lookup("BadFieldNames").msgclass 108 MapMessage = pool.lookup("MapMessage").msgclass 109 MapMessageWireEquiv = pool.lookup("MapMessageWireEquiv").msgclass 110 MapMessageWireEquiv_entry1 = 111 pool.lookup("MapMessageWireEquiv_entry1").msgclass 112 MapMessageWireEquiv_entry2 = 113 pool.lookup("MapMessageWireEquiv_entry2").msgclass 114 OneofMessage = pool.lookup("OneofMessage").msgclass 115 116# ------------ test cases --------------- 117 118 class MessageContainerTest < Test::Unit::TestCase 119 120 def test_defaults 121 m = TestMessage.new 122 assert m.optional_int32 == 0 123 assert m.optional_int64 == 0 124 assert m.optional_uint32 == 0 125 assert m.optional_uint64 == 0 126 assert m.optional_bool == false 127 assert m.optional_float == 0.0 128 assert m.optional_double == 0.0 129 assert m.optional_string == "" 130 assert m.optional_bytes == "" 131 assert m.optional_msg == nil 132 assert m.optional_enum == :Default 133 end 134 135 def test_setters 136 m = TestMessage.new 137 m.optional_int32 = -42 138 assert m.optional_int32 == -42 139 m.optional_int64 = -0x1_0000_0000 140 assert m.optional_int64 == -0x1_0000_0000 141 m.optional_uint32 = 0x9000_0000 142 assert m.optional_uint32 == 0x9000_0000 143 m.optional_uint64 = 0x9000_0000_0000_0000 144 assert m.optional_uint64 == 0x9000_0000_0000_0000 145 m.optional_bool = true 146 assert m.optional_bool == true 147 m.optional_float = 0.5 148 assert m.optional_float == 0.5 149 m.optional_double = 0.5 150 m.optional_string = "hello" 151 assert m.optional_string == "hello" 152 m.optional_bytes = "world".encode!('ASCII-8BIT') 153 assert m.optional_bytes == "world" 154 m.optional_msg = TestMessage2.new(:foo => 42) 155 assert m.optional_msg == TestMessage2.new(:foo => 42) 156 m.optional_msg = nil 157 assert m.optional_msg == nil 158 end 159 160 def test_ctor_args 161 m = TestMessage.new(:optional_int32 => -42, 162 :optional_msg => TestMessage2.new, 163 :optional_enum => :C, 164 :repeated_string => ["hello", "there", "world"]) 165 assert m.optional_int32 == -42 166 assert m.optional_msg.class == TestMessage2 167 assert m.repeated_string.length == 3 168 assert m.optional_enum == :C 169 assert m.repeated_string[0] == "hello" 170 assert m.repeated_string[1] == "there" 171 assert m.repeated_string[2] == "world" 172 end 173 174 def test_inspect 175 m = TestMessage.new(:optional_int32 => -42, 176 :optional_enum => :A, 177 :optional_msg => TestMessage2.new, 178 :repeated_string => ["hello", "there", "world"]) 179 expected = '<BasicTest::TestMessage: optional_int32: -42, optional_int64: 0, optional_uint32: 0, optional_uint64: 0, optional_bool: false, optional_float: 0.0, optional_double: 0.0, optional_string: "", optional_bytes: "", optional_msg: <BasicTest::TestMessage2: foo: 0>, optional_enum: :A, repeated_int32: [], repeated_int64: [], repeated_uint32: [], repeated_uint64: [], repeated_bool: [], repeated_float: [], repeated_double: [], repeated_string: ["hello", "there", "world"], repeated_bytes: [], repeated_msg: [], repeated_enum: []>' 180 assert_equal expected, m.inspect 181 end 182 183 def test_hash 184 m1 = TestMessage.new(:optional_int32 => 42) 185 m2 = TestMessage.new(:optional_int32 => 102) 186 assert m1.hash != 0 187 assert m2.hash != 0 188 # relying on the randomness here -- if hash function changes and we are 189 # unlucky enough to get a collision, then change the values above. 190 assert m1.hash != m2.hash 191 end 192 193 def test_unknown_field_errors 194 e = assert_raise NoMethodError do 195 TestMessage.new.hello 196 end 197 assert_match(/hello/, e.message) 198 199 e = assert_raise NoMethodError do 200 TestMessage.new.hello = "world" 201 end 202 assert_match(/hello/, e.message) 203 end 204 205 def test_initialization_map_errors 206 e = assert_raise ArgumentError do 207 TestMessage.new(:hello => "world") 208 end 209 assert_match(/hello/, e.message) 210 211 e = assert_raise ArgumentError do 212 MapMessage.new(:map_string_int32 => "hello") 213 end 214 assert_equal e.message, "Expected Hash object as initializer value for map field 'map_string_int32' (given String)." 215 216 e = assert_raise ArgumentError do 217 TestMessage.new(:repeated_uint32 => "hello") 218 end 219 assert_equal e.message, "Expected array as initializer value for repeated field 'repeated_uint32' (given String)." 220 end 221 222 def test_type_errors 223 m = TestMessage.new 224 225 # Use rescue to allow subclasses of error 226 success = false 227 begin 228 m.optional_int32 = "hello" 229 rescue TypeError 230 success = true 231 end 232 assert(success) 233 234 success = false 235 begin 236 m.optional_string = nil 237 rescue TypeError 238 success = true 239 end 240 assert(success) 241 242 success = false 243 begin 244 m.optional_bool = 42 245 rescue TypeError 246 success = true 247 end 248 assert(success) 249 250 success = false 251 begin 252 m.optional_msg = TestMessage.new # expects TestMessage2 253 rescue TypeError 254 success = true 255 end 256 assert(success) 257 258 success = false 259 begin 260 m.repeated_int32 = [] # needs RepeatedField 261 rescue TypeError 262 success = true 263 end 264 assert(success) 265 266 success = false 267 begin 268 m.repeated_msg.push TestMessage.new 269 rescue TypeError 270 success = true 271 end 272 assert(success) 273 end 274 275 def test_string_encoding 276 m = TestMessage.new 277 278 # Assigning a normal (ASCII or UTF8) string to a bytes field, or 279 # ASCII-8BIT to a string field will convert to the proper encoding. 280 m.optional_bytes = "Test string ASCII".encode!('ASCII') 281 assert m.optional_bytes.frozen? 282 assert_equal Encoding::ASCII_8BIT, m.optional_bytes.encoding 283 assert_equal "Test string ASCII", m.optional_bytes 284 285 assert_raise Encoding::UndefinedConversionError do 286 m.optional_bytes = "Test string UTF-8 \u0100".encode!('UTF-8') 287 end 288 289 assert_raise Encoding::UndefinedConversionError do 290 m.optional_string = ["FFFF"].pack('H*') 291 end 292 293 # "Ordinary" use case. 294 m.optional_bytes = ["FFFF"].pack('H*') 295 m.optional_string = "\u0100" 296 297 # strings are immutable so we can't do this, but serialize should catch it. 298 m.optional_string = "asdf".encode!('UTF-8') 299 assert_raise do 300 m.optional_string.encode!('ASCII-8BIT') 301 end 302 end 303 304 def test_rptfield_int32 305 l = Google::Protobuf::RepeatedField.new(:int32) 306 assert l.count == 0 307 l = Google::Protobuf::RepeatedField.new(:int32, [1, 2, 3]) 308 assert l.count == 3 309 assert_equal [1, 2, 3], l 310 assert_equal l, [1, 2, 3] 311 l.push 4 312 assert l == [1, 2, 3, 4] 313 dst_list = [] 314 l.each { |val| dst_list.push val } 315 assert dst_list == [1, 2, 3, 4] 316 assert l.to_a == [1, 2, 3, 4] 317 assert l[0] == 1 318 assert l[3] == 4 319 l[0] = 5 320 assert l == [5, 2, 3, 4] 321 322 l2 = l.dup 323 assert l == l2 324 assert l.object_id != l2.object_id 325 l2.push 6 326 assert l.count == 4 327 assert l2.count == 5 328 329 assert l.inspect == '[5, 2, 3, 4]' 330 331 l.concat([7, 8, 9]) 332 assert l == [5, 2, 3, 4, 7, 8, 9] 333 assert l.pop == 9 334 assert l == [5, 2, 3, 4, 7, 8] 335 336 success = false 337 begin 338 m = TestMessage.new 339 l.push m 340 rescue TypeError 341 success = true 342 end 343 assert(success) 344 345 m = TestMessage.new 346 m.repeated_int32 = l 347 assert m.repeated_int32 == [5, 2, 3, 4, 7, 8] 348 assert m.repeated_int32.object_id == l.object_id 349 l.push 42 350 assert m.repeated_int32.pop == 42 351 352 l3 = l + l.dup 353 assert l3.count == l.count * 2 354 l.count.times do |i| 355 assert l3[i] == l[i] 356 assert l3[l.count + i] == l[i] 357 end 358 359 l.clear 360 assert l.count == 0 361 l += [1, 2, 3, 4] 362 l.replace([5, 6, 7, 8]) 363 assert l == [5, 6, 7, 8] 364 365 l4 = Google::Protobuf::RepeatedField.new(:int32) 366 l4[5] = 42 367 assert l4 == [0, 0, 0, 0, 0, 42] 368 369 l4 << 100 370 assert l4 == [0, 0, 0, 0, 0, 42, 100] 371 l4 << 101 << 102 372 assert l4 == [0, 0, 0, 0, 0, 42, 100, 101, 102] 373 end 374 375 def test_parent_rptfield 376 #make sure we set the RepeatedField and can add to it 377 m = TestMessage.new 378 assert m.repeated_string == [] 379 m.repeated_string << 'ok' 380 m.repeated_string.push('ok2') 381 assert m.repeated_string == ['ok', 'ok2'] 382 m.repeated_string += ['ok3'] 383 assert m.repeated_string == ['ok', 'ok2', 'ok3'] 384 end 385 386 def test_rptfield_msg 387 l = Google::Protobuf::RepeatedField.new(:message, TestMessage) 388 l.push TestMessage.new 389 assert l.count == 1 390 391 success = false 392 begin 393 l.push TestMessage2.new 394 rescue TypeError 395 success = true 396 end 397 assert(success) 398 399 success = false 400 begin 401 l.push 42 402 rescue TypeError 403 success = true 404 end 405 assert(success) 406 407 l2 = l.dup 408 assert l2[0] == l[0] 409 assert l2[0].object_id == l[0].object_id 410 411 l2 = Google::Protobuf.deep_copy(l) 412 assert l2[0] == l[0] 413 assert l2[0].object_id != l[0].object_id 414 415 l3 = l + l2 416 assert l3.count == 2 417 assert l3[0] == l[0] 418 assert l3[1] == l2[0] 419 l3[0].optional_int32 = 1000 420 assert l[0].optional_int32 == 1000 421 422 new_msg = TestMessage.new(:optional_int32 => 200) 423 l4 = l + [new_msg] 424 assert l4.count == 2 425 new_msg.optional_int32 = 1000 426 assert l4[1].optional_int32 == 1000 427 end 428 429 def test_rptfield_enum 430 l = Google::Protobuf::RepeatedField.new(:enum, TestEnum) 431 l.push :A 432 l.push :B 433 l.push :C 434 assert l.count == 3 435 assert_raise RangeError do 436 l.push :D 437 end 438 assert l[0] == :A 439 440 l.push 4 441 assert l[3] == 4 442 end 443 444 def test_rptfield_initialize 445 assert_raise ArgumentError do 446 l = Google::Protobuf::RepeatedField.new 447 end 448 assert_raise ArgumentError do 449 l = Google::Protobuf::RepeatedField.new(:message) 450 end 451 assert_raise ArgumentError do 452 l = Google::Protobuf::RepeatedField.new([1, 2, 3]) 453 end 454 assert_raise ArgumentError do 455 l = Google::Protobuf::RepeatedField.new(:message, [TestMessage2.new]) 456 end 457 end 458 459 def test_rptfield_array_ducktyping 460 l = Google::Protobuf::RepeatedField.new(:int32) 461 length_methods = %w(count length size) 462 length_methods.each do |lm| 463 assert l.send(lm) == 0 464 end 465 # out of bounds returns a nil 466 assert l[0] == nil 467 assert l[1] == nil 468 assert l[-1] == nil 469 l.push 4 470 length_methods.each do |lm| 471 assert l.send(lm) == 1 472 end 473 assert l[0] == 4 474 assert l[1] == nil 475 assert l[-1] == 4 476 assert l[-2] == nil 477 478 l.push 2 479 length_methods.each do |lm| 480 assert l.send(lm) == 2 481 end 482 assert l[0] == 4 483 assert l[1] == 2 484 assert l[2] == nil 485 assert l[-1] == 2 486 assert l[-2] == 4 487 assert l[-3] == nil 488 489 #adding out of scope will backfill with empty objects 490 end 491 492 def test_map_basic 493 # allowed key types: 494 # :int32, :int64, :uint32, :uint64, :bool, :string, :bytes. 495 496 m = Google::Protobuf::Map.new(:string, :int32) 497 m["asdf"] = 1 498 assert m["asdf"] == 1 499 m["jkl;"] = 42 500 assert m == { "jkl;" => 42, "asdf" => 1 } 501 assert m.has_key?("asdf") 502 assert !m.has_key?("qwerty") 503 assert m.length == 2 504 505 m2 = m.dup 506 assert m == m2 507 assert m.hash != 0 508 assert m.hash == m2.hash 509 510 collected = {} 511 m.each { |k,v| collected[v] = k } 512 assert collected == { 42 => "jkl;", 1 => "asdf" } 513 514 assert m.delete("asdf") == 1 515 assert !m.has_key?("asdf") 516 assert m["asdf"] == nil 517 assert !m.has_key?("asdf") 518 519 # We only assert on inspect value when there is one map entry because the 520 # order in which elements appear is unspecified (depends on the internal 521 # hash function). We don't want a brittle test. 522 assert m.inspect == "{\"jkl;\"=>42}" 523 524 assert m.keys == ["jkl;"] 525 assert m.values == [42] 526 527 m.clear 528 assert m.length == 0 529 assert m == {} 530 531 success = false 532 begin 533 m[1] = 1 534 rescue TypeError 535 success = true 536 end 537 assert(success) 538 539 assert_raise RangeError do 540 m["asdf"] = 0x1_0000_0000 541 end 542 end 543 544 def test_map_ctor 545 m = Google::Protobuf::Map.new(:string, :int32, 546 {"a" => 1, "b" => 2, "c" => 3}) 547 assert m == {"a" => 1, "c" => 3, "b" => 2} 548 end 549 550 def test_map_keytypes 551 m = Google::Protobuf::Map.new(:int32, :int32) 552 m[1] = 42 553 m[-1] = 42 554 assert_raise RangeError do 555 m[0x8000_0000] = 1 556 end 557 558 success = false 559 begin 560 m["asdf"] = 1 561 rescue TypeError 562 success = true 563 end 564 assert(success) 565 566 m = Google::Protobuf::Map.new(:int64, :int32) 567 m[0x1000_0000_0000_0000] = 1 568 assert_raise RangeError do 569 m[0x1_0000_0000_0000_0000] = 1 570 end 571 572 success = false 573 begin 574 m["asdf"] = 1 575 rescue TypeError 576 success = true 577 end 578 assert(success) 579 580 m = Google::Protobuf::Map.new(:uint32, :int32) 581 m[0x8000_0000] = 1 582 assert_raise RangeError do 583 m[0x1_0000_0000] = 1 584 end 585 assert_raise RangeError do 586 m[-1] = 1 587 end 588 589 m = Google::Protobuf::Map.new(:uint64, :int32) 590 m[0x8000_0000_0000_0000] = 1 591 assert_raise RangeError do 592 m[0x1_0000_0000_0000_0000] = 1 593 end 594 assert_raise RangeError do 595 m[-1] = 1 596 end 597 598 m = Google::Protobuf::Map.new(:bool, :int32) 599 m[true] = 1 600 m[false] = 2 601 602 success = false 603 begin 604 m[1] = 1 605 rescue TypeError 606 success = true 607 end 608 assert(success) 609 610 success = false 611 begin 612 m["asdf"] = 1 613 rescue TypeError 614 success = true 615 end 616 assert(success) 617 618 m = Google::Protobuf::Map.new(:string, :int32) 619 m["asdf"] = 1 620 success = false 621 begin 622 m[1] = 1 623 rescue TypeError 624 success = true 625 end 626 assert(success) 627 assert_raise Encoding::UndefinedConversionError do 628 bytestring = ["FFFF"].pack("H*") 629 m[bytestring] = 1 630 end 631 632 m = Google::Protobuf::Map.new(:bytes, :int32) 633 bytestring = ["FFFF"].pack("H*") 634 m[bytestring] = 1 635 # Allowed -- we will automatically convert to ASCII-8BIT. 636 m["asdf"] = 1 637 success = false 638 begin 639 m[1] = 1 640 rescue TypeError 641 success = true 642 end 643 assert(success) 644 end 645 646 def test_map_msg_enum_valuetypes 647 m = Google::Protobuf::Map.new(:string, :message, TestMessage) 648 m["asdf"] = TestMessage.new 649 success = false 650 begin 651 m["jkl;"] = TestMessage2.new 652 rescue TypeError 653 success = true 654 end 655 assert(success) 656 657 m = Google::Protobuf::Map.new( 658 :string, :message, TestMessage, 659 { "a" => TestMessage.new(:optional_int32 => 42), 660 "b" => TestMessage.new(:optional_int32 => 84) }) 661 assert m.length == 2 662 assert m.values.map{|msg| msg.optional_int32}.sort == [42, 84] 663 664 m = Google::Protobuf::Map.new(:string, :enum, TestEnum, 665 { "x" => :A, "y" => :B, "z" => :C }) 666 assert m.length == 3 667 assert m["z"] == :C 668 m["z"] = 2 669 assert m["z"] == :B 670 m["z"] = 4 671 assert m["z"] == 4 672 assert_raise RangeError do 673 m["z"] = :Z 674 end 675 assert_raise RangeError do 676 m["z"] = "z" 677 end 678 end 679 680 def test_map_dup_deep_copy 681 m = Google::Protobuf::Map.new( 682 :string, :message, TestMessage, 683 { "a" => TestMessage.new(:optional_int32 => 42), 684 "b" => TestMessage.new(:optional_int32 => 84) }) 685 686 m2 = m.dup 687 assert m == m2 688 assert m.object_id != m2.object_id 689 assert m["a"].object_id == m2["a"].object_id 690 assert m["b"].object_id == m2["b"].object_id 691 692 m2 = Google::Protobuf.deep_copy(m) 693 assert m == m2 694 assert m.object_id != m2.object_id 695 assert m["a"].object_id != m2["a"].object_id 696 assert m["b"].object_id != m2["b"].object_id 697 end 698 699 def test_map_field 700 m = MapMessage.new 701 assert m.map_string_int32 == {} 702 assert m.map_string_msg == {} 703 704 m = MapMessage.new( 705 :map_string_int32 => {"a" => 1, "b" => 2}, 706 :map_string_msg => {"a" => TestMessage2.new(:foo => 1), 707 "b" => TestMessage2.new(:foo => 2)}) 708 assert m.map_string_int32.keys.sort == ["a", "b"] 709 assert m.map_string_int32["a"] == 1 710 assert m.map_string_msg["b"].foo == 2 711 712 m.map_string_int32["c"] = 3 713 assert m.map_string_int32["c"] == 3 714 m.map_string_msg["c"] = TestMessage2.new(:foo => 3) 715 assert m.map_string_msg["c"] == TestMessage2.new(:foo => 3) 716 m.map_string_msg.delete("b") 717 m.map_string_msg.delete("c") 718 assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) } 719 720 success = false 721 begin 722 m.map_string_msg["e"] = TestMessage.new # wrong value type 723 rescue TypeError 724 success = true 725 end 726 assert(success) 727 # ensure nothing was added by the above 728 assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) } 729 730 m.map_string_int32 = Google::Protobuf::Map.new(:string, :int32) 731 success = false 732 begin 733 m.map_string_int32 = Google::Protobuf::Map.new(:string, :int64) 734 rescue TypeError 735 success = true 736 end 737 assert(success) 738 success = false 739 begin 740 m.map_string_int32 = {} 741 rescue TypeError 742 success = true 743 end 744 assert(success) 745 746 success = false 747 begin 748 m = MapMessage.new(:map_string_int32 => { 1 => "I am not a number" }) 749 rescue TypeError 750 success = true 751 end 752 assert(success) 753 end 754 755 def test_map_encode_decode 756 m = MapMessage.new( 757 :map_string_int32 => {"a" => 1, "b" => 2}, 758 :map_string_msg => {"a" => TestMessage2.new(:foo => 1), 759 "b" => TestMessage2.new(:foo => 2)}) 760 m2 = MapMessage.decode(MapMessage.encode(m)) 761 assert m == m2 762 763 m3 = MapMessageWireEquiv.decode(MapMessage.encode(m)) 764 assert m3.map_string_int32.length == 2 765 766 kv = {} 767 m3.map_string_int32.map { |msg| kv[msg.key] = msg.value } 768 assert kv == {"a" => 1, "b" => 2} 769 770 kv = {} 771 m3.map_string_msg.map { |msg| kv[msg.key] = msg.value } 772 assert kv == {"a" => TestMessage2.new(:foo => 1), 773 "b" => TestMessage2.new(:foo => 2)} 774 end 775 776 def test_oneof_descriptors 777 d = OneofMessage.descriptor 778 o = d.lookup_oneof("my_oneof") 779 assert o != nil 780 assert o.class == Google::Protobuf::OneofDescriptor 781 assert o.name == "my_oneof" 782 oneof_count = 0 783 d.each_oneof{ |oneof| 784 oneof_count += 1 785 assert oneof == o 786 } 787 assert oneof_count == 1 788 assert o.count == 4 789 field_names = o.map{|f| f.name}.sort 790 assert field_names == ["a", "b", "c", "d"] 791 end 792 793 def test_oneof 794 d = OneofMessage.new 795 assert d.a == "" 796 assert d.b == 0 797 assert d.c == nil 798 assert d.d == :Default 799 assert d.my_oneof == nil 800 801 d.a = "hi" 802 assert d.a == "hi" 803 assert d.b == 0 804 assert d.c == nil 805 assert d.d == :Default 806 assert d.my_oneof == :a 807 808 d.b = 42 809 assert d.a == "" 810 assert d.b == 42 811 assert d.c == nil 812 assert d.d == :Default 813 assert d.my_oneof == :b 814 815 d.c = TestMessage2.new(:foo => 100) 816 assert d.a == "" 817 assert d.b == 0 818 assert d.c.foo == 100 819 assert d.d == :Default 820 assert d.my_oneof == :c 821 822 d.d = :C 823 assert d.a == "" 824 assert d.b == 0 825 assert d.c == nil 826 assert d.d == :C 827 assert d.my_oneof == :d 828 829 d2 = OneofMessage.decode(OneofMessage.encode(d)) 830 assert d2 == d 831 832 encoded_field_a = OneofMessage.encode(OneofMessage.new(:a => "string")) 833 encoded_field_b = OneofMessage.encode(OneofMessage.new(:b => 1000)) 834 encoded_field_c = OneofMessage.encode( 835 OneofMessage.new(:c => TestMessage2.new(:foo => 1))) 836 encoded_field_d = OneofMessage.encode(OneofMessage.new(:d => :B)) 837 838 d3 = OneofMessage.decode( 839 encoded_field_c + encoded_field_a + encoded_field_d) 840 assert d3.a == "" 841 assert d3.b == 0 842 assert d3.c == nil 843 assert d3.d == :B 844 845 d4 = OneofMessage.decode( 846 encoded_field_c + encoded_field_a + encoded_field_d + 847 encoded_field_c) 848 assert d4.a == "" 849 assert d4.b == 0 850 assert d4.c.foo == 1 851 assert d4.d == :Default 852 853 d5 = OneofMessage.new(:a => "hello") 854 assert d5.a == "hello" 855 d5.a = nil 856 assert d5.a == "" 857 assert OneofMessage.encode(d5) == '' 858 assert d5.my_oneof == nil 859 end 860 861 def test_enum_field 862 m = TestMessage.new 863 assert m.optional_enum == :Default 864 m.optional_enum = :A 865 assert m.optional_enum == :A 866 assert_raise RangeError do 867 m.optional_enum = :ASDF 868 end 869 m.optional_enum = 1 870 assert m.optional_enum == :A 871 m.optional_enum = 100 872 assert m.optional_enum == 100 873 end 874 875 def test_dup 876 m = TestMessage.new 877 m.optional_string = "hello" 878 m.optional_int32 = 42 879 tm1 = TestMessage2.new(:foo => 100) 880 tm2 = TestMessage2.new(:foo => 200) 881 m.repeated_msg.push tm1 882 assert m.repeated_msg[-1] == tm1 883 m.repeated_msg.push tm2 884 assert m.repeated_msg[-1] == tm2 885 m2 = m.dup 886 assert m == m2 887 m.optional_int32 += 1 888 assert m != m2 889 assert m.repeated_msg[0] == m2.repeated_msg[0] 890 assert m.repeated_msg[0].object_id == m2.repeated_msg[0].object_id 891 end 892 893 def test_deep_copy 894 m = TestMessage.new(:optional_int32 => 42, 895 :repeated_msg => [TestMessage2.new(:foo => 100)]) 896 m2 = Google::Protobuf.deep_copy(m) 897 assert m == m2 898 assert m.repeated_msg == m2.repeated_msg 899 assert m.repeated_msg.object_id != m2.repeated_msg.object_id 900 assert m.repeated_msg[0].object_id != m2.repeated_msg[0].object_id 901 end 902 903 def test_eq 904 m = TestMessage.new(:optional_int32 => 42, 905 :repeated_int32 => [1, 2, 3]) 906 m2 = TestMessage.new(:optional_int32 => 43, 907 :repeated_int32 => [1, 2, 3]) 908 assert m != m2 909 end 910 911 def test_enum_lookup 912 assert TestEnum::A == 1 913 assert TestEnum::B == 2 914 assert TestEnum::C == 3 915 916 assert TestEnum::lookup(1) == :A 917 assert TestEnum::lookup(2) == :B 918 assert TestEnum::lookup(3) == :C 919 920 assert TestEnum::resolve(:A) == 1 921 assert TestEnum::resolve(:B) == 2 922 assert TestEnum::resolve(:C) == 3 923 end 924 925 def test_parse_serialize 926 m = TestMessage.new(:optional_int32 => 42, 927 :optional_string => "hello world", 928 :optional_enum => :B, 929 :repeated_string => ["a", "b", "c"], 930 :repeated_int32 => [42, 43, 44], 931 :repeated_enum => [:A, :B, :C, 100], 932 :repeated_msg => [TestMessage2.new(:foo => 1), 933 TestMessage2.new(:foo => 2)]) 934 data = TestMessage.encode m 935 m2 = TestMessage.decode data 936 assert m == m2 937 938 data = Google::Protobuf.encode m 939 m2 = Google::Protobuf.decode(TestMessage, data) 940 assert m == m2 941 end 942 943 def test_encode_decode_helpers 944 m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2']) 945 assert_equal 'foo', m.optional_string 946 assert_equal ['bar1', 'bar2'], m.repeated_string 947 948 json = m.to_json 949 m2 = TestMessage.decode_json(json) 950 assert_equal 'foo', m2.optional_string 951 assert_equal ['bar1', 'bar2'], m2.repeated_string 952 if RUBY_PLATFORM != "java" 953 assert m2.optional_string.frozen? 954 assert m2.repeated_string[0].frozen? 955 end 956 957 proto = m.to_proto 958 m2 = TestMessage.decode(proto) 959 assert_equal 'foo', m2.optional_string 960 assert_equal ['bar1', 'bar2'], m2.repeated_string 961 end 962 963 def test_protobuf_encode_decode_helpers 964 m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2']) 965 encoded_msg = Google::Protobuf.encode(m) 966 assert_equal m.to_proto, encoded_msg 967 968 decoded_msg = Google::Protobuf.decode(TestMessage, encoded_msg) 969 assert_equal TestMessage.decode(m.to_proto), decoded_msg 970 end 971 972 def test_protobuf_encode_decode_json_helpers 973 m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2']) 974 encoded_msg = Google::Protobuf.encode_json(m) 975 assert_equal m.to_json, encoded_msg 976 977 decoded_msg = Google::Protobuf.decode_json(TestMessage, encoded_msg) 978 assert_equal TestMessage.decode_json(m.to_json), decoded_msg 979 end 980 981 def test_to_h 982 m = TestMessage.new(:optional_bool => true, :optional_double => -10.100001, :optional_string => 'foo', :repeated_string => ['bar1', 'bar2']) 983 expected_result = { 984 :optional_bool=>true, 985 :optional_bytes=>"", 986 :optional_double=>-10.100001, 987 :optional_enum=>:Default, 988 :optional_float=>0.0, 989 :optional_int32=>0, 990 :optional_int64=>0, 991 :optional_msg=>nil, 992 :optional_string=>"foo", 993 :optional_uint32=>0, 994 :optional_uint64=>0, 995 :repeated_bool=>[], 996 :repeated_bytes=>[], 997 :repeated_double=>[], 998 :repeated_enum=>[], 999 :repeated_float=>[], 1000 :repeated_int32=>[], 1001 :repeated_int64=>[], 1002 :repeated_msg=>[], 1003 :repeated_string=>["bar1", "bar2"], 1004 :repeated_uint32=>[], 1005 :repeated_uint64=>[] 1006 } 1007 assert_equal expected_result, m.to_h 1008 end 1009 1010 1011 def test_def_errors 1012 s = Google::Protobuf::DescriptorPool.new 1013 success = false 1014 begin 1015 s.build do 1016 # enum with no default (integer value 0) 1017 add_enum "MyEnum" do 1018 value :A, 1 1019 end 1020 end 1021 rescue TypeError 1022 success = true 1023 end 1024 assert(success) 1025 success = false 1026 begin 1027 s.build do 1028 # message with required field (unsupported in proto3) 1029 add_message "MyMessage" do 1030 required :foo, :int32, 1 1031 end 1032 end 1033 rescue TypeError 1034 success = true 1035 end 1036 assert(success) 1037 end 1038 1039 def test_corecursive 1040 # just be sure that we can instantiate types with corecursive field-type 1041 # references. 1042 m = Recursive1.new(:foo => Recursive2.new(:foo => Recursive1.new)) 1043 assert Recursive1.descriptor.lookup("foo").subtype == 1044 Recursive2.descriptor 1045 assert Recursive2.descriptor.lookup("foo").subtype == 1046 Recursive1.descriptor 1047 1048 serialized = Recursive1.encode(m) 1049 m2 = Recursive1.decode(serialized) 1050 assert m == m2 1051 end 1052 1053 def test_serialize_cycle 1054 m = Recursive1.new(:foo => Recursive2.new) 1055 m.foo.foo = m 1056 assert_raise RuntimeError do 1057 serialized = Recursive1.encode(m) 1058 end 1059 end 1060 1061 def test_bad_field_names 1062 m = BadFieldNames.new(:dup => 1, :class => 2) 1063 m2 = m.dup 1064 assert m == m2 1065 assert m['dup'] == 1 1066 assert m['class'] == 2 1067 m['dup'] = 3 1068 assert m['dup'] == 3 1069 end 1070 1071 def test_int_ranges 1072 m = TestMessage.new 1073 1074 m.optional_int32 = 0 1075 m.optional_int32 = -0x8000_0000 1076 m.optional_int32 = +0x7fff_ffff 1077 m.optional_int32 = 1.0 1078 m.optional_int32 = -1.0 1079 m.optional_int32 = 2e9 1080 assert_raise RangeError do 1081 m.optional_int32 = -0x8000_0001 1082 end 1083 assert_raise RangeError do 1084 m.optional_int32 = +0x8000_0000 1085 end 1086 assert_raise RangeError do 1087 m.optional_int32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum 1088 end 1089 assert_raise RangeError do 1090 m.optional_int32 = 1e12 1091 end 1092 assert_raise RangeError do 1093 m.optional_int32 = 1.5 1094 end 1095 1096 m.optional_uint32 = 0 1097 m.optional_uint32 = +0xffff_ffff 1098 m.optional_uint32 = 1.0 1099 m.optional_uint32 = 4e9 1100 assert_raise RangeError do 1101 m.optional_uint32 = -1 1102 end 1103 assert_raise RangeError do 1104 m.optional_uint32 = -1.5 1105 end 1106 assert_raise RangeError do 1107 m.optional_uint32 = -1.5e12 1108 end 1109 assert_raise RangeError do 1110 m.optional_uint32 = -0x1000_0000_0000_0000 1111 end 1112 assert_raise RangeError do 1113 m.optional_uint32 = +0x1_0000_0000 1114 end 1115 assert_raise RangeError do 1116 m.optional_uint32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum 1117 end 1118 assert_raise RangeError do 1119 m.optional_uint32 = 1e12 1120 end 1121 assert_raise RangeError do 1122 m.optional_uint32 = 1.5 1123 end 1124 1125 m.optional_int64 = 0 1126 m.optional_int64 = -0x8000_0000_0000_0000 1127 m.optional_int64 = +0x7fff_ffff_ffff_ffff 1128 m.optional_int64 = 1.0 1129 m.optional_int64 = -1.0 1130 m.optional_int64 = 8e18 1131 m.optional_int64 = -8e18 1132 assert_raise RangeError do 1133 m.optional_int64 = -0x8000_0000_0000_0001 1134 end 1135 assert_raise RangeError do 1136 m.optional_int64 = +0x8000_0000_0000_0000 1137 end 1138 assert_raise RangeError do 1139 m.optional_int64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum 1140 end 1141 assert_raise RangeError do 1142 m.optional_int64 = 1e50 1143 end 1144 assert_raise RangeError do 1145 m.optional_int64 = 1.5 1146 end 1147 1148 m.optional_uint64 = 0 1149 m.optional_uint64 = +0xffff_ffff_ffff_ffff 1150 m.optional_uint64 = 1.0 1151 m.optional_uint64 = 16e18 1152 assert_raise RangeError do 1153 m.optional_uint64 = -1 1154 end 1155 assert_raise RangeError do 1156 m.optional_uint64 = -1.5 1157 end 1158 assert_raise RangeError do 1159 m.optional_uint64 = -1.5e12 1160 end 1161 assert_raise RangeError do 1162 m.optional_uint64 = -0x1_0000_0000_0000_0000 1163 end 1164 assert_raise RangeError do 1165 m.optional_uint64 = +0x1_0000_0000_0000_0000 1166 end 1167 assert_raise RangeError do 1168 m.optional_uint64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum 1169 end 1170 assert_raise RangeError do 1171 m.optional_uint64 = 1e50 1172 end 1173 assert_raise RangeError do 1174 m.optional_uint64 = 1.5 1175 end 1176 end 1177 1178 def test_stress_test 1179 m = TestMessage.new 1180 m.optional_int32 = 42 1181 m.optional_int64 = 0x100000000 1182 m.optional_string = "hello world" 1183 10.times do m.repeated_msg.push TestMessage2.new(:foo => 42) end 1184 10.times do m.repeated_string.push "hello world" end 1185 1186 data = TestMessage.encode(m) 1187 1188 l = 0 1189 10_000.times do 1190 m = TestMessage.decode(data) 1191 data_new = TestMessage.encode(m) 1192 assert data_new == data 1193 data = data_new 1194 end 1195 end 1196 1197 def test_reflection 1198 m = TestMessage.new(:optional_int32 => 1234) 1199 msgdef = m.class.descriptor 1200 assert msgdef.class == Google::Protobuf::Descriptor 1201 assert msgdef.any? {|field| field.name == "optional_int32"} 1202 optional_int32 = msgdef.lookup "optional_int32" 1203 assert optional_int32.class == Google::Protobuf::FieldDescriptor 1204 assert optional_int32 != nil 1205 assert optional_int32.name == "optional_int32" 1206 assert optional_int32.type == :int32 1207 optional_int32.set(m, 5678) 1208 assert m.optional_int32 == 5678 1209 m.optional_int32 = 1000 1210 assert optional_int32.get(m) == 1000 1211 1212 optional_msg = msgdef.lookup "optional_msg" 1213 assert optional_msg.subtype == TestMessage2.descriptor 1214 1215 optional_msg.set(m, optional_msg.subtype.msgclass.new) 1216 1217 assert msgdef.msgclass == TestMessage 1218 1219 optional_enum = msgdef.lookup "optional_enum" 1220 assert optional_enum.subtype == TestEnum.descriptor 1221 assert optional_enum.subtype.class == Google::Protobuf::EnumDescriptor 1222 optional_enum.subtype.each do |k, v| 1223 # set with integer, check resolution to symbolic name 1224 optional_enum.set(m, v) 1225 assert optional_enum.get(m) == k 1226 end 1227 end 1228 1229 def test_json 1230 # TODO: Fix JSON in JRuby version. 1231 return if RUBY_PLATFORM == "java" 1232 m = TestMessage.new(:optional_int32 => 1234, 1233 :optional_int64 => -0x1_0000_0000, 1234 :optional_uint32 => 0x8000_0000, 1235 :optional_uint64 => 0xffff_ffff_ffff_ffff, 1236 :optional_bool => true, 1237 :optional_float => 1.0, 1238 :optional_double => -1e100, 1239 :optional_string => "Test string", 1240 :optional_bytes => ["FFFFFFFF"].pack('H*'), 1241 :optional_msg => TestMessage2.new(:foo => 42), 1242 :repeated_int32 => [1, 2, 3, 4], 1243 :repeated_string => ["a", "b", "c"], 1244 :repeated_bool => [true, false, true, false], 1245 :repeated_msg => [TestMessage2.new(:foo => 1), 1246 TestMessage2.new(:foo => 2)]) 1247 1248 json_text = TestMessage.encode_json(m) 1249 m2 = TestMessage.decode_json(json_text) 1250 assert m == m2 1251 1252 # Crash case from GitHub issue 283. 1253 bar = Bar.new(msg: "bar") 1254 baz1 = Baz.new(msg: "baz") 1255 baz2 = Baz.new(msg: "quux") 1256 Foo.encode_json(Foo.new) 1257 Foo.encode_json(Foo.new(bar: bar)) 1258 Foo.encode_json(Foo.new(bar: bar, baz: [baz1, baz2])) 1259 end 1260 1261 def test_json_maps 1262 # TODO: Fix JSON in JRuby version. 1263 return if RUBY_PLATFORM == "java" 1264 m = MapMessage.new(:map_string_int32 => {"a" => 1}) 1265 expected = '{"mapStringInt32":{"a":1},"mapStringMsg":{}}' 1266 expected_preserve = '{"map_string_int32":{"a":1},"map_string_msg":{}}' 1267 assert MapMessage.encode_json(m) == expected 1268 1269 json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true) 1270 assert json == expected_preserve 1271 1272 m2 = MapMessage.decode_json(MapMessage.encode_json(m)) 1273 assert m == m2 1274 end 1275 end 1276end 1277