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