149 lines
3.7 KiB
Ruby
149 lines
3.7 KiB
Ruby
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
|
|
# RSpec.describe Process, type: :model do
|
|
# it { should define_enum_for(:status) }
|
|
# end
|
|
# end
|
|
#
|
|
# # Minitest (Shoulda)
|
|
# 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
|
|
# RSpec.describe Process, type: :model do
|
|
# it do
|
|
# should define_enum_for(:status).
|
|
# with([:running, :stopped, :suspended])
|
|
# end
|
|
# end
|
|
#
|
|
# # Minitest (Shoulda)
|
|
# 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)
|
|
@record = subject
|
|
enum_defined? && enum_values_match? && column_type_is_integer?
|
|
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 << " and store the value in a column with an integer type"
|
|
|
|
desc
|
|
end
|
|
|
|
protected
|
|
|
|
attr_reader :record, :attribute_name, :options
|
|
|
|
def expectation
|
|
"#{model.name} to #{description}"
|
|
end
|
|
|
|
def expected_enum_values
|
|
hashify(options[:expected_enum_values]).with_indifferent_access
|
|
end
|
|
|
|
def actual_enum_values
|
|
model.send(attribute_name.to_s.pluralize)
|
|
end
|
|
|
|
def enum_defined?
|
|
model.defined_enums.include?(attribute_name.to_s)
|
|
end
|
|
|
|
def enum_values_match?
|
|
expected_enum_values.empty? || actual_enum_values == expected_enum_values
|
|
end
|
|
|
|
def column_type_is_integer?
|
|
column.type == :integer
|
|
end
|
|
|
|
def column
|
|
model.columns_hash[attribute_name.to_s]
|
|
end
|
|
|
|
def model
|
|
record.class
|
|
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
|