diff --git a/lib/validates_timeliness/validate_timeliness_matcher.rb b/lib/validates_timeliness/validate_timeliness_matcher.rb index 1740582..7524b51 100644 --- a/lib/validates_timeliness/validate_timeliness_matcher.rb +++ b/lib/validates_timeliness/validate_timeliness_matcher.rb @@ -2,40 +2,52 @@ 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 error_messages - messages = ActiveRecord::Base.send(:timeliness_default_error_messages) - messages = messages.inject({}) {|h , (k, v)| h[k] = v.sub('%s', '') } - @options.reverse_merge!(messages) - end def matches?(record) @record = record + type = options[:type] + + conversion_method = case type + when :time then :to_dummy_time + when :date then :to_date + when :datetime then :to_time + end + + 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'} + } - valid = error_matching('2000-01-32 00:00:00', /#{options[:invalid_datetime_message]}/) && - error_matching('2000-01-01 25:00:00', /#{options[:invalid_datetime_message]}/) && - no_error_matching('2000-01-01 00:00:00', /#{options[:invalid_datetime_message]}/) + valid = error_matching(test_values[type][:fail], /#{options["invalid_#{type}_message".to_sym]}/) && + no_error_matching(test_values[type][:pass], /#{options["invalid_#{type}_message".to_sym]}/) - if valid && after = options[:after] + if valid && options[:after] + after = parse(options[:after], type).send(conversion_method) valid = error_matching(after, /#{options[:after_message]}/) && no_error_matching(after + 1, /#{options[:after_message]}/) end - if valid && before = options[:before] - valid = error_matching(before, /#{options[:after_message]}/) && - no_error_matching(before - 1, /#{options[:after_message]}/) + if valid && options[:before] + before = parse(options[:before], type).send(conversion_method) + valid = error_matching(before, /#{options[:before_message]}/) && + no_error_matching(before - 1, /#{options[:before_message]}/) end - if valid && on_or_after = options[:on_or_after] + if valid && options[:on_or_after] + on_or_after = parse(options[:on_or_after], type).send(conversion_method) valid = error_matching(on_or_after -1, /#{options[:on_or_after_message]}/) && no_error_matching(on_or_after, /#{options[:on_or_after_message]}/) end - if valid && on_or_before = options[:on_or_before] + if valid && options[:on_or_before] + on_or_before = parse(options[:on_or_before], type).send(conversion_method) valid = error_matching(on_or_before + 1, /#{options[:on_or_before_message]}/) && no_error_matching(on_or_before, /#{options[:on_or_before_message]}/) end @@ -56,7 +68,16 @@ module Spec end private - attr_reader :actual, :expected, :record, :options, :last_failure + + def parse(value, type) + ActiveRecord::Base.parse_date_time(value, type) + 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) @@ -80,14 +101,26 @@ module Spec pass end end - - def validate_timeliness_of(attribute, options={}) - ValidateTimeliness.new(attribute, options) + + def validate_date(attribute, options={}) + options[:type] = :date + validate_timeliness_of(attribute, options) end - - alias validate_date validate_timeliness_of - alias validate_time validate_timeliness_of - alias validate_datetime validate_timeliness_of + + 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 diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 1e37f55..62bff14 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,6 +1,8 @@ $:.unshift(File.dirname(__FILE__) + '/../lib') $:.unshift(File.dirname(__FILE__)) +ENV['RAILS_ENV'] = 'test' + require 'rubygems' require 'spec' require 'spec/interop/test' diff --git a/spec/validate_timeliness_matcher_spec.rb b/spec/validate_timeliness_matcher_spec.rb new file mode 100644 index 0000000..8922d58 --- /dev/null +++ b/spec/validate_timeliness_matcher_spec.rb @@ -0,0 +1,105 @@ +require File.dirname(__FILE__) + '/spec_helper' + +describe Spec::Rails::Matchers, "ValidateTimeliness matcher" do + attr_accessor :no_validation, :with_validation + + before do + class Person < ActiveRecord::Base + alias_attribute :birth_datetime, :birth_date_and_time + end + + class PersonWithValidations < Person + validates_date :birth_date, :before => '2000-01-10', :after => '2000-01-01' + validates_time :birth_time, :before => '23:00', :after => '09:00' + validates_datetime :birth_date_and_time, :before => '2000-01-10 23:00', :after => '2000-01-01 09:00' + + alias_attribute :birth_datetime, :birth_date_and_time + end + @no_validation = Person.new + @with_validation = PersonWithValidations.new + end + + [:date, :time, :datetime].each do |type| + attribute = type == :datetime ? :date_and_time : type + + it "should correctly report that #{type} is validated" do + with_validation.should self.send("validate_#{type}", "birth_#{attribute}".to_sym) + end + + it "should correctly report that #{type} is not validated" do + no_validation.should_not self.send("validate_#{type}", "birth_#{attribute}".to_sym) + end + end + + describe "with before option" do + test_values = { + :date => ['2000-01-10', '2000-01-11'], + :time => ['23:00', '22:59'], + :datetime => ['2000-01-10 23:00', '2000-01-10 22:59'] + } + + [:date, :time, :datetime].each do |type| + attribute = type == :datetime ? :date_and_time : type + + it "should correctly report that #{type} is validated" do + with_validation.should self.send("validate_#{type}", "birth_#{attribute}", :before => test_values[type][0]) + end + + it "should correctly report that #{type} is not validated when option value is incorrect" do + with_validation.should_not self.send("validate_#{type}", "birth_#{attribute}", :before => test_values[type][1]) + end + + it "should correctly report that #{type} is not validated with option" do + no_validation.should_not self.send("validate_#{type}", "birth_#{attribute}", :before => test_values[type][0]) + end + end + end + + describe "with after option" do + test_values = { + :date => ['2000-01-01', '2000-01-02'], + :time => ['09:00', '09:01'], + :datetime => ['2000-01-01 09:00', '2000-01-01 09:01'] + } + + [:date, :time, :datetime].each do |type| + attribute = type == :datetime ? :date_and_time : type + + it "should correctly report that #{type} is validated" do + with_validation.should self.send("validate_#{type}", "birth_#{attribute}", :after => test_values[type][0]) + end + + it "should correctly report that #{type} is not validated when option value is incorrect" do + with_validation.should_not self.send("validate_#{type}", "birth_#{attribute}", :after => test_values[type][1]) + end + + it "should correctly report that #{type} is not validated with option" do + no_validation.should_not self.send("validate_#{type}", "birth_#{attribute}", :after => test_values[type][0]) + end + end + end + +# describe "with on_or_before option" do +# test_values = { +# :date => ['2000-01-01', '2000-01-02'], +# :time => ['09:00', '09:01'], +# :datetime => ['2000-01-01 09:00', '2000-01-01 09:01'] +# } +# +# [:date, :time, :datetime].each do |type| +# attribute = type == :datetime ? :date_and_time : type + +# it "should correctly report that #{type} is validated" do +# with_validation.should self.send("validate_#{type}", "birth_#{attribute}", :after => test_values[type][0]) +# end +# +# it "should correctly report that #{type} is not validated when option value is incorrect" do +# with_validation.should_not self.send("validate_#{type}", "birth_#{attribute}", :after => test_values[type][1]) +# end +# +# it "should correctly report that #{type} is not validated with option" do +# no_validation.should_not self.send("validate_#{type}", "birth_#{attribute}", :after => test_values[type][0]) +# end +# end +# end +end