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,73 @@
1
+ require 'spec_helper'
2
+
3
+ require 'protobuf/generators/enum_generator'
4
+
5
+ RSpec.describe ::Protobuf::Generators::EnumGenerator do
6
+
7
+ let(:values) do
8
+ [
9
+ { :name => 'FOO', :number => 1 },
10
+ { :name => 'BAR', :number => 2 },
11
+ { :name => 'BAZ', :number => 3 },
12
+ ]
13
+ end
14
+ let(:options) { nil }
15
+ let(:enum_fields) do
16
+ {
17
+ :name => 'TestEnum',
18
+ :value => values,
19
+ :options => options,
20
+ }
21
+ end
22
+
23
+ let(:enum) { ::Google::Protobuf::EnumDescriptorProto.new(enum_fields) }
24
+
25
+ subject { described_class.new(enum) }
26
+
27
+ describe '#compile' do
28
+ let(:compiled) do
29
+ <<-RUBY
30
+ class TestEnum < ::Protobuf::Enum
31
+ define :FOO, 1
32
+ define :BAR, 2
33
+ define :BAZ, 3
34
+ end
35
+
36
+ RUBY
37
+ end
38
+
39
+ it 'compiles the enum and its field values' do
40
+ subject.compile
41
+ expect(subject.to_s).to eq(compiled)
42
+ end
43
+
44
+ context 'when allow_alias option is set' do
45
+ let(:compiled) do
46
+ <<-RUBY
47
+ class TestEnum < ::Protobuf::Enum
48
+ set_option :allow_alias
49
+
50
+ define :FOO, 1
51
+ define :BAR, 2
52
+ define :BAZ, 3
53
+ end
54
+
55
+ RUBY
56
+ end
57
+
58
+ let(:options) { { :allow_alias => true } }
59
+
60
+ it 'sets the allow_alias option' do
61
+ subject.compile
62
+ expect(subject.to_s).to eq(compiled)
63
+ end
64
+ end
65
+ end
66
+
67
+ describe '#build_value' do
68
+ it 'returns a string identifying the given enum value' do
69
+ expect(subject.build_value(enum.value.first)).to eq("define :FOO, 1")
70
+ end
71
+ end
72
+
73
+ end
@@ -0,0 +1,265 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Protobuf::Enum do
4
+
5
+ describe 'class dsl' do
6
+ let(:name) { :THREE }
7
+ let(:tag) { 3 }
8
+
9
+ before(:all) do
10
+ Test::EnumTestType.define(:MINUS_ONE, -1)
11
+ Test::EnumTestType.define(:THREE, 3)
12
+ end
13
+
14
+ before(:all) do
15
+ EnumAliasTest = ::Class.new(::Protobuf::Enum) do
16
+ set_option :allow_alias
17
+ define :FOO, 1
18
+ define :BAR, 1
19
+ define :BAZ, 2
20
+ end
21
+ end
22
+
23
+ describe '.aliases_allowed?' do
24
+ it 'is nil when the option is not set' do
25
+ expect(Test::EnumTestType.aliases_allowed?).to be nil
26
+ end
27
+ end
28
+
29
+ describe '.define' do
30
+ it 'defines a constant enum on the parent class' do
31
+ expect(Test::EnumTestType.constants).to include(name)
32
+ expect(Test::EnumTestType::THREE).to be_a(Protobuf::Enum)
33
+ end
34
+
35
+ context 'when enum allows aliases' do
36
+ before(:all) do
37
+ DefineEnumAlias = ::Class.new(::Protobuf::Enum) do
38
+ set_option :allow_alias
39
+ end
40
+ end
41
+
42
+ it 'allows defining enums with the same tag number' do
43
+ expect do
44
+ DefineEnumAlias.define(:FOO, 1)
45
+ DefineEnumAlias.define(:BAR, 1)
46
+ end.not_to raise_error
47
+ end
48
+ end
49
+ end
50
+
51
+ describe '.enums' do
52
+ it 'provides an array of defined Enums' do
53
+ expect(Test::EnumTestType.enums).to eq(
54
+ [
55
+ Test::EnumTestType::ONE,
56
+ Test::EnumTestType::TWO,
57
+ Test::EnumTestType::MINUS_ONE,
58
+ Test::EnumTestType::THREE,
59
+ ],
60
+ )
61
+ end
62
+
63
+ context 'when enum allows aliases' do
64
+ it 'treats aliased enums as valid' do
65
+ expect(EnumAliasTest.enums).to eq(
66
+ [
67
+ EnumAliasTest::FOO,
68
+ EnumAliasTest::BAR,
69
+ EnumAliasTest::BAZ,
70
+ ],
71
+ )
72
+ end
73
+ end
74
+ end
75
+
76
+ describe '.enums_for_tag' do
77
+ it 'returns an array of Enums for the given tag, if any' do
78
+ expect(EnumAliasTest.enums_for_tag(1)).to eq([EnumAliasTest::FOO, EnumAliasTest::BAR])
79
+ expect(EnumAliasTest.enums_for_tag(2)).to eq([EnumAliasTest::BAZ])
80
+ expect(EnumAliasTest.enums_for_tag(3)).to eq([])
81
+ end
82
+ end
83
+
84
+ describe '.fetch' do
85
+ context 'when candidate is an Enum' do
86
+ it 'responds with the Enum' do
87
+ expect(Test::EnumTestType.fetch(Test::EnumTestType::THREE)).to eq(Test::EnumTestType::THREE)
88
+ end
89
+ end
90
+
91
+ context 'when candidate can be coerced to a symbol' do
92
+ it 'fetches based on the symbol name' do
93
+ expect(Test::EnumTestType.fetch("ONE")).to eq(Test::EnumTestType::ONE)
94
+ expect(Test::EnumTestType.fetch(:ONE)).to eq(Test::EnumTestType::ONE)
95
+ end
96
+ end
97
+
98
+ context 'when candidate can be coerced to an integer' do
99
+ it 'fetches based on the integer tag' do
100
+ expect(Test::EnumTestType.fetch(3.0)).to eq(Test::EnumTestType::THREE)
101
+ expect(Test::EnumTestType.fetch(3)).to eq(Test::EnumTestType::THREE)
102
+ end
103
+
104
+ context 'when enum allows aliases' do
105
+ it 'fetches the first defined Enum' do
106
+ expect(EnumAliasTest.fetch(1)).to eq(EnumAliasTest::FOO)
107
+ end
108
+ end
109
+ end
110
+
111
+ context 'when candidate is not an applicable type' do
112
+ it 'returns a nil' do
113
+ expect(Test::EnumTestType.fetch(EnumAliasTest::FOO)).to be_nil
114
+ expect(Test::EnumTestType.fetch(Test::Resource.new)).to be_nil
115
+ expect(Test::EnumTestType.fetch(nil)).to be_nil
116
+ expect(Test::EnumTestType.fetch(false)).to be_nil
117
+ expect(Test::EnumTestType.fetch(-10)).to be_nil
118
+ end
119
+ end
120
+ end
121
+
122
+ describe '.enum_for_tag' do
123
+ it 'gets the Enum corresponding to the given tag' do
124
+ expect(Test::EnumTestType.enum_for_tag(tag)).to eq(Test::EnumTestType.const_get(name))
125
+ expect(Test::EnumTestType.enum_for_tag(-5)).to be_nil
126
+ end
127
+ end
128
+
129
+ describe '.name_for_tag' do
130
+ it 'get the name of the enum given the enum' do
131
+ expect(Test::EnumTestType.name_for_tag(::Test::EnumTestType::THREE)).to eq(name)
132
+ end
133
+
134
+ it 'gets the name of the enum corresponding to the given tag' do
135
+ expect(Test::EnumTestType.name_for_tag(tag)).to eq(name)
136
+ end
137
+
138
+ it 'gets the name when the tag is coercable to an int' do
139
+ expect(Test::EnumTestType.name_for_tag("3")).to eq(name)
140
+ end
141
+
142
+ it 'returns nil when tag does not correspond to a name' do
143
+ expect(Test::EnumTestType.name_for_tag(12345)).to be_nil
144
+ end
145
+
146
+ context 'when given name is nil' do
147
+ it 'returns a nil' do
148
+ expect(Test::EnumTestType.name_for_tag(nil)).to be_nil
149
+ end
150
+ end
151
+
152
+ context 'when enum allows aliases' do
153
+ it 'returns the first defined name for the given tag' do
154
+ expect(EnumAliasTest.name_for_tag(1)).to eq(:FOO)
155
+ end
156
+ end
157
+ end
158
+
159
+ describe '.valid_tag?' do
160
+ context 'when tag is defined' do
161
+ specify { expect(Test::EnumTestType.valid_tag?(tag)).to be true }
162
+ end
163
+
164
+ context 'when tag is not defined' do
165
+ specify { expect(Test::EnumTestType.valid_tag?(300)).to be false }
166
+ end
167
+
168
+ context 'is true for aliased enums' do
169
+ specify { expect(EnumAliasTest.valid_tag?(1)).to be true }
170
+ end
171
+ end
172
+
173
+ describe '.enum_for_name' do
174
+ it 'gets the Enum corresponding to the given name' do
175
+ expect(Test::EnumTestType.enum_for_name(name)).to eq(Test::EnumTestType::THREE)
176
+ end
177
+ end
178
+
179
+ describe '.values' do
180
+ around do |example|
181
+ # this method is deprecated
182
+ ::Protobuf.deprecator.silence(&example)
183
+ end
184
+
185
+ it 'provides a hash of defined Enums' do
186
+ expect(Test::EnumTestType.values).to eq(
187
+ :MINUS_ONE => Test::EnumTestType::MINUS_ONE,
188
+ :ONE => Test::EnumTestType::ONE,
189
+ :TWO => Test::EnumTestType::TWO,
190
+ :THREE => Test::EnumTestType::THREE,
191
+ )
192
+ end
193
+
194
+ it 'contains aliased Enums' do
195
+ expect(EnumAliasTest.values).to eq(
196
+ :FOO => EnumAliasTest::FOO,
197
+ :BAR => EnumAliasTest::BAR,
198
+ :BAZ => EnumAliasTest::BAZ,
199
+ )
200
+ end
201
+ end
202
+
203
+ describe '.all_tags' do
204
+ it 'provides a unique array of defined tags' do
205
+ expect(Test::EnumTestType.all_tags).to include(1, 2, -1, 3)
206
+ expect(EnumAliasTest.all_tags).to include(1, 2)
207
+ end
208
+ end
209
+ end
210
+
211
+ subject { Test::EnumTestType::ONE }
212
+ specify { expect(subject.class).to eq(Fixnum) }
213
+ specify { expect(subject.parent_class).to eq(Test::EnumTestType) }
214
+ specify { expect(subject.name).to eq(:ONE) }
215
+ specify { expect(subject.tag).to eq(1) }
216
+
217
+ context 'deprecated' do
218
+ around do |example|
219
+ # this method is deprecated
220
+ ::Protobuf.deprecator.silence(&example)
221
+ end
222
+
223
+ specify { expect(subject.value).to eq(1) }
224
+ end
225
+
226
+ specify { expect(subject.to_hash_value).to eq(1) }
227
+ specify { expect(subject.to_s).to eq("1") }
228
+ specify { expect(subject.inspect).to eq('#<Protobuf::Enum(Test::EnumTestType)::ONE=1>') }
229
+ specify { expect(subject.to_s(:tag)).to eq("1") }
230
+ specify { expect(subject.to_s(:name)).to eq("ONE") }
231
+
232
+ it "can be used as the index to an array" do
233
+ array = [0, 1, 2, 3]
234
+ expect(array[::Test::EnumTestType::ONE]).to eq(1)
235
+ end
236
+
237
+ describe '#try' do
238
+ specify { expect(subject.try(:parent_class)).to eq(subject.parent_class) }
239
+ specify { expect(subject.try(:class)).to eq(subject.class) }
240
+ specify { expect(subject.try(:name)).to eq(subject.name) }
241
+ specify { expect(subject.try(:tag)).to eq(subject.tag) }
242
+
243
+ context 'deprecated' do
244
+ around do |example|
245
+ # this method is deprecated
246
+ ::Protobuf.deprecator.silence(&example)
247
+ end
248
+
249
+ specify { expect(subject.try(:value)).to eq(subject.value) }
250
+ end
251
+
252
+ specify { expect(subject.try(:to_i)).to eq(subject.to_i) }
253
+ specify { expect(subject.try(:to_int)).to eq(subject.to_int) }
254
+ specify { subject.try { |yielded| expect(yielded).to eq(subject) } }
255
+ end
256
+
257
+ context 'when coercing from enum' do
258
+ subject { Test::StatusType::PENDING }
259
+ it { is_expected.to eq(0) }
260
+ end
261
+
262
+ context 'when coercing from integer' do
263
+ specify { expect(0).to eq(Test::StatusType::PENDING) }
264
+ end
265
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ require 'protobuf/code_generator'
4
+ require 'protobuf/generators/extension_generator'
5
+
6
+ RSpec.describe ::Protobuf::Generators::ExtensionGenerator do
7
+
8
+ let(:field_descriptors) do
9
+ [
10
+ double('field descriptor 1', :to_s => " field 1\n"),
11
+ double('field descriptor 2', :to_s => " field 2\n"),
12
+ double('field descriptor 3', :to_s => " field 3\n"),
13
+ ]
14
+ end
15
+ let(:message_type) { 'FooBar' }
16
+
17
+ before do
18
+ expect(::Protobuf::Generators::FieldGenerator).to receive(:new).with(field_descriptors[0], 1).and_return(field_descriptors[0])
19
+ expect(::Protobuf::Generators::FieldGenerator).to receive(:new).with(field_descriptors[1], 1).and_return(field_descriptors[1])
20
+ expect(::Protobuf::Generators::FieldGenerator).to receive(:new).with(field_descriptors[2], 1).and_return(field_descriptors[2])
21
+ end
22
+
23
+ subject { described_class.new(message_type, field_descriptors, 0) }
24
+
25
+ describe '#compile' do
26
+ let(:compiled) do
27
+ 'class FooBar < ::Protobuf::Message
28
+ field 1
29
+ field 2
30
+ field 3
31
+ end
32
+
33
+ '
34
+ end
35
+
36
+ it 'compiles the a class with the extension fields' do
37
+ subject.compile
38
+ expect(subject.to_s).to eq(compiled)
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Protobuf::Field::Int32Field do
4
+
5
+ class SomeBoolMessage < ::Protobuf::Message
6
+ optional :bool, :some_bool, 1
7
+ end
8
+
9
+ let(:instance) { SomeBoolMessage.new }
10
+
11
+ describe '#define_setter' do
12
+ subject { instance.some_bool = value; instance.some_bool }
13
+
14
+ [true, false].each do |val|
15
+ context "when set with #{val}" do
16
+ let(:value) { val }
17
+
18
+ it 'is readable as a bool' do
19
+ expect(subject).to eq(val)
20
+ end
21
+ end
22
+ end
23
+
24
+ [['true', true], ['false', false]].each do |val, expected|
25
+ context "when set with a string of #{val}" do
26
+ let(:value) { val }
27
+
28
+ it 'is readable as a bool' do
29
+ expect(subject).to eq(expected)
30
+ end
31
+ end
32
+ end
33
+
34
+ context 'when set with a non-bool string' do
35
+ let(:value) { "aaaa" }
36
+
37
+ it 'throws an error' do
38
+ expect { subject }.to raise_error(TypeError)
39
+ end
40
+ end
41
+
42
+ context 'when set with something that is not a bool' do
43
+ let(:value) { [1, 2, 3] }
44
+
45
+ it 'throws an error' do
46
+ expect { subject }.to raise_error(TypeError)
47
+ end
48
+ end
49
+ end
50
+
51
+ end
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Protobuf::Field::FieldArray do
4
+
5
+ class SomeBasicMessage < ::Protobuf::Message
6
+ optional :string, :field, 1
7
+ end
8
+
9
+ class MoreComplexMessage < SomeBasicMessage
10
+ end
11
+
12
+ class OtherBasicMessage < ::Protobuf::Message
13
+ optional :string, :other_field, 1
14
+ end
15
+
16
+ class SomeRepeatMessage < ::Protobuf::Message
17
+ optional :string, :some_string, 1
18
+ repeated :string, :multiple_strings, 2
19
+ repeated SomeBasicMessage, :multiple_basic_msgs, 3
20
+ end
21
+
22
+ let(:instance) { SomeRepeatMessage.new }
23
+
24
+ %w(<< push).each do |method|
25
+ describe "\##{method}" do
26
+ context 'when applied to a string field array' do
27
+ it 'adds a string' do
28
+ expect(instance.multiple_strings).to be_empty
29
+ instance.multiple_strings.send(method, 'string 1')
30
+ expect(instance.multiple_strings).to eq(['string 1'])
31
+ instance.multiple_strings.send(method, 'string 2')
32
+ expect(instance.multiple_strings).to eq(['string 1', 'string 2'])
33
+ end
34
+
35
+ it 'fails if not adding a string' do
36
+ expect { instance.multiple_strings.send(method, 100.0) }.to raise_error(TypeError)
37
+ end
38
+ end
39
+
40
+ context 'when applied to a MessageField field array' do
41
+ it 'adds a MessageField object' do
42
+ expect(instance.multiple_basic_msgs).to be_empty
43
+ basic_msg1 = SomeBasicMessage.new
44
+ instance.multiple_basic_msgs.send(method, basic_msg1)
45
+ expect(instance.multiple_basic_msgs).to eq([basic_msg1])
46
+ basic_msg2 = SomeBasicMessage.new
47
+ instance.multiple_basic_msgs.send(method, basic_msg2)
48
+ expect(instance.multiple_basic_msgs).to eq([basic_msg1, basic_msg2])
49
+ end
50
+
51
+ it 'adds a Hash from a MessageField object' do
52
+ expect(instance.multiple_basic_msgs).to be_empty
53
+ basic_msg1 = SomeBasicMessage.new
54
+ basic_msg1.field = 'my value'
55
+ instance.multiple_basic_msgs.send(method, basic_msg1.to_hash)
56
+ expect(instance.multiple_basic_msgs).to eq([basic_msg1])
57
+ end
58
+
59
+ it 'does not downcast a MessageField' do
60
+ expect(instance.multiple_basic_msgs).to be_empty
61
+ basic_msg1 = MoreComplexMessage.new
62
+ instance.multiple_basic_msgs.send(method, basic_msg1)
63
+ expect(instance.multiple_basic_msgs).to eq([basic_msg1])
64
+ expect(instance.multiple_basic_msgs.first).to be_a(MoreComplexMessage)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end