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 Rails
|
||||||
module Matchers
|
module Matchers
|
||||||
class ValidateTimeliness
|
class ValidateTimeliness
|
||||||
cattr_accessor :test_values
|
|
||||||
|
|
||||||
@@test_values = {
|
VALIDITY_TEST_VALUES = {
|
||||||
:date => {:pass => '2000-01-01', :fail => '2000-01-32'},
|
:date => {:pass => '2000-01-01', :fail => '2000-01-32'},
|
||||||
:time => {:pass => '12:00', :fail => '25:00'},
|
:time => {:pass => '12:00', :fail => '25:00'},
|
||||||
:datetime => {:pass => '2000-01-01 00:00:00', :fail => '2000-01-32 00:00: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)
|
def initialize(attribute, options)
|
||||||
@expected, @options = attribute, options
|
@expected, @options = attribute, options
|
||||||
@validator = ValidatesTimeliness::Validator.new(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
|
end
|
||||||
|
|
||||||
def matches?(record)
|
def matches?(record)
|
||||||
@record = record
|
@record = record
|
||||||
type = options[:type]
|
@type = options[:type]
|
||||||
|
|
||||||
invalid_value = @@test_values[type][:fail]
|
valid = test_validity
|
||||||
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_option(:before, :-) if options[:before] && valid
|
valid = test_option(:before) if @options[:before] && valid
|
||||||
valid = test_option(:after, :+) if options[:after] && 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_before) 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_after) if @options[:on_or_after] && valid
|
||||||
|
|
||||||
|
valid = test_between if @options[:between] && valid
|
||||||
|
|
||||||
return valid
|
return valid
|
||||||
end
|
end
|
||||||
|
|
||||||
def failure_message
|
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
|
end
|
||||||
|
|
||||||
def negative_failure_message
|
def negative_failure_message
|
||||||
"expected not to validate #{options[:type]} attribute #{expected.inspect}"
|
"expected not to validate #{@type} attribute #{@expected.inspect}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def description
|
def description
|
||||||
"have validated #{options[:type]} attribute #{expected.inspect}"
|
"have validated #{@type} attribute #{@expected.inspect}"
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
attr_reader :actual, :expected, :record, :options, :messages, :last_failure, :validator
|
|
||||||
|
|
||||||
def test_option(option, modifier, settings={})
|
def test_validity
|
||||||
settings.reverse_merge!(:modify_on => :valid)
|
invalid_value = VALIDITY_TEST_VALUES[@type][:fail]
|
||||||
boundary = parse_and_cast(options[option])
|
valid_value = parse_and_cast(VALIDITY_TEST_VALUES[@type][:pass])
|
||||||
|
error_matching(invalid_value, "invalid_#{@type}".to_sym) &&
|
||||||
valid_value, invalid_value = if settings[:modify_on] == :valid
|
no_error_matching(valid_value, "invalid_#{@type}".to_sym)
|
||||||
[ boundary.send(modifier, 1), boundary ]
|
|
||||||
else
|
|
||||||
[ boundary, boundary.send(modifier, 1) ]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
message = messages[option]
|
def test_option(option)
|
||||||
error_matching(invalid_value, /#{message}/) &&
|
settings = OPTION_TEST_SETTINGS[option]
|
||||||
no_error_matching(valid_value, /#{message}/)
|
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
|
end
|
||||||
|
|
||||||
def parse_and_cast(value)
|
def parse_and_cast(value)
|
||||||
value = validator.send(:restriction_value, value, record)
|
value = @validator.send(:restriction_value, value, @record)
|
||||||
validator.send(:type_cast_value, value)
|
@validator.send(:type_cast_value, value)
|
||||||
end
|
end
|
||||||
|
|
||||||
def error_matching(value, match)
|
def error_matching(value, option)
|
||||||
record.send("#{expected}=", value)
|
match = error_message_for(option)
|
||||||
record.valid?
|
@record.send("#{@expected}=", value)
|
||||||
errors = record.errors.on(expected)
|
@record.valid?
|
||||||
pass = [ errors ].flatten.any? {|error| match === error }
|
errors = @record.errors.on(@expected)
|
||||||
@last_failure = "error matching #{match.inspect} when value is #{format_value(value)}" unless pass
|
pass = [ errors ].flatten.any? {|error| /#{match}/ === error }
|
||||||
|
@last_failure = "error matching '#{match}' when value is #{format_value(value)}" unless pass
|
||||||
pass
|
pass
|
||||||
end
|
end
|
||||||
|
|
||||||
def no_error_matching(value, match)
|
def no_error_matching(value, option)
|
||||||
pass = !error_matching(value, match)
|
pass = !error_matching(value, option)
|
||||||
@last_failure = "no error matching #{match.inspect} when value is #{format_value(value)}" unless pass
|
unless pass
|
||||||
|
error = error_message_for(option)
|
||||||
|
@last_failure = "no error matching '#{error}' when value is #{format_value(value)}"
|
||||||
|
end
|
||||||
pass
|
pass
|
||||||
end
|
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)
|
def format_value(value)
|
||||||
return value if value.is_a?(String)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_date(attribute, options={})
|
def validate_date(attribute, options={})
|
||||||
options[:type] = :date
|
options[:type] = :date
|
||||||
validate_timeliness_of(attribute, options)
|
ValidateTimeliness.new(attribute, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_time(attribute, options={})
|
def validate_time(attribute, options={})
|
||||||
options[:type] = :time
|
options[:type] = :time
|
||||||
validate_timeliness_of(attribute, options)
|
ValidateTimeliness.new(attribute, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_datetime(attribute, options={})
|
def validate_datetime(attribute, options={})
|
||||||
options[:type] = :datetime
|
options[:type] = :datetime
|
||||||
validate_timeliness_of(attribute, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def validate_timeliness_of(attribute, options={})
|
|
||||||
ValidateTimeliness.new(attribute, options)
|
ValidateTimeliness.new(attribute, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -6,13 +6,17 @@ end
|
|||||||
class WithValidation < Person
|
class WithValidation < Person
|
||||||
validates_date :birth_date,
|
validates_date :birth_date,
|
||||||
:before => '2000-01-10', :after => '2000-01-01',
|
: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,
|
validates_time :birth_time,
|
||||||
:before => '23:00', :after => '09:00',
|
: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,
|
validates_datetime :birth_date_and_time,
|
||||||
:before => '2000-01-10 23:00', :after => '2000-01-01 09:00',
|
: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
|
end
|
||||||
|
|
||||||
@ -137,6 +141,29 @@ describe "ValidateTimeliness matcher" do
|
|||||||
end
|
end
|
||||||
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
|
describe "custom messages" do
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user