module Shoulda module Matchers module ActiveRecord # The `define_enum_for` matcher is used to test that the `enum` macro has # been used to decorate an attribute with enum methods. # # class Process < ActiveRecord::Base # enum status: [:running, :stopped, :suspended] # end # # # RSpec # describe Process do # it { should define_enum_for(:status) } # end # end # # # Test::Unit # class ProcessTest < ActiveSupport::TestCase # should define_enum_for(:status) # end # # #### Qualifiers # # ##### with # # Use `with` to test that the enum has been defined with a certain set of # known values. # # class Process < ActiveRecord::Base # enum status: [:running, :stopped, :suspended] # end # # # RSpec # describe Process do # it do # should define_enum_for(:status). # with([:running, :stopped, :suspended]) # end # end # # # Test::Unit # class ProcessTest < ActiveSupport::TestCase # should define_enum_for(:status). # with([:running, :stopped, :suspended]) # end # # @return [DefineEnumForMatcher] # def define_enum_for(attribute_name) DefineEnumForMatcher.new(attribute_name) end # @private class DefineEnumForMatcher def initialize(attribute_name) @attribute_name = attribute_name @options = {} end def with(expected_enum_values) options[:expected_enum_values] = expected_enum_values self end def matches?(subject) @model = subject enum_defined? && enum_values_match? end def failure_message "Expected #{expectation}" end alias :failure_message_for_should :failure_message def failure_message_when_negated "Did not expect #{expectation}" end alias :failure_message_for_should_not :failure_message_when_negated def description desc = "define :#{attribute_name} as an enum" if options[:expected_enum_values] desc << " with #{options[:expected_enum_values]}" end desc end protected attr_reader :model, :attribute_name, :options def expectation "#{model.class.name} to #{description}" end def expected_enum_values hashify(options[:expected_enum_values]).with_indifferent_access end def enum_method attribute_name.to_s.pluralize end def actual_enum_values model.class.send(enum_method) end def enum_defined? model.class.respond_to?(enum_method) end def enum_values_match? expected_enum_values.empty? || actual_enum_values == expected_enum_values end def hashify(value) if value.nil? return {} end if value.is_a?(Array) new_value = {} value.each_with_index do |v, i| new_value[v] = i end new_value else value end end end end end end