mirror of
https://github.com/ditkrg/validates_timeliness.git
synced 2026-01-24 23:06:42 +00:00
127 lines
4.4 KiB
Ruby
127 lines
4.4 KiB
Ruby
module Spec
|
|
module Rails
|
|
module Matchers
|
|
class ValidateTimeliness
|
|
attr_reader :actual, :expected, :record, :options, :last_failure
|
|
|
|
def initialize(attribute, options)
|
|
@expected, @options = attribute, options
|
|
@options.reverse_merge!(error_messages)
|
|
end
|
|
|
|
def matches?(record)
|
|
@record = record
|
|
type = options[:type]
|
|
|
|
test_values = {
|
|
:date => {:pass => '2000-01-01', :fail => '2000-01-32'},
|
|
:time => {:pass => '12:00', :fail => '25:00'},
|
|
:datetime => {:pass => '2000-01-01 00:00:00', :fail => '2000-01-32 00:00:00'}
|
|
}
|
|
|
|
invalid_value = test_values[type][:fail]
|
|
valid_value = parse_and_cast(test_values[type][:pass])
|
|
valid = error_matching(invalid_value, /#{options["invalid_#{type}_message".to_sym]}/) &&
|
|
no_error_matching(valid_value, /#{options["invalid_#{type}_message".to_sym]}/)
|
|
|
|
valid = test_option(:before, :-) if options[:before] && valid
|
|
valid = test_option(:after, :+) if options[:after] && valid
|
|
|
|
valid = test_option(:on_or_before, :+, :pre) if options[:on_or_before] && valid
|
|
valid = test_option(:on_or_after, :-, :pre) if options[:on_or_after] && valid
|
|
|
|
return valid
|
|
end
|
|
|
|
def failure_message
|
|
"expected model to validate #{options[:type]} attribute #{expected.inspect} with #{last_failure}"
|
|
end
|
|
|
|
def negative_failure_message
|
|
"expected not to validate #{options[:type]} attribute #{expected.inspect}"
|
|
end
|
|
|
|
def description
|
|
"have validated #{options[:type]} attribute #{expected.inspect}"
|
|
end
|
|
|
|
private
|
|
|
|
def test_option(option, modifier, modify_when=:post)
|
|
boundary = parse_and_cast(options[option])
|
|
|
|
valid_value = modify_when == :post ? boundary.send(modifier, 1) : boundary
|
|
invalid_value = modify_when == :post ? boundary : boundary.send(modifier, 1)
|
|
|
|
message = options["#{option}_message".to_sym]
|
|
error_matching(invalid_value, /#{message}/) &&
|
|
no_error_matching(valid_value, /#{message}/)
|
|
end
|
|
|
|
def parse_and_cast(value)
|
|
@conversion_method ||= case options[:type]
|
|
when :time then :to_dummy_time
|
|
when :date then :to_date
|
|
when :datetime then :to_time
|
|
end
|
|
value = ActiveRecord::Base.parse_date_time(value, options[:type])
|
|
value.send(@conversion_method)
|
|
end
|
|
|
|
def error_messages
|
|
messages = ActiveRecord::Base.send(:timeliness_default_error_messages)
|
|
messages = messages.inject({}) {|h, (k, v)| h[k] = v.sub(' %s', ''); h }
|
|
@options.reverse_merge!(messages)
|
|
end
|
|
|
|
def error_matching(value, match)
|
|
record.send("#{expected}=", value)
|
|
record.valid?
|
|
errors = record.errors.on(expected)
|
|
pass = case errors
|
|
when String
|
|
match === errors
|
|
when Array
|
|
errors.any? {|error| match === error }
|
|
else
|
|
false
|
|
end
|
|
@last_failure = "error matching #{match.inspect} when value is #{format_value(value)}" unless pass
|
|
pass
|
|
end
|
|
|
|
def no_error_matching(value, match)
|
|
pass = !error_matching(value, match)
|
|
@last_failure = "error matching #{match.inspect} when value is #{format_value(value)}" unless pass
|
|
pass
|
|
end
|
|
|
|
def format_value(value)
|
|
return value if value.is_a?(String)
|
|
value.strftime(ActiveRecord::Errors.date_time_error_value_formats[options[:type]])
|
|
end
|
|
end
|
|
|
|
def validate_date(attribute, options={})
|
|
options[:type] = :date
|
|
validate_timeliness_of(attribute, options)
|
|
end
|
|
|
|
def validate_time(attribute, options={})
|
|
options[:type] = :time
|
|
validate_timeliness_of(attribute, options)
|
|
end
|
|
|
|
def validate_datetime(attribute, options={})
|
|
options[:type] = :datetime
|
|
validate_timeliness_of(attribute, options)
|
|
end
|
|
|
|
private
|
|
def validate_timeliness_of(attribute, options={})
|
|
ValidateTimeliness.new(attribute, options)
|
|
end
|
|
end
|
|
end
|
|
end
|