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