google-protobuf 3.0.0 → 3.20.0

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

Potentially problematic release.


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

Files changed (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