protobuf-core 3.5.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.
Files changed (110) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +18 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +23 -0
  8. data/Rakefile +5 -0
  9. data/bin/protoc-gen-ruby +16 -0
  10. data/lib/protobuf.rb +27 -0
  11. data/lib/protobuf/code_generator.rb +44 -0
  12. data/lib/protobuf/core.rb +2 -0
  13. data/lib/protobuf/core/version.rb +5 -0
  14. data/lib/protobuf/decoder.rb +73 -0
  15. data/lib/protobuf/deprecation.rb +112 -0
  16. data/lib/protobuf/descriptors.rb +3 -0
  17. data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +54 -0
  18. data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +251 -0
  19. data/lib/protobuf/encoder.rb +67 -0
  20. data/lib/protobuf/enum.rb +303 -0
  21. data/lib/protobuf/exceptions.rb +9 -0
  22. data/lib/protobuf/field.rb +74 -0
  23. data/lib/protobuf/field/base_field.rb +267 -0
  24. data/lib/protobuf/field/bool_field.rb +59 -0
  25. data/lib/protobuf/field/bytes_field.rb +82 -0
  26. data/lib/protobuf/field/double_field.rb +25 -0
  27. data/lib/protobuf/field/enum_field.rb +68 -0
  28. data/lib/protobuf/field/field_array.rb +87 -0
  29. data/lib/protobuf/field/fixed32_field.rb +25 -0
  30. data/lib/protobuf/field/fixed64_field.rb +28 -0
  31. data/lib/protobuf/field/float_field.rb +41 -0
  32. data/lib/protobuf/field/int32_field.rb +21 -0
  33. data/lib/protobuf/field/int64_field.rb +21 -0
  34. data/lib/protobuf/field/integer_field.rb +23 -0
  35. data/lib/protobuf/field/message_field.rb +65 -0
  36. data/lib/protobuf/field/sfixed32_field.rb +27 -0
  37. data/lib/protobuf/field/sfixed64_field.rb +28 -0
  38. data/lib/protobuf/field/signed_integer_field.rb +29 -0
  39. data/lib/protobuf/field/sint32_field.rb +21 -0
  40. data/lib/protobuf/field/sint64_field.rb +21 -0
  41. data/lib/protobuf/field/string_field.rb +34 -0
  42. data/lib/protobuf/field/uint32_field.rb +21 -0
  43. data/lib/protobuf/field/uint64_field.rb +21 -0
  44. data/lib/protobuf/field/varint_field.rb +73 -0
  45. data/lib/protobuf/generators/base.rb +70 -0
  46. data/lib/protobuf/generators/enum_generator.rb +41 -0
  47. data/lib/protobuf/generators/extension_generator.rb +27 -0
  48. data/lib/protobuf/generators/field_generator.rb +131 -0
  49. data/lib/protobuf/generators/file_generator.rb +132 -0
  50. data/lib/protobuf/generators/group_generator.rb +105 -0
  51. data/lib/protobuf/generators/message_generator.rb +98 -0
  52. data/lib/protobuf/generators/printable.rb +160 -0
  53. data/lib/protobuf/logging.rb +39 -0
  54. data/lib/protobuf/message.rb +193 -0
  55. data/lib/protobuf/message/fields.rb +133 -0
  56. data/lib/protobuf/message/serialization.rb +89 -0
  57. data/lib/protobuf/optionable.rb +23 -0
  58. data/lib/protobuf/wire_type.rb +10 -0
  59. data/proto/dynamic_discovery.proto +44 -0
  60. data/proto/google/protobuf/compiler/plugin.proto +147 -0
  61. data/proto/google/protobuf/descriptor.proto +620 -0
  62. data/proto/rpc.proto +62 -0
  63. data/protobuf-core.gemspec +31 -0
  64. data/spec/bin/protoc-gen-ruby_spec.rb +23 -0
  65. data/spec/data/data.bin +3 -0
  66. data/spec/data/types.bin +0 -0
  67. data/spec/encoding/all_types_spec.rb +105 -0
  68. data/spec/encoding/extreme_values_spec.rb +0 -0
  69. data/spec/functional/class_inheritance_spec.rb +52 -0
  70. data/spec/functional/compile_and_require_spec.rb +29 -0
  71. data/spec/lib/protobuf/base_spec.rb +84 -0
  72. data/spec/lib/protobuf/code_generator_spec.rb +60 -0
  73. data/spec/lib/protobuf/enum_generator_spec.rb +73 -0
  74. data/spec/lib/protobuf/enum_spec.rb +265 -0
  75. data/spec/lib/protobuf/extension_generator_spec.rb +42 -0
  76. data/spec/lib/protobuf/field/bool_field_spec.rb +51 -0
  77. data/spec/lib/protobuf/field/field_array_spec.rb +69 -0
  78. data/spec/lib/protobuf/field/float_field_spec.rb +55 -0
  79. data/spec/lib/protobuf/field/int32_field_spec.rb +90 -0
  80. data/spec/lib/protobuf/field/string_field_spec.rb +45 -0
  81. data/spec/lib/protobuf/field_generator_spec.rb +102 -0
  82. data/spec/lib/protobuf/field_spec.rb +191 -0
  83. data/spec/lib/protobuf/file_generator_spec.rb +32 -0
  84. data/spec/lib/protobuf/message_generator_spec.rb +0 -0
  85. data/spec/lib/protobuf/message_spec.rb +526 -0
  86. data/spec/lib/protobuf/optionable_spec.rb +46 -0
  87. data/spec/lib/protobuf_spec.rb +45 -0
  88. data/spec/spec_helper.rb +9 -0
  89. data/spec/support/packed_field.rb +22 -0
  90. data/spec/support/test/all_types.data.bin +0 -0
  91. data/spec/support/test/all_types.data.txt +119 -0
  92. data/spec/support/test/bacon.proto +14 -0
  93. data/spec/support/test/defaults.pb.rb +27 -0
  94. data/spec/support/test/defaults.proto +9 -0
  95. data/spec/support/test/enum.pb.rb +61 -0
  96. data/spec/support/test/enum.proto +34 -0
  97. data/spec/support/test/extended.pb.rb +24 -0
  98. data/spec/support/test/extended.proto +10 -0
  99. data/spec/support/test/extreme_values.data.bin +0 -0
  100. data/spec/support/test/google_unittest.pb.rb +530 -0
  101. data/spec/support/test/google_unittest.proto +713 -0
  102. data/spec/support/test/google_unittest_import.pb.rb +39 -0
  103. data/spec/support/test/google_unittest_import.proto +64 -0
  104. data/spec/support/test/google_unittest_import_public.pb.rb +10 -0
  105. data/spec/support/test/google_unittest_import_public.proto +38 -0
  106. data/spec/support/test/multi_field_extensions.pb.rb +58 -0
  107. data/spec/support/test/multi_field_extensions.proto +33 -0
  108. data/spec/support/test/resource.pb.rb +106 -0
  109. data/spec/support/test/resource.proto +94 -0
  110. metadata +306 -0
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ require 'protobuf/generators/file_generator'
4
+
5
+ RSpec.describe ::Protobuf::Generators::FileGenerator do
6
+
7
+ let(:base_descriptor_fields) { { :name => 'test/foo.proto' } }
8
+ let(:descriptor_fields) { base_descriptor_fields }
9
+ let(:file_descriptor) { ::Google::Protobuf::FileDescriptorProto.new(descriptor_fields) }
10
+
11
+ subject { described_class.new(file_descriptor) }
12
+ specify { expect(subject.file_name).to eq('test/foo.pb.rb') }
13
+
14
+ describe '#print_import_requires' do
15
+ let(:descriptor_fields) do
16
+ base_descriptor_fields.merge(
17
+ :dependency => [
18
+ 'test/bar.proto',
19
+ 'test/baz.proto',
20
+ ],
21
+ )
22
+ end
23
+
24
+ it 'prints a ruby require for each dependency' do
25
+ expect(subject).to receive(:print_require).with('test/bar.pb')
26
+ expect(subject).to receive(:print_require).with('test/baz.pb')
27
+ subject.print_import_requires
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1,526 @@
1
+ # encoding: utf-8
2
+
3
+ require 'stringio'
4
+ require 'spec_helper'
5
+
6
+ RSpec.describe Protobuf::Message do
7
+
8
+ describe '.decode' do
9
+ let(:message) { ::Test::Resource.new(:name => "Jim") }
10
+
11
+ it 'creates a new message object decoded from the given bytes' do
12
+ expect(::Test::Resource.decode(message.encode)).to eq message
13
+ end
14
+
15
+ context 'with a new enum value' do
16
+ let(:older_message) do
17
+ Class.new(Protobuf::Message) do
18
+ enum_class = Class.new(::Protobuf::Enum) do
19
+ define :YAY, 1
20
+ end
21
+
22
+ optional enum_class, :enum_field, 1
23
+ repeated enum_class, :enum_list, 2
24
+ end
25
+ end
26
+
27
+ let(:newer_message) do
28
+ Class.new(Protobuf::Message) do
29
+ enum_class = Class.new(::Protobuf::Enum) do
30
+ define :YAY, 1
31
+ define :HOORAY, 2
32
+ end
33
+
34
+ optional enum_class, :enum_field, 1
35
+ repeated enum_class, :enum_list, 2
36
+ end
37
+ end
38
+
39
+ context 'with a singular field' do
40
+ it 'treats the field as if it was unset when decoding' do
41
+ newer = newer_message.new(:enum_field => :HOORAY).serialize
42
+
43
+ expect(older_message.decode(newer).enum_field!).to be_nil
44
+ end
45
+
46
+ it 'rejects an unknown value when using the constructor' do
47
+ expect { older_message.new(:enum_field => :HOORAY) }.to raise_error
48
+ end
49
+
50
+ it 'rejects an unknown value when the setter' do
51
+ older = older_message.new
52
+ expect { older.enum_field = :HOORAY }.to raise_error
53
+ end
54
+ end
55
+
56
+ context 'with a repeated field' do
57
+ it 'treats the field as if it was unset when decoding' do
58
+ newer = newer_message.new(:enum_list => [:HOORAY]).serialize
59
+
60
+ expect(older_message.decode(newer).enum_list).to eq([])
61
+ end
62
+
63
+ it 'rejects an unknown value when using the constructor' do
64
+ expect { older_message.new(:enum_list => [:HOORAY]) }.to raise_error
65
+ end
66
+
67
+ it 'rejects an unknown value when the setter' do
68
+ older = older_message.new
69
+ expect { older.enum_field = [:HOORAY] }.to raise_error
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ describe '.decode_from' do
76
+ let(:message) { ::Test::Resource.new(:name => "Jim") }
77
+
78
+ it 'creates a new message object decoded from the given byte stream' do
79
+ stream = ::StringIO.new(message.encode)
80
+ expect(::Test::Resource.decode_from(stream)).to eq message
81
+ end
82
+ end
83
+
84
+ describe 'defining a new field' do
85
+ context 'when defining a field with a tag that has already been used' do
86
+ it 'raises a TagCollisionError' do
87
+ expect do
88
+ Class.new(Protobuf::Message) do
89
+ optional ::Protobuf::Field::Int32Field, :foo, 1
90
+ optional ::Protobuf::Field::Int32Field, :bar, 1
91
+ end
92
+ end.to raise_error(Protobuf::TagCollisionError, /Field number 1 has already been used/)
93
+ end
94
+ end
95
+
96
+ context 'when defining an extension field with a tag that has already been used' do
97
+ it 'raises a TagCollisionError' do
98
+ expect do
99
+ Class.new(Protobuf::Message) do
100
+ extensions 100...110
101
+ optional ::Protobuf::Field::Int32Field, :foo, 100
102
+ optional ::Protobuf::Field::Int32Field, :bar, 100, :extension => true
103
+ end
104
+ end.to raise_error(Protobuf::TagCollisionError, /Field number 100 has already been used/)
105
+ end
106
+ end
107
+
108
+ context 'when defining a field with a name that has already been used' do
109
+ it 'raises a DuplicateFieldNameError' do
110
+ expect do
111
+ Class.new(Protobuf::Message) do
112
+ optional ::Protobuf::Field::Int32Field, :foo, 1
113
+ optional ::Protobuf::Field::Int32Field, :foo, 2
114
+ end
115
+ end.to raise_error(Protobuf::DuplicateFieldNameError, /Field name foo has already been used/)
116
+ end
117
+ end
118
+
119
+ context 'when defining an extension field with a name that has already been used' do
120
+ it 'raises a DuplicateFieldNameError' do
121
+ expect do
122
+ Class.new(Protobuf::Message) do
123
+ extensions 100...110
124
+ optional ::Protobuf::Field::Int32Field, :foo, 1
125
+ optional ::Protobuf::Field::Int32Field, :foo, 100, :extension => true
126
+ end
127
+ end.to raise_error(Protobuf::DuplicateFieldNameError, /Field name foo has already been used/)
128
+ end
129
+ end
130
+ end
131
+
132
+ describe '.encode' do
133
+ let(:values) { { :name => "Jim" } }
134
+
135
+ it 'creates a new message object with the given values and returns the encoded bytes' do
136
+ expect(::Test::Resource.encode(values)).to eq ::Test::Resource.new(values).encode
137
+ end
138
+ end
139
+
140
+ describe '#initialize' do
141
+ it "defaults to the first value listed in the enum's type definition" do
142
+ test_enum = Test::EnumTestMessage.new
143
+ expect(test_enum.non_default_enum).to eq(1)
144
+ end
145
+
146
+ it "defaults to a a value with a name" do
147
+ test_enum = Test::EnumTestMessage.new
148
+ expect(test_enum.non_default_enum.name).to eq(:ONE)
149
+ end
150
+
151
+ it "exposes the enum getter raw value through ! method" do
152
+ test_enum = Test::EnumTestMessage.new
153
+ expect(test_enum.non_default_enum!).to be_nil
154
+ end
155
+
156
+ it "exposes the enum getter raw value through ! method (when set)" do
157
+ test_enum = Test::EnumTestMessage.new
158
+ test_enum.non_default_enum = 1
159
+ expect(test_enum.non_default_enum!).to eq(1)
160
+ end
161
+
162
+ it "does not try to set attributes which have nil values" do
163
+ expect_any_instance_of(Test::EnumTestMessage).not_to receive("non_default_enum=")
164
+ Test::EnumTestMessage.new(:non_default_enum => nil)
165
+ end
166
+
167
+ it "takes a hash as an initialization argument" do
168
+ test_enum = Test::EnumTestMessage.new(:non_default_enum => 2)
169
+ expect(test_enum.non_default_enum).to eq(2)
170
+ end
171
+
172
+ it "initializes with an object that responds to #to_hash" do
173
+ hashie_object = OpenStruct.new(:to_hash => { :non_default_enum => 2 })
174
+ test_enum = Test::EnumTestMessage.new(hashie_object)
175
+ expect(test_enum.non_default_enum).to eq(2)
176
+ end
177
+
178
+ it "initializes with an object with a block" do
179
+ test_enum = Test::EnumTestMessage.new { |p| p.non_default_enum = 2 }
180
+ expect(test_enum.non_default_enum).to eq(2)
181
+ end
182
+
183
+ context 'ignoring unknown fields' do
184
+ before { ::Protobuf.ignore_unknown_fields = true }
185
+
186
+ context 'with valid fields' do
187
+ let(:values) { { :name => "Jim" } }
188
+
189
+ it "does not raise an error" do
190
+ expect { ::Test::Resource.new(values) }.to_not raise_error
191
+ end
192
+ end
193
+
194
+ context 'with non-existent field' do
195
+ let(:values) { { :name => "Jim", :othername => "invalid" } }
196
+
197
+ it "does not raise an error" do
198
+ expect { ::Test::Resource.new(values) }.to_not raise_error
199
+ end
200
+ end
201
+ end
202
+
203
+ context 'not ignoring unknown fields' do
204
+ before { ::Protobuf.ignore_unknown_fields = false }
205
+ after { ::Protobuf.ignore_unknown_fields = true }
206
+
207
+ context 'with valid fields' do
208
+ let(:values) { { :name => "Jim" } }
209
+
210
+ it "does not raise an error" do
211
+ expect { ::Test::Resource.new(values) }.to_not raise_error
212
+ end
213
+ end
214
+
215
+ context 'with non-existent field' do
216
+ let(:values) { { :name => "Jim", :othername => "invalid" } }
217
+
218
+ it "raises an error and mentions the erroneous field" do
219
+ expect { ::Test::Resource.new(values) }.to raise_error(::Protobuf::FieldNotDefinedError, /othername/)
220
+ end
221
+
222
+ context 'with a nil value' do
223
+ let(:values) { { :name => "Jim", :othername => nil } }
224
+
225
+ it "raises an error and mentions the erroneous field" do
226
+ expect { ::Test::Resource.new(values) }.to raise_error(::Protobuf::FieldNotDefinedError, /othername/)
227
+ end
228
+ end
229
+ end
230
+ end
231
+ end
232
+
233
+ describe '#encode' do
234
+ context "encoding" do
235
+ it "accepts UTF-8 strings into string fields" do
236
+ message = ::Test::Resource.new(:name => "Kyle Redfearn\u0060s iPad")
237
+
238
+ expect { message.encode }.to_not raise_error
239
+ end
240
+
241
+ it "keeps utf-8 when utf-8 is input for string fields" do
242
+ name = 'my name💩'
243
+ name.force_encoding(Encoding::UTF_8)
244
+
245
+ message = ::Test::Resource.new(:name => name)
246
+ new_message = ::Test::Resource.decode(message.encode)
247
+ expect(new_message.name == name).to be true
248
+ end
249
+
250
+ it "trims binary when binary is input for string fields" do
251
+ name = "my name\xC3"
252
+ name.force_encoding(Encoding::BINARY)
253
+
254
+ message = ::Test::Resource.new(:name => name)
255
+ new_message = ::Test::Resource.decode(message.encode)
256
+ expect(new_message.name == "my name").to be true
257
+ end
258
+ end
259
+
260
+ context "when there's no value for a required field" do
261
+ let(:message) { ::Test::ResourceWithRequiredField.new }
262
+
263
+ it "raises a 'message not initialized' error" do
264
+ expect do
265
+ message.encode
266
+ end.to raise_error(Protobuf::SerializationError, /required/i)
267
+ end
268
+ end
269
+
270
+ context "repeated fields" do
271
+ let(:message) { ::Test::Resource.new(:name => "something") }
272
+
273
+ it "does not raise an error when repeated fields are []" do
274
+ expect do
275
+ message.repeated_enum = []
276
+ message.encode
277
+ end.to_not raise_error
278
+ end
279
+
280
+ it "sets the value to nil when empty array is passed" do
281
+ message.repeated_enum = []
282
+ expect(message.instance_variable_get("@values")[:repeated_enum]).to be_nil
283
+ end
284
+
285
+ it "does not compact the edit original array" do
286
+ a = [nil].freeze
287
+ message.repeated_enum = a
288
+ expect(message.repeated_enum).to eq([])
289
+ expect(a).to eq([nil].freeze)
290
+ end
291
+
292
+ it "compacts the set array" do
293
+ message.repeated_enum = [nil]
294
+ expect(message.repeated_enum).to eq([])
295
+ end
296
+
297
+ it "raises TypeError when a non-array replaces it" do
298
+ expect do
299
+ message.repeated_enum = 2
300
+ end.to raise_error(/value of type/)
301
+ end
302
+ end
303
+ end
304
+
305
+ describe "boolean predicate methods" do
306
+ subject { Test::ResourceFindRequest.new(:name => "resource") }
307
+
308
+ it { is_expected.to respond_to(:active?) }
309
+
310
+ it "sets the predicate to true when the boolean value is true" do
311
+ subject.active = true
312
+ expect(subject.active?).to be true
313
+ end
314
+
315
+ it "sets the predicate to false when the boolean value is false" do
316
+ subject.active = false
317
+ expect(subject.active?).to be false
318
+ end
319
+
320
+ it "does not put predicate methods on non-boolean fields" do
321
+ expect(Test::ResourceFindRequest.new(:name => "resource")).to_not respond_to(:name?)
322
+ end
323
+ end
324
+
325
+ describe "#respond_to_and_has?" do
326
+ subject { Test::EnumTestMessage.new(:non_default_enum => 2) }
327
+
328
+ it "is false when the message does not have the field" do
329
+ expect(subject.respond_to_and_has?(:other_field)).to be false
330
+ end
331
+
332
+ it "is true when the message has the field" do
333
+ expect(subject.respond_to_and_has?(:non_default_enum)).to be true
334
+ end
335
+ end
336
+
337
+ describe "#respond_to_has_and_present?" do
338
+ subject { Test::EnumTestMessage.new(:non_default_enum => 2) }
339
+
340
+ it "is false when the message does not have the field" do
341
+ expect(subject.respond_to_and_has_and_present?(:other_field)).to be false
342
+ end
343
+
344
+ it "is false when the field is repeated and a value is not present" do
345
+ expect(subject.respond_to_and_has_and_present?(:repeated_enums)).to be false
346
+ end
347
+
348
+ it "is false when the field is repeated and the value is empty array" do
349
+ subject.repeated_enums = []
350
+ expect(subject.respond_to_and_has_and_present?(:repeated_enums)).to be false
351
+ end
352
+
353
+ it "is true when the field is repeated and a value is present" do
354
+ subject.repeated_enums = [2]
355
+ expect(subject.respond_to_and_has_and_present?(:repeated_enums)).to be true
356
+ end
357
+
358
+ it "is true when the message has the field" do
359
+ expect(subject.respond_to_and_has_and_present?(:non_default_enum)).to be true
360
+ end
361
+
362
+ context "#API" do
363
+ subject { Test::EnumTestMessage.new(:non_default_enum => 2) }
364
+
365
+ specify { expect(subject).to respond_to(:respond_to_and_has_and_present?) }
366
+ specify { expect(subject).to respond_to(:responds_to_and_has_and_present?) }
367
+ specify { expect(subject).to respond_to(:responds_to_has?) }
368
+ specify { expect(subject).to respond_to(:respond_to_has?) }
369
+ specify { expect(subject).to respond_to(:respond_to_has_present?) }
370
+ specify { expect(subject).to respond_to(:responds_to_has_present?) }
371
+ specify { expect(subject).to respond_to(:respond_to_and_has_present?) }
372
+ specify { expect(subject).to respond_to(:responds_to_and_has_present?) }
373
+ end
374
+
375
+ end
376
+
377
+ describe '#inspect' do
378
+ let(:klass) do
379
+ Class.new(Protobuf::Message) do |klass|
380
+ enum_class = Class.new(Protobuf::Enum) do
381
+ define :YAY, 1
382
+ end
383
+
384
+ klass.const_set(:EnumKlass, enum_class)
385
+
386
+ optional :string, :name, 1
387
+ repeated :int32, :counts, 2
388
+ optional enum_class, :enum, 3
389
+ end
390
+ end
391
+
392
+ before { stub_const('MyMessage', klass) }
393
+
394
+ it 'lists the fields' do
395
+ proto = klass.new(:name => 'wooo', :counts => [1, 2, 3], :enum => klass::EnumKlass::YAY)
396
+ expect(proto.inspect).to eq('#<MyMessage name="wooo" counts=[1, 2, 3] enum=#<Protobuf::Enum(MyMessage::EnumKlass)::YAY=1>>')
397
+ end
398
+ end
399
+
400
+ describe '#to_hash' do
401
+ context 'generating values for an ENUM field' do
402
+ it 'converts the enum to its tag representation' do
403
+ hash = Test::EnumTestMessage.new(:non_default_enum => :TWO).to_hash
404
+ expect(hash).to eq(:non_default_enum => 2)
405
+ end
406
+
407
+ it 'does not populate default values' do
408
+ hash = Test::EnumTestMessage.new.to_hash
409
+ expect(hash).to eq({})
410
+ end
411
+
412
+ it 'converts repeated enum fields to an array of the tags' do
413
+ hash = Test::EnumTestMessage.new(:repeated_enums => [:ONE, :TWO, :TWO, :ONE]).to_hash
414
+ expect(hash).to eq(:repeated_enums => [1, 2, 2, 1])
415
+ end
416
+ end
417
+
418
+ context 'generating values for a Message field' do
419
+ it 'recursively hashes field messages' do
420
+ hash = Test::Nested.new(:resource => { :name => 'Nested' }).to_hash
421
+ expect(hash).to eq(:resource => { :name => 'Nested' })
422
+ end
423
+
424
+ it 'recursively hashes a repeated set of messages' do
425
+ proto = Test::Nested.new(
426
+ :multiple_resources => [
427
+ Test::Resource.new(:name => 'Resource 1'),
428
+ Test::Resource.new(:name => 'Resource 2'),
429
+ ],
430
+ )
431
+
432
+ expect(proto.to_hash).to eq(
433
+ :multiple_resources => [
434
+ { :name => 'Resource 1' },
435
+ { :name => 'Resource 2' },
436
+ ],
437
+ )
438
+ end
439
+ end
440
+ end
441
+
442
+ describe '#to_json' do
443
+ subject do
444
+ ::Test::ResourceFindRequest.new(:name => 'Test Name', :active => false)
445
+ end
446
+
447
+ specify { expect(subject.to_json).to eq '{"name":"Test Name","active":false}' }
448
+ end
449
+
450
+ describe '.to_json' do
451
+ it 'returns the class name of the message for use in json encoding' do
452
+ expect do
453
+ ::Timeout.timeout(0.1) do
454
+ expect(::Test::Resource.to_json).to eq("Test::Resource")
455
+ end
456
+ end.not_to raise_error
457
+ end
458
+ end
459
+
460
+ describe "#define_setter" do
461
+ subject { ::Test::Resource.new }
462
+
463
+ it "allows string fields to be set to nil" do
464
+ expect { subject.name = nil }.to_not raise_error
465
+ end
466
+
467
+ it "does not allow string fields to be set to Numeric" do
468
+ expect { subject.name = 1 }.to raise_error(/name/)
469
+ end
470
+ end
471
+
472
+ describe '.get_extension_field' do
473
+ it 'fetches an extension field by its tag' do
474
+ field = ::Test::Resource.get_extension_field(100)
475
+ expect(field).to be_a(::Protobuf::Field::BoolField)
476
+ expect(field.tag).to eq(100)
477
+ expect(field.name).to eq(:ext_is_searchable)
478
+ expect(field).to be_extension
479
+ end
480
+
481
+ it 'fetches an extension field by its symbolized name' do
482
+ expect(::Test::Resource.get_extension_field(:ext_is_searchable)).to be_a(::Protobuf::Field::BoolField)
483
+ expect(::Test::Resource.get_extension_field('ext_is_searchable')).to be_a(::Protobuf::Field::BoolField)
484
+ end
485
+
486
+ it 'returns nil when attempting to get a non-extension field' do
487
+ expect(::Test::Resource.get_extension_field(1)).to be_nil
488
+ end
489
+
490
+ it 'returns nil when field is not found' do
491
+ expect(::Test::Resource.get_extension_field(-1)).to be_nil
492
+ expect(::Test::Resource.get_extension_field(nil)).to be_nil
493
+ end
494
+ end
495
+
496
+ describe '.get_field' do
497
+ it 'fetches a non-extension field by its tag' do
498
+ field = ::Test::Resource.get_field(1)
499
+ expect(field).to be_a(::Protobuf::Field::StringField)
500
+ expect(field.tag).to eq(1)
501
+ expect(field.name).to eq(:name)
502
+ expect(field).not_to be_extension
503
+ end
504
+
505
+ it 'fetches a non-extension field by its symbolized name' do
506
+ expect(::Test::Resource.get_field(:name)).to be_a(::Protobuf::Field::StringField)
507
+ expect(::Test::Resource.get_field('name')).to be_a(::Protobuf::Field::StringField)
508
+ end
509
+
510
+ it 'fetches an extension field when forced' do
511
+ expect(::Test::Resource.get_field(100, true)).to be_a(::Protobuf::Field::BoolField)
512
+ expect(::Test::Resource.get_field(:ext_is_searchable, true)).to be_a(::Protobuf::Field::BoolField)
513
+ expect(::Test::Resource.get_field('ext_is_searchable', true)).to be_a(::Protobuf::Field::BoolField)
514
+ end
515
+
516
+ it 'returns nil when attempting to get an extension field' do
517
+ expect(::Test::Resource.get_field(100)).to be_nil
518
+ end
519
+
520
+ it 'returns nil when field is not defined' do
521
+ expect(::Test::Resource.get_field(-1)).to be_nil
522
+ expect(::Test::Resource.get_field(nil)).to be_nil
523
+ end
524
+ end
525
+
526
+ end