google-protobuf 3.7.0 → 3.20.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 (45) 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/source_context_pb.rb +1 -1
  32. data/lib/google/protobuf/struct_pb.rb +4 -4
  33. data/lib/google/protobuf/timestamp_pb.rb +1 -1
  34. data/lib/google/protobuf/type_pb.rb +9 -8
  35. data/lib/google/protobuf/well_known_types.rb +20 -4
  36. data/lib/google/protobuf/wrappers_pb.rb +9 -9
  37. data/lib/google/protobuf.rb +6 -4
  38. data/tests/basic.rb +380 -71
  39. data/tests/generated_code_test.rb +0 -0
  40. data/tests/stress.rb +1 -1
  41. metadata +27 -30
  42. data/ext/google/protobuf_c/encode_decode.c +0 -1574
  43. data/ext/google/protobuf_c/storage.c +0 -1019
  44. data/ext/google/protobuf_c/upb.c +0 -17318
  45. 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,60 @@ 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
+ # TODO: Remove the platform check once https://github.com/jruby/jruby/issues/6818 is released in JRuby 9.3.0.0
70
+ GC.start(full_mark: true, immediate_sweep: true) unless RUBY_PLATFORM == "java"
71
+ TestMessage.encode(msg)
72
+ end
73
+
74
+ def test_issue_9440
75
+ msg = HelloRequest.new
76
+ msg.id = 8
77
+ assert_equal 8, msg.id
78
+ msg.version = '1'
79
+ assert_equal 8, msg.id
80
+ end
81
+
35
82
  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)
83
+ m = TestSingularFields.new
84
+ assert !m.has_singular_msg?
85
+ m.singular_msg = TestMessage2.new
86
+ assert m.has_singular_msg?
87
+ assert TestSingularFields.descriptor.lookup('singular_msg').has?(m)
41
88
 
42
89
  m = OneofMessage.new
43
90
  assert !m.has_my_oneof?
@@ -46,32 +93,31 @@ module BasicTest
46
93
  assert_raise NoMethodError do
47
94
  m.has_a?
48
95
  end
49
- assert_raise ArgumentError do
50
- OneofMessage.descriptor.lookup('a').has?(m)
51
- end
96
+ assert_true OneofMessage.descriptor.lookup('a').has?(m)
52
97
 
53
- m = TestMessage.new
98
+ m = TestSingularFields.new
54
99
  assert_raise NoMethodError do
55
- m.has_optional_int32?
100
+ m.has_singular_int32?
56
101
  end
57
102
  assert_raise ArgumentError do
58
- TestMessage.descriptor.lookup('optional_int32').has?(m)
103
+ TestSingularFields.descriptor.lookup('singular_int32').has?(m)
59
104
  end
60
105
 
61
106
  assert_raise NoMethodError do
62
- m.has_optional_string?
107
+ m.has_singular_string?
63
108
  end
64
109
  assert_raise ArgumentError do
65
- TestMessage.descriptor.lookup('optional_string').has?(m)
110
+ TestSingularFields.descriptor.lookup('singular_string').has?(m)
66
111
  end
67
112
 
68
113
  assert_raise NoMethodError do
69
- m.has_optional_bool?
114
+ m.has_singular_bool?
70
115
  end
71
116
  assert_raise ArgumentError do
72
- TestMessage.descriptor.lookup('optional_bool').has?(m)
117
+ TestSingularFields.descriptor.lookup('singular_bool').has?(m)
73
118
  end
74
119
 
120
+ m = TestMessage.new
75
121
  assert_raise NoMethodError do
76
122
  m.has_repeated_msg?
77
123
  end
@@ -80,40 +126,70 @@ module BasicTest
80
126
  end
81
127
  end
82
128
 
129
+ def test_no_presence
130
+ m = TestSingularFields.new
131
+
132
+ # Explicitly setting to zero does not cause anything to be serialized.
133
+ m.singular_int32 = 0
134
+ assert_equal "", TestSingularFields.encode(m)
135
+
136
+ # Explicitly setting to a non-zero value *does* cause serialization.
137
+ m.singular_int32 = 1
138
+ assert_not_equal "", TestSingularFields.encode(m)
139
+
140
+ m.singular_int32 = 0
141
+ assert_equal "", TestSingularFields.encode(m)
142
+ end
143
+
83
144
  def test_set_clear_defaults
145
+ m = TestSingularFields.new
146
+
147
+ m.singular_int32 = -42
148
+ assert_equal -42, m.singular_int32
149
+ m.clear_singular_int32
150
+ assert_equal 0, m.singular_int32
151
+
152
+ m.singular_int32 = 50
153
+ assert_equal 50, m.singular_int32
154
+ TestSingularFields.descriptor.lookup('singular_int32').clear(m)
155
+ assert_equal 0, m.singular_int32
156
+
157
+ m.singular_string = "foo bar"
158
+ assert_equal "foo bar", m.singular_string
159
+ m.clear_singular_string
160
+ assert_equal "", m.singular_string
161
+
162
+ m.singular_string = "foo"
163
+ assert_equal "foo", m.singular_string
164
+ TestSingularFields.descriptor.lookup('singular_string').clear(m)
165
+ assert_equal "", m.singular_string
166
+
167
+ m.singular_msg = TestMessage2.new(:foo => 42)
168
+ assert_equal TestMessage2.new(:foo => 42), m.singular_msg
169
+ assert m.has_singular_msg?
170
+ m.clear_singular_msg
171
+ assert_equal nil, m.singular_msg
172
+ assert !m.has_singular_msg?
173
+
174
+ m.singular_msg = TestMessage2.new(:foo => 42)
175
+ assert_equal TestMessage2.new(:foo => 42), m.singular_msg
176
+ TestSingularFields.descriptor.lookup('singular_msg').clear(m)
177
+ assert_equal nil, m.singular_msg
178
+ end
179
+
180
+ def test_import_proto2
84
181
  m = TestMessage.new
182
+ assert !m.has_optional_proto2_submessage?
183
+ m.optional_proto2_submessage = ::FooBar::Proto2::TestImportedMessage.new
184
+ assert m.has_optional_proto2_submessage?
185
+ assert TestMessage.descriptor.lookup('optional_proto2_submessage').has?(m)
85
186
 
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
187
+ m.clear_optional_proto2_submessage
188
+ assert !m.has_optional_proto2_submessage?
189
+ end
190
+
191
+ def test_clear_repeated_fields
192
+ m = TestMessage.new
117
193
 
118
194
  m.repeated_int32.push(1)
119
195
  assert_equal [1], m.repeated_int32
@@ -129,6 +205,7 @@ module BasicTest
129
205
  m.a = "foo"
130
206
  assert_equal "foo", m.a
131
207
  assert m.has_my_oneof?
208
+ assert_equal :a, m.my_oneof
132
209
  m.clear_a
133
210
  assert !m.has_my_oneof?
134
211
 
@@ -144,7 +221,6 @@ module BasicTest
144
221
  assert !m.has_my_oneof?
145
222
  end
146
223
 
147
-
148
224
  def test_initialization_map_errors
149
225
  e = assert_raise ArgumentError do
150
226
  TestMessage.new(:hello => "world")
@@ -154,12 +230,12 @@ module BasicTest
154
230
  e = assert_raise ArgumentError do
155
231
  MapMessage.new(:map_string_int32 => "hello")
156
232
  end
157
- assert_equal e.message, "Expected Hash object as initializer value for map field 'map_string_int32'."
233
+ assert_equal e.message, "Expected Hash object as initializer value for map field 'map_string_int32' (given String)."
158
234
 
159
235
  e = assert_raise ArgumentError do
160
236
  TestMessage.new(:repeated_uint32 => "hello")
161
237
  end
162
- assert_equal e.message, "Expected array as initializer value for repeated field 'repeated_uint32'."
238
+ assert_equal e.message, "Expected array as initializer value for repeated field 'repeated_uint32' (given String)."
163
239
  end
164
240
 
165
241
  def test_map_field
@@ -170,10 +246,12 @@ module BasicTest
170
246
  m = MapMessage.new(
171
247
  :map_string_int32 => {"a" => 1, "b" => 2},
172
248
  :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
173
- "b" => TestMessage2.new(:foo => 2)})
249
+ "b" => TestMessage2.new(:foo => 2)},
250
+ :map_string_enum => {"a" => :A, "b" => :B})
174
251
  assert m.map_string_int32.keys.sort == ["a", "b"]
175
252
  assert m.map_string_int32["a"] == 1
176
253
  assert m.map_string_msg["b"].foo == 2
254
+ assert m.map_string_enum["a"] == :A
177
255
 
178
256
  m.map_string_int32["c"] = 3
179
257
  assert m.map_string_int32["c"] == 3
@@ -197,18 +275,37 @@ module BasicTest
197
275
  m.map_string_int32 = {}
198
276
  end
199
277
 
200
- assert_raise TypeError do
278
+ assert_raise Google::Protobuf::TypeError do
201
279
  m = MapMessage.new(:map_string_int32 => { 1 => "I am not a number" })
202
280
  end
203
281
  end
204
282
 
283
+ def test_map_field_with_symbol
284
+ m = MapMessage.new
285
+ assert m.map_string_int32 == {}
286
+ assert m.map_string_msg == {}
287
+
288
+ m = MapMessage.new(
289
+ :map_string_int32 => {a: 1, "b" => 2},
290
+ :map_string_msg => {a: TestMessage2.new(:foo => 1),
291
+ b: TestMessage2.new(:foo => 10)})
292
+ assert_equal 1, m.map_string_int32[:a]
293
+ assert_equal 2, m.map_string_int32[:b]
294
+ assert_equal 10, m.map_string_msg[:b].foo
295
+ end
296
+
205
297
  def test_map_inspect
206
298
  m = MapMessage.new(
207
299
  :map_string_int32 => {"a" => 1, "b" => 2},
208
300
  :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
301
+ "b" => TestMessage2.new(:foo => 2)},
302
+ :map_string_enum => {"a" => :A, "b" => :B})
303
+
304
+ # JRuby doesn't keep consistent ordering so check for either version
305
+ 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}>"
306
+ 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}>"
307
+ inspect_result = m.inspect
308
+ assert expected_a == inspect_result || expected_b == inspect_result, "Incorrect inspect result: #{inspect_result}"
212
309
  end
213
310
 
214
311
  def test_map_corruption
@@ -218,6 +315,128 @@ module BasicTest
218
315
  m.map_string_int32['aaa'] = 3
219
316
  end
220
317
 
318
+ def test_map_wrappers
319
+ run_asserts = ->(m) {
320
+ assert_equal 2.0, m.map_double[0].value
321
+ assert_equal 4.0, m.map_float[0].value
322
+ assert_equal 3, m.map_int32[0].value
323
+ assert_equal 4, m.map_int64[0].value
324
+ assert_equal 5, m.map_uint32[0].value
325
+ assert_equal 6, m.map_uint64[0].value
326
+ assert_equal true, m.map_bool[0].value
327
+ assert_equal 'str', m.map_string[0].value
328
+ assert_equal 'fun', m.map_bytes[0].value
329
+ }
330
+
331
+ m = proto_module::Wrapper.new(
332
+ map_double: {0 => Google::Protobuf::DoubleValue.new(value: 2.0)},
333
+ map_float: {0 => Google::Protobuf::FloatValue.new(value: 4.0)},
334
+ map_int32: {0 => Google::Protobuf::Int32Value.new(value: 3)},
335
+ map_int64: {0 => Google::Protobuf::Int64Value.new(value: 4)},
336
+ map_uint32: {0 => Google::Protobuf::UInt32Value.new(value: 5)},
337
+ map_uint64: {0 => Google::Protobuf::UInt64Value.new(value: 6)},
338
+ map_bool: {0 => Google::Protobuf::BoolValue.new(value: true)},
339
+ map_string: {0 => Google::Protobuf::StringValue.new(value: 'str')},
340
+ map_bytes: {0 => Google::Protobuf::BytesValue.new(value: 'fun')},
341
+ )
342
+
343
+ run_asserts.call(m)
344
+ serialized = proto_module::Wrapper::encode(m)
345
+ m2 = proto_module::Wrapper::decode(serialized)
346
+ run_asserts.call(m2)
347
+
348
+ # Test the case where we are serializing directly from the parsed form
349
+ # (before anything lazy is materialized).
350
+ m3 = proto_module::Wrapper::decode(serialized)
351
+ serialized2 = proto_module::Wrapper::encode(m3)
352
+ m4 = proto_module::Wrapper::decode(serialized2)
353
+ run_asserts.call(m4)
354
+
355
+ # Test that the lazy form compares equal to the expanded form.
356
+ m5 = proto_module::Wrapper::decode(serialized2)
357
+ assert_equal m5, m
358
+ end
359
+
360
+ def test_map_wrappers_with_default_values
361
+ run_asserts = ->(m) {
362
+ assert_equal 0.0, m.map_double[0].value
363
+ assert_equal 0.0, m.map_float[0].value
364
+ assert_equal 0, m.map_int32[0].value
365
+ assert_equal 0, m.map_int64[0].value
366
+ assert_equal 0, m.map_uint32[0].value
367
+ assert_equal 0, m.map_uint64[0].value
368
+ assert_equal false, m.map_bool[0].value
369
+ assert_equal '', m.map_string[0].value
370
+ assert_equal '', m.map_bytes[0].value
371
+ }
372
+
373
+ m = proto_module::Wrapper.new(
374
+ map_double: {0 => Google::Protobuf::DoubleValue.new(value: 0.0)},
375
+ map_float: {0 => Google::Protobuf::FloatValue.new(value: 0.0)},
376
+ map_int32: {0 => Google::Protobuf::Int32Value.new(value: 0)},
377
+ map_int64: {0 => Google::Protobuf::Int64Value.new(value: 0)},
378
+ map_uint32: {0 => Google::Protobuf::UInt32Value.new(value: 0)},
379
+ map_uint64: {0 => Google::Protobuf::UInt64Value.new(value: 0)},
380
+ map_bool: {0 => Google::Protobuf::BoolValue.new(value: false)},
381
+ map_string: {0 => Google::Protobuf::StringValue.new(value: '')},
382
+ map_bytes: {0 => Google::Protobuf::BytesValue.new(value: '')},
383
+ )
384
+
385
+ run_asserts.call(m)
386
+ serialized = proto_module::Wrapper::encode(m)
387
+ m2 = proto_module::Wrapper::decode(serialized)
388
+ run_asserts.call(m2)
389
+
390
+ # Test the case where we are serializing directly from the parsed form
391
+ # (before anything lazy is materialized).
392
+ m3 = proto_module::Wrapper::decode(serialized)
393
+ serialized2 = proto_module::Wrapper::encode(m3)
394
+ m4 = proto_module::Wrapper::decode(serialized2)
395
+ run_asserts.call(m4)
396
+
397
+ # Test that the lazy form compares equal to the expanded form.
398
+ m5 = proto_module::Wrapper::decode(serialized2)
399
+ assert_equal m5, m
400
+ end
401
+
402
+ def test_map_wrappers_with_no_value
403
+ run_asserts = ->(m) {
404
+ assert_equal 0.0, m.map_double[0].value
405
+ assert_equal 0.0, m.map_float[0].value
406
+ assert_equal 0, m.map_int32[0].value
407
+ assert_equal 0, m.map_int64[0].value
408
+ assert_equal 0, m.map_uint32[0].value
409
+ assert_equal 0, m.map_uint64[0].value
410
+ assert_equal false, m.map_bool[0].value
411
+ assert_equal '', m.map_string[0].value
412
+ assert_equal '', m.map_bytes[0].value
413
+ }
414
+
415
+ m = proto_module::Wrapper.new(
416
+ map_double: {0 => Google::Protobuf::DoubleValue.new()},
417
+ map_float: {0 => Google::Protobuf::FloatValue.new()},
418
+ map_int32: {0 => Google::Protobuf::Int32Value.new()},
419
+ map_int64: {0 => Google::Protobuf::Int64Value.new()},
420
+ map_uint32: {0 => Google::Protobuf::UInt32Value.new()},
421
+ map_uint64: {0 => Google::Protobuf::UInt64Value.new()},
422
+ map_bool: {0 => Google::Protobuf::BoolValue.new()},
423
+ map_string: {0 => Google::Protobuf::StringValue.new()},
424
+ map_bytes: {0 => Google::Protobuf::BytesValue.new()},
425
+ )
426
+ run_asserts.call(m)
427
+
428
+ serialized = proto_module::Wrapper::encode(m)
429
+ m2 = proto_module::Wrapper::decode(serialized)
430
+ run_asserts.call(m2)
431
+
432
+ # Test the case where we are serializing directly from the parsed form
433
+ # (before anything lazy is materialized).
434
+ m3 = proto_module::Wrapper::decode(serialized)
435
+ serialized2 = proto_module::Wrapper::encode(m3)
436
+ m4 = proto_module::Wrapper::decode(serialized2)
437
+ run_asserts.call(m4)
438
+ end
439
+
221
440
  def test_concurrent_decoding
222
441
  o = Outer.new
223
442
  o.items[0] = Inner.new
@@ -237,7 +456,8 @@ module BasicTest
237
456
  m = MapMessage.new(
238
457
  :map_string_int32 => {"a" => 1, "b" => 2},
239
458
  :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
240
- "b" => TestMessage2.new(:foo => 2)})
459
+ "b" => TestMessage2.new(:foo => 2)},
460
+ :map_string_enum => {"a" => :A, "b" => :B})
241
461
  m2 = MapMessage.decode(MapMessage.encode(m))
242
462
  assert m == m2
243
463
 
@@ -267,6 +487,14 @@ module BasicTest
267
487
  assert_match(/No such field: not_in_message/, e.message)
268
488
  end
269
489
 
490
+ #def test_json_quoted_string
491
+ # m = TestMessage.decode_json(%q(
492
+ # "optionalInt64": "1",,
493
+ # }))
494
+ # puts(m)
495
+ # assert_equal 1, m.optional_int32
496
+ #end
497
+
270
498
  def test_to_h
271
499
  m = TestMessage.new(:optional_bool => true, :optional_double => -10.100001, :optional_string => 'foo', :repeated_string => ['bar1', 'bar2'], :repeated_msg => [TestMessage2.new(:foo => 100)])
272
500
  expected_result = {
@@ -278,6 +506,8 @@ module BasicTest
278
506
  :optional_int32=>0,
279
507
  :optional_int64=>0,
280
508
  :optional_msg=>nil,
509
+ :optional_msg2=>nil,
510
+ :optional_proto2_submessage=>nil,
281
511
  :optional_string=>"foo",
282
512
  :optional_uint32=>0,
283
513
  :optional_uint64=>0,
@@ -298,10 +528,12 @@ module BasicTest
298
528
  m = MapMessage.new(
299
529
  :map_string_int32 => {"a" => 1, "b" => 2},
300
530
  :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
301
- "b" => TestMessage2.new(:foo => 2)})
531
+ "b" => TestMessage2.new(:foo => 2)},
532
+ :map_string_enum => {"a" => :A, "b" => :B})
302
533
  expected_result = {
303
534
  :map_string_int32 => {"a" => 1, "b" => 2},
304
- :map_string_msg => {"a" => {:foo => 1}, "b" => {:foo => 2}}
535
+ :map_string_msg => {"a" => {:foo => 1}, "b" => {:foo => 2}},
536
+ :map_string_enum => {"a" => :A, "b" => :B}
305
537
  }
306
538
  assert_equal expected_result, m.to_h
307
539
  end
@@ -311,26 +543,50 @@ module BasicTest
311
543
  # TODO: Fix JSON in JRuby version.
312
544
  return if RUBY_PLATFORM == "java"
313
545
  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
546
+ expected = {mapStringInt32: {a: 1}, mapStringMsg: {}, mapStringEnum: {}}
547
+ expected_preserve = {map_string_int32: {a: 1}, map_string_msg: {}, map_string_enum: {}}
548
+ assert_equal JSON.parse(MapMessage.encode_json(m, :emit_defaults=>true), :symbolize_names => true), expected
317
549
 
318
- json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true)
319
- assert JSON.parse(json, :symbolize_names => true) == expected_preserve
550
+ json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true, :emit_defaults=>true)
551
+ assert_equal JSON.parse(json, :symbolize_names => true), expected_preserve
320
552
 
321
553
  m2 = MapMessage.decode_json(MapMessage.encode_json(m))
322
- assert m == m2
554
+ assert_equal m, m2
323
555
  end
324
556
 
325
557
  def test_json_maps_emit_defaults_submsg
326
558
  # TODO: Fix JSON in JRuby version.
327
559
  return if RUBY_PLATFORM == "java"
328
- m = MapMessage.new(:map_string_msg => {"a" => TestMessage2.new})
329
- expected = {mapStringInt32: {}, mapStringMsg: {a: {foo: 0}}}
560
+ m = MapMessage.new(:map_string_msg => {"a" => TestMessage2.new(foo: 0)})
561
+ expected = {mapStringInt32: {}, mapStringMsg: {a: {foo: 0}}, mapStringEnum: {}}
330
562
 
331
563
  actual = MapMessage.encode_json(m, :emit_defaults => true)
332
564
 
333
- assert JSON.parse(actual, :symbolize_names => true) == expected
565
+ assert_equal JSON.parse(actual, :symbolize_names => true), expected
566
+ end
567
+
568
+ def test_json_emit_defaults_submsg
569
+ # TODO: Fix JSON in JRuby version.
570
+ return if RUBY_PLATFORM == "java"
571
+ m = TestSingularFields.new(singular_msg: proto_module::TestMessage2.new)
572
+
573
+ expected = {
574
+ singularInt32: 0,
575
+ singularInt64: "0",
576
+ singularUint32: 0,
577
+ singularUint64: "0",
578
+ singularBool: false,
579
+ singularFloat: 0,
580
+ singularDouble: 0,
581
+ singularString: "",
582
+ singularBytes: "",
583
+ singularMsg: {},
584
+ singularEnum: "Default",
585
+ }
586
+
587
+ actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true)
588
+
589
+ assert_equal expected, JSON.parse(actual, :symbolize_names => true)
334
590
  end
335
591
 
336
592
  def test_respond_to
@@ -351,11 +607,64 @@ module BasicTest
351
607
  assert nil != file_descriptor
352
608
  assert_equal "tests/basic_test.proto", file_descriptor.name
353
609
  assert_equal :proto3, file_descriptor.syntax
610
+ end
354
611
 
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
612
+ # Ruby 2.5 changed to raise FrozenError instead of RuntimeError
613
+ FrozenErrorType = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.5') ? RuntimeError : FrozenError
614
+
615
+ def test_map_freeze
616
+ m = proto_module::MapMessage.new
617
+ m.map_string_int32['a'] = 5
618
+ m.map_string_msg['b'] = proto_module::TestMessage2.new
619
+
620
+ m.map_string_int32.freeze
621
+ m.map_string_msg.freeze
622
+
623
+ assert m.map_string_int32.frozen?
624
+ assert m.map_string_msg.frozen?
625
+
626
+ assert_raise(FrozenErrorType) { m.map_string_int32['foo'] = 1 }
627
+ assert_raise(FrozenErrorType) { m.map_string_msg['bar'] = proto_module::TestMessage2.new }
628
+ assert_raise(FrozenErrorType) { m.map_string_int32.delete('a') }
629
+ assert_raise(FrozenErrorType) { m.map_string_int32.clear }
630
+ end
631
+
632
+ def test_map_length
633
+ m = proto_module::MapMessage.new
634
+ assert_equal 0, m.map_string_int32.length
635
+ assert_equal 0, m.map_string_msg.length
636
+ assert_equal 0, m.map_string_int32.size
637
+ assert_equal 0, m.map_string_msg.size
638
+
639
+ m.map_string_int32['a'] = 1
640
+ m.map_string_int32['b'] = 2
641
+ m.map_string_msg['a'] = proto_module::TestMessage2.new
642
+ assert_equal 2, m.map_string_int32.length
643
+ assert_equal 1, m.map_string_msg.length
644
+ assert_equal 2, m.map_string_int32.size
645
+ assert_equal 1, m.map_string_msg.size
646
+ end
647
+
648
+ def test_string_with_singleton_class_enabled
649
+ str = 'foobar'
650
+ # NOTE: Accessing a singleton class of an object changes its low level class representation
651
+ # as far as the C API's CLASS_OF() method concerned, exposing the issue
652
+ str.singleton_class
653
+ m = proto_module::TestMessage.new(
654
+ optional_string: str,
655
+ optional_bytes: str
656
+ )
657
+
658
+ assert_equal str, m.optional_string
659
+ assert_equal str, m.optional_bytes
660
+ end
661
+
662
+ def test_utf8
663
+ m = proto_module::TestMessage.new(
664
+ optional_string: "µpb",
665
+ )
666
+ m2 = proto_module::TestMessage.decode(proto_module::TestMessage.encode(m))
667
+ assert_equal m2, m
359
668
  end
360
669
  end
361
670
  end
File without changes
data/tests/stress.rb CHANGED
@@ -30,7 +30,7 @@ module StressTest
30
30
  100_000.times do
31
31
  mnew = TestMessage.decode(data)
32
32
  mnew = mnew.dup
33
- assert_equal mnew.inspect, m.inspect
33
+ assert_equal m.inspect, mnew.inspect
34
34
  assert TestMessage.encode(mnew) == data
35
35
  end
36
36
  end