activerecord 1.0.0 → 1.1.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 (47) hide show
  1. data/CHANGELOG +102 -1
  2. data/dev-utils/eval_debugger.rb +12 -7
  3. data/lib/active_record.rb +2 -0
  4. data/lib/active_record/aggregations.rb +1 -1
  5. data/lib/active_record/associations.rb +74 -53
  6. data/lib/active_record/associations.rb.orig +555 -0
  7. data/lib/active_record/associations/association_collection.rb +74 -15
  8. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +86 -25
  9. data/lib/active_record/associations/has_many_association.rb +48 -50
  10. data/lib/active_record/base.rb +56 -24
  11. data/lib/active_record/connection_adapters/abstract_adapter.rb +46 -3
  12. data/lib/active_record/connection_adapters/mysql_adapter.rb +15 -15
  13. data/lib/active_record/connection_adapters/postgresql_adapter.rb +128 -135
  14. data/lib/active_record/connection_adapters/sqlite_adapter.rb +76 -78
  15. data/lib/active_record/deprecated_associations.rb +1 -1
  16. data/lib/active_record/fixtures.rb +137 -54
  17. data/lib/active_record/observer.rb +1 -1
  18. data/lib/active_record/support/inflector.rb +8 -0
  19. data/lib/active_record/transactions.rb +31 -14
  20. data/rakefile +13 -5
  21. data/test/abstract_unit.rb +7 -1
  22. data/test/associations_test.rb +99 -27
  23. data/test/base_test.rb +15 -1
  24. data/test/connections/native_sqlite/connection.rb +24 -14
  25. data/test/deprecated_associations_test.rb +3 -4
  26. data/test/deprecated_associations_test.rb.orig +334 -0
  27. data/test/fixtures/bad_fixtures/attr_with_numeric_first_char +1 -0
  28. data/test/fixtures/bad_fixtures/attr_with_spaces +1 -0
  29. data/test/fixtures/bad_fixtures/blank_line +3 -0
  30. data/test/fixtures/bad_fixtures/duplicate_attributes +3 -0
  31. data/test/fixtures/bad_fixtures/missing_value +1 -0
  32. data/test/fixtures/company_in_module.rb +15 -1
  33. data/test/fixtures/db_definitions/mysql.sql +2 -1
  34. data/test/fixtures/db_definitions/postgresql.sql +2 -1
  35. data/test/fixtures/db_definitions/sqlite.sql +2 -1
  36. data/test/fixtures/developers_projects/david_action_controller +2 -1
  37. data/test/fixtures/developers_projects/david_active_record +2 -1
  38. data/test/fixtures/fixture_database.sqlite +0 -0
  39. data/test/fixtures/fixture_database_2.sqlite +0 -0
  40. data/test/fixtures/project.rb +2 -1
  41. data/test/fixtures/projects/action_controller +1 -1
  42. data/test/fixtures/topics/second +1 -1
  43. data/test/fixtures_test.rb +63 -4
  44. data/test/inflector_test.rb +17 -0
  45. data/test/modules_test.rb +8 -0
  46. data/test/transactions_test.rb +16 -4
  47. metadata +10 -2
@@ -42,7 +42,8 @@ class AssociationsTest < Test::Unit::TestCase
42
42
  end
43
43
 
44
44
  def test_storing_in_pstore
45
- store_filename = "/tmp/ar-pstore-association-test"
45
+ require "tmpdir"
46
+ store_filename = File.join(Dir.tmpdir, "ar-pstore-association-test")
46
47
  File.delete(store_filename) if File.exists?(store_filename)
47
48
  require "pstore"
48
49
  apple = Firm.create("name" => "Apple")
@@ -170,8 +171,9 @@ class HasManyAssociationsTest < Test::Unit::TestCase
170
171
 
171
172
  def test_finding_using_sql
172
173
  firm = Firm.find_first
173
- firm.clients_using_sql.first
174
- assert_equal "Microsoft", firm.clients_using_sql.first.name
174
+ first_client = firm.clients_using_sql.first
175
+ assert_not_nil first_client
176
+ assert_equal "Microsoft", first_client.name
175
177
  assert_equal 1, firm.clients_using_sql.size
176
178
  assert_equal 1, Firm.find_first.clients_using_sql.size
177
179
  end
@@ -181,6 +183,11 @@ class HasManyAssociationsTest < Test::Unit::TestCase
181
183
  assert_equal 1, Firm.find_first.clients.find_all("name = 'Summit'").length
182
184
  end
183
185
 
186
+ def test_find_all_sanitized
187
+ firm = Firm.find_first
188
+ assert_equal firm.clients.find_all("name = 'Summit'"), firm.clients.find_all(["name = '%s'", "Summit"])
189
+ end
190
+
184
191
  def test_find_in_collection
185
192
  assert_equal Client.find(2).name, @signals37.clients.find(2).name
186
193
  assert_equal Client.find(2).name, @signals37.clients.find {|c| c.name == @signals37.clients.find(2).name }.name
@@ -204,7 +211,7 @@ class HasManyAssociationsTest < Test::Unit::TestCase
204
211
 
205
212
  def test_adding_a_collection
206
213
  force_signal37_to_load_all_clients_of_firm
207
- @signals37.clients_of_firm.concat(Client.new("name" => "Natural Company"), Client.new("name" => "Apple"))
214
+ @signals37.clients_of_firm.concat([Client.new("name" => "Natural Company"), Client.new("name" => "Apple")])
208
215
  assert_equal 3, @signals37.clients_of_firm.size
209
216
  assert_equal 3, @signals37.clients_of_firm(true).size
210
217
  end
@@ -234,6 +241,7 @@ class HasManyAssociationsTest < Test::Unit::TestCase
234
241
  force_signal37_to_load_all_clients_of_firm
235
242
  @signals37.clients_of_firm.create("name" => "Another Client")
236
243
  assert_equal 2, @signals37.clients_of_firm.size
244
+ #@signals37.clients_of_firm.clear
237
245
  @signals37.clients_of_firm.delete([@signals37.clients_of_firm[0], @signals37.clients_of_firm[1]])
238
246
  assert_equal 0, @signals37.clients_of_firm.size
239
247
  assert_equal 0, @signals37.clients_of_firm(true).size
@@ -243,7 +251,7 @@ class HasManyAssociationsTest < Test::Unit::TestCase
243
251
  force_signal37_to_load_all_clients_of_firm
244
252
  @signals37.clients_of_firm.create("name" => "Another Client")
245
253
  assert_equal 2, @signals37.clients_of_firm.size
246
- @signals37.clients_of_firm.delete(@signals37.clients_of_firm)
254
+ @signals37.clients_of_firm.clear
247
255
  assert_equal 0, @signals37.clients_of_firm.size
248
256
  assert_equal 0, @signals37.clients_of_firm(true).size
249
257
  end
@@ -257,12 +265,24 @@ class HasManyAssociationsTest < Test::Unit::TestCase
257
265
  assert_equal 2, summit.client_of
258
266
  end
259
267
 
268
+ def test_deleting_type_mismatch
269
+ david = Developer.find(1)
270
+ david.projects.id
271
+ assert_raises(ActiveRecord::AssociationTypeMismatch) { david.projects.delete(1) }
272
+ end
273
+
274
+ def test_deleting_self_type_mismatch
275
+ david = Developer.find(1)
276
+ david.projects.id
277
+ assert_raises(ActiveRecord::AssociationTypeMismatch) { david.projects.delete(Project.find(1).developers) }
278
+ end
279
+
260
280
  def test_destroy_all
261
281
  force_signal37_to_load_all_clients_of_firm
262
- assert !@signals37.clients_of_firm.empty?
282
+ assert !@signals37.clients_of_firm.empty?, "37signals has clients after load"
263
283
  @signals37.clients_of_firm.destroy_all
264
- assert @signals37.clients_of_firm.empty?
265
- assert @signals37.clients_of_firm(true).empty?
284
+ assert @signals37.clients_of_firm.empty?, "37signals has no clients after destroy all"
285
+ assert @signals37.clients_of_firm(true).empty?, "37signals has no clients after destroy all and refresh"
266
286
  end
267
287
 
268
288
  def test_dependence
@@ -291,6 +311,10 @@ class HasManyAssociationsTest < Test::Unit::TestCase
291
311
  def test_included_in_collection
292
312
  assert @signals37.clients.include?(Client.find(2))
293
313
  end
314
+
315
+ def test_adding_array_and_collection
316
+ assert_nothing_raised { Firm.find_first.clients + Firm.find_all.last.clients }
317
+ end
294
318
  end
295
319
 
296
320
  class BelongsToAssociationsTest < Test::Unit::TestCase
@@ -306,8 +330,8 @@ class BelongsToAssociationsTest < Test::Unit::TestCase
306
330
  end
307
331
 
308
332
  def test_type_mismatch
309
- assert_raises(ActiveRecord::AssociationTypeMismatch) { Account.find(1).firm = 1 }
310
- assert_raises(ActiveRecord::AssociationTypeMismatch) { Account.find(1).firm = Project.find(1) }
333
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { Account.find(1).firm = 1 }
334
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { Account.find(1).firm = Project.find(1) }
311
335
  end
312
336
 
313
337
  def test_natural_assignment
@@ -327,12 +351,12 @@ class BelongsToAssociationsTest < Test::Unit::TestCase
327
351
 
328
352
  def test_with_different_class_name
329
353
  assert_equal Company.find(1).name, Company.find(3).firm_with_other_name.name
330
- assert !Company.find(3).firm_with_other_name.empty?, "Microsoft should have a firm"
354
+ assert_not_nil Company.find(3).firm_with_other_name, "Microsoft should have a firm"
331
355
  end
332
356
 
333
357
  def test_with_condition
334
358
  assert_equal Company.find(1).name, Company.find(3).firm_with_condition.name
335
- assert !Company.find(3).firm_with_condition.empty?, "Microsoft should have a firm"
359
+ assert_not_nil Company.find(3).firm_with_condition, "Microsoft should have a firm"
336
360
  end
337
361
 
338
362
  def test_belongs_to_counter
@@ -367,12 +391,9 @@ end
367
391
 
368
392
  class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
369
393
  def setup
370
- create_fixtures "accounts"
371
- create_fixtures "companies"
372
- create_fixtures "accounts"
373
- create_fixtures "developers"
374
- create_fixtures "projects"
375
- create_fixtures "developers_projects"
394
+ @accounts, @companies, @developers, @projects, @developers_projects =
395
+ create_fixtures "accounts", "companies", "developers", "projects", "developers_projects"
396
+
376
397
  @signals37 = Firm.find(1)
377
398
  end
378
399
 
@@ -388,7 +409,7 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
388
409
  assert_equal david.name, active_record.developers.first.name
389
410
  end
390
411
 
391
- def test_addings
412
+ def test_adding_single
392
413
  jamis = Developer.find(2)
393
414
  jamis.projects.id # causing the collection to load
394
415
  action_controller = Project.find(2)
@@ -404,8 +425,8 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
404
425
 
405
426
  def test_adding_type_mismatch
406
427
  jamis = Developer.find(2)
407
- assert_raises(ActiveRecord::AssociationTypeMismatch) { jamis.projects << nil }
408
- assert_raises(ActiveRecord::AssociationTypeMismatch) { jamis.projects << 1 }
428
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { jamis.projects << nil }
429
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { jamis.projects << 1 }
409
430
  end
410
431
 
411
432
  def test_adding_from_the_project
@@ -422,15 +443,37 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
422
443
  assert_equal 2, action_controller.developers(true).size
423
444
  end
424
445
 
446
+ def test_adding_multiple
447
+ aridridel = Developer.new("name" => "Aridridel")
448
+ aridridel.save
449
+ aridridel.projects.id
450
+ aridridel.projects.push(Project.find(1), Project.find(2))
451
+ assert_equal 2, aridridel.projects.size
452
+ assert_equal 2, aridridel.projects(true).size
453
+ end
454
+
425
455
  def test_adding_a_collection
426
456
  aridridel = Developer.new("name" => "Aridridel")
427
457
  aridridel.save
428
458
  aridridel.projects.id
429
- aridridel.projects.concat([ Project.find(1), Project.find(2) ])
459
+ aridridel.projects.concat([Project.find(1), Project.find(2)])
430
460
  assert_equal 2, aridridel.projects.size
431
461
  assert_equal 2, aridridel.projects(true).size
432
462
  end
433
463
 
464
+ def test_uniq_after_the_fact
465
+ @developers["jamis"].find.projects << @projects["active_record"].find
466
+ @developers["jamis"].find.projects << @projects["active_record"].find
467
+ assert_equal 3, @developers["jamis"].find.projects.size
468
+ assert_equal 1, @developers["jamis"].find.projects.uniq.size
469
+ end
470
+
471
+ def test_uniq_before_the_fact
472
+ @projects["active_record"].find.developers << @developers["jamis"].find
473
+ @projects["active_record"].find.developers << @developers["david"].find
474
+ assert_equal 2, @projects["active_record"].find.developers.size
475
+ end
476
+
434
477
  def test_deleting
435
478
  david = Developer.find(1)
436
479
  active_record = Project.find(1)
@@ -445,18 +488,18 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
445
488
  assert_equal 1, active_record.developers(true).size
446
489
  end
447
490
 
448
- def test_deleting_a_collection
491
+ def test_deleting_array
449
492
  david = Developer.find(1)
450
493
  david.projects.id
451
494
  david.projects.delete(Project.find_all)
452
495
  assert_equal 0, david.projects.size
453
496
  assert_equal 0, david.projects(true).size
454
497
  end
455
-
456
- def test_deleting_a_association_collection
498
+
499
+ def test_deleting_all
457
500
  david = Developer.find(1)
458
501
  david.projects.id
459
- david.projects.delete(david.projects)
502
+ david.projects.clear
460
503
  assert_equal 0, david.projects.size
461
504
  assert_equal 0, david.projects(true).size
462
505
  end
@@ -466,6 +509,10 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
466
509
  assert Developer.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = '1'").empty?
467
510
  end
468
511
 
512
+ def test_additional_columns_from_join_table
513
+ assert_equal Date.new(2004, 10, 10).to_s, Developer.find(1).projects.first.joined_on.to_s
514
+ end
515
+
469
516
  def test_destroy_all
470
517
  david = Developer.find(1)
471
518
  david.projects.id
@@ -474,4 +521,29 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
474
521
  assert david.projects.empty?
475
522
  assert david.projects(true).empty?
476
523
  end
477
- end
524
+
525
+ def test_rich_association
526
+ @jamis = @developers["jamis"].find
527
+ @jamis.projects.push_with_attributes(@projects["action_controller"].find, :joined_on => Date.today)
528
+ assert_equal Date.today.to_s, @jamis.projects.select { |p| p.name == @projects["action_controller"]["name"] }.first.joined_on.to_s
529
+ assert_equal Date.today.to_s, @developers["jamis"].find.projects.select { |p| p.name == @projects["action_controller"]["name"] }.first.joined_on.to_s
530
+ end
531
+
532
+ def test_associations_with_conditions
533
+ assert_equal 2, @projects["active_record"].find.developers.size
534
+ assert_equal 1, @projects["active_record"].find.developers_named_david.size
535
+
536
+ @projects["active_record"].find.developers_named_david.clear
537
+ assert_equal 1, @projects["active_record"].find.developers.size
538
+ end
539
+
540
+ def test_find_in_association
541
+ # Using sql
542
+ assert_equal @developers["david"].find, @projects["active_record"].find.developers.find(@developers["david"]["id"]), "SQL find"
543
+
544
+ # Using ruby
545
+ @active_record = @projects["active_record"].find
546
+ @active_record.developers.reload
547
+ assert_equal @developers["david"].find, @active_record.developers.find(@developers["david"]["id"]), "Ruby find"
548
+ end
549
+ end
@@ -59,9 +59,13 @@ class BasicsTest < Test::Unit::TestCase
59
59
  assert topic.respond_to?("title")
60
60
  assert topic.respond_to?("title?")
61
61
  assert topic.respond_to?("title=")
62
+ assert topic.respond_to?(:title)
63
+ assert topic.respond_to?(:title?)
64
+ assert topic.respond_to?(:title=)
62
65
  assert topic.respond_to?("author_name")
63
66
  assert topic.respond_to?("attribute_names")
64
67
  assert !topic.respond_to?("nothingness")
68
+ assert !topic.respond_to?(:nothingness)
65
69
  end
66
70
 
67
71
  def test_array_content
@@ -325,6 +329,10 @@ class BasicsTest < Test::Unit::TestCase
325
329
  assert_equal Topic.find(1), Topic.find(2).parent
326
330
  end
327
331
 
332
+ def test_hashing
333
+ assert_equal [ Topic.find(1) ], [ Topic.find(2).parent ] & [ Topic.find(1) ]
334
+ end
335
+
328
336
  def test_destroy_new_record
329
337
  client = Client.new
330
338
  client.destroy
@@ -510,4 +518,10 @@ class BasicsTest < Test::Unit::TestCase
510
518
  assert_equal(settings, Topic.find(topic.id).content)
511
519
  Topic.serialize(:content)
512
520
  end
513
- end
521
+
522
+ def test_quote
523
+ content = "\\ \001 ' \n \\n \""
524
+ topic = Topic.create('content' => content)
525
+ assert_equal content, Topic.find(topic.id).content
526
+ end
527
+ end
@@ -3,22 +3,32 @@ require 'fixtures/course'
3
3
  require 'logger'
4
4
  ActiveRecord::Base.logger = Logger.new("debug.log")
5
5
 
6
- base = "#{File.dirname(__FILE__)}/../../fixtures"
7
- sqlite_test_db = "#{base}/fixture_database.sqlite"
8
- sqlite_test_db2 = "#{base}/fixture_database_2.sqlite"
6
+ BASE_DIR = File.expand_path(File.dirname(__FILE__) + '/../../fixtures')
7
+ sqlite_test_db = "#{BASE_DIR}/fixture_database.sqlite"
8
+ sqlite_test_db2 = "#{BASE_DIR}/fixture_database_2.sqlite"
9
9
 
10
- [sqlite_test_db, sqlite_test_db2].each do |db|
11
- unless File.exist?(db) and File.size(db) > 0
12
- puts "*** You must create the SQLite test database in: #{db} ***"
13
- exit!
10
+ def make_connection(clazz, db_file, db_definitions_file)
11
+ unless File.exist?(db_file)
12
+ puts "SQLite database not found at #{db_file}. Rebuilding it."
13
+ sqlite_command = "sqlite #{db_file} 'create table a (a integer); drop table a;'"
14
+ puts "Executing '#{sqlite_command}'"
15
+ `#{sqlite_command}`
16
+ clazz.establish_connection(
17
+ :adapter => "sqlite",
18
+ :dbfile => db_file)
19
+ script = File.read("#{BASE_DIR}/db_definitions/#{db_definitions_file}")
20
+ # SQLite-Ruby has problems with semi-colon separated commands, so split and execute one at a time
21
+ script.split(';').each do
22
+ |command|
23
+ clazz.connection.execute(command) unless command.strip.empty?
24
+ end
14
25
  else
15
- puts "OK: #{db}"
26
+ clazz.establish_connection(
27
+ :adapter => "sqlite",
28
+ :dbfile => db_file)
16
29
  end
17
30
  end
18
31
 
19
- ActiveRecord::Base.establish_connection(
20
- :adapter => "sqlite",
21
- :dbfile => sqlite_test_db)
22
- Course.establish_connection(
23
- :adapter => "sqlite",
24
- :dbfile => sqlite_test_db2)
32
+ make_connection(ActiveRecord::Base, sqlite_test_db, 'sqlite.sql')
33
+ make_connection(Course, sqlite_test_db2, 'sqlite2.sql')
34
+
@@ -99,13 +99,11 @@ class DeprecatedAssociationsTest < Test::Unit::TestCase
99
99
  def test_belongs_to_with_different_class_name
100
100
  assert_equal Company.find(1).name, Company.find(3).firm_with_other_name.name
101
101
  assert Company.find(3).has_firm_with_other_name?, "Microsoft should have a firm"
102
- assert !Company.find(1).has_firm_with_other_name?, "37signals shouldn't have a firm"
103
102
  end
104
103
 
105
104
  def test_belongs_to_with_condition
106
105
  assert_equal Company.find(1).name, Company.find(3).firm_with_condition.name
107
106
  assert Company.find(3).has_firm_with_condition?, "Microsoft should have a firm"
108
- assert !Company.find(1).has_firm_with_condition?, "37signals shouldn't have a firm"
109
107
  end
110
108
 
111
109
 
@@ -314,16 +312,17 @@ class DeprecatedAssociationsTest < Test::Unit::TestCase
314
312
 
315
313
  def test_storing_in_pstore
316
314
  require "pstore"
315
+ require "tmpdir"
317
316
  apple = Firm.create("name" => "Apple")
318
317
  natural = Client.new("name" => "Natural Company")
319
318
  apple.clients << natural
320
319
 
321
- db = PStore.new("/tmp/ar-pstore-association-test")
320
+ db = PStore.new(File.join(Dir.tmpdir, "ar-pstore-association-test"))
322
321
  db.transaction do
323
322
  db["apple"] = apple
324
323
  end
325
324
 
326
- db = PStore.new("/tmp/ar-pstore-association-test")
325
+ db = PStore.new(File.join(Dir.tmpdir, "ar-pstore-association-test"))
327
326
  db.transaction do
328
327
  assert_equal "Natural Company", db["apple"].clients.first.name
329
328
  end
@@ -0,0 +1,334 @@
1
+ require 'abstract_unit'
2
+ require 'fixtures/developer'
3
+ require 'fixtures/project'
4
+ require 'fixtures/company'
5
+ require 'fixtures/topic'
6
+ # require File.dirname(__FILE__) + '/../dev-utils/eval_debugger'
7
+ require 'fixtures/reply'
8
+
9
+ # Can't declare new classes in test case methods, so tests before that
10
+ bad_collection_keys = false
11
+ begin
12
+ class Car < ActiveRecord::Base; has_many :wheels, :name => "wheels"; end
13
+ rescue ActiveRecord::ActiveRecordError
14
+ bad_collection_keys = true
15
+ end
16
+ raise "ActiveRecord should have barked on bad collection keys" unless bad_collection_keys
17
+
18
+
19
+ class DeprecatedAssociationsTest < Test::Unit::TestCase
20
+ def setup
21
+ create_fixtures "accounts", "companies", "accounts", "developers", "projects", "developers_projects", "topics"
22
+ @signals37 = Firm.find(1)
23
+ end
24
+
25
+ def test_has_many_find
26
+ assert_equal 2, Firm.find_first.clients.length
27
+ end
28
+
29
+ def test_has_many_orders
30
+ assert_equal "Summit", Firm.find_first.clients.first.name
31
+ end
32
+
33
+ def test_has_many_class_name
34
+ assert_equal "Microsoft", Firm.find_first.clients_sorted_desc.first.name
35
+ end
36
+
37
+ def test_has_many_foreign_key
38
+ assert_equal "Microsoft", Firm.find_first.clients_of_firm.first.name
39
+ end
40
+
41
+ def test_has_many_conditions
42
+ assert_equal "Microsoft", Firm.find_first.clients_like_ms.first.name
43
+ end
44
+
45
+ def test_has_many_sql
46
+ firm = Firm.find_first
47
+ assert_equal "Microsoft", firm.clients_using_sql.first.name
48
+ assert_equal 1, firm.clients_using_sql_count
49
+ assert_equal 1, Firm.find_first.clients_using_sql_count
50
+ end
51
+
52
+ def test_has_many_queries
53
+ assert Firm.find_first.has_clients?
54
+ firm = Firm.find_first
55
+ assert_equal 2, firm.clients_count # tests using class count
56
+ firm.clients
57
+ assert firm.has_clients?
58
+ assert_equal 2, firm.clients_count # tests using collection length
59
+ end
60
+
61
+ def test_has_many_dependence
62
+ assert_equal 2, Client.find_all.length
63
+ Firm.find_first.destroy
64
+ assert_equal 0, Client.find_all.length
65
+ end
66
+
67
+ def test_has_many_dependence_with_transaction_support_on_failure
68
+ assert_equal 2, Client.find_all.length
69
+
70
+ firm = Firm.find_first
71
+ clients = firm.clients
72
+ clients.last.instance_eval { def before_destroy() raise "Trigger rollback" end }
73
+
74
+ firm.destroy rescue "do nothing"
75
+
76
+ assert_equal 2, Client.find_all.length
77
+ end
78
+
79
+ def test_has_one_dependence
80
+ firm = Firm.find(1)
81
+ assert firm.has_account?
82
+ firm.destroy
83
+ assert_equal 1, Account.find_all.length
84
+ end
85
+
86
+ def test_has_one_dependence_with_missing_association
87
+ Account.destroy_all
88
+ firm = Firm.find(1)
89
+ assert !firm.has_account?
90
+ firm.destroy
91
+ end
92
+
93
+ def test_belongs_to
94
+ assert_equal @signals37.name, Client.find(3).firm.name
95
+ assert Client.find(3).has_firm?, "Microsoft should have a firm"
96
+ # assert !Company.find(1).has_firm?, "37signals shouldn't have a firm"
97
+ end
98
+
99
+ def test_belongs_to_with_different_class_name
100
+ assert_equal Company.find(1).name, Company.find(3).firm_with_other_name.name
101
+ assert Company.find(3).has_firm_with_other_name?, "Microsoft should have a firm"
102
+ end
103
+
104
+ def test_belongs_to_with_condition
105
+ assert_equal Company.find(1).name, Company.find(3).firm_with_condition.name
106
+ assert Company.find(3).has_firm_with_condition?, "Microsoft should have a firm"
107
+ end
108
+
109
+
110
+ def test_belongs_to_equality
111
+ assert Company.find(3).firm?(Company.find(1)), "Microsoft should have 37signals as firm"
112
+ assert_raises(RuntimeError) { !Company.find(3).firm?(Company.find(3)) } # "Summit shouldn't have itself as firm"
113
+ end
114
+
115
+ def test_has_one
116
+ assert @signals37.account?(Account.find(1))
117
+ assert_equal Account.find(1).credit_limit, @signals37.account.credit_limit
118
+ assert @signals37.has_account?, "37signals should have an account"
119
+ assert Account.find(1).firm?(@signals37), "37signals account should be able to backtrack"
120
+ assert Account.find(1).has_firm?, "37signals account should be able to backtrack"
121
+
122
+ assert !Account.find(2).has_firm?, "Unknown isn't linked"
123
+ assert !Account.find(2).firm?(@signals37), "Unknown isn't linked"
124
+ end
125
+
126
+ def test_has_many_dependence_on_account
127
+ assert_equal 2, Account.find_all.length
128
+ @signals37.destroy
129
+ assert_equal 1, Account.find_all.length
130
+ end
131
+
132
+ def test_find_in
133
+ assert_equal Client.find(2).name, @signals37.find_in_clients(2).name
134
+ assert_raises(ActiveRecord::RecordNotFound) { @signals37.find_in_clients(6) }
135
+ end
136
+
137
+ def test_force_reload
138
+ firm = Firm.new
139
+ firm.save
140
+ firm.clients.each {|c|} # forcing to load all clients
141
+ assert firm.clients.empty?, "New firm shouldn't have client objects"
142
+ assert !firm.has_clients?, "New firm shouldn't have clients"
143
+ assert_equal 0, firm.clients_count, "New firm should have 0 clients"
144
+
145
+ client = Client.new("firm_id" => firm.id)
146
+ client.save
147
+
148
+ assert firm.clients.empty?, "New firm should have cached no client objects"
149
+ assert !firm.has_clients?, "New firm should have cached a no-clients response"
150
+ assert_equal 0, firm.clients_count, "New firm should have cached 0 clients count"
151
+
152
+ assert !firm.clients(true).empty?, "New firm should have reloaded client objects"
153
+ assert firm.has_clients?(true), "New firm should have reloaded with a have-clients response"
154
+ assert_equal 1, firm.clients_count(true), "New firm should have reloaded clients count"
155
+ end
156
+
157
+ def test_included_in_collection
158
+ assert @signals37.clients.include?(Client.find(2))
159
+ end
160
+
161
+ def test_build_to_collection
162
+ assert_equal 1, @signals37.clients_of_firm_count
163
+ new_client = @signals37.build_to_clients_of_firm("name" => "Another Client")
164
+ assert_equal "Another Client", new_client.name
165
+ assert new_client.save
166
+
167
+ assert new_client.firm?(@signals37)
168
+ assert_equal 2, @signals37.clients_of_firm_count(true)
169
+ end
170
+
171
+ def test_create_in_collection
172
+ assert_equal @signals37.create_in_clients_of_firm("name" => "Another Client"), @signals37.clients_of_firm(true).last
173
+ end
174
+
175
+ def test_succesful_build_association
176
+ firm = Firm.new("name" => "GlobalMegaCorp")
177
+ firm.save
178
+
179
+ account = firm.build_account("credit_limit" => 1000)
180
+ assert account.save
181
+ assert_equal account, firm.account
182
+ end
183
+
184
+ def test_failing_build_association
185
+ firm = Firm.new("name" => "GlobalMegaCorp")
186
+ firm.save
187
+
188
+ account = firm.build_account
189
+ assert !account.save
190
+ assert_equal "can't be empty", account.errors.on("credit_limit")
191
+ end
192
+
193
+ def test_create_association
194
+ firm = Firm.new("name" => "GlobalMegaCorp")
195
+ firm.save
196
+ assert_equal firm.create_account("credit_limit" => 1000), firm.account
197
+ end
198
+
199
+ def test_has_and_belongs_to_many
200
+ david = Developer.find(1)
201
+ assert david.has_projects?
202
+ assert_equal 2, david.projects_count
203
+
204
+ active_record = Project.find(1)
205
+ assert active_record.has_developers?
206
+ assert_equal 2, active_record.developers_count
207
+ assert_equal david.name, active_record.developers.first.name
208
+ end
209
+
210
+ def test_has_and_belongs_to_many_removing
211
+ david = Developer.find(1)
212
+ active_record = Project.find(1)
213
+
214
+ david.remove_projects(active_record)
215
+
216
+ assert_equal 1, david.projects_count
217
+ assert_equal 1, active_record.developers_count
218
+ end
219
+
220
+ def test_has_and_belongs_to_many_zero
221
+ david = Developer.find(1)
222
+ david.remove_projects(Project.find_all)
223
+
224
+ assert_equal 0, david.projects_count
225
+ assert !david.has_projects?
226
+ end
227
+
228
+ def test_has_and_belongs_to_many_adding
229
+ jamis = Developer.find(2)
230
+ action_controller = Project.find(2)
231
+
232
+ jamis.add_projects(action_controller)
233
+
234
+ assert_equal 2, jamis.projects_count
235
+ assert_equal 2, action_controller.developers_count
236
+ end
237
+
238
+ def test_has_and_belongs_to_many_adding_from_the_project
239
+ jamis = Developer.find(2)
240
+ action_controller = Project.find(2)
241
+
242
+ action_controller.add_developers(jamis)
243
+
244
+ assert_equal 2, jamis.projects_count
245
+ assert_equal 2, action_controller.developers_count
246
+ end
247
+
248
+ def test_has_and_belongs_to_many_adding_a_collection
249
+ aridridel = Developer.new("name" => "Aridridel")
250
+ aridridel.save
251
+
252
+ aridridel.add_projects([ Project.find(1), Project.find(2) ])
253
+ assert_equal 2, aridridel.projects_count
254
+ end
255
+
256
+ def test_belongs_to_counter
257
+ topic = Topic.create("title" => "Apple", "content" => "hello world")
258
+ assert_equal 0, topic.send(:read_attribute, "replies_count"), "No replies yet"
259
+
260
+ reply = topic.create_in_replies("title" => "I'm saying no!", "content" => "over here")
261
+ assert_equal 1, Topic.find(topic.id).send(:read_attribute, "replies_count"), "First reply created"
262
+
263
+ reply.destroy
264
+ assert_equal 0, Topic.find(topic.id).send(:read_attribute, "replies_count"), "First reply deleted"
265
+ end
266
+
267
+ def test_natural_assignment_of_has_one
268
+ apple = Firm.create("name" => "Apple")
269
+ citibank = Account.create("credit_limit" => 10)
270
+ apple.account = citibank
271
+ assert_equal apple.id, citibank.firm_id
272
+ end
273
+
274
+ def test_natural_assignment_of_belongs_to
275
+ apple = Firm.create("name" => "Apple")
276
+ citibank = Account.create("credit_limit" => 10)
277
+ citibank.firm = apple
278
+ assert_equal apple.id, citibank.firm_id
279
+ end
280
+
281
+ def test_natural_assignment_of_has_many
282
+ apple = Firm.create("name" => "Apple")
283
+ natural = Client.new("name" => "Natural Company")
284
+ apple.clients << natural
285
+ assert_equal apple.id, natural.firm_id
286
+ assert_equal Client.find(natural.id), Firm.find(apple.id).clients.find { |c| c.id == natural.id }
287
+ apple.clients.delete natural
288
+ assert_nil Firm.find(apple.id).clients.find { |c| c.id == natural.id }
289
+ end
290
+
291
+
292
+ def test_natural_adding_of_has_and_belongs_to_many
293
+ rails = Project.create("name" => "Rails")
294
+ ap = Project.create("name" => "Action Pack")
295
+ john = Developer.create("name" => "John")
296
+ mike = Developer.create("name" => "Mike")
297
+ rails.developers << john
298
+ rails.developers << mike
299
+
300
+ assert_equal Developer.find(john.id), Project.find(rails.id).developers.find { |d| d.id == john.id }
301
+ assert_equal Developer.find(mike.id), Project.find(rails.id).developers.find { |d| d.id == mike.id }
302
+ assert_equal Project.find(rails.id), Developer.find(mike.id).projects.find { |p| p.id == rails.id }
303
+ assert_equal Project.find(rails.id), Developer.find(john.id).projects.find { |p| p.id == rails.id }
304
+ ap.developers << john
305
+ assert_equal Developer.find(john.id), Project.find(ap.id).developers.find { |d| d.id == john.id }
306
+ assert_equal Project.find(ap.id), Developer.find(john.id).projects.find { |p| p.id == ap.id }
307
+
308
+ ap.developers.delete john
309
+ assert_nil Project.find(ap.id).developers.find { |d| d.id == john.id }
310
+ assert_nil Developer.find(john.id).projects.find { |p| p.id == ap.id }
311
+ end
312
+
313
+ def test_storing_in_pstore
314
+ require "pstore"
315
+ apple = Firm.create("name" => "Apple")
316
+ natural = Client.new("name" => "Natural Company")
317
+ apple.clients << natural
318
+
319
+ db = PStore.new("/tmp/ar-pstore-association-test")
320
+ db.transaction do
321
+ db["apple"] = apple
322
+ end
323
+
324
+ db = PStore.new("/tmp/ar-pstore-association-test")
325
+ db.transaction do
326
+ assert_equal "Natural Company", db["apple"].clients.first.name
327
+ end
328
+ end
329
+
330
+ def test_has_many_find_all
331
+ assert_equal 2, Firm.find_first.find_all_in_clients("type = 'Client'").length
332
+ assert_equal 1, Firm.find_first.find_all_in_clients("name = 'Summit'").length
333
+ end
334
+ end