Updated README.rdoc again
[feedcatcher.git] / vendor / rails / activerecord / test / cases / validations_test.rb
1 # encoding: utf-8
2 require "cases/helper"
3 require 'models/topic'
4 require 'models/reply'
5 require 'models/person'
6 require 'models/developer'
7 require 'models/warehouse_thing'
8 require 'models/guid'
9 require 'models/owner'
10 require 'models/pet'
11 require 'models/event'
12
13 # The following methods in Topic are used in test_conditional_validation_*
14 class Topic
15 has_many :unique_replies, :dependent => :destroy, :foreign_key => "parent_id"
16 has_many :silly_unique_replies, :dependent => :destroy, :foreign_key => "parent_id"
17
18 def condition_is_true
19 true
20 end
21
22 def condition_is_true_but_its_not
23 false
24 end
25 end
26
27 class ProtectedPerson < ActiveRecord::Base
28 set_table_name 'people'
29 attr_accessor :addon
30 attr_protected :first_name
31 end
32
33 class UniqueReply < Reply
34 validates_uniqueness_of :content, :scope => 'parent_id'
35 end
36
37 class SillyUniqueReply < UniqueReply
38 end
39
40 class Wizard < ActiveRecord::Base
41 self.abstract_class = true
42
43 validates_uniqueness_of :name
44 end
45
46 class IneptWizard < Wizard
47 validates_uniqueness_of :city
48 end
49
50 class Conjurer < IneptWizard
51 end
52
53 class Thaumaturgist < IneptWizard
54 end
55
56
57 class ValidationsTest < ActiveRecord::TestCase
58 fixtures :topics, :developers, 'warehouse-things'
59
60 # Most of the tests mess with the validations of Topic, so lets repair it all the time.
61 # Other classes we mess with will be dealt with in the specific tests
62 repair_validations(Topic)
63
64 def test_single_field_validation
65 r = Reply.new
66 r.title = "There's no content!"
67 assert !r.valid?, "A reply without content shouldn't be saveable"
68
69 r.content = "Messa content!"
70 assert r.valid?, "A reply with content should be saveable"
71 end
72
73 def test_single_attr_validation_and_error_msg
74 r = Reply.new
75 r.title = "There's no content!"
76 assert !r.valid?
77 assert r.errors.invalid?("content"), "A reply without content should mark that attribute as invalid"
78 assert_equal "Empty", r.errors.on("content"), "A reply without content should contain an error"
79 assert_equal 1, r.errors.count
80 end
81
82 def test_double_attr_validation_and_error_msg
83 r = Reply.new
84 assert !r.valid?
85
86 assert r.errors.invalid?("title"), "A reply without title should mark that attribute as invalid"
87 assert_equal "Empty", r.errors.on("title"), "A reply without title should contain an error"
88
89 assert r.errors.invalid?("content"), "A reply without content should mark that attribute as invalid"
90 assert_equal "Empty", r.errors.on("content"), "A reply without content should contain an error"
91
92 assert_equal 2, r.errors.count
93 end
94
95 def test_error_on_create
96 r = Reply.new
97 r.title = "Wrong Create"
98 assert !r.valid?
99 assert r.errors.invalid?("title"), "A reply with a bad title should mark that attribute as invalid"
100 assert_equal "is Wrong Create", r.errors.on("title"), "A reply with a bad content should contain an error"
101 end
102
103 def test_error_on_update
104 r = Reply.new
105 r.title = "Bad"
106 r.content = "Good"
107 assert r.save, "First save should be successful"
108
109 r.title = "Wrong Update"
110 assert !r.save, "Second save should fail"
111
112 assert r.errors.invalid?("title"), "A reply with a bad title should mark that attribute as invalid"
113 assert_equal "is Wrong Update", r.errors.on("title"), "A reply with a bad content should contain an error"
114 end
115
116 def test_invalid_record_exception
117 assert_raise(ActiveRecord::RecordInvalid) { Reply.create! }
118 assert_raise(ActiveRecord::RecordInvalid) { Reply.new.save! }
119
120 begin
121 r = Reply.new
122 r.save!
123 flunk
124 rescue ActiveRecord::RecordInvalid => invalid
125 assert_equal r, invalid.record
126 end
127 end
128
129 def test_exception_on_create_bang_many
130 assert_raise(ActiveRecord::RecordInvalid) do
131 Reply.create!([ { "title" => "OK" }, { "title" => "Wrong Create" }])
132 end
133 end
134
135 def test_exception_on_create_bang_with_block
136 assert_raise(ActiveRecord::RecordInvalid) do
137 Reply.create!({ "title" => "OK" }) do |r|
138 r.content = nil
139 end
140 end
141 end
142
143 def test_exception_on_create_bang_many_with_block
144 assert_raise(ActiveRecord::RecordInvalid) do
145 Reply.create!([{ "title" => "OK" }, { "title" => "Wrong Create" }]) do |r|
146 r.content = nil
147 end
148 end
149 end
150
151 def test_scoped_create_without_attributes
152 Reply.with_scope(:create => {}) do
153 assert_raise(ActiveRecord::RecordInvalid) { Reply.create! }
154 end
155 end
156
157 def test_create_with_exceptions_using_scope_for_protected_attributes
158 assert_nothing_raised do
159 ProtectedPerson.with_scope( :create => { :first_name => "Mary" } ) do
160 person = ProtectedPerson.create! :addon => "Addon"
161 assert_equal person.first_name, "Mary", "scope should ignore attr_protected"
162 end
163 end
164 end
165
166 def test_create_with_exceptions_using_scope_and_empty_attributes
167 assert_nothing_raised do
168 ProtectedPerson.with_scope( :create => { :first_name => "Mary" } ) do
169 person = ProtectedPerson.create!
170 assert_equal person.first_name, "Mary", "should be ok when no attributes are passed to create!"
171 end
172 end
173 end
174
175 def test_single_error_per_attr_iteration
176 r = Reply.new
177 r.save
178
179 errors = []
180 r.errors.each { |attr, msg| errors << [attr, msg] }
181
182 assert errors.include?(["title", "Empty"])
183 assert errors.include?(["content", "Empty"])
184 end
185
186 def test_multiple_errors_per_attr_iteration_with_full_error_composition
187 r = Reply.new
188 r.title = "Wrong Create"
189 r.content = "Mismatch"
190 r.save
191
192 errors = []
193 r.errors.each_full { |error| errors << error }
194
195 assert_equal "Title is Wrong Create", errors[0]
196 assert_equal "Title is Content Mismatch", errors[1]
197 assert_equal 2, r.errors.count
198 end
199
200 def test_errors_on_base
201 r = Reply.new
202 r.content = "Mismatch"
203 r.save
204 r.errors.add_to_base "Reply is not dignifying"
205
206 errors = []
207 r.errors.each_full { |error| errors << error }
208
209 assert_equal "Reply is not dignifying", r.errors.on_base
210
211 assert errors.include?("Title Empty")
212 assert errors.include?("Reply is not dignifying")
213 assert_equal 2, r.errors.count
214 end
215
216 def test_create_without_validation
217 reply = Reply.new
218 assert !reply.save
219 assert reply.save(false)
220 end
221
222 def test_create_without_validation_bang
223 count = Reply.count
224 assert_nothing_raised { Reply.new.save_without_validation! }
225 assert count+1, Reply.count
226 end
227
228 def test_validates_each
229 hits = 0
230 Topic.validates_each(:title, :content, [:title, :content]) do |record, attr|
231 record.errors.add attr, 'gotcha'
232 hits += 1
233 end
234 t = Topic.new("title" => "valid", "content" => "whatever")
235 assert !t.save
236 assert_equal 4, hits
237 assert_equal %w(gotcha gotcha), t.errors.on(:title)
238 assert_equal %w(gotcha gotcha), t.errors.on(:content)
239 end
240
241 def test_no_title_confirmation
242 Topic.validates_confirmation_of(:title)
243
244 t = Topic.new(:author_name => "Plutarch")
245 assert t.valid?
246
247 t.title_confirmation = "Parallel Lives"
248 assert !t.valid?
249
250 t.title_confirmation = nil
251 t.title = "Parallel Lives"
252 assert t.valid?
253
254 t.title_confirmation = "Parallel Lives"
255 assert t.valid?
256 end
257
258 def test_title_confirmation
259 Topic.validates_confirmation_of(:title)
260
261 t = Topic.create("title" => "We should be confirmed","title_confirmation" => "")
262 assert !t.save
263
264 t.title_confirmation = "We should be confirmed"
265 assert t.save
266 end
267
268 def test_terms_of_service_agreement_no_acceptance
269 Topic.validates_acceptance_of(:terms_of_service, :on => :create)
270
271 t = Topic.create("title" => "We should not be confirmed")
272 assert t.save
273 end
274
275 def test_terms_of_service_agreement
276 Topic.validates_acceptance_of(:terms_of_service, :on => :create)
277
278 t = Topic.create("title" => "We should be confirmed","terms_of_service" => "")
279 assert !t.save
280 assert_equal "must be accepted", t.errors.on(:terms_of_service)
281
282 t.terms_of_service = "1"
283 assert t.save
284 end
285
286
287 def test_eula
288 Topic.validates_acceptance_of(:eula, :message => "must be abided", :on => :create)
289
290 t = Topic.create("title" => "We should be confirmed","eula" => "")
291 assert !t.save
292 assert_equal "must be abided", t.errors.on(:eula)
293
294 t.eula = "1"
295 assert t.save
296 end
297
298 def test_terms_of_service_agreement_with_accept_value
299 Topic.validates_acceptance_of(:terms_of_service, :on => :create, :accept => "I agree.")
300
301 t = Topic.create("title" => "We should be confirmed", "terms_of_service" => "")
302 assert !t.save
303 assert_equal "must be accepted", t.errors.on(:terms_of_service)
304
305 t.terms_of_service = "I agree."
306 assert t.save
307 end
308
309 def test_validates_acceptance_of_as_database_column
310 repair_validations(Reply) do
311 Reply.validates_acceptance_of(:author_name)
312
313 reply = Reply.create("author_name" => "Dan Brown")
314 assert_equal "Dan Brown", reply["author_name"]
315 end
316 end
317
318 def test_validates_acceptance_of_with_non_existant_table
319 Object.const_set :IncorporealModel, Class.new(ActiveRecord::Base)
320
321 assert_nothing_raised ActiveRecord::StatementInvalid do
322 IncorporealModel.validates_acceptance_of(:incorporeal_column)
323 end
324 end
325
326 def test_validate_presences
327 Topic.validates_presence_of(:title, :content)
328
329 t = Topic.create
330 assert !t.save
331 assert_equal "can't be blank", t.errors.on(:title)
332 assert_equal "can't be blank", t.errors.on(:content)
333
334 t.title = "something"
335 t.content = " "
336
337 assert !t.save
338 assert_equal "can't be blank", t.errors.on(:content)
339
340 t.content = "like stuff"
341
342 assert t.save
343 end
344
345 def test_validate_uniqueness
346 Topic.validates_uniqueness_of(:title)
347
348 t = Topic.new("title" => "I'm unique!")
349 assert t.save, "Should save t as unique"
350
351 t.content = "Remaining unique"
352 assert t.save, "Should still save t as unique"
353
354 t2 = Topic.new("title" => "I'm unique!")
355 assert !t2.valid?, "Shouldn't be valid"
356 assert !t2.save, "Shouldn't save t2 as unique"
357 assert_equal "has already been taken", t2.errors.on(:title)
358
359 t2.title = "Now Im really also unique"
360 assert t2.save, "Should now save t2 as unique"
361 end
362
363 def test_validates_uniquness_with_newline_chars
364 Topic.validates_uniqueness_of(:title, :case_sensitive => false)
365
366 t = Topic.new("title" => "new\nline")
367 assert t.save, "Should save t as unique"
368 end
369
370 def test_validate_uniqueness_with_scope
371 repair_validations(Reply) do
372 Reply.validates_uniqueness_of(:content, :scope => "parent_id")
373
374 t = Topic.create("title" => "I'm unique!")
375
376 r1 = t.replies.create "title" => "r1", "content" => "hello world"
377 assert r1.valid?, "Saving r1"
378
379 r2 = t.replies.create "title" => "r2", "content" => "hello world"
380 assert !r2.valid?, "Saving r2 first time"
381
382 r2.content = "something else"
383 assert r2.save, "Saving r2 second time"
384
385 t2 = Topic.create("title" => "I'm unique too!")
386 r3 = t2.replies.create "title" => "r3", "content" => "hello world"
387 assert r3.valid?, "Saving r3"
388 end
389 end
390
391 def test_validate_uniqueness_scoped_to_defining_class
392 t = Topic.create("title" => "What, me worry?")
393
394 r1 = t.unique_replies.create "title" => "r1", "content" => "a barrel of fun"
395 assert r1.valid?, "Saving r1"
396
397 r2 = t.silly_unique_replies.create "title" => "r2", "content" => "a barrel of fun"
398 assert !r2.valid?, "Saving r2"
399
400 # Should succeed as validates_uniqueness_of only applies to
401 # UniqueReply and its subclasses
402 r3 = t.replies.create "title" => "r2", "content" => "a barrel of fun"
403 assert r3.valid?, "Saving r3"
404 end
405
406 def test_validate_uniqueness_with_scope_array
407 repair_validations(Reply) do
408 Reply.validates_uniqueness_of(:author_name, :scope => [:author_email_address, :parent_id])
409
410 t = Topic.create("title" => "The earth is actually flat!")
411
412 r1 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy@rubyonrails.com", "title" => "You're crazy!", "content" => "Crazy reply"
413 assert r1.valid?, "Saving r1"
414
415 r2 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy@rubyonrails.com", "title" => "You're crazy!", "content" => "Crazy reply again..."
416 assert !r2.valid?, "Saving r2. Double reply by same author."
417
418 r2.author_email_address = "jeremy_alt_email@rubyonrails.com"
419 assert r2.save, "Saving r2 the second time."
420
421 r3 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy_alt_email@rubyonrails.com", "title" => "You're wrong", "content" => "It's cubic"
422 assert !r3.valid?, "Saving r3"
423
424 r3.author_name = "jj"
425 assert r3.save, "Saving r3 the second time."
426
427 r3.author_name = "jeremy"
428 assert !r3.save, "Saving r3 the third time."
429 end
430 end
431
432 def test_validate_case_insensitive_uniqueness
433 Topic.validates_uniqueness_of(:title, :parent_id, :case_sensitive => false, :allow_nil => true)
434
435 t = Topic.new("title" => "I'm unique!", :parent_id => 2)
436 assert t.save, "Should save t as unique"
437
438 t.content = "Remaining unique"
439 assert t.save, "Should still save t as unique"
440
441 t2 = Topic.new("title" => "I'm UNIQUE!", :parent_id => 1)
442 assert !t2.valid?, "Shouldn't be valid"
443 assert !t2.save, "Shouldn't save t2 as unique"
444 assert t2.errors.on(:title)
445 assert t2.errors.on(:parent_id)
446 assert_equal "has already been taken", t2.errors.on(:title)
447
448 t2.title = "I'm truly UNIQUE!"
449 assert !t2.valid?, "Shouldn't be valid"
450 assert !t2.save, "Shouldn't save t2 as unique"
451 assert_nil t2.errors.on(:title)
452 assert t2.errors.on(:parent_id)
453
454 t2.parent_id = 4
455 assert t2.save, "Should now save t2 as unique"
456
457 t2.parent_id = nil
458 t2.title = nil
459 assert t2.valid?, "should validate with nil"
460 assert t2.save, "should save with nil"
461
462 with_kcode('UTF8') do
463 t_utf8 = Topic.new("title" => "Я тоже уникальный!")
464 assert t_utf8.save, "Should save t_utf8 as unique"
465
466 # If database hasn't UTF-8 character set, this test fails
467 if Topic.find(t_utf8, :select => 'LOWER(title) AS title').title == "я тоже уникальный!"
468 t2_utf8 = Topic.new("title" => "я тоже УНИКАЛЬНЫЙ!")
469 assert !t2_utf8.valid?, "Shouldn't be valid"
470 assert !t2_utf8.save, "Shouldn't save t2_utf8 as unique"
471 end
472 end
473 end
474
475 def test_validate_case_sensitive_uniqueness
476 Topic.validates_uniqueness_of(:title, :case_sensitive => true, :allow_nil => true)
477
478 t = Topic.new("title" => "I'm unique!")
479 assert t.save, "Should save t as unique"
480
481 t.content = "Remaining unique"
482 assert t.save, "Should still save t as unique"
483
484 t2 = Topic.new("title" => "I'M UNIQUE!")
485 assert t2.valid?, "Should be valid"
486 assert t2.save, "Should save t2 as unique"
487 assert !t2.errors.on(:title)
488 assert !t2.errors.on(:parent_id)
489 assert_not_equal "has already been taken", t2.errors.on(:title)
490
491 t3 = Topic.new("title" => "I'M uNiQUe!")
492 assert t3.valid?, "Should be valid"
493 assert t3.save, "Should save t2 as unique"
494 assert !t3.errors.on(:title)
495 assert !t3.errors.on(:parent_id)
496 assert_not_equal "has already been taken", t3.errors.on(:title)
497 end
498
499 def test_validate_case_sensitive_uniqueness_with_attribute_passed_as_integer
500 Topic.validates_uniqueness_of(:title, :case_sensitve => true)
501 t = Topic.create!('title' => 101)
502
503 t2 = Topic.new('title' => 101)
504 assert !t2.valid?
505 assert t2.errors.on(:title)
506 end
507
508 def test_validate_uniqueness_with_non_standard_table_names
509 i1 = WarehouseThing.create(:value => 1000)
510 assert !i1.valid?, "i1 should not be valid"
511 assert i1.errors.on(:value), "Should not be empty"
512 end
513
514 def test_validates_uniqueness_inside_with_scope
515 Topic.validates_uniqueness_of(:title)
516
517 Topic.with_scope(:find => { :conditions => { :author_name => "David" } }) do
518 t1 = Topic.new("title" => "I'm unique!", "author_name" => "Mary")
519 assert t1.save
520 t2 = Topic.new("title" => "I'm unique!", "author_name" => "David")
521 assert !t2.valid?
522 end
523 end
524
525 def test_validate_uniqueness_with_columns_which_are_sql_keywords
526 repair_validations(Guid) do
527 Guid.validates_uniqueness_of :key
528 g = Guid.new
529 g.key = "foo"
530 assert_nothing_raised { !g.valid? }
531 end
532 end
533
534 def test_validate_uniqueness_with_limit
535 # Event.title is limited to 5 characters
536 e1 = Event.create(:title => "abcde")
537 assert e1.valid?, "Could not create an event with a unique, 5 character title"
538 e2 = Event.create(:title => "abcdefgh")
539 assert !e2.valid?, "Created an event whose title, with limit taken into account, is not unique"
540 end
541
542 def test_validate_straight_inheritance_uniqueness
543 w1 = IneptWizard.create(:name => "Rincewind", :city => "Ankh-Morpork")
544 assert w1.valid?, "Saving w1"
545
546 # Should use validation from base class (which is abstract)
547 w2 = IneptWizard.new(:name => "Rincewind", :city => "Quirm")
548 assert !w2.valid?, "w2 shouldn't be valid"
549 assert w2.errors.on(:name), "Should have errors for name"
550 assert_equal "has already been taken", w2.errors.on(:name), "Should have uniqueness message for name"
551
552 w3 = Conjurer.new(:name => "Rincewind", :city => "Quirm")
553 assert !w3.valid?, "w3 shouldn't be valid"
554 assert w3.errors.on(:name), "Should have errors for name"
555 assert_equal "has already been taken", w3.errors.on(:name), "Should have uniqueness message for name"
556
557 w4 = Conjurer.create(:name => "The Amazing Bonko", :city => "Quirm")
558 assert w4.valid?, "Saving w4"
559
560 w5 = Thaumaturgist.new(:name => "The Amazing Bonko", :city => "Lancre")
561 assert !w5.valid?, "w5 shouldn't be valid"
562 assert w5.errors.on(:name), "Should have errors for name"
563 assert_equal "has already been taken", w5.errors.on(:name), "Should have uniqueness message for name"
564
565 w6 = Thaumaturgist.new(:name => "Mustrum Ridcully", :city => "Quirm")
566 assert !w6.valid?, "w6 shouldn't be valid"
567 assert w6.errors.on(:city), "Should have errors for city"
568 assert_equal "has already been taken", w6.errors.on(:city), "Should have uniqueness message for city"
569 end
570
571 def test_validate_format
572 Topic.validates_format_of(:title, :content, :with => /^Validation\smacros \w+!$/, :message => "is bad data")
573
574 t = Topic.create("title" => "i'm incorrect", "content" => "Validation macros rule!")
575 assert !t.valid?, "Shouldn't be valid"
576 assert !t.save, "Shouldn't save because it's invalid"
577 assert_equal "is bad data", t.errors.on(:title)
578 assert_nil t.errors.on(:content)
579
580 t.title = "Validation macros rule!"
581
582 assert t.save
583 assert_nil t.errors.on(:title)
584
585 assert_raise(ArgumentError) { Topic.validates_format_of(:title, :content) }
586 end
587
588 def test_validate_format_with_allow_blank
589 Topic.validates_format_of(:title, :with => /^Validation\smacros \w+!$/, :allow_blank=>true)
590 assert !Topic.create("title" => "Shouldn't be valid").valid?
591 assert Topic.create("title" => "").valid?
592 assert Topic.create("title" => nil).valid?
593 assert Topic.create("title" => "Validation macros rule!").valid?
594 end
595
596 # testing ticket #3142
597 def test_validate_format_numeric
598 Topic.validates_format_of(:title, :content, :with => /^[1-9][0-9]*$/, :message => "is bad data")
599
600 t = Topic.create("title" => "72x", "content" => "6789")
601 assert !t.valid?, "Shouldn't be valid"
602 assert !t.save, "Shouldn't save because it's invalid"
603 assert_equal "is bad data", t.errors.on(:title)
604 assert_nil t.errors.on(:content)
605
606 t.title = "-11"
607 assert !t.valid?, "Shouldn't be valid"
608
609 t.title = "03"
610 assert !t.valid?, "Shouldn't be valid"
611
612 t.title = "z44"
613 assert !t.valid?, "Shouldn't be valid"
614
615 t.title = "5v7"
616 assert !t.valid?, "Shouldn't be valid"
617
618 t.title = "1"
619
620 assert t.save
621 assert_nil t.errors.on(:title)
622 end
623
624 def test_validate_format_with_formatted_message
625 Topic.validates_format_of(:title, :with => /^Valid Title$/, :message => "can't be {{value}}")
626 t = Topic.create(:title => 'Invalid title')
627 assert_equal "can't be Invalid title", t.errors.on(:title)
628 end
629
630 def test_validates_inclusion_of
631 Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ) )
632
633 assert !Topic.create("title" => "a!", "content" => "abc").valid?
634 assert !Topic.create("title" => "a b", "content" => "abc").valid?
635 assert !Topic.create("title" => nil, "content" => "def").valid?
636
637 t = Topic.create("title" => "a", "content" => "I know you are but what am I?")
638 assert t.valid?
639 t.title = "uhoh"
640 assert !t.valid?
641 assert t.errors.on(:title)
642 assert_equal "is not included in the list", t.errors["title"]
643
644 assert_raise(ArgumentError) { Topic.validates_inclusion_of( :title, :in => nil ) }
645 assert_raise(ArgumentError) { Topic.validates_inclusion_of( :title, :in => 0) }
646
647 assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of( :title, :in => "hi!" ) }
648 assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of( :title, :in => {} ) }
649 assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of( :title, :in => [] ) }
650 end
651
652 def test_validates_inclusion_of_with_allow_nil
653 Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :allow_nil=>true )
654
655 assert !Topic.create("title" => "a!", "content" => "abc").valid?
656 assert !Topic.create("title" => "", "content" => "abc").valid?
657 assert Topic.create("title" => nil, "content" => "abc").valid?
658 end
659
660 def test_numericality_with_getter_method
661 repair_validations(Developer) do
662 Developer.validates_numericality_of( :salary )
663 developer = Developer.new("name" => "michael", "salary" => nil)
664 developer.instance_eval("def salary; read_attribute('salary') ? read_attribute('salary') : 100000; end")
665 assert developer.valid?
666 end
667 end
668
669 def test_validates_length_of_with_allow_nil
670 Topic.validates_length_of( :title, :is => 5, :allow_nil=>true )
671
672 assert !Topic.create("title" => "ab").valid?
673 assert !Topic.create("title" => "").valid?
674 assert Topic.create("title" => nil).valid?
675 assert Topic.create("title" => "abcde").valid?
676 end
677
678 def test_validates_length_of_with_allow_blank
679 Topic.validates_length_of( :title, :is => 5, :allow_blank=>true )
680
681 assert !Topic.create("title" => "ab").valid?
682 assert Topic.create("title" => "").valid?
683 assert Topic.create("title" => nil).valid?
684 assert Topic.create("title" => "abcde").valid?
685 end
686
687 def test_validates_inclusion_of_with_formatted_message
688 Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :message => "option {{value}} is not in the list" )
689
690 assert Topic.create("title" => "a", "content" => "abc").valid?
691
692 t = Topic.create("title" => "uhoh", "content" => "abc")
693 assert !t.valid?
694 assert t.errors.on(:title)
695 assert_equal "option uhoh is not in the list", t.errors["title"]
696 end
697
698 def test_numericality_with_allow_nil_and_getter_method
699 repair_validations(Developer) do
700 Developer.validates_numericality_of( :salary, :allow_nil => true)
701 developer = Developer.new("name" => "michael", "salary" => nil)
702 developer.instance_eval("def salary; read_attribute('salary') ? read_attribute('salary') : 100000; end")
703 assert developer.valid?
704 end
705 end
706
707 def test_validates_exclusion_of
708 Topic.validates_exclusion_of( :title, :in => %w( abe monkey ) )
709
710 assert Topic.create("title" => "something", "content" => "abc").valid?
711 assert !Topic.create("title" => "monkey", "content" => "abc").valid?
712 end
713
714 def test_validates_exclusion_of_with_formatted_message
715 Topic.validates_exclusion_of( :title, :in => %w( abe monkey ), :message => "option {{value}} is restricted" )
716
717 assert Topic.create("title" => "something", "content" => "abc")
718
719 t = Topic.create("title" => "monkey")
720 assert !t.valid?
721 assert t.errors.on(:title)
722 assert_equal "option monkey is restricted", t.errors["title"]
723 end
724
725 def test_validates_length_of_using_minimum
726 Topic.validates_length_of :title, :minimum => 5
727
728 t = Topic.create("title" => "valid", "content" => "whatever")
729 assert t.valid?
730
731 t.title = "not"
732 assert !t.valid?
733 assert t.errors.on(:title)
734 assert_equal "is too short (minimum is 5 characters)", t.errors["title"]
735
736 t.title = ""
737 assert !t.valid?
738 assert t.errors.on(:title)
739 assert_equal "is too short (minimum is 5 characters)", t.errors["title"]
740
741 t.title = nil
742 assert !t.valid?
743 assert t.errors.on(:title)
744 assert_equal "is too short (minimum is 5 characters)", t.errors["title"]
745 end
746
747 def test_optionally_validates_length_of_using_minimum
748 Topic.validates_length_of :title, :minimum => 5, :allow_nil => true
749
750 t = Topic.create("title" => "valid", "content" => "whatever")
751 assert t.valid?
752
753 t.title = nil
754 assert t.valid?
755 end
756
757 def test_validates_length_of_using_maximum
758 Topic.validates_length_of :title, :maximum => 5
759
760 t = Topic.create("title" => "valid", "content" => "whatever")
761 assert t.valid?
762
763 t.title = "notvalid"
764 assert !t.valid?
765 assert t.errors.on(:title)
766 assert_equal "is too long (maximum is 5 characters)", t.errors["title"]
767
768 t.title = ""
769 assert t.valid?
770
771 t.title = nil
772 assert !t.valid?
773 end
774
775 def test_optionally_validates_length_of_using_maximum
776 Topic.validates_length_of :title, :maximum => 5, :allow_nil => true
777
778 t = Topic.create("title" => "valid", "content" => "whatever")
779 assert t.valid?
780
781 t.title = nil
782 assert t.valid?
783 end
784
785 def test_validates_length_of_using_within
786 Topic.validates_length_of(:title, :content, :within => 3..5)
787
788 t = Topic.new("title" => "a!", "content" => "I'm ooooooooh so very long")
789 assert !t.valid?
790 assert_equal "is too short (minimum is 3 characters)", t.errors.on(:title)
791 assert_equal "is too long (maximum is 5 characters)", t.errors.on(:content)
792
793 t.title = nil
794 t.content = nil
795 assert !t.valid?
796 assert_equal "is too short (minimum is 3 characters)", t.errors.on(:title)
797 assert_equal "is too short (minimum is 3 characters)", t.errors.on(:content)
798
799 t.title = "abe"
800 t.content = "mad"
801 assert t.valid?
802 end
803
804 def test_optionally_validates_length_of_using_within
805 Topic.validates_length_of :title, :content, :within => 3..5, :allow_nil => true
806
807 t = Topic.create('title' => 'abc', 'content' => 'abcd')
808 assert t.valid?
809
810 t.title = nil
811 assert t.valid?
812 end
813
814 def test_optionally_validates_length_of_using_within_on_create
815 Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "my string is too long: {{count}}"
816
817 t = Topic.create("title" => "thisisnotvalid", "content" => "whatever")
818 assert !t.save
819 assert t.errors.on(:title)
820 assert_equal "my string is too long: 10", t.errors[:title]
821
822 t.title = "butthisis"
823 assert t.save
824
825 t.title = "few"
826 assert t.save
827
828 t.content = "andthisislong"
829 assert t.save
830
831 t.content = t.title = "iamfine"
832 assert t.save
833 end
834
835 def test_optionally_validates_length_of_using_within_on_update
836 Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "my string is too short: {{count}}"
837
838 t = Topic.create("title" => "vali", "content" => "whatever")
839 assert !t.save
840 assert t.errors.on(:title)
841
842 t.title = "not"
843 assert !t.save
844 assert t.errors.on(:title)
845 assert_equal "my string is too short: 5", t.errors[:title]
846
847 t.title = "valid"
848 t.content = "andthisistoolong"
849 assert !t.save
850 assert t.errors.on(:content)
851
852 t.content = "iamfine"
853 assert t.save
854 end
855
856 def test_validates_length_of_using_is
857 Topic.validates_length_of :title, :is => 5
858
859 t = Topic.create("title" => "valid", "content" => "whatever")
860 assert t.valid?
861
862 t.title = "notvalid"
863 assert !t.valid?
864 assert t.errors.on(:title)
865 assert_equal "is the wrong length (should be 5 characters)", t.errors["title"]
866
867 t.title = ""
868 assert !t.valid?
869
870 t.title = nil
871 assert !t.valid?
872 end
873
874 def test_optionally_validates_length_of_using_is
875 Topic.validates_length_of :title, :is => 5, :allow_nil => true
876
877 t = Topic.create("title" => "valid", "content" => "whatever")
878 assert t.valid?
879
880 t.title = nil
881 assert t.valid?
882 end
883
884 def test_validates_length_of_using_bignum
885 bigmin = 2 ** 30
886 bigmax = 2 ** 32
887 bigrange = bigmin...bigmax
888 assert_nothing_raised do
889 Topic.validates_length_of :title, :is => bigmin + 5
890 Topic.validates_length_of :title, :within => bigrange
891 Topic.validates_length_of :title, :in => bigrange
892 Topic.validates_length_of :title, :minimum => bigmin
893 Topic.validates_length_of :title, :maximum => bigmax
894 end
895 end
896
897 def test_validates_length_with_globally_modified_error_message
898 ActiveSupport::Deprecation.silence do
899 ActiveRecord::Errors.default_error_messages[:too_short] = 'tu est trops petit hombre {{count}}'
900 end
901 Topic.validates_length_of :title, :minimum => 10
902 t = Topic.create(:title => 'too short')
903 assert !t.valid?
904
905 assert_equal 'tu est trops petit hombre 10', t.errors['title']
906 end
907
908 def test_validates_size_of_association
909 repair_validations(Owner) do
910 assert_nothing_raised { Owner.validates_size_of :pets, :minimum => 1 }
911 o = Owner.new('name' => 'nopets')
912 assert !o.save
913 assert o.errors.on(:pets)
914 pet = o.pets.build('name' => 'apet')
915 assert o.valid?
916 end
917 end
918
919 def test_validates_size_of_association_using_within
920 repair_validations(Owner) do
921 assert_nothing_raised { Owner.validates_size_of :pets, :within => 1..2 }
922 o = Owner.new('name' => 'nopets')
923 assert !o.save
924 assert o.errors.on(:pets)
925
926 pet = o.pets.build('name' => 'apet')
927 assert o.valid?
928
929 2.times { o.pets.build('name' => 'apet') }
930 assert !o.save
931 assert o.errors.on(:pets)
932 end
933 end
934
935 def test_validates_length_of_nasty_params
936 assert_raise(ArgumentError) { Topic.validates_length_of(:title, :minimum=>6, :maximum=>9) }
937 assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>6, :maximum=>9) }
938 assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>6, :minimum=>9) }
939 assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>6, :is=>9) }
940 assert_raise(ArgumentError) { Topic.validates_length_of(:title, :minimum=>"a") }
941 assert_raise(ArgumentError) { Topic.validates_length_of(:title, :maximum=>"a") }
942 assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>"a") }
943 assert_raise(ArgumentError) { Topic.validates_length_of(:title, :is=>"a") }
944 end
945
946 def test_validates_length_of_custom_errors_for_minimum_with_message
947 Topic.validates_length_of( :title, :minimum=>5, :message=>"boo {{count}}" )
948 t = Topic.create("title" => "uhoh", "content" => "whatever")
949 assert !t.valid?
950 assert t.errors.on(:title)
951 assert_equal "boo 5", t.errors["title"]
952 end
953
954 def test_validates_length_of_custom_errors_for_minimum_with_too_short
955 Topic.validates_length_of( :title, :minimum=>5, :too_short=>"hoo {{count}}" )
956 t = Topic.create("title" => "uhoh", "content" => "whatever")
957 assert !t.valid?
958 assert t.errors.on(:title)
959 assert_equal "hoo 5", t.errors["title"]
960 end
961
962 def test_validates_length_of_custom_errors_for_maximum_with_message
963 Topic.validates_length_of( :title, :maximum=>5, :message=>"boo {{count}}" )
964 t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
965 assert !t.valid?
966 assert t.errors.on(:title)
967 assert_equal "boo 5", t.errors["title"]
968 end
969
970 def test_validates_length_of_custom_errors_for_in
971 Topic.validates_length_of(:title, :in => 10..20, :message => "hoo {{count}}")
972 t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
973 assert !t.valid?
974 assert t.errors.on(:title)
975 assert_equal "hoo 10", t.errors["title"]
976
977 t = Topic.create("title" => "uhohuhohuhohuhohuhohuhohuhohuhoh", "content" => "whatever")
978 assert !t.valid?
979 assert t.errors.on(:title)
980 assert_equal "hoo 20", t.errors["title"]
981 end
982
983 def test_validates_length_of_custom_errors_for_maximum_with_too_long
984 Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}" )
985 t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
986 assert !t.valid?
987 assert t.errors.on(:title)
988 assert_equal "hoo 5", t.errors["title"]
989 end
990
991 def test_validates_length_of_custom_errors_for_is_with_message
992 Topic.validates_length_of( :title, :is=>5, :message=>"boo {{count}}" )
993 t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
994 assert !t.valid?
995 assert t.errors.on(:title)
996 assert_equal "boo 5", t.errors["title"]
997 end
998
999 def test_validates_length_of_custom_errors_for_is_with_wrong_length
1000 Topic.validates_length_of( :title, :is=>5, :wrong_length=>"hoo {{count}}" )
1001 t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1002 assert !t.valid?
1003 assert t.errors.on(:title)
1004 assert_equal "hoo 5", t.errors["title"]
1005 end
1006
1007 def test_validates_length_of_using_minimum_utf8
1008 with_kcode('UTF8') do
1009 Topic.validates_length_of :title, :minimum => 5
1010
1011 t = Topic.create("title" => "一二三四五", "content" => "whatever")
1012 assert t.valid?
1013
1014 t.title = "一二三四"
1015 assert !t.valid?
1016 assert t.errors.on(:title)
1017 assert_equal "is too short (minimum is 5 characters)", t.errors["title"]
1018 end
1019 end
1020
1021 def test_validates_length_of_using_maximum_utf8
1022 with_kcode('UTF8') do
1023 Topic.validates_length_of :title, :maximum => 5
1024
1025 t = Topic.create("title" => "一二三四五", "content" => "whatever")
1026 assert t.valid?
1027
1028 t.title = "一二34五六"
1029 assert !t.valid?
1030 assert t.errors.on(:title)
1031 assert_equal "is too long (maximum is 5 characters)", t.errors["title"]
1032 end
1033 end
1034
1035 def test_validates_length_of_using_within_utf8
1036 with_kcode('UTF8') do
1037 Topic.validates_length_of(:title, :content, :within => 3..5)
1038
1039 t = Topic.new("title" => "一二", "content" => "12三四五六七")
1040 assert !t.valid?
1041 assert_equal "is too short (minimum is 3 characters)", t.errors.on(:title)
1042 assert_equal "is too long (maximum is 5 characters)", t.errors.on(:content)
1043 t.title = "一二三"
1044 t.content = "12三"
1045 assert t.valid?
1046 end
1047 end
1048
1049 def test_optionally_validates_length_of_using_within_utf8
1050 with_kcode('UTF8') do
1051 Topic.validates_length_of :title, :within => 3..5, :allow_nil => true
1052
1053 t = Topic.create(:title => "一二三四五")
1054 assert t.valid?, t.errors.inspect
1055
1056 t = Topic.create(:title => "一二三")
1057 assert t.valid?, t.errors.inspect
1058
1059 t.title = nil
1060 assert t.valid?, t.errors.inspect
1061 end
1062 end
1063
1064 def test_optionally_validates_length_of_using_within_on_create_utf8
1065 with_kcode('UTF8') do
1066 Topic.validates_length_of :title, :within => 5..10, :on => :create, :too_long => "長すぎます: {{count}}"
1067
1068 t = Topic.create("title" => "一二三四五六七八九十A", "content" => "whatever")
1069 assert !t.save
1070 assert t.errors.on(:title)
1071 assert_equal "長すぎます: 10", t.errors[:title]
1072
1073 t.title = "一二三四五六七八九"
1074 assert t.save
1075
1076 t.title = "一二3"
1077 assert t.save
1078
1079 t.content = "一二三四五六七八九十"
1080 assert t.save
1081
1082 t.content = t.title = "一二三四五六"
1083 assert t.save
1084 end
1085 end
1086
1087 def test_optionally_validates_length_of_using_within_on_update_utf8
1088 with_kcode('UTF8') do
1089 Topic.validates_length_of :title, :within => 5..10, :on => :update, :too_short => "短すぎます: {{count}}"
1090
1091 t = Topic.create("title" => "一二三4", "content" => "whatever")
1092 assert !t.save
1093 assert t.errors.on(:title)
1094
1095 t.title = "1二三4"
1096 assert !t.save
1097 assert t.errors.on(:title)
1098 assert_equal "短すぎます: 5", t.errors[:title]
1099
1100 t.title = "一二三四五六七八九十A"
1101 assert !t.save
1102 assert t.errors.on(:title)
1103
1104 t.title = "一二345"
1105 assert t.save
1106 end
1107 end
1108
1109 def test_validates_length_of_using_is_utf8
1110 with_kcode('UTF8') do
1111 Topic.validates_length_of :title, :is => 5
1112
1113 t = Topic.create("title" => "一二345", "content" => "whatever")
1114 assert t.valid?
1115
1116 t.title = "一二345六"
1117 assert !t.valid?
1118 assert t.errors.on(:title)
1119 assert_equal "is the wrong length (should be 5 characters)", t.errors["title"]
1120 end
1121 end
1122
1123 def test_validates_length_of_with_block
1124 Topic.validates_length_of :content, :minimum => 5, :too_short=>"Your essay must be at least {{count}} words.",
1125 :tokenizer => lambda {|str| str.scan(/\w+/) }
1126 t = Topic.create!(:content => "this content should be long enough")
1127 assert t.valid?
1128
1129 t.content = "not long enough"
1130 assert !t.valid?
1131 assert t.errors.on(:content)
1132 assert_equal "Your essay must be at least 5 words.", t.errors[:content]
1133 end
1134
1135 def test_validates_size_of_association_utf8
1136 repair_validations(Owner) do
1137 with_kcode('UTF8') do
1138 assert_nothing_raised { Owner.validates_size_of :pets, :minimum => 1 }
1139 o = Owner.new('name' => 'あいうえおかきくけこ')
1140 assert !o.save
1141 assert o.errors.on(:pets)
1142 o.pets.build('name' => 'あいうえおかきくけこ')
1143 assert o.valid?
1144 end
1145 end
1146 end
1147
1148 def test_validates_associated_many
1149 Topic.validates_associated( :replies )
1150 t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1151 t.replies << [r = Reply.new("title" => "A reply"), r2 = Reply.new("title" => "Another reply", "content" => "non-empty"), r3 = Reply.new("title" => "Yet another reply"), r4 = Reply.new("title" => "The last reply", "content" => "non-empty")]
1152 assert !t.valid?
1153 assert t.errors.on(:replies)
1154 assert_equal 1, r.errors.count # make sure all associated objects have been validated
1155 assert_equal 0, r2.errors.count
1156 assert_equal 1, r3.errors.count
1157 assert_equal 0, r4.errors.count
1158 r.content = r3.content = "non-empty"
1159 assert t.valid?
1160 end
1161
1162 def test_validates_associated_one
1163 repair_validations(Reply) do
1164 Reply.validates_associated( :topic )
1165 Topic.validates_presence_of( :content )
1166 r = Reply.new("title" => "A reply", "content" => "with content!")
1167 r.topic = Topic.create("title" => "uhohuhoh")
1168 assert !r.valid?
1169 assert r.errors.on(:topic)
1170 r.topic.content = "non-empty"
1171 assert r.valid?
1172 end
1173 end
1174
1175 def test_validate_block
1176 Topic.validate { |topic| topic.errors.add("title", "will never be valid") }
1177 t = Topic.create("title" => "Title", "content" => "whatever")
1178 assert !t.valid?
1179 assert t.errors.on(:title)
1180 assert_equal "will never be valid", t.errors["title"]
1181 end
1182
1183 def test_invalid_validator
1184 Topic.validate 3
1185 assert_raise(ArgumentError) { t = Topic.create }
1186 end
1187
1188 def test_throw_away_typing
1189 d = Developer.new("name" => "David", "salary" => "100,000")
1190 assert !d.valid?
1191 assert_equal 100, d.salary
1192 assert_equal "100,000", d.salary_before_type_cast
1193 end
1194
1195 def test_validates_acceptance_of_with_custom_error_using_quotes
1196 repair_validations(Developer) do
1197 Developer.validates_acceptance_of :salary, :message=> "This string contains 'single' and \"double\" quotes"
1198 d = Developer.new
1199 d.salary = "0"
1200 assert !d.valid?
1201 assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:salary).last
1202 end
1203 end
1204
1205 def test_validates_confirmation_of_with_custom_error_using_quotes
1206 repair_validations(Developer) do
1207 Developer.validates_confirmation_of :name, :message=> "confirm 'single' and \"double\" quotes"
1208 d = Developer.new
1209 d.name = "John"
1210 d.name_confirmation = "Johnny"
1211 assert !d.valid?
1212 assert_equal "confirm 'single' and \"double\" quotes", d.errors.on(:name)
1213 end
1214 end
1215
1216 def test_validates_format_of_with_custom_error_using_quotes
1217 repair_validations(Developer) do
1218 Developer.validates_format_of :name, :with => /^(A-Z*)$/, :message=> "format 'single' and \"double\" quotes"
1219 d = Developer.new
1220 d.name = d.name_confirmation = "John 32"
1221 assert !d.valid?
1222 assert_equal "format 'single' and \"double\" quotes", d.errors.on(:name)
1223 end
1224 end
1225
1226 def test_validates_inclusion_of_with_custom_error_using_quotes
1227 repair_validations(Developer) do
1228 Developer.validates_inclusion_of :salary, :in => 1000..80000, :message=> "This string contains 'single' and \"double\" quotes"
1229 d = Developer.new
1230 d.salary = "90,000"
1231 assert !d.valid?
1232 assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:salary).last
1233 end
1234 end
1235
1236 def test_validates_length_of_with_custom_too_long_using_quotes
1237 repair_validations(Developer) do
1238 Developer.validates_length_of :name, :maximum => 4, :too_long=> "This string contains 'single' and \"double\" quotes"
1239 d = Developer.new
1240 d.name = "Jeffrey"
1241 assert !d.valid?
1242 assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:name)
1243 end
1244 end
1245
1246 def test_validates_length_of_with_custom_too_short_using_quotes
1247 repair_validations(Developer) do
1248 Developer.validates_length_of :name, :minimum => 4, :too_short=> "This string contains 'single' and \"double\" quotes"
1249 d = Developer.new
1250 d.name = "Joe"
1251 assert !d.valid?
1252 assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:name)
1253 end
1254 end
1255
1256 def test_validates_length_of_with_custom_message_using_quotes
1257 repair_validations(Developer) do
1258 Developer.validates_length_of :name, :minimum => 4, :message=> "This string contains 'single' and \"double\" quotes"
1259 d = Developer.new
1260 d.name = "Joe"
1261 assert !d.valid?
1262 assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:name)
1263 end
1264 end
1265
1266 def test_validates_presence_of_with_custom_message_using_quotes
1267 repair_validations(Developer) do
1268 Developer.validates_presence_of :non_existent, :message=> "This string contains 'single' and \"double\" quotes"
1269 d = Developer.new
1270 d.name = "Joe"
1271 assert !d.valid?
1272 assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:non_existent)
1273 end
1274 end
1275
1276 def test_validates_uniqueness_of_with_custom_message_using_quotes
1277 repair_validations(Developer) do
1278 Developer.validates_uniqueness_of :name, :message=> "This string contains 'single' and \"double\" quotes"
1279 d = Developer.new
1280 d.name = "David"
1281 assert !d.valid?
1282 assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:name)
1283 end
1284 end
1285
1286 def test_validates_associated_with_custom_message_using_quotes
1287 repair_validations(Reply) do
1288 Reply.validates_associated :topic, :message=> "This string contains 'single' and \"double\" quotes"
1289 Topic.validates_presence_of :content
1290 r = Reply.create("title" => "A reply", "content" => "with content!")
1291 r.topic = Topic.create("title" => "uhohuhoh")
1292 assert !r.valid?
1293 assert_equal "This string contains 'single' and \"double\" quotes", r.errors.on(:topic)
1294 end
1295 end
1296
1297 def test_if_validation_using_method_true
1298 # When the method returns true
1299 Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => :condition_is_true )
1300 t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1301 assert !t.valid?
1302 assert t.errors.on(:title)
1303 assert_equal "hoo 5", t.errors["title"]
1304 end
1305
1306 def test_unless_validation_using_method_true
1307 # When the method returns true
1308 Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => :condition_is_true )
1309 t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1310 assert t.valid?
1311 assert !t.errors.on(:title)
1312 end
1313
1314 def test_if_validation_using_method_false
1315 # When the method returns false
1316 Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => :condition_is_true_but_its_not )
1317 t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1318 assert t.valid?
1319 assert !t.errors.on(:title)
1320 end
1321
1322 def test_unless_validation_using_method_false
1323 # When the method returns false
1324 Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => :condition_is_true_but_its_not )
1325 t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1326 assert !t.valid?
1327 assert t.errors.on(:title)
1328 assert_equal "hoo 5", t.errors["title"]
1329 end
1330
1331 def test_if_validation_using_string_true
1332 # When the evaluated string returns true
1333 Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => "a = 1; a == 1" )
1334 t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1335 assert !t.valid?
1336 assert t.errors.on(:title)
1337 assert_equal "hoo 5", t.errors["title"]
1338 end
1339
1340 def test_unless_validation_using_string_true
1341 # When the evaluated string returns true
1342 Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => "a = 1; a == 1" )
1343 t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1344 assert t.valid?
1345 assert !t.errors.on(:title)
1346 end
1347
1348 def test_if_validation_using_string_false
1349 # When the evaluated string returns false
1350 Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => "false")
1351 t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1352 assert t.valid?
1353 assert !t.errors.on(:title)
1354 end
1355
1356 def test_unless_validation_using_string_false
1357 # When the evaluated string returns false
1358 Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => "false")
1359 t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1360 assert !t.valid?
1361 assert t.errors.on(:title)
1362 assert_equal "hoo 5", t.errors["title"]
1363 end
1364
1365 def test_if_validation_using_block_true
1366 # When the block returns true
1367 Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}",
1368 :if => Proc.new { |r| r.content.size > 4 } )
1369 t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1370 assert !t.valid?
1371 assert t.errors.on(:title)
1372 assert_equal "hoo 5", t.errors["title"]
1373 end
1374
1375 def test_unless_validation_using_block_true
1376 # When the block returns true
1377 Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}",
1378 :unless => Proc.new { |r| r.content.size > 4 } )
1379 t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1380 assert t.valid?
1381 assert !t.errors.on(:title)
1382 end
1383
1384 def test_if_validation_using_block_false
1385 # When the block returns false
1386 Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}",
1387 :if => Proc.new { |r| r.title != "uhohuhoh"} )
1388 t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1389 assert t.valid?
1390 assert !t.errors.on(:title)
1391 end
1392
1393 def test_unless_validation_using_block_false
1394 # When the block returns false
1395 Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}",
1396 :unless => Proc.new { |r| r.title != "uhohuhoh"} )
1397 t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1398 assert !t.valid?
1399 assert t.errors.on(:title)
1400 assert_equal "hoo 5", t.errors["title"]
1401 end
1402
1403 def test_validates_associated_missing
1404 repair_validations(Reply) do
1405 Reply.validates_presence_of(:topic)
1406 r = Reply.create("title" => "A reply", "content" => "with content!")
1407 assert !r.valid?
1408 assert r.errors.on(:topic)
1409
1410 r.topic = Topic.find :first
1411 assert r.valid?
1412 end
1413 end
1414
1415 def test_errors_to_xml
1416 r = Reply.new :title => "Wrong Create"
1417 assert !r.valid?
1418 xml = r.errors.to_xml(:skip_instruct => true)
1419 assert_equal "<errors>", xml.first(8)
1420 assert xml.include?("<error>Title is Wrong Create</error>")
1421 assert xml.include?("<error>Content Empty</error>")
1422 end
1423
1424 def test_validation_order
1425 Topic.validates_presence_of :title
1426 Topic.validates_length_of :title, :minimum => 2
1427
1428 t = Topic.new("title" => "")
1429 assert !t.valid?
1430 assert_equal "can't be blank", t.errors.on("title").first
1431 end
1432
1433 def test_invalid_should_be_the_opposite_of_valid
1434 Topic.validates_presence_of :title
1435
1436 t = Topic.new
1437 assert t.invalid?
1438 assert t.errors.invalid?(:title)
1439
1440 t.title = 'Things are going to change'
1441 assert !t.invalid?
1442 end
1443
1444 # previous implementation of validates_presence_of eval'd the
1445 # string with the wrong binding, this regression test is to
1446 # ensure that it works correctly
1447 def test_validation_with_if_as_string
1448 Topic.validates_presence_of(:title)
1449 Topic.validates_presence_of(:author_name, :if => "title.to_s.match('important')")
1450
1451 t = Topic.new
1452 assert !t.valid?, "A topic without a title should not be valid"
1453 assert !t.errors.invalid?("author_name"), "A topic without an 'important' title should not require an author"
1454
1455 t.title = "Just a title"
1456 assert t.valid?, "A topic with a basic title should be valid"
1457
1458 t.title = "A very important title"
1459 assert !t.valid?, "A topic with an important title, but without an author, should not be valid"
1460 assert t.errors.invalid?("author_name"), "A topic with an 'important' title should require an author"
1461
1462 t.author_name = "Hubert J. Farnsworth"
1463 assert t.valid?, "A topic with an important title and author should be valid"
1464 end
1465 end
1466
1467
1468 class ValidatesNumericalityTest < ActiveRecord::TestCase
1469 NIL = [nil]
1470 BLANK = ["", " ", " \t \r \n"]
1471 BIGDECIMAL_STRINGS = %w(12345678901234567890.1234567890) # 30 significent digits
1472 FLOAT_STRINGS = %w(0.0 +0.0 -0.0 10.0 10.5 -10.5 -0.0001 -090.1 90.1e1 -90.1e5 -90.1e-5 90e-5)
1473 INTEGER_STRINGS = %w(0 +0 -0 10 +10 -10 0090 -090)
1474 FLOATS = [0.0, 10.0, 10.5, -10.5, -0.0001] + FLOAT_STRINGS
1475 INTEGERS = [0, 10, -10] + INTEGER_STRINGS
1476 BIGDECIMAL = BIGDECIMAL_STRINGS.collect! { |bd| BigDecimal.new(bd) }
1477 JUNK = ["not a number", "42 not a number", "0xdeadbeef", "00-1", "--3", "+-3", "+3-1", "-+019.0", "12.12.13.12", "123\nnot a number"]
1478 INFINITY = [1.0/0.0]
1479
1480 repair_validations(Topic)
1481
1482 def test_default_validates_numericality_of
1483 Topic.validates_numericality_of :approved
1484
1485 invalid!(NIL + BLANK + JUNK)
1486 valid!(FLOATS + INTEGERS + BIGDECIMAL + INFINITY)
1487 end
1488
1489 def test_validates_numericality_of_with_nil_allowed
1490 Topic.validates_numericality_of :approved, :allow_nil => true
1491
1492 invalid!(JUNK)
1493 valid!(NIL + BLANK + FLOATS + INTEGERS + BIGDECIMAL + INFINITY)
1494 end
1495
1496 def test_validates_numericality_of_with_integer_only
1497 Topic.validates_numericality_of :approved, :only_integer => true
1498
1499 invalid!(NIL + BLANK + JUNK + FLOATS + BIGDECIMAL + INFINITY)
1500 valid!(INTEGERS)
1501 end
1502
1503 def test_validates_numericality_of_with_integer_only_and_nil_allowed
1504 Topic.validates_numericality_of :approved, :only_integer => true, :allow_nil => true
1505
1506 invalid!(JUNK + FLOATS + BIGDECIMAL + INFINITY)
1507 valid!(NIL + BLANK + INTEGERS)
1508 end
1509
1510 def test_validates_numericality_with_greater_than
1511 Topic.validates_numericality_of :approved, :greater_than => 10
1512
1513 invalid!([-10, 10], 'must be greater than 10')
1514 valid!([11])
1515 end
1516
1517 def test_validates_numericality_with_greater_than_or_equal
1518 Topic.validates_numericality_of :approved, :greater_than_or_equal_to => 10
1519
1520 invalid!([-9, 9], 'must be greater than or equal to 10')
1521 valid!([10])
1522 end
1523
1524 def test_validates_numericality_with_equal_to
1525 Topic.validates_numericality_of :approved, :equal_to => 10
1526
1527 invalid!([-10, 11] + INFINITY, 'must be equal to 10')
1528 valid!([10])
1529 end
1530
1531 def test_validates_numericality_with_less_than
1532 Topic.validates_numericality_of :approved, :less_than => 10
1533
1534 invalid!([10], 'must be less than 10')
1535 valid!([-9, 9])
1536 end
1537
1538 def test_validates_numericality_with_less_than_or_equal_to
1539 Topic.validates_numericality_of :approved, :less_than_or_equal_to => 10
1540
1541 invalid!([11], 'must be less than or equal to 10')
1542 valid!([-10, 10])
1543 end
1544
1545 def test_validates_numericality_with_odd
1546 Topic.validates_numericality_of :approved, :odd => true
1547
1548 invalid!([-2, 2], 'must be odd')
1549 valid!([-1, 1])
1550 end
1551
1552 def test_validates_numericality_with_even
1553 Topic.validates_numericality_of :approved, :even => true
1554
1555 invalid!([-1, 1], 'must be even')
1556 valid!([-2, 2])
1557 end
1558
1559 def test_validates_numericality_with_greater_than_less_than_and_even
1560 Topic.validates_numericality_of :approved, :greater_than => 1, :less_than => 4, :even => true
1561
1562 invalid!([1, 3, 4])
1563 valid!([2])
1564 end
1565
1566 def test_validates_numericality_with_numeric_message
1567 Topic.validates_numericality_of :approved, :less_than => 4, :message => "smaller than {{count}}"
1568 topic = Topic.new("title" => "numeric test", "approved" => 10)
1569
1570 assert !topic.valid?
1571 assert_equal "smaller than 4", topic.errors.on(:approved)
1572
1573 Topic.validates_numericality_of :approved, :greater_than => 4, :message => "greater than {{count}}"
1574 topic = Topic.new("title" => "numeric test", "approved" => 1)
1575
1576 assert !topic.valid?
1577 assert_equal "greater than 4", topic.errors.on(:approved)
1578 end
1579
1580 private
1581 def invalid!(values, error=nil)
1582 with_each_topic_approved_value(values) do |topic, value|
1583 assert !topic.valid?, "#{value.inspect} not rejected as a number"
1584 assert topic.errors.on(:approved)
1585 assert_equal error, topic.errors.on(:approved) if error
1586 end
1587 end
1588
1589 def valid!(values)
1590 with_each_topic_approved_value(values) do |topic, value|
1591 assert topic.valid?, "#{value.inspect} not accepted as a number"
1592 end
1593 end
1594
1595 def with_each_topic_approved_value(values)
1596 topic = Topic.new("title" => "numeric test", "content" => "whatever")
1597 values.each do |value|
1598 topic.approved = value
1599 yield topic, value
1600 end
1601 end
1602 end