PageRenderTime 57ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/rails/activerecord/test/validations_test.rb

https://github.com/millbanksystems/hansard
Ruby | 1131 lines | 1059 code | 71 blank | 1 comment | 0 complexity | a4c7c9173b5cfda6a9228b03f778e906 MD5 | raw file
Possible License(s): Apache-2.0, MPL-2.0-no-copyleft-exception
  1. require 'abstract_unit'
  2. require 'fixtures/topic'
  3. require 'fixtures/reply'
  4. require 'fixtures/person'
  5. require 'fixtures/developer'
  6. # The following methods in Topic are used in test_conditional_validation_*
  7. class Topic
  8. def condition_is_true
  9. return true
  10. end
  11. def condition_is_true_but_its_not
  12. return false
  13. end
  14. end
  15. class ProtectedPerson < ActiveRecord::Base
  16. set_table_name 'people'
  17. attr_accessor :addon
  18. attr_protected :first_name
  19. end
  20. class ValidationsTest < Test::Unit::TestCase
  21. fixtures :topics, :developers
  22. def setup
  23. Topic.write_inheritable_attribute(:validate, nil)
  24. Topic.write_inheritable_attribute(:validate_on_create, nil)
  25. Topic.write_inheritable_attribute(:validate_on_update, nil)
  26. end
  27. def test_single_field_validation
  28. r = Reply.new
  29. r.title = "There's no content!"
  30. assert !r.valid?, "A reply without content shouldn't be saveable"
  31. r.content = "Messa content!"
  32. assert r.valid?, "A reply with content should be saveable"
  33. end
  34. def test_single_attr_validation_and_error_msg
  35. r = Reply.new
  36. r.title = "There's no content!"
  37. assert !r.valid?
  38. assert r.errors.invalid?("content"), "A reply without content should mark that attribute as invalid"
  39. assert_equal "Empty", r.errors.on("content"), "A reply without content should contain an error"
  40. assert_equal 1, r.errors.count
  41. end
  42. def test_double_attr_validation_and_error_msg
  43. r = Reply.new
  44. assert !r.valid?
  45. assert r.errors.invalid?("title"), "A reply without title should mark that attribute as invalid"
  46. assert_equal "Empty", r.errors.on("title"), "A reply without title should contain an error"
  47. assert r.errors.invalid?("content"), "A reply without content should mark that attribute as invalid"
  48. assert_equal "Empty", r.errors.on("content"), "A reply without content should contain an error"
  49. assert_equal 2, r.errors.count
  50. end
  51. def test_error_on_create
  52. r = Reply.new
  53. r.title = "Wrong Create"
  54. assert !r.valid?
  55. assert r.errors.invalid?("title"), "A reply with a bad title should mark that attribute as invalid"
  56. assert_equal "is Wrong Create", r.errors.on("title"), "A reply with a bad content should contain an error"
  57. end
  58. def test_error_on_update
  59. r = Reply.new
  60. r.title = "Bad"
  61. r.content = "Good"
  62. assert r.save, "First save should be successful"
  63. r.title = "Wrong Update"
  64. assert !r.save, "Second save should fail"
  65. assert r.errors.invalid?("title"), "A reply with a bad title should mark that attribute as invalid"
  66. assert_equal "is Wrong Update", r.errors.on("title"), "A reply with a bad content should contain an error"
  67. end
  68. def test_invalid_record_exception
  69. assert_raises(ActiveRecord::RecordInvalid) { Reply.create! }
  70. assert_raises(ActiveRecord::RecordInvalid) { Reply.new.save! }
  71. begin
  72. r = Reply.new
  73. r.save!
  74. flunk
  75. rescue ActiveRecord::RecordInvalid => invalid
  76. assert_equal r, invalid.record
  77. end
  78. end
  79. def test_scoped_create_without_attributes
  80. Reply.with_scope(:create => {}) do
  81. assert_raises(ActiveRecord::RecordInvalid) { Reply.create! }
  82. end
  83. end
  84. def test_create_with_exceptions_using_scope_for_protected_attributes
  85. assert_nothing_raised do
  86. ProtectedPerson.with_scope( :create => { :first_name => "Mary" } ) do
  87. person = ProtectedPerson.create! :addon => "Addon"
  88. assert_equal person.first_name, "Mary", "scope should ignore attr_protected"
  89. end
  90. end
  91. end
  92. def test_create_with_exceptions_using_scope_and_empty_attributes
  93. assert_nothing_raised do
  94. ProtectedPerson.with_scope( :create => { :first_name => "Mary" } ) do
  95. person = ProtectedPerson.create!
  96. assert_equal person.first_name, "Mary", "should be ok when no attributes are passed to create!"
  97. end
  98. end
  99. end
  100. def test_single_error_per_attr_iteration
  101. r = Reply.new
  102. r.save
  103. errors = []
  104. r.errors.each { |attr, msg| errors << [attr, msg] }
  105. assert errors.include?(["title", "Empty"])
  106. assert errors.include?(["content", "Empty"])
  107. end
  108. def test_multiple_errors_per_attr_iteration_with_full_error_composition
  109. r = Reply.new
  110. r.title = "Wrong Create"
  111. r.content = "Mismatch"
  112. r.save
  113. errors = []
  114. r.errors.each_full { |error| errors << error }
  115. assert_equal "Title is Wrong Create", errors[0]
  116. assert_equal "Title is Content Mismatch", errors[1]
  117. assert_equal 2, r.errors.count
  118. end
  119. def test_errors_on_base
  120. r = Reply.new
  121. r.content = "Mismatch"
  122. r.save
  123. r.errors.add_to_base "Reply is not dignifying"
  124. errors = []
  125. r.errors.each_full { |error| errors << error }
  126. assert_equal "Reply is not dignifying", r.errors.on_base
  127. assert errors.include?("Title Empty")
  128. assert errors.include?("Reply is not dignifying")
  129. assert_equal 2, r.errors.count
  130. end
  131. def test_create_without_validation
  132. reply = Reply.new
  133. assert !reply.save
  134. assert reply.save(false)
  135. end
  136. def test_create_without_validation_bang
  137. count = Reply.count
  138. assert_nothing_raised { Reply.new.save_without_validation! }
  139. assert count+1, Reply.count
  140. end
  141. def test_validates_each
  142. perform = true
  143. hits = 0
  144. Topic.validates_each(:title, :content, [:title, :content]) do |record, attr|
  145. if perform
  146. record.errors.add attr, 'gotcha'
  147. hits += 1
  148. end
  149. end
  150. t = Topic.new("title" => "valid", "content" => "whatever")
  151. assert !t.save
  152. assert_equal 4, hits
  153. assert_equal %w(gotcha gotcha), t.errors.on(:title)
  154. assert_equal %w(gotcha gotcha), t.errors.on(:content)
  155. ensure
  156. perform = false
  157. end
  158. def test_no_title_confirmation
  159. Topic.validates_confirmation_of(:title)
  160. t = Topic.new(:author_name => "Plutarch")
  161. assert t.valid?
  162. t.title_confirmation = "Parallel Lives"
  163. assert !t.valid?
  164. t.title_confirmation = nil
  165. t.title = "Parallel Lives"
  166. assert t.valid?
  167. t.title_confirmation = "Parallel Lives"
  168. assert t.valid?
  169. end
  170. def test_title_confirmation
  171. Topic.validates_confirmation_of(:title)
  172. t = Topic.create("title" => "We should be confirmed","title_confirmation" => "")
  173. assert !t.save
  174. t.title_confirmation = "We should be confirmed"
  175. assert t.save
  176. end
  177. def test_terms_of_service_agreement_no_acceptance
  178. Topic.validates_acceptance_of(:terms_of_service, :on => :create)
  179. t = Topic.create("title" => "We should not be confirmed")
  180. assert t.save
  181. end
  182. def test_terms_of_service_agreement
  183. Topic.validates_acceptance_of(:terms_of_service, :on => :create)
  184. t = Topic.create("title" => "We should be confirmed","terms_of_service" => "")
  185. assert !t.save
  186. assert_equal "must be accepted", t.errors.on(:terms_of_service)
  187. t.terms_of_service = "1"
  188. assert t.save
  189. end
  190. def test_eula
  191. Topic.validates_acceptance_of(:eula, :message => "must be abided", :on => :create)
  192. t = Topic.create("title" => "We should be confirmed","eula" => "")
  193. assert !t.save
  194. assert_equal "must be abided", t.errors.on(:eula)
  195. t.eula = "1"
  196. assert t.save
  197. end
  198. def test_terms_of_service_agreement_with_accept_value
  199. Topic.validates_acceptance_of(:terms_of_service, :on => :create, :accept => "I agree.")
  200. t = Topic.create("title" => "We should be confirmed", "terms_of_service" => "")
  201. assert !t.save
  202. assert_equal "must be accepted", t.errors.on(:terms_of_service)
  203. t.terms_of_service = "I agree."
  204. assert t.save
  205. end
  206. def test_validate_presences
  207. Topic.validates_presence_of(:title, :content)
  208. t = Topic.create
  209. assert !t.save
  210. assert_equal "can't be blank", t.errors.on(:title)
  211. assert_equal "can't be blank", t.errors.on(:content)
  212. t.title = "something"
  213. t.content = " "
  214. assert !t.save
  215. assert_equal "can't be blank", t.errors.on(:content)
  216. t.content = "like stuff"
  217. assert t.save
  218. end
  219. def test_validate_uniqueness
  220. Topic.validates_uniqueness_of(:title)
  221. t = Topic.new("title" => "I'm unique!")
  222. assert t.save, "Should save t as unique"
  223. t.content = "Remaining unique"
  224. assert t.save, "Should still save t as unique"
  225. t2 = Topic.new("title" => "I'm unique!")
  226. assert !t2.valid?, "Shouldn't be valid"
  227. assert !t2.save, "Shouldn't save t2 as unique"
  228. assert_equal "has already been taken", t2.errors.on(:title)
  229. t2.title = "Now Im really also unique"
  230. assert t2.save, "Should now save t2 as unique"
  231. end
  232. def test_validate_uniqueness_with_scope
  233. Reply.validates_uniqueness_of(:content, :scope => "parent_id")
  234. t = Topic.create("title" => "I'm unique!")
  235. r1 = t.replies.create "title" => "r1", "content" => "hello world"
  236. assert r1.valid?, "Saving r1"
  237. r2 = t.replies.create "title" => "r2", "content" => "hello world"
  238. assert !r2.valid?, "Saving r2 first time"
  239. r2.content = "something else"
  240. assert r2.save, "Saving r2 second time"
  241. t2 = Topic.create("title" => "I'm unique too!")
  242. r3 = t2.replies.create "title" => "r3", "content" => "hello world"
  243. assert r3.valid?, "Saving r3"
  244. end
  245. def test_validate_uniqueness_with_scope_array
  246. Reply.validates_uniqueness_of(:author_name, :scope => [:author_email_address, :parent_id])
  247. t = Topic.create("title" => "The earth is actually flat!")
  248. r1 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy@rubyonrails.com", "title" => "You're crazy!", "content" => "Crazy reply"
  249. assert r1.valid?, "Saving r1"
  250. r2 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy@rubyonrails.com", "title" => "You're crazy!", "content" => "Crazy reply again..."
  251. assert !r2.valid?, "Saving r2. Double reply by same author."
  252. r2.author_email_address = "jeremy_alt_email@rubyonrails.com"
  253. assert r2.save, "Saving r2 the second time."
  254. r3 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy_alt_email@rubyonrails.com", "title" => "You're wrong", "content" => "It's cubic"
  255. assert !r3.valid?, "Saving r3"
  256. r3.author_name = "jj"
  257. assert r3.save, "Saving r3 the second time."
  258. r3.author_name = "jeremy"
  259. assert !r3.save, "Saving r3 the third time."
  260. end
  261. def test_validate_case_insensitive_uniqueness
  262. Topic.validates_uniqueness_of(:title, :parent_id, :case_sensitive => false, :allow_nil => true)
  263. t = Topic.new("title" => "I'm unique!", :parent_id => 2)
  264. assert t.save, "Should save t as unique"
  265. t.content = "Remaining unique"
  266. assert t.save, "Should still save t as unique"
  267. t2 = Topic.new("title" => "I'm UNIQUE!", :parent_id => 1)
  268. assert !t2.valid?, "Shouldn't be valid"
  269. assert !t2.save, "Shouldn't save t2 as unique"
  270. assert t2.errors.on(:title)
  271. assert t2.errors.on(:parent_id)
  272. assert_equal "has already been taken", t2.errors.on(:title)
  273. t2.title = "I'm truly UNIQUE!"
  274. assert !t2.valid?, "Shouldn't be valid"
  275. assert !t2.save, "Shouldn't save t2 as unique"
  276. assert_nil t2.errors.on(:title)
  277. assert t2.errors.on(:parent_id)
  278. t2.parent_id = 3
  279. assert t2.save, "Should now save t2 as unique"
  280. t2.parent_id = nil
  281. t2.title = nil
  282. assert t2.valid?, "should validate with nil"
  283. assert t2.save, "should save with nil"
  284. end
  285. def test_validate_format
  286. Topic.validates_format_of(:title, :content, :with => /^Validation\smacros \w+!$/, :message => "is bad data")
  287. t = Topic.create("title" => "i'm incorrect", "content" => "Validation macros rule!")
  288. assert !t.valid?, "Shouldn't be valid"
  289. assert !t.save, "Shouldn't save because it's invalid"
  290. assert_equal "is bad data", t.errors.on(:title)
  291. assert_nil t.errors.on(:content)
  292. t.title = "Validation macros rule!"
  293. assert t.save
  294. assert_nil t.errors.on(:title)
  295. assert_raise(ArgumentError) { Topic.validates_format_of(:title, :content) }
  296. end
  297. # testing ticket #3142
  298. def test_validate_format_numeric
  299. Topic.validates_format_of(:title, :content, :with => /^[1-9][0-9]*$/, :message => "is bad data")
  300. t = Topic.create("title" => "72x", "content" => "6789")
  301. assert !t.valid?, "Shouldn't be valid"
  302. assert !t.save, "Shouldn't save because it's invalid"
  303. assert_equal "is bad data", t.errors.on(:title)
  304. assert_nil t.errors.on(:content)
  305. t.title = "-11"
  306. assert !t.valid?, "Shouldn't be valid"
  307. t.title = "03"
  308. assert !t.valid?, "Shouldn't be valid"
  309. t.title = "z44"
  310. assert !t.valid?, "Shouldn't be valid"
  311. t.title = "5v7"
  312. assert !t.valid?, "Shouldn't be valid"
  313. t.title = "1"
  314. assert t.save
  315. assert_nil t.errors.on(:title)
  316. end
  317. def test_validates_inclusion_of
  318. Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ) )
  319. assert !Topic.create("title" => "a!", "content" => "abc").valid?
  320. assert !Topic.create("title" => "a b", "content" => "abc").valid?
  321. assert !Topic.create("title" => nil, "content" => "def").valid?
  322. t = Topic.create("title" => "a", "content" => "I know you are but what am I?")
  323. assert t.valid?
  324. t.title = "uhoh"
  325. assert !t.valid?
  326. assert t.errors.on(:title)
  327. assert_equal "is not included in the list", t.errors["title"]
  328. assert_raise(ArgumentError) { Topic.validates_inclusion_of( :title, :in => nil ) }
  329. assert_raise(ArgumentError) { Topic.validates_inclusion_of( :title, :in => 0) }
  330. assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of( :title, :in => "hi!" ) }
  331. assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of( :title, :in => {} ) }
  332. assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of( :title, :in => [] ) }
  333. end
  334. def test_validates_inclusion_of_with_allow_nil
  335. Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :allow_nil=>true )
  336. assert !Topic.create("title" => "a!", "content" => "abc").valid?
  337. assert !Topic.create("title" => "", "content" => "abc").valid?
  338. assert Topic.create("title" => nil, "content" => "abc").valid?
  339. end
  340. def test_numericality_with_allow_nil_and_getter_method
  341. Developer.validates_numericality_of( :salary, :allow_nil => true)
  342. developer = Developer.new("name" => "michael", "salary" => nil)
  343. developer.instance_eval("def salary; read_attribute('salary') ? read_attribute('salary') : 100000; end")
  344. assert developer.valid?
  345. end
  346. def test_validates_exclusion_of
  347. Topic.validates_exclusion_of( :title, :in => %w( abe monkey ) )
  348. assert Topic.create("title" => "something", "content" => "abc").valid?
  349. assert !Topic.create("title" => "monkey", "content" => "abc").valid?
  350. end
  351. def test_validates_length_of_using_minimum
  352. Topic.validates_length_of :title, :minimum => 5
  353. t = Topic.create("title" => "valid", "content" => "whatever")
  354. assert t.valid?
  355. t.title = "not"
  356. assert !t.valid?
  357. assert t.errors.on(:title)
  358. assert_equal "is too short (minimum is 5 characters)", t.errors["title"]
  359. t.title = ""
  360. assert !t.valid?
  361. assert t.errors.on(:title)
  362. assert_equal "is too short (minimum is 5 characters)", t.errors["title"]
  363. t.title = nil
  364. assert !t.valid?
  365. assert t.errors.on(:title)
  366. assert_equal "is too short (minimum is 5 characters)", t.errors["title"]
  367. end
  368. def test_optionally_validates_length_of_using_minimum
  369. Topic.validates_length_of :title, :minimum => 5, :allow_nil => true
  370. t = Topic.create("title" => "valid", "content" => "whatever")
  371. assert t.valid?
  372. t.title = nil
  373. assert t.valid?
  374. end
  375. def test_validates_length_of_using_maximum
  376. Topic.validates_length_of :title, :maximum => 5
  377. t = Topic.create("title" => "valid", "content" => "whatever")
  378. assert t.valid?
  379. t.title = "notvalid"
  380. assert !t.valid?
  381. assert t.errors.on(:title)
  382. assert_equal "is too long (maximum is 5 characters)", t.errors["title"]
  383. t.title = ""
  384. assert t.valid?
  385. t.title = nil
  386. assert !t.valid?
  387. end
  388. def test_optionally_validates_length_of_using_maximum
  389. Topic.validates_length_of :title, :maximum => 5, :allow_nil => true
  390. t = Topic.create("title" => "valid", "content" => "whatever")
  391. assert t.valid?
  392. t.title = nil
  393. assert t.valid?
  394. end
  395. def test_validates_length_of_using_within
  396. Topic.validates_length_of(:title, :content, :within => 3..5)
  397. t = Topic.new("title" => "a!", "content" => "I'm ooooooooh so very long")
  398. assert !t.valid?
  399. assert_equal "is too short (minimum is 3 characters)", t.errors.on(:title)
  400. assert_equal "is too long (maximum is 5 characters)", t.errors.on(:content)
  401. t.title = nil
  402. t.content = nil
  403. assert !t.valid?
  404. assert_equal "is too short (minimum is 3 characters)", t.errors.on(:title)
  405. assert_equal "is too short (minimum is 3 characters)", t.errors.on(:content)
  406. t.title = "abe"
  407. t.content = "mad"
  408. assert t.valid?
  409. end
  410. def test_optionally_validates_length_of_using_within
  411. Topic.validates_length_of :title, :content, :within => 3..5, :allow_nil => true
  412. t = Topic.create('title' => 'abc', 'content' => 'abcd')
  413. assert t.valid?
  414. t.title = nil
  415. assert t.valid?
  416. end
  417. def test_optionally_validates_length_of_using_within_on_create
  418. Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "my string is too long: %d"
  419. t = Topic.create("title" => "thisisnotvalid", "content" => "whatever")
  420. assert !t.save
  421. assert t.errors.on(:title)
  422. assert_equal "my string is too long: 10", t.errors[:title]
  423. t.title = "butthisis"
  424. assert t.save
  425. t.title = "few"
  426. assert t.save
  427. t.content = "andthisislong"
  428. assert t.save
  429. t.content = t.title = "iamfine"
  430. assert t.save
  431. end
  432. def test_optionally_validates_length_of_using_within_on_update
  433. Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "my string is too short: %d"
  434. t = Topic.create("title" => "vali", "content" => "whatever")
  435. assert !t.save
  436. assert t.errors.on(:title)
  437. t.title = "not"
  438. assert !t.save
  439. assert t.errors.on(:title)
  440. assert_equal "my string is too short: 5", t.errors[:title]
  441. t.title = "valid"
  442. t.content = "andthisistoolong"
  443. assert !t.save
  444. assert t.errors.on(:content)
  445. t.content = "iamfine"
  446. assert t.save
  447. end
  448. def test_validates_length_of_using_is
  449. Topic.validates_length_of :title, :is => 5
  450. t = Topic.create("title" => "valid", "content" => "whatever")
  451. assert t.valid?
  452. t.title = "notvalid"
  453. assert !t.valid?
  454. assert t.errors.on(:title)
  455. assert_equal "is the wrong length (should be 5 characters)", t.errors["title"]
  456. t.title = ""
  457. assert !t.valid?
  458. t.title = nil
  459. assert !t.valid?
  460. end
  461. def test_optionally_validates_length_of_using_is
  462. Topic.validates_length_of :title, :is => 5, :allow_nil => true
  463. t = Topic.create("title" => "valid", "content" => "whatever")
  464. assert t.valid?
  465. t.title = nil
  466. assert t.valid?
  467. end
  468. def test_validates_length_of_using_bignum
  469. bigmin = 2 ** 30
  470. bigmax = 2 ** 32
  471. bigrange = bigmin...bigmax
  472. assert_nothing_raised do
  473. Topic.validates_length_of :title, :is => bigmin + 5
  474. Topic.validates_length_of :title, :within => bigrange
  475. Topic.validates_length_of :title, :in => bigrange
  476. Topic.validates_length_of :title, :minimum => bigmin
  477. Topic.validates_length_of :title, :maximum => bigmax
  478. end
  479. end
  480. def test_validates_length_with_globaly_modified_error_message
  481. ActiveRecord::Errors.default_error_messages[:too_short] = 'tu est trops petit hombre %d'
  482. Topic.validates_length_of :title, :minimum => 10
  483. t = Topic.create(:title => 'too short')
  484. assert !t.valid?
  485. assert_equal 'tu est trops petit hombre 10', t.errors['title']
  486. end
  487. def test_add_on_boundary_breaking_is_deprecated
  488. t = Topic.new('title' => 'noreplies', 'content' => 'whatever')
  489. class << t
  490. def validate
  491. errors.add_on_boundary_breaking('title', 1..6)
  492. end
  493. end
  494. assert_deprecated 'add_on_boundary_breaking' do
  495. assert !t.valid?
  496. end
  497. end
  498. def test_validates_size_of_association
  499. assert_nothing_raised { Topic.validates_size_of :replies, :minimum => 1 }
  500. t = Topic.new('title' => 'noreplies', 'content' => 'whatever')
  501. assert !t.save
  502. assert t.errors.on(:replies)
  503. t.replies.create('title' => 'areply', 'content' => 'whateveragain')
  504. assert t.valid?
  505. end
  506. def test_validates_length_of_nasty_params
  507. assert_raise(ArgumentError) { Topic.validates_length_of(:title, :minimum=>6, :maximum=>9) }
  508. assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>6, :maximum=>9) }
  509. assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>6, :minimum=>9) }
  510. assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>6, :is=>9) }
  511. assert_raise(ArgumentError) { Topic.validates_length_of(:title, :minimum=>"a") }
  512. assert_raise(ArgumentError) { Topic.validates_length_of(:title, :maximum=>"a") }
  513. assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>"a") }
  514. assert_raise(ArgumentError) { Topic.validates_length_of(:title, :is=>"a") }
  515. end
  516. def test_validates_length_of_custom_errors_for_minimum_with_message
  517. Topic.validates_length_of( :title, :minimum=>5, :message=>"boo %d" )
  518. t = Topic.create("title" => "uhoh", "content" => "whatever")
  519. assert !t.valid?
  520. assert t.errors.on(:title)
  521. assert_equal "boo 5", t.errors["title"]
  522. end
  523. def test_validates_length_of_custom_errors_for_minimum_with_too_short
  524. Topic.validates_length_of( :title, :minimum=>5, :too_short=>"hoo %d" )
  525. t = Topic.create("title" => "uhoh", "content" => "whatever")
  526. assert !t.valid?
  527. assert t.errors.on(:title)
  528. assert_equal "hoo 5", t.errors["title"]
  529. end
  530. def test_validates_length_of_custom_errors_for_maximum_with_message
  531. Topic.validates_length_of( :title, :maximum=>5, :message=>"boo %d" )
  532. t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
  533. assert !t.valid?
  534. assert t.errors.on(:title)
  535. assert_equal "boo 5", t.errors["title"]
  536. end
  537. def test_validates_length_of_custom_errors_for_maximum_with_too_long
  538. Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d" )
  539. t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
  540. assert !t.valid?
  541. assert t.errors.on(:title)
  542. assert_equal "hoo 5", t.errors["title"]
  543. end
  544. def test_validates_length_of_custom_errors_for_is_with_message
  545. Topic.validates_length_of( :title, :is=>5, :message=>"boo %d" )
  546. t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
  547. assert !t.valid?
  548. assert t.errors.on(:title)
  549. assert_equal "boo 5", t.errors["title"]
  550. end
  551. def test_validates_length_of_custom_errors_for_is_with_wrong_length
  552. Topic.validates_length_of( :title, :is=>5, :wrong_length=>"hoo %d" )
  553. t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
  554. assert !t.valid?
  555. assert t.errors.on(:title)
  556. assert_equal "hoo 5", t.errors["title"]
  557. end
  558. def kcode_scope(kcode)
  559. orig_kcode = $KCODE
  560. $KCODE = kcode
  561. begin
  562. yield
  563. ensure
  564. $KCODE = orig_kcode
  565. end
  566. end
  567. def test_validates_length_of_using_minimum_utf8
  568. kcode_scope('UTF8') do
  569. Topic.validates_length_of :title, :minimum => 5
  570. t = Topic.create("title" => "一二三四五", "content" => "whatever")
  571. assert t.valid?
  572. t.title = "一二三四"
  573. assert !t.valid?
  574. assert t.errors.on(:title)
  575. assert_equal "is too short (minimum is 5 characters)", t.errors["title"]
  576. end
  577. end
  578. def test_validates_length_of_using_maximum_utf8
  579. kcode_scope('UTF8') do
  580. Topic.validates_length_of :title, :maximum => 5
  581. t = Topic.create("title" => "一二三四五", "content" => "whatever")
  582. assert t.valid?
  583. t.title = "一二34五六"
  584. assert !t.valid?
  585. assert t.errors.on(:title)
  586. assert_equal "is too long (maximum is 5 characters)", t.errors["title"]
  587. end
  588. end
  589. def test_validates_length_of_using_within_utf8
  590. kcode_scope('UTF8') do
  591. Topic.validates_length_of(:title, :content, :within => 3..5)
  592. t = Topic.new("title" => "一二", "content" => "12三四五六七")
  593. assert !t.valid?
  594. assert_equal "is too short (minimum is 3 characters)", t.errors.on(:title)
  595. assert_equal "is too long (maximum is 5 characters)", t.errors.on(:content)
  596. t.title = "一二三"
  597. t.content = "12三"
  598. assert t.valid?
  599. end
  600. end
  601. def test_optionally_validates_length_of_using_within_utf8
  602. kcode_scope('UTF8') do
  603. Topic.validates_length_of :title, :content, :within => 3..5, :allow_nil => true
  604. t = Topic.create('title' => '一二三', 'content' => '一二三四五')
  605. assert t.valid?
  606. t.title = nil
  607. assert t.valid?
  608. end
  609. end
  610. def test_optionally_validates_length_of_using_within_on_create_utf8
  611. kcode_scope('UTF8') do
  612. Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "長すぎます: %d"
  613. t = Topic.create("title" => "一二三四五六七八九十A", "content" => "whatever")
  614. assert !t.save
  615. assert t.errors.on(:title)
  616. assert_equal "長すぎます: 10", t.errors[:title]
  617. t.title = "一二三四五六七八九"
  618. assert t.save
  619. t.title = "一二3"
  620. assert t.save
  621. t.content = "一二三四五六七八九十"
  622. assert t.save
  623. t.content = t.title = "一二三四五六"
  624. assert t.save
  625. end
  626. end
  627. def test_optionally_validates_length_of_using_within_on_update_utf8
  628. kcode_scope('UTF8') do
  629. Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "短すぎます: %d"
  630. t = Topic.create("title" => "一二三4", "content" => "whatever")
  631. assert !t.save
  632. assert t.errors.on(:title)
  633. t.title = "1二三4"
  634. assert !t.save
  635. assert t.errors.on(:title)
  636. assert_equal "短すぎます: 5", t.errors[:title]
  637. t.title = "valid"
  638. t.content = "一二三四五六七八九十A"
  639. assert !t.save
  640. assert t.errors.on(:content)
  641. t.content = "一二345"
  642. assert t.save
  643. end
  644. end
  645. def test_validates_length_of_using_is_utf8
  646. kcode_scope('UTF8') do
  647. Topic.validates_length_of :title, :is => 5
  648. t = Topic.create("title" => "一二345", "content" => "whatever")
  649. assert t.valid?
  650. t.title = "一二345六"
  651. assert !t.valid?
  652. assert t.errors.on(:title)
  653. assert_equal "is the wrong length (should be 5 characters)", t.errors["title"]
  654. end
  655. end
  656. def test_validates_size_of_association_utf8
  657. kcode_scope('UTF8') do
  658. assert_nothing_raised { Topic.validates_size_of :replies, :minimum => 1 }
  659. t = Topic.new('title' => 'あいうえお', 'content' => 'かきくけこ')
  660. assert !t.save
  661. assert t.errors.on(:replies)
  662. t.replies.create('title' => 'あいうえお', 'content' => 'かきくけこ')
  663. assert t.valid?
  664. end
  665. end
  666. def test_validates_associated_many
  667. Topic.validates_associated( :replies )
  668. t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
  669. t.replies << [r = Reply.create("title" => "A reply"), r2 = Reply.create("title" => "Another reply")]
  670. assert !t.valid?
  671. assert t.errors.on(:replies)
  672. assert_equal 1, r.errors.count # make sure all associated objects have been validated
  673. assert_equal 1, r2.errors.count
  674. r.content = r2.content = "non-empty"
  675. assert t.valid?
  676. end
  677. def test_validates_associated_one
  678. Reply.validates_associated( :topic )
  679. Topic.validates_presence_of( :content )
  680. r = Reply.create("title" => "A reply", "content" => "with content!")
  681. r.topic = Topic.create("title" => "uhohuhoh")
  682. assert !r.valid?
  683. assert r.errors.on(:topic)
  684. r.topic.content = "non-empty"
  685. assert r.valid?
  686. end
  687. def test_validate_block
  688. Topic.validate { |topic| topic.errors.add("title", "will never be valid") }
  689. t = Topic.create("title" => "Title", "content" => "whatever")
  690. assert !t.valid?
  691. assert t.errors.on(:title)
  692. assert_equal "will never be valid", t.errors["title"]
  693. end
  694. def test_invalid_validator
  695. Topic.validate 3
  696. assert_raise(ActiveRecord::ActiveRecordError) { t = Topic.create }
  697. end
  698. def test_throw_away_typing
  699. d = Developer.new("name" => "David", "salary" => "100,000")
  700. assert !d.valid?
  701. assert_equal 100, d.salary
  702. assert_equal "100,000", d.salary_before_type_cast
  703. end
  704. def test_validates_acceptance_of_with_custom_error_using_quotes
  705. Developer.validates_acceptance_of :salary, :message=> "This string contains 'single' and \"double\" quotes"
  706. d = Developer.new
  707. d.salary = "0"
  708. assert !d.valid?
  709. assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:salary).last
  710. end
  711. def test_validates_confirmation_of_with_custom_error_using_quotes
  712. Developer.validates_confirmation_of :name, :message=> "confirm 'single' and \"double\" quotes"
  713. d = Developer.new
  714. d.name = "John"
  715. d.name_confirmation = "Johnny"
  716. assert !d.valid?
  717. assert_equal "confirm 'single' and \"double\" quotes", d.errors.on(:name)
  718. end
  719. def test_validates_format_of_with_custom_error_using_quotes
  720. Developer.validates_format_of :name, :with => /^(A-Z*)$/, :message=> "format 'single' and \"double\" quotes"
  721. d = Developer.new
  722. d.name = d.name_confirmation = "John 32"
  723. assert !d.valid?
  724. assert_equal "format 'single' and \"double\" quotes", d.errors.on(:name)
  725. end
  726. def test_validates_inclusion_of_with_custom_error_using_quotes
  727. Developer.validates_inclusion_of :salary, :in => 1000..80000, :message=> "This string contains 'single' and \"double\" quotes"
  728. d = Developer.new
  729. d.salary = "90,000"
  730. assert !d.valid?
  731. assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:salary).last
  732. end
  733. def test_validates_length_of_with_custom_too_long_using_quotes
  734. Developer.validates_length_of :name, :maximum => 4, :too_long=> "This string contains 'single' and \"double\" quotes"
  735. d = Developer.new
  736. d.name = "Jeffrey"
  737. assert !d.valid?
  738. assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:name).last
  739. end
  740. def test_validates_length_of_with_custom_too_short_using_quotes
  741. Developer.validates_length_of :name, :minimum => 4, :too_short=> "This string contains 'single' and \"double\" quotes"
  742. d = Developer.new
  743. d.name = "Joe"
  744. assert !d.valid?
  745. assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:name).last
  746. end
  747. def test_validates_length_of_with_custom_message_using_quotes
  748. Developer.validates_length_of :name, :minimum => 4, :message=> "This string contains 'single' and \"double\" quotes"
  749. d = Developer.new
  750. d.name = "Joe"
  751. assert !d.valid?
  752. assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:name).last
  753. end
  754. def test_validates_presence_of_with_custom_message_using_quotes
  755. Developer.validates_presence_of :non_existent, :message=> "This string contains 'single' and \"double\" quotes"
  756. d = Developer.new
  757. d.name = "Joe"
  758. assert !d.valid?
  759. assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:non_existent)
  760. end
  761. def test_validates_uniqueness_of_with_custom_message_using_quotes
  762. Developer.validates_uniqueness_of :name, :message=> "This string contains 'single' and \"double\" quotes"
  763. d = Developer.new
  764. d.name = "David"
  765. assert !d.valid?
  766. assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:name).last
  767. end
  768. def test_validates_associated_with_custom_message_using_quotes
  769. Reply.validates_associated :topic, :message=> "This string contains 'single' and \"double\" quotes"
  770. Topic.validates_presence_of :content
  771. r = Reply.create("title" => "A reply", "content" => "with content!")
  772. r.topic = Topic.create("title" => "uhohuhoh")
  773. assert !r.valid?
  774. assert_equal "This string contains 'single' and \"double\" quotes", r.errors.on(:topic).last
  775. end
  776. def test_conditional_validation_using_method_true
  777. # When the method returns true
  778. Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :if => :condition_is_true )
  779. t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
  780. assert !t.valid?
  781. assert t.errors.on(:title)
  782. assert_equal "hoo 5", t.errors["title"]
  783. end
  784. def test_conditional_validation_using_method_false
  785. # When the method returns false
  786. Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :if => :condition_is_true_but_its_not )
  787. t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
  788. assert t.valid?
  789. assert !t.errors.on(:title)
  790. end
  791. def test_conditional_validation_using_string_true
  792. # When the evaluated string returns true
  793. Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :if => "a = 1; a == 1" )
  794. t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
  795. assert !t.valid?
  796. assert t.errors.on(:title)
  797. assert_equal "hoo 5", t.errors["title"]
  798. end
  799. def test_conditional_validation_using_string_false
  800. # When the evaluated string returns false
  801. Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :if => "false")
  802. t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
  803. assert t.valid?
  804. assert !t.errors.on(:title)
  805. end
  806. def test_conditional_validation_using_block_true
  807. # When the block returns true
  808. Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d",
  809. :if => Proc.new { |r| r.content.size > 4 } )
  810. t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
  811. assert !t.valid?
  812. assert t.errors.on(:title)
  813. assert_equal "hoo 5", t.errors["title"]
  814. end
  815. def test_conditional_validation_using_block_false
  816. # When the block returns false
  817. Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d",
  818. :if => Proc.new { |r| r.title != "uhohuhoh"} )
  819. t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
  820. assert t.valid?
  821. assert !t.errors.on(:title)
  822. end
  823. def test_validates_associated_missing
  824. Reply.validates_presence_of(:topic)
  825. r = Reply.create("title" => "A reply", "content" => "with content!")
  826. assert !r.valid?
  827. assert r.errors.on(:topic)
  828. r.topic = Topic.find :first
  829. assert r.valid?
  830. end
  831. def test_errors_to_xml
  832. r = Reply.new :title => "Wrong Create"
  833. assert !r.valid?
  834. xml = r.errors.to_xml(:skip_instruct => true)
  835. assert_equal "<errors>", xml.first(8)
  836. assert xml.include?("<error>Title is Wrong Create</error>")
  837. assert xml.include?("<error>Content Empty</error>")
  838. end
  839. def test_validation_order
  840. Topic.validates_presence_of :title
  841. Topic.validates_length_of :title, :minimum => 2
  842. t = Topic.new("title" => "")
  843. assert !t.valid?
  844. assert_equal "can't be blank", t.errors.on("title").first
  845. end
  846. end
  847. class ValidatesNumericalityTest < Test::Unit::TestCase
  848. NIL = [nil]
  849. BLANK = ["", " ", " \t \r \n"]
  850. BIGDECIMAL_STRINGS = %w(12345678901234567890.1234567890) # 30 significent digits
  851. 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)
  852. INTEGER_STRINGS = %w(0 +0 -0 10 +10 -10 0090 -090)
  853. FLOATS = [0.0, 10.0, 10.5, -10.5, -0.0001] + FLOAT_STRINGS
  854. INTEGERS = [0, 10, -10] + INTEGER_STRINGS
  855. BIGDECIMAL = BIGDECIMAL_STRINGS.collect! { |bd| BigDecimal.new(bd) }
  856. 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"]
  857. def setup
  858. Topic.write_inheritable_attribute(:validate, nil)
  859. Topic.write_inheritable_attribute(:validate_on_create, nil)
  860. Topic.write_inheritable_attribute(:validate_on_update, nil)
  861. end
  862. def test_default_validates_numericality_of
  863. Topic.validates_numericality_of :approved
  864. invalid!(NIL + BLANK + JUNK)
  865. valid!(FLOATS + INTEGERS + BIGDECIMAL)
  866. end
  867. def test_validates_numericality_of_with_nil_allowed
  868. Topic.validates_numericality_of :approved, :allow_nil => true
  869. invalid!(BLANK + JUNK)
  870. valid!(NIL + FLOATS + INTEGERS + BIGDECIMAL)
  871. end
  872. def test_validates_numericality_of_with_integer_only
  873. Topic.validates_numericality_of :approved, :only_integer => true
  874. invalid!(NIL + BLANK + JUNK + FLOATS + BIGDECIMAL)
  875. valid!(INTEGERS)
  876. end
  877. def test_validates_numericality_of_with_integer_only_and_nil_allowed
  878. Topic.validates_numericality_of :approved, :only_integer => true, :allow_nil => true
  879. invalid!(BLANK + JUNK + FLOATS + BIGDECIMAL)
  880. valid!(NIL + INTEGERS)
  881. end
  882. private
  883. def invalid!(values)
  884. with_each_topic_approved_value(values) do |topic, value|
  885. assert !topic.valid?, "#{value.inspect} not rejected as a number"
  886. assert topic.errors.on(:approved)
  887. end
  888. end
  889. def valid!(values)
  890. with_each_topic_approved_value(values) do |topic, value|
  891. assert topic.valid?, "#{value.inspect} not accepted as a number"
  892. end
  893. end
  894. def with_each_topic_approved_value(values)
  895. topic = Topic.new("title" => "numeric test", "content" => "whatever")
  896. values.each do |value|
  897. topic.approved = value
  898. yield topic, value
  899. end
  900. end
  901. end