1require 'google/protobuf/wrappers_pb.rb' 2 3# Defines tests which are common between proto2 and proto3 syntax. 4# 5# Requires that the proto messages are exactly the same in proto2 and proto3 syntax 6# and that the including class should define a 'proto_module' method which returns 7# the enclosing module of the proto message classes. 8 9require 'bigdecimal' 10 11module CommonTests 12 # Ruby 2.5 changed to raise FrozenError instead of RuntimeError 13 FrozenErrorType = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.5') ? RuntimeError : FrozenError 14 15 def test_defaults 16 m = proto_module::TestMessage.new 17 assert m.optional_int32 == 0 18 assert m.optional_int64 == 0 19 assert m.optional_uint32 == 0 20 assert m.optional_uint64 == 0 21 assert m.optional_bool == false 22 assert m.optional_float == 0.0 23 assert m.optional_double == 0.0 24 assert m.optional_string == "" 25 assert m.optional_bytes == "" 26 assert m.optional_msg == nil 27 assert m.optional_enum == :Default 28 end 29 30 def test_setters 31 m = proto_module::TestMessage.new 32 m.optional_int32 = -42 33 assert m.optional_int32 == -42 34 m.optional_int64 = -0x1_0000_0000 35 assert m.optional_int64 == -0x1_0000_0000 36 m.optional_uint32 = 0x9000_0000 37 assert m.optional_uint32 == 0x9000_0000 38 m.optional_uint64 = 0x9000_0000_0000_0000 39 assert m.optional_uint64 == 0x9000_0000_0000_0000 40 m.optional_bool = true 41 assert m.optional_bool == true 42 m.optional_float = 0.5 43 assert m.optional_float == 0.5 44 m.optional_double = 0.5 45 assert m.optional_double == 0.5 46 m.optional_string = "hello" 47 assert m.optional_string == "hello" 48 m.optional_string = :hello 49 assert m.optional_string == "hello" 50 m.optional_bytes = "world".encode!('ASCII-8BIT') 51 assert m.optional_bytes == "world" 52 m.optional_msg = proto_module::TestMessage2.new(:foo => 42) 53 assert m.optional_msg == proto_module::TestMessage2.new(:foo => 42) 54 m.optional_msg = nil 55 assert m.optional_msg == nil 56 m.optional_enum = :C 57 assert m.optional_enum == :C 58 m.optional_enum = 'C' 59 assert m.optional_enum == :C 60 end 61 62 def test_ctor_args 63 m = proto_module::TestMessage.new(:optional_int32 => -42, 64 :optional_msg => proto_module::TestMessage2.new, 65 :optional_enum => :C, 66 :repeated_string => ["hello", "there", "world"]) 67 assert m.optional_int32 == -42 68 assert m.optional_msg.class == proto_module::TestMessage2 69 assert m.repeated_string.length == 3 70 assert m.optional_enum == :C 71 assert m.repeated_string[0] == "hello" 72 assert m.repeated_string[1] == "there" 73 assert m.repeated_string[2] == "world" 74 end 75 76 def test_ctor_string_symbol_args 77 m = proto_module::TestMessage.new(:optional_enum => 'C', :repeated_enum => ['A', 'B']) 78 assert_equal :C, m.optional_enum 79 assert_equal [:A, :B], m.repeated_enum 80 81 m = proto_module::TestMessage.new(:optional_string => :foo, :repeated_string => [:foo, :bar]) 82 assert_equal 'foo', m.optional_string 83 assert_equal ['foo', 'bar'], m.repeated_string 84 end 85 86 def test_ctor_nil_args 87 m = proto_module::TestMessage.new(:optional_enum => nil, :optional_int32 => nil, :optional_string => nil, :optional_msg => nil) 88 89 assert_equal :Default, m.optional_enum 90 assert_equal 0, m.optional_int32 91 assert_equal "", m.optional_string 92 assert_nil m.optional_msg 93 end 94 95 def test_embeddedmsg_hash_init 96 m = proto_module::TestEmbeddedMessageParent.new( 97 :child_msg => {sub_child: {optional_int32: 1}}, 98 :number => 2, 99 :repeated_msg => [{sub_child: {optional_int32: 3}}], 100 :repeated_number => [10, 20, 30]) 101 102 assert_equal 2, m.number 103 assert_equal [10, 20, 30], m.repeated_number 104 105 assert_not_nil m.child_msg 106 assert_not_nil m.child_msg.sub_child 107 assert_equal m.child_msg.sub_child.optional_int32, 1 108 109 assert_not_nil m.repeated_msg 110 assert_equal 1, m.repeated_msg.length 111 assert_equal 3, m.repeated_msg.first.sub_child.optional_int32 112 end 113 114 def test_inspect_eq_to_s 115 m = proto_module::TestMessage.new( 116 :optional_int32 => -42, 117 :optional_enum => :A, 118 :optional_msg => proto_module::TestMessage2.new(foo: 0), 119 :repeated_string => ["hello", "there", "world"]) 120 expected = "<#{proto_module}::TestMessage: optional_int32: -42, optional_msg: <#{proto_module}::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: []>" 121 assert_equal expected, m.inspect 122 assert_equal expected, m.to_s 123 124 m = proto_module::OneofMessage.new(:b => -42) 125 expected = "<#{proto_module}::OneofMessage: b: -42>" 126 assert_equal expected, m.inspect 127 assert_equal expected, m.to_s 128 end 129 130 def test_hash 131 m1 = proto_module::TestMessage.new(:optional_int32 => 42) 132 m2 = proto_module::TestMessage.new(:optional_int32 => 102, repeated_string: ['please', 'work', 'ok?']) 133 m3 = proto_module::TestMessage.new(:optional_int32 => 102, repeated_string: ['please', 'work', 'ok?']) 134 assert m1.hash != 0 135 assert m2.hash != 0 136 assert m3.hash != 0 137 # relying on the randomness here -- if hash function changes and we are 138 # unlucky enough to get a collision, then change the values above. 139 assert m1.hash != m2.hash 140 assert_equal m2.hash, m3.hash 141 end 142 143 def test_unknown_field_errors 144 e = assert_raise NoMethodError do 145 proto_module::TestMessage.new.hello 146 end 147 assert_match(/hello/, e.message) 148 149 e = assert_raise NoMethodError do 150 proto_module::TestMessage.new.hello = "world" 151 end 152 assert_match(/hello/, e.message) 153 end 154 155 def test_type_errors 156 m = proto_module::TestMessage.new 157 e = assert_raise Google::Protobuf::TypeError do 158 m.optional_int32 = "hello" 159 end 160 161 # Google::Protobuf::TypeError should inherit from TypeError for backwards compatibility 162 # TODO: This can be removed when we can safely migrate to Google::Protobuf::TypeError 163 assert e.is_a?(::TypeError) 164 165 assert_raise Google::Protobuf::TypeError do 166 m.optional_string = 42 167 end 168 assert_raise Google::Protobuf::TypeError do 169 m.optional_string = nil 170 end 171 assert_raise Google::Protobuf::TypeError do 172 m.optional_bool = 42 173 end 174 assert_raise Google::Protobuf::TypeError do 175 m.optional_msg = proto_module::TestMessage.new # expects TestMessage2 176 end 177 178 assert_raise Google::Protobuf::TypeError do 179 m.repeated_int32 = [] # needs RepeatedField 180 end 181 182 assert_raise Google::Protobuf::TypeError do 183 m.repeated_int32.push "hello" 184 end 185 186 assert_raise Google::Protobuf::TypeError do 187 m.repeated_msg.push proto_module::TestMessage.new 188 end 189 end 190 191 def test_string_encoding 192 m = proto_module::TestMessage.new 193 194 # Assigning a normal (ASCII or UTF8) string to a bytes field, or 195 # ASCII-8BIT to a string field will convert to the proper encoding. 196 m.optional_bytes = "Test string ASCII".encode!('ASCII') 197 assert m.optional_bytes.frozen? 198 assert_equal Encoding::ASCII_8BIT, m.optional_bytes.encoding 199 assert_equal "Test string ASCII", m.optional_bytes 200 201 assert_raise Encoding::UndefinedConversionError do 202 m.optional_bytes = "Test string UTF-8 \u0100".encode!('UTF-8') 203 end 204 205 assert_raise Encoding::UndefinedConversionError do 206 m.optional_string = ["FFFF"].pack('H*') 207 end 208 209 # "Ordinary" use case. 210 m.optional_bytes = ["FFFF"].pack('H*') 211 m.optional_string = "\u0100" 212 213 # strings are immutable so we can't do this, but serialize should catch it. 214 m.optional_string = "asdf".encode!('UTF-8') 215 assert_raise(FrozenErrorType) { m.optional_string.encode!('ASCII-8BIT') } 216 end 217 218 def test_rptfield_int32 219 l = Google::Protobuf::RepeatedField.new(:int32) 220 assert l.count == 0 221 l = Google::Protobuf::RepeatedField.new(:int32, [1, 2, 3]) 222 assert l.count == 3 223 assert_equal [1, 2, 3], l 224 assert_equal l, [1, 2, 3] 225 l.push 4 226 assert l == [1, 2, 3, 4] 227 dst_list = [] 228 l.each { |val| dst_list.push val } 229 assert dst_list == [1, 2, 3, 4] 230 assert l.to_a == [1, 2, 3, 4] 231 assert l[0] == 1 232 assert l[3] == 4 233 l[0] = 5 234 assert l == [5, 2, 3, 4] 235 236 l2 = l.dup 237 assert l == l2 238 assert l.object_id != l2.object_id 239 l2.push 6 240 assert l.count == 4 241 assert l2.count == 5 242 243 assert l.inspect == '[5, 2, 3, 4]' 244 245 l.concat([7, 8, 9]) 246 assert l == [5, 2, 3, 4, 7, 8, 9] 247 assert l.pop == 9 248 assert l == [5, 2, 3, 4, 7, 8] 249 250 assert_raise Google::Protobuf::TypeError do 251 m = proto_module::TestMessage.new 252 l.push m 253 end 254 255 m = proto_module::TestMessage.new 256 m.repeated_int32 = l 257 assert m.repeated_int32 == [5, 2, 3, 4, 7, 8] 258 assert m.repeated_int32.object_id == l.object_id 259 l.push 42 260 assert m.repeated_int32.pop == 42 261 262 l3 = l + l.dup 263 assert l3.count == l.count * 2 264 l.count.times do |i| 265 assert l3[i] == l[i] 266 assert l3[l.count + i] == l[i] 267 end 268 269 l.clear 270 assert l.count == 0 271 l += [1, 2, 3, 4] 272 l.replace([5, 6, 7, 8]) 273 assert l == [5, 6, 7, 8] 274 275 l4 = Google::Protobuf::RepeatedField.new(:int32) 276 l4[5] = 42 277 assert l4 == [0, 0, 0, 0, 0, 42] 278 279 l4 << 100 280 assert l4 == [0, 0, 0, 0, 0, 42, 100] 281 l4 << 101 << 102 282 assert l4 == [0, 0, 0, 0, 0, 42, 100, 101, 102] 283 end 284 285 def test_parent_rptfield 286 #make sure we set the RepeatedField and can add to it 287 m = proto_module::TestMessage.new 288 assert m.repeated_string == [] 289 m.repeated_string << 'ok' 290 m.repeated_string.push('ok2') 291 assert m.repeated_string == ['ok', 'ok2'] 292 m.repeated_string += ['ok3'] 293 assert m.repeated_string == ['ok', 'ok2', 'ok3'] 294 end 295 296 def test_rptfield_msg 297 l = Google::Protobuf::RepeatedField.new(:message, proto_module::TestMessage) 298 l.push proto_module::TestMessage.new 299 assert l.count == 1 300 assert_raise Google::Protobuf::TypeError do 301 l.push proto_module::TestMessage2.new 302 end 303 assert_raise Google::Protobuf::TypeError do 304 l.push 42 305 end 306 307 l2 = l.dup 308 assert l2[0] == l[0] 309 assert l2[0].object_id == l[0].object_id 310 311 l2 = Google::Protobuf.deep_copy(l) 312 assert l2[0] == l[0] 313 assert l2[0].object_id != l[0].object_id 314 315 l3 = l + l2 316 assert l3.count == 2 317 assert l3[0] == l[0] 318 assert l3[1] == l2[0] 319 l3[0].optional_int32 = 1000 320 assert l[0].optional_int32 == 1000 321 322 new_msg = proto_module::TestMessage.new(:optional_int32 => 200) 323 l4 = l + [new_msg] 324 assert l4.count == 2 325 new_msg.optional_int32 = 1000 326 assert l4[1].optional_int32 == 1000 327 end 328 329 def test_rptfield_enum 330 l = Google::Protobuf::RepeatedField.new(:enum, proto_module::TestEnum) 331 l.push :A 332 l.push :B 333 l.push :C 334 assert l.count == 3 335 assert_raise RangeError do 336 l.push :D 337 end 338 assert l[0] == :A 339 340 l.push 4 341 assert l[3] == 4 342 end 343 344 def test_rptfield_initialize 345 assert_raise ArgumentError do 346 Google::Protobuf::RepeatedField.new 347 end 348 assert_raise ArgumentError do 349 Google::Protobuf::RepeatedField.new(:message) 350 end 351 assert_raise ArgumentError do 352 Google::Protobuf::RepeatedField.new([1, 2, 3]) 353 end 354 assert_raise ArgumentError do 355 Google::Protobuf::RepeatedField.new(:message, [proto_module::TestMessage2.new]) 356 end 357 end 358 359 def test_rptfield_array_ducktyping 360 l = Google::Protobuf::RepeatedField.new(:int32) 361 length_methods = %w(count length size) 362 length_methods.each do |lm| 363 assert l.send(lm) == 0 364 end 365 # out of bounds returns a nil 366 assert l[0] == nil 367 assert l[1] == nil 368 assert l[-1] == nil 369 l.push 4 370 length_methods.each do |lm| 371 assert l.send(lm) == 1 372 end 373 assert l[0] == 4 374 assert l[1] == nil 375 assert l[-1] == 4 376 assert l[-2] == nil 377 378 l.push 2 379 length_methods.each do |lm| 380 assert l.send(lm) == 2 381 end 382 assert l[0] == 4 383 assert l[1] == 2 384 assert l[2] == nil 385 assert l[-1] == 2 386 assert l[-2] == 4 387 assert l[-3] == nil 388 389 #adding out of scope will backfill with empty objects 390 end 391 392 def test_map_basic 393 # allowed key types: 394 # :int32, :int64, :uint32, :uint64, :bool, :string, :bytes. 395 396 m = Google::Protobuf::Map.new(:string, :int32) 397 m["asdf"] = 1 398 assert m["asdf"] == 1 399 m["jkl;"] = 42 400 assert m == { "jkl;" => 42, "asdf" => 1 } 401 assert m.has_key?("asdf") 402 assert !m.has_key?("qwerty") 403 assert m.length == 2 404 405 m2 = m.dup 406 assert_equal m, m2 407 assert m.hash != 0 408 assert_equal m.hash, m2.hash 409 410 collected = {} 411 m.each { |k,v| collected[v] = k } 412 assert collected == { 42 => "jkl;", 1 => "asdf" } 413 414 assert m.delete("asdf") == 1 415 assert !m.has_key?("asdf") 416 assert m["asdf"] == nil 417 assert !m.has_key?("asdf") 418 419 # We only assert on inspect value when there is one map entry because the 420 # order in which elements appear is unspecified (depends on the internal 421 # hash function). We don't want a brittle test. 422 assert m.inspect == "{\"jkl;\"=>42}" 423 424 assert m.keys == ["jkl;"] 425 assert m.values == [42] 426 427 m.clear 428 assert m.length == 0 429 assert m == {} 430 431 assert_raise Google::Protobuf::TypeError do 432 m[1] = 1 433 end 434 assert_raise RangeError do 435 m["asdf"] = 0x1_0000_0000 436 end 437 end 438 439 def test_b_8385 440 m1 = Google::Protobuf::Map.new(:string, :string) 441 m2 = Google::Protobuf::Map.new(:string, :string) 442 443 assert_equal m1, m2 444 445 m1["counter"] = "a" 446 m2["counter"] = "aa" 447 448 assert_not_equal m1, m2 449 end 450 451 def test_map_ctor 452 m = Google::Protobuf::Map.new(:string, :int32, 453 {"a" => 1, "b" => 2, "c" => 3}) 454 assert m == {"a" => 1, "c" => 3, "b" => 2} 455 end 456 457 def test_map_keytypes 458 m = Google::Protobuf::Map.new(:int32, :int32) 459 m[1] = 42 460 m[-1] = 42 461 assert_raise RangeError do 462 m[0x8000_0000] = 1 463 end 464 assert_raise Google::Protobuf::TypeError do 465 m["asdf"] = 1 466 end 467 468 m = Google::Protobuf::Map.new(:int64, :int32) 469 m[0x1000_0000_0000_0000] = 1 470 assert_raise RangeError do 471 m[0x1_0000_0000_0000_0000] = 1 472 end 473 assert_raise Google::Protobuf::TypeError do 474 m["asdf"] = 1 475 end 476 477 m = Google::Protobuf::Map.new(:uint32, :int32) 478 m[0x8000_0000] = 1 479 assert_raise RangeError do 480 m[0x1_0000_0000] = 1 481 end 482 assert_raise RangeError do 483 m[-1] = 1 484 end 485 486 m = Google::Protobuf::Map.new(:uint64, :int32) 487 m[0x8000_0000_0000_0000] = 1 488 assert_raise RangeError do 489 m[0x1_0000_0000_0000_0000] = 1 490 end 491 assert_raise RangeError do 492 m[-1] = 1 493 end 494 495 m = Google::Protobuf::Map.new(:bool, :int32) 496 m[true] = 1 497 m[false] = 2 498 assert_raise Google::Protobuf::TypeError do 499 m[1] = 1 500 end 501 assert_raise Google::Protobuf::TypeError do 502 m["asdf"] = 1 503 end 504 505 m = Google::Protobuf::Map.new(:string, :int32) 506 m["asdf"] = 1 507 assert_raise Google::Protobuf::TypeError do 508 m[1] = 1 509 end 510 assert_raise Encoding::UndefinedConversionError do 511 bytestring = ["FFFF"].pack("H*") 512 m[bytestring] = 1 513 end 514 515 m = Google::Protobuf::Map.new(:bytes, :int32) 516 bytestring = ["FFFF"].pack("H*") 517 m[bytestring] = 1 518 # Allowed -- we will automatically convert to ASCII-8BIT. 519 m["asdf"] = 1 520 assert_raise Google::Protobuf::TypeError do 521 m[1] = 1 522 end 523 end 524 525 def test_map_msg_enum_valuetypes 526 m = Google::Protobuf::Map.new(:string, :message, proto_module::TestMessage) 527 m["asdf"] = proto_module::TestMessage.new 528 assert_raise Google::Protobuf::TypeError do 529 m["jkl;"] = proto_module::TestMessage2.new 530 end 531 532 m = Google::Protobuf::Map.new( 533 :string, :message, proto_module::TestMessage, 534 { "a" => proto_module::TestMessage.new(:optional_int32 => 42), 535 "b" => proto_module::TestMessage.new(:optional_int32 => 84) }) 536 assert m.length == 2 537 assert m.values.map{|msg| msg.optional_int32}.sort == [42, 84] 538 539 m = Google::Protobuf::Map.new(:string, :enum, proto_module::TestEnum, 540 { "x" => :A, "y" => :B, "z" => :C }) 541 assert m.length == 3 542 assert m["z"] == :C 543 m["z"] = 2 544 assert m["z"] == :B 545 m["z"] = 4 546 assert m["z"] == 4 547 assert_raise RangeError do 548 m["z"] = :Z 549 end 550 assert_raise RangeError do 551 m["z"] = "z" 552 end 553 end 554 555 def test_map_dup_deep_copy 556 m = Google::Protobuf::Map.new( 557 :string, :message, proto_module::TestMessage, 558 { "a" => proto_module::TestMessage.new(:optional_int32 => 42), 559 "b" => proto_module::TestMessage.new(:optional_int32 => 84) }) 560 561 m2 = m.dup 562 assert m.to_h == m2.to_h 563 assert m == m2 564 assert m.object_id != m2.object_id 565 assert m["a"].object_id == m2["a"].object_id 566 assert m["b"].object_id == m2["b"].object_id 567 568 m2 = Google::Protobuf.deep_copy(m) 569 assert m == m2 570 assert m.object_id != m2.object_id 571 assert m["a"].object_id != m2["a"].object_id 572 assert m["b"].object_id != m2["b"].object_id 573 end 574 575 def test_oneof_descriptors 576 d = proto_module::OneofMessage.descriptor 577 o = d.lookup_oneof("my_oneof") 578 assert o != nil 579 assert o.class == Google::Protobuf::OneofDescriptor 580 assert o.name == "my_oneof" 581 oneof_count = 0 582 d.each_oneof{ |oneof| 583 oneof_count += 1 584 assert oneof == o 585 } 586 assert oneof_count == 1 587 assert o.count == 4 588 field_names = o.map{|f| f.name}.sort 589 assert field_names == ["a", "b", "c", "d"] 590 end 591 592 def test_oneof 593 d = proto_module::OneofMessage.new 594 assert d.a == "" 595 assert d.b == 0 596 assert d.c == nil 597 assert d.d == :Default 598 assert d.my_oneof == nil 599 600 d.a = "hi" 601 assert d.a == "hi" 602 assert d.b == 0 603 assert d.c == nil 604 assert d.d == :Default 605 assert d.my_oneof == :a 606 607 d.b = 42 608 assert d.a == "" 609 assert d.b == 42 610 assert d.c == nil 611 assert d.d == :Default 612 assert d.my_oneof == :b 613 614 d.c = proto_module::TestMessage2.new(:foo => 100) 615 assert d.a == "" 616 assert d.b == 0 617 assert d.c.foo == 100 618 assert d.d == :Default 619 assert d.my_oneof == :c 620 621 d.d = :C 622 assert d.a == "" 623 assert d.b == 0 624 assert d.c == nil 625 assert d.d == :C 626 assert d.my_oneof == :d 627 628 d2 = proto_module::OneofMessage.decode(proto_module::OneofMessage.encode(d)) 629 assert d2 == d 630 631 encoded_field_a = proto_module::OneofMessage.encode(proto_module::OneofMessage.new(:a => "string")) 632 encoded_field_b = proto_module::OneofMessage.encode(proto_module::OneofMessage.new(:b => 1000)) 633 encoded_field_c = proto_module::OneofMessage.encode( 634 proto_module::OneofMessage.new(:c => proto_module::TestMessage2.new(:foo => 1))) 635 encoded_field_d = proto_module::OneofMessage.encode(proto_module::OneofMessage.new(:d => :B)) 636 637 d3 = proto_module::OneofMessage.decode( 638 encoded_field_c + encoded_field_a + encoded_field_b + encoded_field_d) 639 assert d3.a == "" 640 assert d3.b == 0 641 assert d3.c == nil 642 assert d3.d == :B 643 644 d4 = proto_module::OneofMessage.decode( 645 encoded_field_c + encoded_field_a + encoded_field_b + encoded_field_d + 646 encoded_field_c) 647 assert d4.a == "" 648 assert d4.b == 0 649 assert d4.c.foo == 1 650 assert d4.d == :Default 651 652 d5 = proto_module::OneofMessage.new(:a => "hello") 653 assert d5.a == "hello" 654 d5.a = nil 655 assert d5.a == "" 656 assert proto_module::OneofMessage.encode(d5) == '' 657 assert d5.my_oneof == nil 658 end 659 660 def test_enum_field 661 m = proto_module::TestMessage.new 662 assert m.optional_enum == :Default 663 m.optional_enum = :A 664 assert m.optional_enum == :A 665 assert_raise RangeError do 666 m.optional_enum = :ASDF 667 end 668 m.optional_enum = 1 669 assert m.optional_enum == :A 670 m.optional_enum = 100 671 assert m.optional_enum == 100 672 end 673 674 def test_dup 675 m = proto_module::TestMessage.new 676 m.optional_string = "hello" 677 m.optional_int32 = 42 678 tm1 = proto_module::TestMessage2.new(:foo => 100) 679 tm2 = proto_module::TestMessage2.new(:foo => 200) 680 m.repeated_msg.push tm1 681 assert m.repeated_msg[-1] == tm1 682 m.repeated_msg.push tm2 683 assert m.repeated_msg[-1] == tm2 684 m2 = m.dup 685 assert m == m2 686 m.optional_int32 += 1 687 assert m != m2 688 assert m.repeated_msg[0] == m2.repeated_msg[0] 689 assert m.repeated_msg[0].object_id == m2.repeated_msg[0].object_id 690 end 691 692 def test_deep_copy 693 m = proto_module::TestMessage.new(:optional_int32 => 42, 694 :repeated_msg => [proto_module::TestMessage2.new(:foo => 100)]) 695 m2 = Google::Protobuf.deep_copy(m) 696 assert m == m2 697 assert m.repeated_msg == m2.repeated_msg 698 assert m.repeated_msg.object_id != m2.repeated_msg.object_id 699 assert m.repeated_msg[0].object_id != m2.repeated_msg[0].object_id 700 end 701 702 def test_message_eq 703 m = proto_module::TestMessage.new(:optional_int32 => 42, 704 :repeated_int32 => [1, 2, 3]) 705 m2 = proto_module::TestMessage.new(:optional_int32 => 43, 706 :repeated_int32 => [1, 2, 3]) 707 assert m != m2 708 assert_not_equal proto_module::TestMessage.new, proto_module::TestMessage2.new 709 end 710 711 def test_enum_lookup 712 assert proto_module::TestEnum::A == 1 713 assert proto_module::TestEnum::B == 2 714 assert proto_module::TestEnum::C == 3 715 716 assert proto_module::TestEnum::lookup(1) == :A 717 assert proto_module::TestEnum::lookup(2) == :B 718 assert proto_module::TestEnum::lookup(3) == :C 719 720 assert proto_module::TestEnum::resolve(:A) == 1 721 assert proto_module::TestEnum::resolve(:B) == 2 722 assert proto_module::TestEnum::resolve(:C) == 3 723 end 724 725 def test_enum_const_get_helpers 726 m = proto_module::TestMessage.new 727 assert_equal proto_module::TestEnum::Default, m.optional_enum_const 728 assert_equal proto_module::TestEnum.const_get(:Default), m.optional_enum_const 729 730 m = proto_module::TestMessage.new({optional_enum: proto_module::TestEnum::A}) 731 assert_equal proto_module::TestEnum::A, m.optional_enum_const 732 assert_equal proto_module::TestEnum.const_get(:A), m.optional_enum_const 733 734 m = proto_module::TestMessage.new({optional_enum: proto_module::TestEnum::B}) 735 assert_equal proto_module::TestEnum::B, m.optional_enum_const 736 assert_equal proto_module::TestEnum.const_get(:B), m.optional_enum_const 737 738 m = proto_module::TestMessage.new({optional_enum: proto_module::TestEnum::C}) 739 assert_equal proto_module::TestEnum::C, m.optional_enum_const 740 assert_equal proto_module::TestEnum.const_get(:C), m.optional_enum_const 741 742 m = proto_module::TestMessage2.new({foo: 2}) 743 assert_equal 2, m.foo 744 assert_raise(NoMethodError) { m.foo_ } 745 assert_raise(NoMethodError) { m.foo_X } 746 assert_raise(NoMethodError) { m.foo_XX } 747 assert_raise(NoMethodError) { m.foo_XXX } 748 assert_raise(NoMethodError) { m.foo_XXXX } 749 assert_raise(NoMethodError) { m.foo_XXXXX } 750 assert_raise(NoMethodError) { m.foo_XXXXXX } 751 752 m = proto_module::Enumer.new({optional_enum: :B}) 753 assert_equal :B, m.optional_enum 754 assert_raise(NoMethodError) { m.optional_enum_ } 755 assert_raise(NoMethodError) { m.optional_enum_X } 756 assert_raise(NoMethodError) { m.optional_enum_XX } 757 assert_raise(NoMethodError) { m.optional_enum_XXX } 758 assert_raise(NoMethodError) { m.optional_enum_XXXX } 759 assert_raise(NoMethodError) { m.optional_enum_XXXXX } 760 assert_raise(NoMethodError) { m.optional_enum_XXXXXX } 761 end 762 763 def test_enum_getter 764 m = proto_module::Enumer.new(:optional_enum => :B, :repeated_enum => [:A, :C]) 765 766 assert_equal :B, m.optional_enum 767 assert_equal 2, m.optional_enum_const 768 assert_equal proto_module::TestEnum::B, m.optional_enum_const 769 assert_equal [:A, :C], m.repeated_enum 770 assert_equal [1, 3], m.repeated_enum_const 771 assert_equal [proto_module::TestEnum::A, proto_module::TestEnum::C], m.repeated_enum_const 772 end 773 774 def test_enum_getter_oneof 775 m = proto_module::Enumer.new(:const => :C) 776 777 assert_equal :C, m.const 778 assert_equal 3, m.const_const 779 assert_equal proto_module::TestEnum::C, m.const_const 780 end 781 782 def test_enum_getter_only_enums 783 m = proto_module::Enumer.new(:optional_enum => :B, :a_const => 'thing') 784 785 assert_equal 'thing', m.a_const 786 assert_equal :B, m.optional_enum 787 788 assert_raise(NoMethodError) { m.a } 789 assert_raise(NoMethodError) { m.a_const_const } 790 end 791 792 def test_repeated_push 793 m = proto_module::TestMessage.new 794 795 m.repeated_string += ['one'] 796 m.repeated_string += %w[two three] 797 assert_equal %w[one two three], m.repeated_string 798 799 m.repeated_string.push( *['four', 'five'] ) 800 assert_equal %w[one two three four five], m.repeated_string 801 802 m.repeated_string.push 'six', 'seven' 803 assert_equal %w[one two three four five six seven], m.repeated_string 804 805 m = proto_module::TestMessage.new 806 807 m.repeated_msg += [proto_module::TestMessage2.new(:foo => 1), proto_module::TestMessage2.new(:foo => 2)] 808 m.repeated_msg += [proto_module::TestMessage2.new(:foo => 3)] 809 m.repeated_msg.push proto_module::TestMessage2.new(:foo => 4), proto_module::TestMessage2.new(:foo => 5) 810 assert_equal [1, 2, 3, 4, 5], m.repeated_msg.map {|x| x.foo} 811 end 812 813 def test_parse_serialize 814 m = proto_module::TestMessage.new(:optional_int32 => 42, 815 :optional_string => "hello world", 816 :optional_enum => :B, 817 :repeated_string => ["a", "b", "c"], 818 :repeated_int32 => [42, 43, 44], 819 :repeated_enum => [:A, :B, :C], 820 :repeated_msg => [proto_module::TestMessage2.new(:foo => 1), 821 proto_module::TestMessage2.new(:foo => 2)]) 822 if proto_module == ::BasicTest 823 # For proto3 we can add an unknown enum value safely. 824 m.repeated_enum << 100 825 end 826 827 data = proto_module::TestMessage.encode m 828 m2 = proto_module::TestMessage.decode data 829 830 assert_equal m, m2 831 832 data = Google::Protobuf.encode m 833 m2 = Google::Protobuf.decode(proto_module::TestMessage, data) 834 assert m == m2 835 end 836 837 def test_encode_decode_helpers 838 m = proto_module::TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2']) 839 assert_equal 'foo', m.optional_string 840 assert_equal ['bar1', 'bar2'], m.repeated_string 841 842 json = m.to_json 843 m2 = proto_module::TestMessage.decode_json(json) 844 assert_equal 'foo', m2.optional_string 845 assert_equal ['bar1', 'bar2'], m2.repeated_string 846 if RUBY_PLATFORM != "java" 847 assert m2.optional_string.frozen? 848 assert m2.repeated_string[0].frozen? 849 end 850 851 proto = m.to_proto 852 m2 = proto_module::TestMessage.decode(proto) 853 assert_equal 'foo', m2.optional_string 854 assert_equal ['bar1', 'bar2'], m2.repeated_string 855 end 856 857 def test_protobuf_encode_decode_helpers 858 m = proto_module::TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2']) 859 encoded_msg = Google::Protobuf.encode(m) 860 assert_equal m.to_proto, encoded_msg 861 862 decoded_msg = Google::Protobuf.decode(proto_module::TestMessage, encoded_msg) 863 assert_equal proto_module::TestMessage.decode(m.to_proto), decoded_msg 864 end 865 866 def test_protobuf_encode_decode_json_helpers 867 m = proto_module::TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2']) 868 encoded_msg = Google::Protobuf.encode_json(m) 869 assert_equal m.to_json, encoded_msg 870 871 decoded_msg = Google::Protobuf.decode_json(proto_module::TestMessage, encoded_msg) 872 assert_equal proto_module::TestMessage.decode_json(m.to_json), decoded_msg 873 874 assert_equal [m].to_json, Google::Protobuf.encode_json([m]) 875 assert_equal proto_module::TestMessage.decode_json([m.to_json].first), decoded_msg 876 end 877 878 def test_def_errors 879 s = Google::Protobuf::DescriptorPool.new 880 assert_raise Google::Protobuf::TypeError do 881 s.build do 882 # enum with no default (integer value 0) 883 add_enum "MyEnum" do 884 value :A, 1 885 end 886 end 887 end 888 assert_raise Google::Protobuf::TypeError do 889 s.build do 890 # message with required field (unsupported in proto3) 891 add_message "MyMessage" do 892 required :foo, :int32, 1 893 end 894 end 895 end 896 end 897 898 def test_corecursive 899 # just be sure that we can instantiate types with corecursive field-type 900 # references. 901 m = proto_module::Recursive1.new(:foo => proto_module::Recursive2.new(:foo => proto_module::Recursive1.new)) 902 assert proto_module::Recursive1.descriptor.lookup("foo").subtype == 903 proto_module::Recursive2.descriptor 904 assert proto_module::Recursive2.descriptor.lookup("foo").subtype == 905 proto_module::Recursive1.descriptor 906 907 serialized = proto_module::Recursive1.encode(m) 908 m2 = proto_module::Recursive1.decode(serialized) 909 assert m == m2 910 end 911 912 def test_serialize_cycle 913 m = proto_module::Recursive1.new(:foo => proto_module::Recursive2.new) 914 m.foo.foo = m 915 assert_raise RuntimeError do 916 proto_module::Recursive1.encode(m) 917 end 918 end 919 920 def test_bad_field_names 921 m = proto_module::BadFieldNames.new(:dup => 1, :class => 2) 922 m2 = m.dup 923 assert m == m2 924 assert m['dup'] == 1 925 assert m['class'] == 2 926 m['dup'] = 3 927 assert m['dup'] == 3 928 end 929 930 def test_int_ranges 931 m = proto_module::TestMessage.new 932 933 m.optional_int32 = 0 934 m.optional_int32 = -0x8000_0000 935 m.optional_int32 = +0x7fff_ffff 936 m.optional_int32 = 1.0 937 m.optional_int32 = -1.0 938 m.optional_int32 = 2e9 939 assert_raise RangeError do 940 m.optional_int32 = -0x8000_0001 941 end 942 assert_raise RangeError do 943 m.optional_int32 = +0x8000_0000 944 end 945 assert_raise RangeError do 946 m.optional_int32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum 947 end 948 assert_raise RangeError do 949 m.optional_int32 = 1e12 950 end 951 assert_raise RangeError do 952 m.optional_int32 = 1.5 953 end 954 955 m.optional_uint32 = 0 956 m.optional_uint32 = +0xffff_ffff 957 m.optional_uint32 = 1.0 958 m.optional_uint32 = 4e9 959 assert_raise RangeError do 960 m.optional_uint32 = -1 961 end 962 assert_raise RangeError do 963 m.optional_uint32 = -1.5 964 end 965 assert_raise RangeError do 966 m.optional_uint32 = -1.5e12 967 end 968 assert_raise RangeError do 969 m.optional_uint32 = -0x1000_0000_0000_0000 970 end 971 assert_raise RangeError do 972 m.optional_uint32 = +0x1_0000_0000 973 end 974 assert_raise RangeError do 975 m.optional_uint32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum 976 end 977 assert_raise RangeError do 978 m.optional_uint32 = 1e12 979 end 980 assert_raise RangeError do 981 m.optional_uint32 = 1.5 982 end 983 984 m.optional_int64 = 0 985 m.optional_int64 = -0x8000_0000_0000_0000 986 m.optional_int64 = +0x7fff_ffff_ffff_ffff 987 m.optional_int64 = 1.0 988 m.optional_int64 = -1.0 989 m.optional_int64 = 8e18 990 m.optional_int64 = -8e18 991 assert_raise RangeError do 992 m.optional_int64 = -0x8000_0000_0000_0001 993 end 994 assert_raise RangeError do 995 m.optional_int64 = +0x8000_0000_0000_0000 996 end 997 assert_raise RangeError do 998 m.optional_int64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum 999 end 1000 assert_raise RangeError do 1001 m.optional_int64 = 1e50 1002 end 1003 assert_raise RangeError do 1004 m.optional_int64 = 1.5 1005 end 1006 1007 m.optional_uint64 = 0 1008 m.optional_uint64 = +0xffff_ffff_ffff_ffff 1009 m.optional_uint64 = 1.0 1010 m.optional_uint64 = 16e18 1011 assert_raise RangeError do 1012 m.optional_uint64 = -1 1013 end 1014 assert_raise RangeError do 1015 m.optional_uint64 = -1.5 1016 end 1017 assert_raise RangeError do 1018 m.optional_uint64 = -1.5e12 1019 end 1020 assert_raise RangeError do 1021 m.optional_uint64 = -0x1_0000_0000_0000_0000 1022 end 1023 assert_raise RangeError do 1024 m.optional_uint64 = +0x1_0000_0000_0000_0000 1025 end 1026 assert_raise RangeError do 1027 m.optional_uint64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum 1028 end 1029 assert_raise RangeError do 1030 m.optional_uint64 = 1e50 1031 end 1032 assert_raise RangeError do 1033 m.optional_uint64 = 1.5 1034 end 1035 end 1036 1037 def test_stress_test 1038 m = proto_module::TestMessage.new 1039 m.optional_int32 = 42 1040 m.optional_int64 = 0x100000000 1041 m.optional_string = "hello world" 1042 10.times do m.repeated_msg.push proto_module::TestMessage2.new(:foo => 42) end 1043 10.times do m.repeated_string.push "hello world" end 1044 1045 data = proto_module::TestMessage.encode(m) 1046 1047 10_000.times do 1048 m = proto_module::TestMessage.decode(data) 1049 data_new = proto_module::TestMessage.encode(m) 1050 assert data_new == data 1051 data = data_new 1052 end 1053 end 1054 1055 def test_reflection 1056 m = proto_module::TestMessage.new(:optional_int32 => 1234) 1057 msgdef = m.class.descriptor 1058 assert msgdef.class == Google::Protobuf::Descriptor 1059 assert msgdef.any? {|field| field.name == "optional_int32"} 1060 optional_int32 = msgdef.lookup "optional_int32" 1061 assert optional_int32.class == Google::Protobuf::FieldDescriptor 1062 assert optional_int32 != nil 1063 assert optional_int32.name == "optional_int32" 1064 assert optional_int32.type == :int32 1065 optional_int32.set(m, 5678) 1066 assert m.optional_int32 == 5678 1067 m.optional_int32 = 1000 1068 assert optional_int32.get(m) == 1000 1069 1070 optional_msg = msgdef.lookup "optional_msg" 1071 assert optional_msg.subtype == proto_module::TestMessage2.descriptor 1072 1073 optional_msg.set(m, optional_msg.subtype.msgclass.new) 1074 1075 assert msgdef.msgclass == proto_module::TestMessage 1076 1077 optional_enum = msgdef.lookup "optional_enum" 1078 assert optional_enum.subtype == proto_module::TestEnum.descriptor 1079 assert optional_enum.subtype.class == Google::Protobuf::EnumDescriptor 1080 optional_enum.subtype.each do |k, v| 1081 # set with integer, check resolution to symbolic name 1082 optional_enum.set(m, v) 1083 assert optional_enum.get(m) == k 1084 end 1085 end 1086 1087 def test_json 1088 m = proto_module::TestMessage.new(:optional_int32 => 1234, 1089 :optional_int64 => -0x1_0000_0000, 1090 :optional_uint32 => 0x8000_0000, 1091 :optional_uint64 => 0xffff_ffff_ffff_ffff, 1092 :optional_bool => true, 1093 :optional_float => 1.0, 1094 :optional_double => -1e100, 1095 :optional_string => "Test string", 1096 :optional_bytes => ["FFFFFFFF"].pack('H*'), 1097 :optional_msg => proto_module::TestMessage2.new(:foo => 42), 1098 :repeated_int32 => [1, 2, 3, 4], 1099 :repeated_string => ["a", "b", "c"], 1100 :repeated_bool => [true, false, true, false], 1101 :repeated_msg => [proto_module::TestMessage2.new(:foo => 1), 1102 proto_module::TestMessage2.new(:foo => 2)]) 1103 1104 json_text = proto_module::TestMessage.encode_json(m) 1105 m2 = proto_module::TestMessage.decode_json(json_text) 1106 assert_equal m, m2 1107 1108 # Crash case from GitHub issue 283. 1109 bar = proto_module::Bar.new(msg: "bar") 1110 baz1 = proto_module::Baz.new(msg: "baz") 1111 baz2 = proto_module::Baz.new(msg: "quux") 1112 proto_module::Foo.encode_json(proto_module::Foo.new) 1113 proto_module::Foo.encode_json(proto_module::Foo.new(bar: bar)) 1114 proto_module::Foo.encode_json(proto_module::Foo.new(bar: bar, baz: [baz1, baz2])) 1115 end 1116 1117 def test_json_empty 1118 assert proto_module::TestMessage.encode_json(proto_module::TestMessage.new) == '{}' 1119 end 1120 1121 def test_json_emit_defaults 1122 # TODO: Fix JSON in JRuby version. 1123 return if RUBY_PLATFORM == "java" 1124 m = proto_module::TestMessage.new 1125 1126 expected = { 1127 repeatedInt32: [], 1128 repeatedInt64: [], 1129 repeatedUint32: [], 1130 repeatedUint64: [], 1131 repeatedBool: [], 1132 repeatedFloat: [], 1133 repeatedDouble: [], 1134 repeatedString: [], 1135 repeatedBytes: [], 1136 repeatedMsg: [], 1137 repeatedEnum: [] 1138 } 1139 1140 actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true) 1141 1142 assert_equal expected, JSON.parse(actual, :symbolize_names => true) 1143 end 1144 1145 def test_json_emit_defaults_submsg 1146 # TODO: Fix JSON in JRuby version. 1147 return if RUBY_PLATFORM == "java" 1148 m = proto_module::TestMessage.new(optional_msg: proto_module::TestMessage2.new) 1149 1150 expected = { 1151 optionalMsg: {}, 1152 repeatedInt32: [], 1153 repeatedInt64: [], 1154 repeatedUint32: [], 1155 repeatedUint64: [], 1156 repeatedBool: [], 1157 repeatedFloat: [], 1158 repeatedDouble: [], 1159 repeatedString: [], 1160 repeatedBytes: [], 1161 repeatedMsg: [], 1162 repeatedEnum: [] 1163 } 1164 1165 actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true) 1166 1167 assert_equal expected, JSON.parse(actual, :symbolize_names => true) 1168 end 1169 1170 def test_json_emit_defaults_repeated_submsg 1171 # TODO: Fix JSON in JRuby version. 1172 return if RUBY_PLATFORM == "java" 1173 m = proto_module::TestMessage.new(repeated_msg: [proto_module::TestMessage2.new]) 1174 1175 expected = { 1176 repeatedInt32: [], 1177 repeatedInt64: [], 1178 repeatedUint32: [], 1179 repeatedUint64: [], 1180 repeatedBool: [], 1181 repeatedFloat: [], 1182 repeatedDouble: [], 1183 repeatedString: [], 1184 repeatedBytes: [], 1185 repeatedMsg: [{}], 1186 repeatedEnum: [] 1187 } 1188 1189 actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true) 1190 1191 assert_equal expected, JSON.parse(actual, :symbolize_names => true) 1192 end 1193 1194 def value_from_ruby(value) 1195 ret = Google::Protobuf::Value.new 1196 case value 1197 when String 1198 ret.string_value = value 1199 when Google::Protobuf::Struct 1200 ret.struct_value = value 1201 when Hash 1202 ret.struct_value = struct_from_ruby(value) 1203 when Google::Protobuf::ListValue 1204 ret.list_value = value 1205 when Array 1206 ret.list_value = list_from_ruby(value) 1207 else 1208 @log.error "Unknown type: #{value.class}" 1209 raise Google::Protobuf::Error, "Unknown type: #{value.class}" 1210 end 1211 ret 1212 end 1213 1214 def list_from_ruby(arr) 1215 ret = Google::Protobuf::ListValue.new 1216 arr.each do |v| 1217 ret.values << value_from_ruby(v) 1218 end 1219 ret 1220 end 1221 1222 def struct_from_ruby(hash) 1223 ret = Google::Protobuf::Struct.new 1224 hash.each do |k, v| 1225 ret.fields[k] ||= value_from_ruby(v) 1226 end 1227 ret 1228 end 1229 1230 def test_deep_json 1231 # will not overflow 1232 json = '{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":'\ 1233 '{"a":{"a":{"a":{"a":{}}}}}}}}}}}}}}}}' 1234 1235 struct = struct_from_ruby(JSON.parse(json)) 1236 assert_equal json, struct.to_json 1237 1238 encoded = proto_module::MyRepeatedStruct.encode( 1239 proto_module::MyRepeatedStruct.new(structs: [proto_module::MyStruct.new(struct: struct)])) 1240 assert_equal json, proto_module::MyRepeatedStruct.decode(encoded).structs[0].struct.to_json 1241 1242 # will overflow 1243 json = '{"a":{"a":{"a":[{"a":{"a":[{"a":[{"a":{"a":[{"a":[{"a":'\ 1244 '{"a":[{"a":[{"a":{"a":{"a":[{"a":"a"}]}}}]}]}}]}]}}]}]}}]}}}' 1245 1246 struct = struct_from_ruby(JSON.parse(json)) 1247 assert_equal json, struct.to_json 1248 1249 assert_raise(RuntimeError, "Recursion limit exceeded during encoding") do 1250 struct = Google::Protobuf::Struct.new 1251 struct.fields["foobar"] = Google::Protobuf::Value.new(struct_value: struct) 1252 Google::Protobuf::Struct.encode(struct) 1253 end 1254 end 1255 1256 def test_comparison_with_arbitrary_object 1257 assert proto_module::TestMessage.new != nil 1258 end 1259 1260 def test_wrappers_set_to_default 1261 run_asserts = ->(m) { 1262 assert_equal 0.0, m.double.value 1263 assert_equal 0.0, m.float.value 1264 assert_equal 0, m.int32.value 1265 assert_equal 0, m.int64.value 1266 assert_equal 0, m.uint32.value 1267 assert_equal 0, m.uint64.value 1268 assert_equal false, m.bool.value 1269 assert_equal '', m.string.value 1270 assert_equal '', m.bytes.value 1271 } 1272 1273 m = proto_module::Wrapper.new( 1274 double: Google::Protobuf::DoubleValue.new(value: 0.0), 1275 float: Google::Protobuf::FloatValue.new(value: 0.0), 1276 int32: Google::Protobuf::Int32Value.new(value: 0), 1277 int64: Google::Protobuf::Int64Value.new(value: 0), 1278 uint32: Google::Protobuf::UInt32Value.new(value: 0), 1279 uint64: Google::Protobuf::UInt64Value.new(value: 0), 1280 bool: Google::Protobuf::BoolValue.new(value: false), 1281 string: Google::Protobuf::StringValue.new(value: ""), 1282 bytes: Google::Protobuf::BytesValue.new(value: ''), 1283 ) 1284 1285 run_asserts.call(m) 1286 m2 = proto_module::Wrapper.decode(m.to_proto) 1287 run_asserts.call(m2) 1288 m3 = proto_module::Wrapper.decode_json(m.to_json) 1289 run_asserts.call(m3) 1290 end 1291 1292 def test_wrapper_getters 1293 run_asserts = ->(m) { 1294 assert_equal 2.0, m.double_as_value 1295 assert_equal 2.0, m.double.value 1296 assert_equal 2.0, m.double_as_value 1297 1298 assert_equal 4.0, m.float_as_value 1299 assert_equal 4.0, m.float.value 1300 assert_equal 4.0, m.float_as_value 1301 1302 assert_equal 3, m.int32_as_value 1303 assert_equal 3, m.int32.value 1304 assert_equal 3, m.int32_as_value 1305 1306 assert_equal 4, m.int64_as_value 1307 assert_equal 4, m.int64.value 1308 assert_equal 4, m.int64_as_value 1309 1310 assert_equal 5, m.uint32_as_value 1311 assert_equal 5, m.uint32.value 1312 assert_equal 5, m.uint32_as_value 1313 1314 assert_equal 6, m.uint64_as_value 1315 assert_equal 6, m.uint64.value 1316 assert_equal 6, m.uint64_as_value 1317 1318 assert_equal true, m.bool_as_value 1319 assert_equal true, m.bool.value 1320 assert_equal true, m.bool_as_value 1321 1322 assert_equal "st\nr", m.string_as_value 1323 assert_equal "st\nr", m.string.value 1324 assert_equal "st\nr", m.string_as_value 1325 1326 assert_equal 'fun', m.bytes_as_value 1327 assert_equal 'fun', m.bytes.value 1328 assert_equal 'fun', m.bytes_as_value 1329 } 1330 1331 m = proto_module::Wrapper.new( 1332 double: Google::Protobuf::DoubleValue.new(value: 2.0), 1333 float: Google::Protobuf::FloatValue.new(value: 4.0), 1334 int32: Google::Protobuf::Int32Value.new(value: 3), 1335 int64: Google::Protobuf::Int64Value.new(value: 4), 1336 uint32: Google::Protobuf::UInt32Value.new(value: 5), 1337 uint64: Google::Protobuf::UInt64Value.new(value: 6), 1338 bool: Google::Protobuf::BoolValue.new(value: true), 1339 string: Google::Protobuf::StringValue.new(value: "st\nr"), 1340 bytes: Google::Protobuf::BytesValue.new(value: 'fun'), 1341 real_string: '100' 1342 ) 1343 1344 run_asserts.call(m) 1345 serialized = proto_module::Wrapper::encode(m) 1346 m2 = proto_module::Wrapper::decode(serialized) 1347 run_asserts.call(m2) 1348 1349 # Test the case where we are serializing directly from the parsed form 1350 # (before anything lazy is materialized). 1351 m3 = proto_module::Wrapper::decode(serialized) 1352 serialized2 = proto_module::Wrapper::encode(m3) 1353 m4 = proto_module::Wrapper::decode(serialized2) 1354 run_asserts.call(m4) 1355 1356 # Test that the lazy form compares equal to the expanded form. 1357 m5 = proto_module::Wrapper::decode(serialized2) 1358 assert_equal m5, m 1359 1360 serialized_json = proto_module::Wrapper::encode_json(m) 1361 m6 = proto_module::Wrapper::decode_json(serialized_json) 1362 assert_equal m6, m 1363 end 1364 1365 def test_repeated_wrappers 1366 run_asserts = ->(m) { 1367 assert_equal 2.0, m.repeated_double[0].value 1368 assert_equal 4.0, m.repeated_float[0].value 1369 assert_equal 3, m.repeated_int32[0].value 1370 assert_equal 4, m.repeated_int64[0].value 1371 assert_equal 5, m.repeated_uint32[0].value 1372 assert_equal 6, m.repeated_uint64[0].value 1373 assert_equal true, m.repeated_bool[0].value 1374 assert_equal 'str', m.repeated_string[0].value 1375 assert_equal 'fun', m.repeated_bytes[0].value 1376 } 1377 1378 m = proto_module::Wrapper.new( 1379 repeated_double: [Google::Protobuf::DoubleValue.new(value: 2.0)], 1380 repeated_float: [Google::Protobuf::FloatValue.new(value: 4.0)], 1381 repeated_int32: [Google::Protobuf::Int32Value.new(value: 3)], 1382 repeated_int64: [Google::Protobuf::Int64Value.new(value: 4)], 1383 repeated_uint32: [Google::Protobuf::UInt32Value.new(value: 5)], 1384 repeated_uint64: [Google::Protobuf::UInt64Value.new(value: 6)], 1385 repeated_bool: [Google::Protobuf::BoolValue.new(value: true)], 1386 repeated_string: [Google::Protobuf::StringValue.new(value: 'str')], 1387 repeated_bytes: [Google::Protobuf::BytesValue.new(value: 'fun')], 1388 ) 1389 1390 run_asserts.call(m) 1391 serialized = proto_module::Wrapper::encode(m) 1392 m2 = proto_module::Wrapper::decode(serialized) 1393 run_asserts.call(m2) 1394 1395 # Test the case where we are serializing directly from the parsed form 1396 # (before anything lazy is materialized). 1397 m3 = proto_module::Wrapper::decode(serialized) 1398 serialized2 = proto_module::Wrapper::encode(m3) 1399 m4 = proto_module::Wrapper::decode(serialized2) 1400 run_asserts.call(m4) 1401 1402 # Test that the lazy form compares equal to the expanded form. 1403 m5 = proto_module::Wrapper::decode(serialized2) 1404 assert_equal m5, m 1405 1406 # Test JSON. 1407 serialized_json = proto_module::Wrapper::encode_json(m5) 1408 m6 = proto_module::Wrapper::decode_json(serialized_json) 1409 run_asserts.call(m6) 1410 assert_equal m6, m 1411 end 1412 1413 def test_oneof_wrappers 1414 run_test = ->(m) { 1415 serialized = proto_module::Wrapper::encode(m) 1416 m2 = proto_module::Wrapper::decode(serialized) 1417 1418 # Encode directly from lazy form. 1419 serialized2 = proto_module::Wrapper::encode(m2) 1420 1421 assert_equal m, m2 1422 assert_equal serialized, serialized2 1423 1424 serialized_json = proto_module::Wrapper::encode_json(m) 1425 m3 = proto_module::Wrapper::decode_json(serialized_json) 1426 assert_equal m, m3 1427 } 1428 1429 m = proto_module::Wrapper.new() 1430 1431 run_test.call(m) 1432 m.oneof_double_as_value = 2.0 1433 run_test.call(m) 1434 m.oneof_float_as_value = 4.0 1435 run_test.call(m) 1436 m.oneof_int32_as_value = 3 1437 run_test.call(m) 1438 m.oneof_int64_as_value = 5 1439 run_test.call(m) 1440 m.oneof_uint32_as_value = 6 1441 run_test.call(m) 1442 m.oneof_uint64_as_value = 7 1443 run_test.call(m) 1444 m.oneof_string_as_value = 'str' 1445 run_test.call(m) 1446 m.oneof_bytes_as_value = 'fun' 1447 run_test.call(m) 1448 end 1449 1450 def test_top_level_wrappers 1451 # We don't expect anyone to do this, but we should also make sure it does 1452 # the right thing. 1453 run_test = ->(klass, val) { 1454 m = klass.new(value: val) 1455 serialized = klass::encode(m) 1456 m2 = klass::decode(serialized) 1457 1458 # Encode directly from lazy form. 1459 serialized2 = klass::encode(m2) 1460 1461 assert_equal m, m2 1462 assert_equal serialized, serialized2 1463 1464 serialized_json = klass::encode_json(m) 1465 1466 # This is nonsensical to do and does not work. There is no good reason 1467 # to parse a wrapper type directly. 1468 assert_raise(RuntimeError) { klass::decode_json(serialized_json) } 1469 } 1470 1471 run_test.call(Google::Protobuf::DoubleValue, 2.0) 1472 run_test.call(Google::Protobuf::FloatValue, 4.0) 1473 run_test.call(Google::Protobuf::Int32Value, 3) 1474 run_test.call(Google::Protobuf::Int64Value, 4) 1475 run_test.call(Google::Protobuf::UInt32Value, 5) 1476 run_test.call(Google::Protobuf::UInt64Value, 6) 1477 run_test.call(Google::Protobuf::BoolValue, true) 1478 run_test.call(Google::Protobuf::StringValue, 'str') 1479 run_test.call(Google::Protobuf::BytesValue, 'fun') 1480 end 1481 1482 def test_wrapper_setters_as_value 1483 run_asserts = ->(m) { 1484 m.double_as_value = 4.8 1485 assert_equal 4.8, m.double_as_value 1486 assert_equal Google::Protobuf::DoubleValue.new(value: 4.8), m.double 1487 m.float_as_value = 2.4 1488 assert_in_delta 2.4, m.float_as_value 1489 assert_in_delta Google::Protobuf::FloatValue.new(value: 2.4).value, m.float.value 1490 m.int32_as_value = 5 1491 assert_equal 5, m.int32_as_value 1492 assert_equal Google::Protobuf::Int32Value.new(value: 5), m.int32 1493 m.int64_as_value = 15 1494 assert_equal 15, m.int64_as_value 1495 assert_equal Google::Protobuf::Int64Value.new(value: 15), m.int64 1496 m.uint32_as_value = 50 1497 assert_equal 50, m.uint32_as_value 1498 assert_equal Google::Protobuf::UInt32Value.new(value: 50), m.uint32 1499 m.uint64_as_value = 500 1500 assert_equal 500, m.uint64_as_value 1501 assert_equal Google::Protobuf::UInt64Value.new(value: 500), m.uint64 1502 m.bool_as_value = false 1503 assert_equal false, m.bool_as_value 1504 assert_equal Google::Protobuf::BoolValue.new(value: false), m.bool 1505 m.string_as_value = 'xy' 1506 assert_equal 'xy', m.string_as_value 1507 assert_equal Google::Protobuf::StringValue.new(value: 'xy'), m.string 1508 m.bytes_as_value = '123' 1509 assert_equal '123', m.bytes_as_value 1510 assert_equal Google::Protobuf::BytesValue.new(value: '123'), m.bytes 1511 1512 m.double_as_value = nil 1513 assert_nil m.double 1514 assert_nil m.double_as_value 1515 m.float_as_value = nil 1516 assert_nil m.float 1517 assert_nil m.float_as_value 1518 m.int32_as_value = nil 1519 assert_nil m.int32 1520 assert_nil m.int32_as_value 1521 m.int64_as_value = nil 1522 assert_nil m.int64 1523 assert_nil m.int64_as_value 1524 m.uint32_as_value = nil 1525 assert_nil m.uint32 1526 assert_nil m.uint32_as_value 1527 m.uint64_as_value = nil 1528 assert_nil m.uint64 1529 assert_nil m.uint64_as_value 1530 m.bool_as_value = nil 1531 assert_nil m.bool 1532 assert_nil m.bool_as_value 1533 m.string_as_value = nil 1534 assert_nil m.string 1535 assert_nil m.string_as_value 1536 m.bytes_as_value = nil 1537 assert_nil m.bytes 1538 assert_nil m.bytes_as_value 1539 } 1540 1541 m2 = proto_module::Wrapper.new( 1542 double: Google::Protobuf::DoubleValue.new(value: 2.0), 1543 float: Google::Protobuf::FloatValue.new(value: 4.0), 1544 int32: Google::Protobuf::Int32Value.new(value: 3), 1545 int64: Google::Protobuf::Int64Value.new(value: 4), 1546 uint32: Google::Protobuf::UInt32Value.new(value: 5), 1547 uint64: Google::Protobuf::UInt64Value.new(value: 6), 1548 bool: Google::Protobuf::BoolValue.new(value: true), 1549 string: Google::Protobuf::StringValue.new(value: 'str'), 1550 bytes: Google::Protobuf::BytesValue.new(value: 'fun'), 1551 real_string: '100' 1552 ) 1553 1554 run_asserts.call(m2) 1555 1556 serialized = proto_module::Wrapper::encode(m2) 1557 m3 = proto_module::Wrapper::decode(serialized) 1558 run_asserts.call(m3) 1559 end 1560 1561 def test_wrapper_setters 1562 run_asserts = ->(m) { 1563 m.double = Google::Protobuf::DoubleValue.new(value: 4.8) 1564 assert_equal 4.8, m.double_as_value 1565 assert_equal Google::Protobuf::DoubleValue.new(value: 4.8), m.double 1566 m.float = Google::Protobuf::FloatValue.new(value: 2.4) 1567 assert_in_delta 2.4, m.float_as_value 1568 assert_in_delta Google::Protobuf::FloatValue.new(value: 2.4).value, m.float.value 1569 m.int32 = Google::Protobuf::Int32Value.new(value: 5) 1570 assert_equal 5, m.int32_as_value 1571 assert_equal Google::Protobuf::Int32Value.new(value: 5), m.int32 1572 m.int64 = Google::Protobuf::Int64Value.new(value: 15) 1573 assert_equal 15, m.int64_as_value 1574 assert_equal Google::Protobuf::Int64Value.new(value: 15), m.int64 1575 m.uint32 = Google::Protobuf::UInt32Value.new(value: 50) 1576 assert_equal 50, m.uint32_as_value 1577 assert_equal Google::Protobuf::UInt32Value.new(value: 50), m.uint32 1578 m.uint64 = Google::Protobuf::UInt64Value.new(value: 500) 1579 assert_equal 500, m.uint64_as_value 1580 assert_equal Google::Protobuf::UInt64Value.new(value: 500), m.uint64 1581 m.bool = Google::Protobuf::BoolValue.new(value: false) 1582 assert_equal false, m.bool_as_value 1583 assert_equal Google::Protobuf::BoolValue.new(value: false), m.bool 1584 m.string = Google::Protobuf::StringValue.new(value: 'xy') 1585 assert_equal 'xy', m.string_as_value 1586 assert_equal Google::Protobuf::StringValue.new(value: 'xy'), m.string 1587 m.bytes = Google::Protobuf::BytesValue.new(value: '123') 1588 assert_equal '123', m.bytes_as_value 1589 assert_equal Google::Protobuf::BytesValue.new(value: '123'), m.bytes 1590 1591 m.double = nil 1592 assert_nil m.double 1593 assert_nil m.double_as_value 1594 m.float = nil 1595 assert_nil m.float 1596 assert_nil m.float_as_value 1597 m.int32 = nil 1598 assert_nil m.int32 1599 assert_nil m.int32_as_value 1600 m.int64 = nil 1601 assert_nil m.int64 1602 assert_nil m.int64_as_value 1603 m.uint32 = nil 1604 assert_nil m.uint32 1605 assert_nil m.uint32_as_value 1606 m.uint64 = nil 1607 assert_nil m.uint64 1608 assert_nil m.uint64_as_value 1609 m.bool = nil 1610 assert_nil m.bool 1611 assert_nil m.bool_as_value 1612 m.string = nil 1613 assert_nil m.string 1614 assert_nil m.string_as_value 1615 m.bytes = nil 1616 assert_nil m.bytes 1617 assert_nil m.bytes_as_value 1618 } 1619 1620 m = proto_module::Wrapper.new 1621 run_asserts.call(m) 1622 1623 m2 = proto_module::Wrapper.new( 1624 double: Google::Protobuf::DoubleValue.new(value: 2.0), 1625 float: Google::Protobuf::FloatValue.new(value: 4.0), 1626 int32: Google::Protobuf::Int32Value.new(value: 3), 1627 int64: Google::Protobuf::Int64Value.new(value: 4), 1628 uint32: Google::Protobuf::UInt32Value.new(value: 5), 1629 uint64: Google::Protobuf::UInt64Value.new(value: 6), 1630 bool: Google::Protobuf::BoolValue.new(value: true), 1631 string: Google::Protobuf::StringValue.new(value: 'str'), 1632 bytes: Google::Protobuf::BytesValue.new(value: 'fun'), 1633 real_string: '100' 1634 ) 1635 1636 run_asserts.call(m2) 1637 1638 serialized = proto_module::Wrapper::encode(m2) 1639 m3 = proto_module::Wrapper::decode(serialized) 1640 run_asserts.call(m3) 1641 end 1642 1643 def test_wrappers_only 1644 m = proto_module::Wrapper.new(real_string: 'hi', string_in_oneof: 'there') 1645 1646 assert_raise(NoMethodError) { m.real_string_as_value } 1647 assert_raise(NoMethodError) { m.as_value } 1648 assert_raise(NoMethodError) { m._as_value } 1649 assert_raise(NoMethodError) { m.string_in_oneof_as_value } 1650 1651 m = proto_module::Wrapper.new 1652 m.string_as_value = 'you' 1653 assert_equal 'you', m.string.value 1654 assert_equal 'you', m.string_as_value 1655 assert_raise(NoMethodError) { m.string_ } 1656 assert_raise(NoMethodError) { m.string_X } 1657 assert_raise(NoMethodError) { m.string_XX } 1658 assert_raise(NoMethodError) { m.string_XXX } 1659 assert_raise(NoMethodError) { m.string_XXXX } 1660 assert_raise(NoMethodError) { m.string_XXXXX } 1661 assert_raise(NoMethodError) { m.string_XXXXXX } 1662 assert_raise(NoMethodError) { m.string_XXXXXXX } 1663 assert_raise(NoMethodError) { m.string_XXXXXXXX } 1664 assert_raise(NoMethodError) { m.string_XXXXXXXXX } 1665 assert_raise(NoMethodError) { m.string_XXXXXXXXXX } 1666 end 1667 1668 def test_converts_time 1669 m = proto_module::TimeMessage.new 1670 1671 m.timestamp = Google::Protobuf::Timestamp.new(seconds: 5, nanos: 6) 1672 assert_kind_of Google::Protobuf::Timestamp, m.timestamp 1673 assert_equal 5, m.timestamp.seconds 1674 assert_equal 6, m.timestamp.nanos 1675 1676 m.timestamp = Time.at(9466, 123456.789) 1677 assert_equal Google::Protobuf::Timestamp.new(seconds: 9466, nanos: 123456789), m.timestamp 1678 1679 m = proto_module::TimeMessage.new(timestamp: Time.at(1)) 1680 assert_equal Google::Protobuf::Timestamp.new(seconds: 1, nanos: 0), m.timestamp 1681 1682 assert_raise(Google::Protobuf::TypeError) { m.timestamp = 2 } 1683 assert_raise(Google::Protobuf::TypeError) { m.timestamp = 2.4 } 1684 assert_raise(Google::Protobuf::TypeError) { m.timestamp = '4' } 1685 assert_raise(Google::Protobuf::TypeError) { m.timestamp = proto_module::TimeMessage.new } 1686 1687 def test_time(year, month, day) 1688 str = ("\"%04d-%02d-%02dT00:00:00.000+00:00\"" % [year, month, day]) 1689 t = Google::Protobuf::Timestamp.decode_json(str) 1690 time = Time.new(year, month, day, 0, 0, 0, "+00:00") 1691 assert_equal t.seconds, time.to_i 1692 end 1693 1694 (1970..2010).each do |year| 1695 test_time(year, 2, 28) 1696 test_time(year, 3, 01) 1697 end 1698 end 1699 1700 def test_converts_duration 1701 m = proto_module::TimeMessage.new 1702 1703 m.duration = Google::Protobuf::Duration.new(seconds: 2, nanos: 22) 1704 assert_kind_of Google::Protobuf::Duration, m.duration 1705 assert_equal 2, m.duration.seconds 1706 assert_equal 22, m.duration.nanos 1707 1708 m.duration = 10.5 1709 assert_equal Google::Protobuf::Duration.new(seconds: 10, nanos: 500_000_000), m.duration 1710 1711 m.duration = 200 1712 assert_equal Google::Protobuf::Duration.new(seconds: 200, nanos: 0), m.duration 1713 1714 m.duration = Rational(3, 2) 1715 assert_equal Google::Protobuf::Duration.new(seconds: 1, nanos: 500_000_000), m.duration 1716 1717 m.duration = BigDecimal("5") 1718 assert_equal Google::Protobuf::Duration.new(seconds: 5, nanos: 0), m.duration 1719 1720 m = proto_module::TimeMessage.new(duration: 1.1) 1721 assert_equal Google::Protobuf::Duration.new(seconds: 1, nanos: 100_000_000), m.duration 1722 1723 m = proto_module::TimeMessage.new(duration: 123.321) 1724 assert_equal Google::Protobuf::Duration.new(seconds: 123, nanos: 321_000_000), m.duration 1725 1726 m = proto_module::TimeMessage.new(duration: -123.321) 1727 assert_equal Google::Protobuf::Duration.new(seconds: -123, nanos: -321_000_000), m.duration 1728 1729 assert_raise(Google::Protobuf::TypeError) { m.duration = '2' } 1730 assert_raise(Google::Protobuf::TypeError) { m.duration = proto_module::TimeMessage.new } 1731 end 1732 1733 def test_freeze 1734 m = proto_module::TestMessage.new 1735 m.optional_int32 = 10 1736 m.freeze 1737 1738 frozen_error = assert_raise(FrozenErrorType) { m.optional_int32 = 20 } 1739 assert_match "can't modify frozen #{proto_module}::TestMessage", frozen_error.message 1740 assert_equal 10, m.optional_int32 1741 assert_equal true, m.frozen? 1742 1743 assert_raise(FrozenErrorType) { m.optional_int64 = 2 } 1744 assert_raise(FrozenErrorType) { m.optional_uint32 = 3 } 1745 assert_raise(FrozenErrorType) { m.optional_uint64 = 4 } 1746 assert_raise(FrozenErrorType) { m.optional_bool = true } 1747 assert_raise(FrozenErrorType) { m.optional_float = 6.0 } 1748 assert_raise(FrozenErrorType) { m.optional_double = 7.0 } 1749 assert_raise(FrozenErrorType) { m.optional_string = '8' } 1750 assert_raise(FrozenErrorType) { m.optional_bytes = nil } 1751 assert_raise(FrozenErrorType) { m.optional_msg = proto_module::TestMessage2.new } 1752 assert_raise(FrozenErrorType) { m.optional_enum = :A } 1753 assert_raise(FrozenErrorType) { m.repeated_int32 = 1 } 1754 assert_raise(FrozenErrorType) { m.repeated_int64 = 2 } 1755 assert_raise(FrozenErrorType) { m.repeated_uint32 = 3 } 1756 assert_raise(FrozenErrorType) { m.repeated_uint64 = 4 } 1757 assert_raise(FrozenErrorType) { m.repeated_bool = true } 1758 assert_raise(FrozenErrorType) { m.repeated_float = 6.0 } 1759 assert_raise(FrozenErrorType) { m.repeated_double = 7.0 } 1760 assert_raise(FrozenErrorType) { m.repeated_string = '8' } 1761 assert_raise(FrozenErrorType) { m.repeated_bytes = nil } 1762 assert_raise(FrozenErrorType) { m.repeated_msg = proto_module::TestMessage2.new } 1763 assert_raise(FrozenErrorType) { m.repeated_enum = :A } 1764 end 1765 1766 def test_eq 1767 m1 = proto_module::TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2']) 1768 m2 = proto_module::TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2']) 1769 1770 h = {} 1771 h[m1] = :yes 1772 1773 assert m1 == m2 1774 assert m1.eql?(m2) 1775 assert m1.hash == m2.hash 1776 assert h[m1] == :yes 1777 assert h[m2] == :yes 1778 1779 m1.optional_int32 = 2 1780 1781 assert m1 != m2 1782 assert !m1.eql?(m2) 1783 assert m1.hash != m2.hash 1784 assert_nil h[m2] 1785 end 1786 1787 def cruby_or_jruby_9_3_or_higher? 1788 # https://github.com/jruby/jruby/issues/6818 was fixed in JRuby 9.3.0.0 1789 match = RUBY_PLATFORM == "java" && 1790 JRUBY_VERSION.match(/^(\d+)\.(\d+)\.\d+\.\d+$/) 1791 match && (match[1].to_i > 9 || (match[1].to_i == 9 && match[2].to_i >= 3)) 1792 end 1793 1794 def test_object_gc 1795 m = proto_module::TestMessage.new(optional_msg: proto_module::TestMessage2.new) 1796 m.optional_msg 1797 # https://github.com/jruby/jruby/issues/6818 was fixed in JRuby 9.3.0.0 1798 GC.start(full_mark: true, immediate_sweep: true) if cruby_or_jruby_9_3_or_higher? 1799 m.optional_msg.inspect 1800 end 1801 1802 def test_object_gc_freeze 1803 m = proto_module::TestMessage.new 1804 m.repeated_float.freeze 1805 # https://github.com/jruby/jruby/issues/6818 was fixed in JRuby 9.3.0.0 1806 GC.start(full_mark: true) if cruby_or_jruby_9_3_or_higher? 1807 1808 # Make sure we remember that the object is frozen. 1809 # The wrapper object contains this information, so we need to ensure that 1810 # the previous GC did not collect it. 1811 assert m.repeated_float.frozen? 1812 1813 # https://github.com/jruby/jruby/issues/6818 was fixed in JRuby 9.3.0.0 1814 GC.start(full_mark: true, immediate_sweep: true) if cruby_or_jruby_9_3_or_higher? 1815 assert m.repeated_float.frozen? 1816 end 1817 1818 def test_optional_fields_respond_to? # regression test for issue 9202 1819 msg = proto_module::TestMessage.new 1820 assert msg.respond_to? :optional_int32= 1821 msg.optional_int32 = 42 1822 1823 assert msg.respond_to? :optional_int32 1824 assert_equal 42, msg.optional_int32 1825 1826 assert msg.respond_to? :clear_optional_int32 1827 msg.clear_optional_int32 1828 assert_equal 0, msg.optional_int32 1829 1830 assert msg.respond_to? :has_optional_int32? 1831 assert !msg.has_optional_int32? 1832 1833 assert !msg.respond_to?( :optional_int32_as_value= ) 1834 assert_raise NoMethodError do 1835 msg.optional_int32_as_value = 42 1836 end 1837 1838 assert !msg.respond_to?( :optional_int32_as_value ) 1839 assert_raise NoMethodError do 1840 msg.optional_int32_as_value 1841 end 1842 1843 assert msg.respond_to? :optional_enum_const 1844 assert_equal 0, msg.optional_enum_const 1845 1846 assert !msg.respond_to?( :foo ) 1847 assert_raise NoMethodError do 1848 msg.foo 1849 end 1850 1851 assert !msg.respond_to?( :foo_const ) 1852 assert_raise NoMethodError do 1853 msg.foo_const 1854 end 1855 1856 assert !msg.respond_to?( :optional_int32_const ) 1857 assert_raise NoMethodError do 1858 msg.optional_int32_const 1859 end 1860 end 1861 1862 def test_oneof_fields_respond_to? # regression test for issue 9202 1863 msg = proto_module::OneofMessage.new 1864 1865 # names of the elements of a oneof and the oneof itself are valid actions. 1866 assert msg.respond_to? :my_oneof 1867 assert_nil msg.my_oneof 1868 assert msg.respond_to? :a 1869 assert_equal "", msg.a 1870 assert msg.respond_to? :b 1871 assert_equal 0, msg.b 1872 assert msg.respond_to? :c 1873 assert_nil msg.c 1874 assert msg.respond_to? :d 1875 assert_equal :Default, msg.d 1876 1877 # `clear` prefix actions work on elements of a oneof and the oneof itself. 1878 assert msg.respond_to? :clear_my_oneof 1879 msg.clear_my_oneof 1880 # Repeatedly clearing a oneof used to cause a NoMethodError under JRuby 1881 msg.clear_my_oneof 1882 assert msg.respond_to? :clear_a 1883 msg.clear_a 1884 assert msg.respond_to? :clear_b 1885 msg.clear_b 1886 assert msg.respond_to? :clear_c 1887 msg.clear_c 1888 assert msg.respond_to? :clear_d 1889 msg.clear_d 1890 1891 # `=` suffix actions should work on elements of a oneof but not the oneof itself. 1892 assert !msg.respond_to?( :my_oneof= ) 1893 error = assert_raise RuntimeError do 1894 msg.my_oneof = nil 1895 end 1896 assert_equal "Oneof accessors are read-only.", error.message 1897 assert msg.respond_to? :a= 1898 msg.a = "foo" 1899 assert msg.respond_to? :b= 1900 msg.b = 42 1901 assert msg.respond_to? :c= 1902 msg.c = proto_module::TestMessage2.new 1903 assert msg.respond_to? :d= 1904 msg.d = :Default 1905 1906 # `has_` prefix + "?" suffix actions work for oneofs fields. 1907 assert msg.respond_to? :has_my_oneof? 1908 assert msg.has_my_oneof? 1909 1910 # `_as_value` suffix actions should only work for wrapped fields. 1911 assert !msg.respond_to?( :my_oneof_as_value ) 1912 assert_raise NoMethodError do 1913 msg.my_oneof_as_value 1914 end 1915 assert !msg.respond_to?( :a_as_value ) 1916 assert_raise NoMethodError do 1917 msg.a_as_value 1918 end 1919 assert !msg.respond_to?( :b_as_value ) 1920 assert_raise NoMethodError do 1921 msg.b_as_value 1922 end 1923 assert !msg.respond_to?( :c_as_value ) 1924 assert_raise NoMethodError do 1925 msg.c_as_value 1926 end 1927 assert !msg.respond_to?( :d_as_value ) 1928 assert_raise NoMethodError do 1929 msg.d_as_value 1930 end 1931 1932 # `_as_value=` suffix actions should only work for wrapped fields. 1933 assert !msg.respond_to?( :my_oneof_as_value= ) 1934 assert_raise NoMethodError do 1935 msg.my_oneof_as_value = :boom 1936 end 1937 assert !msg.respond_to?( :a_as_value= ) 1938 assert_raise NoMethodError do 1939 msg.a_as_value = "" 1940 end 1941 assert !msg.respond_to?( :b_as_value= ) 1942 assert_raise NoMethodError do 1943 msg.b_as_value = 42 1944 end 1945 assert !msg.respond_to?( :c_as_value= ) 1946 assert_raise NoMethodError do 1947 msg.c_as_value = proto_module::TestMessage2.new 1948 end 1949 assert !msg.respond_to?( :d_as_value= ) 1950 assert_raise NoMethodError do 1951 msg.d_as_value = :Default 1952 end 1953 1954 # `_const` suffix actions should only work for enum fields. 1955 assert !msg.respond_to?( :my_oneof_const ) 1956 assert_raise NoMethodError do 1957 msg.my_oneof_const 1958 end 1959 assert !msg.respond_to?( :a_const ) 1960 assert_raise NoMethodError do 1961 msg.a_const 1962 end 1963 assert !msg.respond_to?( :b_const ) 1964 assert_raise NoMethodError do 1965 msg.b_const 1966 end 1967 assert !msg.respond_to?( :c_const ) 1968 assert_raise NoMethodError do 1969 msg.c_const 1970 end 1971 assert msg.respond_to? :d_const 1972 assert_equal 0, msg.d_const 1973 end 1974 1975 def test_wrapped_fields_respond_to? # regression test for issue 9202 1976 msg = proto_module::Wrapper.new 1977 assert msg.respond_to?( :double_as_value= ) 1978 msg.double_as_value = 42 1979 assert msg.respond_to?( :double_as_value ) 1980 assert_equal 42, msg.double_as_value 1981 assert_equal Google::Protobuf::DoubleValue.new(value: 42), msg.double 1982 end 1983end 1984