mirror of
https://github.com/ditkrg/validates_timeliness.git
synced 2026-01-22 22:06:45 +00:00
added between option testing to matcher and refactored
This commit is contained in:
parent
45ab815039
commit
a71d6f7945
@ -2,120 +2,156 @@ module Spec
|
||||
module Rails
|
||||
module Matchers
|
||||
class ValidateTimeliness
|
||||
cattr_accessor :test_values
|
||||
|
||||
@@test_values = {
|
||||
VALIDITY_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'}
|
||||
}
|
||||
|
||||
OPTION_TEST_SETTINGS = {
|
||||
:before => { :method => :-, :modify_on => :valid },
|
||||
:after => { :method => :+, :modify_on => :valid },
|
||||
:on_or_before => { :method => :+, :modify_on => :invalid },
|
||||
:on_or_after => { :method => :-, :modify_on => :invalid }
|
||||
}
|
||||
|
||||
def initialize(attribute, options)
|
||||
@expected, @options = attribute, options
|
||||
@validator = ValidatesTimeliness::Validator.new(options)
|
||||
compile_error_messages
|
||||
end
|
||||
|
||||
def compile_error_messages
|
||||
messages = validator.send(:error_messages)
|
||||
@messages = messages.inject({}) {|h, (k, v)| h[k] = v.gsub(/ (\%s|\{\{\w*\}\})/, ''); h }
|
||||
end
|
||||
|
||||
def matches?(record)
|
||||
@record = record
|
||||
type = options[:type]
|
||||
@type = options[:type]
|
||||
|
||||
invalid_value = @@test_values[type][:fail]
|
||||
valid_value = parse_and_cast(@@test_values[type][:pass])
|
||||
valid = error_matching(invalid_value, /#{messages["invalid_#{type}".to_sym]}/) &&
|
||||
no_error_matching(valid_value, /#{messages["invalid_#{type}".to_sym]}/)
|
||||
valid = test_validity
|
||||
|
||||
valid = test_option(:before, :-) if options[:before] && valid
|
||||
valid = test_option(:after, :+) if options[:after] && valid
|
||||
valid = test_option(:before) if @options[:before] && valid
|
||||
valid = test_option(:after) if @options[:after] && valid
|
||||
|
||||
valid = test_option(:on_or_before, :+, :modify_on => :invalid) if options[:on_or_before] && valid
|
||||
valid = test_option(:on_or_after, :-, :modify_on => :invalid) if options[:on_or_after] && valid
|
||||
valid = test_option(:on_or_before) if @options[:on_or_before] && valid
|
||||
valid = test_option(:on_or_after) if @options[:on_or_after] && valid
|
||||
|
||||
valid = test_between if @options[:between] && valid
|
||||
|
||||
return valid
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"expected model to validate #{options[:type]} attribute #{expected.inspect} with #{last_failure}"
|
||||
"expected model to validate #{@type} attribute #{@expected.inspect} with #{@last_failure}"
|
||||
end
|
||||
|
||||
def negative_failure_message
|
||||
"expected not to validate #{options[:type]} attribute #{expected.inspect}"
|
||||
"expected not to validate #{@type} attribute #{@expected.inspect}"
|
||||
end
|
||||
|
||||
def description
|
||||
"have validated #{options[:type]} attribute #{expected.inspect}"
|
||||
"have validated #{@type} attribute #{@expected.inspect}"
|
||||
end
|
||||
|
||||
private
|
||||
attr_reader :actual, :expected, :record, :options, :messages, :last_failure, :validator
|
||||
|
||||
def test_option(option, modifier, settings={})
|
||||
settings.reverse_merge!(:modify_on => :valid)
|
||||
boundary = parse_and_cast(options[option])
|
||||
|
||||
valid_value, invalid_value = if settings[:modify_on] == :valid
|
||||
[ boundary.send(modifier, 1), boundary ]
|
||||
else
|
||||
[ boundary, boundary.send(modifier, 1) ]
|
||||
def test_validity
|
||||
invalid_value = VALIDITY_TEST_VALUES[@type][:fail]
|
||||
valid_value = parse_and_cast(VALIDITY_TEST_VALUES[@type][:pass])
|
||||
error_matching(invalid_value, "invalid_#{@type}".to_sym) &&
|
||||
no_error_matching(valid_value, "invalid_#{@type}".to_sym)
|
||||
end
|
||||
|
||||
message = messages[option]
|
||||
error_matching(invalid_value, /#{message}/) &&
|
||||
no_error_matching(valid_value, /#{message}/)
|
||||
def test_option(option)
|
||||
settings = OPTION_TEST_SETTINGS[option]
|
||||
boundary = parse_and_cast(@options[option])
|
||||
|
||||
method = settings[:method]
|
||||
|
||||
valid_value, invalid_value = if settings[:modify_on] == :valid
|
||||
[ boundary.send(method, 1), boundary ]
|
||||
else
|
||||
[ boundary, boundary.send(method, 1) ]
|
||||
end
|
||||
|
||||
error_matching(invalid_value, option) &&
|
||||
no_error_matching(valid_value, option)
|
||||
end
|
||||
|
||||
def test_before
|
||||
before = parse_and_cast(@options[:before])
|
||||
|
||||
error_matching(before - 1, :before) &&
|
||||
no_error_matching(before, :before)
|
||||
end
|
||||
|
||||
def test_between
|
||||
between = parse_and_cast(@options[:between])
|
||||
|
||||
error_matching(between.first - 1, :between) &&
|
||||
error_matching(between.last + 1, :between) &&
|
||||
no_error_matching(between.first, :between) &&
|
||||
no_error_matching(between.last, :between)
|
||||
end
|
||||
|
||||
def parse_and_cast(value)
|
||||
value = validator.send(:restriction_value, value, record)
|
||||
validator.send(:type_cast_value, value)
|
||||
value = @validator.send(:restriction_value, value, @record)
|
||||
@validator.send(:type_cast_value, value)
|
||||
end
|
||||
|
||||
def error_matching(value, match)
|
||||
record.send("#{expected}=", value)
|
||||
record.valid?
|
||||
errors = record.errors.on(expected)
|
||||
pass = [ errors ].flatten.any? {|error| match === error }
|
||||
@last_failure = "error matching #{match.inspect} when value is #{format_value(value)}" unless pass
|
||||
def error_matching(value, option)
|
||||
match = error_message_for(option)
|
||||
@record.send("#{@expected}=", value)
|
||||
@record.valid?
|
||||
errors = @record.errors.on(@expected)
|
||||
pass = [ errors ].flatten.any? {|error| /#{match}/ === error }
|
||||
@last_failure = "error matching '#{match}' when value is #{format_value(value)}" unless pass
|
||||
pass
|
||||
end
|
||||
|
||||
def no_error_matching(value, match)
|
||||
pass = !error_matching(value, match)
|
||||
@last_failure = "no error matching #{match.inspect} when value is #{format_value(value)}" unless pass
|
||||
def no_error_matching(value, option)
|
||||
pass = !error_matching(value, option)
|
||||
unless pass
|
||||
error = error_message_for(option)
|
||||
@last_failure = "no error matching '#{error}' when value is #{format_value(value)}"
|
||||
end
|
||||
pass
|
||||
end
|
||||
|
||||
def error_message_for(option)
|
||||
msg = @validator.send(:error_messages)[option]
|
||||
restriction = @validator.send(:restriction_value, @validator.configuration[option], @record)
|
||||
|
||||
if restriction
|
||||
restriction = [restriction] unless restriction.is_a?(Array)
|
||||
restriction.map! {|r| @validator.send(:type_cast_value, r) }
|
||||
interpolate = @validator.send(:interpolation_values, option, restriction )
|
||||
if defined?(I18n)
|
||||
msg = @record.errors.generate_message(@expected, option, interpolate)
|
||||
else
|
||||
msg = msg % interpolate
|
||||
end
|
||||
end
|
||||
msg
|
||||
end
|
||||
|
||||
def format_value(value)
|
||||
return value if value.is_a?(String)
|
||||
value.strftime(ValidatesTimeliness::Validator.error_value_formats[options[:type]])
|
||||
value.strftime(ValidatesTimeliness::Validator.error_value_formats[@type])
|
||||
end
|
||||
end
|
||||
|
||||
def validate_date(attribute, options={})
|
||||
options[:type] = :date
|
||||
validate_timeliness_of(attribute, options)
|
||||
ValidateTimeliness.new(attribute, options)
|
||||
end
|
||||
|
||||
def validate_time(attribute, options={})
|
||||
options[:type] = :time
|
||||
validate_timeliness_of(attribute, options)
|
||||
ValidateTimeliness.new(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
|
||||
|
||||
@ -6,13 +6,17 @@ end
|
||||
class WithValidation < Person
|
||||
validates_date :birth_date,
|
||||
:before => '2000-01-10', :after => '2000-01-01',
|
||||
:on_or_before => '2000-01-09', :on_or_after => '2000-01-02'
|
||||
:on_or_before => '2000-01-09', :on_or_after => '2000-01-02',
|
||||
:between => ['2000-01-01', '2000-01-03']
|
||||
|
||||
validates_time :birth_time,
|
||||
:before => '23:00', :after => '09:00',
|
||||
:on_or_before => '22:00', :on_or_after => '10:00'
|
||||
:on_or_before => '22:00', :on_or_after => '10:00',
|
||||
:between => ['09:00', '17:00']
|
||||
validates_datetime :birth_date_and_time,
|
||||
:before => '2000-01-10 23:00', :after => '2000-01-01 09:00',
|
||||
:on_or_before => '2000-01-09 23:00', :on_or_after => '2000-01-02 09:00'
|
||||
:on_or_before => '2000-01-09 23:00', :on_or_after => '2000-01-02 09:00',
|
||||
:between => ['2000-01-01 09:00', '2000-01-01 17:00']
|
||||
|
||||
end
|
||||
|
||||
@ -137,6 +141,29 @@ describe "ValidateTimeliness matcher" do
|
||||
end
|
||||
end
|
||||
|
||||
describe "between option" do
|
||||
test_values = {
|
||||
:date => [ ['2000-01-01', '2000-01-03'], ['2000-01-01', '2000-01-04'] ],
|
||||
:time => [ ['09:00', '17:00'], ['09:00', '17:01'] ],
|
||||
:datetime => [ ['2000-01-01 09:00', '2000-01-01 17:00'], ['2000-01-01 09:00', '2000-01-01 17:01'] ]
|
||||
}
|
||||
|
||||
[:date, :time, :datetime].each do |type|
|
||||
|
||||
it "should report that #{type} is validated" do
|
||||
with_validation.should self.send("validate_#{type}", attribute_for_type(type), :between => test_values[type][0])
|
||||
end
|
||||
|
||||
it "should report that #{type} is not validated when option value is incorrect" do
|
||||
with_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :between => test_values[type][1])
|
||||
end
|
||||
|
||||
it "should report that #{type} is not validated with option" do
|
||||
no_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :between => test_values[type][0])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "custom messages" do
|
||||
|
||||
before do
|
||||
|
||||
Loading…
Reference in New Issue
Block a user