require 'spec_helper' describe Virtus::ValueObject do let(:class_under_test) do Class.new do def self.name 'GeoLocation' end include Virtus::ValueObject attribute :latitude, Float attribute :longitude, Float end end let(:attribute_values) { { :latitude => 10.0, :longitude => 20.0 } } let(:instance_with_equal_state) { class_under_test.new(attribute_values) } let(:instance_with_different_state) do class_under_test.new(:latitude => attribute_values[:latitude]) end subject { class_under_test.new(attribute_values) } describe 'initialization' do it 'sets the attribute values provided to Class.new' do expect(class_under_test.new(:latitude => 10000.001).latitude).to eq(10000.001) expect(subject.latitude).to eql(attribute_values[:latitude]) end end describe 'writer visibility' do it 'attributes are configured for private writers' do expect(class_under_test.attribute_set[:latitude].public_reader?).to be(true) expect(class_under_test.attribute_set[:longitude].public_writer?).to be(false) end it 'writer methods are set to private' do private_methods = class_under_test.private_instance_methods private_methods.map! { |m| m.to_s } expect(private_methods).to include('latitude=', 'longitude=', 'attributes=') end it 'attempts to call attribute writer methods raises NameError' do expect { subject.latitude = 5.0 }.to raise_exception(NameError) expect { subject.longitude = 5.0 }.to raise_exception(NameError) end end describe 'equality' do describe '#==' do it 'returns true for different objects with the same state' do expect(subject).to eq(instance_with_equal_state) end it 'returns false for different objects with different state' do expect(subject).not_to eq(instance_with_different_state) end end describe '#eql?' do it 'returns true for different objects with the same state' do expect(subject).to eql(instance_with_equal_state) end it 'returns false for different objects with different state' do expect(subject).not_to eql(instance_with_different_state) end end describe '#equal?' do it 'returns false for different objects with the same state' do expect(subject).not_to equal(instance_with_equal_state) end it 'returns false for different objects with different state' do expect(subject).not_to equal(instance_with_different_state) end end describe '#hash' do it 'returns the same value for different objects with the same state' do expect(subject.hash).to eql(instance_with_equal_state.hash) end it 'returns different values for different objects with different state' do expect(subject.hash).not_to eql(instance_with_different_state.hash) end end end describe '#inspect' do it 'includes the class name and attribute values' do expect(subject.inspect).to eq('#') end end end