szilm-validates_timeliness 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. data/CHANGELOG +116 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +403 -0
  4. data/Rakefile +52 -0
  5. data/TODO +8 -0
  6. data/lib/validates_timeliness.rb +49 -0
  7. data/lib/validates_timeliness/action_view/instance_tag.rb +52 -0
  8. data/lib/validates_timeliness/active_record/attribute_methods.rb +77 -0
  9. data/lib/validates_timeliness/active_record/multiparameter_attributes.rb +69 -0
  10. data/lib/validates_timeliness/formats.rb +365 -0
  11. data/lib/validates_timeliness/locale/en.yml +18 -0
  12. data/lib/validates_timeliness/matcher.rb +1 -0
  13. data/lib/validates_timeliness/parser.rb +44 -0
  14. data/lib/validates_timeliness/spec/rails/matchers/validate_timeliness.rb +162 -0
  15. data/lib/validates_timeliness/validation_methods.rb +46 -0
  16. data/lib/validates_timeliness/validator.rb +230 -0
  17. data/lib/validates_timeliness/version.rb +3 -0
  18. data/spec/action_view/instance_tag_spec.rb +194 -0
  19. data/spec/active_record/attribute_methods_spec.rb +157 -0
  20. data/spec/active_record/multiparameter_attributes_spec.rb +118 -0
  21. data/spec/formats_spec.rb +306 -0
  22. data/spec/ginger_scenarios.rb +19 -0
  23. data/spec/parser_spec.rb +61 -0
  24. data/spec/resources/application.rb +2 -0
  25. data/spec/resources/person.rb +3 -0
  26. data/spec/resources/schema.rb +10 -0
  27. data/spec/resources/sqlite_patch.rb +19 -0
  28. data/spec/spec/rails/matchers/validate_timeliness_spec.rb +245 -0
  29. data/spec/spec_helper.rb +58 -0
  30. data/spec/time_travel/MIT-LICENSE +20 -0
  31. data/spec/time_travel/time_extensions.rb +33 -0
  32. data/spec/time_travel/time_travel.rb +12 -0
  33. data/spec/validator_spec.rb +713 -0
  34. metadata +102 -0
@@ -0,0 +1,306 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe ValidatesTimeliness::Formats do
4
+
5
+ describe "format proc generator" do
6
+ it "should generate proc which outputs date array with values in correct order" do
7
+ generate_proc('yyyy-mm-dd').call('2000', '1', '2').should == [2000,1,2,0,0,0,0]
8
+ end
9
+
10
+ it "should generate proc which outputs date array from format with different order" do
11
+ generate_proc('dd/mm/yyyy').call('2', '1', '2000').should == [2000,1,2,0,0,0,0]
12
+ end
13
+
14
+ it "should generate proc which outputs time array" do
15
+ generate_proc('hh:nn:ss').call('01', '02', '03').should == [0,0,0,1,2,3,0]
16
+ end
17
+
18
+ it "should generate proc which outputs time array with meridian 'pm' adjusted hour" do
19
+ generate_proc('hh:nn:ss ampm').call('01', '02', '03', 'pm').should == [0,0,0,13,2,3,0]
20
+ end
21
+
22
+ it "should generate proc which outputs time array with meridian 'am' unadjusted hour" do
23
+ generate_proc('hh:nn:ss ampm').call('01', '02', '03', 'am').should == [0,0,0,1,2,3,0]
24
+ end
25
+
26
+ it "should generate proc which outputs time array with microseconds" do
27
+ generate_proc('hh:nn:ss.u').call('01', '02', '03', '99').should == [0,0,0,1,2,3,990000]
28
+ end
29
+
30
+ it "should generate proc which outputs datetime array with zone offset" do
31
+ generate_proc('yyyy-mm-dd hh:nn:ss.u zo').call('2001', '02', '03', '04', '05', '06', '99', '+10:00').should == [2001,2,3,4,5,6,990000,36000]
32
+ end
33
+ end
34
+
35
+ describe "validate regexps" do
36
+
37
+ describe "for time formats" do
38
+ format_tests = {
39
+ 'hh:nn:ss' => {:pass => ['12:12:12', '01:01:01'], :fail => ['1:12:12', '12:1:12', '12:12:1', '12-12-12']},
40
+ 'hh-nn-ss' => {:pass => ['12-12-12', '01-01-01'], :fail => ['1-12-12', '12-1-12', '12-12-1', '12:12:12']},
41
+ 'h:nn' => {:pass => ['12:12', '1:01'], :fail => ['12:2', '12-12']},
42
+ 'h.nn' => {:pass => ['2.12', '12.12'], :fail => ['2.1', '12:12']},
43
+ 'h nn' => {:pass => ['2 12', '12 12'], :fail => ['2 1', '2.12', '12:12']},
44
+ 'h-nn' => {:pass => ['2-12', '12-12'], :fail => ['2-1', '2.12', '12:12']},
45
+ 'h:nn_ampm' => {:pass => ['2:12am', '2:12 pm', '2:12 AM', '2:12PM'], :fail => ['1:2am', '1:12 pm', '2.12am']},
46
+ 'h.nn_ampm' => {:pass => ['2.12am', '2.12 pm'], :fail => ['1:2am', '1:12 pm', '2:12am']},
47
+ 'h nn_ampm' => {:pass => ['2 12am', '2 12 pm'], :fail => ['1 2am', '1 12 pm', '2:12am']},
48
+ 'h-nn_ampm' => {:pass => ['2-12am', '2-12 pm'], :fail => ['1-2am', '1-12 pm', '2:12am']},
49
+ 'h_ampm' => {:pass => ['2am', '2 am', '12 pm'], :fail => ['1.am', '12 pm', '2:12am']},
50
+ }
51
+ format_tests.each do |format, values|
52
+ it "should correctly validate times in format '#{format}'" do
53
+ regexp = generate_regexp(format)
54
+ values[:pass].each {|value| value.should match(regexp)}
55
+ values[:fail].each {|value| value.should_not match(regexp)}
56
+ end
57
+ end
58
+ end
59
+
60
+ describe "for date formats" do
61
+ format_tests = {
62
+ 'yyyy/mm/dd' => {:pass => ['2000/02/01'], :fail => ['2000\02\01', '2000/2/1', '00/02/01']},
63
+ 'yyyy-mm-dd' => {:pass => ['2000-02-01'], :fail => ['2000\02\01', '2000-2-1', '00-02-01']},
64
+ 'yyyy.mm.dd' => {:pass => ['2000.02.01'], :fail => ['2000\02\01', '2000.2.1', '00.02.01']},
65
+ 'm/d/yy' => {:pass => ['2/1/01', '02/01/00', '02/01/2000'], :fail => ['2/1/0', '2.1.01']},
66
+ 'd/m/yy' => {:pass => ['1/2/01', '01/02/00', '01/02/2000'], :fail => ['1/2/0', '1.2.01']},
67
+ 'm\d\yy' => {:pass => ['2\1\01', '2\01\00', '02\01\2000'], :fail => ['2\1\0', '2/1/01']},
68
+ 'd\m\yy' => {:pass => ['1\2\01', '1\02\00', '01\02\2000'], :fail => ['1\2\0', '1/2/01']},
69
+ 'd-m-yy' => {:pass => ['1-2-01', '1-02-00', '01-02-2000'], :fail => ['1-2-0', '1/2/01']},
70
+ 'd.m.yy' => {:pass => ['1.2.01', '1.02.00', '01.02.2000'], :fail => ['1.2.0', '1/2/01']},
71
+ 'd mmm yy' => {:pass => ['1 Feb 00', '1 Feb 2000', '1 February 00', '01 February 2000'],
72
+ :fail => ['1 Fe 00', 'Feb 1 2000', '1 Feb 0']}
73
+ }
74
+ format_tests.each do |format, values|
75
+ it "should correctly validate dates in format '#{format}'" do
76
+ regexp = generate_regexp(format)
77
+ values[:pass].each {|value| value.should match(regexp)}
78
+ values[:fail].each {|value| value.should_not match(regexp)}
79
+ end
80
+ end
81
+ end
82
+
83
+ describe "for datetime formats" do
84
+ format_tests = {
85
+ 'ddd mmm d hh:nn:ss zo yyyy' => {:pass => ['Sat Jul 19 12:00:00 +1000 2008'], :fail => []},
86
+ 'yyyy-mm-ddThh:nn:ss(?:Z|zo)' => {:pass => ['2008-07-19T12:00:00+10:00', '2008-07-19T12:00:00Z'], :fail => ['2008-07-19T12:00:00Z+10:00']},
87
+ }
88
+ format_tests.each do |format, values|
89
+ it "should correctly validate datetimes in format '#{format}'" do
90
+ regexp = generate_regexp(format)
91
+ values[:pass].each {|value| value.should match(regexp)}
92
+ values[:fail].each {|value| value.should_not match(regexp)}
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ describe "parse" do
99
+
100
+ it "should return time array from date string" do
101
+ time_array = formats.parse('12:13:14', :time, :strict => true)
102
+ time_array.should == [2000,1,1,12,13,14,0]
103
+ end
104
+
105
+ it "should return date array from time string" do
106
+ time_array = formats.parse('2000-02-01', :date, :strict => true)
107
+ time_array.should == [2000,2,1,0,0,0,0]
108
+ end
109
+
110
+ it "should return datetime array from string value" do
111
+ time_array = formats.parse('2000-02-01 12:13:14', :datetime, :strict => true)
112
+ time_array.should == [2000,2,1,12,13,14,0]
113
+ end
114
+
115
+ it "should parse date string when type is datetime" do
116
+ time_array = formats.parse('2000-02-01', :datetime, :strict => false)
117
+ time_array.should == [2000,2,1,0,0,0,0]
118
+ end
119
+
120
+ it "should ignore time when extracting date and strict is false" do
121
+ time_array = formats.parse('2000-02-01 12:13', :date, :strict => false)
122
+ time_array.should == [2000,2,1,0,0,0,0]
123
+ end
124
+
125
+ it "should ignore time when extracting date from format with trailing year and strict is false" do
126
+ time_array = formats.parse('01-02-2000 12:13', :date, :strict => false)
127
+ time_array.should == [2000,2,1,0,0,0,0]
128
+ end
129
+
130
+ it "should ignore date when extracting time and strict is false" do
131
+ time_array = formats.parse('2000-02-01 12:13', :time, :strict => false)
132
+ time_array.should == [2000,1,1,12,13,0,0]
133
+ end
134
+
135
+ it "should return zone offset when :include_offset option is true" do
136
+ time_array = formats.parse('2000-02-01T12:13:14-10:30', :datetime, :include_offset => true)
137
+ time_array.should == [2000,2,1,12,13,14,0,-37800]
138
+ end
139
+ end
140
+
141
+ describe "parse with format option" do
142
+ it "should return values if string matches specified format" do
143
+ time_array = formats.parse('2000-02-01 12:13:14', :datetime, :format => 'yyyy-mm-dd hh:nn:ss')
144
+ time_array.should == [2000,2,1,12,13,14,0]
145
+ end
146
+
147
+ it "should return nil if string does not match specified format" do
148
+ time_array = formats.parse('2000-02-01 12:13', :datetime, :format => 'yyyy-mm-dd hh:nn:ss')
149
+ time_array.should be_nil
150
+ end
151
+ end
152
+
153
+ describe "parsing date with ambiguous year" do
154
+ it "should return year in current century if year below threshold" do
155
+ time_array = formats.parse('01-02-29', :date)
156
+ time_array.should == [2029,2,1,0,0,0,0]
157
+ end
158
+
159
+ it "should return year in last century if year at or above threshold" do
160
+ time_array = formats.parse('01-02-30', :date)
161
+ time_array.should == [1930,2,1,0,0,0,0]
162
+ end
163
+
164
+ it "should allow custom threshold" do
165
+ default = ValidatesTimeliness::Formats.ambiguous_year_threshold
166
+ ValidatesTimeliness::Formats.ambiguous_year_threshold = 40
167
+ time_array = formats.parse('01-02-39', :date)
168
+ time_array.should == [2039,2,1,0,0,0,0]
169
+ time_array = formats.parse('01-02-40', :date)
170
+ time_array.should == [1940,2,1,0,0,0,0]
171
+ ValidatesTimeliness::Formats.ambiguous_year_threshold = default
172
+ end
173
+ end
174
+
175
+ describe "parse with custom dummy date values" do
176
+ before(:all) do
177
+ @old_dummy_date = formats.dummy_date_for_time_type
178
+ formats.dummy_date_for_time_type = [2009,1,1]
179
+ end
180
+
181
+ it "should return time array with custom dummy date" do
182
+ time_array = formats.parse('12:13:14', :time, :strict => true)
183
+ time_array.should == [2009,1,1,12,13,14,0]
184
+ end
185
+
186
+ after(:all) do
187
+ formats.dummy_date_for_time_type = @old_dummy_date
188
+ end
189
+ end
190
+
191
+ describe "parse ISO8601 datetime" do
192
+ it "should return array without zone offset when no offset in string" do
193
+ time_array = formats.parse('2000-02-01T12:13:14Z', :datetime, :strict => true)
194
+ time_array.should == [2000,2,1,12,13,14,0]
195
+ end
196
+
197
+ it "should return array with zone offset when offset in string" do
198
+ time_array = formats.parse('2000-02-01T12:13:14+10:00', :datetime, :strict => true)
199
+ time_array.should == [2000,2,1,12,13,14,0,36000]
200
+ end
201
+ end
202
+
203
+ describe "removing formats" do
204
+ it "should remove format from format array" do
205
+ formats.remove_formats(:time, 'h.nn_ampm')
206
+ formats.time_formats.should_not include("h o'clock")
207
+ end
208
+
209
+ it "should not match time after its format is removed" do
210
+ validate('2.12am', :time).should be_true
211
+ formats.remove_formats(:time, 'h.nn_ampm')
212
+ validate('2.12am', :time).should be_false
213
+ end
214
+
215
+ it "should raise error if format does not exist" do
216
+ lambda { formats.remove_formats(:time, "ss:hh:nn") }.should raise_error()
217
+ end
218
+
219
+ after do
220
+ formats.time_formats << 'h.nn_ampm'
221
+ formats.compile_format_expressions
222
+ end
223
+ end
224
+
225
+ describe "adding formats" do
226
+ before do
227
+ formats.compile_format_expressions
228
+ end
229
+
230
+ it "should add format to format array" do
231
+ formats.add_formats(:time, "h o'clock")
232
+ formats.time_formats.should include("h o'clock")
233
+ end
234
+
235
+ it "should match new format after its added" do
236
+ validate("12 o'clock", :time).should be_false
237
+ formats.add_formats(:time, "h o'clock")
238
+ validate("12 o'clock", :time).should be_true
239
+ end
240
+
241
+ it "should add format before specified format and be higher precedence" do
242
+ formats.add_formats(:time, "ss:hh:nn", :before => 'hh:nn:ss')
243
+ validate("59:23:58", :time).should be_true
244
+ time_array = formats.parse('59:23:58', :time)
245
+ time_array.should == [2000,1,1,23,58,59,0]
246
+ end
247
+
248
+ it "should raise error if format exists" do
249
+ lambda { formats.add_formats(:time, "hh:nn:ss") }.should raise_error()
250
+ end
251
+
252
+ it "should raise error if format exists" do
253
+ lambda { formats.add_formats(:time, "ss:hh:nn", :before => 'nn:hh:ss') }.should raise_error()
254
+ end
255
+
256
+ after do
257
+ formats.time_formats.delete("h o'clock")
258
+ formats.time_formats.delete("ss:hh:nn")
259
+ # reload class instead
260
+ end
261
+ end
262
+
263
+ describe "removing US formats" do
264
+ it "should validate a date as European format when US formats removed" do
265
+ time_array = formats.parse('01/02/2000', :date)
266
+ time_array.should == [2000, 1, 2,0,0,0,0]
267
+ formats.remove_us_formats
268
+ time_array = formats.parse('01/02/2000', :date)
269
+ time_array.should == [2000, 2, 1,0,0,0,0]
270
+ end
271
+
272
+ after do
273
+ # reload class
274
+ end
275
+ end
276
+
277
+
278
+ def formats
279
+ ValidatesTimeliness::Formats
280
+ end
281
+
282
+ def validate(time_string, type)
283
+ valid = false
284
+ formats.send("#{type}_expressions").each do |format, regexp, processor|
285
+ valid = true and break if /\A#{regexp}\Z/ =~ time_string
286
+ end
287
+ valid
288
+ end
289
+
290
+ def generate_regexp(format)
291
+ # wrap in line start and end anchors to emulate extract values method
292
+ /\A#{formats.send(:generate_format_expression, format)[0]}\Z/
293
+ end
294
+
295
+ def generate_regexp_str(format)
296
+ formats.send(:generate_format_expression, format)[0].inspect
297
+ end
298
+
299
+ def generate_proc(format)
300
+ formats.send(:generate_format_expression, format)[1]
301
+ end
302
+
303
+ def delete_format(type, format)
304
+ formats.send("#{type}_formats").delete(format)
305
+ end
306
+ end
@@ -0,0 +1,19 @@
1
+ # For use with the ginger gem to test plugin against multiple versions of Rails.
2
+ #
3
+ # To use ginger:
4
+ #
5
+ # gem install ginger
6
+ #
7
+ # Then run
8
+ #
9
+ # ginger spec
10
+ #
11
+ Ginger.configure do |config|
12
+ rails_versions = ['2.0.2', '2.1.2', '2.2.2', '2.3.3', '2.3.4', '2.3.5']
13
+
14
+ rails_versions.each do |v|
15
+ g = Ginger::Scenario.new("Rails #{v}")
16
+ g['rails'] = v
17
+ config.scenarios << g.dup
18
+ end
19
+ end
@@ -0,0 +1,61 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe ValidatesTimeliness::Parser do
4
+ attr_accessor :person
5
+
6
+ describe "parse" do
7
+ it "should return time object for valid time string" do
8
+ parse("2000-01-01 12:13:14", :datetime).should be_kind_of(Time)
9
+ end
10
+
11
+ it "should return nil for time string with invalid date part" do
12
+ parse("2000-02-30 12:13:14", :datetime).should be_nil
13
+ end
14
+
15
+ it "should return nil for time string with invalid time part" do
16
+ parse("2000-02-01 25:13:14", :datetime).should be_nil
17
+ end
18
+
19
+ it "should return Time object when passed a Time object" do
20
+ parse(Time.now, :datetime).should be_kind_of(Time)
21
+ end
22
+
23
+ if RAILS_VER >= '2.1'
24
+ it "should convert time string into current timezone" do
25
+ Time.zone = 'Melbourne'
26
+ time = parse("2000-01-01 12:13:14", :datetime)
27
+ Time.zone.utc_offset.should == 10.hours
28
+ end
29
+ end
30
+
31
+ it "should return nil for invalid date string" do
32
+ parse("2000-02-30", :date).should be_nil
33
+ end
34
+
35
+ def parse(*args)
36
+ ValidatesTimeliness::Parser.parse(*args)
37
+ end
38
+ end
39
+
40
+ describe "make_time" do
41
+
42
+ if RAILS_VER >= '2.1'
43
+
44
+ it "should create time using current timezone" do
45
+ Time.zone = 'Melbourne'
46
+ time = ValidatesTimeliness::Parser.make_time([2000,1,1,12,0,0])
47
+ time.zone.should == "EST"
48
+ end
49
+
50
+ else
51
+
52
+ it "should create time using default timezone" do
53
+ time = ValidatesTimeliness::Parser.make_time([2000,1,1,12,0,0])
54
+ time.zone.should == "UTC"
55
+ end
56
+
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,2 @@
1
+ class ApplicationController; end
2
+
@@ -0,0 +1,3 @@
1
+ class Person < ActiveRecord::Base
2
+ set_table_name 'people'
3
+ end
@@ -0,0 +1,10 @@
1
+ ActiveRecord::Schema.define(:version => 1) do
2
+
3
+ create_table "people", :force => true do |t|
4
+ t.column "name", :string
5
+ t.column "birth_date_and_time", :datetime
6
+ t.column "birth_date", :date
7
+ t.column "birth_time", :time
8
+ end
9
+
10
+ end
@@ -0,0 +1,19 @@
1
+ # patches adapter in rails 2.0 which mistakenly made time attributes map to datetime column type
2
+ ActiveRecord::ConnectionAdapters::SQLiteAdapter.class_eval do
3
+ def native_database_types #:nodoc:
4
+ {
5
+ :primary_key => default_primary_key_type,
6
+ :string => { :name => "varchar", :limit => 255 },
7
+ :text => { :name => "text" },
8
+ :integer => { :name => "integer" },
9
+ :float => { :name => "float" },
10
+ :decimal => { :name => "decimal" },
11
+ :datetime => { :name => "datetime" },
12
+ :timestamp => { :name => "datetime" },
13
+ :time => { :name => "time" },
14
+ :date => { :name => "date" },
15
+ :binary => { :name => "blob" },
16
+ :boolean => { :name => "boolean" }
17
+ }
18
+ end
19
+ end
@@ -0,0 +1,245 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
+ require 'validates_timeliness/matcher'
3
+
4
+ class NoValidation < Person
5
+ end
6
+
7
+ class WithValidation < Person
8
+ validates_date :birth_date,
9
+ :is_at => '2000-01-01',
10
+ :before => '2000-01-10',
11
+ :after => '2000-01-01',
12
+ :on_or_before => '2000-01-09',
13
+ :on_or_after => '2000-01-02',
14
+ :between => ['2000-01-01', '2000-01-03']
15
+
16
+ validates_time :birth_time,
17
+ :is_at => '09:00',
18
+ :before => '23:00',
19
+ :after => '09:00',
20
+ :on_or_before => '22:00',
21
+ :on_or_after => '10:00',
22
+ :between => ['09:00', '17:00']
23
+
24
+ validates_datetime :birth_date_and_time,
25
+ :is_at => '2000-01-01 09:00',
26
+ :before => '2000-01-10 23:00',
27
+ :after => '2000-01-01 09:00',
28
+ :on_or_before => '2000-01-09 23:00',
29
+ :on_or_after => '2000-01-02 09:00',
30
+ :between => ['2000-01-01 09:00', '2000-01-01 17:00']
31
+
32
+ end
33
+
34
+ class CustomMessages < Person
35
+ validates_date :birth_date,
36
+ :invalid_date_message => 'is not really a date',
37
+ :before => '2000-01-10',
38
+ :before_message => 'is too late',
39
+ :after => '2000-01-01',
40
+ :after_message => 'is too early',
41
+ :on_or_before => '2000-01-09',
42
+ :on_or_before_message => 'is just too late',
43
+ :on_or_after => '2000-01-02',
44
+ :on_or_after_message => 'is just too early'
45
+ end
46
+
47
+ describe "ValidateTimeliness matcher" do
48
+ attr_accessor :no_validation, :with_validation
49
+
50
+ @@attribute_for_type = { :date => :birth_date, :time => :birth_time, :datetime => :birth_date_and_time }
51
+
52
+ before do
53
+ @no_validation = NoValidation.new
54
+ @with_validation = WithValidation.new
55
+ end
56
+
57
+ [:date, :time, :datetime].each do |type|
58
+
59
+ it "should report that #{type} is validated" do
60
+ with_validation.should self.send("validate_#{type}", attribute_for_type(type))
61
+ end
62
+
63
+ it "should report that #{type} is not validated" do
64
+ no_validation.should_not self.send("validate_#{type}", attribute_for_type(type))
65
+ end
66
+ end
67
+
68
+ describe "with is_at option" do
69
+ test_values = {
70
+ :date => ['2000-01-01', '2000-01-02'],
71
+ :time => ['09:00', '09:01'],
72
+ :datetime => ['2000-01-01 09:00', '2000-01-01 09:01']
73
+ }
74
+
75
+ [:date, :time, :datetime].each do |type|
76
+
77
+ it "should report that #{type} is validated" do
78
+ with_validation.should self.send("validate_#{type}", attribute_for_type(type), :is_at => test_values[type][0])
79
+ end
80
+
81
+ it "should report that #{type} is not validated when option value is incorrect" do
82
+ with_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :is_at => test_values[type][1])
83
+ end
84
+
85
+ it "should report that #{type} is not validated with option" do
86
+ no_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :is_at => test_values[type][0])
87
+ end
88
+ end
89
+ end
90
+
91
+ describe "with before option" do
92
+ test_values = {
93
+ :date => ['2000-01-10', '2000-01-11'],
94
+ :time => ['23:00', '22:59'],
95
+ :datetime => ['2000-01-10 23:00', '2000-01-10 22:59']
96
+ }
97
+
98
+ [:date, :time, :datetime].each do |type|
99
+
100
+ it "should report that #{type} is validated" do
101
+ with_validation.should self.send("validate_#{type}", attribute_for_type(type), :before => test_values[type][0])
102
+ end
103
+
104
+ it "should report that #{type} is not validated when option value is incorrect" do
105
+ with_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :before => test_values[type][1])
106
+ end
107
+
108
+ it "should report that #{type} is not validated with option" do
109
+ no_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :before => test_values[type][0])
110
+ end
111
+ end
112
+ end
113
+
114
+ describe "with after option" do
115
+ test_values = {
116
+ :date => ['2000-01-01', '2000-01-02'],
117
+ :time => ['09:00', '09:01'],
118
+ :datetime => ['2000-01-01 09:00', '2000-01-01 09:01']
119
+ }
120
+
121
+ [:date, :time, :datetime].each do |type|
122
+
123
+ it "should report that #{type} is validated" do
124
+ with_validation.should self.send("validate_#{type}", attribute_for_type(type), :after => test_values[type][0])
125
+ end
126
+
127
+ it "should report that #{type} is not validated when option value is incorrect" do
128
+ with_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :after => test_values[type][1])
129
+ end
130
+
131
+ it "should report that #{type} is not validated with option" do
132
+ no_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :after => test_values[type][0])
133
+ end
134
+ end
135
+ end
136
+
137
+ describe "with on_or_before option" do
138
+ test_values = {
139
+ :date => ['2000-01-09', '2000-01-08'],
140
+ :time => ['22:00', '21:59'],
141
+ :datetime => ['2000-01-09 23:00', '2000-01-09 22:59']
142
+ }
143
+
144
+ [:date, :time, :datetime].each do |type|
145
+
146
+ it "should report that #{type} is validated" do
147
+ with_validation.should self.send("validate_#{type}", attribute_for_type(type), :on_or_before => test_values[type][0])
148
+ end
149
+
150
+ it "should report that #{type} is not validated when option value is incorrect" do
151
+ with_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :on_or_before => test_values[type][1])
152
+ end
153
+
154
+ it "should report that #{type} is not validated with option" do
155
+ no_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :on_or_before => test_values[type][0])
156
+ end
157
+ end
158
+ end
159
+
160
+ describe "with on_or_after option" do
161
+ test_values = {
162
+ :date => ['2000-01-02', '2000-01-03'],
163
+ :time => ['10:00', '10:01'],
164
+ :datetime => ['2000-01-02 09:00', '2000-01-02 09:01']
165
+ }
166
+
167
+ [:date, :time, :datetime].each do |type|
168
+
169
+ it "should report that #{type} is validated" do
170
+ with_validation.should self.send("validate_#{type}", attribute_for_type(type), :on_or_after => test_values[type][0])
171
+ end
172
+
173
+ it "should report that #{type} is not validated when option value is incorrect" do
174
+ with_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :on_or_after => test_values[type][1])
175
+ end
176
+
177
+ it "should report that #{type} is not validated with option" do
178
+ no_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :on_or_after => test_values[type][0])
179
+ end
180
+ end
181
+ end
182
+
183
+ describe "between option" do
184
+ test_values = {
185
+ :date => [ ['2000-01-01', '2000-01-03'], ['2000-01-01', '2000-01-04'] ],
186
+ :time => [ ['09:00', '17:00'], ['09:00', '17:01'] ],
187
+ :datetime => [ ['2000-01-01 09:00', '2000-01-01 17:00'], ['2000-01-01 09:00', '2000-01-01 17:01'] ]
188
+ }
189
+
190
+ [:date, :time, :datetime].each do |type|
191
+
192
+ it "should report that #{type} is validated" do
193
+ with_validation.should self.send("validate_#{type}", attribute_for_type(type), :between => test_values[type][0])
194
+ end
195
+
196
+ it "should report that #{type} is not validated when option value is incorrect" do
197
+ with_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :between => test_values[type][1])
198
+ end
199
+
200
+ it "should report that #{type} is not validated with option" do
201
+ no_validation.should_not self.send("validate_#{type}", attribute_for_type(type), :between => test_values[type][0])
202
+ end
203
+ end
204
+ end
205
+
206
+ describe "custom messages" do
207
+
208
+ before do
209
+ @person = CustomMessages.new
210
+ end
211
+
212
+ it "should match error message for invalid" do
213
+ @person.should validate_date(:birth_date, :invalid_date_message => 'is not really a date')
214
+ end
215
+
216
+ it "should match error message for before option" do
217
+ @person.should validate_date(:birth_date, :before => '2000-01-10',
218
+ :invalid_date_message => 'is not really a date',
219
+ :before_message => 'is too late')
220
+ end
221
+
222
+ it "should match error message for after option" do
223
+ @person.should validate_date(:birth_date, :after => '2000-01-01',
224
+ :invalid_date_message => 'is not really a date',
225
+ :after_message => 'is too early')
226
+ end
227
+
228
+ it "should match error message for on_or_before option" do
229
+ @person.should validate_date(:birth_date, :on_or_before => '2000-01-09',
230
+ :invalid_date_message => 'is not really a date',
231
+ :on_or_before_message => 'is just too late')
232
+ end
233
+
234
+ it "should match error message for on_or_after option" do
235
+ @person.should validate_date(:birth_date, :on_or_after => '2000-01-02',
236
+ :invalid_date_message => 'is not really a date',
237
+ :on_or_after_message => 'is just too early')
238
+ end
239
+
240
+ end
241
+
242
+ def attribute_for_type(type)
243
+ @@attribute_for_type[type.to_sym]
244
+ end
245
+ end