google-protobuf 3.21.0.rc.2-x64-mingw-ucrt

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of google-protobuf might be problematic. Click here for more details.

Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/ext/google/protobuf_c/convert.c +361 -0
  3. data/ext/google/protobuf_c/convert.h +75 -0
  4. data/ext/google/protobuf_c/defs.c +1280 -0
  5. data/ext/google/protobuf_c/defs.h +107 -0
  6. data/ext/google/protobuf_c/extconf.rb +28 -0
  7. data/ext/google/protobuf_c/map.c +702 -0
  8. data/ext/google/protobuf_c/map.h +66 -0
  9. data/ext/google/protobuf_c/message.c +1402 -0
  10. data/ext/google/protobuf_c/message.h +104 -0
  11. data/ext/google/protobuf_c/protobuf.c +480 -0
  12. data/ext/google/protobuf_c/protobuf.h +120 -0
  13. data/ext/google/protobuf_c/repeated_field.c +657 -0
  14. data/ext/google/protobuf_c/repeated_field.h +63 -0
  15. data/ext/google/protobuf_c/ruby-upb.c +11115 -0
  16. data/ext/google/protobuf_c/ruby-upb.h +5612 -0
  17. data/ext/google/protobuf_c/third_party/utf8_range/LICENSE +21 -0
  18. data/ext/google/protobuf_c/third_party/utf8_range/naive.c +92 -0
  19. data/ext/google/protobuf_c/third_party/utf8_range/range2-neon.c +157 -0
  20. data/ext/google/protobuf_c/third_party/utf8_range/range2-sse.c +170 -0
  21. data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.h +9 -0
  22. data/ext/google/protobuf_c/wrap_memcpy.c +52 -0
  23. data/lib/google/3.1/protobuf_c.so +0 -0
  24. data/lib/google/protobuf/any_pb.rb +19 -0
  25. data/lib/google/protobuf/api_pb.rb +42 -0
  26. data/lib/google/protobuf/descriptor_dsl.rb +465 -0
  27. data/lib/google/protobuf/descriptor_pb.rb +269 -0
  28. data/lib/google/protobuf/duration_pb.rb +19 -0
  29. data/lib/google/protobuf/empty_pb.rb +17 -0
  30. data/lib/google/protobuf/field_mask_pb.rb +18 -0
  31. data/lib/google/protobuf/message_exts.rb +53 -0
  32. data/lib/google/protobuf/repeated_field.rb +201 -0
  33. data/lib/google/protobuf/source_context_pb.rb +18 -0
  34. data/lib/google/protobuf/struct_pb.rb +37 -0
  35. data/lib/google/protobuf/timestamp_pb.rb +19 -0
  36. data/lib/google/protobuf/type_pb.rb +92 -0
  37. data/lib/google/protobuf/well_known_types.rb +240 -0
  38. data/lib/google/protobuf/wrappers_pb.rb +50 -0
  39. data/lib/google/protobuf.rb +79 -0
  40. data/tests/basic.rb +739 -0
  41. data/tests/generated_code_test.rb +23 -0
  42. data/tests/stress.rb +38 -0
  43. metadata +138 -0
data/tests/basic.rb ADDED
@@ -0,0 +1,739 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # basic_test_pb.rb is in the same directory as this test.
4
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
5
+
6
+ require 'basic_test_pb'
7
+ require 'common_tests'
8
+ require 'google/protobuf'
9
+ require 'json'
10
+ require 'test/unit'
11
+
12
+ # ------------- generated code --------------
13
+
14
+ module BasicTest
15
+ pool = Google::Protobuf::DescriptorPool.new
16
+ pool.build do
17
+ add_message "BadFieldNames" do
18
+ optional :dup, :int32, 1
19
+ optional :class, :int32, 2
20
+ end
21
+ end
22
+
23
+ BadFieldNames = pool.lookup("BadFieldNames").msgclass
24
+
25
+ # ------------ test cases ---------------
26
+
27
+ class MessageContainerTest < Test::Unit::TestCase
28
+ # Required by CommonTests module to resolve proto3 proto classes used in tests.
29
+ def proto_module
30
+ ::BasicTest
31
+ end
32
+ include CommonTests
33
+
34
+ def test_issue_8311_crash
35
+ Google::Protobuf::DescriptorPool.generated_pool.build do
36
+ add_file("inner.proto", :syntax => :proto3) do
37
+ add_message "Inner" do
38
+ # Removing either of these fixes the segfault.
39
+ optional :foo, :string, 1
40
+ optional :bar, :string, 2
41
+ end
42
+ end
43
+ end
44
+
45
+ Google::Protobuf::DescriptorPool.generated_pool.build do
46
+ add_file("outer.proto", :syntax => :proto3) do
47
+ add_message "Outer" do
48
+ repeated :inners, :message, 1, "Inner"
49
+ end
50
+ end
51
+ end
52
+
53
+ outer = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("Outer").msgclass
54
+
55
+ outer.new(
56
+ inners: []
57
+ )['inners'].to_s
58
+
59
+ assert_raise Google::Protobuf::TypeError do
60
+ outer.new(
61
+ inners: [nil]
62
+ ).to_s
63
+ end
64
+ end
65
+
66
+ def test_issue_8559_crash
67
+ msg = TestMessage.new
68
+ msg.repeated_int32 = ::Google::Protobuf::RepeatedField.new(:int32, [1, 2, 3])
69
+
70
+ # https://github.com/jruby/jruby/issues/6818 was fixed in JRuby 9.3.0.0
71
+ if cruby_or_jruby_9_3_or_higher?
72
+ GC.start(full_mark: true, immediate_sweep: true)
73
+ end
74
+ TestMessage.encode(msg)
75
+ end
76
+
77
+ def test_issue_9440
78
+ msg = HelloRequest.new
79
+ msg.id = 8
80
+ assert_equal 8, msg.id
81
+ msg.version = '1'
82
+ assert_equal 8, msg.id
83
+ end
84
+
85
+ def test_issue_9507
86
+ pool = Google::Protobuf::DescriptorPool.new
87
+ pool.build do
88
+ add_message "NpeMessage" do
89
+ optional :type, :enum, 1, "TestEnum"
90
+ optional :other, :string, 2
91
+ end
92
+ add_enum "TestEnum" do
93
+ value :Something, 0
94
+ end
95
+ end
96
+
97
+ msgclass = pool.lookup("NpeMessage").msgclass
98
+
99
+ m = msgclass.new(
100
+ other: "foo" # must be set, but can be blank
101
+ )
102
+
103
+ begin
104
+ encoded = msgclass.encode(m)
105
+ rescue java.lang.NullPointerException
106
+ flunk "NPE rescued"
107
+ end
108
+ decoded = msgclass.decode(encoded)
109
+ decoded.inspect
110
+ decoded.to_proto
111
+ end
112
+
113
+ def test_has_field
114
+ m = TestSingularFields.new
115
+ assert !m.has_singular_msg?
116
+ m.singular_msg = TestMessage2.new
117
+ assert m.has_singular_msg?
118
+ assert TestSingularFields.descriptor.lookup('singular_msg').has?(m)
119
+
120
+ m = OneofMessage.new
121
+ assert !m.has_my_oneof?
122
+ m.a = "foo"
123
+ assert m.has_my_oneof?
124
+ assert_raise NoMethodError do
125
+ m.has_a?
126
+ end
127
+ assert_true OneofMessage.descriptor.lookup('a').has?(m)
128
+
129
+ m = TestSingularFields.new
130
+ assert_raise NoMethodError do
131
+ m.has_singular_int32?
132
+ end
133
+ assert_raise ArgumentError do
134
+ TestSingularFields.descriptor.lookup('singular_int32').has?(m)
135
+ end
136
+
137
+ assert_raise NoMethodError do
138
+ m.has_singular_string?
139
+ end
140
+ assert_raise ArgumentError do
141
+ TestSingularFields.descriptor.lookup('singular_string').has?(m)
142
+ end
143
+
144
+ assert_raise NoMethodError do
145
+ m.has_singular_bool?
146
+ end
147
+ assert_raise ArgumentError do
148
+ TestSingularFields.descriptor.lookup('singular_bool').has?(m)
149
+ end
150
+
151
+ m = TestMessage.new
152
+ assert_raise NoMethodError do
153
+ m.has_repeated_msg?
154
+ end
155
+ assert_raise ArgumentError do
156
+ TestMessage.descriptor.lookup('repeated_msg').has?(m)
157
+ end
158
+ end
159
+
160
+ def test_no_presence
161
+ m = TestSingularFields.new
162
+
163
+ # Explicitly setting to zero does not cause anything to be serialized.
164
+ m.singular_int32 = 0
165
+ assert_equal "", TestSingularFields.encode(m)
166
+
167
+ # Explicitly setting to a non-zero value *does* cause serialization.
168
+ m.singular_int32 = 1
169
+ assert_not_equal "", TestSingularFields.encode(m)
170
+
171
+ m.singular_int32 = 0
172
+ assert_equal "", TestSingularFields.encode(m)
173
+ end
174
+
175
+ def test_set_clear_defaults
176
+ m = TestSingularFields.new
177
+
178
+ m.singular_int32 = -42
179
+ assert_equal( -42, m.singular_int32 )
180
+ m.clear_singular_int32
181
+ assert_equal 0, m.singular_int32
182
+
183
+ m.singular_int32 = 50
184
+ assert_equal 50, m.singular_int32
185
+ TestSingularFields.descriptor.lookup('singular_int32').clear(m)
186
+ assert_equal 0, m.singular_int32
187
+
188
+ m.singular_string = "foo bar"
189
+ assert_equal "foo bar", m.singular_string
190
+ m.clear_singular_string
191
+ assert_equal "", m.singular_string
192
+
193
+ m.singular_string = "foo"
194
+ assert_equal "foo", m.singular_string
195
+ TestSingularFields.descriptor.lookup('singular_string').clear(m)
196
+ assert_equal "", m.singular_string
197
+
198
+ m.singular_msg = TestMessage2.new(:foo => 42)
199
+ assert_equal TestMessage2.new(:foo => 42), m.singular_msg
200
+ assert m.has_singular_msg?
201
+ m.clear_singular_msg
202
+ assert_equal nil, m.singular_msg
203
+ assert !m.has_singular_msg?
204
+
205
+ m.singular_msg = TestMessage2.new(:foo => 42)
206
+ assert_equal TestMessage2.new(:foo => 42), m.singular_msg
207
+ TestSingularFields.descriptor.lookup('singular_msg').clear(m)
208
+ assert_equal nil, m.singular_msg
209
+ end
210
+
211
+ def test_import_proto2
212
+ m = TestMessage.new
213
+ assert !m.has_optional_proto2_submessage?
214
+ m.optional_proto2_submessage = ::FooBar::Proto2::TestImportedMessage.new
215
+ assert m.has_optional_proto2_submessage?
216
+ assert TestMessage.descriptor.lookup('optional_proto2_submessage').has?(m)
217
+
218
+ m.clear_optional_proto2_submessage
219
+ assert !m.has_optional_proto2_submessage?
220
+ end
221
+
222
+ def test_clear_repeated_fields
223
+ m = TestMessage.new
224
+
225
+ m.repeated_int32.push(1)
226
+ assert_equal [1], m.repeated_int32
227
+ m.clear_repeated_int32
228
+ assert_equal [], m.repeated_int32
229
+
230
+ m.repeated_int32.push(1)
231
+ assert_equal [1], m.repeated_int32
232
+ TestMessage.descriptor.lookup('repeated_int32').clear(m)
233
+ assert_equal [], m.repeated_int32
234
+
235
+ m = OneofMessage.new
236
+ m.a = "foo"
237
+ assert_equal "foo", m.a
238
+ assert m.has_my_oneof?
239
+ assert_equal :a, m.my_oneof
240
+ m.clear_a
241
+ assert !m.has_my_oneof?
242
+
243
+ m.a = "foobar"
244
+ assert m.has_my_oneof?
245
+ m.clear_my_oneof
246
+ assert !m.has_my_oneof?
247
+
248
+ m.a = "bar"
249
+ assert_equal "bar", m.a
250
+ assert m.has_my_oneof?
251
+ OneofMessage.descriptor.lookup('a').clear(m)
252
+ assert !m.has_my_oneof?
253
+ end
254
+
255
+ def test_initialization_map_errors
256
+ e = assert_raise ArgumentError do
257
+ TestMessage.new(:hello => "world")
258
+ end
259
+ assert_match(/hello/, e.message)
260
+
261
+ e = assert_raise ArgumentError do
262
+ MapMessage.new(:map_string_int32 => "hello")
263
+ end
264
+ assert_equal e.message, "Expected Hash object as initializer value for map field 'map_string_int32' (given String)."
265
+
266
+ e = assert_raise ArgumentError do
267
+ TestMessage.new(:repeated_uint32 => "hello")
268
+ end
269
+ assert_equal e.message, "Expected array as initializer value for repeated field 'repeated_uint32' (given String)."
270
+ end
271
+
272
+ def test_map_field
273
+ m = MapMessage.new
274
+ assert m.map_string_int32 == {}
275
+ assert m.map_string_msg == {}
276
+
277
+ m = MapMessage.new(
278
+ :map_string_int32 => {"a" => 1, "b" => 2},
279
+ :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
280
+ "b" => TestMessage2.new(:foo => 2)},
281
+ :map_string_enum => {"a" => :A, "b" => :B})
282
+ assert m.map_string_int32.keys.sort == ["a", "b"]
283
+ assert m.map_string_int32["a"] == 1
284
+ assert m.map_string_msg["b"].foo == 2
285
+ assert m.map_string_enum["a"] == :A
286
+
287
+ m.map_string_int32["c"] = 3
288
+ assert m.map_string_int32["c"] == 3
289
+ m.map_string_msg["c"] = TestMessage2.new(:foo => 3)
290
+ assert m.map_string_msg["c"] == TestMessage2.new(:foo => 3)
291
+ m.map_string_msg.delete("b")
292
+ m.map_string_msg.delete("c")
293
+ assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) }
294
+
295
+ assert_raise Google::Protobuf::TypeError do
296
+ m.map_string_msg["e"] = TestMessage.new # wrong value type
297
+ end
298
+ # ensure nothing was added by the above
299
+ assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) }
300
+
301
+ m.map_string_int32 = Google::Protobuf::Map.new(:string, :int32)
302
+ assert_raise Google::Protobuf::TypeError do
303
+ m.map_string_int32 = Google::Protobuf::Map.new(:string, :int64)
304
+ end
305
+ assert_raise Google::Protobuf::TypeError do
306
+ m.map_string_int32 = {}
307
+ end
308
+
309
+ assert_raise Google::Protobuf::TypeError do
310
+ m = MapMessage.new(:map_string_int32 => { 1 => "I am not a number" })
311
+ end
312
+ end
313
+
314
+ def test_map_field_with_symbol
315
+ m = MapMessage.new
316
+ assert m.map_string_int32 == {}
317
+ assert m.map_string_msg == {}
318
+
319
+ m = MapMessage.new(
320
+ :map_string_int32 => {a: 1, "b" => 2},
321
+ :map_string_msg => {a: TestMessage2.new(:foo => 1),
322
+ b: TestMessage2.new(:foo => 10)})
323
+ assert_equal 1, m.map_string_int32[:a]
324
+ assert_equal 2, m.map_string_int32[:b]
325
+ assert_equal 10, m.map_string_msg[:b].foo
326
+ end
327
+
328
+ def test_map_inspect
329
+ m = MapMessage.new(
330
+ :map_string_int32 => {"a" => 1, "b" => 2},
331
+ :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
332
+ "b" => TestMessage2.new(:foo => 2)},
333
+ :map_string_enum => {"a" => :A, "b" => :B})
334
+
335
+ # JRuby doesn't keep consistent ordering so check for either version
336
+ expected_a = "<BasicTest::MapMessage: map_string_int32: {\"b\"=>2, \"a\"=>1}, map_string_msg: {\"b\"=><BasicTest::TestMessage2: foo: 2>, \"a\"=><BasicTest::TestMessage2: foo: 1>}, map_string_enum: {\"b\"=>:B, \"a\"=>:A}>"
337
+ expected_b = "<BasicTest::MapMessage: map_string_int32: {\"a\"=>1, \"b\"=>2}, map_string_msg: {\"a\"=><BasicTest::TestMessage2: foo: 1>, \"b\"=><BasicTest::TestMessage2: foo: 2>}, map_string_enum: {\"a\"=>:A, \"b\"=>:B}>"
338
+ inspect_result = m.inspect
339
+ assert expected_a == inspect_result || expected_b == inspect_result, "Incorrect inspect result: #{inspect_result}"
340
+ end
341
+
342
+ def test_map_corruption
343
+ # This pattern led to a crash in a previous version of upb/protobuf.
344
+ m = MapMessage.new(map_string_int32: { "aaa" => 1 })
345
+ m.map_string_int32['podid'] = 2
346
+ m.map_string_int32['aaa'] = 3
347
+ end
348
+
349
+ def test_map_wrappers
350
+ run_asserts = ->(m) {
351
+ assert_equal 2.0, m.map_double[0].value
352
+ assert_equal 4.0, m.map_float[0].value
353
+ assert_equal 3, m.map_int32[0].value
354
+ assert_equal 4, m.map_int64[0].value
355
+ assert_equal 5, m.map_uint32[0].value
356
+ assert_equal 6, m.map_uint64[0].value
357
+ assert_equal true, m.map_bool[0].value
358
+ assert_equal 'str', m.map_string[0].value
359
+ assert_equal 'fun', m.map_bytes[0].value
360
+ }
361
+
362
+ m = proto_module::Wrapper.new(
363
+ map_double: {0 => Google::Protobuf::DoubleValue.new(value: 2.0)},
364
+ map_float: {0 => Google::Protobuf::FloatValue.new(value: 4.0)},
365
+ map_int32: {0 => Google::Protobuf::Int32Value.new(value: 3)},
366
+ map_int64: {0 => Google::Protobuf::Int64Value.new(value: 4)},
367
+ map_uint32: {0 => Google::Protobuf::UInt32Value.new(value: 5)},
368
+ map_uint64: {0 => Google::Protobuf::UInt64Value.new(value: 6)},
369
+ map_bool: {0 => Google::Protobuf::BoolValue.new(value: true)},
370
+ map_string: {0 => Google::Protobuf::StringValue.new(value: 'str')},
371
+ map_bytes: {0 => Google::Protobuf::BytesValue.new(value: 'fun')},
372
+ )
373
+
374
+ run_asserts.call(m)
375
+ serialized = proto_module::Wrapper::encode(m)
376
+ m2 = proto_module::Wrapper::decode(serialized)
377
+ run_asserts.call(m2)
378
+
379
+ # Test the case where we are serializing directly from the parsed form
380
+ # (before anything lazy is materialized).
381
+ m3 = proto_module::Wrapper::decode(serialized)
382
+ serialized2 = proto_module::Wrapper::encode(m3)
383
+ m4 = proto_module::Wrapper::decode(serialized2)
384
+ run_asserts.call(m4)
385
+
386
+ # Test that the lazy form compares equal to the expanded form.
387
+ m5 = proto_module::Wrapper::decode(serialized2)
388
+ assert_equal m5, m
389
+ end
390
+
391
+ def test_map_wrappers_with_default_values
392
+ run_asserts = ->(m) {
393
+ assert_equal 0.0, m.map_double[0].value
394
+ assert_equal 0.0, m.map_float[0].value
395
+ assert_equal 0, m.map_int32[0].value
396
+ assert_equal 0, m.map_int64[0].value
397
+ assert_equal 0, m.map_uint32[0].value
398
+ assert_equal 0, m.map_uint64[0].value
399
+ assert_equal false, m.map_bool[0].value
400
+ assert_equal '', m.map_string[0].value
401
+ assert_equal '', m.map_bytes[0].value
402
+ }
403
+
404
+ m = proto_module::Wrapper.new(
405
+ map_double: {0 => Google::Protobuf::DoubleValue.new(value: 0.0)},
406
+ map_float: {0 => Google::Protobuf::FloatValue.new(value: 0.0)},
407
+ map_int32: {0 => Google::Protobuf::Int32Value.new(value: 0)},
408
+ map_int64: {0 => Google::Protobuf::Int64Value.new(value: 0)},
409
+ map_uint32: {0 => Google::Protobuf::UInt32Value.new(value: 0)},
410
+ map_uint64: {0 => Google::Protobuf::UInt64Value.new(value: 0)},
411
+ map_bool: {0 => Google::Protobuf::BoolValue.new(value: false)},
412
+ map_string: {0 => Google::Protobuf::StringValue.new(value: '')},
413
+ map_bytes: {0 => Google::Protobuf::BytesValue.new(value: '')},
414
+ )
415
+
416
+ run_asserts.call(m)
417
+ serialized = proto_module::Wrapper::encode(m)
418
+ m2 = proto_module::Wrapper::decode(serialized)
419
+ run_asserts.call(m2)
420
+
421
+ # Test the case where we are serializing directly from the parsed form
422
+ # (before anything lazy is materialized).
423
+ m3 = proto_module::Wrapper::decode(serialized)
424
+ serialized2 = proto_module::Wrapper::encode(m3)
425
+ m4 = proto_module::Wrapper::decode(serialized2)
426
+ run_asserts.call(m4)
427
+
428
+ # Test that the lazy form compares equal to the expanded form.
429
+ m5 = proto_module::Wrapper::decode(serialized2)
430
+ assert_equal m5, m
431
+ end
432
+
433
+ def test_map_wrappers_with_no_value
434
+ run_asserts = ->(m) {
435
+ assert_equal 0.0, m.map_double[0].value
436
+ assert_equal 0.0, m.map_float[0].value
437
+ assert_equal 0, m.map_int32[0].value
438
+ assert_equal 0, m.map_int64[0].value
439
+ assert_equal 0, m.map_uint32[0].value
440
+ assert_equal 0, m.map_uint64[0].value
441
+ assert_equal false, m.map_bool[0].value
442
+ assert_equal '', m.map_string[0].value
443
+ assert_equal '', m.map_bytes[0].value
444
+ }
445
+
446
+ m = proto_module::Wrapper.new(
447
+ map_double: {0 => Google::Protobuf::DoubleValue.new()},
448
+ map_float: {0 => Google::Protobuf::FloatValue.new()},
449
+ map_int32: {0 => Google::Protobuf::Int32Value.new()},
450
+ map_int64: {0 => Google::Protobuf::Int64Value.new()},
451
+ map_uint32: {0 => Google::Protobuf::UInt32Value.new()},
452
+ map_uint64: {0 => Google::Protobuf::UInt64Value.new()},
453
+ map_bool: {0 => Google::Protobuf::BoolValue.new()},
454
+ map_string: {0 => Google::Protobuf::StringValue.new()},
455
+ map_bytes: {0 => Google::Protobuf::BytesValue.new()},
456
+ )
457
+ run_asserts.call(m)
458
+
459
+ serialized = proto_module::Wrapper::encode(m)
460
+ m2 = proto_module::Wrapper::decode(serialized)
461
+ run_asserts.call(m2)
462
+
463
+ # Test the case where we are serializing directly from the parsed form
464
+ # (before anything lazy is materialized).
465
+ m3 = proto_module::Wrapper::decode(serialized)
466
+ serialized2 = proto_module::Wrapper::encode(m3)
467
+ m4 = proto_module::Wrapper::decode(serialized2)
468
+ run_asserts.call(m4)
469
+ end
470
+
471
+ def test_concurrent_decoding
472
+ o = Outer.new
473
+ o.items[0] = Inner.new
474
+ raw = Outer.encode(o)
475
+
476
+ thds = 2.times.map do
477
+ Thread.new do
478
+ 100000.times do
479
+ assert_equal o, Outer.decode(raw)
480
+ end
481
+ end
482
+ end
483
+ thds.map(&:join)
484
+ end
485
+
486
+ def test_map_encode_decode
487
+ m = MapMessage.new(
488
+ :map_string_int32 => {"a" => 1, "b" => 2},
489
+ :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
490
+ "b" => TestMessage2.new(:foo => 2)},
491
+ :map_string_enum => {"a" => :A, "b" => :B})
492
+ m2 = MapMessage.decode(MapMessage.encode(m))
493
+ assert m == m2
494
+
495
+ m3 = MapMessageWireEquiv.decode(MapMessage.encode(m))
496
+ assert m3.map_string_int32.length == 2
497
+
498
+ kv = {}
499
+ m3.map_string_int32.map { |msg| kv[msg.key] = msg.value }
500
+ assert kv == {"a" => 1, "b" => 2}
501
+
502
+ kv = {}
503
+ m3.map_string_msg.map { |msg| kv[msg.key] = msg.value }
504
+ assert kv == {"a" => TestMessage2.new(:foo => 1),
505
+ "b" => TestMessage2.new(:foo => 2)}
506
+ end
507
+
508
+ def test_protobuf_decode_json_ignore_unknown_fields
509
+ m = TestMessage.decode_json({
510
+ optional_string: "foo",
511
+ not_in_message: "some_value"
512
+ }.to_json, { ignore_unknown_fields: true })
513
+
514
+ assert_equal m.optional_string, "foo"
515
+ e = assert_raise Google::Protobuf::ParseError do
516
+ TestMessage.decode_json({ not_in_message: "some_value" }.to_json)
517
+ end
518
+ assert_match(/No such field: not_in_message/, e.message)
519
+ end
520
+
521
+ #def test_json_quoted_string
522
+ # m = TestMessage.decode_json(%q(
523
+ # "optionalInt64": "1",,
524
+ # }))
525
+ # puts(m)
526
+ # assert_equal 1, m.optional_int32
527
+ #end
528
+
529
+ def test_to_h
530
+ m = TestMessage.new(:optional_bool => true, :optional_double => -10.100001, :optional_string => 'foo', :repeated_string => ['bar1', 'bar2'], :repeated_msg => [TestMessage2.new(:foo => 100)])
531
+ expected_result = {
532
+ :optional_bool=>true,
533
+ :optional_bytes=>"",
534
+ :optional_double=>-10.100001,
535
+ :optional_enum=>:Default,
536
+ :optional_float=>0.0,
537
+ :optional_int32=>0,
538
+ :optional_int64=>0,
539
+ :optional_msg=>nil,
540
+ :optional_msg2=>nil,
541
+ :optional_proto2_submessage=>nil,
542
+ :optional_string=>"foo",
543
+ :optional_uint32=>0,
544
+ :optional_uint64=>0,
545
+ :repeated_bool=>[],
546
+ :repeated_bytes=>[],
547
+ :repeated_double=>[],
548
+ :repeated_enum=>[],
549
+ :repeated_float=>[],
550
+ :repeated_int32=>[],
551
+ :repeated_int64=>[],
552
+ :repeated_msg=>[{:foo => 100}],
553
+ :repeated_string=>["bar1", "bar2"],
554
+ :repeated_uint32=>[],
555
+ :repeated_uint64=>[]
556
+ }
557
+ assert_equal expected_result, m.to_h
558
+
559
+ m = MapMessage.new(
560
+ :map_string_int32 => {"a" => 1, "b" => 2},
561
+ :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
562
+ "b" => TestMessage2.new(:foo => 2)},
563
+ :map_string_enum => {"a" => :A, "b" => :B})
564
+ expected_result = {
565
+ :map_string_int32 => {"a" => 1, "b" => 2},
566
+ :map_string_msg => {"a" => {:foo => 1}, "b" => {:foo => 2}},
567
+ :map_string_enum => {"a" => :A, "b" => :B}
568
+ }
569
+ assert_equal expected_result, m.to_h
570
+ end
571
+
572
+
573
+ def test_json_maps
574
+ m = MapMessage.new(:map_string_int32 => {"a" => 1})
575
+ expected = {mapStringInt32: {a: 1}, mapStringMsg: {}, mapStringEnum: {}}
576
+ expected_preserve = {map_string_int32: {a: 1}, map_string_msg: {}, map_string_enum: {}}
577
+ assert_equal JSON.parse(MapMessage.encode_json(m, :emit_defaults=>true), :symbolize_names => true), expected
578
+
579
+ json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true, :emit_defaults=>true)
580
+ assert_equal JSON.parse(json, :symbolize_names => true), expected_preserve
581
+
582
+ m2 = MapMessage.decode_json(MapMessage.encode_json(m))
583
+ assert_equal m, m2
584
+ end
585
+
586
+ def test_json_maps_emit_defaults_submsg
587
+ m = MapMessage.new(:map_string_msg => {"a" => TestMessage2.new(foo: 0)})
588
+ expected = {mapStringInt32: {}, mapStringMsg: {a: {foo: 0}}, mapStringEnum: {}}
589
+
590
+ actual = MapMessage.encode_json(m, :emit_defaults => true)
591
+
592
+ assert_equal JSON.parse(actual, :symbolize_names => true), expected
593
+ end
594
+
595
+ def test_json_emit_defaults_submsg
596
+ m = TestSingularFields.new(singular_msg: proto_module::TestMessage2.new)
597
+
598
+ expected = {
599
+ singularInt32: 0,
600
+ singularInt64: "0",
601
+ singularUint32: 0,
602
+ singularUint64: "0",
603
+ singularBool: false,
604
+ singularFloat: 0,
605
+ singularDouble: 0,
606
+ singularString: "",
607
+ singularBytes: "",
608
+ singularMsg: {},
609
+ singularEnum: "Default",
610
+ }
611
+
612
+ actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true)
613
+
614
+ assert_equal expected, JSON.parse(actual, :symbolize_names => true)
615
+ end
616
+
617
+ def test_respond_to
618
+ msg = MapMessage.new
619
+ assert msg.respond_to?(:map_string_int32)
620
+ assert !msg.respond_to?(:bacon)
621
+ end
622
+
623
+ def test_file_descriptor
624
+ file_descriptor = TestMessage.descriptor.file_descriptor
625
+ assert nil != file_descriptor
626
+ assert_equal "tests/basic_test.proto", file_descriptor.name
627
+ assert_equal :proto3, file_descriptor.syntax
628
+
629
+ file_descriptor = TestEnum.descriptor.file_descriptor
630
+ assert nil != file_descriptor
631
+ assert_equal "tests/basic_test.proto", file_descriptor.name
632
+ assert_equal :proto3, file_descriptor.syntax
633
+ end
634
+
635
+ # Ruby 2.5 changed to raise FrozenError instead of RuntimeError
636
+ FrozenErrorType = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.5') ? RuntimeError : FrozenError
637
+
638
+ def test_map_freeze
639
+ m = proto_module::MapMessage.new
640
+ m.map_string_int32['a'] = 5
641
+ m.map_string_msg['b'] = proto_module::TestMessage2.new
642
+
643
+ m.map_string_int32.freeze
644
+ m.map_string_msg.freeze
645
+
646
+ assert m.map_string_int32.frozen?
647
+ assert m.map_string_msg.frozen?
648
+
649
+ assert_raise(FrozenErrorType) { m.map_string_int32['foo'] = 1 }
650
+ assert_raise(FrozenErrorType) { m.map_string_msg['bar'] = proto_module::TestMessage2.new }
651
+ assert_raise(FrozenErrorType) { m.map_string_int32.delete('a') }
652
+ assert_raise(FrozenErrorType) { m.map_string_int32.clear }
653
+ end
654
+
655
+ def test_map_length
656
+ m = proto_module::MapMessage.new
657
+ assert_equal 0, m.map_string_int32.length
658
+ assert_equal 0, m.map_string_msg.length
659
+ assert_equal 0, m.map_string_int32.size
660
+ assert_equal 0, m.map_string_msg.size
661
+
662
+ m.map_string_int32['a'] = 1
663
+ m.map_string_int32['b'] = 2
664
+ m.map_string_msg['a'] = proto_module::TestMessage2.new
665
+ assert_equal 2, m.map_string_int32.length
666
+ assert_equal 1, m.map_string_msg.length
667
+ assert_equal 2, m.map_string_int32.size
668
+ assert_equal 1, m.map_string_msg.size
669
+ end
670
+
671
+ def test_string_with_singleton_class_enabled
672
+ str = 'foobar'
673
+ # NOTE: Accessing a singleton class of an object changes its low level class representation
674
+ # as far as the C API's CLASS_OF() method concerned, exposing the issue
675
+ str.singleton_class
676
+ m = proto_module::TestMessage.new(
677
+ optional_string: str,
678
+ optional_bytes: str
679
+ )
680
+
681
+ assert_equal str, m.optional_string
682
+ assert_equal str, m.optional_bytes
683
+ end
684
+
685
+ def test_utf8
686
+ m = proto_module::TestMessage.new(
687
+ optional_string: "µpb",
688
+ )
689
+ m2 = proto_module::TestMessage.decode(proto_module::TestMessage.encode(m))
690
+ assert_equal m2, m
691
+ end
692
+
693
+ def test_map_fields_respond_to? # regression test for issue 9202
694
+ msg = proto_module::MapMessage.new
695
+ assert msg.respond_to?(:map_string_int32=)
696
+ msg.map_string_int32 = Google::Protobuf::Map.new(:string, :int32)
697
+ assert msg.respond_to?(:map_string_int32)
698
+ assert_equal( Google::Protobuf::Map.new(:string, :int32), msg.map_string_int32 )
699
+ assert msg.respond_to?(:clear_map_string_int32)
700
+ msg.clear_map_string_int32
701
+
702
+ assert !msg.respond_to?(:has_map_string_int32?)
703
+ assert_raise NoMethodError do
704
+ msg.has_map_string_int32?
705
+ end
706
+ assert !msg.respond_to?(:map_string_int32_as_value)
707
+ assert_raise NoMethodError do
708
+ msg.map_string_int32_as_value
709
+ end
710
+ assert !msg.respond_to?(:map_string_int32_as_value=)
711
+ assert_raise NoMethodError do
712
+ msg.map_string_int32_as_value = :boom
713
+ end
714
+ end
715
+ end
716
+
717
+ def test_oneof_fields_respond_to? # regression test for issue 9202
718
+ msg = proto_module::OneofMessage.new
719
+ # `has_` prefix + "?" suffix actions should only work for oneofs fields.
720
+ assert msg.has_my_oneof?
721
+ assert msg.respond_to? :has_my_oneof?
722
+ assert !msg.respond_to?( :has_a? )
723
+ assert_raise NoMethodError do
724
+ msg.has_a?
725
+ end
726
+ assert !msg.respond_to?( :has_b? )
727
+ assert_raise NoMethodError do
728
+ msg.has_b?
729
+ end
730
+ assert !msg.respond_to?( :has_c? )
731
+ assert_raise NoMethodError do
732
+ msg.has_c?
733
+ end
734
+ assert !msg.respond_to?( :has_d? )
735
+ assert_raise NoMethodError do
736
+ msg.has_d?
737
+ end
738
+ end
739
+ end