validations_test.rb 22.2 KB
Newer Older
D
Initial  
David Heinemeier Hansson 已提交
1
require 'abstract_unit'
2 3 4
require 'fixtures/topic'
require 'fixtures/reply'
require 'fixtures/developer'
D
Initial  
David Heinemeier Hansson 已提交
5 6

class ValidationsTest < Test::Unit::TestCase
7
  fixtures :topics, :developers
D
Initial  
David Heinemeier Hansson 已提交
8

9 10 11 12
  def setup
    Topic.write_inheritable_attribute(:validate, nil)
    Topic.write_inheritable_attribute(:validate_on_create, nil)
    Topic.write_inheritable_attribute(:validate_on_update, nil)
13 14
  end

D
Initial  
David Heinemeier Hansson 已提交
15 16 17 18 19 20 21 22
  def test_single_field_validation
    r = Reply.new
    r.title = "There's no content!"
    assert !r.save, "A reply without content shouldn't be saveable"

    r.content = "Messa content!"
    assert r.save, "A reply with content should be saveable"
  end
23

D
Initial  
David Heinemeier Hansson 已提交
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
  def test_single_attr_validation_and_error_msg
    r = Reply.new
    r.title = "There's no content!"
    r.save
    assert r.errors.invalid?("content"), "A reply without content should mark that attribute as invalid"
    assert_equal "Empty", r.errors.on("content"), "A reply without content should contain an error"
    assert_equal 1, r.errors.count
  end

  def test_double_attr_validation_and_error_msg
    r = Reply.new
    assert !r.save

    assert r.errors.invalid?("title"), "A reply without title should mark that attribute as invalid"
    assert_equal "Empty", r.errors.on("title"), "A reply without title should contain an error"

    assert r.errors.invalid?("content"), "A reply without content should mark that attribute as invalid"
    assert_equal "Empty", r.errors.on("content"), "A reply without content should contain an error"

    assert_equal 2, r.errors.count
  end
45

D
Initial  
David Heinemeier Hansson 已提交
46 47 48 49 50 51 52 53 54 55 56 57 58
  def test_error_on_create
    r = Reply.new
    r.title = "Wrong Create"
    assert !r.save
    assert r.errors.invalid?("title"), "A reply with a bad title should mark that attribute as invalid"
    assert_equal "is Wrong Create", r.errors.on("title"), "A reply with a bad content should contain an error"
  end

  def test_error_on_update
    r = Reply.new
    r.title = "Bad"
    r.content = "Good"
    assert r.save, "First save should be successful"
59

D
Initial  
David Heinemeier Hansson 已提交
60 61
    r.title = "Wrong Update"
    assert !r.save, "Second save should fail"
62

D
Initial  
David Heinemeier Hansson 已提交
63 64 65
    assert r.errors.invalid?("title"), "A reply with a bad title should mark that attribute as invalid"
    assert_equal "is Wrong Update", r.errors.on("title"), "A reply with a bad content should contain an error"
  end
66

D
Initial  
David Heinemeier Hansson 已提交
67 68 69
  def test_single_error_per_attr_iteration
    r = Reply.new
    r.save
70

D
Initial  
David Heinemeier Hansson 已提交
71 72
    errors = []
    r.errors.each { |attr, msg| errors << [attr, msg] }
73

D
Initial  
David Heinemeier Hansson 已提交
74 75 76
    assert errors.include?(["title", "Empty"])
    assert errors.include?(["content", "Empty"])
  end
77

D
Initial  
David Heinemeier Hansson 已提交
78 79 80 81 82
  def test_multiple_errors_per_attr_iteration_with_full_error_composition
    r = Reply.new
    r.title   = "Wrong Create"
    r.content = "Mismatch"
    r.save
83

D
Initial  
David Heinemeier Hansson 已提交
84 85
    errors = []
    r.errors.each_full { |error| errors << error }
86

D
Initial  
David Heinemeier Hansson 已提交
87 88 89 90
    assert_equal "Title is Wrong Create", errors[0]
    assert_equal "Title is Content Mismatch", errors[1]
    assert_equal 2, r.errors.count
  end
91

D
Initial  
David Heinemeier Hansson 已提交
92 93 94 95 96
  def test_errors_on_base
    r = Reply.new
    r.content = "Mismatch"
    r.save
    r.errors.add_to_base "Reply is not dignifying"
97

D
Initial  
David Heinemeier Hansson 已提交
98 99
    errors = []
    r.errors.each_full { |error| errors << error }
100

D
Initial  
David Heinemeier Hansson 已提交
101
    assert_equal "Reply is not dignifying", r.errors.on_base
102

D
Initial  
David Heinemeier Hansson 已提交
103 104 105 106 107 108 109 110 111 112
    assert errors.include?("Title Empty")
    assert errors.include?("Reply is not dignifying")
    assert_equal 2, r.errors.count
  end

  def test_create_without_validation
    reply = Reply.new
    assert !reply.save
    assert reply.save(false)
  end
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131

  def test_validates_each
    perform = true
    hits = 0
    Topic.validates_each(:title, :content, [:title, :content]) do |record, attr|
      if perform
        record.errors.add attr, 'gotcha'
        hits += 1
      end
    end
    t = Topic.new("title" => "valid", "content" => "whatever")
    assert !t.save
    assert_equal 4, hits
    assert_equal %w(gotcha gotcha), t.errors.on(:title)
    assert_equal %w(gotcha gotcha), t.errors.on(:content)
  ensure
    perform = false
  end

D
Initial  
David Heinemeier Hansson 已提交
132 133 134 135
  def test_errors_on_boundary_breaking
    developer = Developer.new("name" => "xs")
    assert !developer.save
    assert_equal "is too short (min is 3 characters)", developer.errors.on("name")
136

D
Initial  
David Heinemeier Hansson 已提交
137 138 139 140 141 142 143
    developer.name = "All too very long for this boundary, it really is"
    assert !developer.save
    assert_equal "is too long (max is 20 characters)", developer.errors.on("name")

    developer.name = "Just right"
    assert developer.save
  end
144

145 146
  def test_title_confirmation_no_confirm
    Topic.validates_confirmation_of(:title)
147

148 149 150
    t = Topic.create("title" => "We should not be confirmed")
    assert t.save
  end
151

152
  def test_title_confirmation
153
    Topic.validates_confirmation_of(:title)
154

155
    t = Topic.create("title" => "We should be confirmed","title_confirmation" => "")
156
    assert !t.save
157

158 159
    t.title_confirmation = "We should be confirmed"
    assert t.save
160 161
  end

162 163 164 165 166 167 168
  def test_terms_of_service_agreement_no_acceptance
    Topic.validates_acceptance_of(:terms_of_service, :on => :create)

    t = Topic.create("title" => "We should not be confirmed")
    assert t.save
  end

169
  def test_terms_of_service_agreement
170
    Topic.validates_acceptance_of(:terms_of_service, :on => :create)
171

172
    t = Topic.create("title" => "We should be confirmed","terms_of_service" => "")
173
    assert !t.save
174
    assert_equal "must be accepted", t.errors.on(:terms_of_service)
175

176
    t.terms_of_service = "1"
177 178
    assert t.save
  end
179 180 181


  def test_eula
182
    Topic.validates_acceptance_of(:eula, :message => "must be abided", :on => :create)
183

184
    t = Topic.create("title" => "We should be confirmed","eula" => "")
185 186 187 188 189
    assert !t.save
    assert_equal "must be abided", t.errors.on(:eula)

    t.eula = "1"
    assert t.save
190
  end
191

192 193 194 195 196 197 198 199 200 201 202
  def test_terms_of_service_agreement_with_accept_value
    Topic.validates_acceptance_of(:terms_of_service, :on => :create, :accept => "I agree.")

    t = Topic.create("title" => "We should be confirmed", "terms_of_service" => "")
    assert !t.save
    assert_equal "must be accepted", t.errors.on(:terms_of_service)

    t.terms_of_service = "I agree."
    assert t.save
  end

203
  def test_validate_presences
204
    Topic.validates_presence_of(:title, :content)
205

206 207 208 209
    t = Topic.create
    assert !t.save
    assert_equal "can't be empty", t.errors.on(:title)
    assert_equal "can't be empty", t.errors.on(:content)
210

211 212
    t.title = "something"
    t.content  = "another"
213

214
    assert t.save
215
  end
216

217
  def test_validate_uniqueness
218
    Topic.validates_uniqueness_of(:title)
219

220 221 222 223 224 225 226 227 228 229
    t = Topic.new("title" => "I'm unique!")
    assert t.save, "Should save t as unique"

    t.content = "Remaining unique"
    assert t.save, "Should still save t as unique"

    t2 = Topic.new("title" => "I'm unique!")
    assert !t2.valid?, "Shouldn't be valid"
    assert !t2.save, "Shouldn't save t2 as unique"
    assert_equal "has already been taken", t2.errors.on(:title)
230

231 232 233
    t2.title = "Now Im really also unique"
    assert t2.save, "Should now save t2 as unique"
  end
234

235 236
  def test_validate_uniqueness_with_scope
    Reply.validates_uniqueness_of(:content, :scope => "parent_id")
237

238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
    t = Topic.create("title" => "I'm unique!")

    r1 = t.replies.create "title" => "r1", "content" => "hello world"
    assert r1.valid?, "Saving r1"

    r2 = t.replies.create "title" => "r2", "content" => "hello world"
    assert !r2.valid?, "Saving r2 first time"

    r2.content = "something else"
    assert r2.save, "Saving r2 second time"

    t2 = Topic.create("title" => "I'm unique too!")
    r3 = t2.replies.create "title" => "r3", "content" => "hello world"
    assert r3.valid?, "Saving r3"
  end

254
  def test_validate_format
255
    Topic.validates_format_of(:title, :content, :with => /^Validation\smacros \w+!$/, :message => "is bad data")
256 257 258 259 260 261 262 263 264 265 266 267 268 269

    t = Topic.create("title" => "i'm incorrect", "content" => "Validation macros rule!")
    assert !t.valid?, "Shouldn't be valid"
    assert !t.save, "Shouldn't save because it's invalid"
    assert_equal "is bad data", t.errors.on(:title)
    assert_nil t.errors.on(:content)

    t.title = "Validation macros rule!"

    assert t.save
    assert_nil t.errors.on(:title)

    assert_raise(ArgumentError) { Topic.validates_format_of(:title, :content) }
  end
270 271 272 273 274 275 276

  def test_validates_inclusion_of
    Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ) )

    assert !Topic.create("title" => "a!", "content" => "abc").valid?
    assert !Topic.create("title" => "a b", "content" => "abc").valid?
    assert !Topic.create("title" => nil, "content" => "def").valid?
277

278 279 280 281 282 283 284 285 286 287 288 289 290 291
    t = Topic.create("title" => "a", "content" => "I know you are but what am I?")
    assert t.valid?
    t.title = "uhoh"
    assert !t.valid?
    assert t.errors.on(:title)
    assert_equal "is not included in the list", t.errors["title"]

    assert_raise(ArgumentError) { Topic.validates_inclusion_of( :title, :in => nil ) }
    assert_raise(ArgumentError) { Topic.validates_inclusion_of( :title, :in => 0) }

    assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of( :title, :in => "hi!" ) }
    assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of( :title, :in => {} ) }
    assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of( :title, :in => [] ) }
  end
292

293 294 295 296 297 298 299 300
  def test_validates_inclusion_of_with_allow_nil
    Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :allow_nil=>true )

    assert !Topic.create("title" => "a!", "content" => "abc").valid?
    assert !Topic.create("title" => "", "content" => "abc").valid?
    assert Topic.create("title" => nil, "content" => "abc").valid?
  end

301
  def test_validates_length_of_using_minimum
302 303
    Topic.validates_length_of :title, :minimum => 5

304 305
    t = Topic.create("title" => "valid", "content" => "whatever")
    assert t.valid?
306

307 308 309 310
    t.title = "not"
    assert !t.valid?
    assert t.errors.on(:title)
    assert_equal "is too short (min is 5 characters)", t.errors["title"]
311

312 313 314
    t.title = ""
    assert !t.valid?
    assert t.errors.on(:title)
315 316
    assert_equal "is too short (min is 5 characters)", t.errors["title"]

317 318 319
    t.title = nil
    assert !t.valid?
    assert t.errors.on(:title)
320 321 322 323 324 325 326 327 328 329 330
    assert_equal "is too short (min is 5 characters)", t.errors["title"]
  end

  def test_optionally_validates_length_of_using_minimum
    Topic.validates_length_of :title, :minimum => 5, :allow_nil => true

    t = Topic.create("title" => "valid", "content" => "whatever")
    assert t.valid?

    t.title = nil
    assert t.valid?
331
  end
332

333
  def test_validates_length_of_using_maximum
334 335
    Topic.validates_length_of :title, :maximum => 5

336 337
    t = Topic.create("title" => "valid", "content" => "whatever")
    assert t.valid?
338

339 340 341 342
    t.title = "notvalid"
    assert !t.valid?
    assert t.errors.on(:title)
    assert_equal "is too long (max is 5 characters)", t.errors["title"]
343

344 345
    t.title = ""
    assert t.valid?
346 347 348 349 350 351 352 353 354 355 356

    t.title = nil
    assert !t.valid?
  end

  def test_optionally_validates_length_of_using_maximum
    Topic.validates_length_of :title, :maximum => 5, :allow_nil => true

    t = Topic.create("title" => "valid", "content" => "whatever")
    assert t.valid?

357 358 359 360 361 362 363 364 365
    t.title = nil
    assert t.valid?
  end

  def test_validates_length_of_using_within
    Topic.validates_length_of(:title, :content, :within => 3..5)

    t = Topic.create("title" => "a!", "content" => "I'm ooooooooh so very long")
    assert !t.save
366

367 368 369 370 371 372 373 374
    assert_equal "is too short (min is 3 characters)", t.errors.on(:title)
    assert_equal "is too long (max is 5 characters)", t.errors.on(:content)

    t.title = "abe"
    t.content  = "mad"
    assert t.save
  end

375 376 377 378 379 380 381 382 383 384
  def test_optionally_validates_length_of_using_within
    Topic.validates_length_of :title, :content, :within => 3..5, :allow_nil => true

    t = Topic.create('title' => 'abc', 'content' => 'abcd')
    assert t.valid?

    t.title = nil
    assert t.valid?
  end

385
  def test_validates_length_of_using_is
386 387
    Topic.validates_length_of :title, :is => 5

388 389
    t = Topic.create("title" => "valid", "content" => "whatever")
    assert t.valid?
390

391 392 393 394
    t.title = "notvalid"
    assert !t.valid?
    assert t.errors.on(:title)
    assert_equal "is the wrong length (should be 5 characters)", t.errors["title"]
395

396 397
    t.title = ""
    assert !t.valid?
398

399 400 401 402
    t.title = nil
    assert !t.valid?
  end

403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
  def test_optionally_validates_length_of_using_is
    Topic.validates_length_of :title, :is => 5, :allow_nil => true

    t = Topic.create("title" => "valid", "content" => "whatever")
    assert t.valid?

    t.title = nil
    assert t.valid?
  end

  def test_validates_length_of_using_bignum
    bigmin = 2 ** 30
    bigmax = 2 ** 32
    bigrange = bigmin...bigmax
    assert_nothing_raised do
      Topic.validates_length_of :title, :is => bigmin + 5
      Topic.validates_length_of :title, :within => bigrange
      Topic.validates_length_of :title, :in => bigrange
      Topic.validates_length_of :title, :minimum => bigmin
      Topic.validates_length_of :title, :maximum => bigmax
    end
  end

  def test_validates_size_of_association
    assert_nothing_raised { Topic.validates_size_of :replies, :minimum => 1 }
    t = Topic.new('title' => 'noreplies', 'content' => 'whatever')
    assert !t.save
    assert t.errors.on(:replies)
    t.replies.create('title' => 'areply', 'content' => 'whateveragain')
    assert t.valid?
  end

435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
  def test_validates_length_of_nasty_params
    assert_raise(ArgumentError) { Topic.validates_length_of(:title, :minimum=>6, :maximum=>9) }
    assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>6, :maximum=>9) }
    assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>6, :minimum=>9) }
    assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>6, :is=>9) }
    assert_raise(ArgumentError) { Topic.validates_length_of(:title, :minimum=>"a") }
    assert_raise(ArgumentError) { Topic.validates_length_of(:title, :maximum=>"a") }
    assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>"a") }
    assert_raise(ArgumentError) { Topic.validates_length_of(:title, :is=>"a") }
  end

  def test_validates_length_of_custom_errors_for_minimum_with_message
    Topic.validates_length_of( :title, :minimum=>5, :message=>"boo %d" )
    t = Topic.create("title" => "uhoh", "content" => "whatever")
    assert !t.valid?
    assert t.errors.on(:title)
    assert_equal "boo 5", t.errors["title"]
  end

  def test_validates_length_of_custom_errors_for_minimum_with_too_short
    Topic.validates_length_of( :title, :minimum=>5, :too_short=>"hoo %d" )
    t = Topic.create("title" => "uhoh", "content" => "whatever")
    assert !t.valid?
    assert t.errors.on(:title)
    assert_equal "hoo 5", t.errors["title"]
  end

  def test_validates_length_of_custom_errors_for_maximum_with_message
    Topic.validates_length_of( :title, :maximum=>5, :message=>"boo %d" )
    t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
    assert !t.valid?
    assert t.errors.on(:title)
    assert_equal "boo 5", t.errors["title"]
  end

  def test_validates_length_of_custom_errors_for_maximum_with_too_long
    Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d" )
    t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
    assert !t.valid?
    assert t.errors.on(:title)
    assert_equal "hoo 5", t.errors["title"]
  end
477

478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
  def test_validates_length_of_custom_errors_for_is_with_message
    Topic.validates_length_of( :title, :is=>5, :message=>"boo %d" )
    t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
    assert !t.valid?
    assert t.errors.on(:title)
    assert_equal "boo 5", t.errors["title"]
  end

  def test_validates_length_of_custom_errors_for_is_with_wrong_length
    Topic.validates_length_of( :title, :is=>5, :wrong_length=>"hoo %d" )
    t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
    assert !t.valid?
    assert t.errors.on(:title)
    assert_equal "hoo 5", t.errors["title"]
  end

494 495 496
  def test_validates_associated_many
    Topic.validates_associated( :replies )
    t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
497
    t.replies << [r = Reply.create("title" => "A reply"), r2 = Reply.create("title" => "Another reply")]
498 499
    assert !t.valid?
    assert t.errors.on(:replies)
500 501 502
    assert_equal 1, r.errors.count  # make sure all associated objects have been validated
    assert_equal 1, r2.errors.count
    r.content = r2.content = "non-empty"
503 504 505 506 507 508 509 510 511 512 513 514 515 516
    assert t.valid?
  end

  def test_validates_associated_one
    Reply.validates_associated( :topic )
    Topic.validates_presence_of( :content )
    r = Reply.create("title" => "A reply", "content" => "with content!")
    r.topic = Topic.create("title" => "uhohuhoh")
    assert !r.valid?
    assert r.errors.on(:topic)
    r.topic.content = "non-empty"
    assert r.valid?
  end

517 518 519 520 521 522 523 524 525 526 527 528 529
  def test_validate_block
    Topic.validate { |topic| topic.errors.add("title", "will never be valid") }
    t = Topic.create("title" => "Title", "content" => "whatever")
    assert !t.valid?
    assert t.errors.on(:title)
    assert_equal "will never be valid", t.errors["title"]
  end

  def test_invalid_validator
    Topic.validate 3
    assert_raise(ActiveRecord::ActiveRecordError) { t = Topic.create }
  end

530 531 532
  def test_throw_away_typing
    d = Developer.create "name" => "David", "salary" => "100,000"
    assert !d.valid?
533
    assert_equal 100, d.salary
534 535
    assert_equal "100,000", d.salary_before_type_cast
  end
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617

  def test_validates_acceptance_of_with_custom_error_using_quotes
    Developer.validates_acceptance_of :salary, :message=> "This string contains 'single' and \"double\" quotes"
    d = Developer.new
    d.salary = "0"
    assert !d.valid?
    assert_equal d.errors.on(:salary).first, "This string contains 'single' and \"double\" quotes"
  end

  def test_validates_confirmation_of_with_custom_error_using_quotes
    Developer.validates_confirmation_of :name, :message=> "This string contains 'single' and \"double\" quotes"
    d = Developer.new
    d.name = "John"
    d.name_confirmation = "Johnny"
    assert !d.valid?
    assert_equal d.errors.on(:name), "This string contains 'single' and \"double\" quotes"
  end

  def test_validates_format_of_with_custom_error_using_quotes
    Developer.validates_format_of :name, :with => /^(A-Z*)$/, :message=> "This string contains 'single' and \"double\" quotes"
    d = Developer.new
    d.name = "John 32"
    assert !d.valid?
    assert_equal d.errors.on(:name), "This string contains 'single' and \"double\" quotes"
  end

  def test_validates_inclusion_of_with_custom_error_using_quotes
    Developer.validates_inclusion_of :salary, :in => 1000..80000, :message=> "This string contains 'single' and \"double\" quotes"
    d = Developer.new
    d.salary = "90,000"
    assert !d.valid?
    assert_equal d.errors.on(:salary).first, "This string contains 'single' and \"double\" quotes"
  end

  def test_validates_length_of_with_custom_too_long_using_quotes
    Developer.validates_length_of :name, :maximum => 4, :too_long=> "This string contains 'single' and \"double\" quotes"
    d = Developer.new
    d.name = "Jeffrey"
    assert !d.valid?
    assert_equal d.errors.on(:name).first, "This string contains 'single' and \"double\" quotes"
  end

  def test_validates_length_of_with_custom_too_short_using_quotes
    Developer.validates_length_of :name, :minimum => 4, :too_short=> "This string contains 'single' and \"double\" quotes"
    d = Developer.new
    d.name = "Joe"
    assert !d.valid?
    assert_equal d.errors.on(:name).first, "This string contains 'single' and \"double\" quotes"
  end

  def test_validates_length_of_with_custom_message_using_quotes
    Developer.validates_length_of :name, :minimum => 4, :message=> "This string contains 'single' and \"double\" quotes"
    d = Developer.new
    d.name = "Joe"
    assert !d.valid?
    assert_equal d.errors.on(:name).first, "This string contains 'single' and \"double\" quotes"
  end

  def test_validates_presence_of_with_custom_message_using_quotes
    Developer.validates_presence_of :non_existent, :message=> "This string contains 'single' and \"double\" quotes"
    d = Developer.new
    d.name = "Joe"
    assert !d.valid?
    assert_equal d.errors.on(:non_existent), "This string contains 'single' and \"double\" quotes"
  end

  def test_validates_uniqueness_of_with_custom_message_using_quotes
    Developer.validates_uniqueness_of :name, :message=> "This string contains 'single' and \"double\" quotes"
    d = Developer.new
    d.name = "David"
    assert !d.valid?
    assert_equal d.errors.on(:name).first, "This string contains 'single' and \"double\" quotes"
  end

  def test_validates_associated_with_custom_message_using_quotes
    Reply.validates_associated :topic, :message=> "This string contains 'single' and \"double\" quotes"
    Topic.validates_presence_of :content
    r = Reply.create("title" => "A reply", "content" => "with content!")
    r.topic = Topic.create("title" => "uhohuhoh")
    assert !r.valid?
    assert_equal r.errors.on(:topic).first, "This string contains 'single' and \"double\" quotes"
  end
618 619

  def test_validates_numericality_of_with_string
620
    Topic.validates_numericality_of( :approved )
621
    ["not a number","42 not a number","0xdeadbeef","00-1","-+019.0","12.12.13.12",nil].each do |v|
622
        t = Topic.create("title" => "numeric test", "content" => "whatever", "approved" => "not a number")
623
        assert !t.valid?, "#{v} not rejected as a number"
624
        assert t.errors.on(:approved)
625 626 627 628
    end
  end

  def test_validates_numericality_of
629 630 631
    Topic.validates_numericality_of( :approved, :allow_nil => true )
    ["10", "10.0", "10.5", "-10.5", "-0.0001","0090","-090","-090.1",nil,""].each do |v|
        t = Topic.create("title" => "numeric test", "content" => "whatever", "approved" => v)
632
        assert t.valid?, "#{v} not recognized as a number"
633 634
        # we cannot check this as approved is actually an integer field
        #assert_in_delta v.to_f, t.approved, 0.0000001
635 636 637 638
    end
  end
  
  def test_validates_numericality_of_int_with_string
639
    Topic.validates_numericality_of( :approved, :only_integer => true )
640
    ["not a number","42 not a number","0xdeadbeef","0-1","--3","+-3","+3-1",nil].each do |v|
641
        t = Topic.create("title" => "numeric test", "content" => "whatever", "approved" => v)
642
        assert !t.valid?, "#{v} not rejected as integer"
643
        assert t.errors.on(:approved)
644 645 646 647
    end
  end
  
  def test_validates_numericality_of_int
648 649 650
    Topic.validates_numericality_of( :approved, :only_integer => true, :allow_nil => true )
    ["42", "+42", "-42", "042", "0042", "-042", 42, nil,""].each do |v|
        t = Topic.create("title" => "numeric test", "content" => "whatever", "approved" => v)
651
        assert t.valid?, "#{v} not recognized as integer"
652
        assert_equal((v.nil? or v == "")? nil : v.to_i, t.approved)
653 654
    end
  end
655

656
end