protobuf-core 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
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