rspec-virtus icon indicating copy to clipboard operation
rspec-virtus copied to clipboard

Model with boolean attribute

Open legendetm opened this issue 8 years ago • 0 comments

With the current version it is not possible to test attribute type if attribute type is boolean.

The current implementation uses method Attribute#primitive to fetch and compare types, which in case of Boolean returns BasicObject (because ruby does not have a corresponding type) and thus fails.

class Authorization
  include Virtus.model

  attribute :status, String
  attribute :approved, Boolean
  attribute :pending
end

it { expect(described_class).to have_attribute(:approved).of_type(described_class::Boolean) } # fails
it { expect(described_class).to have_attribute(:approved).of_type(Virtus::Attribute::Boolean) } # fails
it { expect(described_class).to have_attribute(:approved).of_type(Axiom::Types::Boolean) } #fails

Authorization.attribute_set['status']   #=> #<Virtus::Attribute type=Axiom::Types::String (String)
Authorization.attribute_set['status'].primitive   #=> String

Authorization.attribute_set['approved'] #=> #<Virtus::Attribute::Boolean type=Axiom::Types::Boolean (BasicObject) ...
Authorization.attribute_set['approved'].primitive #=> BasicObject

Authorization.attribute_set['pending']  #=> #<Virtus::Attribute type=Axiom::Types::Object (BasicObject)
Authorization.attribute_set['pending'].primitive  #=> BasicObject

As a solution I suggest to update method type_correct? to check if attribute is instance of given type.

module RSpec
  module Virtus
    class Matcher
      def type_correct?
        if @options[:member_type]
          member_type == @options[:member_type] && (attribute_type == @options[:type] || attribute.is_a?(@options[:type]))
        elsif @options[:type]
          attribute_type == @options[:type] || attribute.is_a?(@options[:type])
        else
          true
        end
      end
    end
  end
end

legendetm avatar Mar 23 '16 13:03 legendetm