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,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