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_equal 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 end 906 907 def test_int_ranges 908 m = proto_module::TestMessage.new 909 910 m.optional_int32 = 0 911 m.optional_int32 = -0x8000_0000 912 m.optional_int32 = +0x7fff_ffff 913 m.optional_int32 = 1.0 914 m.optional_int32 = -1.0 915 m.optional_int32 = 2e9 916 assert_raise RangeError do 917 m.optional_int32 = -0x8000_0001 918 end 919 assert_raise RangeError do 920 m.optional_int32 = +0x8000_0000 921 end 922 assert_raise RangeError do 923 m.optional_int32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum 924 end 925 assert_raise RangeError do 926 m.optional_int32 = 1e12 927 end 928 assert_raise RangeError do 929 m.optional_int32 = 1.5 930 end 931 932 m.optional_uint32 = 0 933 m.optional_uint32 = +0xffff_ffff 934 m.optional_uint32 = 1.0 935 m.optional_uint32 = 4e9 936 assert_raise RangeError do 937 m.optional_uint32 = -1 938 end 939 assert_raise RangeError do 940 m.optional_uint32 = -1.5 941 end 942 assert_raise RangeError do 943 m.optional_uint32 = -1.5e12 944 end 945 assert_raise RangeError do 946 m.optional_uint32 = -0x1000_0000_0000_0000 947 end 948 assert_raise RangeError do 949 m.optional_uint32 = +0x1_0000_0000 950 end 951 assert_raise RangeError do 952 m.optional_uint32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum 953 end 954 assert_raise RangeError do 955 m.optional_uint32 = 1e12 956 end 957 assert_raise RangeError do 958 m.optional_uint32 = 1.5 959 end 960 961 m.optional_int64 = 0 962 m.optional_int64 = -0x8000_0000_0000_0000 963 m.optional_int64 = +0x7fff_ffff_ffff_ffff 964 m.optional_int64 = 1.0 965 m.optional_int64 = -1.0 966 m.optional_int64 = 8e18 967 m.optional_int64 = -8e18 968 assert_raise RangeError do 969 m.optional_int64 = -0x8000_0000_0000_0001 970 end 971 assert_raise RangeError do 972 m.optional_int64 = +0x8000_0000_0000_0000 973 end 974 assert_raise RangeError do 975 m.optional_int64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum 976 end 977 assert_raise RangeError do 978 m.optional_int64 = 1e50 979 end 980 assert_raise RangeError do 981 m.optional_int64 = 1.5 982 end 983 984 m.optional_uint64 = 0 985 m.optional_uint64 = +0xffff_ffff_ffff_ffff 986 m.optional_uint64 = 1.0 987 m.optional_uint64 = 16e18 988 assert_raise RangeError do 989 m.optional_uint64 = -1 990 end 991 assert_raise RangeError do 992 m.optional_uint64 = -1.5 993 end 994 assert_raise RangeError do 995 m.optional_uint64 = -1.5e12 996 end 997 assert_raise RangeError do 998 m.optional_uint64 = -0x1_0000_0000_0000_0000 999 end 1000 assert_raise RangeError do 1001 m.optional_uint64 = +0x1_0000_0000_0000_0000 1002 end 1003 assert_raise RangeError do 1004 m.optional_uint64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum 1005 end 1006 assert_raise RangeError do 1007 m.optional_uint64 = 1e50 1008 end 1009 assert_raise RangeError do 1010 m.optional_uint64 = 1.5 1011 end 1012 end 1013 1014 def test_stress_test 1015 m = proto_module::TestMessage.new 1016 m.optional_int32 = 42 1017 m.optional_int64 = 0x100000000 1018 m.optional_string = "hello world" 1019 10.times do m.repeated_msg.push proto_module::TestMessage2.new(:foo => 42) end 1020 10.times do m.repeated_string.push "hello world" end 1021 1022 data = proto_module::TestMessage.encode(m) 1023 1024 10_000.times do 1025 m = proto_module::TestMessage.decode(data) 1026 data_new = proto_module::TestMessage.encode(m) 1027 assert data_new == data 1028 data = data_new 1029 end 1030 end 1031 1032 def test_reflection 1033 m = proto_module::TestMessage.new(:optional_int32 => 1234) 1034 msgdef = m.class.descriptor 1035 assert msgdef.class == Google::Protobuf::Descriptor 1036 assert msgdef.any? {|field| field.name == "optional_int32"} 1037 optional_int32 = msgdef.lookup "optional_int32" 1038 assert optional_int32.class == Google::Protobuf::FieldDescriptor 1039 assert optional_int32 != nil 1040 assert optional_int32.name == "optional_int32" 1041 assert optional_int32.type == :int32 1042 optional_int32.set(m, 5678) 1043 assert m.optional_int32 == 5678 1044 m.optional_int32 = 1000 1045 assert optional_int32.get(m) == 1000 1046 1047 optional_msg = msgdef.lookup "optional_msg" 1048 assert optional_msg.subtype == proto_module::TestMessage2.descriptor 1049 1050 optional_msg.set(m, optional_msg.subtype.msgclass.new) 1051 1052 assert msgdef.msgclass == proto_module::TestMessage 1053 1054 optional_enum = msgdef.lookup "optional_enum" 1055 assert optional_enum.subtype == proto_module::TestEnum.descriptor 1056 assert optional_enum.subtype.class == Google::Protobuf::EnumDescriptor 1057 optional_enum.subtype.each do |k, v| 1058 # set with integer, check resolution to symbolic name 1059 optional_enum.set(m, v) 1060 assert optional_enum.get(m) == k 1061 end 1062 end 1063 1064 def test_json 1065 # TODO: Fix JSON in JRuby version. 1066 return if RUBY_PLATFORM == "java" 1067 m = proto_module::TestMessage.new(:optional_int32 => 1234, 1068 :optional_int64 => -0x1_0000_0000, 1069 :optional_uint32 => 0x8000_0000, 1070 :optional_uint64 => 0xffff_ffff_ffff_ffff, 1071 :optional_bool => true, 1072 :optional_float => 1.0, 1073 :optional_double => -1e100, 1074 :optional_string => "Test string", 1075 :optional_bytes => ["FFFFFFFF"].pack('H*'), 1076 :optional_msg => proto_module::TestMessage2.new(:foo => 42), 1077 :repeated_int32 => [1, 2, 3, 4], 1078 :repeated_string => ["a", "b", "c"], 1079 :repeated_bool => [true, false, true, false], 1080 :repeated_msg => [proto_module::TestMessage2.new(:foo => 1), 1081 proto_module::TestMessage2.new(:foo => 2)]) 1082 1083 json_text = proto_module::TestMessage.encode_json(m) 1084 m2 = proto_module::TestMessage.decode_json(json_text) 1085 assert_equal m, m2 1086 1087 # Crash case from GitHub issue 283. 1088 bar = proto_module::Bar.new(msg: "bar") 1089 baz1 = proto_module::Baz.new(msg: "baz") 1090 baz2 = proto_module::Baz.new(msg: "quux") 1091 proto_module::Foo.encode_json(proto_module::Foo.new) 1092 proto_module::Foo.encode_json(proto_module::Foo.new(bar: bar)) 1093 proto_module::Foo.encode_json(proto_module::Foo.new(bar: bar, baz: [baz1, baz2])) 1094 end 1095 1096 def test_json_empty 1097 assert proto_module::TestMessage.encode_json(proto_module::TestMessage.new) == '{}' 1098 end 1099 1100 def test_json_emit_defaults 1101 # TODO: Fix JSON in JRuby version. 1102 return if RUBY_PLATFORM == "java" 1103 m = proto_module::TestMessage.new 1104 1105 expected = { 1106 optionalInt32: 0, 1107 optionalInt64: "0", 1108 optionalUint32: 0, 1109 optionalUint64: "0", 1110 optionalBool: false, 1111 optionalFloat: 0, 1112 optionalDouble: 0, 1113 optionalString: "", 1114 optionalBytes: "", 1115 optionalEnum: "Default", 1116 repeatedInt32: [], 1117 repeatedInt64: [], 1118 repeatedUint32: [], 1119 repeatedUint64: [], 1120 repeatedBool: [], 1121 repeatedFloat: [], 1122 repeatedDouble: [], 1123 repeatedString: [], 1124 repeatedBytes: [], 1125 repeatedMsg: [], 1126 repeatedEnum: [] 1127 } 1128 1129 actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true) 1130 1131 assert_equal expected, JSON.parse(actual, :symbolize_names => true) 1132 end 1133 1134 def test_json_emit_defaults_submsg 1135 # TODO: Fix JSON in JRuby version. 1136 return if RUBY_PLATFORM == "java" 1137 m = proto_module::TestMessage.new(optional_msg: proto_module::TestMessage2.new) 1138 1139 expected = { 1140 optionalInt32: 0, 1141 optionalInt64: "0", 1142 optionalUint32: 0, 1143 optionalUint64: "0", 1144 optionalBool: false, 1145 optionalFloat: 0, 1146 optionalDouble: 0, 1147 optionalString: "", 1148 optionalBytes: "", 1149 optionalMsg: {foo: 0}, 1150 optionalEnum: "Default", 1151 repeatedInt32: [], 1152 repeatedInt64: [], 1153 repeatedUint32: [], 1154 repeatedUint64: [], 1155 repeatedBool: [], 1156 repeatedFloat: [], 1157 repeatedDouble: [], 1158 repeatedString: [], 1159 repeatedBytes: [], 1160 repeatedMsg: [], 1161 repeatedEnum: [] 1162 } 1163 1164 actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true) 1165 1166 assert_equal expected, JSON.parse(actual, :symbolize_names => true) 1167 end 1168 1169 def test_json_emit_defaults_repeated_submsg 1170 # TODO: Fix JSON in JRuby version. 1171 return if RUBY_PLATFORM == "java" 1172 m = proto_module::TestMessage.new(repeated_msg: [proto_module::TestMessage2.new]) 1173 1174 expected = { 1175 optionalInt32: 0, 1176 optionalInt64: "0", 1177 optionalUint32: 0, 1178 optionalUint64: "0", 1179 optionalBool: false, 1180 optionalFloat: 0, 1181 optionalDouble: 0, 1182 optionalString: "", 1183 optionalBytes: "", 1184 optionalEnum: "Default", 1185 repeatedInt32: [], 1186 repeatedInt64: [], 1187 repeatedUint32: [], 1188 repeatedUint64: [], 1189 repeatedBool: [], 1190 repeatedFloat: [], 1191 repeatedDouble: [], 1192 repeatedString: [], 1193 repeatedBytes: [], 1194 repeatedMsg: [{foo: 0}], 1195 repeatedEnum: [] 1196 } 1197 1198 actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true) 1199 1200 assert_equal expected, JSON.parse(actual, :symbolize_names => true) 1201 end 1202 1203 def value_from_ruby(value) 1204 ret = Google::Protobuf::Value.new 1205 case value 1206 when String 1207 ret.string_value = value 1208 when Google::Protobuf::Struct 1209 ret.struct_value = value 1210 when Hash 1211 ret.struct_value = struct_from_ruby(value) 1212 when Google::Protobuf::ListValue 1213 ret.list_value = value 1214 when Array 1215 ret.list_value = list_from_ruby(value) 1216 else 1217 @log.error "Unknown type: #{value.class}" 1218 raise Google::Protobuf::Error, "Unknown type: #{value.class}" 1219 end 1220 ret 1221 end 1222 1223 def list_from_ruby(arr) 1224 ret = Google::Protobuf::ListValue.new 1225 arr.each do |v| 1226 ret.values << value_from_ruby(v) 1227 end 1228 ret 1229 end 1230 1231 def struct_from_ruby(hash) 1232 ret = Google::Protobuf::Struct.new 1233 hash.each do |k, v| 1234 ret.fields[k] ||= value_from_ruby(v) 1235 end 1236 ret 1237 end 1238 1239 def test_deep_json 1240 # will not overflow 1241 json = '{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":'\ 1242 '{"a":{"a":{"a":{"a":{}}}}}}}}}}}}}}}}' 1243 1244 struct = struct_from_ruby(JSON.parse(json)) 1245 assert_equal json, struct.to_json 1246 1247 encoded = proto_module::MyRepeatedStruct.encode( 1248 proto_module::MyRepeatedStruct.new(structs: [proto_module::MyStruct.new(struct: struct)])) 1249 assert_equal json, proto_module::MyRepeatedStruct.decode(encoded).structs[0].struct.to_json 1250 1251 # will overflow 1252 json = '{"a":{"a":{"a":[{"a":{"a":[{"a":[{"a":{"a":[{"a":[{"a":'\ 1253 '{"a":[{"a":[{"a":{"a":{"a":[{"a":"a"}]}}}]}]}}]}]}}]}]}}]}}}' 1254 1255 struct = struct_from_ruby(JSON.parse(json)) 1256 assert_equal json, struct.to_json 1257 1258 assert_raise(RuntimeError, "Maximum recursion depth exceeded during encoding") do 1259 proto_module::MyRepeatedStruct.encode( 1260 proto_module::MyRepeatedStruct.new(structs: [proto_module::MyStruct.new(struct: struct)])) 1261 end 1262 end 1263 1264 def test_comparison_with_arbitrary_object 1265 assert proto_module::TestMessage.new != nil 1266 end 1267 1268 def test_wrappers_set_to_default 1269 run_asserts = ->(m) { 1270 assert_equal 0.0, m.double.value 1271 assert_equal 0.0, m.float.value 1272 assert_equal 0, m.int32.value 1273 assert_equal 0, m.int64.value 1274 assert_equal 0, m.uint32.value 1275 assert_equal 0, m.uint64.value 1276 assert_equal false, m.bool.value 1277 assert_equal '', m.string.value 1278 assert_equal '', m.bytes.value 1279 } 1280 1281 m = proto_module::Wrapper.new( 1282 double: Google::Protobuf::DoubleValue.new(value: 0.0), 1283 float: Google::Protobuf::FloatValue.new(value: 0.0), 1284 int32: Google::Protobuf::Int32Value.new(value: 0), 1285 int64: Google::Protobuf::Int64Value.new(value: 0), 1286 uint32: Google::Protobuf::UInt32Value.new(value: 0), 1287 uint64: Google::Protobuf::UInt64Value.new(value: 0), 1288 bool: Google::Protobuf::BoolValue.new(value: false), 1289 string: Google::Protobuf::StringValue.new(value: ""), 1290 bytes: Google::Protobuf::BytesValue.new(value: ''), 1291 ) 1292 1293 run_asserts.call(m) 1294 m2 = proto_module::Wrapper.decode(m.to_proto) 1295 run_asserts.call(m2) 1296 m3 = proto_module::Wrapper.decode_json(m.to_json) 1297 end 1298 1299 def test_wrapper_getters 1300 run_asserts = ->(m) { 1301 assert_equal 2.0, m.double_as_value 1302 assert_equal 2.0, m.double.value 1303 assert_equal 2.0, m.double_as_value 1304 1305 assert_equal 4.0, m.float_as_value 1306 assert_equal 4.0, m.float.value 1307 assert_equal 4.0, m.float_as_value 1308 1309 assert_equal 3, m.int32_as_value 1310 assert_equal 3, m.int32.value 1311 assert_equal 3, m.int32_as_value 1312 1313 assert_equal 4, m.int64_as_value 1314 assert_equal 4, m.int64.value 1315 assert_equal 4, m.int64_as_value 1316 1317 assert_equal 5, m.uint32_as_value 1318 assert_equal 5, m.uint32.value 1319 assert_equal 5, m.uint32_as_value 1320 1321 assert_equal 6, m.uint64_as_value 1322 assert_equal 6, m.uint64.value 1323 assert_equal 6, m.uint64_as_value 1324 1325 assert_equal true, m.bool_as_value 1326 assert_equal true, m.bool.value 1327 assert_equal true, m.bool_as_value 1328 1329 assert_equal "st\nr", m.string_as_value 1330 assert_equal "st\nr", m.string.value 1331 assert_equal "st\nr", m.string_as_value 1332 1333 assert_equal 'fun', m.bytes_as_value 1334 assert_equal 'fun', m.bytes.value 1335 assert_equal 'fun', m.bytes_as_value 1336 } 1337 1338 m = proto_module::Wrapper.new( 1339 double: Google::Protobuf::DoubleValue.new(value: 2.0), 1340 float: Google::Protobuf::FloatValue.new(value: 4.0), 1341 int32: Google::Protobuf::Int32Value.new(value: 3), 1342 int64: Google::Protobuf::Int64Value.new(value: 4), 1343 uint32: Google::Protobuf::UInt32Value.new(value: 5), 1344 uint64: Google::Protobuf::UInt64Value.new(value: 6), 1345 bool: Google::Protobuf::BoolValue.new(value: true), 1346 string: Google::Protobuf::StringValue.new(value: "st\nr"), 1347 bytes: Google::Protobuf::BytesValue.new(value: 'fun'), 1348 real_string: '100' 1349 ) 1350 1351 run_asserts.call(m) 1352 serialized = proto_module::Wrapper::encode(m) 1353 m2 = proto_module::Wrapper::decode(serialized) 1354 run_asserts.call(m2) 1355 1356 # Test the case where we are serializing directly from the parsed form 1357 # (before anything lazy is materialized). 1358 m3 = proto_module::Wrapper::decode(serialized) 1359 serialized2 = proto_module::Wrapper::encode(m3) 1360 m4 = proto_module::Wrapper::decode(serialized2) 1361 run_asserts.call(m4) 1362 1363 # Test that the lazy form compares equal to the expanded form. 1364 m5 = proto_module::Wrapper::decode(serialized2) 1365 assert_equal m5, m 1366 1367 serialized_json = proto_module::Wrapper::encode_json(m) 1368 m6 = proto_module::Wrapper::decode_json(serialized_json) 1369 assert_equal m6, m 1370 end 1371 1372 def test_repeated_wrappers 1373 run_asserts = ->(m) { 1374 assert_equal 2.0, m.repeated_double[0].value 1375 assert_equal 4.0, m.repeated_float[0].value 1376 assert_equal 3, m.repeated_int32[0].value 1377 assert_equal 4, m.repeated_int64[0].value 1378 assert_equal 5, m.repeated_uint32[0].value 1379 assert_equal 6, m.repeated_uint64[0].value 1380 assert_equal true, m.repeated_bool[0].value 1381 assert_equal 'str', m.repeated_string[0].value 1382 assert_equal 'fun', m.repeated_bytes[0].value 1383 } 1384 1385 m = proto_module::Wrapper.new( 1386 repeated_double: [Google::Protobuf::DoubleValue.new(value: 2.0)], 1387 repeated_float: [Google::Protobuf::FloatValue.new(value: 4.0)], 1388 repeated_int32: [Google::Protobuf::Int32Value.new(value: 3)], 1389 repeated_int64: [Google::Protobuf::Int64Value.new(value: 4)], 1390 repeated_uint32: [Google::Protobuf::UInt32Value.new(value: 5)], 1391 repeated_uint64: [Google::Protobuf::UInt64Value.new(value: 6)], 1392 repeated_bool: [Google::Protobuf::BoolValue.new(value: true)], 1393 repeated_string: [Google::Protobuf::StringValue.new(value: 'str')], 1394 repeated_bytes: [Google::Protobuf::BytesValue.new(value: 'fun')], 1395 ) 1396 1397 run_asserts.call(m) 1398 serialized = proto_module::Wrapper::encode(m) 1399 m2 = proto_module::Wrapper::decode(serialized) 1400 run_asserts.call(m2) 1401 1402 # Test the case where we are serializing directly from the parsed form 1403 # (before anything lazy is materialized). 1404 m3 = proto_module::Wrapper::decode(serialized) 1405 serialized2 = proto_module::Wrapper::encode(m3) 1406 m4 = proto_module::Wrapper::decode(serialized2) 1407 run_asserts.call(m4) 1408 1409 # Test that the lazy form compares equal to the expanded form. 1410 m5 = proto_module::Wrapper::decode(serialized2) 1411 assert_equal m5, m 1412 1413 # Test JSON. 1414 serialized_json = proto_module::Wrapper::encode_json(m5) 1415 m6 = proto_module::Wrapper::decode_json(serialized_json) 1416 run_asserts.call(m6) 1417 assert_equal m6, m 1418 end 1419 1420 def test_oneof_wrappers 1421 run_test = ->(m) { 1422 serialized = proto_module::Wrapper::encode(m) 1423 m2 = proto_module::Wrapper::decode(serialized) 1424 1425 # Encode directly from lazy form. 1426 serialized2 = proto_module::Wrapper::encode(m2) 1427 1428 assert_equal m, m2 1429 assert_equal serialized, serialized2 1430 1431 serialized_json = proto_module::Wrapper::encode_json(m) 1432 m3 = proto_module::Wrapper::decode_json(serialized_json) 1433 assert_equal m, m3 1434 } 1435 1436 m = proto_module::Wrapper.new() 1437 1438 run_test.call(m) 1439 m.oneof_double_as_value = 2.0 1440 run_test.call(m) 1441 m.oneof_float_as_value = 4.0 1442 run_test.call(m) 1443 m.oneof_int32_as_value = 3 1444 run_test.call(m) 1445 m.oneof_int64_as_value = 5 1446 run_test.call(m) 1447 m.oneof_uint32_as_value = 6 1448 run_test.call(m) 1449 m.oneof_uint64_as_value = 7 1450 run_test.call(m) 1451 m.oneof_string_as_value = 'str' 1452 run_test.call(m) 1453 m.oneof_bytes_as_value = 'fun' 1454 run_test.call(m) 1455 end 1456 1457 def test_top_level_wrappers 1458 # We don't expect anyone to do this, but we should also make sure it does 1459 # the right thing. 1460 run_test = ->(klass, val) { 1461 m = klass.new(value: val) 1462 serialized = klass::encode(m) 1463 m2 = klass::decode(serialized) 1464 1465 # Encode directly from lazy form. 1466 serialized2 = klass::encode(m2) 1467 1468 assert_equal m, m2 1469 assert_equal serialized, serialized2 1470 1471 serialized_json = klass::encode_json(m) 1472 1473 # This is nonsensical to do and does not work. There is no good reason 1474 # to parse a wrapper type directly. 1475 assert_raise(RuntimeError) { klass::decode_json(serialized_json) } 1476 } 1477 1478 run_test.call(Google::Protobuf::DoubleValue, 2.0) 1479 run_test.call(Google::Protobuf::FloatValue, 4.0) 1480 run_test.call(Google::Protobuf::Int32Value, 3) 1481 run_test.call(Google::Protobuf::Int64Value, 4) 1482 run_test.call(Google::Protobuf::UInt32Value, 5) 1483 run_test.call(Google::Protobuf::UInt64Value, 6) 1484 run_test.call(Google::Protobuf::BoolValue, true) 1485 run_test.call(Google::Protobuf::StringValue, 'str') 1486 run_test.call(Google::Protobuf::BytesValue, 'fun') 1487 end 1488 1489 def test_wrapper_setters_as_value 1490 run_asserts = ->(m) { 1491 m.double_as_value = 4.8 1492 assert_equal 4.8, m.double_as_value 1493 assert_equal Google::Protobuf::DoubleValue.new(value: 4.8), m.double 1494 m.float_as_value = 2.4 1495 assert_in_delta 2.4, m.float_as_value 1496 assert_in_delta Google::Protobuf::FloatValue.new(value: 2.4).value, m.float.value 1497 m.int32_as_value = 5 1498 assert_equal 5, m.int32_as_value 1499 assert_equal Google::Protobuf::Int32Value.new(value: 5), m.int32 1500 m.int64_as_value = 15 1501 assert_equal 15, m.int64_as_value 1502 assert_equal Google::Protobuf::Int64Value.new(value: 15), m.int64 1503 m.uint32_as_value = 50 1504 assert_equal 50, m.uint32_as_value 1505 assert_equal Google::Protobuf::UInt32Value.new(value: 50), m.uint32 1506 m.uint64_as_value = 500 1507 assert_equal 500, m.uint64_as_value 1508 assert_equal Google::Protobuf::UInt64Value.new(value: 500), m.uint64 1509 m.bool_as_value = false 1510 assert_equal false, m.bool_as_value 1511 assert_equal Google::Protobuf::BoolValue.new(value: false), m.bool 1512 m.string_as_value = 'xy' 1513 assert_equal 'xy', m.string_as_value 1514 assert_equal Google::Protobuf::StringValue.new(value: 'xy'), m.string 1515 m.bytes_as_value = '123' 1516 assert_equal '123', m.bytes_as_value 1517 assert_equal Google::Protobuf::BytesValue.new(value: '123'), m.bytes 1518 1519 m.double_as_value = nil 1520 assert_nil m.double 1521 assert_nil m.double_as_value 1522 m.float_as_value = nil 1523 assert_nil m.float 1524 assert_nil m.float_as_value 1525 m.int32_as_value = nil 1526 assert_nil m.int32 1527 assert_nil m.int32_as_value 1528 m.int64_as_value = nil 1529 assert_nil m.int64 1530 assert_nil m.int64_as_value 1531 m.uint32_as_value = nil 1532 assert_nil m.uint32 1533 assert_nil m.uint32_as_value 1534 m.uint64_as_value = nil 1535 assert_nil m.uint64 1536 assert_nil m.uint64_as_value 1537 m.bool_as_value = nil 1538 assert_nil m.bool 1539 assert_nil m.bool_as_value 1540 m.string_as_value = nil 1541 assert_nil m.string 1542 assert_nil m.string_as_value 1543 m.bytes_as_value = nil 1544 assert_nil m.bytes 1545 assert_nil m.bytes_as_value 1546 } 1547 1548 m = proto_module::Wrapper.new 1549 1550 m2 = proto_module::Wrapper.new( 1551 double: Google::Protobuf::DoubleValue.new(value: 2.0), 1552 float: Google::Protobuf::FloatValue.new(value: 4.0), 1553 int32: Google::Protobuf::Int32Value.new(value: 3), 1554 int64: Google::Protobuf::Int64Value.new(value: 4), 1555 uint32: Google::Protobuf::UInt32Value.new(value: 5), 1556 uint64: Google::Protobuf::UInt64Value.new(value: 6), 1557 bool: Google::Protobuf::BoolValue.new(value: true), 1558 string: Google::Protobuf::StringValue.new(value: 'str'), 1559 bytes: Google::Protobuf::BytesValue.new(value: 'fun'), 1560 real_string: '100' 1561 ) 1562 1563 run_asserts.call(m2) 1564 1565 serialized = proto_module::Wrapper::encode(m2) 1566 m3 = proto_module::Wrapper::decode(serialized) 1567 run_asserts.call(m3) 1568 end 1569 1570 def test_wrapper_setters 1571 run_asserts = ->(m) { 1572 m.double = Google::Protobuf::DoubleValue.new(value: 4.8) 1573 assert_equal 4.8, m.double_as_value 1574 assert_equal Google::Protobuf::DoubleValue.new(value: 4.8), m.double 1575 m.float = Google::Protobuf::FloatValue.new(value: 2.4) 1576 assert_in_delta 2.4, m.float_as_value 1577 assert_in_delta Google::Protobuf::FloatValue.new(value: 2.4).value, m.float.value 1578 m.int32 = Google::Protobuf::Int32Value.new(value: 5) 1579 assert_equal 5, m.int32_as_value 1580 assert_equal Google::Protobuf::Int32Value.new(value: 5), m.int32 1581 m.int64 = Google::Protobuf::Int64Value.new(value: 15) 1582 assert_equal 15, m.int64_as_value 1583 assert_equal Google::Protobuf::Int64Value.new(value: 15), m.int64 1584 m.uint32 = Google::Protobuf::UInt32Value.new(value: 50) 1585 assert_equal 50, m.uint32_as_value 1586 assert_equal Google::Protobuf::UInt32Value.new(value: 50), m.uint32 1587 m.uint64 = Google::Protobuf::UInt64Value.new(value: 500) 1588 assert_equal 500, m.uint64_as_value 1589 assert_equal Google::Protobuf::UInt64Value.new(value: 500), m.uint64 1590 m.bool = Google::Protobuf::BoolValue.new(value: false) 1591 assert_equal false, m.bool_as_value 1592 assert_equal Google::Protobuf::BoolValue.new(value: false), m.bool 1593 m.string = Google::Protobuf::StringValue.new(value: 'xy') 1594 assert_equal 'xy', m.string_as_value 1595 assert_equal Google::Protobuf::StringValue.new(value: 'xy'), m.string 1596 m.bytes = Google::Protobuf::BytesValue.new(value: '123') 1597 assert_equal '123', m.bytes_as_value 1598 assert_equal Google::Protobuf::BytesValue.new(value: '123'), m.bytes 1599 1600 m.double = nil 1601 assert_nil m.double 1602 assert_nil m.double_as_value 1603 m.float = nil 1604 assert_nil m.float 1605 assert_nil m.float_as_value 1606 m.int32 = nil 1607 assert_nil m.int32 1608 assert_nil m.int32_as_value 1609 m.int64 = nil 1610 assert_nil m.int64 1611 assert_nil m.int64_as_value 1612 m.uint32 = nil 1613 assert_nil m.uint32 1614 assert_nil m.uint32_as_value 1615 m.uint64 = nil 1616 assert_nil m.uint64 1617 assert_nil m.uint64_as_value 1618 m.bool = nil 1619 assert_nil m.bool 1620 assert_nil m.bool_as_value 1621 m.string = nil 1622 assert_nil m.string 1623 assert_nil m.string_as_value 1624 m.bytes = nil 1625 assert_nil m.bytes 1626 assert_nil m.bytes_as_value 1627 } 1628 1629 m = proto_module::Wrapper.new 1630 run_asserts.call(m) 1631 1632 m2 = proto_module::Wrapper.new( 1633 double: Google::Protobuf::DoubleValue.new(value: 2.0), 1634 float: Google::Protobuf::FloatValue.new(value: 4.0), 1635 int32: Google::Protobuf::Int32Value.new(value: 3), 1636 int64: Google::Protobuf::Int64Value.new(value: 4), 1637 uint32: Google::Protobuf::UInt32Value.new(value: 5), 1638 uint64: Google::Protobuf::UInt64Value.new(value: 6), 1639 bool: Google::Protobuf::BoolValue.new(value: true), 1640 string: Google::Protobuf::StringValue.new(value: 'str'), 1641 bytes: Google::Protobuf::BytesValue.new(value: 'fun'), 1642 real_string: '100' 1643 ) 1644 1645 run_asserts.call(m2) 1646 1647 serialized = proto_module::Wrapper::encode(m2) 1648 m3 = proto_module::Wrapper::decode(serialized) 1649 run_asserts.call(m3) 1650 end 1651 1652 def test_wrappers_only 1653 m = proto_module::Wrapper.new(real_string: 'hi', string_in_oneof: 'there') 1654 1655 assert_raise(NoMethodError) { m.real_string_as_value } 1656 assert_raise(NoMethodError) { m.as_value } 1657 assert_raise(NoMethodError) { m._as_value } 1658 assert_raise(NoMethodError) { m.string_in_oneof_as_value } 1659 1660 m = proto_module::Wrapper.new 1661 m.string_as_value = 'you' 1662 assert_equal 'you', m.string.value 1663 assert_equal 'you', m.string_as_value 1664 assert_raise(NoMethodError) { m.string_ } 1665 assert_raise(NoMethodError) { m.string_X } 1666 assert_raise(NoMethodError) { m.string_XX } 1667 assert_raise(NoMethodError) { m.string_XXX } 1668 assert_raise(NoMethodError) { m.string_XXXX } 1669 assert_raise(NoMethodError) { m.string_XXXXX } 1670 assert_raise(NoMethodError) { m.string_XXXXXX } 1671 assert_raise(NoMethodError) { m.string_XXXXXXX } 1672 assert_raise(NoMethodError) { m.string_XXXXXXXX } 1673 assert_raise(NoMethodError) { m.string_XXXXXXXXX } 1674 assert_raise(NoMethodError) { m.string_XXXXXXXXXX } 1675 end 1676 1677 def test_converts_time 1678 m = proto_module::TimeMessage.new 1679 1680 m.timestamp = Google::Protobuf::Timestamp.new(seconds: 5, nanos: 6) 1681 assert_kind_of Google::Protobuf::Timestamp, m.timestamp 1682 assert_equal 5, m.timestamp.seconds 1683 assert_equal 6, m.timestamp.nanos 1684 1685 m.timestamp = Time.at(9466, 123456.789) 1686 assert_equal Google::Protobuf::Timestamp.new(seconds: 9466, nanos: 123456789), m.timestamp 1687 1688 m = proto_module::TimeMessage.new(timestamp: Time.at(1)) 1689 assert_equal Google::Protobuf::Timestamp.new(seconds: 1, nanos: 0), m.timestamp 1690 1691 assert_raise(Google::Protobuf::TypeError) { m.timestamp = 2 } 1692 assert_raise(Google::Protobuf::TypeError) { m.timestamp = 2.4 } 1693 assert_raise(Google::Protobuf::TypeError) { m.timestamp = '4' } 1694 assert_raise(Google::Protobuf::TypeError) { m.timestamp = proto_module::TimeMessage.new } 1695 1696 def test_time(year, month, day) 1697 str = ("\"%04d-%02d-%02dT00:00:00.000+00:00\"" % [year, month, day]) 1698 t = Google::Protobuf::Timestamp.decode_json(str) 1699 time = Time.new(year, month, day, 0, 0, 0, "+00:00") 1700 assert_equal t.seconds, time.to_i 1701 end 1702 1703 (1970..2010).each do |year| 1704 test_time(year, 2, 28) 1705 test_time(year, 3, 01) 1706 end 1707 end 1708 1709 def test_converts_duration 1710 m = proto_module::TimeMessage.new 1711 1712 m.duration = Google::Protobuf::Duration.new(seconds: 2, nanos: 22) 1713 assert_kind_of Google::Protobuf::Duration, m.duration 1714 assert_equal 2, m.duration.seconds 1715 assert_equal 22, m.duration.nanos 1716 1717 m.duration = 10.5 1718 assert_equal Google::Protobuf::Duration.new(seconds: 10, nanos: 500_000_000), m.duration 1719 1720 m.duration = 200 1721 assert_equal Google::Protobuf::Duration.new(seconds: 200, nanos: 0), m.duration 1722 1723 m.duration = Rational(3, 2) 1724 assert_equal Google::Protobuf::Duration.new(seconds: 1, nanos: 500_000_000), m.duration 1725 1726 m.duration = BigDecimal("5") 1727 assert_equal Google::Protobuf::Duration.new(seconds: 5, nanos: 0), m.duration 1728 1729 m = proto_module::TimeMessage.new(duration: 1.1) 1730 assert_equal Google::Protobuf::Duration.new(seconds: 1, nanos: 100_000_000), m.duration 1731 1732 assert_raise(Google::Protobuf::TypeError) { m.duration = '2' } 1733 assert_raise(Google::Protobuf::TypeError) { m.duration = proto_module::TimeMessage.new } 1734 end 1735 1736 def test_freeze 1737 m = proto_module::TestMessage.new 1738 m.optional_int32 = 10 1739 m.freeze 1740 1741 frozen_error = assert_raise(FrozenErrorType) { m.optional_int32 = 20 } 1742 assert_match "can't modify frozen #{proto_module}::TestMessage", frozen_error.message 1743 assert_equal 10, m.optional_int32 1744 assert_equal true, m.frozen? 1745 1746 assert_raise(FrozenErrorType) { m.optional_int64 = 2 } 1747 assert_raise(FrozenErrorType) { m.optional_uint32 = 3 } 1748 assert_raise(FrozenErrorType) { m.optional_uint64 = 4 } 1749 assert_raise(FrozenErrorType) { m.optional_bool = true } 1750 assert_raise(FrozenErrorType) { m.optional_float = 6.0 } 1751 assert_raise(FrozenErrorType) { m.optional_double = 7.0 } 1752 assert_raise(FrozenErrorType) { m.optional_string = '8' } 1753 assert_raise(FrozenErrorType) { m.optional_bytes = nil } 1754 assert_raise(FrozenErrorType) { m.optional_msg = proto_module::TestMessage2.new } 1755 assert_raise(FrozenErrorType) { m.optional_enum = :A } 1756 assert_raise(FrozenErrorType) { m.repeated_int32 = 1 } 1757 assert_raise(FrozenErrorType) { m.repeated_int64 = 2 } 1758 assert_raise(FrozenErrorType) { m.repeated_uint32 = 3 } 1759 assert_raise(FrozenErrorType) { m.repeated_uint64 = 4 } 1760 assert_raise(FrozenErrorType) { m.repeated_bool = true } 1761 assert_raise(FrozenErrorType) { m.repeated_float = 6.0 } 1762 assert_raise(FrozenErrorType) { m.repeated_double = 7.0 } 1763 assert_raise(FrozenErrorType) { m.repeated_string = '8' } 1764 assert_raise(FrozenErrorType) { m.repeated_bytes = nil } 1765 assert_raise(FrozenErrorType) { m.repeated_msg = proto_module::TestMessage2.new } 1766 assert_raise(FrozenErrorType) { m.repeated_enum = :A } 1767 end 1768 1769 def test_eq 1770 m1 = proto_module::TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2']) 1771 m2 = proto_module::TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2']) 1772 1773 h = {} 1774 h[m1] = :yes 1775 1776 assert m1 == m2 1777 assert m1.eql?(m2) 1778 assert m1.hash == m2.hash 1779 assert h[m1] == :yes 1780 assert h[m2] == :yes 1781 1782 m1.optional_int32 = 2 1783 1784 assert m1 != m2 1785 assert !m1.eql?(m2) 1786 assert m1.hash != m2.hash 1787 assert_nil h[m2] 1788 end 1789end 1790