google-protobuf 3.7.0 → 3.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (46) hide show
  1. checksums.yaml +4 -4
  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 +669 -1646
  5. data/ext/google/protobuf_c/defs.h +107 -0
  6. data/ext/google/protobuf_c/extconf.rb +13 -8
  7. data/ext/google/protobuf_c/map.c +330 -477
  8. data/ext/google/protobuf_c/map.h +66 -0
  9. data/ext/google/protobuf_c/message.c +1048 -379
  10. data/ext/google/protobuf_c/message.h +104 -0
  11. data/ext/google/protobuf_c/protobuf.c +413 -54
  12. data/ext/google/protobuf_c/protobuf.h +53 -546
  13. data/ext/google/protobuf_c/repeated_field.c +318 -315
  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 +4 -3
  23. data/lib/google/protobuf/any_pb.rb +1 -1
  24. data/lib/google/protobuf/api_pb.rb +4 -3
  25. data/lib/google/protobuf/descriptor_dsl.rb +465 -0
  26. data/lib/google/protobuf/descriptor_pb.rb +269 -0
  27. data/lib/google/protobuf/duration_pb.rb +1 -1
  28. data/lib/google/protobuf/empty_pb.rb +1 -1
  29. data/lib/google/protobuf/field_mask_pb.rb +1 -1
  30. data/lib/google/protobuf/message_exts.rb +2 -2
  31. data/lib/google/protobuf/repeated_field.rb +15 -2
  32. data/lib/google/protobuf/source_context_pb.rb +1 -1
  33. data/lib/google/protobuf/struct_pb.rb +4 -4
  34. data/lib/google/protobuf/timestamp_pb.rb +1 -1
  35. data/lib/google/protobuf/type_pb.rb +9 -8
  36. data/lib/google/protobuf/well_known_types.rb +20 -4
  37. data/lib/google/protobuf/wrappers_pb.rb +9 -9
  38. data/lib/google/protobuf.rb +6 -4
  39. data/tests/basic.rb +455 -77
  40. data/tests/generated_code_test.rb +0 -0
  41. data/tests/stress.rb +1 -1
  42. metadata +27 -30
  43. data/ext/google/protobuf_c/encode_decode.c +0 -1574
  44. data/ext/google/protobuf_c/storage.c +0 -1019
  45. data/ext/google/protobuf_c/upb.c +0 -17318
  46. data/ext/google/protobuf_c/upb.h +0 -9755
data/tests/basic.rb CHANGED
@@ -17,7 +17,6 @@ module BasicTest
17
17
  add_message "BadFieldNames" do
18
18
  optional :dup, :int32, 1
19
19
  optional :class, :int32, 2
20
- optional :"a.b", :int32, 3
21
20
  end
22
21
  end
23
22
 
@@ -32,12 +31,91 @@ module BasicTest
32
31
  end
33
32
  include CommonTests
34
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
+
35
113
  def test_has_field
36
- m = TestMessage.new
37
- assert !m.has_optional_msg?
38
- m.optional_msg = TestMessage2.new
39
- assert m.has_optional_msg?
40
- assert TestMessage.descriptor.lookup('optional_msg').has?(m)
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)
41
119
 
42
120
  m = OneofMessage.new
43
121
  assert !m.has_my_oneof?
@@ -46,32 +124,31 @@ module BasicTest
46
124
  assert_raise NoMethodError do
47
125
  m.has_a?
48
126
  end
49
- assert_raise ArgumentError do
50
- OneofMessage.descriptor.lookup('a').has?(m)
51
- end
127
+ assert_true OneofMessage.descriptor.lookup('a').has?(m)
52
128
 
53
- m = TestMessage.new
129
+ m = TestSingularFields.new
54
130
  assert_raise NoMethodError do
55
- m.has_optional_int32?
131
+ m.has_singular_int32?
56
132
  end
57
133
  assert_raise ArgumentError do
58
- TestMessage.descriptor.lookup('optional_int32').has?(m)
134
+ TestSingularFields.descriptor.lookup('singular_int32').has?(m)
59
135
  end
60
136
 
61
137
  assert_raise NoMethodError do
62
- m.has_optional_string?
138
+ m.has_singular_string?
63
139
  end
64
140
  assert_raise ArgumentError do
65
- TestMessage.descriptor.lookup('optional_string').has?(m)
141
+ TestSingularFields.descriptor.lookup('singular_string').has?(m)
66
142
  end
67
143
 
68
144
  assert_raise NoMethodError do
69
- m.has_optional_bool?
145
+ m.has_singular_bool?
70
146
  end
71
147
  assert_raise ArgumentError do
72
- TestMessage.descriptor.lookup('optional_bool').has?(m)
148
+ TestSingularFields.descriptor.lookup('singular_bool').has?(m)
73
149
  end
74
150
 
151
+ m = TestMessage.new
75
152
  assert_raise NoMethodError do
76
153
  m.has_repeated_msg?
77
154
  end
@@ -80,40 +157,70 @@ module BasicTest
80
157
  end
81
158
  end
82
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
+
83
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
84
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
85
221
 
86
- m.optional_int32 = -42
87
- assert_equal -42, m.optional_int32
88
- m.clear_optional_int32
89
- assert_equal 0, m.optional_int32
90
-
91
- m.optional_int32 = 50
92
- assert_equal 50, m.optional_int32
93
- TestMessage.descriptor.lookup('optional_int32').clear(m)
94
- assert_equal 0, m.optional_int32
95
-
96
- m.optional_string = "foo bar"
97
- assert_equal "foo bar", m.optional_string
98
- m.clear_optional_string
99
- assert_equal "", m.optional_string
100
-
101
- m.optional_string = "foo"
102
- assert_equal "foo", m.optional_string
103
- TestMessage.descriptor.lookup('optional_string').clear(m)
104
- assert_equal "", m.optional_string
105
-
106
- m.optional_msg = TestMessage2.new(:foo => 42)
107
- assert_equal TestMessage2.new(:foo => 42), m.optional_msg
108
- assert m.has_optional_msg?
109
- m.clear_optional_msg
110
- assert_equal nil, m.optional_msg
111
- assert !m.has_optional_msg?
112
-
113
- m.optional_msg = TestMessage2.new(:foo => 42)
114
- assert_equal TestMessage2.new(:foo => 42), m.optional_msg
115
- TestMessage.descriptor.lookup('optional_msg').clear(m)
116
- assert_equal nil, m.optional_msg
222
+ def test_clear_repeated_fields
223
+ m = TestMessage.new
117
224
 
118
225
  m.repeated_int32.push(1)
119
226
  assert_equal [1], m.repeated_int32
@@ -129,6 +236,7 @@ module BasicTest
129
236
  m.a = "foo"
130
237
  assert_equal "foo", m.a
131
238
  assert m.has_my_oneof?
239
+ assert_equal :a, m.my_oneof
132
240
  m.clear_a
133
241
  assert !m.has_my_oneof?
134
242
 
@@ -144,7 +252,6 @@ module BasicTest
144
252
  assert !m.has_my_oneof?
145
253
  end
146
254
 
147
-
148
255
  def test_initialization_map_errors
149
256
  e = assert_raise ArgumentError do
150
257
  TestMessage.new(:hello => "world")
@@ -154,12 +261,12 @@ module BasicTest
154
261
  e = assert_raise ArgumentError do
155
262
  MapMessage.new(:map_string_int32 => "hello")
156
263
  end
157
- assert_equal e.message, "Expected Hash object as initializer value for map field 'map_string_int32'."
264
+ assert_equal e.message, "Expected Hash object as initializer value for map field 'map_string_int32' (given String)."
158
265
 
159
266
  e = assert_raise ArgumentError do
160
267
  TestMessage.new(:repeated_uint32 => "hello")
161
268
  end
162
- assert_equal e.message, "Expected array as initializer value for repeated field 'repeated_uint32'."
269
+ assert_equal e.message, "Expected array as initializer value for repeated field 'repeated_uint32' (given String)."
163
270
  end
164
271
 
165
272
  def test_map_field
@@ -170,10 +277,12 @@ module BasicTest
170
277
  m = MapMessage.new(
171
278
  :map_string_int32 => {"a" => 1, "b" => 2},
172
279
  :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
173
- "b" => TestMessage2.new(:foo => 2)})
280
+ "b" => TestMessage2.new(:foo => 2)},
281
+ :map_string_enum => {"a" => :A, "b" => :B})
174
282
  assert m.map_string_int32.keys.sort == ["a", "b"]
175
283
  assert m.map_string_int32["a"] == 1
176
284
  assert m.map_string_msg["b"].foo == 2
285
+ assert m.map_string_enum["a"] == :A
177
286
 
178
287
  m.map_string_int32["c"] = 3
179
288
  assert m.map_string_int32["c"] == 3
@@ -197,18 +306,37 @@ module BasicTest
197
306
  m.map_string_int32 = {}
198
307
  end
199
308
 
200
- assert_raise TypeError do
309
+ assert_raise Google::Protobuf::TypeError do
201
310
  m = MapMessage.new(:map_string_int32 => { 1 => "I am not a number" })
202
311
  end
203
312
  end
204
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
+
205
328
  def test_map_inspect
206
329
  m = MapMessage.new(
207
330
  :map_string_int32 => {"a" => 1, "b" => 2},
208
331
  :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
209
- "b" => TestMessage2.new(:foo => 2)})
210
- expected = "<BasicTest::MapMessage: map_string_int32: {\"b\"=>2, \"a\"=>1}, map_string_msg: {\"b\"=><BasicTest::TestMessage2: foo: 2>, \"a\"=><BasicTest::TestMessage2: foo: 1>}>"
211
- assert_equal expected, m.inspect
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}"
212
340
  end
213
341
 
214
342
  def test_map_corruption
@@ -218,6 +346,128 @@ module BasicTest
218
346
  m.map_string_int32['aaa'] = 3
219
347
  end
220
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
+
221
471
  def test_concurrent_decoding
222
472
  o = Outer.new
223
473
  o.items[0] = Inner.new
@@ -237,7 +487,8 @@ module BasicTest
237
487
  m = MapMessage.new(
238
488
  :map_string_int32 => {"a" => 1, "b" => 2},
239
489
  :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
240
- "b" => TestMessage2.new(:foo => 2)})
490
+ "b" => TestMessage2.new(:foo => 2)},
491
+ :map_string_enum => {"a" => :A, "b" => :B})
241
492
  m2 = MapMessage.decode(MapMessage.encode(m))
242
493
  assert m == m2
243
494
 
@@ -267,6 +518,14 @@ module BasicTest
267
518
  assert_match(/No such field: not_in_message/, e.message)
268
519
  end
269
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
+
270
529
  def test_to_h
271
530
  m = TestMessage.new(:optional_bool => true, :optional_double => -10.100001, :optional_string => 'foo', :repeated_string => ['bar1', 'bar2'], :repeated_msg => [TestMessage2.new(:foo => 100)])
272
531
  expected_result = {
@@ -278,6 +537,8 @@ module BasicTest
278
537
  :optional_int32=>0,
279
538
  :optional_int64=>0,
280
539
  :optional_msg=>nil,
540
+ :optional_msg2=>nil,
541
+ :optional_proto2_submessage=>nil,
281
542
  :optional_string=>"foo",
282
543
  :optional_uint32=>0,
283
544
  :optional_uint64=>0,
@@ -298,44 +559,62 @@ module BasicTest
298
559
  m = MapMessage.new(
299
560
  :map_string_int32 => {"a" => 1, "b" => 2},
300
561
  :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
301
- "b" => TestMessage2.new(:foo => 2)})
562
+ "b" => TestMessage2.new(:foo => 2)},
563
+ :map_string_enum => {"a" => :A, "b" => :B})
302
564
  expected_result = {
303
565
  :map_string_int32 => {"a" => 1, "b" => 2},
304
- :map_string_msg => {"a" => {:foo => 1}, "b" => {:foo => 2}}
566
+ :map_string_msg => {"a" => {:foo => 1}, "b" => {:foo => 2}},
567
+ :map_string_enum => {"a" => :A, "b" => :B}
305
568
  }
306
569
  assert_equal expected_result, m.to_h
307
570
  end
308
571
 
309
572
 
310
573
  def test_json_maps
311
- # TODO: Fix JSON in JRuby version.
312
- return if RUBY_PLATFORM == "java"
313
574
  m = MapMessage.new(:map_string_int32 => {"a" => 1})
314
- expected = {mapStringInt32: {a: 1}, mapStringMsg: {}}
315
- expected_preserve = {map_string_int32: {a: 1}, map_string_msg: {}}
316
- assert JSON.parse(MapMessage.encode_json(m), :symbolize_names => true) == expected
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
317
578
 
318
- json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true)
319
- assert JSON.parse(json, :symbolize_names => true) == expected_preserve
579
+ json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true, :emit_defaults=>true)
580
+ assert_equal JSON.parse(json, :symbolize_names => true), expected_preserve
320
581
 
321
582
  m2 = MapMessage.decode_json(MapMessage.encode_json(m))
322
- assert m == m2
583
+ assert_equal m, m2
323
584
  end
324
585
 
325
586
  def test_json_maps_emit_defaults_submsg
326
- # TODO: Fix JSON in JRuby version.
327
- return if RUBY_PLATFORM == "java"
328
- m = MapMessage.new(:map_string_msg => {"a" => TestMessage2.new})
329
- expected = {mapStringInt32: {}, mapStringMsg: {a: {foo: 0}}}
587
+ m = MapMessage.new(:map_string_msg => {"a" => TestMessage2.new(foo: 0)})
588
+ expected = {mapStringInt32: {}, mapStringMsg: {a: {foo: 0}}, mapStringEnum: {}}
330
589
 
331
590
  actual = MapMessage.encode_json(m, :emit_defaults => true)
332
591
 
333
- assert JSON.parse(actual, :symbolize_names => true) == expected
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)
334
615
  end
335
616
 
336
617
  def test_respond_to
337
- # This test fails with JRuby 1.7.23, likely because of an old JRuby bug.
338
- return if RUBY_PLATFORM == "java"
339
618
  msg = MapMessage.new
340
619
  assert msg.respond_to?(:map_string_int32)
341
620
  assert !msg.respond_to?(:bacon)
@@ -351,11 +630,110 @@ module BasicTest
351
630
  assert nil != file_descriptor
352
631
  assert_equal "tests/basic_test.proto", file_descriptor.name
353
632
  assert_equal :proto3, file_descriptor.syntax
633
+ end
354
634
 
355
- file_descriptor = BadFieldNames.descriptor.file_descriptor
356
- assert nil != file_descriptor
357
- assert_equal nil, file_descriptor.name
358
- assert_equal :proto3, file_descriptor.syntax
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?
359
737
  end
360
738
  end
361
739
  end
File without changes