markos_validates_timeliness 2.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. data/CHANGELOG +121 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +402 -0
  4. data/Rakefile +52 -0
  5. data/TODO +8 -0
  6. data/lib/validates_timeliness/action_view/instance_tag.rb +52 -0
  7. data/lib/validates_timeliness/active_record/attribute_methods.rb +77 -0
  8. data/lib/validates_timeliness/active_record/multiparameter_attributes.rb +69 -0
  9. data/lib/validates_timeliness/formats.rb +368 -0
  10. data/lib/validates_timeliness/locale/en.new.yml +18 -0
  11. data/lib/validates_timeliness/locale/en.old.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/lib/validates_timeliness.rb +59 -0
  19. data/spec/action_view/instance_tag_spec.rb +194 -0
  20. data/spec/active_record/attribute_methods_spec.rb +157 -0
  21. data/spec/active_record/multiparameter_attributes_spec.rb +118 -0
  22. data/spec/formats_spec.rb +313 -0
  23. data/spec/ginger_scenarios.rb +19 -0
  24. data/spec/parser_spec.rb +65 -0
  25. data/spec/resources/application.rb +2 -0
  26. data/spec/resources/person.rb +3 -0
  27. data/spec/resources/schema.rb +10 -0
  28. data/spec/resources/sqlite_patch.rb +19 -0
  29. data/spec/spec/rails/matchers/validate_timeliness_spec.rb +245 -0
  30. data/spec/spec_helper.rb +58 -0
  31. data/spec/time_travel/MIT-LICENSE +20 -0
  32. data/spec/time_travel/time_extensions.rb +33 -0
  33. data/spec/time_travel/time_travel.rb +12 -0
  34. data/spec/validator_spec.rb +723 -0
  35. metadata +104 -0
@@ -0,0 +1,313 @@
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 nil if time hour is out of range for AM meridian" do
106
+ time_array = formats.parse('13:14 am', :time, :strict => true)
107
+ time_array.should == nil
108
+ time_array = formats.parse('00:14 am', :time, :strict => true)
109
+ time_array.should == nil
110
+ end
111
+
112
+ it "should return date array from time string" do
113
+ time_array = formats.parse('2000-02-01', :date, :strict => true)
114
+ time_array.should == [2000,2,1,0,0,0,0]
115
+ end
116
+
117
+ it "should return datetime array from string value" do
118
+ time_array = formats.parse('2000-02-01 12:13:14', :datetime, :strict => true)
119
+ time_array.should == [2000,2,1,12,13,14,0]
120
+ end
121
+
122
+ it "should parse date string when type is datetime" do
123
+ time_array = formats.parse('2000-02-01', :datetime, :strict => false)
124
+ time_array.should == [2000,2,1,0,0,0,0]
125
+ end
126
+
127
+ it "should ignore time when extracting date and strict is false" do
128
+ time_array = formats.parse('2000-02-01 12:13', :date, :strict => false)
129
+ time_array.should == [2000,2,1,0,0,0,0]
130
+ end
131
+
132
+ it "should ignore time when extracting date from format with trailing year and strict is false" do
133
+ time_array = formats.parse('01-02-2000 12:13', :date, :strict => false)
134
+ time_array.should == [2000,2,1,0,0,0,0]
135
+ end
136
+
137
+ it "should ignore date when extracting time and strict is false" do
138
+ time_array = formats.parse('2000-02-01 12:13', :time, :strict => false)
139
+ time_array.should == [2000,1,1,12,13,0,0]
140
+ end
141
+
142
+ it "should return zone offset when :include_offset option is true" do
143
+ time_array = formats.parse('2000-02-01T12:13:14-10:30', :datetime, :include_offset => true)
144
+ time_array.should == [2000,2,1,12,13,14,0,-37800]
145
+ end
146
+ end
147
+
148
+ describe "parse with format option" do
149
+ it "should return values if string matches specified format" do
150
+ time_array = formats.parse('2000-02-01 12:13:14', :datetime, :format => 'yyyy-mm-dd hh:nn:ss')
151
+ time_array.should == [2000,2,1,12,13,14,0]
152
+ end
153
+
154
+ it "should return nil if string does not match specified format" do
155
+ time_array = formats.parse('2000-02-01 12:13', :datetime, :format => 'yyyy-mm-dd hh:nn:ss')
156
+ time_array.should be_nil
157
+ end
158
+ end
159
+
160
+ describe "parsing date with ambiguous year" do
161
+ it "should return year in current century if year below threshold" do
162
+ time_array = formats.parse('01-02-29', :date)
163
+ time_array.should == [2029,2,1,0,0,0,0]
164
+ end
165
+
166
+ it "should return year in last century if year at or above threshold" do
167
+ time_array = formats.parse('01-02-30', :date)
168
+ time_array.should == [1930,2,1,0,0,0,0]
169
+ end
170
+
171
+ it "should allow custom threshold" do
172
+ default = ValidatesTimeliness::Formats.ambiguous_year_threshold
173
+ ValidatesTimeliness::Formats.ambiguous_year_threshold = 40
174
+ time_array = formats.parse('01-02-39', :date)
175
+ time_array.should == [2039,2,1,0,0,0,0]
176
+ time_array = formats.parse('01-02-40', :date)
177
+ time_array.should == [1940,2,1,0,0,0,0]
178
+ ValidatesTimeliness::Formats.ambiguous_year_threshold = default
179
+ end
180
+ end
181
+
182
+ describe "parse with custom dummy date values" do
183
+ before(:all) do
184
+ @old_dummy_date = formats.dummy_date_for_time_type
185
+ formats.dummy_date_for_time_type = [2009,1,1]
186
+ end
187
+
188
+ it "should return time array with custom dummy date" do
189
+ time_array = formats.parse('12:13:14', :time, :strict => true)
190
+ time_array.should == [2009,1,1,12,13,14,0]
191
+ end
192
+
193
+ after(:all) do
194
+ formats.dummy_date_for_time_type = @old_dummy_date
195
+ end
196
+ end
197
+
198
+ describe "parse ISO8601 datetime" do
199
+ it "should return array without zone offset when no offset in string" do
200
+ time_array = formats.parse('2000-02-01T12:13:14Z', :datetime, :strict => true)
201
+ time_array.should == [2000,2,1,12,13,14,0]
202
+ end
203
+
204
+ it "should return array with zone offset when offset in string" do
205
+ time_array = formats.parse('2000-02-01T12:13:14+10:00', :datetime, :strict => true)
206
+ time_array.should == [2000,2,1,12,13,14,0,36000]
207
+ end
208
+ end
209
+
210
+ describe "removing formats" do
211
+ it "should remove format from format array" do
212
+ formats.remove_formats(:time, 'h.nn_ampm')
213
+ formats.time_formats.should_not include("h o'clock")
214
+ end
215
+
216
+ it "should not match time after its format is removed" do
217
+ validate('2.12am', :time).should be_true
218
+ formats.remove_formats(:time, 'h.nn_ampm')
219
+ validate('2.12am', :time).should be_false
220
+ end
221
+
222
+ it "should raise error if format does not exist" do
223
+ lambda { formats.remove_formats(:time, "ss:hh:nn") }.should raise_error()
224
+ end
225
+
226
+ after do
227
+ formats.time_formats << 'h.nn_ampm'
228
+ formats.compile_format_expressions
229
+ end
230
+ end
231
+
232
+ describe "adding formats" do
233
+ before do
234
+ formats.compile_format_expressions
235
+ end
236
+
237
+ it "should add format to format array" do
238
+ formats.add_formats(:time, "h o'clock")
239
+ formats.time_formats.should include("h o'clock")
240
+ end
241
+
242
+ it "should match new format after its added" do
243
+ validate("12 o'clock", :time).should be_false
244
+ formats.add_formats(:time, "h o'clock")
245
+ validate("12 o'clock", :time).should be_true
246
+ end
247
+
248
+ it "should add format before specified format and be higher precedence" do
249
+ formats.add_formats(:time, "ss:hh:nn", :before => 'hh:nn:ss')
250
+ validate("59:23:58", :time).should be_true
251
+ time_array = formats.parse('59:23:58', :time)
252
+ time_array.should == [2000,1,1,23,58,59,0]
253
+ end
254
+
255
+ it "should raise error if format exists" do
256
+ lambda { formats.add_formats(:time, "hh:nn:ss") }.should raise_error()
257
+ end
258
+
259
+ it "should raise error if format exists" do
260
+ lambda { formats.add_formats(:time, "ss:hh:nn", :before => 'nn:hh:ss') }.should raise_error()
261
+ end
262
+
263
+ after do
264
+ formats.time_formats.delete("h o'clock")
265
+ formats.time_formats.delete("ss:hh:nn")
266
+ # reload class instead
267
+ end
268
+ end
269
+
270
+ describe "removing US formats" do
271
+ it "should validate a date as European format when US formats removed" do
272
+ time_array = formats.parse('01/02/2000', :date)
273
+ time_array.should == [2000, 1, 2,0,0,0,0]
274
+ formats.remove_us_formats
275
+ time_array = formats.parse('01/02/2000', :date)
276
+ time_array.should == [2000, 2, 1,0,0,0,0]
277
+ end
278
+
279
+ after do
280
+ # reload class
281
+ end
282
+ end
283
+
284
+
285
+ def formats
286
+ ValidatesTimeliness::Formats
287
+ end
288
+
289
+ def validate(time_string, type)
290
+ valid = false
291
+ formats.send("#{type}_expressions").each do |format, regexp, processor|
292
+ valid = true and break if /\A#{regexp}\Z/ =~ time_string
293
+ end
294
+ valid
295
+ end
296
+
297
+ def generate_regexp(format)
298
+ # wrap in line start and end anchors to emulate extract values method
299
+ /\A#{formats.send(:generate_format_expression, format)[0]}\Z/
300
+ end
301
+
302
+ def generate_regexp_str(format)
303
+ formats.send(:generate_format_expression, format)[0].inspect
304
+ end
305
+
306
+ def generate_proc(format)
307
+ formats.send(:generate_format_expression, format)[1]
308
+ end
309
+
310
+ def delete_format(type, format)
311
+ formats.send("#{type}_formats").delete(format)
312
+ end
313
+ 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', '2.3.6', '2.3.9']
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,65 @@
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 Time object for ISO 8601 string with time zone" do
12
+ parse("2000-01-01T12:23:42+09:00", :datetime).should be_kind_of(Time)
13
+ end
14
+
15
+ it "should return nil for time string with invalid date part" do
16
+ parse("2000-02-30 12:13:14", :datetime).should be_nil
17
+ end
18
+
19
+ it "should return nil for time string with invalid time part" do
20
+ parse("2000-02-01 25:13:14", :datetime).should be_nil
21
+ end
22
+
23
+ it "should return Time object when passed a Time object" do
24
+ parse(Time.now, :datetime).should be_kind_of(Time)
25
+ end
26
+
27
+ if RAILS_VER >= '2.1'
28
+ it "should convert time string into current timezone" do
29
+ Time.zone = 'Melbourne'
30
+ time = parse("2000-06-01 12:13:14", :datetime)
31
+ time.utc_offset.should == 10.hours
32
+ end
33
+ end
34
+
35
+ it "should return nil for invalid date string" do
36
+ parse("2000-02-30", :date).should be_nil
37
+ end
38
+
39
+ def parse(*args)
40
+ ValidatesTimeliness::Parser.parse(*args)
41
+ end
42
+ end
43
+
44
+ describe "make_time" do
45
+
46
+ if RAILS_VER >= '2.1'
47
+
48
+ it "should create time using current timezone" do
49
+ Time.zone = 'Melbourne'
50
+ time = ValidatesTimeliness::Parser.make_time([2000,1,1,12,0,0])
51
+ time.zone.should == "EST"
52
+ end
53
+
54
+ else
55
+
56
+ it "should create time using default timezone" do
57
+ time = ValidatesTimeliness::Parser.make_time([2000,1,1,12,0,0])
58
+ time.zone.should == "UTC"
59
+ end
60
+
61
+ end
62
+
63
+ end
64
+
65
+ 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