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, 119 :repeated_string => ["hello", "there", "world"]) 120 expected = "<#{proto_module}::TestMessage: optional_int32: -42, optional_int64: 0, optional_uint32: 0, optional_uint64: 0, optional_bool: false, optional_float: 0.0, optional_double: 0.0, optional_string: \"\", optional_bytes: \"\", optional_msg: <#{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: a: \"\", b: -42, c: nil, d: :Default>" 126 assert_equal expected, m.inspect 127 assert_equal expected, m.to_s 128 end 129 130 def test_hash 131 m1 = proto_module::TestMessage.new(:optional_int32 => 42) 132 m2 = proto_module::TestMessage.new(:optional_int32 => 102, repeated_string: ['please', 'work', 'ok?']) 133 m3 = proto_module::TestMessage.new(:optional_int32 => 102, repeated_string: ['please', 'work', 'ok?']) 134 assert m1.hash != 0 135 assert m2.hash != 0 136 assert m3.hash != 0 137 # relying on the randomness here -- if hash function changes and we are 138 # unlucky enough to get a collision, then change the values above. 139 assert m1.hash != m2.hash 140 assert_equal m2.hash, m3.hash 141 end 142 143 def test_unknown_field_errors 144 e = assert_raise NoMethodError do 145 proto_module::TestMessage.new.hello 146 end 147 assert_match(/hello/, e.message) 148 149 e = assert_raise NoMethodError do 150 proto_module::TestMessage.new.hello = "world" 151 end 152 assert_match(/hello/, e.message) 153 end 154 155 def test_type_errors 156 m = proto_module::TestMessage.new 157 e = assert_raise Google::Protobuf::TypeError do 158 m.optional_int32 = "hello" 159 end 160 161 # Google::Protobuf::TypeError should inherit from TypeError for backwards compatibility 162 # TODO: This can be removed when we can safely migrate to Google::Protobuf::TypeError 163 assert e.is_a?(::TypeError) 164 165 assert_raise Google::Protobuf::TypeError do 166 m.optional_string = 42 167 end 168 assert_raise Google::Protobuf::TypeError do 169 m.optional_string = nil 170 end 171 assert_raise Google::Protobuf::TypeError do 172 m.optional_bool = 42 173 end 174 assert_raise Google::Protobuf::TypeError do 175 m.optional_msg = proto_module::TestMessage.new # expects TestMessage2 176 end 177 178 assert_raise Google::Protobuf::TypeError do 179 m.repeated_int32 = [] # needs RepeatedField 180 end 181 182 assert_raise Google::Protobuf::TypeError do 183 m.repeated_int32.push "hello" 184 end 185 186 assert_raise Google::Protobuf::TypeError do 187 m.repeated_msg.push proto_module::TestMessage.new 188 end 189 end 190 191 def test_string_encoding 192 m = proto_module::TestMessage.new 193 194 # Assigning a normal (ASCII or UTF8) string to a bytes field, or 195 # ASCII-8BIT to a string field will convert to the proper encoding. 196 m.optional_bytes = "Test string ASCII".encode!('ASCII') 197 assert m.optional_bytes.frozen? 198 assert_equal Encoding::ASCII_8BIT, m.optional_bytes.encoding 199 assert_equal "Test string ASCII", m.optional_bytes 200 201 assert_raise Encoding::UndefinedConversionError do 202 m.optional_bytes = "Test string UTF-8 \u0100".encode!('UTF-8') 203 end 204 205 assert_raise Encoding::UndefinedConversionError do 206 m.optional_string = ["FFFF"].pack('H*') 207 end 208 209 # "Ordinary" use case. 210 m.optional_bytes = ["FFFF"].pack('H*') 211 m.optional_string = "\u0100" 212 213 # strings are immutable so we can't do this, but serialize should catch it. 214 m.optional_string = "asdf".encode!('UTF-8') 215 assert_raise(FrozenErrorType) { m.optional_string.encode!('ASCII-8BIT') } 216 end 217 218 def test_rptfield_int32 219 l = Google::Protobuf::RepeatedField.new(:int32) 220 assert l.count == 0 221 l = Google::Protobuf::RepeatedField.new(:int32, [1, 2, 3]) 222 assert l.count == 3 223 assert_equal [1, 2, 3], l 224 assert_equal l, [1, 2, 3] 225 l.push 4 226 assert l == [1, 2, 3, 4] 227 dst_list = [] 228 l.each { |val| dst_list.push val } 229 assert dst_list == [1, 2, 3, 4] 230 assert l.to_a == [1, 2, 3, 4] 231 assert l[0] == 1 232 assert l[3] == 4 233 l[0] = 5 234 assert l == [5, 2, 3, 4] 235 236 l2 = l.dup 237 assert l == l2 238 assert l.object_id != l2.object_id 239 l2.push 6 240 assert l.count == 4 241 assert l2.count == 5 242 243 assert l.inspect == '[5, 2, 3, 4]' 244 245 l.concat([7, 8, 9]) 246 assert l == [5, 2, 3, 4, 7, 8, 9] 247 assert l.pop == 9 248 assert l == [5, 2, 3, 4, 7, 8] 249 250 assert_raise Google::Protobuf::TypeError do 251 m = proto_module::TestMessage.new 252 l.push m 253 end 254 255 m = proto_module::TestMessage.new 256 m.repeated_int32 = l 257 assert m.repeated_int32 == [5, 2, 3, 4, 7, 8] 258 assert m.repeated_int32.object_id == l.object_id 259 l.push 42 260 assert m.repeated_int32.pop == 42 261 262 l3 = l + l.dup 263 assert l3.count == l.count * 2 264 l.count.times do |i| 265 assert l3[i] == l[i] 266 assert l3[l.count + i] == l[i] 267 end 268 269 l.clear 270 assert l.count == 0 271 l += [1, 2, 3, 4] 272 l.replace([5, 6, 7, 8]) 273 assert l == [5, 6, 7, 8] 274 275 l4 = Google::Protobuf::RepeatedField.new(:int32) 276 l4[5] = 42 277 assert l4 == [0, 0, 0, 0, 0, 42] 278 279 l4 << 100 280 assert l4 == [0, 0, 0, 0, 0, 42, 100] 281 l4 << 101 << 102 282 assert l4 == [0, 0, 0, 0, 0, 42, 100, 101, 102] 283 end 284 285 def test_parent_rptfield 286 #make sure we set the RepeatedField and can add to it 287 m = proto_module::TestMessage.new 288 assert m.repeated_string == [] 289 m.repeated_string << 'ok' 290 m.repeated_string.push('ok2') 291 assert m.repeated_string == ['ok', 'ok2'] 292 m.repeated_string += ['ok3'] 293 assert m.repeated_string == ['ok', 'ok2', 'ok3'] 294 end 295 296 def test_rptfield_msg 297 l = Google::Protobuf::RepeatedField.new(:message, proto_module::TestMessage) 298 l.push proto_module::TestMessage.new 299 assert l.count == 1 300 assert_raise Google::Protobuf::TypeError do 301 l.push proto_module::TestMessage2.new 302 end 303 assert_raise Google::Protobuf::TypeError do 304 l.push 42 305 end 306 307 l2 = l.dup 308 assert l2[0] == l[0] 309 assert l2[0].object_id == l[0].object_id 310 311 l2 = Google::Protobuf.deep_copy(l) 312 assert l2[0] == l[0] 313 assert l2[0].object_id != l[0].object_id 314 315 l3 = l + l2 316 assert l3.count == 2 317 assert l3[0] == l[0] 318 assert l3[1] == l2[0] 319 l3[0].optional_int32 = 1000 320 assert l[0].optional_int32 == 1000 321 322 new_msg = proto_module::TestMessage.new(:optional_int32 => 200) 323 l4 = l + [new_msg] 324 assert l4.count == 2 325 new_msg.optional_int32 = 1000 326 assert l4[1].optional_int32 == 1000 327 end 328 329 def test_rptfield_enum 330 l = Google::Protobuf::RepeatedField.new(:enum, proto_module::TestEnum) 331 l.push :A 332 l.push :B 333 l.push :C 334 assert l.count == 3 335 assert_raise RangeError do 336 l.push :D 337 end 338 assert l[0] == :A 339 340 l.push 4 341 assert l[3] == 4 342 end 343 344 def test_rptfield_initialize 345 assert_raise ArgumentError do 346 Google::Protobuf::RepeatedField.new 347 end 348 assert_raise ArgumentError do 349 Google::Protobuf::RepeatedField.new(:message) 350 end 351 assert_raise ArgumentError do 352 Google::Protobuf::RepeatedField.new([1, 2, 3]) 353 end 354 assert_raise ArgumentError do 355 Google::Protobuf::RepeatedField.new(:message, [proto_module::TestMessage2.new]) 356 end 357 end 358 359 def test_rptfield_array_ducktyping 360 l = Google::Protobuf::RepeatedField.new(:int32) 361 length_methods = %w(count length size) 362 length_methods.each do |lm| 363 assert l.send(lm) == 0 364 end 365 # out of bounds returns a nil 366 assert l[0] == nil 367 assert l[1] == nil 368 assert l[-1] == nil 369 l.push 4 370 length_methods.each do |lm| 371 assert l.send(lm) == 1 372 end 373 assert l[0] == 4 374 assert l[1] == nil 375 assert l[-1] == 4 376 assert l[-2] == nil 377 378 l.push 2 379 length_methods.each do |lm| 380 assert l.send(lm) == 2 381 end 382 assert l[0] == 4 383 assert l[1] == 2 384 assert l[2] == nil 385 assert l[-1] == 2 386 assert l[-2] == 4 387 assert l[-3] == nil 388 389 #adding out of scope will backfill with empty objects 390 end 391 392 def test_map_basic 393 # allowed key types: 394 # :int32, :int64, :uint32, :uint64, :bool, :string, :bytes. 395 396 m = Google::Protobuf::Map.new(:string, :int32) 397 m["asdf"] = 1 398 assert m["asdf"] == 1 399 m["jkl;"] = 42 400 assert m == { "jkl;" => 42, "asdf" => 1 } 401 assert m.has_key?("asdf") 402 assert !m.has_key?("qwerty") 403 assert m.length == 2 404 405 m2 = m.dup 406 assert_equal m, m2 407 assert m.hash != 0 408 assert_equal m.hash, m2.hash 409 410 collected = {} 411 m.each { |k,v| collected[v] = k } 412 assert collected == { 42 => "jkl;", 1 => "asdf" } 413 414 assert m.delete("asdf") == 1 415 assert !m.has_key?("asdf") 416 assert m["asdf"] == nil 417 assert !m.has_key?("asdf") 418 419 # We only assert on inspect value when there is one map entry because the 420 # order in which elements appear is unspecified (depends on the internal 421 # hash function). We don't want a brittle test. 422 assert m.inspect == "{\"jkl;\"=>42}" 423 424 assert m.keys == ["jkl;"] 425 assert m.values == [42] 426 427 m.clear 428 assert m.length == 0 429 assert m == {} 430 431 assert_raise TypeError do 432 m[1] = 1 433 end 434 assert_raise RangeError do 435 m["asdf"] = 0x1_0000_0000 436 end 437 end 438 439 def test_map_ctor 440 m = Google::Protobuf::Map.new(:string, :int32, 441 {"a" => 1, "b" => 2, "c" => 3}) 442 assert m == {"a" => 1, "c" => 3, "b" => 2} 443 end 444 445 def test_map_keytypes 446 m = Google::Protobuf::Map.new(:int32, :int32) 447 m[1] = 42 448 m[-1] = 42 449 assert_raise RangeError do 450 m[0x8000_0000] = 1 451 end 452 assert_raise Google::Protobuf::TypeError do 453 m["asdf"] = 1 454 end 455 456 m = Google::Protobuf::Map.new(:int64, :int32) 457 m[0x1000_0000_0000_0000] = 1 458 assert_raise RangeError do 459 m[0x1_0000_0000_0000_0000] = 1 460 end 461 assert_raise Google::Protobuf::TypeError do 462 m["asdf"] = 1 463 end 464 465 m = Google::Protobuf::Map.new(:uint32, :int32) 466 m[0x8000_0000] = 1 467 assert_raise RangeError do 468 m[0x1_0000_0000] = 1 469 end 470 assert_raise RangeError do 471 m[-1] = 1 472 end 473 474 m = Google::Protobuf::Map.new(:uint64, :int32) 475 m[0x8000_0000_0000_0000] = 1 476 assert_raise RangeError do 477 m[0x1_0000_0000_0000_0000] = 1 478 end 479 assert_raise RangeError do 480 m[-1] = 1 481 end 482 483 m = Google::Protobuf::Map.new(:bool, :int32) 484 m[true] = 1 485 m[false] = 2 486 assert_raise Google::Protobuf::TypeError do 487 m[1] = 1 488 end 489 assert_raise Google::Protobuf::TypeError do 490 m["asdf"] = 1 491 end 492 493 m = Google::Protobuf::Map.new(:string, :int32) 494 m["asdf"] = 1 495 assert_raise TypeError do 496 m[1] = 1 497 end 498 assert_raise Encoding::UndefinedConversionError do 499 bytestring = ["FFFF"].pack("H*") 500 m[bytestring] = 1 501 end 502 503 m = Google::Protobuf::Map.new(:bytes, :int32) 504 bytestring = ["FFFF"].pack("H*") 505 m[bytestring] = 1 506 # Allowed -- we will automatically convert to ASCII-8BIT. 507 m["asdf"] = 1 508 assert_raise TypeError do 509 m[1] = 1 510 end 511 end 512 513 def test_map_msg_enum_valuetypes 514 m = Google::Protobuf::Map.new(:string, :message, proto_module::TestMessage) 515 m["asdf"] = proto_module::TestMessage.new 516 assert_raise Google::Protobuf::TypeError do 517 m["jkl;"] = proto_module::TestMessage2.new 518 end 519 520 m = Google::Protobuf::Map.new( 521 :string, :message, proto_module::TestMessage, 522 { "a" => proto_module::TestMessage.new(:optional_int32 => 42), 523 "b" => proto_module::TestMessage.new(:optional_int32 => 84) }) 524 assert m.length == 2 525 assert m.values.map{|msg| msg.optional_int32}.sort == [42, 84] 526 527 m = Google::Protobuf::Map.new(:string, :enum, proto_module::TestEnum, 528 { "x" => :A, "y" => :B, "z" => :C }) 529 assert m.length == 3 530 assert m["z"] == :C 531 m["z"] = 2 532 assert m["z"] == :B 533 m["z"] = 4 534 assert m["z"] == 4 535 assert_raise RangeError do 536 m["z"] = :Z 537 end 538 assert_raise RangeError do 539 m["z"] = "z" 540 end 541 end 542 543 def test_map_dup_deep_copy 544 m = Google::Protobuf::Map.new( 545 :string, :message, proto_module::TestMessage, 546 { "a" => proto_module::TestMessage.new(:optional_int32 => 42), 547 "b" => proto_module::TestMessage.new(:optional_int32 => 84) }) 548 549 m2 = m.dup 550 assert m == m2 551 assert m.object_id != m2.object_id 552 assert m["a"].object_id == m2["a"].object_id 553 assert m["b"].object_id == m2["b"].object_id 554 555 m2 = Google::Protobuf.deep_copy(m) 556 assert m == m2 557 assert m.object_id != m2.object_id 558 assert m["a"].object_id != m2["a"].object_id 559 assert m["b"].object_id != m2["b"].object_id 560 end 561 562 def test_oneof_descriptors 563 d = proto_module::OneofMessage.descriptor 564 o = d.lookup_oneof("my_oneof") 565 assert o != nil 566 assert o.class == Google::Protobuf::OneofDescriptor 567 assert o.name == "my_oneof" 568 oneof_count = 0 569 d.each_oneof{ |oneof| 570 oneof_count += 1 571 assert oneof == o 572 } 573 assert oneof_count == 1 574 assert o.count == 4 575 field_names = o.map{|f| f.name}.sort 576 assert field_names == ["a", "b", "c", "d"] 577 end 578 579 def test_oneof 580 d = proto_module::OneofMessage.new 581 assert d.a == "" 582 assert d.b == 0 583 assert d.c == nil 584 assert d.d == :Default 585 assert d.my_oneof == nil 586 587 d.a = "hi" 588 assert d.a == "hi" 589 assert d.b == 0 590 assert d.c == nil 591 assert d.d == :Default 592 assert d.my_oneof == :a 593 594 d.b = 42 595 assert d.a == "" 596 assert d.b == 42 597 assert d.c == nil 598 assert d.d == :Default 599 assert d.my_oneof == :b 600 601 d.c = proto_module::TestMessage2.new(:foo => 100) 602 assert d.a == "" 603 assert d.b == 0 604 assert d.c.foo == 100 605 assert d.d == :Default 606 assert d.my_oneof == :c 607 608 d.d = :C 609 assert d.a == "" 610 assert d.b == 0 611 assert d.c == nil 612 assert d.d == :C 613 assert d.my_oneof == :d 614 615 d2 = proto_module::OneofMessage.decode(proto_module::OneofMessage.encode(d)) 616 assert d2 == d 617 618 encoded_field_a = proto_module::OneofMessage.encode(proto_module::OneofMessage.new(:a => "string")) 619 encoded_field_b = proto_module::OneofMessage.encode(proto_module::OneofMessage.new(:b => 1000)) 620 encoded_field_c = proto_module::OneofMessage.encode( 621 proto_module::OneofMessage.new(:c => proto_module::TestMessage2.new(:foo => 1))) 622 encoded_field_d = proto_module::OneofMessage.encode(proto_module::OneofMessage.new(:d => :B)) 623 624 d3 = proto_module::OneofMessage.decode( 625 encoded_field_c + encoded_field_a + encoded_field_b + encoded_field_d) 626 assert d3.a == "" 627 assert d3.b == 0 628 assert d3.c == nil 629 assert d3.d == :B 630 631 d4 = proto_module::OneofMessage.decode( 632 encoded_field_c + encoded_field_a + encoded_field_b + encoded_field_d + 633 encoded_field_c) 634 assert d4.a == "" 635 assert d4.b == 0 636 assert d4.c.foo == 1 637 assert d4.d == :Default 638 639 d5 = proto_module::OneofMessage.new(:a => "hello") 640 assert d5.a == "hello" 641 d5.a = nil 642 assert d5.a == "" 643 assert proto_module::OneofMessage.encode(d5) == '' 644 assert d5.my_oneof == nil 645 end 646 647 def test_enum_field 648 m = proto_module::TestMessage.new 649 assert m.optional_enum == :Default 650 m.optional_enum = :A 651 assert m.optional_enum == :A 652 assert_raise RangeError do 653 m.optional_enum = :ASDF 654 end 655 m.optional_enum = 1 656 assert m.optional_enum == :A 657 m.optional_enum = 100 658 assert m.optional_enum == 100 659 end 660 661 def test_dup 662 m = proto_module::TestMessage.new 663 m.optional_string = "hello" 664 m.optional_int32 = 42 665 tm1 = proto_module::TestMessage2.new(:foo => 100) 666 tm2 = proto_module::TestMessage2.new(:foo => 200) 667 m.repeated_msg.push tm1 668 assert m.repeated_msg[-1] == tm1 669 m.repeated_msg.push tm2 670 assert m.repeated_msg[-1] == tm2 671 m2 = m.dup 672 assert m == m2 673 m.optional_int32 += 1 674 assert m != m2 675 assert m.repeated_msg[0] == m2.repeated_msg[0] 676 assert m.repeated_msg[0].object_id == m2.repeated_msg[0].object_id 677 end 678 679 def test_deep_copy 680 m = proto_module::TestMessage.new(:optional_int32 => 42, 681 :repeated_msg => [proto_module::TestMessage2.new(:foo => 100)]) 682 m2 = Google::Protobuf.deep_copy(m) 683 assert m == m2 684 assert m.repeated_msg == m2.repeated_msg 685 assert m.repeated_msg.object_id != m2.repeated_msg.object_id 686 assert m.repeated_msg[0].object_id != m2.repeated_msg[0].object_id 687 end 688 689 def test_eq 690 m = proto_module::TestMessage.new(:optional_int32 => 42, 691 :repeated_int32 => [1, 2, 3]) 692 m2 = proto_module::TestMessage.new(:optional_int32 => 43, 693 :repeated_int32 => [1, 2, 3]) 694 assert m != m2 695 end 696 697 def test_enum_lookup 698 assert proto_module::TestEnum::A == 1 699 assert proto_module::TestEnum::B == 2 700 assert proto_module::TestEnum::C == 3 701 702 assert proto_module::TestEnum::lookup(1) == :A 703 assert proto_module::TestEnum::lookup(2) == :B 704 assert proto_module::TestEnum::lookup(3) == :C 705 706 assert proto_module::TestEnum::resolve(:A) == 1 707 assert proto_module::TestEnum::resolve(:B) == 2 708 assert proto_module::TestEnum::resolve(:C) == 3 709 end 710 711 def test_enum_const_get_helpers 712 m = proto_module::TestMessage.new 713 assert_equal proto_module::TestEnum::Default, m.optional_enum_const 714 assert_equal proto_module::TestEnum.const_get(:Default), m.optional_enum_const 715 716 m = proto_module::TestMessage.new({optional_enum: proto_module::TestEnum::A}) 717 assert_equal proto_module::TestEnum::A, m.optional_enum_const 718 assert_equal proto_module::TestEnum.const_get(:A), m.optional_enum_const 719 720 m = proto_module::TestMessage.new({optional_enum: proto_module::TestEnum::B}) 721 assert_equal proto_module::TestEnum::B, m.optional_enum_const 722 assert_equal proto_module::TestEnum.const_get(:B), m.optional_enum_const 723 724 m = proto_module::TestMessage.new({optional_enum: proto_module::TestEnum::C}) 725 assert_equal proto_module::TestEnum::C, m.optional_enum_const 726 assert_equal proto_module::TestEnum.const_get(:C), m.optional_enum_const 727 728 m = proto_module::TestMessage2.new({foo: 2}) 729 assert_equal 2, m.foo 730 assert_raise(NoMethodError) { m.foo_ } 731 assert_raise(NoMethodError) { m.foo_X } 732 assert_raise(NoMethodError) { m.foo_XX } 733 assert_raise(NoMethodError) { m.foo_XXX } 734 assert_raise(NoMethodError) { m.foo_XXXX } 735 assert_raise(NoMethodError) { m.foo_XXXXX } 736 assert_raise(NoMethodError) { m.foo_XXXXXX } 737 738 m = proto_module::Enumer.new({optional_enum: :B}) 739 assert_equal :B, m.optional_enum 740 assert_raise(NoMethodError) { m.optional_enum_ } 741 assert_raise(NoMethodError) { m.optional_enum_X } 742 assert_raise(NoMethodError) { m.optional_enum_XX } 743 assert_raise(NoMethodError) { m.optional_enum_XXX } 744 assert_raise(NoMethodError) { m.optional_enum_XXXX } 745 assert_raise(NoMethodError) { m.optional_enum_XXXXX } 746 assert_raise(NoMethodError) { m.optional_enum_XXXXXX } 747 end 748 749 def test_enum_getter 750 m = proto_module::Enumer.new(:optional_enum => :B, :repeated_enum => [:A, :C]) 751 752 assert_equal :B, m.optional_enum 753 assert_equal 2, m.optional_enum_const 754 assert_equal proto_module::TestEnum::B, m.optional_enum_const 755 assert_equal [:A, :C], m.repeated_enum 756 assert_equal [1, 3], m.repeated_enum_const 757 assert_equal [proto_module::TestEnum::A, proto_module::TestEnum::C], m.repeated_enum_const 758 end 759 760 def test_enum_getter_oneof 761 m = proto_module::Enumer.new(:const => :C) 762 763 assert_equal :C, m.const 764 assert_equal 3, m.const_const 765 assert_equal proto_module::TestEnum::C, m.const_const 766 end 767 768 def test_enum_getter_only_enums 769 m = proto_module::Enumer.new(:optional_enum => :B, :a_const => 'thing') 770 771 assert_equal 'thing', m.a_const 772 assert_equal :B, m.optional_enum 773 774 assert_raise(NoMethodError) { m.a } 775 assert_raise(NoMethodError) { m.a_const_const } 776 end 777 778 def test_repeated_push 779 m = proto_module::TestMessage.new 780 781 m.repeated_string += ['one'] 782 m.repeated_string += %w[two three] 783 assert_equal %w[one two three], m.repeated_string 784 785 m.repeated_string.push *['four', 'five'] 786 assert_equal %w[one two three four five], m.repeated_string 787 788 m.repeated_string.push 'six', 'seven' 789 assert_equal %w[one two three four five six seven], m.repeated_string 790 791 m = proto_module::TestMessage.new 792 793 m.repeated_msg += [proto_module::TestMessage2.new(:foo => 1), proto_module::TestMessage2.new(:foo => 2)] 794 m.repeated_msg += [proto_module::TestMessage2.new(:foo => 3)] 795 m.repeated_msg.push proto_module::TestMessage2.new(:foo => 4), proto_module::TestMessage2.new(:foo => 5) 796 assert_equal [1, 2, 3, 4, 5], m.repeated_msg.map {|x| x.foo} 797 end 798 799 def test_parse_serialize 800 m = proto_module::TestMessage.new(:optional_int32 => 42, 801 :optional_string => "hello world", 802 :optional_enum => :B, 803 :repeated_string => ["a", "b", "c"], 804 :repeated_int32 => [42, 43, 44], 805 :repeated_enum => [:A, :B, :C, 100], 806 :repeated_msg => [proto_module::TestMessage2.new(:foo => 1), 807 proto_module::TestMessage2.new(:foo => 2)]) 808 data = proto_module::TestMessage.encode m 809 m2 = proto_module::TestMessage.decode data 810 assert m == m2 811 812 data = Google::Protobuf.encode m 813 m2 = Google::Protobuf.decode(proto_module::TestMessage, data) 814 assert 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 end 854 855 def test_def_errors 856 s = Google::Protobuf::DescriptorPool.new 857 assert_raise Google::Protobuf::TypeError do 858 s.build do 859 # enum with no default (integer value 0) 860 add_enum "MyEnum" do 861 value :A, 1 862 end 863 end 864 end 865 assert_raise Google::Protobuf::TypeError do 866 s.build do 867 # message with required field (unsupported in proto3) 868 add_message "MyMessage" do 869 required :foo, :int32, 1 870 end 871 end 872 end 873 end 874 875 def test_corecursive 876 # just be sure that we can instantiate types with corecursive field-type 877 # references. 878 m = proto_module::Recursive1.new(:foo => proto_module::Recursive2.new(:foo => proto_module::Recursive1.new)) 879 assert proto_module::Recursive1.descriptor.lookup("foo").subtype == 880 proto_module::Recursive2.descriptor 881 assert proto_module::Recursive2.descriptor.lookup("foo").subtype == 882 proto_module::Recursive1.descriptor 883 884 serialized = proto_module::Recursive1.encode(m) 885 m2 = proto_module::Recursive1.decode(serialized) 886 assert m == m2 887 end 888 889 def test_serialize_cycle 890 m = proto_module::Recursive1.new(:foo => proto_module::Recursive2.new) 891 m.foo.foo = m 892 assert_raise RuntimeError do 893 proto_module::Recursive1.encode(m) 894 end 895 end 896 897 def test_bad_field_names 898 m = proto_module::BadFieldNames.new(:dup => 1, :class => 2) 899 m2 = m.dup 900 assert m == m2 901 assert m['dup'] == 1 902 assert m['class'] == 2 903 m['dup'] = 3 904 assert m['dup'] == 3 905 m['a.b'] = 4 906 assert m['a.b'] == 4 907 end 908 909 def test_int_ranges 910 m = proto_module::TestMessage.new 911 912 m.optional_int32 = 0 913 m.optional_int32 = -0x8000_0000 914 m.optional_int32 = +0x7fff_ffff 915 m.optional_int32 = 1.0 916 m.optional_int32 = -1.0 917 m.optional_int32 = 2e9 918 assert_raise RangeError do 919 m.optional_int32 = -0x8000_0001 920 end 921 assert_raise RangeError do 922 m.optional_int32 = +0x8000_0000 923 end 924 assert_raise RangeError do 925 m.optional_int32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum 926 end 927 assert_raise RangeError do 928 m.optional_int32 = 1e12 929 end 930 assert_raise RangeError do 931 m.optional_int32 = 1.5 932 end 933 934 m.optional_uint32 = 0 935 m.optional_uint32 = +0xffff_ffff 936 m.optional_uint32 = 1.0 937 m.optional_uint32 = 4e9 938 assert_raise RangeError do 939 m.optional_uint32 = -1 940 end 941 assert_raise RangeError do 942 m.optional_uint32 = -1.5 943 end 944 assert_raise RangeError do 945 m.optional_uint32 = -1.5e12 946 end 947 assert_raise RangeError do 948 m.optional_uint32 = -0x1000_0000_0000_0000 949 end 950 assert_raise RangeError do 951 m.optional_uint32 = +0x1_0000_0000 952 end 953 assert_raise RangeError do 954 m.optional_uint32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum 955 end 956 assert_raise RangeError do 957 m.optional_uint32 = 1e12 958 end 959 assert_raise RangeError do 960 m.optional_uint32 = 1.5 961 end 962 963 m.optional_int64 = 0 964 m.optional_int64 = -0x8000_0000_0000_0000 965 m.optional_int64 = +0x7fff_ffff_ffff_ffff 966 m.optional_int64 = 1.0 967 m.optional_int64 = -1.0 968 m.optional_int64 = 8e18 969 m.optional_int64 = -8e18 970 assert_raise RangeError do 971 m.optional_int64 = -0x8000_0000_0000_0001 972 end 973 assert_raise RangeError do 974 m.optional_int64 = +0x8000_0000_0000_0000 975 end 976 assert_raise RangeError do 977 m.optional_int64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum 978 end 979 assert_raise RangeError do 980 m.optional_int64 = 1e50 981 end 982 assert_raise RangeError do 983 m.optional_int64 = 1.5 984 end 985 986 m.optional_uint64 = 0 987 m.optional_uint64 = +0xffff_ffff_ffff_ffff 988 m.optional_uint64 = 1.0 989 m.optional_uint64 = 16e18 990 assert_raise RangeError do 991 m.optional_uint64 = -1 992 end 993 assert_raise RangeError do 994 m.optional_uint64 = -1.5 995 end 996 assert_raise RangeError do 997 m.optional_uint64 = -1.5e12 998 end 999 assert_raise RangeError do 1000 m.optional_uint64 = -0x1_0000_0000_0000_0000 1001 end 1002 assert_raise RangeError do 1003 m.optional_uint64 = +0x1_0000_0000_0000_0000 1004 end 1005 assert_raise RangeError do 1006 m.optional_uint64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum 1007 end 1008 assert_raise RangeError do 1009 m.optional_uint64 = 1e50 1010 end 1011 assert_raise RangeError do 1012 m.optional_uint64 = 1.5 1013 end 1014 end 1015 1016 def test_stress_test 1017 m = proto_module::TestMessage.new 1018 m.optional_int32 = 42 1019 m.optional_int64 = 0x100000000 1020 m.optional_string = "hello world" 1021 10.times do m.repeated_msg.push proto_module::TestMessage2.new(:foo => 42) end 1022 10.times do m.repeated_string.push "hello world" end 1023 1024 data = proto_module::TestMessage.encode(m) 1025 1026 10_000.times do 1027 m = proto_module::TestMessage.decode(data) 1028 data_new = proto_module::TestMessage.encode(m) 1029 assert data_new == data 1030 data = data_new 1031 end 1032 end 1033 1034 def test_reflection 1035 m = proto_module::TestMessage.new(:optional_int32 => 1234) 1036 msgdef = m.class.descriptor 1037 assert msgdef.class == Google::Protobuf::Descriptor 1038 assert msgdef.any? {|field| field.name == "optional_int32"} 1039 optional_int32 = msgdef.lookup "optional_int32" 1040 assert optional_int32.class == Google::Protobuf::FieldDescriptor 1041 assert optional_int32 != nil 1042 assert optional_int32.name == "optional_int32" 1043 assert optional_int32.type == :int32 1044 optional_int32.set(m, 5678) 1045 assert m.optional_int32 == 5678 1046 m.optional_int32 = 1000 1047 assert optional_int32.get(m) == 1000 1048 1049 optional_msg = msgdef.lookup "optional_msg" 1050 assert optional_msg.subtype == proto_module::TestMessage2.descriptor 1051 1052 optional_msg.set(m, optional_msg.subtype.msgclass.new) 1053 1054 assert msgdef.msgclass == proto_module::TestMessage 1055 1056 optional_enum = msgdef.lookup "optional_enum" 1057 assert optional_enum.subtype == proto_module::TestEnum.descriptor 1058 assert optional_enum.subtype.class == Google::Protobuf::EnumDescriptor 1059 optional_enum.subtype.each do |k, v| 1060 # set with integer, check resolution to symbolic name 1061 optional_enum.set(m, v) 1062 assert optional_enum.get(m) == k 1063 end 1064 end 1065 1066 def test_json 1067 # TODO: Fix JSON in JRuby version. 1068 return if RUBY_PLATFORM == "java" 1069 m = proto_module::TestMessage.new(:optional_int32 => 1234, 1070 :optional_int64 => -0x1_0000_0000, 1071 :optional_uint32 => 0x8000_0000, 1072 :optional_uint64 => 0xffff_ffff_ffff_ffff, 1073 :optional_bool => true, 1074 :optional_float => 1.0, 1075 :optional_double => -1e100, 1076 :optional_string => "Test string", 1077 :optional_bytes => ["FFFFFFFF"].pack('H*'), 1078 :optional_msg => proto_module::TestMessage2.new(:foo => 42), 1079 :repeated_int32 => [1, 2, 3, 4], 1080 :repeated_string => ["a", "b", "c"], 1081 :repeated_bool => [true, false, true, false], 1082 :repeated_msg => [proto_module::TestMessage2.new(:foo => 1), 1083 proto_module::TestMessage2.new(:foo => 2)]) 1084 1085 json_text = proto_module::TestMessage.encode_json(m) 1086 m2 = proto_module::TestMessage.decode_json(json_text) 1087 puts m.inspect 1088 puts m2.inspect 1089 assert m == m2 1090 1091 # Crash case from GitHub issue 283. 1092 bar = proto_module::Bar.new(msg: "bar") 1093 baz1 = proto_module::Baz.new(msg: "baz") 1094 baz2 = proto_module::Baz.new(msg: "quux") 1095 proto_module::Foo.encode_json(proto_module::Foo.new) 1096 proto_module::Foo.encode_json(proto_module::Foo.new(bar: bar)) 1097 proto_module::Foo.encode_json(proto_module::Foo.new(bar: bar, baz: [baz1, baz2])) 1098 end 1099 1100 def test_json_empty 1101 assert proto_module::TestMessage.encode_json(proto_module::TestMessage.new) == '{}' 1102 end 1103 1104 def test_json_emit_defaults 1105 # TODO: Fix JSON in JRuby version. 1106 return if RUBY_PLATFORM == "java" 1107 m = proto_module::TestMessage.new 1108 1109 expected = { 1110 optionalInt32: 0, 1111 optionalInt64: "0", 1112 optionalUint32: 0, 1113 optionalUint64: "0", 1114 optionalBool: false, 1115 optionalFloat: 0, 1116 optionalDouble: 0, 1117 optionalString: "", 1118 optionalBytes: "", 1119 optionalEnum: "Default", 1120 repeatedInt32: [], 1121 repeatedInt64: [], 1122 repeatedUint32: [], 1123 repeatedUint64: [], 1124 repeatedBool: [], 1125 repeatedFloat: [], 1126 repeatedDouble: [], 1127 repeatedString: [], 1128 repeatedBytes: [], 1129 repeatedMsg: [], 1130 repeatedEnum: [] 1131 } 1132 1133 actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true) 1134 1135 assert JSON.parse(actual, :symbolize_names => true) == expected 1136 end 1137 1138 def test_json_emit_defaults_submsg 1139 # TODO: Fix JSON in JRuby version. 1140 return if RUBY_PLATFORM == "java" 1141 m = proto_module::TestMessage.new(optional_msg: proto_module::TestMessage2.new) 1142 1143 expected = { 1144 optionalInt32: 0, 1145 optionalInt64: "0", 1146 optionalUint32: 0, 1147 optionalUint64: "0", 1148 optionalBool: false, 1149 optionalFloat: 0, 1150 optionalDouble: 0, 1151 optionalString: "", 1152 optionalBytes: "", 1153 optionalMsg: {foo: 0}, 1154 optionalEnum: "Default", 1155 repeatedInt32: [], 1156 repeatedInt64: [], 1157 repeatedUint32: [], 1158 repeatedUint64: [], 1159 repeatedBool: [], 1160 repeatedFloat: [], 1161 repeatedDouble: [], 1162 repeatedString: [], 1163 repeatedBytes: [], 1164 repeatedMsg: [], 1165 repeatedEnum: [] 1166 } 1167 1168 actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true) 1169 1170 assert JSON.parse(actual, :symbolize_names => true) == expected 1171 end 1172 1173 def test_json_emit_defaults_repeated_submsg 1174 # TODO: Fix JSON in JRuby version. 1175 return if RUBY_PLATFORM == "java" 1176 m = proto_module::TestMessage.new(repeated_msg: [proto_module::TestMessage2.new]) 1177 1178 expected = { 1179 optionalInt32: 0, 1180 optionalInt64: "0", 1181 optionalUint32: 0, 1182 optionalUint64: "0", 1183 optionalBool: false, 1184 optionalFloat: 0, 1185 optionalDouble: 0, 1186 optionalString: "", 1187 optionalBytes: "", 1188 optionalEnum: "Default", 1189 repeatedInt32: [], 1190 repeatedInt64: [], 1191 repeatedUint32: [], 1192 repeatedUint64: [], 1193 repeatedBool: [], 1194 repeatedFloat: [], 1195 repeatedDouble: [], 1196 repeatedString: [], 1197 repeatedBytes: [], 1198 repeatedMsg: [{foo: 0}], 1199 repeatedEnum: [] 1200 } 1201 1202 actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true) 1203 1204 assert JSON.parse(actual, :symbolize_names => true) == expected 1205 end 1206 1207 def value_from_ruby(value) 1208 ret = Google::Protobuf::Value.new 1209 case value 1210 when String 1211 ret.string_value = value 1212 when Google::Protobuf::Struct 1213 ret.struct_value = value 1214 when Hash 1215 ret.struct_value = struct_from_ruby(value) 1216 when Google::Protobuf::ListValue 1217 ret.list_value = value 1218 when Array 1219 ret.list_value = list_from_ruby(value) 1220 else 1221 @log.error "Unknown type: #{value.class}" 1222 raise Google::Protobuf::Error, "Unknown type: #{value.class}" 1223 end 1224 ret 1225 end 1226 1227 def list_from_ruby(arr) 1228 ret = Google::Protobuf::ListValue.new 1229 arr.each do |v| 1230 ret.values << value_from_ruby(v) 1231 end 1232 ret 1233 end 1234 1235 def struct_from_ruby(hash) 1236 ret = Google::Protobuf::Struct.new 1237 hash.each do |k, v| 1238 ret.fields[k] ||= value_from_ruby(v) 1239 end 1240 ret 1241 end 1242 1243 def test_deep_json 1244 # will not overflow 1245 json = '{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":'\ 1246 '{"a":{"a":{"a":{"a":{}}}}}}}}}}}}}}}}' 1247 1248 struct = struct_from_ruby(JSON.parse(json)) 1249 assert_equal json, struct.to_json 1250 1251 encoded = proto_module::MyRepeatedStruct.encode( 1252 proto_module::MyRepeatedStruct.new(structs: [proto_module::MyStruct.new(struct: struct)])) 1253 assert_equal json, proto_module::MyRepeatedStruct.decode(encoded).structs[0].struct.to_json 1254 1255 # will overflow 1256 json = '{"a":{"a":{"a":[{"a":{"a":[{"a":[{"a":{"a":[{"a":[{"a":'\ 1257 '{"a":[{"a":[{"a":{"a":{"a":[{"a":"a"}]}}}]}]}}]}]}}]}]}}]}}}' 1258 1259 struct = struct_from_ruby(JSON.parse(json)) 1260 assert_equal json, struct.to_json 1261 1262 assert_raise(RuntimeError, "Maximum recursion depth exceeded during encoding") do 1263 proto_module::MyRepeatedStruct.encode( 1264 proto_module::MyRepeatedStruct.new(structs: [proto_module::MyStruct.new(struct: struct)])) 1265 end 1266 end 1267 1268 def test_comparison_with_arbitrary_object 1269 assert proto_module::TestMessage.new != nil 1270 end 1271 1272 def test_wrapper_getters 1273 m = proto_module::Wrapper.new( 1274 double: Google::Protobuf::DoubleValue.new(value: 2.0), 1275 float: Google::Protobuf::FloatValue.new(value: 4.0), 1276 int32: Google::Protobuf::Int32Value.new(value: 3), 1277 int64: Google::Protobuf::Int64Value.new(value: 4), 1278 uint32: Google::Protobuf::UInt32Value.new(value: 5), 1279 uint64: Google::Protobuf::UInt64Value.new(value: 6), 1280 bool: Google::Protobuf::BoolValue.new(value: true), 1281 string: Google::Protobuf::StringValue.new(value: 'str'), 1282 bytes: Google::Protobuf::BytesValue.new(value: 'fun'), 1283 real_string: '100' 1284 ) 1285 1286 assert_equal 2.0, m.double_as_value 1287 assert_equal 2.0, m.double.value 1288 assert_equal 4.0, m.float_as_value 1289 assert_equal 4.0, m.float.value 1290 assert_equal 3, m.int32_as_value 1291 assert_equal 3, m.int32.value 1292 assert_equal 4, m.int64_as_value 1293 assert_equal 4, m.int64.value 1294 assert_equal 5, m.uint32_as_value 1295 assert_equal 5, m.uint32.value 1296 assert_equal 6, m.uint64_as_value 1297 assert_equal 6, m.uint64.value 1298 assert_equal true, m.bool_as_value 1299 assert_equal true, m.bool.value 1300 assert_equal 'str', m.string_as_value 1301 assert_equal 'str', m.string.value 1302 assert_equal 'fun', m.bytes_as_value 1303 assert_equal 'fun', m.bytes.value 1304 end 1305 1306 def test_wrapper_setters_as_value 1307 m = proto_module::Wrapper.new 1308 1309 m.double_as_value = 4.8 1310 assert_equal 4.8, m.double_as_value 1311 assert_equal Google::Protobuf::DoubleValue.new(value: 4.8), m.double 1312 m.float_as_value = 2.4 1313 assert_in_delta 2.4, m.float_as_value 1314 assert_in_delta Google::Protobuf::FloatValue.new(value: 2.4).value, m.float.value 1315 m.int32_as_value = 5 1316 assert_equal 5, m.int32_as_value 1317 assert_equal Google::Protobuf::Int32Value.new(value: 5), m.int32 1318 m.int64_as_value = 15 1319 assert_equal 15, m.int64_as_value 1320 assert_equal Google::Protobuf::Int64Value.new(value: 15), m.int64 1321 m.uint32_as_value = 50 1322 assert_equal 50, m.uint32_as_value 1323 assert_equal Google::Protobuf::UInt32Value.new(value: 50), m.uint32 1324 m.uint64_as_value = 500 1325 assert_equal 500, m.uint64_as_value 1326 assert_equal Google::Protobuf::UInt64Value.new(value: 500), m.uint64 1327 m.bool_as_value = false 1328 assert_equal false, m.bool_as_value 1329 assert_equal Google::Protobuf::BoolValue.new(value: false), m.bool 1330 m.string_as_value = 'xy' 1331 assert_equal 'xy', m.string_as_value 1332 assert_equal Google::Protobuf::StringValue.new(value: 'xy'), m.string 1333 m.bytes_as_value = '123' 1334 assert_equal '123', m.bytes_as_value 1335 assert_equal Google::Protobuf::BytesValue.new(value: '123'), m.bytes 1336 1337 m.double_as_value = nil 1338 assert_nil m.double 1339 assert_nil m.double_as_value 1340 m.float_as_value = nil 1341 assert_nil m.float 1342 assert_nil m.float_as_value 1343 m.int32_as_value = nil 1344 assert_nil m.int32 1345 assert_nil m.int32_as_value 1346 m.int64_as_value = nil 1347 assert_nil m.int64 1348 assert_nil m.int64_as_value 1349 m.uint32_as_value = nil 1350 assert_nil m.uint32 1351 assert_nil m.uint32_as_value 1352 m.uint64_as_value = nil 1353 assert_nil m.uint64 1354 assert_nil m.uint64_as_value 1355 m.bool_as_value = nil 1356 assert_nil m.bool 1357 assert_nil m.bool_as_value 1358 m.string_as_value = nil 1359 assert_nil m.string 1360 assert_nil m.string_as_value 1361 m.bytes_as_value = nil 1362 assert_nil m.bytes 1363 assert_nil m.bytes_as_value 1364 end 1365 1366 def test_wrapper_setters 1367 m = proto_module::Wrapper.new 1368 1369 m.double = Google::Protobuf::DoubleValue.new(value: 4.8) 1370 assert_equal 4.8, m.double_as_value 1371 assert_equal Google::Protobuf::DoubleValue.new(value: 4.8), m.double 1372 m.float = Google::Protobuf::FloatValue.new(value: 2.4) 1373 assert_in_delta 2.4, m.float_as_value 1374 assert_in_delta Google::Protobuf::FloatValue.new(value: 2.4).value, m.float.value 1375 m.int32 = Google::Protobuf::Int32Value.new(value: 5) 1376 assert_equal 5, m.int32_as_value 1377 assert_equal Google::Protobuf::Int32Value.new(value: 5), m.int32 1378 m.int64 = Google::Protobuf::Int64Value.new(value: 15) 1379 assert_equal 15, m.int64_as_value 1380 assert_equal Google::Protobuf::Int64Value.new(value: 15), m.int64 1381 m.uint32 = Google::Protobuf::UInt32Value.new(value: 50) 1382 assert_equal 50, m.uint32_as_value 1383 assert_equal Google::Protobuf::UInt32Value.new(value: 50), m.uint32 1384 m.uint64 = Google::Protobuf::UInt64Value.new(value: 500) 1385 assert_equal 500, m.uint64_as_value 1386 assert_equal Google::Protobuf::UInt64Value.new(value: 500), m.uint64 1387 m.bool = Google::Protobuf::BoolValue.new(value: false) 1388 assert_equal false, m.bool_as_value 1389 assert_equal Google::Protobuf::BoolValue.new(value: false), m.bool 1390 m.string = Google::Protobuf::StringValue.new(value: 'xy') 1391 assert_equal 'xy', m.string_as_value 1392 assert_equal Google::Protobuf::StringValue.new(value: 'xy'), m.string 1393 m.bytes = Google::Protobuf::BytesValue.new(value: '123') 1394 assert_equal '123', m.bytes_as_value 1395 assert_equal Google::Protobuf::BytesValue.new(value: '123'), m.bytes 1396 1397 m.double = nil 1398 assert_nil m.double 1399 assert_nil m.double_as_value 1400 m.float = nil 1401 assert_nil m.float 1402 assert_nil m.float_as_value 1403 m.int32 = nil 1404 assert_nil m.int32 1405 assert_nil m.int32_as_value 1406 m.int64 = nil 1407 assert_nil m.int64 1408 assert_nil m.int64_as_value 1409 m.uint32 = nil 1410 assert_nil m.uint32 1411 assert_nil m.uint32_as_value 1412 m.uint64 = nil 1413 assert_nil m.uint64 1414 assert_nil m.uint64_as_value 1415 m.bool = nil 1416 assert_nil m.bool 1417 assert_nil m.bool_as_value 1418 m.string = nil 1419 assert_nil m.string 1420 assert_nil m.string_as_value 1421 m.bytes = nil 1422 assert_nil m.bytes 1423 assert_nil m.bytes_as_value 1424 end 1425 1426 def test_wrappers_only 1427 m = proto_module::Wrapper.new(real_string: 'hi', oneof_string: 'there') 1428 1429 assert_raise(NoMethodError) { m.real_string_as_value } 1430 assert_raise(NoMethodError) { m.as_value } 1431 assert_raise(NoMethodError) { m._as_value } 1432 assert_raise(NoMethodError) { m.oneof_string_as_value } 1433 1434 m = proto_module::Wrapper.new 1435 m.string_as_value = 'you' 1436 assert_equal 'you', m.string.value 1437 assert_equal 'you', m.string_as_value 1438 assert_raise(NoMethodError) { m.string_ } 1439 assert_raise(NoMethodError) { m.string_X } 1440 assert_raise(NoMethodError) { m.string_XX } 1441 assert_raise(NoMethodError) { m.string_XXX } 1442 assert_raise(NoMethodError) { m.string_XXXX } 1443 assert_raise(NoMethodError) { m.string_XXXXX } 1444 assert_raise(NoMethodError) { m.string_XXXXXX } 1445 assert_raise(NoMethodError) { m.string_XXXXXXX } 1446 assert_raise(NoMethodError) { m.string_XXXXXXXX } 1447 assert_raise(NoMethodError) { m.string_XXXXXXXXX } 1448 assert_raise(NoMethodError) { m.string_XXXXXXXXXX } 1449 end 1450 1451 def test_converts_time 1452 m = proto_module::TimeMessage.new 1453 1454 m.timestamp = Google::Protobuf::Timestamp.new(seconds: 5, nanos: 6) 1455 assert_kind_of Google::Protobuf::Timestamp, m.timestamp 1456 assert_equal 5, m.timestamp.seconds 1457 assert_equal 6, m.timestamp.nanos 1458 1459 m.timestamp = Time.at(9466, 123456.789) 1460 assert_equal Google::Protobuf::Timestamp.new(seconds: 9466, nanos: 123456789), m.timestamp 1461 1462 m = proto_module::TimeMessage.new(timestamp: Time.at(1)) 1463 assert_equal Google::Protobuf::Timestamp.new(seconds: 1, nanos: 0), m.timestamp 1464 1465 assert_raise(Google::Protobuf::TypeError) { m.timestamp = 2 } 1466 assert_raise(Google::Protobuf::TypeError) { m.timestamp = 2.4 } 1467 assert_raise(Google::Protobuf::TypeError) { m.timestamp = '4' } 1468 assert_raise(Google::Protobuf::TypeError) { m.timestamp = proto_module::TimeMessage.new } 1469 end 1470 1471 def test_converts_duration 1472 m = proto_module::TimeMessage.new 1473 1474 m.duration = Google::Protobuf::Duration.new(seconds: 2, nanos: 22) 1475 assert_kind_of Google::Protobuf::Duration, m.duration 1476 assert_equal 2, m.duration.seconds 1477 assert_equal 22, m.duration.nanos 1478 1479 m.duration = 10.5 1480 assert_equal Google::Protobuf::Duration.new(seconds: 10, nanos: 500_000_000), m.duration 1481 1482 m.duration = 200 1483 assert_equal Google::Protobuf::Duration.new(seconds: 200, nanos: 0), m.duration 1484 1485 m.duration = Rational(3, 2) 1486 assert_equal Google::Protobuf::Duration.new(seconds: 1, nanos: 500_000_000), m.duration 1487 1488 m.duration = BigDecimal.new("5") 1489 assert_equal Google::Protobuf::Duration.new(seconds: 5, nanos: 0), m.duration 1490 1491 m = proto_module::TimeMessage.new(duration: 1.1) 1492 assert_equal Google::Protobuf::Duration.new(seconds: 1, nanos: 100_000_000), m.duration 1493 1494 assert_raise(Google::Protobuf::TypeError) { m.duration = '2' } 1495 assert_raise(Google::Protobuf::TypeError) { m.duration = proto_module::TimeMessage.new } 1496 end 1497 1498 def test_freeze 1499 m = proto_module::TestMessage.new 1500 m.optional_int32 = 10 1501 m.freeze 1502 1503 frozen_error = assert_raise(FrozenErrorType) { m.optional_int32 = 20 } 1504 assert_equal "can't modify frozen #{proto_module}::TestMessage", frozen_error.message 1505 assert_equal 10, m.optional_int32 1506 assert_equal true, m.frozen? 1507 1508 assert_raise(FrozenErrorType) { m.optional_int64 = 2 } 1509 assert_raise(FrozenErrorType) { m.optional_uint32 = 3 } 1510 assert_raise(FrozenErrorType) { m.optional_uint64 = 4 } 1511 assert_raise(FrozenErrorType) { m.optional_bool = true } 1512 assert_raise(FrozenErrorType) { m.optional_float = 6.0 } 1513 assert_raise(FrozenErrorType) { m.optional_double = 7.0 } 1514 assert_raise(FrozenErrorType) { m.optional_string = '8' } 1515 assert_raise(FrozenErrorType) { m.optional_bytes = nil } 1516 assert_raise(FrozenErrorType) { m.optional_msg = proto_module::TestMessage2.new } 1517 assert_raise(FrozenErrorType) { m.optional_enum = :A } 1518 assert_raise(FrozenErrorType) { m.repeated_int32 = 1 } 1519 assert_raise(FrozenErrorType) { m.repeated_int64 = 2 } 1520 assert_raise(FrozenErrorType) { m.repeated_uint32 = 3 } 1521 assert_raise(FrozenErrorType) { m.repeated_uint64 = 4 } 1522 assert_raise(FrozenErrorType) { m.repeated_bool = true } 1523 assert_raise(FrozenErrorType) { m.repeated_float = 6.0 } 1524 assert_raise(FrozenErrorType) { m.repeated_double = 7.0 } 1525 assert_raise(FrozenErrorType) { m.repeated_string = '8' } 1526 assert_raise(FrozenErrorType) { m.repeated_bytes = nil } 1527 assert_raise(FrozenErrorType) { m.repeated_msg = proto_module::TestMessage2.new } 1528 assert_raise(FrozenErrorType) { m.repeated_enum = :A } 1529 end 1530 1531 def test_eq 1532 m1 = proto_module::TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2']) 1533 m2 = proto_module::TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2']) 1534 1535 h = {} 1536 h[m1] = :yes 1537 1538 assert m1 == m2 1539 assert m1.eql?(m2) 1540 assert m1.hash == m2.hash 1541 assert h[m1] == :yes 1542 assert h[m2] == :yes 1543 1544 m1.optional_int32 = 2 1545 1546 assert m1 != m2 1547 assert !m1.eql?(m2) 1548 assert m1.hash != m2.hash 1549 assert_nil h[m2] 1550 end 1551end 1552