ant-mapper 0.0.2

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