protobuf 3.7.5 → 3.8.0.pre1
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.
- checksums.yaml +4 -4
- data/lib/protobuf/field/base_field.rb +18 -0
- data/lib/protobuf/field/field_hash.rb +104 -0
- data/lib/protobuf/generators/field_generator.rb +53 -10
- data/lib/protobuf/generators/group_generator.rb +7 -3
- data/lib/protobuf/generators/message_generator.rb +1 -1
- data/lib/protobuf/message.rb +30 -3
- data/lib/protobuf/message/fields.rb +13 -0
- data/lib/protobuf/version.rb +1 -1
- data/spec/functional/code_generator_spec.rb +20 -0
- data/spec/lib/protobuf/field/field_array_spec.rb +48 -12
- data/spec/lib/protobuf/field/field_hash_spec.rb +168 -0
- data/spec/lib/protobuf/generators/extension_generator_spec.rb +3 -3
- data/spec/lib/protobuf/generators/field_generator_spec.rb +53 -16
- data/spec/lib/protobuf/message_spec.rb +37 -0
- data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +1 -1
- data/spec/support/protos/map-test.bin +157 -0
- data/spec/support/protos/map-test.pb.rb +85 -0
- data/spec/support/protos/map-test.proto +68 -0
- metadata +99 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36998518e999db66696a856ca6489d2e7b4063a6
|
4
|
+
data.tar.gz: 9b342418d7b1bf86249fcb2ed4924b9c2cfc28a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 481bb0ddef459a46e0f34feab99b584dfdc21503e9198fd3df15bafe59d40b8d1115ef3c796bf531f67dfa60dfa112142affa4ab75c2553a4096abaa99683da4
|
7
|
+
data.tar.gz: 9db74e2292597dd416c9c69f299282dc3a7e928a4ff2c5da686a1ca2d8931b8ad5831a904dfec338c602fbd28fa3c833599e19083a3988c00f1827ed002d0422
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'active_support/core_ext/hash/slice'
|
2
2
|
require 'protobuf/field/field_array'
|
3
|
+
require 'protobuf/field/field_hash'
|
4
|
+
|
3
5
|
module Protobuf
|
4
6
|
module Field
|
5
7
|
class BaseField
|
@@ -82,6 +84,8 @@ module Protobuf
|
|
82
84
|
def default_value
|
83
85
|
@default_value ||= if optional? || required?
|
84
86
|
typed_default_value
|
87
|
+
elsif map?
|
88
|
+
::Protobuf::Field::FieldHash.new(self).freeze
|
85
89
|
elsif repeated?
|
86
90
|
::Protobuf::Field::FieldArray.new(self).freeze
|
87
91
|
else
|
@@ -113,6 +117,10 @@ module Protobuf
|
|
113
117
|
false
|
114
118
|
end
|
115
119
|
|
120
|
+
def map?
|
121
|
+
@is_map ||= repeated_message? && type_class.get_option(:map_entry)
|
122
|
+
end
|
123
|
+
|
116
124
|
def optional?
|
117
125
|
@optional
|
118
126
|
end
|
@@ -136,6 +144,16 @@ module Protobuf
|
|
136
144
|
# FIXME: need to cleanup (rename) this warthog of a method.
|
137
145
|
def set(message_instance, bytes)
|
138
146
|
return message_instance[name] = decode(bytes) unless repeated?
|
147
|
+
|
148
|
+
if map?
|
149
|
+
hash = message_instance[name]
|
150
|
+
entry = decode(bytes)
|
151
|
+
# decoded value could be nil for an
|
152
|
+
# enum value that is not recognized
|
153
|
+
hash[entry.key] = entry.value unless entry.value.nil?
|
154
|
+
return hash[entry.key]
|
155
|
+
end
|
156
|
+
|
139
157
|
return message_instance[name] << decode(bytes) unless packed?
|
140
158
|
|
141
159
|
array = message_instance[name]
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module Protobuf
|
2
|
+
module Field
|
3
|
+
class FieldHash < Hash
|
4
|
+
|
5
|
+
##
|
6
|
+
# Attributes
|
7
|
+
#
|
8
|
+
|
9
|
+
attr_reader :field, :key_field, :value_field
|
10
|
+
|
11
|
+
##
|
12
|
+
# Constructor
|
13
|
+
#
|
14
|
+
|
15
|
+
def initialize(field)
|
16
|
+
@field = field
|
17
|
+
@key_field = field.type_class.get_field(:key)
|
18
|
+
@value_field = field.type_class.get_field(:value)
|
19
|
+
end
|
20
|
+
|
21
|
+
##
|
22
|
+
# Public Instance Methods
|
23
|
+
#
|
24
|
+
|
25
|
+
def []=(key, val)
|
26
|
+
super(normalize_key(key), normalize_val(val))
|
27
|
+
end
|
28
|
+
|
29
|
+
alias store []=
|
30
|
+
|
31
|
+
def replace(val)
|
32
|
+
raise_type_error(val) unless val.is_a?(Hash)
|
33
|
+
clear
|
34
|
+
update(val)
|
35
|
+
end
|
36
|
+
|
37
|
+
def merge!(other)
|
38
|
+
raise_type_error(other) unless other.is_a?(Hash)
|
39
|
+
# keys and values will be normalized by []= above
|
40
|
+
other.each { |k, v| self[k] = v }
|
41
|
+
end
|
42
|
+
|
43
|
+
alias update merge!
|
44
|
+
|
45
|
+
# Return a hash-representation of the given values for this field type.
|
46
|
+
# The value in this case would be the hash itself, right? Unfortunately
|
47
|
+
# not because the values of the map could be messages themselves that we
|
48
|
+
# need to transform.
|
49
|
+
def to_hash_value
|
50
|
+
each_with_object({}) do |(key, value), hash|
|
51
|
+
hash[key] = value.respond_to?(:to_hash_value) ? value.to_hash_value : value
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_s
|
56
|
+
"{#{field.name}}"
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
##
|
62
|
+
# Private Instance Methods
|
63
|
+
#
|
64
|
+
|
65
|
+
def normalize_key(key)
|
66
|
+
normalize(:key, key, key_field)
|
67
|
+
end
|
68
|
+
|
69
|
+
def normalize_val(value)
|
70
|
+
normalize(:value, value, value_field)
|
71
|
+
end
|
72
|
+
|
73
|
+
def normalize(what, value, normalize_field)
|
74
|
+
raise_type_error(value) if value.nil?
|
75
|
+
value = value.to_proto if value.respond_to?(:to_proto)
|
76
|
+
fail TypeError, "Unacceptable #{what} #{value} for field #{field.name} of type #{normalize_field.type_class}" unless normalize_field.acceptable?(value)
|
77
|
+
|
78
|
+
if normalize_field.is_a?(::Protobuf::Field::EnumField)
|
79
|
+
fetch_enum(normalize_field.type_class, value)
|
80
|
+
elsif normalize_field.is_a?(::Protobuf::Field::MessageField) && value.is_a?(normalize_field.type_class)
|
81
|
+
value
|
82
|
+
elsif normalize_field.is_a?(::Protobuf::Field::MessageField) && value.respond_to?(:to_hash)
|
83
|
+
normalize_field.type_class.new(value.to_hash)
|
84
|
+
else
|
85
|
+
value
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def fetch_enum(type, val)
|
90
|
+
en = type.fetch(val)
|
91
|
+
raise_type_error(val) if en.nil?
|
92
|
+
en
|
93
|
+
end
|
94
|
+
|
95
|
+
def raise_type_error(val)
|
96
|
+
fail TypeError, <<-TYPE_ERROR
|
97
|
+
Expected map value of type '#{key_field.type_class} -> #{value_field.type_class}'
|
98
|
+
Got '#{val.class}' for map protobuf field #{field.name}
|
99
|
+
TYPE_ERROR
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -19,6 +19,11 @@ module Protobuf
|
|
19
19
|
#
|
20
20
|
attr_reader :field_options
|
21
21
|
|
22
|
+
def initialize(field_descriptor, enclosing_msg_descriptor, indent_level)
|
23
|
+
super(field_descriptor, indent_level)
|
24
|
+
@enclosing_msg_descriptor = enclosing_msg_descriptor
|
25
|
+
end
|
26
|
+
|
22
27
|
def applicable_options
|
23
28
|
# Note on the strange use of `#inspect`:
|
24
29
|
# :boom.inspect #=> ":boom"
|
@@ -60,7 +65,11 @@ module Protobuf
|
|
60
65
|
|
61
66
|
def compile
|
62
67
|
run_once(:compile) do
|
63
|
-
field_definition =
|
68
|
+
field_definition = if map?
|
69
|
+
["map #{map_key_type_name}", map_value_type_name, name, number, applicable_options]
|
70
|
+
else
|
71
|
+
["#{label} #{type_name}", name, number, applicable_options]
|
72
|
+
end
|
64
73
|
puts field_definition.flatten.compact.join(', ')
|
65
74
|
end
|
66
75
|
end
|
@@ -101,15 +110,28 @@ module Protobuf
|
|
101
110
|
|
102
111
|
# Determine the field type
|
103
112
|
def type_name
|
104
|
-
@type_name ||=
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
+
@type_name ||= determine_type_name(descriptor)
|
114
|
+
end
|
115
|
+
|
116
|
+
# If this field is a map field, this returns a message descriptor that
|
117
|
+
# represents the entries in the map. Returns nil if this field is not
|
118
|
+
# a map field.
|
119
|
+
def map_entry
|
120
|
+
@map_entry ||= determine_map_entry
|
121
|
+
end
|
122
|
+
|
123
|
+
def map?
|
124
|
+
!map_entry.nil?
|
125
|
+
end
|
126
|
+
|
127
|
+
def map_key_type_name
|
128
|
+
return nil if map_entry.nil?
|
129
|
+
determine_type_name(map_entry.field.find { |v| v.name == 'key' && v.number == 1 })
|
130
|
+
end
|
131
|
+
|
132
|
+
def map_value_type_name
|
133
|
+
return nil if map_entry.nil?
|
134
|
+
determine_type_name(map_entry.field.find { |v| v.name == 'value' && v.number == 2 })
|
113
135
|
end
|
114
136
|
|
115
137
|
private
|
@@ -145,6 +167,27 @@ module Protobuf
|
|
145
167
|
descriptor.default_value
|
146
168
|
end
|
147
169
|
|
170
|
+
def determine_type_name(descriptor)
|
171
|
+
case descriptor.type.name
|
172
|
+
when :TYPE_MESSAGE, :TYPE_ENUM, :TYPE_GROUP then
|
173
|
+
modulize(descriptor.type_name)
|
174
|
+
else
|
175
|
+
type_name = descriptor.type.name.to_s.downcase.sub(/^type_/, '')
|
176
|
+
":#{type_name}"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def determine_map_entry
|
181
|
+
return nil if @enclosing_msg_descriptor.nil?
|
182
|
+
return nil unless descriptor.label.name == :LABEL_REPEATED && descriptor.type.name == :TYPE_MESSAGE
|
183
|
+
# find nested message type
|
184
|
+
name_parts = descriptor.type_name.split(".")
|
185
|
+
return nil if name_parts.size < 2 || name_parts[-2] != @enclosing_msg_descriptor.name
|
186
|
+
nested = @enclosing_msg_descriptor.nested_type.find { |e| e.name == name_parts[-1] }
|
187
|
+
return nested if !nested.nil? && nested.options.try(:map_entry?)
|
188
|
+
nil
|
189
|
+
end
|
190
|
+
|
148
191
|
end
|
149
192
|
end
|
150
193
|
end
|
@@ -46,7 +46,7 @@ module Protobuf
|
|
46
46
|
|
47
47
|
def add_extension_fields(field_descriptors)
|
48
48
|
field_descriptors.each do |field_descriptor|
|
49
|
-
@groups[:extension_field] << FieldGenerator.new(field_descriptor, indent_level)
|
49
|
+
@groups[:extension_field] << FieldGenerator.new(field_descriptor, nil, indent_level)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
@@ -61,18 +61,22 @@ module Protobuf
|
|
61
61
|
|
62
62
|
def add_message_declarations(descriptors)
|
63
63
|
descriptors.each do |descriptor|
|
64
|
+
# elide synthetic map entry messages (we handle map fields differently)
|
65
|
+
next if descriptor.options.try(:map_entry?) { false }
|
64
66
|
@groups[:message_declaration] << MessageGenerator.new(descriptor, indent_level, :declaration => true)
|
65
67
|
end
|
66
68
|
end
|
67
69
|
|
68
|
-
def add_message_fields(field_descriptors)
|
70
|
+
def add_message_fields(field_descriptors, msg_descriptor)
|
69
71
|
field_descriptors.each do |field_descriptor|
|
70
|
-
@groups[:field] << FieldGenerator.new(field_descriptor, indent_level)
|
72
|
+
@groups[:field] << FieldGenerator.new(field_descriptor, msg_descriptor, indent_level)
|
71
73
|
end
|
72
74
|
end
|
73
75
|
|
74
76
|
def add_messages(descriptors, options = {})
|
75
77
|
descriptors.each do |descriptor|
|
78
|
+
# elide synthetic map entry message (we handle map fields differently)
|
79
|
+
next if descriptor.options.try(:map_entry?) { false }
|
76
80
|
@groups[:message] << MessageGenerator.new(descriptor, indent_level, options)
|
77
81
|
end
|
78
82
|
end
|
@@ -44,7 +44,7 @@ module Protobuf
|
|
44
44
|
group.add_messages(descriptor.nested_type, :extension_fields => @extension_fields, :namespace => type_namespace)
|
45
45
|
group.add_comment(:options, 'Message Options')
|
46
46
|
group.add_options(descriptor.options) if options?
|
47
|
-
group.add_message_fields(descriptor.field)
|
47
|
+
group.add_message_fields(descriptor.field, descriptor)
|
48
48
|
self.class.validate_tags(fully_qualified_type_namespace, descriptor.field.map(&:number))
|
49
49
|
|
50
50
|
group.add_comment(:extension_range, 'Extension Fields')
|
data/lib/protobuf/message.rb
CHANGED
@@ -50,7 +50,7 @@ module Protobuf
|
|
50
50
|
|
51
51
|
def clear!
|
52
52
|
@values.delete_if do |_, value|
|
53
|
-
if value.is_a?(::Protobuf::Field::FieldArray)
|
53
|
+
if value.is_a?(::Protobuf::Field::FieldArray) || value.is_a?(::Protobuf::Field::FieldHash)
|
54
54
|
value.clear
|
55
55
|
false
|
56
56
|
else
|
@@ -86,6 +86,17 @@ module Protobuf
|
|
86
86
|
fail ::Protobuf::SerializationError, "Required field #{self.class.name}##{field.name} does not have a value." if field.required?
|
87
87
|
next
|
88
88
|
end
|
89
|
+
if field.map?
|
90
|
+
# on-the-wire, maps are represented like an array of entries where
|
91
|
+
# each entry is a message of two fields, key and value.
|
92
|
+
array = Array.new(value.size)
|
93
|
+
i = 0
|
94
|
+
value.each do |k, v|
|
95
|
+
array[i] = field.type_class.new(:key => k, :value => v)
|
96
|
+
i += 1
|
97
|
+
end
|
98
|
+
value = array
|
99
|
+
end
|
89
100
|
|
90
101
|
yield(field, value)
|
91
102
|
end
|
@@ -151,8 +162,9 @@ module Protobuf
|
|
151
162
|
|
152
163
|
def [](name)
|
153
164
|
field = self.class.get_field(name, true)
|
154
|
-
return @values[field.fully_qualified_name] ||= ::Protobuf::Field::FieldArray.new(field) if field.repeated?
|
155
165
|
|
166
|
+
return @values[field.fully_qualified_name] ||= ::Protobuf::Field::FieldHash.new(field) if field.map?
|
167
|
+
return @values[field.fully_qualified_name] ||= ::Protobuf::Field::FieldArray.new(field) if field.repeated?
|
156
168
|
@values.fetch(field.fully_qualified_name, field.default_value)
|
157
169
|
rescue # not having a field should be the exceptional state
|
158
170
|
raise if field
|
@@ -184,9 +196,24 @@ module Protobuf
|
|
184
196
|
|
185
197
|
private
|
186
198
|
|
199
|
+
# rubocop:disable Metrics/MethodLength
|
187
200
|
def set_field(name, value, ignore_nil_for_repeated)
|
188
201
|
if (field = self.class.get_field(name, true))
|
189
|
-
if field.
|
202
|
+
if field.map?
|
203
|
+
unless value.is_a?(Hash)
|
204
|
+
fail TypeError, <<-TYPE_ERROR
|
205
|
+
Expected map value
|
206
|
+
Got '#{value.class}' for map protobuf field #{field.name}
|
207
|
+
TYPE_ERROR
|
208
|
+
end
|
209
|
+
|
210
|
+
if value.empty?
|
211
|
+
@values.delete(field.fully_qualified_name)
|
212
|
+
else
|
213
|
+
@values[field.fully_qualified_name] ||= ::Protobuf::Field::FieldHash.new(field)
|
214
|
+
@values[field.fully_qualified_name].replace(value)
|
215
|
+
end
|
216
|
+
elsif field.repeated?
|
190
217
|
if value.nil? && ignore_nil_for_repeated
|
191
218
|
::Protobuf.deprecator.deprecation_warning("#{self.class}#[#{name}]=nil", "use an empty array instead of nil")
|
192
219
|
return
|
@@ -44,6 +44,19 @@ module Protobuf
|
|
44
44
|
define_field(:required, type_class, name, tag, options)
|
45
45
|
end
|
46
46
|
|
47
|
+
# Define a map field.
|
48
|
+
#
|
49
|
+
def map(key_type_class, value_type_class, name, tag, options = {})
|
50
|
+
# manufacture a message that represents the map entry, used for
|
51
|
+
# serialization and deserialization
|
52
|
+
entry_type = Class.new(::Protobuf::Message) do
|
53
|
+
set_option :map_entry, true
|
54
|
+
optional key_type_class, :key, 1
|
55
|
+
optional value_type_class, :value, 2
|
56
|
+
end
|
57
|
+
define_field(:repeated, entry_type, name, tag, options)
|
58
|
+
end
|
59
|
+
|
47
60
|
# Define an extension range.
|
48
61
|
#
|
49
62
|
def extensions(range)
|
data/lib/protobuf/version.rb
CHANGED
@@ -24,6 +24,26 @@ RSpec.describe 'code generation' do
|
|
24
24
|
expect(code_generator.response_bytes).to eq(expected_output)
|
25
25
|
end
|
26
26
|
|
27
|
+
it "generates code for map types" do
|
28
|
+
input_descriptor = ::Google::Protobuf::FileDescriptorSet.decode(
|
29
|
+
IO.read(PROTOS_PATH.join('map-test.bin'), :mode => 'rb'))
|
30
|
+
request = ::Google::Protobuf::Compiler::CodeGeneratorRequest.new(:file_to_generate => ['map-test.proto'],
|
31
|
+
:proto_file => input_descriptor.file)
|
32
|
+
|
33
|
+
file_name = "map-test.pb.rb"
|
34
|
+
file_content = File.open(PROTOS_PATH.join(file_name), "r:UTF-8", &:read)
|
35
|
+
expected_file_output =
|
36
|
+
::Google::Protobuf::Compiler::CodeGeneratorResponse::File.new(
|
37
|
+
:name => file_name, :content => file_content)
|
38
|
+
|
39
|
+
expected_response =
|
40
|
+
::Google::Protobuf::Compiler::CodeGeneratorResponse.encode(:file => [expected_file_output])
|
41
|
+
|
42
|
+
code_generator = ::Protobuf::CodeGenerator.new(request.encode)
|
43
|
+
code_generator.eval_unknown_extensions!
|
44
|
+
expect(code_generator.response_bytes).to eq(expected_response)
|
45
|
+
end
|
46
|
+
|
27
47
|
it "generates code (including service stubs) with custom field and method options" do
|
28
48
|
expected_unittest_custom_options =
|
29
49
|
File.open(PROTOS_PATH.join('google_unittest_custom_options.pb.rb'), "r:UTF-8", &:read)
|
@@ -2,21 +2,39 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
RSpec.describe Protobuf::Field::FieldArray do
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
let(:basic_message) do
|
6
|
+
Class.new(::Protobuf::Message) do
|
7
|
+
optional :string, :field, 1
|
8
|
+
end
|
7
9
|
end
|
8
10
|
|
9
|
-
|
11
|
+
let(:more_complex_message) do
|
12
|
+
Class.new(BasicMessage) do
|
13
|
+
end
|
10
14
|
end
|
11
15
|
|
12
|
-
|
13
|
-
|
16
|
+
let(:some_enum) do
|
17
|
+
Class.new(::Protobuf::Enum) do
|
18
|
+
define :FOO, 1
|
19
|
+
define :BAR, 2
|
20
|
+
define :BAZ, 3
|
21
|
+
end
|
14
22
|
end
|
15
23
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
24
|
+
let(:repeat_message) do
|
25
|
+
Class.new(::Protobuf::Message) do
|
26
|
+
optional :string, :some_string, 1
|
27
|
+
repeated :string, :multiple_strings, 2
|
28
|
+
repeated BasicMessage, :multiple_basic_msgs, 3
|
29
|
+
repeated SomeEnum, :multiple_enums, 4
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
before do
|
34
|
+
stub_const('BasicMessage', basic_message)
|
35
|
+
stub_const('MoreComplexMessage', more_complex_message)
|
36
|
+
stub_const('SomeEnum', some_enum)
|
37
|
+
stub_const('SomeRepeatMessage', repeat_message)
|
20
38
|
end
|
21
39
|
|
22
40
|
let(:instance) { SomeRepeatMessage.new }
|
@@ -40,17 +58,21 @@ RSpec.describe Protobuf::Field::FieldArray do
|
|
40
58
|
context 'when applied to a MessageField field array' do
|
41
59
|
it 'adds a MessageField object' do
|
42
60
|
expect(instance.multiple_basic_msgs).to be_empty
|
43
|
-
basic_msg1 =
|
61
|
+
basic_msg1 = BasicMessage.new
|
44
62
|
instance.multiple_basic_msgs.send(method, basic_msg1)
|
45
63
|
expect(instance.multiple_basic_msgs).to eq([basic_msg1])
|
46
|
-
basic_msg2 =
|
64
|
+
basic_msg2 = BasicMessage.new
|
47
65
|
instance.multiple_basic_msgs.send(method, basic_msg2)
|
48
66
|
expect(instance.multiple_basic_msgs).to eq([basic_msg1, basic_msg2])
|
49
67
|
end
|
50
68
|
|
69
|
+
it 'fails if not adding a MessageField' do
|
70
|
+
expect { instance.multiple_basic_msgs.send(method, 100.0) }.to raise_error(TypeError)
|
71
|
+
end
|
72
|
+
|
51
73
|
it 'adds a Hash from a MessageField object' do
|
52
74
|
expect(instance.multiple_basic_msgs).to be_empty
|
53
|
-
basic_msg1 =
|
75
|
+
basic_msg1 = BasicMessage.new
|
54
76
|
basic_msg1.field = 'my value'
|
55
77
|
instance.multiple_basic_msgs.send(method, basic_msg1.to_hash)
|
56
78
|
expect(instance.multiple_basic_msgs).to eq([basic_msg1])
|
@@ -64,6 +86,20 @@ RSpec.describe Protobuf::Field::FieldArray do
|
|
64
86
|
expect(instance.multiple_basic_msgs.first).to be_a(MoreComplexMessage)
|
65
87
|
end
|
66
88
|
end
|
89
|
+
|
90
|
+
context 'when applied to an EnumField field array' do
|
91
|
+
it 'adds an EnumField object' do
|
92
|
+
expect(instance.multiple_enums).to be_empty
|
93
|
+
instance.multiple_enums.send(method, SomeEnum::FOO)
|
94
|
+
expect(instance.multiple_enums).to eq([SomeEnum::FOO])
|
95
|
+
instance.multiple_enums.send(method, SomeEnum::BAR)
|
96
|
+
expect(instance.multiple_enums).to eq([SomeEnum::FOO, SomeEnum::BAR])
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'fails if not adding an EnumField' do
|
100
|
+
expect { instance.multiple_basic_msgs.send(method, 100.0) }.to raise_error(TypeError)
|
101
|
+
end
|
102
|
+
end
|
67
103
|
end
|
68
104
|
end
|
69
105
|
end
|