spec/lib/protobuf/message_spec.rb in protobuf-3.6.12 vs spec/lib/protobuf/message_spec.rb in protobuf-3.7.0.pre0
- old
+ new
@@ -179,68 +179,10 @@
it "initializes with an object with a block" do
test_enum = Test::EnumTestMessage.new { |p| p.non_default_enum = 2 }
expect(test_enum.non_default_enum).to eq(2)
end
-
- context 'ignoring unknown fields' do
- around do |example|
- orig = ::Protobuf.ignore_unknown_fields?
- ::Protobuf.ignore_unknown_fields = true
- example.call
- ::Protobuf.ignore_unknown_fields = orig
- end
-
- context 'with valid fields' do
- let(:values) { { :name => "Jim" } }
-
- it "does not raise an error" do
- expect { ::Test::Resource.new(values) }.to_not raise_error
- end
- end
-
- context 'with non-existent field' do
- let(:values) { { :name => "Jim", :othername => "invalid" } }
-
- it "does not raise an error" do
- expect { ::Test::Resource.new(values) }.to_not raise_error
- end
- end
- end
-
- context 'not ignoring unknown fields' do
- around do |example|
- orig = ::Protobuf.ignore_unknown_fields?
- ::Protobuf.ignore_unknown_fields = false
- example.call
- ::Protobuf.ignore_unknown_fields = orig
- end
-
- context 'with valid fields' do
- let(:values) { { :name => "Jim" } }
-
- it "does not raise an error" do
- expect { ::Test::Resource.new(values) }.to_not raise_error
- end
- end
-
- context 'with non-existent field' do
- let(:values) { { :name => "Jim", :othername => "invalid" } }
-
- it "raises an error and mentions the erroneous field" do
- expect { ::Test::Resource.new(values) }.to raise_error(::Protobuf::FieldNotDefinedError, /othername/)
- end
-
- context 'with a nil value' do
- let(:values) { { :name => "Jim", :othername => nil } }
-
- it "raises an error and mentions the erroneous field" do
- expect { ::Test::Resource.new(values) }.to raise_error(::Protobuf::FieldNotDefinedError, /othername/)
- end
- end
- end
- end
end
describe '#encode' do
context "encoding" do
it "accepts UTF-8 strings into string fields" do
@@ -446,10 +388,33 @@
{ :name => 'Resource 2' },
],
)
end
end
+
+ it 'uses simple field names as keys when possible and fully qualified names otherwise' do
+ message = Class.new(::Protobuf::Message) do
+ optional :int32, :field, 1
+ optional :int32, :colliding_field, 2
+ extensions 100...200
+ optional :int32, :".ext.normal_ext_field", 100, :extension => true
+ optional :int32, :".ext.colliding_field", 101, :extension => true
+ optional :int32, :".ext.colliding_field2", 102, :extension => true
+ optional :int32, :".ext2.colliding_field2", 103, :extension => true
+ end
+
+ hash = {
+ :field => 1,
+ :colliding_field => 2,
+ :normal_ext_field => 3,
+ :".ext.colliding_field" => 4,
+ :".ext.colliding_field2" => 5,
+ :".ext2.colliding_field2" => 6,
+ }
+ instance = message.new(hash)
+ expect(instance.to_hash).to eq(hash)
+ end
end
describe '#to_json' do
subject do
::Test::ResourceFindRequest.new(:name => 'Test Name', :active => false)
@@ -466,34 +431,61 @@
end
end.not_to raise_error
end
end
- describe "#define_setter" do
+ describe "#define_accessor" do
subject { ::Test::Resource.new }
- it "allows string fields to be set to nil" do
+ it 'allows string fields to be set to nil' do
expect { subject.name = nil }.to_not raise_error
end
- it "does not allow string fields to be set to Numeric" do
+ it 'does not allow string fields to be set to Numeric' do
expect { subject.name = 1 }.to raise_error(/name/)
end
+
+ context '#{simple_field_name}!' do
+ it 'returns value of set field' do
+ expect(::Test::Resource.new(:name => "Joe").name!).to eq("Joe")
+ end
+
+ it 'returns value of set field with default' do
+ expect(::Test::Resource.new(:name => "").name!).to eq("")
+ end
+
+ it 'returns nil if extension field is unset' do
+ expect(subject.ext_is_searchable!).to be_nil
+ end
+
+ it 'returns value of set extension field' do
+ message = ::Test::Resource.new(:ext_is_searchable => true)
+ expect(message.ext_is_searchable!).to be(true)
+ end
+
+ it 'returns value of set extension field with default' do
+ message = ::Test::Resource.new(:ext_is_searchable => false)
+ expect(message.ext_is_searchable!).to be(false)
+ end
+ end
end
describe '.get_extension_field' do
it 'fetches an extension field by its tag' do
field = ::Test::Resource.get_extension_field(100)
expect(field).to be_a(::Protobuf::Field::BoolField)
expect(field.tag).to eq(100)
expect(field.name).to eq(:ext_is_searchable)
+ expect(field.fully_qualified_name).to eq(:'.test.Searchable.ext_is_searchable')
expect(field).to be_extension
end
it 'fetches an extension field by its symbolized name' do
expect(::Test::Resource.get_extension_field(:ext_is_searchable)).to be_a(::Protobuf::Field::BoolField)
expect(::Test::Resource.get_extension_field('ext_is_searchable')).to be_a(::Protobuf::Field::BoolField)
+ expect(::Test::Resource.get_extension_field(:'.test.Searchable.ext_is_searchable')).to be_a(::Protobuf::Field::BoolField)
+ expect(::Test::Resource.get_extension_field('.test.Searchable.ext_is_searchable')).to be_a(::Protobuf::Field::BoolField)
end
it 'returns nil when attempting to get a non-extension field' do
expect(::Test::Resource.get_extension_field(1)).to be_nil
end
@@ -502,28 +494,87 @@
expect(::Test::Resource.get_extension_field(-1)).to be_nil
expect(::Test::Resource.get_extension_field(nil)).to be_nil
end
end
+ describe '#field?' do
+ it 'returns false for non-existent field' do
+ expect(::Test::Resource.get_field('doesnotexist')).to be_nil
+ expect(::Test::Resource.new.field?('doesnotexist')).to be(false)
+ end
+
+ it 'returns false for unset field' do
+ expect(::Test::Resource.get_field('name')).to be
+ expect(::Test::Resource.new.field?('name')).to be(false)
+ end
+
+ it 'returns false for unset field from tag' do
+ expect(::Test::Resource.get_field(1)).to be
+ expect(::Test::Resource.new.field?(1)).to be(false)
+ end
+
+ it 'returns true for set field' do
+ expect(::Test::Resource.new(:name => "Joe").field?('name')).to be(true)
+ end
+
+ it 'returns true for set field with default' do
+ expect(::Test::Resource.new(:name => "").field?('name')).to be(true)
+ end
+
+ it 'returns true from field tag value' do
+ expect(::Test::Resource.new(:name => "Joe").field?(1)).to be(true)
+ end
+
+ it 'returns false for unset extension field' do
+ ext_field = :".test.Searchable.ext_is_searchable"
+ expect(::Test::Resource.get_extension_field(ext_field)).to be
+ expect(::Test::Resource.new.field?(ext_field)).to be(false)
+ end
+
+ it 'returns false for unset extension field from tag' do
+ expect(::Test::Resource.get_extension_field(100)).to be
+ expect(::Test::Resource.new.field?(100)).to be(false)
+ end
+
+ it 'returns true for set extension field' do
+ ext_field = :".test.Searchable.ext_is_searchable"
+ message = ::Test::Resource.new(ext_field => true)
+ expect(message.field?(ext_field)).to be(true)
+ end
+
+ it 'returns true for set extension field with default' do
+ ext_field = :".test.Searchable.ext_is_searchable"
+ message = ::Test::Resource.new(ext_field => false)
+ expect(message.field?(ext_field)).to be(true)
+ end
+
+ it 'returns true for set extension field from tag' do
+ ext_field = :".test.Searchable.ext_is_searchable"
+ message = ::Test::Resource.new(ext_field => false)
+ expect(message.field?(100)).to be(true)
+ end
+ end
+
describe '.get_field' do
it 'fetches a non-extension field by its tag' do
field = ::Test::Resource.get_field(1)
expect(field).to be_a(::Protobuf::Field::StringField)
expect(field.tag).to eq(1)
expect(field.name).to eq(:name)
+ expect(field.fully_qualified_name).to eq(:name)
expect(field).not_to be_extension
end
it 'fetches a non-extension field by its symbolized name' do
expect(::Test::Resource.get_field(:name)).to be_a(::Protobuf::Field::StringField)
expect(::Test::Resource.get_field('name')).to be_a(::Protobuf::Field::StringField)
end
it 'fetches an extension field when forced' do
expect(::Test::Resource.get_field(100, true)).to be_a(::Protobuf::Field::BoolField)
- expect(::Test::Resource.get_field(:ext_is_searchable, true)).to be_a(::Protobuf::Field::BoolField)
- expect(::Test::Resource.get_field('ext_is_searchable', true)).to be_a(::Protobuf::Field::BoolField)
+ expect(::Test::Resource.get_field(:'.test.Searchable.ext_is_searchable', true)).to be_a(::Protobuf::Field::BoolField)
+ expect(::Test::Resource.get_field('.test.Searchable.ext_is_searchable', true)).to be_a(::Protobuf::Field::BoolField)
end
it 'returns nil when attempting to get an extension field' do
expect(::Test::Resource.get_field(100)).to be_nil
end
@@ -532,6 +583,220 @@
expect(::Test::Resource.get_field(-1)).to be_nil
expect(::Test::Resource.get_field(nil)).to be_nil
end
end
+ describe 'defining a field' do
+ # Case 1
+ context 'single base field' do
+ let(:klass) do
+ Class.new(Protobuf::Message) do
+ optional :string, :foo, 1
+ end
+ end
+
+ it 'has an accessor for foo' do
+ message = klass.new(:foo => 'bar')
+ expect(message.foo).to eq('bar')
+ expect(message[:foo]).to eq('bar')
+ expect(message['foo']).to eq('bar')
+ end
+ end
+
+ # Case 2
+ context 'base field and extension field name collision' do
+ let(:klass) do
+ Class.new(Protobuf::Message) do
+ optional :string, :foo, 1
+ optional :string, :".boom.foo", 2, :extension => true
+ end
+ end
+
+ it 'has an accessor for foo that refers to the base field' do
+ message = klass.new(:foo => 'bar', '.boom.foo' => 'bam')
+ expect(message.foo).to eq('bar')
+ expect(message[:foo]).to eq('bar')
+ expect(message['foo']).to eq('bar')
+ expect(message[:'.boom.foo']).to eq('bam')
+ expect(message['.boom.foo']).to eq('bam')
+ end
+ end
+
+ # Case 3
+ context 'no base field with extension fields with name collision' do
+ let(:klass) do
+ Class.new(Protobuf::Message) do
+ optional :string, :".boom.foo", 2, :extension => true
+ optional :string, :".goat.foo", 3, :extension => true
+ end
+ end
+
+ it 'has an accessor for foo that refers to the extension field' do
+ message = klass.new('.boom.foo' => 'bam', '.goat.foo' => 'red')
+ expect { message.foo }.to raise_error(NoMethodError)
+ expect { message[:foo] }.to raise_error(ArgumentError)
+ expect { message['foo'] }.to raise_error(ArgumentError)
+ expect(message[:'.boom.foo']).to eq('bam')
+ expect(message['.boom.foo']).to eq('bam')
+ expect(message[:'.goat.foo']).to eq('red')
+ expect(message['.goat.foo']).to eq('red')
+ end
+ end
+
+ # Case 4
+ context 'no base field with an extension field' do
+ let(:klass) do
+ Class.new(Protobuf::Message) do
+ optional :string, :".boom.foo", 2, :extension => true
+ end
+ end
+
+ it 'has an accessor for foo that refers to the extension field' do
+ message = klass.new('.boom.foo' => 'bam')
+ expect(message.foo).to eq('bam')
+ expect(message[:foo]).to eq('bam')
+ expect(message['foo']).to eq('bam')
+ expect(message[:'.boom.foo']).to eq('bam')
+ expect(message['.boom.foo']).to eq('bam')
+ end
+ end
+ end
+
+ describe '.[]=' do
+ context 'clearing fields' do
+ it 'clears repeated fields with an empty array' do
+ instance = ::Test::Resource.new(:repeated_enum => [::Test::StatusType::ENABLED])
+ expect(instance.field?(:repeated_enum)).to be(true)
+ instance[:repeated_enum] = []
+ expect(instance.field?(:repeated_enum)).to be(false)
+ end
+
+ it 'clears optional fields with nil' do
+ instance = ::Test::Resource.new(:name => "Joe")
+ expect(instance.field?(:name)).to be(true)
+ instance[:name] = nil
+ expect(instance.field?(:name)).to be(false)
+ end
+
+ it 'clears optional extenstion fields with nil' do
+ instance = ::Test::Resource.new(:ext_is_searchable => true)
+ expect(instance.field?(:ext_is_searchable)).to be(true)
+ instance[:ext_is_searchable] = nil
+ expect(instance.field?(:ext_is_searchable)).to be(false)
+ end
+ end
+
+ context 'setting fields' do
+ let(:instance) { ::Test::Resource.new }
+
+ it 'sets and replaces repeated fields' do
+ initial = [::Test::StatusType::ENABLED, ::Test::StatusType::DISABLED]
+ instance[:repeated_enum] = initial
+ expect(instance[:repeated_enum]).to eq(initial)
+ replacement = [::Test::StatusType::DELETED]
+ instance[:repeated_enum] = replacement
+ expect(instance[:repeated_enum]).to eq(replacement)
+ end
+
+ it 'sets acceptable optional field values' do
+ instance[:name] = "Joe"
+ expect(instance[:name]).to eq("Joe")
+ instance[1] = "Tom"
+ expect(instance[:name]).to eq("Tom")
+ end
+
+ it 'sets acceptable empty string field values' do
+ instance[:name] = ""
+ expect(instance.name!).to eq("")
+ end
+
+ it 'sets acceptable empty message field values' do
+ instance = ::Test::Nested.new
+ instance[:resource] = {}
+ expect(instance.resource!).to eq(::Test::Resource.new)
+ end
+
+ it 'sets acceptable extension field values' do
+ instance[:ext_is_searchable] = true
+ expect(instance[:ext_is_searchable]).to eq(true)
+ instance[:".test.Searchable.ext_is_searchable"] = false
+ expect(instance[:ext_is_searchable]).to eq(false)
+ instance[100] = true
+ expect(instance[:ext_is_searchable]).to eq(true)
+ end
+ end
+
+ context 'throwing TypeError' do
+ let(:instance) { ::Test::Resource.new }
+
+ it 'throws when a repeated value is set with a non array' do
+ expect { instance[:repeated_enum] = "string" }.to raise_error(TypeError)
+ end
+
+ it 'throws when a repeated value is set with an array of the wrong type' do
+ expect { instance[:repeated_enum] = [true, false] }.to raise_error(TypeError)
+ end
+
+ it 'throws when an optional value is not #acceptable?' do
+ expect { instance[:name] = 1 }.to raise_error(TypeError)
+ end
+ end
+
+ context 'ignoring unknown fields' do
+ around do |example|
+ orig = ::Protobuf.ignore_unknown_fields?
+ ::Protobuf.ignore_unknown_fields = true
+ example.call
+ ::Protobuf.ignore_unknown_fields = orig
+ end
+
+ context 'with valid fields' do
+ let(:values) { { :name => "Jim" } }
+
+ it "does not raise an error" do
+ expect { ::Test::Resource.new(values) }.to_not raise_error
+ end
+ end
+
+ context 'with non-existent field' do
+ let(:values) { { :name => "Jim", :othername => "invalid" } }
+
+ it "does not raise an error" do
+ expect { ::Test::Resource.new(values) }.to_not raise_error
+ end
+ end
+ end
+
+ context 'not ignoring unknown fields' do
+ around do |example|
+ orig = ::Protobuf.ignore_unknown_fields?
+ ::Protobuf.ignore_unknown_fields = false
+ example.call
+ ::Protobuf.ignore_unknown_fields = orig
+ end
+
+ context 'with valid fields' do
+ let(:values) { { :name => "Jim" } }
+
+ it "does not raise an error" do
+ expect { ::Test::Resource.new(values) }.to_not raise_error
+ end
+ end
+
+ context 'with non-existent field' do
+ let(:values) { { :name => "Jim", :othername => "invalid" } }
+
+ it "raises an error and mentions the erroneous field" do
+ expect { ::Test::Resource.new(values) }.to raise_error(::Protobuf::FieldNotDefinedError, /othername/)
+ end
+
+ context 'with a nil value' do
+ let(:values) { { :name => "Jim", :othername => nil } }
+
+ it "raises an error and mentions the erroneous field" do
+ expect { ::Test::Resource.new(values) }.to raise_error(::Protobuf::FieldNotDefinedError, /othername/)
+ end
+ end
+ end
+ end
+ end
end