~michaelforrest/use-case-mapper/trunk

« back to all changes in this revision

Viewing changes to vendor/rails/activerecord/test/cases/validations_test.rb

  • Committer: Michael Forrest
  • Date: 2010-10-15 16:28:50 UTC
  • Revision ID: michael.forrest@canonical.com-20101015162850-tj2vchanv0kr0dun
refrozeĀ gems

Show diffs side-by-side

added added

removed removed

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