activerecord 1.6.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (96) hide show
  1. data/CHANGELOG +78 -0
  2. data/README +20 -29
  3. data/RUNNING_UNIT_TESTS +1 -2
  4. data/examples/validation.rb +0 -3
  5. data/install.rb +3 -16
  6. data/lib/active_record.rb +11 -4
  7. data/lib/active_record/aggregations.rb +2 -2
  8. data/lib/active_record/associations.rb +8 -8
  9. data/lib/active_record/associations/association_collection.rb +1 -1
  10. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +1 -1
  11. data/lib/active_record/base.rb +117 -43
  12. data/lib/active_record/callbacks.rb +2 -2
  13. data/lib/active_record/connection_adapters/abstract_adapter.rb +7 -14
  14. data/lib/active_record/connection_adapters/db2_adapter.rb +33 -22
  15. data/lib/active_record/connection_adapters/mysql_adapter.rb +74 -33
  16. data/lib/active_record/connection_adapters/oci_adapter.rb +265 -0
  17. data/lib/active_record/connection_adapters/postgresql_adapter.rb +23 -3
  18. data/lib/active_record/connection_adapters/sqlite_adapter.rb +13 -4
  19. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +158 -67
  20. data/lib/active_record/deprecated_associations.rb +4 -4
  21. data/lib/active_record/fixtures.rb +12 -5
  22. data/lib/active_record/locking.rb +22 -22
  23. data/lib/active_record/observer.rb +6 -3
  24. data/lib/active_record/timestamp.rb +15 -5
  25. data/lib/active_record/transactions.rb +4 -4
  26. data/lib/active_record/validations.rb +272 -189
  27. data/lib/active_record/wrappings.rb +2 -2
  28. data/rakefile +17 -2
  29. data/test/aaa_create_tables_test.rb +58 -0
  30. data/test/abstract_unit.rb +3 -2
  31. data/test/aggregations_test.rb +0 -1
  32. data/test/associations_test.rb +27 -28
  33. data/test/base_test.rb +74 -2
  34. data/test/binary_test.rb +6 -2
  35. data/test/class_inheritable_attributes_test.rb +1 -1
  36. data/test/column_alias_test.rb +9 -2
  37. data/test/connections/native_oci/connection.rb +25 -0
  38. data/test/connections/native_sqlite/connection.rb +4 -1
  39. data/test/connections/native_sqlite3/connection.rb +4 -2
  40. data/test/deprecated_associations_test.rb +4 -5
  41. data/test/finder_test.rb +20 -4
  42. data/test/fixtures/db_definitions/create_oracle_db.bat +5 -0
  43. data/test/fixtures/db_definitions/create_oracle_db.sh +5 -0
  44. data/test/fixtures/db_definitions/db2.drop.sql +18 -0
  45. data/test/fixtures/db_definitions/db2.sql +1 -0
  46. data/test/fixtures/db_definitions/db22.drop.sql +2 -0
  47. data/test/fixtures/db_definitions/db22.sql +1 -0
  48. data/test/fixtures/db_definitions/drop_oracle_tables.sql +35 -0
  49. data/test/fixtures/db_definitions/drop_oracle_tables2.sql +3 -0
  50. data/test/fixtures/db_definitions/mysql.drop.sql +18 -0
  51. data/test/fixtures/db_definitions/mysql.sql +2 -1
  52. data/test/fixtures/db_definitions/mysql2.drop.sql +2 -0
  53. data/test/fixtures/db_definitions/mysql2.sql +1 -0
  54. data/test/fixtures/db_definitions/oci.drop.sql +18 -0
  55. data/test/fixtures/db_definitions/oci.sql +167 -0
  56. data/test/fixtures/db_definitions/oci2.drop.sql +2 -0
  57. data/test/fixtures/db_definitions/oci2.sql +6 -0
  58. data/test/fixtures/db_definitions/postgresql.drop.sql +18 -0
  59. data/test/fixtures/db_definitions/postgresql.sql +2 -1
  60. data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
  61. data/test/fixtures/db_definitions/postgresql2.sql +2 -1
  62. data/test/fixtures/db_definitions/sqlite.drop.sql +18 -0
  63. data/test/fixtures/db_definitions/sqlite.sql +2 -1
  64. data/test/fixtures/db_definitions/sqlite2.drop.sql +2 -0
  65. data/test/fixtures/db_definitions/sqlite2.sql +1 -0
  66. data/test/fixtures/db_definitions/sqlserver.drop.sql +18 -0
  67. data/test/fixtures/db_definitions/sqlserver.sql +1 -0
  68. data/test/fixtures/db_definitions/sqlserver2.drop.sql +2 -0
  69. data/test/fixtures/db_definitions/sqlserver2.sql +1 -0
  70. data/test/fixtures/fixture_database.sqlite +0 -0
  71. data/test/fixtures/fixture_database_2.sqlite +0 -0
  72. data/test/fixtures/topics.yml +3 -3
  73. data/test/lifecycle_test.rb +0 -1
  74. data/test/modules_test.rb +0 -1
  75. data/test/reflection_test.rb +0 -1
  76. data/test/validations_test.rb +229 -41
  77. metadata +36 -28
  78. data/dev-utils/eval_debugger.rb +0 -14
  79. data/lib/active_record/support/binding_of_caller.rb +0 -83
  80. data/lib/active_record/support/breakpoint.rb +0 -518
  81. data/lib/active_record/support/class_attribute_accessors.rb +0 -57
  82. data/lib/active_record/support/class_inheritable_attributes.rb +0 -117
  83. data/lib/active_record/support/clean_logger.rb +0 -10
  84. data/lib/active_record/support/core_ext.rb +0 -1
  85. data/lib/active_record/support/core_ext/hash.rb +0 -5
  86. data/lib/active_record/support/core_ext/hash/keys.rb +0 -35
  87. data/lib/active_record/support/core_ext/numeric.rb +0 -7
  88. data/lib/active_record/support/core_ext/numeric/bytes.rb +0 -33
  89. data/lib/active_record/support/core_ext/numeric/time.rb +0 -59
  90. data/lib/active_record/support/core_ext/object_and_class.rb +0 -24
  91. data/lib/active_record/support/core_ext/string.rb +0 -5
  92. data/lib/active_record/support/core_ext/string/inflections.rb +0 -45
  93. data/lib/active_record/support/dependencies.rb +0 -63
  94. data/lib/active_record/support/inflector.rb +0 -84
  95. data/lib/active_record/support/misc.rb +0 -8
  96. data/lib/active_record/support/module_attribute_accessors.rb +0 -57
@@ -144,4 +144,5 @@ CREATE TABLE binaries (
144
144
  CREATE TABLE computers (
145
145
  id serial,
146
146
  developer integer NOT NULL
147
- );
147
+ );
148
+
@@ -0,0 +1,2 @@
1
+ DROP TABLE courses;
2
+
@@ -1,4 +1,5 @@
1
1
  CREATE TABLE courses (
2
2
  id serial,
3
3
  name text
4
- );
4
+ );
5
+
@@ -0,0 +1,18 @@
1
+ DROP TABLE accounts;
2
+ DROP TABLE companies;
3
+ DROP TABLE topics;
4
+ DROP TABLE developers;
5
+ DROP TABLE projects;
6
+ DROP TABLE developers_projects;
7
+ DROP TABLE customers;
8
+ DROP TABLE movies;
9
+ DROP TABLE subscribers;
10
+ DROP TABLE booleantests;
11
+ DROP TABLE auto_id_tests;
12
+ DROP TABLE entrants;
13
+ DROP TABLE colnametests;
14
+ DROP TABLE mixins;
15
+ DROP TABLE people;
16
+ DROP TABLE binaries;
17
+ DROP TABLE computers;
18
+
@@ -113,4 +113,5 @@ CREATE TABLE 'binaries' (
113
113
  CREATE TABLE 'computers' (
114
114
  'id' INTEGER NOT NULL PRIMARY KEY,
115
115
  'developer' INTEGER NOT NULL
116
- );
116
+ );
117
+
@@ -0,0 +1,2 @@
1
+ DROP TABLE courses;
2
+
@@ -2,3 +2,4 @@ CREATE TABLE 'courses' (
2
2
  'id' INTEGER NOT NULL PRIMARY KEY,
3
3
  'name' VARCHAR(255) NOT NULL
4
4
  );
5
+
@@ -0,0 +1,18 @@
1
+ DROP TABLE accounts;
2
+ DROP TABLE companies;
3
+ DROP TABLE topics;
4
+ DROP TABLE developers;
5
+ DROP TABLE projects;
6
+ DROP TABLE developers_projects;
7
+ DROP TABLE customers;
8
+ DROP TABLE movies;
9
+ DROP TABLE subscribers;
10
+ DROP TABLE booleantests;
11
+ DROP TABLE auto_id_tests;
12
+ DROP TABLE entrants;
13
+ DROP TABLE colnametests;
14
+ DROP TABLE mixins;
15
+ DROP TABLE people;
16
+ DROP TABLE binaries;
17
+ DROP TABLE computers;
18
+
@@ -127,3 +127,4 @@ CREATE TABLE computers (
127
127
  developer int NOT NULL,
128
128
  PRIMARY KEY (id)
129
129
  );
130
+
@@ -0,0 +1,2 @@
1
+ DROP TABLE courses;
2
+
@@ -2,3 +2,4 @@ CREATE TABLE courses (
2
2
  id int NOT NULL PRIMARY KEY,
3
3
  name varchar(255) NOT NULL
4
4
  );
5
+
@@ -3,9 +3,9 @@ first:
3
3
  title: The First Topic
4
4
  author_name: David
5
5
  author_email_address: david@loudthinking.com
6
- written_on: 2003-07-16 15:28:00
7
- bonus_time: '12:13:14'
6
+ written_on: 2003-07-16t15:28:00.00+01:00
8
7
  last_read: 2004-04-15
8
+ bonus_time: 2005-01-30t15:28:00.00+01:00
9
9
  content: Have a nice day
10
10
  approved: 0
11
11
  replies_count: 0
@@ -14,7 +14,7 @@ second:
14
14
  id: 2
15
15
  title: The Second Topic's of the day
16
16
  author_name: Mary
17
- written_on: 2003-07-15 15:28:00
17
+ written_on: 2003-07-15t15:28:00.00+01:00
18
18
  content: Have a nice day
19
19
  approved: 1
20
20
  replies_count: 2
@@ -1,4 +1,3 @@
1
- # require File.dirname(__FILE__) + '/../dev-utils/eval_debugger'
2
1
  require 'abstract_unit'
3
2
  require 'fixtures/topic'
4
3
  require 'fixtures/developer'
@@ -1,5 +1,4 @@
1
1
  require 'abstract_unit'
2
- # require File.dirname(__FILE__) + '/../dev-utils/eval_debugger'
3
2
  require 'fixtures/company_in_module'
4
3
 
5
4
  class ModulesTest < Test::Unit::TestCase
@@ -1,4 +1,3 @@
1
- #require File.dirname(__FILE__) + '/../dev-utils/eval_debugger'
2
1
  require 'abstract_unit'
3
2
  require 'fixtures/topic'
4
3
  require 'fixtures/customer'
@@ -6,9 +6,10 @@ require 'fixtures/developer'
6
6
  class ValidationsTest < Test::Unit::TestCase
7
7
  fixtures :topics, :developers
8
8
 
9
- def teardown
10
- Topic.write_inheritable_attribute("validate", [])
11
- Topic.write_inheritable_attribute("validate_on_create", [])
9
+ def setup
10
+ Topic.write_inheritable_attribute(:validate, nil)
11
+ Topic.write_inheritable_attribute(:validate_on_create, nil)
12
+ Topic.write_inheritable_attribute(:validate_on_update, nil)
12
13
  end
13
14
 
14
15
  def test_single_field_validation
@@ -19,7 +20,7 @@ class ValidationsTest < Test::Unit::TestCase
19
20
  r.content = "Messa content!"
20
21
  assert r.save, "A reply with content should be saveable"
21
22
  end
22
-
23
+
23
24
  def test_single_attr_validation_and_error_msg
24
25
  r = Reply.new
25
26
  r.title = "There's no content!"
@@ -41,7 +42,7 @@ class ValidationsTest < Test::Unit::TestCase
41
42
 
42
43
  assert_equal 2, r.errors.count
43
44
  end
44
-
45
+
45
46
  def test_error_on_create
46
47
  r = Reply.new
47
48
  r.title = "Wrong Create"
@@ -50,57 +51,55 @@ class ValidationsTest < Test::Unit::TestCase
50
51
  assert_equal "is Wrong Create", r.errors.on("title"), "A reply with a bad content should contain an error"
51
52
  end
52
53
 
53
-
54
54
  def test_error_on_update
55
55
  r = Reply.new
56
56
  r.title = "Bad"
57
57
  r.content = "Good"
58
-
59
58
  assert r.save, "First save should be successful"
60
-
59
+
61
60
  r.title = "Wrong Update"
62
61
  assert !r.save, "Second save should fail"
63
-
62
+
64
63
  assert r.errors.invalid?("title"), "A reply with a bad title should mark that attribute as invalid"
65
64
  assert_equal "is Wrong Update", r.errors.on("title"), "A reply with a bad content should contain an error"
66
65
  end
67
-
66
+
68
67
  def test_single_error_per_attr_iteration
69
68
  r = Reply.new
70
69
  r.save
71
-
70
+
72
71
  errors = []
73
72
  r.errors.each { |attr, msg| errors << [attr, msg] }
74
-
73
+
75
74
  assert errors.include?(["title", "Empty"])
76
75
  assert errors.include?(["content", "Empty"])
77
76
  end
78
-
77
+
79
78
  def test_multiple_errors_per_attr_iteration_with_full_error_composition
80
79
  r = Reply.new
81
80
  r.title = "Wrong Create"
82
81
  r.content = "Mismatch"
83
82
  r.save
84
-
83
+
85
84
  errors = []
86
85
  r.errors.each_full { |error| errors << error }
87
-
86
+
88
87
  assert_equal "Title is Wrong Create", errors[0]
89
88
  assert_equal "Title is Content Mismatch", errors[1]
90
89
  assert_equal 2, r.errors.count
91
90
  end
92
-
91
+
93
92
  def test_errors_on_base
94
93
  r = Reply.new
95
94
  r.content = "Mismatch"
96
95
  r.save
97
96
  r.errors.add_to_base "Reply is not dignifying"
98
-
97
+
99
98
  errors = []
100
99
  r.errors.each_full { |error| errors << error }
101
-
100
+
102
101
  assert_equal "Reply is not dignifying", r.errors.on_base
103
-
102
+
104
103
  assert errors.include?("Title Empty")
105
104
  assert errors.include?("Reply is not dignifying")
106
105
  assert_equal 2, r.errors.count
@@ -111,12 +110,30 @@ class ValidationsTest < Test::Unit::TestCase
111
110
  assert !reply.save
112
111
  assert reply.save(false)
113
112
  end
114
-
113
+
114
+ def test_validates_each
115
+ perform = true
116
+ hits = 0
117
+ Topic.validates_each(:title, :content, [:title, :content]) do |record, attr|
118
+ if perform
119
+ record.errors.add attr, 'gotcha'
120
+ hits += 1
121
+ end
122
+ end
123
+ t = Topic.new("title" => "valid", "content" => "whatever")
124
+ assert !t.save
125
+ assert_equal 4, hits
126
+ assert_equal %w(gotcha gotcha), t.errors.on(:title)
127
+ assert_equal %w(gotcha gotcha), t.errors.on(:content)
128
+ ensure
129
+ perform = false
130
+ end
131
+
115
132
  def test_errors_on_boundary_breaking
116
133
  developer = Developer.new("name" => "xs")
117
134
  assert !developer.save
118
135
  assert_equal "is too short (min is 3 characters)", developer.errors.on("name")
119
-
136
+
120
137
  developer.name = "All too very long for this boundary, it really is"
121
138
  assert !developer.save
122
139
  assert_equal "is too long (max is 20 characters)", developer.errors.on("name")
@@ -127,11 +144,11 @@ class ValidationsTest < Test::Unit::TestCase
127
144
 
128
145
  def test_title_confirmation_no_confirm
129
146
  Topic.validates_confirmation_of(:title)
130
-
147
+
131
148
  t = Topic.create("title" => "We should not be confirmed")
132
149
  assert t.save
133
150
  end
134
-
151
+
135
152
  def test_title_confirmation
136
153
  Topic.validates_confirmation_of(:title)
137
154
 
@@ -171,7 +188,7 @@ class ValidationsTest < Test::Unit::TestCase
171
188
  t.eula = "1"
172
189
  assert t.save
173
190
  end
174
-
191
+
175
192
  def test_validate_presences
176
193
  Topic.validates_presence_of(:title, :content)
177
194
 
@@ -179,16 +196,16 @@ class ValidationsTest < Test::Unit::TestCase
179
196
  assert !t.save
180
197
  assert_equal "can't be empty", t.errors.on(:title)
181
198
  assert_equal "can't be empty", t.errors.on(:content)
182
-
199
+
183
200
  t.title = "something"
184
201
  t.content = "another"
185
-
202
+
186
203
  assert t.save
187
204
  end
188
-
205
+
189
206
  def test_validate_uniqueness
190
207
  Topic.validates_uniqueness_of(:title)
191
-
208
+
192
209
  t = Topic.new("title" => "I'm unique!")
193
210
  assert t.save, "Should save t as unique"
194
211
 
@@ -199,14 +216,14 @@ class ValidationsTest < Test::Unit::TestCase
199
216
  assert !t2.valid?, "Shouldn't be valid"
200
217
  assert !t2.save, "Shouldn't save t2 as unique"
201
218
  assert_equal "has already been taken", t2.errors.on(:title)
202
-
219
+
203
220
  t2.title = "Now Im really also unique"
204
221
  assert t2.save, "Should now save t2 as unique"
205
222
  end
206
223
 
207
224
  def test_validate_uniqueness_with_scope
208
225
  Reply.validates_uniqueness_of(:content, :scope => "parent_id")
209
-
226
+
210
227
  t = Topic.create("title" => "I'm unique!")
211
228
 
212
229
  r1 = t.replies.create "title" => "r1", "content" => "hello world"
@@ -246,8 +263,7 @@ class ValidationsTest < Test::Unit::TestCase
246
263
  assert !Topic.create("title" => "a!", "content" => "abc").valid?
247
264
  assert !Topic.create("title" => "a b", "content" => "abc").valid?
248
265
  assert !Topic.create("title" => nil, "content" => "def").valid?
249
- assert !Topic.create("title" => %w(a b c), "content" => "def").valid?
250
-
266
+
251
267
  t = Topic.create("title" => "a", "content" => "I know you are but what am I?")
252
268
  assert t.valid?
253
269
  t.title = "uhoh"
@@ -272,32 +288,61 @@ class ValidationsTest < Test::Unit::TestCase
272
288
  end
273
289
 
274
290
  def test_validates_length_of_using_minimum
275
- Topic.validates_length_of( :title, :minimum=>5 )
291
+ Topic.validates_length_of :title, :minimum => 5
292
+
276
293
  t = Topic.create("title" => "valid", "content" => "whatever")
277
294
  assert t.valid?
295
+
278
296
  t.title = "not"
279
297
  assert !t.valid?
280
298
  assert t.errors.on(:title)
281
299
  assert_equal "is too short (min is 5 characters)", t.errors["title"]
300
+
282
301
  t.title = ""
283
302
  assert !t.valid?
284
303
  assert t.errors.on(:title)
304
+ assert_equal "is too short (min is 5 characters)", t.errors["title"]
305
+
285
306
  t.title = nil
286
307
  assert !t.valid?
287
- assert_equal "is too short (min is 5 characters)", t.errors["title"]
288
308
  assert t.errors.on(:title)
309
+ assert_equal "is too short (min is 5 characters)", t.errors["title"]
310
+ end
311
+
312
+ def test_optionally_validates_length_of_using_minimum
313
+ Topic.validates_length_of :title, :minimum => 5, :allow_nil => true
314
+
315
+ t = Topic.create("title" => "valid", "content" => "whatever")
316
+ assert t.valid?
317
+
318
+ t.title = nil
319
+ assert t.valid?
289
320
  end
290
-
321
+
291
322
  def test_validates_length_of_using_maximum
292
- Topic.validates_length_of( :title, :maximum=>5 )
323
+ Topic.validates_length_of :title, :maximum => 5
324
+
293
325
  t = Topic.create("title" => "valid", "content" => "whatever")
294
326
  assert t.valid?
327
+
295
328
  t.title = "notvalid"
296
329
  assert !t.valid?
297
330
  assert t.errors.on(:title)
298
331
  assert_equal "is too long (max is 5 characters)", t.errors["title"]
332
+
299
333
  t.title = ""
300
334
  assert t.valid?
335
+
336
+ t.title = nil
337
+ assert !t.valid?
338
+ end
339
+
340
+ def test_optionally_validates_length_of_using_maximum
341
+ Topic.validates_length_of :title, :maximum => 5, :allow_nil => true
342
+
343
+ t = Topic.create("title" => "valid", "content" => "whatever")
344
+ assert t.valid?
345
+
301
346
  t.title = nil
302
347
  assert t.valid?
303
348
  end
@@ -307,29 +352,75 @@ class ValidationsTest < Test::Unit::TestCase
307
352
 
308
353
  t = Topic.create("title" => "a!", "content" => "I'm ooooooooh so very long")
309
354
  assert !t.save
355
+
310
356
  assert_equal "is too short (min is 3 characters)", t.errors.on(:title)
311
357
  assert_equal "is too long (max is 5 characters)", t.errors.on(:content)
312
358
 
313
359
  t.title = "abe"
314
360
  t.content = "mad"
315
-
316
361
  assert t.save
317
362
  end
318
363
 
364
+ def test_optionally_validates_length_of_using_within
365
+ Topic.validates_length_of :title, :content, :within => 3..5, :allow_nil => true
366
+
367
+ t = Topic.create('title' => 'abc', 'content' => 'abcd')
368
+ assert t.valid?
369
+
370
+ t.title = nil
371
+ assert t.valid?
372
+ end
373
+
319
374
  def test_validates_length_of_using_is
320
- Topic.validates_length_of( :title, :is=>5 )
375
+ Topic.validates_length_of :title, :is => 5
376
+
321
377
  t = Topic.create("title" => "valid", "content" => "whatever")
322
378
  assert t.valid?
379
+
323
380
  t.title = "notvalid"
324
381
  assert !t.valid?
325
382
  assert t.errors.on(:title)
326
383
  assert_equal "is the wrong length (should be 5 characters)", t.errors["title"]
384
+
327
385
  t.title = ""
328
386
  assert !t.valid?
387
+
329
388
  t.title = nil
330
389
  assert !t.valid?
331
390
  end
332
391
 
392
+ def test_optionally_validates_length_of_using_is
393
+ Topic.validates_length_of :title, :is => 5, :allow_nil => true
394
+
395
+ t = Topic.create("title" => "valid", "content" => "whatever")
396
+ assert t.valid?
397
+
398
+ t.title = nil
399
+ assert t.valid?
400
+ end
401
+
402
+ def test_validates_length_of_using_bignum
403
+ bigmin = 2 ** 30
404
+ bigmax = 2 ** 32
405
+ bigrange = bigmin...bigmax
406
+ assert_nothing_raised do
407
+ Topic.validates_length_of :title, :is => bigmin + 5
408
+ Topic.validates_length_of :title, :within => bigrange
409
+ Topic.validates_length_of :title, :in => bigrange
410
+ Topic.validates_length_of :title, :minimum => bigmin
411
+ Topic.validates_length_of :title, :maximum => bigmax
412
+ end
413
+ end
414
+
415
+ def test_validates_size_of_association
416
+ assert_nothing_raised { Topic.validates_size_of :replies, :minimum => 1 }
417
+ t = Topic.new('title' => 'noreplies', 'content' => 'whatever')
418
+ assert !t.save
419
+ assert t.errors.on(:replies)
420
+ t.replies.create('title' => 'areply', 'content' => 'whateveragain')
421
+ assert t.valid?
422
+ end
423
+
333
424
  def test_validates_length_of_nasty_params
334
425
  assert_raise(ArgumentError) { Topic.validates_length_of(:title, :minimum=>6, :maximum=>9) }
335
426
  assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>6, :maximum=>9) }
@@ -372,7 +463,7 @@ class ValidationsTest < Test::Unit::TestCase
372
463
  assert t.errors.on(:title)
373
464
  assert_equal "hoo 5", t.errors["title"]
374
465
  end
375
-
466
+
376
467
  def test_validates_length_of_custom_errors_for_is_with_message
377
468
  Topic.validates_length_of( :title, :is=>5, :message=>"boo %d" )
378
469
  t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
@@ -392,10 +483,12 @@ class ValidationsTest < Test::Unit::TestCase
392
483
  def test_validates_associated_many
393
484
  Topic.validates_associated( :replies )
394
485
  t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
395
- t.replies << [r = Reply.create("title" => "A reply"), Reply.create("title" => "Another reply", "content" => "with content!")]
486
+ t.replies << [r = Reply.create("title" => "A reply"), r2 = Reply.create("title" => "Another reply")]
396
487
  assert !t.valid?
397
488
  assert t.errors.on(:replies)
398
- r.content = "non-empty"
489
+ assert_equal 1, r.errors.count # make sure all associated objects have been validated
490
+ assert_equal 1, r2.errors.count
491
+ r.content = r2.content = "non-empty"
399
492
  assert t.valid?
400
493
  end
401
494
 
@@ -410,10 +503,105 @@ class ValidationsTest < Test::Unit::TestCase
410
503
  assert r.valid?
411
504
  end
412
505
 
506
+ def test_validate_block
507
+ Topic.validate { |topic| topic.errors.add("title", "will never be valid") }
508
+ t = Topic.create("title" => "Title", "content" => "whatever")
509
+ assert !t.valid?
510
+ assert t.errors.on(:title)
511
+ assert_equal "will never be valid", t.errors["title"]
512
+ end
513
+
514
+ def test_invalid_validator
515
+ Topic.validate 3
516
+ assert_raise(ActiveRecord::ActiveRecordError) { t = Topic.create }
517
+ end
518
+
413
519
  def test_throw_away_typing
414
520
  d = Developer.create "name" => "David", "salary" => "100,000"
415
521
  assert !d.valid?
416
522
  assert_equal 100, d.salary
417
523
  assert_equal "100,000", d.salary_before_type_cast
418
524
  end
525
+
526
+ def test_validates_acceptance_of_with_custom_error_using_quotes
527
+ Developer.validates_acceptance_of :salary, :message=> "This string contains 'single' and \"double\" quotes"
528
+ d = Developer.new
529
+ d.salary = "0"
530
+ assert !d.valid?
531
+ assert_equal d.errors.on(:salary).first, "This string contains 'single' and \"double\" quotes"
532
+ end
533
+
534
+ def test_validates_confirmation_of_with_custom_error_using_quotes
535
+ Developer.validates_confirmation_of :name, :message=> "This string contains 'single' and \"double\" quotes"
536
+ d = Developer.new
537
+ d.name = "John"
538
+ d.name_confirmation = "Johnny"
539
+ assert !d.valid?
540
+ assert_equal d.errors.on(:name), "This string contains 'single' and \"double\" quotes"
541
+ end
542
+
543
+ def test_validates_format_of_with_custom_error_using_quotes
544
+ Developer.validates_format_of :name, :with => /^(A-Z*)$/, :message=> "This string contains 'single' and \"double\" quotes"
545
+ d = Developer.new
546
+ d.name = "John 32"
547
+ assert !d.valid?
548
+ assert_equal d.errors.on(:name), "This string contains 'single' and \"double\" quotes"
549
+ end
550
+
551
+ def test_validates_inclusion_of_with_custom_error_using_quotes
552
+ Developer.validates_inclusion_of :salary, :in => 1000..80000, :message=> "This string contains 'single' and \"double\" quotes"
553
+ d = Developer.new
554
+ d.salary = "90,000"
555
+ assert !d.valid?
556
+ assert_equal d.errors.on(:salary).first, "This string contains 'single' and \"double\" quotes"
557
+ end
558
+
559
+ def test_validates_length_of_with_custom_too_long_using_quotes
560
+ Developer.validates_length_of :name, :maximum => 4, :too_long=> "This string contains 'single' and \"double\" quotes"
561
+ d = Developer.new
562
+ d.name = "Jeffrey"
563
+ assert !d.valid?
564
+ assert_equal d.errors.on(:name).first, "This string contains 'single' and \"double\" quotes"
565
+ end
566
+
567
+ def test_validates_length_of_with_custom_too_short_using_quotes
568
+ Developer.validates_length_of :name, :minimum => 4, :too_short=> "This string contains 'single' and \"double\" quotes"
569
+ d = Developer.new
570
+ d.name = "Joe"
571
+ assert !d.valid?
572
+ assert_equal d.errors.on(:name).first, "This string contains 'single' and \"double\" quotes"
573
+ end
574
+
575
+ def test_validates_length_of_with_custom_message_using_quotes
576
+ Developer.validates_length_of :name, :minimum => 4, :message=> "This string contains 'single' and \"double\" quotes"
577
+ d = Developer.new
578
+ d.name = "Joe"
579
+ assert !d.valid?
580
+ assert_equal d.errors.on(:name).first, "This string contains 'single' and \"double\" quotes"
581
+ end
582
+
583
+ def test_validates_presence_of_with_custom_message_using_quotes
584
+ Developer.validates_presence_of :non_existent, :message=> "This string contains 'single' and \"double\" quotes"
585
+ d = Developer.new
586
+ d.name = "Joe"
587
+ assert !d.valid?
588
+ assert_equal d.errors.on(:non_existent), "This string contains 'single' and \"double\" quotes"
589
+ end
590
+
591
+ def test_validates_uniqueness_of_with_custom_message_using_quotes
592
+ Developer.validates_uniqueness_of :name, :message=> "This string contains 'single' and \"double\" quotes"
593
+ d = Developer.new
594
+ d.name = "David"
595
+ assert !d.valid?
596
+ assert_equal d.errors.on(:name).first, "This string contains 'single' and \"double\" quotes"
597
+ end
598
+
599
+ def test_validates_associated_with_custom_message_using_quotes
600
+ Reply.validates_associated :topic, :message=> "This string contains 'single' and \"double\" quotes"
601
+ Topic.validates_presence_of :content
602
+ r = Reply.create("title" => "A reply", "content" => "with content!")
603
+ r.topic = Topic.create("title" => "uhohuhoh")
604
+ assert !r.valid?
605
+ assert_equal r.errors.on(:topic).first, "This string contains 'single' and \"double\" quotes"
606
+ end
419
607
  end