google-protobuf 3.0.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 (46) hide show
  1. checksums.yaml +5 -5
  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 +760 -1243
  5. data/ext/google/protobuf_c/defs.h +107 -0
  6. data/ext/google/protobuf_c/extconf.rb +22 -4
  7. data/ext/google/protobuf_c/map.c +342 -450
  8. data/ext/google/protobuf_c/map.h +66 -0
  9. data/ext/google/protobuf_c/message.c +1108 -284
  10. data/ext/google/protobuf_c/message.h +104 -0
  11. data/ext/google/protobuf_c/protobuf.c +416 -51
  12. data/ext/google/protobuf_c/protobuf.h +53 -472
  13. data/ext/google/protobuf_c/repeated_field.c +318 -317
  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/protobuf/any_pb.rb +6 -4
  24. data/lib/google/protobuf/api_pb.rb +27 -24
  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 +6 -4
  28. data/lib/google/protobuf/empty_pb.rb +4 -2
  29. data/lib/google/protobuf/field_mask_pb.rb +5 -3
  30. data/lib/google/protobuf/message_exts.rb +4 -4
  31. data/lib/google/protobuf/repeated_field.rb +4 -4
  32. data/lib/google/protobuf/source_context_pb.rb +5 -3
  33. data/lib/google/protobuf/struct_pb.rb +23 -21
  34. data/lib/google/protobuf/timestamp_pb.rb +6 -4
  35. data/lib/google/protobuf/type_pb.rb +77 -74
  36. data/lib/google/protobuf/well_known_types.rb +240 -0
  37. data/lib/google/protobuf/wrappers_pb.rb +37 -35
  38. data/lib/google/protobuf.rb +12 -9
  39. data/tests/basic.rb +489 -1001
  40. data/tests/generated_code_test.rb +6 -2
  41. data/tests/stress.rb +1 -1
  42. metadata +39 -34
  43. data/ext/google/protobuf_c/encode_decode.c +0 -1264
  44. data/ext/google/protobuf_c/storage.c +0 -893
  45. data/ext/google/protobuf_c/upb.c +0 -12812
  46. data/ext/google/protobuf_c/upb.h +0 -8569
data/tests/basic.rb CHANGED
@@ -1,6 +1,12 @@
1
1
  #!/usr/bin/ruby
2
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'
3
8
  require 'google/protobuf'
9
+ require 'json'
4
10
  require 'test/unit'
5
11
 
6
12
  # ------------- generated code --------------
@@ -8,620 +14,228 @@ require 'test/unit'
8
14
  module BasicTest
9
15
  pool = Google::Protobuf::DescriptorPool.new
10
16
  pool.build do
11
- add_message "Foo" do
12
- optional :bar, :message, 1, "Bar"
13
- repeated :baz, :message, 2, "Baz"
14
- end
15
-
16
- add_message "Bar" do
17
- optional :msg, :string, 1
18
- end
19
-
20
- add_message "Baz" do
21
- optional :msg, :string, 1
22
- end
23
-
24
- add_message "TestMessage" do
25
- optional :optional_int32, :int32, 1
26
- optional :optional_int64, :int64, 2
27
- optional :optional_uint32, :uint32, 3
28
- optional :optional_uint64, :uint64, 4
29
- optional :optional_bool, :bool, 5
30
- optional :optional_float, :float, 6
31
- optional :optional_double, :double, 7
32
- optional :optional_string, :string, 8
33
- optional :optional_bytes, :bytes, 9
34
- optional :optional_msg, :message, 10, "TestMessage2"
35
- optional :optional_enum, :enum, 11, "TestEnum"
36
-
37
- repeated :repeated_int32, :int32, 12
38
- repeated :repeated_int64, :int64, 13
39
- repeated :repeated_uint32, :uint32, 14
40
- repeated :repeated_uint64, :uint64, 15
41
- repeated :repeated_bool, :bool, 16
42
- repeated :repeated_float, :float, 17
43
- repeated :repeated_double, :double, 18
44
- repeated :repeated_string, :string, 19
45
- repeated :repeated_bytes, :bytes, 20
46
- repeated :repeated_msg, :message, 21, "TestMessage2"
47
- repeated :repeated_enum, :enum, 22, "TestEnum"
48
- end
49
- add_message "TestMessage2" do
50
- optional :foo, :int32, 1
51
- end
52
-
53
- add_message "Recursive1" do
54
- optional :foo, :message, 1, "Recursive2"
55
- end
56
- add_message "Recursive2" do
57
- optional :foo, :message, 1, "Recursive1"
58
- end
59
-
60
- add_enum "TestEnum" do
61
- value :Default, 0
62
- value :A, 1
63
- value :B, 2
64
- value :C, 3
65
- end
66
-
67
17
  add_message "BadFieldNames" do
68
18
  optional :dup, :int32, 1
69
19
  optional :class, :int32, 2
70
- optional :"a.b", :int32, 3
71
- end
72
-
73
- add_message "MapMessage" do
74
- map :map_string_int32, :string, :int32, 1
75
- map :map_string_msg, :string, :message, 2, "TestMessage2"
76
- end
77
- add_message "MapMessageWireEquiv" do
78
- repeated :map_string_int32, :message, 1, "MapMessageWireEquiv_entry1"
79
- repeated :map_string_msg, :message, 2, "MapMessageWireEquiv_entry2"
80
- end
81
- add_message "MapMessageWireEquiv_entry1" do
82
- optional :key, :string, 1
83
- optional :value, :int32, 2
84
- end
85
- add_message "MapMessageWireEquiv_entry2" do
86
- optional :key, :string, 1
87
- optional :value, :message, 2, "TestMessage2"
88
- end
89
-
90
- add_message "OneofMessage" do
91
- oneof :my_oneof do
92
- optional :a, :string, 1
93
- optional :b, :int32, 2
94
- optional :c, :message, 3, "TestMessage2"
95
- optional :d, :enum, 4, "TestEnum"
96
- end
97
20
  end
98
21
  end
99
22
 
100
- Foo = pool.lookup("Foo").msgclass
101
- Bar = pool.lookup("Bar").msgclass
102
- Baz = pool.lookup("Baz").msgclass
103
- TestMessage = pool.lookup("TestMessage").msgclass
104
- TestMessage2 = pool.lookup("TestMessage2").msgclass
105
- Recursive1 = pool.lookup("Recursive1").msgclass
106
- Recursive2 = pool.lookup("Recursive2").msgclass
107
- TestEnum = pool.lookup("TestEnum").enummodule
108
23
  BadFieldNames = pool.lookup("BadFieldNames").msgclass
109
- MapMessage = pool.lookup("MapMessage").msgclass
110
- MapMessageWireEquiv = pool.lookup("MapMessageWireEquiv").msgclass
111
- MapMessageWireEquiv_entry1 =
112
- pool.lookup("MapMessageWireEquiv_entry1").msgclass
113
- MapMessageWireEquiv_entry2 =
114
- pool.lookup("MapMessageWireEquiv_entry2").msgclass
115
- OneofMessage = pool.lookup("OneofMessage").msgclass
116
24
 
117
25
  # ------------ test cases ---------------
118
26
 
119
27
  class MessageContainerTest < Test::Unit::TestCase
120
-
121
- def test_defaults
122
- m = TestMessage.new
123
- assert m.optional_int32 == 0
124
- assert m.optional_int64 == 0
125
- assert m.optional_uint32 == 0
126
- assert m.optional_uint64 == 0
127
- assert m.optional_bool == false
128
- assert m.optional_float == 0.0
129
- assert m.optional_double == 0.0
130
- assert m.optional_string == ""
131
- assert m.optional_bytes == ""
132
- assert m.optional_msg == nil
133
- assert m.optional_enum == :Default
134
- end
135
-
136
- def test_setters
137
- m = TestMessage.new
138
- m.optional_int32 = -42
139
- assert m.optional_int32 == -42
140
- m.optional_int64 = -0x1_0000_0000
141
- assert m.optional_int64 == -0x1_0000_0000
142
- m.optional_uint32 = 0x9000_0000
143
- assert m.optional_uint32 == 0x9000_0000
144
- m.optional_uint64 = 0x9000_0000_0000_0000
145
- assert m.optional_uint64 == 0x9000_0000_0000_0000
146
- m.optional_bool = true
147
- assert m.optional_bool == true
148
- m.optional_float = 0.5
149
- assert m.optional_float == 0.5
150
- m.optional_double = 0.5
151
- m.optional_string = "hello"
152
- assert m.optional_string == "hello"
153
- m.optional_bytes = "world".encode!('ASCII-8BIT')
154
- assert m.optional_bytes == "world"
155
- m.optional_msg = TestMessage2.new(:foo => 42)
156
- assert m.optional_msg == TestMessage2.new(:foo => 42)
157
- m.optional_msg = nil
158
- assert m.optional_msg == nil
159
- end
160
-
161
- def test_ctor_args
162
- m = TestMessage.new(:optional_int32 => -42,
163
- :optional_msg => TestMessage2.new,
164
- :optional_enum => :C,
165
- :repeated_string => ["hello", "there", "world"])
166
- assert m.optional_int32 == -42
167
- assert m.optional_msg.class == TestMessage2
168
- assert m.repeated_string.length == 3
169
- assert m.optional_enum == :C
170
- assert m.repeated_string[0] == "hello"
171
- assert m.repeated_string[1] == "there"
172
- assert m.repeated_string[2] == "world"
173
- end
174
-
175
- def test_inspect
176
- m = TestMessage.new(:optional_int32 => -42,
177
- :optional_enum => :A,
178
- :optional_msg => TestMessage2.new,
179
- :repeated_string => ["hello", "there", "world"])
180
- expected = '<BasicTest::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: <BasicTest::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: []>'
181
- assert_equal expected, m.inspect
182
- end
183
-
184
- def test_hash
185
- m1 = TestMessage.new(:optional_int32 => 42)
186
- m2 = TestMessage.new(:optional_int32 => 102)
187
- assert m1.hash != 0
188
- assert m2.hash != 0
189
- # relying on the randomness here -- if hash function changes and we are
190
- # unlucky enough to get a collision, then change the values above.
191
- assert m1.hash != m2.hash
192
- end
193
-
194
- def test_unknown_field_errors
195
- e = assert_raise NoMethodError do
196
- TestMessage.new.hello
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
197
43
  end
198
- assert_match(/hello/, e.message)
199
44
 
200
- e = assert_raise NoMethodError do
201
- TestMessage.new.hello = "world"
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
202
51
  end
203
- assert_match(/hello/, e.message)
204
- end
205
52
 
206
- def test_initialization_map_errors
207
- e = assert_raise ArgumentError do
208
- TestMessage.new(:hello => "world")
209
- end
210
- assert_match(/hello/, e.message)
53
+ outer = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("Outer").msgclass
211
54
 
212
- e = assert_raise ArgumentError do
213
- MapMessage.new(:map_string_int32 => "hello")
214
- end
215
- assert_equal e.message, "Expected Hash object as initializer value for map field 'map_string_int32'."
55
+ outer.new(
56
+ inners: []
57
+ )['inners'].to_s
216
58
 
217
- e = assert_raise ArgumentError do
218
- TestMessage.new(:repeated_uint32 => "hello")
59
+ assert_raise Google::Protobuf::TypeError do
60
+ outer.new(
61
+ inners: [nil]
62
+ ).to_s
219
63
  end
220
- assert_equal e.message, "Expected array as initializer value for repeated field 'repeated_uint32'."
221
64
  end
222
65
 
223
- def test_type_errors
224
- m = TestMessage.new
225
- assert_raise TypeError do
226
- m.optional_int32 = "hello"
227
- end
228
- assert_raise TypeError do
229
- m.optional_string = 42
230
- end
231
- assert_raise TypeError do
232
- m.optional_string = nil
233
- end
234
- assert_raise TypeError do
235
- m.optional_bool = 42
236
- end
237
- assert_raise TypeError do
238
- m.optional_msg = TestMessage.new # expects TestMessage2
239
- end
240
-
241
- assert_raise TypeError do
242
- m.repeated_int32 = [] # needs RepeatedField
243
- end
244
-
245
- assert_raise TypeError do
246
- m.repeated_int32.push "hello"
247
- end
248
-
249
- assert_raise TypeError do
250
- m.repeated_msg.push TestMessage.new
251
- end
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)
252
72
  end
253
73
 
254
- def test_string_encoding
255
- m = TestMessage.new
256
-
257
- # Assigning a normal (ASCII or UTF8) string to a bytes field, or
258
- # ASCII-8BIT to a string field will convert to the proper encoding.
259
- m.optional_bytes = "Test string ASCII".encode!('ASCII')
260
- assert m.optional_bytes.frozen?
261
- assert_equal Encoding::ASCII_8BIT, m.optional_bytes.encoding
262
- assert_equal "Test string ASCII", m.optional_bytes
263
-
264
- assert_raise Encoding::UndefinedConversionError do
265
- m.optional_bytes = "Test string UTF-8 \u0100".encode!('UTF-8')
266
- end
267
-
268
- assert_raise Encoding::UndefinedConversionError do
269
- m.optional_string = ["FFFF"].pack('H*')
270
- end
271
-
272
- # "Ordinary" use case.
273
- m.optional_bytes = ["FFFF"].pack('H*')
274
- m.optional_string = "\u0100"
275
-
276
- # strings are immutable so we can't do this, but serialize should catch it.
277
- m.optional_string = "asdf".encode!('UTF-8')
278
- assert_raise RuntimeError do
279
- m.optional_string.encode!('ASCII-8BIT')
280
- end
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
281
80
  end
282
81
 
283
- def test_rptfield_int32
284
- l = Google::Protobuf::RepeatedField.new(:int32)
285
- assert l.count == 0
286
- l = Google::Protobuf::RepeatedField.new(:int32, [1, 2, 3])
287
- assert l.count == 3
288
- assert_equal [1, 2, 3], l
289
- assert_equal l, [1, 2, 3]
290
- l.push 4
291
- assert l == [1, 2, 3, 4]
292
- dst_list = []
293
- l.each { |val| dst_list.push val }
294
- assert dst_list == [1, 2, 3, 4]
295
- assert l.to_a == [1, 2, 3, 4]
296
- assert l[0] == 1
297
- assert l[3] == 4
298
- l[0] = 5
299
- assert l == [5, 2, 3, 4]
300
-
301
- l2 = l.dup
302
- assert l == l2
303
- assert l.object_id != l2.object_id
304
- l2.push 6
305
- assert l.count == 4
306
- assert l2.count == 5
307
-
308
- assert l.inspect == '[5, 2, 3, 4]'
309
-
310
- l.concat([7, 8, 9])
311
- assert l == [5, 2, 3, 4, 7, 8, 9]
312
- assert l.pop == 9
313
- assert l == [5, 2, 3, 4, 7, 8]
314
-
315
- assert_raise TypeError do
316
- m = TestMessage.new
317
- l.push m
318
- end
82
+ def test_has_field
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)
319
88
 
320
- m = TestMessage.new
321
- m.repeated_int32 = l
322
- assert m.repeated_int32 == [5, 2, 3, 4, 7, 8]
323
- assert m.repeated_int32.object_id == l.object_id
324
- l.push 42
325
- assert m.repeated_int32.pop == 42
326
-
327
- l3 = l + l.dup
328
- assert l3.count == l.count * 2
329
- l.count.times do |i|
330
- assert l3[i] == l[i]
331
- assert l3[l.count + i] == l[i]
89
+ m = OneofMessage.new
90
+ assert !m.has_my_oneof?
91
+ m.a = "foo"
92
+ assert m.has_my_oneof?
93
+ assert_raise NoMethodError do
94
+ m.has_a?
332
95
  end
96
+ assert_true OneofMessage.descriptor.lookup('a').has?(m)
333
97
 
334
- l.clear
335
- assert l.count == 0
336
- l += [1, 2, 3, 4]
337
- l.replace([5, 6, 7, 8])
338
- assert l == [5, 6, 7, 8]
339
-
340
- l4 = Google::Protobuf::RepeatedField.new(:int32)
341
- l4[5] = 42
342
- assert l4 == [0, 0, 0, 0, 0, 42]
343
-
344
- l4 << 100
345
- assert l4 == [0, 0, 0, 0, 0, 42, 100]
346
- l4 << 101 << 102
347
- assert l4 == [0, 0, 0, 0, 0, 42, 100, 101, 102]
348
- end
349
-
350
- def test_parent_rptfield
351
- #make sure we set the RepeatedField and can add to it
352
- m = TestMessage.new
353
- assert m.repeated_string == []
354
- m.repeated_string << 'ok'
355
- m.repeated_string.push('ok2')
356
- assert m.repeated_string == ['ok', 'ok2']
357
- m.repeated_string += ['ok3']
358
- assert m.repeated_string == ['ok', 'ok2', 'ok3']
359
- end
360
-
361
- def test_rptfield_msg
362
- l = Google::Protobuf::RepeatedField.new(:message, TestMessage)
363
- l.push TestMessage.new
364
- assert l.count == 1
365
- assert_raise TypeError do
366
- l.push TestMessage2.new
98
+ m = TestSingularFields.new
99
+ assert_raise NoMethodError do
100
+ m.has_singular_int32?
367
101
  end
368
- assert_raise TypeError do
369
- l.push 42
370
- end
371
-
372
- l2 = l.dup
373
- assert l2[0] == l[0]
374
- assert l2[0].object_id == l[0].object_id
375
-
376
- l2 = Google::Protobuf.deep_copy(l)
377
- assert l2[0] == l[0]
378
- assert l2[0].object_id != l[0].object_id
379
-
380
- l3 = l + l2
381
- assert l3.count == 2
382
- assert l3[0] == l[0]
383
- assert l3[1] == l2[0]
384
- l3[0].optional_int32 = 1000
385
- assert l[0].optional_int32 == 1000
386
-
387
- new_msg = TestMessage.new(:optional_int32 => 200)
388
- l4 = l + [new_msg]
389
- assert l4.count == 2
390
- new_msg.optional_int32 = 1000
391
- assert l4[1].optional_int32 == 1000
392
- end
393
-
394
- def test_rptfield_enum
395
- l = Google::Protobuf::RepeatedField.new(:enum, TestEnum)
396
- l.push :A
397
- l.push :B
398
- l.push :C
399
- assert l.count == 3
400
- assert_raise RangeError do
401
- l.push :D
102
+ assert_raise ArgumentError do
103
+ TestSingularFields.descriptor.lookup('singular_int32').has?(m)
402
104
  end
403
- assert l[0] == :A
404
-
405
- l.push 4
406
- assert l[3] == 4
407
- end
408
105
 
409
- def test_rptfield_initialize
410
- assert_raise ArgumentError do
411
- l = Google::Protobuf::RepeatedField.new
106
+ assert_raise NoMethodError do
107
+ m.has_singular_string?
412
108
  end
413
109
  assert_raise ArgumentError do
414
- l = Google::Protobuf::RepeatedField.new(:message)
110
+ TestSingularFields.descriptor.lookup('singular_string').has?(m)
415
111
  end
416
- assert_raise ArgumentError do
417
- l = Google::Protobuf::RepeatedField.new([1, 2, 3])
112
+
113
+ assert_raise NoMethodError do
114
+ m.has_singular_bool?
418
115
  end
419
116
  assert_raise ArgumentError do
420
- l = Google::Protobuf::RepeatedField.new(:message, [TestMessage2.new])
117
+ TestSingularFields.descriptor.lookup('singular_bool').has?(m)
421
118
  end
422
- end
423
119
 
424
- def test_rptfield_array_ducktyping
425
- l = Google::Protobuf::RepeatedField.new(:int32)
426
- length_methods = %w(count length size)
427
- length_methods.each do |lm|
428
- assert l.send(lm) == 0
429
- end
430
- # out of bounds returns a nil
431
- assert l[0] == nil
432
- assert l[1] == nil
433
- assert l[-1] == nil
434
- l.push 4
435
- length_methods.each do |lm|
436
- assert l.send(lm) == 1
120
+ m = TestMessage.new
121
+ assert_raise NoMethodError do
122
+ m.has_repeated_msg?
437
123
  end
438
- assert l[0] == 4
439
- assert l[1] == nil
440
- assert l[-1] == 4
441
- assert l[-2] == nil
442
-
443
- l.push 2
444
- length_methods.each do |lm|
445
- assert l.send(lm) == 2
124
+ assert_raise ArgumentError do
125
+ TestMessage.descriptor.lookup('repeated_msg').has?(m)
446
126
  end
447
- assert l[0] == 4
448
- assert l[1] == 2
449
- assert l[2] == nil
450
- assert l[-1] == 2
451
- assert l[-2] == 4
452
- assert l[-3] == nil
453
-
454
- #adding out of scope will backfill with empty objects
455
127
  end
456
128
 
457
- def test_map_basic
458
- # allowed key types:
459
- # :int32, :int64, :uint32, :uint64, :bool, :string, :bytes.
129
+ def test_no_presence
130
+ m = TestSingularFields.new
460
131
 
461
- m = Google::Protobuf::Map.new(:string, :int32)
462
- m["asdf"] = 1
463
- assert m["asdf"] == 1
464
- m["jkl;"] = 42
465
- assert m == { "jkl;" => 42, "asdf" => 1 }
466
- assert m.has_key?("asdf")
467
- assert !m.has_key?("qwerty")
468
- assert m.length == 2
132
+ # Explicitly setting to zero does not cause anything to be serialized.
133
+ m.singular_int32 = 0
134
+ assert_equal "", TestSingularFields.encode(m)
469
135
 
470
- m2 = m.dup
471
- assert m == m2
472
- assert m.hash != 0
473
- assert m.hash == m2.hash
136
+ # Explicitly setting to a non-zero value *does* cause serialization.
137
+ m.singular_int32 = 1
138
+ assert_not_equal "", TestSingularFields.encode(m)
474
139
 
475
- collected = {}
476
- m.each { |k,v| collected[v] = k }
477
- assert collected == { 42 => "jkl;", 1 => "asdf" }
140
+ m.singular_int32 = 0
141
+ assert_equal "", TestSingularFields.encode(m)
142
+ end
478
143
 
479
- assert m.delete("asdf") == 1
480
- assert !m.has_key?("asdf")
481
- assert m["asdf"] == nil
482
- assert !m.has_key?("asdf")
144
+ def test_set_clear_defaults
145
+ m = TestSingularFields.new
483
146
 
484
- # We only assert on inspect value when there is one map entry because the
485
- # order in which elements appear is unspecified (depends on the internal
486
- # hash function). We don't want a brittle test.
487
- assert m.inspect == "{\"jkl;\"=>42}"
147
+ m.singular_int32 = -42
148
+ assert_equal -42, m.singular_int32
149
+ m.clear_singular_int32
150
+ assert_equal 0, m.singular_int32
488
151
 
489
- assert m.keys == ["jkl;"]
490
- assert m.values == [42]
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
491
156
 
492
- m.clear
493
- assert m.length == 0
494
- assert m == {}
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
495
161
 
496
- assert_raise TypeError do
497
- m[1] = 1
498
- end
499
- assert_raise RangeError do
500
- m["asdf"] = 0x1_0000_0000
501
- end
502
- end
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?
503
173
 
504
- def test_map_ctor
505
- m = Google::Protobuf::Map.new(:string, :int32,
506
- {"a" => 1, "b" => 2, "c" => 3})
507
- assert m == {"a" => 1, "c" => 3, "b" => 2}
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
508
178
  end
509
179
 
510
- def test_map_keytypes
511
- m = Google::Protobuf::Map.new(:int32, :int32)
512
- m[1] = 42
513
- m[-1] = 42
514
- assert_raise RangeError do
515
- m[0x8000_0000] = 1
516
- end
517
- assert_raise TypeError do
518
- m["asdf"] = 1
519
- end
180
+ def test_import_proto2
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)
520
186
 
521
- m = Google::Protobuf::Map.new(:int64, :int32)
522
- m[0x1000_0000_0000_0000] = 1
523
- assert_raise RangeError do
524
- m[0x1_0000_0000_0000_0000] = 1
525
- end
526
- assert_raise TypeError do
527
- m["asdf"] = 1
528
- end
187
+ m.clear_optional_proto2_submessage
188
+ assert !m.has_optional_proto2_submessage?
189
+ end
529
190
 
530
- m = Google::Protobuf::Map.new(:uint32, :int32)
531
- m[0x8000_0000] = 1
532
- assert_raise RangeError do
533
- m[0x1_0000_0000] = 1
534
- end
535
- assert_raise RangeError do
536
- m[-1] = 1
537
- end
191
+ def test_clear_repeated_fields
192
+ m = TestMessage.new
538
193
 
539
- m = Google::Protobuf::Map.new(:uint64, :int32)
540
- m[0x8000_0000_0000_0000] = 1
541
- assert_raise RangeError do
542
- m[0x1_0000_0000_0000_0000] = 1
543
- end
544
- assert_raise RangeError do
545
- m[-1] = 1
546
- end
194
+ m.repeated_int32.push(1)
195
+ assert_equal [1], m.repeated_int32
196
+ m.clear_repeated_int32
197
+ assert_equal [], m.repeated_int32
547
198
 
548
- m = Google::Protobuf::Map.new(:bool, :int32)
549
- m[true] = 1
550
- m[false] = 2
551
- assert_raise TypeError do
552
- m[1] = 1
553
- end
554
- assert_raise TypeError do
555
- m["asdf"] = 1
556
- end
199
+ m.repeated_int32.push(1)
200
+ assert_equal [1], m.repeated_int32
201
+ TestMessage.descriptor.lookup('repeated_int32').clear(m)
202
+ assert_equal [], m.repeated_int32
557
203
 
558
- m = Google::Protobuf::Map.new(:string, :int32)
559
- m["asdf"] = 1
560
- assert_raise TypeError do
561
- m[1] = 1
562
- end
563
- assert_raise Encoding::UndefinedConversionError do
564
- bytestring = ["FFFF"].pack("H*")
565
- m[bytestring] = 1
566
- end
204
+ m = OneofMessage.new
205
+ m.a = "foo"
206
+ assert_equal "foo", m.a
207
+ assert m.has_my_oneof?
208
+ assert_equal :a, m.my_oneof
209
+ m.clear_a
210
+ assert !m.has_my_oneof?
567
211
 
568
- m = Google::Protobuf::Map.new(:bytes, :int32)
569
- bytestring = ["FFFF"].pack("H*")
570
- m[bytestring] = 1
571
- # Allowed -- we will automatically convert to ASCII-8BIT.
572
- m["asdf"] = 1
573
- assert_raise TypeError do
574
- m[1] = 1
575
- end
212
+ m.a = "foobar"
213
+ assert m.has_my_oneof?
214
+ m.clear_my_oneof
215
+ assert !m.has_my_oneof?
216
+
217
+ m.a = "bar"
218
+ assert_equal "bar", m.a
219
+ assert m.has_my_oneof?
220
+ OneofMessage.descriptor.lookup('a').clear(m)
221
+ assert !m.has_my_oneof?
576
222
  end
577
223
 
578
- def test_map_msg_enum_valuetypes
579
- m = Google::Protobuf::Map.new(:string, :message, TestMessage)
580
- m["asdf"] = TestMessage.new
581
- assert_raise TypeError do
582
- m["jkl;"] = TestMessage2.new
224
+ def test_initialization_map_errors
225
+ e = assert_raise ArgumentError do
226
+ TestMessage.new(:hello => "world")
583
227
  end
228
+ assert_match(/hello/, e.message)
584
229
 
585
- m = Google::Protobuf::Map.new(
586
- :string, :message, TestMessage,
587
- { "a" => TestMessage.new(:optional_int32 => 42),
588
- "b" => TestMessage.new(:optional_int32 => 84) })
589
- assert m.length == 2
590
- assert m.values.map{|msg| msg.optional_int32}.sort == [42, 84]
591
-
592
- m = Google::Protobuf::Map.new(:string, :enum, TestEnum,
593
- { "x" => :A, "y" => :B, "z" => :C })
594
- assert m.length == 3
595
- assert m["z"] == :C
596
- m["z"] = 2
597
- assert m["z"] == :B
598
- m["z"] = 4
599
- assert m["z"] == 4
600
- assert_raise RangeError do
601
- m["z"] = :Z
602
- end
603
- assert_raise TypeError do
604
- m["z"] = "z"
230
+ e = assert_raise ArgumentError do
231
+ MapMessage.new(:map_string_int32 => "hello")
605
232
  end
606
- end
607
-
608
- def test_map_dup_deep_copy
609
- m = Google::Protobuf::Map.new(
610
- :string, :message, TestMessage,
611
- { "a" => TestMessage.new(:optional_int32 => 42),
612
- "b" => TestMessage.new(:optional_int32 => 84) })
613
-
614
- m2 = m.dup
615
- assert m == m2
616
- assert m.object_id != m2.object_id
617
- assert m["a"].object_id == m2["a"].object_id
618
- assert m["b"].object_id == m2["b"].object_id
233
+ assert_equal e.message, "Expected Hash object as initializer value for map field 'map_string_int32' (given String)."
619
234
 
620
- m2 = Google::Protobuf.deep_copy(m)
621
- assert m == m2
622
- assert m.object_id != m2.object_id
623
- assert m["a"].object_id != m2["a"].object_id
624
- assert m["b"].object_id != m2["b"].object_id
235
+ e = assert_raise ArgumentError do
236
+ TestMessage.new(:repeated_uint32 => "hello")
237
+ end
238
+ assert_equal e.message, "Expected array as initializer value for repeated field 'repeated_uint32' (given String)."
625
239
  end
626
240
 
627
241
  def test_map_field
@@ -632,10 +246,12 @@ module BasicTest
632
246
  m = MapMessage.new(
633
247
  :map_string_int32 => {"a" => 1, "b" => 2},
634
248
  :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
635
- "b" => TestMessage2.new(:foo => 2)})
249
+ "b" => TestMessage2.new(:foo => 2)},
250
+ :map_string_enum => {"a" => :A, "b" => :B})
636
251
  assert m.map_string_int32.keys.sort == ["a", "b"]
637
252
  assert m.map_string_int32["a"] == 1
638
253
  assert m.map_string_msg["b"].foo == 2
254
+ assert m.map_string_enum["a"] == :A
639
255
 
640
256
  m.map_string_int32["c"] = 3
641
257
  assert m.map_string_int32["c"] == 3
@@ -645,30 +261,203 @@ module BasicTest
645
261
  m.map_string_msg.delete("c")
646
262
  assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) }
647
263
 
648
- assert_raise TypeError do
264
+ assert_raise Google::Protobuf::TypeError do
649
265
  m.map_string_msg["e"] = TestMessage.new # wrong value type
650
266
  end
651
267
  # ensure nothing was added by the above
652
268
  assert m.map_string_msg == { "a" => TestMessage2.new(:foo => 1) }
653
269
 
654
270
  m.map_string_int32 = Google::Protobuf::Map.new(:string, :int32)
655
- assert_raise TypeError do
271
+ assert_raise Google::Protobuf::TypeError do
656
272
  m.map_string_int32 = Google::Protobuf::Map.new(:string, :int64)
657
273
  end
658
- assert_raise TypeError do
274
+ assert_raise Google::Protobuf::TypeError do
659
275
  m.map_string_int32 = {}
660
276
  end
661
277
 
662
- assert_raise TypeError do
278
+ assert_raise Google::Protobuf::TypeError do
663
279
  m = MapMessage.new(:map_string_int32 => { 1 => "I am not a number" })
664
280
  end
665
281
  end
666
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
+
297
+ def test_map_inspect
298
+ m = MapMessage.new(
299
+ :map_string_int32 => {"a" => 1, "b" => 2},
300
+ :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
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}"
309
+ end
310
+
311
+ def test_map_corruption
312
+ # This pattern led to a crash in a previous version of upb/protobuf.
313
+ m = MapMessage.new(map_string_int32: { "aaa" => 1 })
314
+ m.map_string_int32['podid'] = 2
315
+ m.map_string_int32['aaa'] = 3
316
+ end
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
+
440
+ def test_concurrent_decoding
441
+ o = Outer.new
442
+ o.items[0] = Inner.new
443
+ raw = Outer.encode(o)
444
+
445
+ thds = 2.times.map do
446
+ Thread.new do
447
+ 100000.times do
448
+ assert_equal o, Outer.decode(raw)
449
+ end
450
+ end
451
+ end
452
+ thds.map(&:join)
453
+ end
454
+
667
455
  def test_map_encode_decode
668
456
  m = MapMessage.new(
669
457
  :map_string_int32 => {"a" => 1, "b" => 2},
670
458
  :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
671
- "b" => TestMessage2.new(:foo => 2)})
459
+ "b" => TestMessage2.new(:foo => 2)},
460
+ :map_string_enum => {"a" => :A, "b" => :B})
672
461
  m2 = MapMessage.decode(MapMessage.encode(m))
673
462
  assert m == m2
674
463
 
@@ -685,213 +474,29 @@ module BasicTest
685
474
  "b" => TestMessage2.new(:foo => 2)}
686
475
  end
687
476
 
688
- def test_oneof_descriptors
689
- d = OneofMessage.descriptor
690
- o = d.lookup_oneof("my_oneof")
691
- assert o != nil
692
- assert o.class == Google::Protobuf::OneofDescriptor
693
- assert o.name == "my_oneof"
694
- oneof_count = 0
695
- d.each_oneof{ |oneof|
696
- oneof_count += 1
697
- assert oneof == o
698
- }
699
- assert oneof_count == 1
700
- assert o.count == 4
701
- field_names = o.map{|f| f.name}.sort
702
- assert field_names == ["a", "b", "c", "d"]
703
- end
704
-
705
- def test_oneof
706
- d = OneofMessage.new
707
- assert d.a == ""
708
- assert d.b == 0
709
- assert d.c == nil
710
- assert d.d == :Default
711
- assert d.my_oneof == nil
712
-
713
- d.a = "hi"
714
- assert d.a == "hi"
715
- assert d.b == 0
716
- assert d.c == nil
717
- assert d.d == :Default
718
- assert d.my_oneof == :a
719
-
720
- d.b = 42
721
- assert d.a == ""
722
- assert d.b == 42
723
- assert d.c == nil
724
- assert d.d == :Default
725
- assert d.my_oneof == :b
726
-
727
- d.c = TestMessage2.new(:foo => 100)
728
- assert d.a == ""
729
- assert d.b == 0
730
- assert d.c.foo == 100
731
- assert d.d == :Default
732
- assert d.my_oneof == :c
733
-
734
- d.d = :C
735
- assert d.a == ""
736
- assert d.b == 0
737
- assert d.c == nil
738
- assert d.d == :C
739
- assert d.my_oneof == :d
740
-
741
- d2 = OneofMessage.decode(OneofMessage.encode(d))
742
- assert d2 == d
743
-
744
- encoded_field_a = OneofMessage.encode(OneofMessage.new(:a => "string"))
745
- encoded_field_b = OneofMessage.encode(OneofMessage.new(:b => 1000))
746
- encoded_field_c = OneofMessage.encode(
747
- OneofMessage.new(:c => TestMessage2.new(:foo => 1)))
748
- encoded_field_d = OneofMessage.encode(OneofMessage.new(:d => :B))
749
-
750
- d3 = OneofMessage.decode(
751
- encoded_field_c + encoded_field_a + encoded_field_d)
752
- assert d3.a == ""
753
- assert d3.b == 0
754
- assert d3.c == nil
755
- assert d3.d == :B
756
-
757
- d4 = OneofMessage.decode(
758
- encoded_field_c + encoded_field_a + encoded_field_d +
759
- encoded_field_c)
760
- assert d4.a == ""
761
- assert d4.b == 0
762
- assert d4.c.foo == 1
763
- assert d4.d == :Default
764
-
765
- d5 = OneofMessage.new(:a => "hello")
766
- assert d5.a == "hello"
767
- d5.a = nil
768
- assert d5.a == ""
769
- assert OneofMessage.encode(d5) == ''
770
- assert d5.my_oneof == nil
771
- end
772
-
773
- def test_enum_field
774
- m = TestMessage.new
775
- assert m.optional_enum == :Default
776
- m.optional_enum = :A
777
- assert m.optional_enum == :A
778
- assert_raise RangeError do
779
- m.optional_enum = :ASDF
780
- end
781
- m.optional_enum = 1
782
- assert m.optional_enum == :A
783
- m.optional_enum = 100
784
- assert m.optional_enum == 100
785
- end
786
-
787
- def test_dup
788
- m = TestMessage.new
789
- m.optional_string = "hello"
790
- m.optional_int32 = 42
791
- tm1 = TestMessage2.new(:foo => 100)
792
- tm2 = TestMessage2.new(:foo => 200)
793
- m.repeated_msg.push tm1
794
- assert m.repeated_msg[-1] == tm1
795
- m.repeated_msg.push tm2
796
- assert m.repeated_msg[-1] == tm2
797
- m2 = m.dup
798
- assert m == m2
799
- m.optional_int32 += 1
800
- assert m != m2
801
- assert m.repeated_msg[0] == m2.repeated_msg[0]
802
- assert m.repeated_msg[0].object_id == m2.repeated_msg[0].object_id
803
- end
804
-
805
- def test_deep_copy
806
- m = TestMessage.new(:optional_int32 => 42,
807
- :repeated_msg => [TestMessage2.new(:foo => 100)])
808
- m2 = Google::Protobuf.deep_copy(m)
809
- assert m == m2
810
- assert m.repeated_msg == m2.repeated_msg
811
- assert m.repeated_msg.object_id != m2.repeated_msg.object_id
812
- assert m.repeated_msg[0].object_id != m2.repeated_msg[0].object_id
813
- end
814
-
815
- def test_eq
816
- m = TestMessage.new(:optional_int32 => 42,
817
- :repeated_int32 => [1, 2, 3])
818
- m2 = TestMessage.new(:optional_int32 => 43,
819
- :repeated_int32 => [1, 2, 3])
820
- assert m != m2
821
- end
477
+ def test_protobuf_decode_json_ignore_unknown_fields
478
+ m = TestMessage.decode_json({
479
+ optional_string: "foo",
480
+ not_in_message: "some_value"
481
+ }.to_json, { ignore_unknown_fields: true })
822
482
 
823
- def test_enum_lookup
824
- assert TestEnum::A == 1
825
- assert TestEnum::B == 2
826
- assert TestEnum::C == 3
827
-
828
- assert TestEnum::lookup(1) == :A
829
- assert TestEnum::lookup(2) == :B
830
- assert TestEnum::lookup(3) == :C
831
-
832
- assert TestEnum::resolve(:A) == 1
833
- assert TestEnum::resolve(:B) == 2
834
- assert TestEnum::resolve(:C) == 3
835
- end
836
-
837
- def test_parse_serialize
838
- m = TestMessage.new(:optional_int32 => 42,
839
- :optional_string => "hello world",
840
- :optional_enum => :B,
841
- :repeated_string => ["a", "b", "c"],
842
- :repeated_int32 => [42, 43, 44],
843
- :repeated_enum => [:A, :B, :C, 100],
844
- :repeated_msg => [TestMessage2.new(:foo => 1),
845
- TestMessage2.new(:foo => 2)])
846
- data = TestMessage.encode m
847
- m2 = TestMessage.decode data
848
- assert m == m2
849
-
850
- data = Google::Protobuf.encode m
851
- m2 = Google::Protobuf.decode(TestMessage, data)
852
- assert m == m2
853
- end
854
-
855
- def test_encode_decode_helpers
856
- m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
857
- assert_equal 'foo', m.optional_string
858
- assert_equal ['bar1', 'bar2'], m.repeated_string
859
-
860
- json = m.to_json
861
- m2 = TestMessage.decode_json(json)
862
- assert_equal 'foo', m2.optional_string
863
- assert_equal ['bar1', 'bar2'], m2.repeated_string
864
- if RUBY_PLATFORM != "java"
865
- assert m2.optional_string.frozen?
866
- assert m2.repeated_string[0].frozen?
483
+ assert_equal m.optional_string, "foo"
484
+ e = assert_raise Google::Protobuf::ParseError do
485
+ TestMessage.decode_json({ not_in_message: "some_value" }.to_json)
867
486
  end
868
-
869
- proto = m.to_proto
870
- m2 = TestMessage.decode(proto)
871
- assert_equal 'foo', m2.optional_string
872
- assert_equal ['bar1', 'bar2'], m2.repeated_string
873
- end
874
-
875
- def test_protobuf_encode_decode_helpers
876
- m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
877
- encoded_msg = Google::Protobuf.encode(m)
878
- assert_equal m.to_proto, encoded_msg
879
-
880
- decoded_msg = Google::Protobuf.decode(TestMessage, encoded_msg)
881
- assert_equal TestMessage.decode(m.to_proto), decoded_msg
487
+ assert_match(/No such field: not_in_message/, e.message)
882
488
  end
883
489
 
884
- def test_protobuf_encode_decode_json_helpers
885
- m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
886
- encoded_msg = Google::Protobuf.encode_json(m)
887
- assert_equal m.to_json, encoded_msg
888
-
889
- decoded_msg = Google::Protobuf.decode_json(TestMessage, encoded_msg)
890
- assert_equal TestMessage.decode_json(m.to_json), decoded_msg
891
- end
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
892
497
 
893
498
  def test_to_h
894
- m = TestMessage.new(:optional_bool => true, :optional_double => -10.100001, :optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
499
+ m = TestMessage.new(:optional_bool => true, :optional_double => -10.100001, :optional_string => 'foo', :repeated_string => ['bar1', 'bar2'], :repeated_msg => [TestMessage2.new(:foo => 100)])
895
500
  expected_result = {
896
501
  :optional_bool=>true,
897
502
  :optional_bytes=>"",
@@ -901,6 +506,8 @@ module BasicTest
901
506
  :optional_int32=>0,
902
507
  :optional_int64=>0,
903
508
  :optional_msg=>nil,
509
+ :optional_msg2=>nil,
510
+ :optional_proto2_submessage=>nil,
904
511
  :optional_string=>"foo",
905
512
  :optional_uint32=>0,
906
513
  :optional_uint64=>0,
@@ -911,272 +518,153 @@ module BasicTest
911
518
  :repeated_float=>[],
912
519
  :repeated_int32=>[],
913
520
  :repeated_int64=>[],
914
- :repeated_msg=>[],
521
+ :repeated_msg=>[{:foo => 100}],
915
522
  :repeated_string=>["bar1", "bar2"],
916
523
  :repeated_uint32=>[],
917
524
  :repeated_uint64=>[]
918
525
  }
919
526
  assert_equal expected_result, m.to_h
920
- end
921
527
 
922
-
923
- def test_def_errors
924
- s = Google::Protobuf::DescriptorPool.new
925
- assert_raise TypeError do
926
- s.build do
927
- # enum with no default (integer value 0)
928
- add_enum "MyEnum" do
929
- value :A, 1
930
- end
931
- end
932
- end
933
- assert_raise TypeError do
934
- s.build do
935
- # message with required field (unsupported in proto3)
936
- add_message "MyMessage" do
937
- required :foo, :int32, 1
938
- end
939
- end
940
- end
941
- end
942
-
943
- def test_corecursive
944
- # just be sure that we can instantiate types with corecursive field-type
945
- # references.
946
- m = Recursive1.new(:foo => Recursive2.new(:foo => Recursive1.new))
947
- assert Recursive1.descriptor.lookup("foo").subtype ==
948
- Recursive2.descriptor
949
- assert Recursive2.descriptor.lookup("foo").subtype ==
950
- Recursive1.descriptor
951
-
952
- serialized = Recursive1.encode(m)
953
- m2 = Recursive1.decode(serialized)
954
- assert m == m2
955
- end
956
-
957
- def test_serialize_cycle
958
- m = Recursive1.new(:foo => Recursive2.new)
959
- m.foo.foo = m
960
- assert_raise RuntimeError do
961
- serialized = Recursive1.encode(m)
962
- end
963
- end
964
-
965
- def test_bad_field_names
966
- m = BadFieldNames.new(:dup => 1, :class => 2)
967
- m2 = m.dup
968
- assert m == m2
969
- assert m['dup'] == 1
970
- assert m['class'] == 2
971
- m['dup'] = 3
972
- assert m['dup'] == 3
973
- m['a.b'] = 4
974
- assert m['a.b'] == 4
528
+ m = MapMessage.new(
529
+ :map_string_int32 => {"a" => 1, "b" => 2},
530
+ :map_string_msg => {"a" => TestMessage2.new(:foo => 1),
531
+ "b" => TestMessage2.new(:foo => 2)},
532
+ :map_string_enum => {"a" => :A, "b" => :B})
533
+ expected_result = {
534
+ :map_string_int32 => {"a" => 1, "b" => 2},
535
+ :map_string_msg => {"a" => {:foo => 1}, "b" => {:foo => 2}},
536
+ :map_string_enum => {"a" => :A, "b" => :B}
537
+ }
538
+ assert_equal expected_result, m.to_h
975
539
  end
976
540
 
977
- def test_int_ranges
978
- m = TestMessage.new
979
541
 
980
- m.optional_int32 = 0
981
- m.optional_int32 = -0x8000_0000
982
- m.optional_int32 = +0x7fff_ffff
983
- m.optional_int32 = 1.0
984
- m.optional_int32 = -1.0
985
- m.optional_int32 = 2e9
986
- assert_raise RangeError do
987
- m.optional_int32 = -0x8000_0001
988
- end
989
- assert_raise RangeError do
990
- m.optional_int32 = +0x8000_0000
991
- end
992
- assert_raise RangeError do
993
- m.optional_int32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
994
- end
995
- assert_raise RangeError do
996
- m.optional_int32 = 1e12
997
- end
998
- assert_raise RangeError do
999
- m.optional_int32 = 1.5
1000
- end
1001
-
1002
- m.optional_uint32 = 0
1003
- m.optional_uint32 = +0xffff_ffff
1004
- m.optional_uint32 = 1.0
1005
- m.optional_uint32 = 4e9
1006
- assert_raise RangeError do
1007
- m.optional_uint32 = -1
1008
- end
1009
- assert_raise RangeError do
1010
- m.optional_uint32 = -1.5
1011
- end
1012
- assert_raise RangeError do
1013
- m.optional_uint32 = -1.5e12
1014
- end
1015
- assert_raise RangeError do
1016
- m.optional_uint32 = -0x1000_0000_0000_0000
1017
- end
1018
- assert_raise RangeError do
1019
- m.optional_uint32 = +0x1_0000_0000
1020
- end
1021
- assert_raise RangeError do
1022
- m.optional_uint32 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
1023
- end
1024
- assert_raise RangeError do
1025
- m.optional_uint32 = 1e12
1026
- end
1027
- assert_raise RangeError do
1028
- m.optional_uint32 = 1.5
1029
- end
1030
-
1031
- m.optional_int64 = 0
1032
- m.optional_int64 = -0x8000_0000_0000_0000
1033
- m.optional_int64 = +0x7fff_ffff_ffff_ffff
1034
- m.optional_int64 = 1.0
1035
- m.optional_int64 = -1.0
1036
- m.optional_int64 = 8e18
1037
- m.optional_int64 = -8e18
1038
- assert_raise RangeError do
1039
- m.optional_int64 = -0x8000_0000_0000_0001
1040
- end
1041
- assert_raise RangeError do
1042
- m.optional_int64 = +0x8000_0000_0000_0000
1043
- end
1044
- assert_raise RangeError do
1045
- m.optional_int64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
1046
- end
1047
- assert_raise RangeError do
1048
- m.optional_int64 = 1e50
1049
- end
1050
- assert_raise RangeError do
1051
- m.optional_int64 = 1.5
1052
- end
1053
-
1054
- m.optional_uint64 = 0
1055
- m.optional_uint64 = +0xffff_ffff_ffff_ffff
1056
- m.optional_uint64 = 1.0
1057
- m.optional_uint64 = 16e18
1058
- assert_raise RangeError do
1059
- m.optional_uint64 = -1
1060
- end
1061
- assert_raise RangeError do
1062
- m.optional_uint64 = -1.5
1063
- end
1064
- assert_raise RangeError do
1065
- m.optional_uint64 = -1.5e12
1066
- end
1067
- assert_raise RangeError do
1068
- m.optional_uint64 = -0x1_0000_0000_0000_0000
1069
- end
1070
- assert_raise RangeError do
1071
- m.optional_uint64 = +0x1_0000_0000_0000_0000
1072
- end
1073
- assert_raise RangeError do
1074
- m.optional_uint64 = +0x1000_0000_0000_0000_0000_0000 # force Bignum
1075
- end
1076
- assert_raise RangeError do
1077
- m.optional_uint64 = 1e50
1078
- end
1079
- assert_raise RangeError do
1080
- m.optional_uint64 = 1.5
1081
- end
1082
- end
542
+ def test_json_maps
543
+ # TODO: Fix JSON in JRuby version.
544
+ return if RUBY_PLATFORM == "java"
545
+ m = MapMessage.new(:map_string_int32 => {"a" => 1})
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
1083
549
 
1084
- def test_stress_test
1085
- m = TestMessage.new
1086
- m.optional_int32 = 42
1087
- m.optional_int64 = 0x100000000
1088
- m.optional_string = "hello world"
1089
- 10.times do m.repeated_msg.push TestMessage2.new(:foo => 42) end
1090
- 10.times do m.repeated_string.push "hello world" end
1091
-
1092
- data = TestMessage.encode(m)
1093
-
1094
- l = 0
1095
- 10_000.times do
1096
- m = TestMessage.decode(data)
1097
- data_new = TestMessage.encode(m)
1098
- assert data_new == data
1099
- data = data_new
1100
- end
1101
- end
550
+ json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true, :emit_defaults=>true)
551
+ assert_equal JSON.parse(json, :symbolize_names => true), expected_preserve
1102
552
 
1103
- def test_reflection
1104
- m = TestMessage.new(:optional_int32 => 1234)
1105
- msgdef = m.class.descriptor
1106
- assert msgdef.class == Google::Protobuf::Descriptor
1107
- assert msgdef.any? {|field| field.name == "optional_int32"}
1108
- optional_int32 = msgdef.lookup "optional_int32"
1109
- assert optional_int32.class == Google::Protobuf::FieldDescriptor
1110
- assert optional_int32 != nil
1111
- assert optional_int32.name == "optional_int32"
1112
- assert optional_int32.type == :int32
1113
- optional_int32.set(m, 5678)
1114
- assert m.optional_int32 == 5678
1115
- m.optional_int32 = 1000
1116
- assert optional_int32.get(m) == 1000
1117
-
1118
- optional_msg = msgdef.lookup "optional_msg"
1119
- assert optional_msg.subtype == TestMessage2.descriptor
1120
-
1121
- optional_msg.set(m, optional_msg.subtype.msgclass.new)
1122
-
1123
- assert msgdef.msgclass == TestMessage
1124
-
1125
- optional_enum = msgdef.lookup "optional_enum"
1126
- assert optional_enum.subtype == TestEnum.descriptor
1127
- assert optional_enum.subtype.class == Google::Protobuf::EnumDescriptor
1128
- optional_enum.subtype.each do |k, v|
1129
- # set with integer, check resolution to symbolic name
1130
- optional_enum.set(m, v)
1131
- assert optional_enum.get(m) == k
1132
- end
553
+ m2 = MapMessage.decode_json(MapMessage.encode_json(m))
554
+ assert_equal m, m2
1133
555
  end
1134
556
 
1135
- def test_json
557
+ def test_json_maps_emit_defaults_submsg
1136
558
  # TODO: Fix JSON in JRuby version.
1137
559
  return if RUBY_PLATFORM == "java"
1138
- m = TestMessage.new(:optional_int32 => 1234,
1139
- :optional_int64 => -0x1_0000_0000,
1140
- :optional_uint32 => 0x8000_0000,
1141
- :optional_uint64 => 0xffff_ffff_ffff_ffff,
1142
- :optional_bool => true,
1143
- :optional_float => 1.0,
1144
- :optional_double => -1e100,
1145
- :optional_string => "Test string",
1146
- :optional_bytes => ["FFFFFFFF"].pack('H*'),
1147
- :optional_msg => TestMessage2.new(:foo => 42),
1148
- :repeated_int32 => [1, 2, 3, 4],
1149
- :repeated_string => ["a", "b", "c"],
1150
- :repeated_bool => [true, false, true, false],
1151
- :repeated_msg => [TestMessage2.new(:foo => 1),
1152
- TestMessage2.new(:foo => 2)])
1153
-
1154
- json_text = TestMessage.encode_json(m)
1155
- m2 = TestMessage.decode_json(json_text)
1156
- assert m == m2
560
+ m = MapMessage.new(:map_string_msg => {"a" => TestMessage2.new(foo: 0)})
561
+ expected = {mapStringInt32: {}, mapStringMsg: {a: {foo: 0}}, mapStringEnum: {}}
562
+
563
+ actual = MapMessage.encode_json(m, :emit_defaults => true)
1157
564
 
1158
- # Crash case from GitHub issue 283.
1159
- bar = Bar.new(msg: "bar")
1160
- baz1 = Baz.new(msg: "baz")
1161
- baz2 = Baz.new(msg: "quux")
1162
- Foo.encode_json(Foo.new)
1163
- Foo.encode_json(Foo.new(bar: bar))
1164
- Foo.encode_json(Foo.new(bar: bar, baz: [baz1, baz2]))
565
+ assert_equal JSON.parse(actual, :symbolize_names => true), expected
1165
566
  end
1166
567
 
1167
- def test_json_maps
568
+ def test_json_emit_defaults_submsg
1168
569
  # TODO: Fix JSON in JRuby version.
1169
570
  return if RUBY_PLATFORM == "java"
1170
- m = MapMessage.new(:map_string_int32 => {"a" => 1})
1171
- expected = '{"mapStringInt32":{"a":1},"mapStringMsg":{}}'
1172
- expected_preserve = '{"map_string_int32":{"a":1},"map_string_msg":{}}'
1173
- assert MapMessage.encode_json(m) == expected
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
+ }
1174
586
 
1175
- json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true)
1176
- assert json == expected_preserve
587
+ actual = proto_module::TestMessage.encode_json(m, :emit_defaults => true)
1177
588
 
1178
- m2 = MapMessage.decode_json(MapMessage.encode_json(m))
1179
- assert m == m2
589
+ assert_equal expected, JSON.parse(actual, :symbolize_names => true)
590
+ end
591
+
592
+ def test_respond_to
593
+ # This test fails with JRuby 1.7.23, likely because of an old JRuby bug.
594
+ return if RUBY_PLATFORM == "java"
595
+ msg = MapMessage.new
596
+ assert msg.respond_to?(:map_string_int32)
597
+ assert !msg.respond_to?(:bacon)
598
+ end
599
+
600
+ def test_file_descriptor
601
+ file_descriptor = TestMessage.descriptor.file_descriptor
602
+ assert nil != file_descriptor
603
+ assert_equal "tests/basic_test.proto", file_descriptor.name
604
+ assert_equal :proto3, file_descriptor.syntax
605
+
606
+ file_descriptor = TestEnum.descriptor.file_descriptor
607
+ assert nil != file_descriptor
608
+ assert_equal "tests/basic_test.proto", file_descriptor.name
609
+ assert_equal :proto3, file_descriptor.syntax
610
+ end
611
+
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
1180
668
  end
1181
669
  end
1182
670
  end