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