activerecord 1.14.4 → 1.15.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 (159) hide show
  1. data/CHANGELOG +400 -1
  2. data/README +2 -2
  3. data/RUNNING_UNIT_TESTS +21 -3
  4. data/Rakefile +55 -10
  5. data/lib/active_record.rb +10 -4
  6. data/lib/active_record/acts/list.rb +15 -4
  7. data/lib/active_record/acts/nested_set.rb +11 -12
  8. data/lib/active_record/acts/tree.rb +13 -14
  9. data/lib/active_record/aggregations.rb +46 -22
  10. data/lib/active_record/associations.rb +213 -162
  11. data/lib/active_record/associations/association_collection.rb +45 -15
  12. data/lib/active_record/associations/association_proxy.rb +32 -13
  13. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +18 -18
  14. data/lib/active_record/associations/has_many_association.rb +37 -17
  15. data/lib/active_record/associations/has_many_through_association.rb +120 -30
  16. data/lib/active_record/associations/has_one_association.rb +1 -1
  17. data/lib/active_record/attribute_methods.rb +75 -0
  18. data/lib/active_record/base.rb +282 -203
  19. data/lib/active_record/calculations.rb +95 -54
  20. data/lib/active_record/callbacks.rb +13 -24
  21. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +12 -1
  22. data/lib/active_record/connection_adapters/abstract/connection_specification.rb.rej +21 -0
  23. data/lib/active_record/connection_adapters/abstract/database_statements.rb +30 -4
  24. data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -9
  25. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +121 -37
  26. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +55 -23
  27. data/lib/active_record/connection_adapters/abstract_adapter.rb +8 -0
  28. data/lib/active_record/connection_adapters/db2_adapter.rb +1 -11
  29. data/lib/active_record/connection_adapters/firebird_adapter.rb +364 -50
  30. data/lib/active_record/connection_adapters/frontbase_adapter.rb +861 -0
  31. data/lib/active_record/connection_adapters/mysql_adapter.rb +86 -33
  32. data/lib/active_record/connection_adapters/openbase_adapter.rb +4 -3
  33. data/lib/active_record/connection_adapters/oracle_adapter.rb +151 -127
  34. data/lib/active_record/connection_adapters/postgresql_adapter.rb +125 -48
  35. data/lib/active_record/connection_adapters/sqlite_adapter.rb +38 -10
  36. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +183 -155
  37. data/lib/active_record/connection_adapters/sybase_adapter.rb +190 -212
  38. data/lib/active_record/deprecated_associations.rb +24 -10
  39. data/lib/active_record/deprecated_finders.rb +4 -1
  40. data/lib/active_record/fixtures.rb +37 -23
  41. data/lib/active_record/locking/optimistic.rb +106 -0
  42. data/lib/active_record/locking/pessimistic.rb +77 -0
  43. data/lib/active_record/migration.rb +8 -5
  44. data/lib/active_record/observer.rb +73 -34
  45. data/lib/active_record/reflection.rb +21 -7
  46. data/lib/active_record/schema_dumper.rb +33 -5
  47. data/lib/active_record/timestamp.rb +23 -34
  48. data/lib/active_record/transactions.rb +37 -30
  49. data/lib/active_record/validations.rb +46 -30
  50. data/lib/active_record/vendor/mysql.rb +20 -5
  51. data/lib/active_record/version.rb +2 -2
  52. data/lib/active_record/wrappings.rb +1 -2
  53. data/lib/active_record/xml_serialization.rb +308 -0
  54. data/test/aaa_create_tables_test.rb +5 -1
  55. data/test/abstract_unit.rb +18 -8
  56. data/test/{active_schema_mysql.rb → active_schema_test_mysql.rb} +2 -2
  57. data/test/adapter_test.rb +9 -7
  58. data/test/adapter_test_sqlserver.rb +81 -0
  59. data/test/aggregations_test.rb +29 -0
  60. data/test/{association_callbacks_test.rb → associations/callbacks_test.rb} +10 -8
  61. data/test/{associations_cascaded_eager_loading_test.rb → associations/cascaded_eager_loading_test.rb} +35 -3
  62. data/test/{associations_go_eager_test.rb → associations/eager_test.rb} +36 -2
  63. data/test/{associations_extensions_test.rb → associations/extension_test.rb} +5 -0
  64. data/test/{associations_join_model_test.rb → associations/join_model_test.rb} +118 -8
  65. data/test/associations_test.rb +339 -45
  66. data/test/attribute_methods_test.rb +49 -0
  67. data/test/base_test.rb +321 -67
  68. data/test/calculations_test.rb +48 -10
  69. data/test/callbacks_test.rb +13 -0
  70. data/test/connection_test_firebird.rb +8 -0
  71. data/test/connections/native_db2/connection.rb +18 -17
  72. data/test/connections/native_firebird/connection.rb +19 -17
  73. data/test/connections/native_frontbase/connection.rb +27 -0
  74. data/test/connections/native_mysql/connection.rb +18 -15
  75. data/test/connections/native_openbase/connection.rb +14 -15
  76. data/test/connections/native_oracle/connection.rb +16 -12
  77. data/test/connections/native_postgresql/connection.rb +16 -17
  78. data/test/connections/native_sqlite/connection.rb +3 -6
  79. data/test/connections/native_sqlite3/connection.rb +3 -6
  80. data/test/connections/native_sqlserver/connection.rb +16 -17
  81. data/test/connections/native_sqlserver_odbc/connection.rb +18 -19
  82. data/test/connections/native_sybase/connection.rb +16 -17
  83. data/test/datatype_test_postgresql.rb +52 -0
  84. data/test/defaults_test.rb +52 -10
  85. data/test/deprecated_associations_test.rb +151 -107
  86. data/test/deprecated_finder_test.rb +83 -66
  87. data/test/empty_date_time_test.rb +25 -0
  88. data/test/finder_test.rb +118 -11
  89. data/test/fixtures/accounts.yml +6 -1
  90. data/test/fixtures/author.rb +27 -4
  91. data/test/fixtures/categorizations.yml +8 -2
  92. data/test/fixtures/category.rb +1 -2
  93. data/test/fixtures/comments.yml +0 -6
  94. data/test/fixtures/companies.yml +6 -1
  95. data/test/fixtures/company.rb +23 -1
  96. data/test/fixtures/company_in_module.rb +8 -10
  97. data/test/fixtures/customer.rb +2 -2
  98. data/test/fixtures/customers.yml +9 -0
  99. data/test/fixtures/db_definitions/db2.drop.sql +1 -0
  100. data/test/fixtures/db_definitions/db2.sql +9 -0
  101. data/test/fixtures/db_definitions/firebird.drop.sql +3 -0
  102. data/test/fixtures/db_definitions/firebird.sql +13 -1
  103. data/test/fixtures/db_definitions/frontbase.drop.sql +31 -0
  104. data/test/fixtures/db_definitions/frontbase.sql +262 -0
  105. data/test/fixtures/db_definitions/frontbase2.drop.sql +1 -0
  106. data/test/fixtures/db_definitions/frontbase2.sql +4 -0
  107. data/test/fixtures/db_definitions/mysql.drop.sql +1 -0
  108. data/test/fixtures/db_definitions/mysql.sql +23 -14
  109. data/test/fixtures/db_definitions/openbase.sql +13 -1
  110. data/test/fixtures/db_definitions/oracle.drop.sql +2 -0
  111. data/test/fixtures/db_definitions/oracle.sql +29 -2
  112. data/test/fixtures/db_definitions/postgresql.drop.sql +3 -1
  113. data/test/fixtures/db_definitions/postgresql.sql +13 -3
  114. data/test/fixtures/db_definitions/schema.rb +29 -1
  115. data/test/fixtures/db_definitions/sqlite.drop.sql +1 -0
  116. data/test/fixtures/db_definitions/sqlite.sql +12 -3
  117. data/test/fixtures/db_definitions/sqlserver.drop.sql +3 -0
  118. data/test/fixtures/db_definitions/sqlserver.sql +35 -0
  119. data/test/fixtures/db_definitions/sybase.drop.sql +2 -0
  120. data/test/fixtures/db_definitions/sybase.sql +13 -4
  121. data/test/fixtures/developer.rb +12 -0
  122. data/test/fixtures/edge.rb +5 -0
  123. data/test/fixtures/edges.yml +6 -0
  124. data/test/fixtures/funny_jokes.yml +3 -7
  125. data/test/fixtures/migrations_with_decimal/1_give_me_big_numbers.rb +15 -0
  126. data/test/fixtures/migrations_with_missing_versions/1000_people_have_middle_names.rb +9 -0
  127. data/test/fixtures/migrations_with_missing_versions/1_people_have_last_names.rb +9 -0
  128. data/test/fixtures/migrations_with_missing_versions/3_we_need_reminders.rb +12 -0
  129. data/test/fixtures/migrations_with_missing_versions/4_innocent_jointable.rb +12 -0
  130. data/test/fixtures/mixin.rb +15 -0
  131. data/test/fixtures/mixins.yml +38 -0
  132. data/test/fixtures/post.rb +3 -2
  133. data/test/fixtures/project.rb +3 -1
  134. data/test/fixtures/topic.rb +6 -1
  135. data/test/fixtures/topics.yml +4 -4
  136. data/test/fixtures/vertex.rb +9 -0
  137. data/test/fixtures/vertices.yml +4 -0
  138. data/test/fixtures_test.rb +45 -0
  139. data/test/inheritance_test.rb +67 -6
  140. data/test/lifecycle_test.rb +40 -19
  141. data/test/locking_test.rb +170 -26
  142. data/test/method_scoping_test.rb +2 -2
  143. data/test/migration_test.rb +387 -110
  144. data/test/migration_test_firebird.rb +124 -0
  145. data/test/mixin_nested_set_test.rb +14 -2
  146. data/test/mixin_test.rb +56 -18
  147. data/test/modules_test.rb +8 -2
  148. data/test/multiple_db_test.rb +2 -2
  149. data/test/pk_test.rb +1 -0
  150. data/test/reflection_test.rb +8 -2
  151. data/test/schema_authorization_test_postgresql.rb +75 -0
  152. data/test/schema_dumper_test.rb +40 -4
  153. data/test/table_name_test_sqlserver.rb +23 -0
  154. data/test/threaded_connections_test.rb +19 -16
  155. data/test/transactions_test.rb +86 -72
  156. data/test/validations_test.rb +126 -56
  157. data/test/xml_serialization_test.rb +125 -0
  158. metadata +45 -11
  159. data/lib/active_record/locking.rb +0 -79
@@ -1,6 +1,7 @@
1
1
  require 'abstract_unit'
2
2
  require 'fixtures/company'
3
3
  require 'fixtures/topic'
4
+ require 'fixtures/reply'
4
5
  require 'fixtures/entrant'
5
6
  require 'fixtures/developer'
6
7
 
@@ -8,78 +9,88 @@ class DeprecatedFinderTest < Test::Unit::TestCase
8
9
  fixtures :companies, :topics, :entrants, :developers
9
10
 
10
11
  def test_find_all_with_limit
11
- entrants = Entrant.find_all nil, "id ASC", 2
12
-
13
- assert_equal(2, entrants.size)
14
- assert_equal(entrants(:first).name, entrants.first.name)
12
+ entrants = assert_deprecated { Entrant.find_all nil, "id ASC", 2 }
13
+ assert_equal 2, entrants.size
14
+ assert_equal entrants(:first), entrants.first
15
15
  end
16
16
 
17
17
  def test_find_all_with_prepared_limit_and_offset
18
- entrants = Entrant.find_all nil, "id ASC", [2, 1]
19
-
20
- assert_equal(2, entrants.size)
21
- assert_equal(entrants(:second).name, entrants.first.name)
18
+ entrants = assert_deprecated { Entrant.find_all nil, "id ASC", [2, 1] }
19
+ assert_equal 2, entrants.size
20
+ assert_equal entrants(:second), entrants.first
22
21
  end
23
22
 
24
23
  def test_find_first
25
- first = Topic.find_first "title = 'The First Topic'"
26
- assert_equal(topics(:first).title, first.title)
24
+ first = assert_deprecated { Topic.find_first "title = 'The First Topic'" }
25
+ assert_equal topics(:first), first
27
26
  end
28
-
27
+
29
28
  def test_find_first_failing
30
- first = Topic.find_first "title = 'The First Topic!'"
31
- assert_nil(first)
29
+ first = assert_deprecated { Topic.find_first "title = 'The First Topic!'" }
30
+ assert_nil first
32
31
  end
33
-
32
+
34
33
  def test_deprecated_find_on_conditions
35
- assert Topic.find_on_conditions(1, ["approved = ?", false])
36
- assert_raises(ActiveRecord::RecordNotFound) { Topic.find_on_conditions(1, ["approved = ?", true]) }
34
+ assert_deprecated 'find_on_conditions' do
35
+ assert Topic.find_on_conditions(1, ["approved = ?", false])
36
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find_on_conditions(1, ["approved = ?", true]) }
37
+ end
37
38
  end
38
-
39
+
39
40
  def test_condition_interpolation
40
- assert_kind_of Firm, Company.find_first(["name = '%s'", "37signals"])
41
- assert_nil Company.find_first(["name = '%s'", "37signals!"])
42
- assert_nil Company.find_first(["name = '%s'", "37signals!' OR 1=1"])
43
- assert_kind_of Time, Topic.find_first(["id = %d", 1]).written_on
41
+ assert_deprecated do
42
+ assert_kind_of Firm, Company.find_first(["name = '%s'", "37signals"])
43
+ assert_nil Company.find_first(["name = '%s'", "37signals!"])
44
+ assert_nil Company.find_first(["name = '%s'", "37signals!' OR 1=1"])
45
+ assert_kind_of Time, Topic.find_first(["id = %d", 1]).written_on
46
+ end
44
47
  end
45
48
 
46
49
  def test_bind_variables
47
- assert_kind_of Firm, Company.find_first(["name = ?", "37signals"])
48
- assert_nil Company.find_first(["name = ?", "37signals!"])
49
- assert_nil Company.find_first(["name = ?", "37signals!' OR 1=1"])
50
- assert_kind_of Time, Topic.find_first(["id = ?", 1]).written_on
51
- assert_raises(ActiveRecord::PreparedStatementInvalid) {
52
- Company.find_first(["id=? AND name = ?", 2])
53
- }
54
- assert_raises(ActiveRecord::PreparedStatementInvalid) {
55
- Company.find_first(["id=?", 2, 3, 4])
56
- }
50
+ assert_deprecated do
51
+ assert_kind_of Firm, Company.find_first(["name = ?", "37signals"])
52
+ assert_nil Company.find_first(["name = ?", "37signals!"])
53
+ assert_nil Company.find_first(["name = ?", "37signals!' OR 1=1"])
54
+ assert_kind_of Time, Topic.find_first(["id = ?", 1]).written_on
55
+ assert_raises(ActiveRecord::PreparedStatementInvalid) {
56
+ Company.find_first(["id=? AND name = ?", 2])
57
+ }
58
+ assert_raises(ActiveRecord::PreparedStatementInvalid) {
59
+ Company.find_first(["id=?", 2, 3, 4])
60
+ }
61
+ end
57
62
  end
58
63
 
59
64
  def test_bind_variables_with_quotes
60
65
  Company.create("name" => "37signals' go'es agains")
61
- assert Company.find_first(["name = ?", "37signals' go'es agains"])
66
+ assert_deprecated do
67
+ assert_not_nil Company.find_first(["name = ?", "37signals' go'es agains"])
68
+ end
62
69
  end
63
70
 
64
71
  def test_named_bind_variables_with_quotes
65
72
  Company.create("name" => "37signals' go'es agains")
66
- assert Company.find_first(["name = :name", {:name => "37signals' go'es agains"}])
73
+ assert_deprecated do
74
+ assert_not_nil Company.find_first(["name = :name", {:name => "37signals' go'es agains"}])
75
+ end
67
76
  end
68
77
 
69
78
  def test_named_bind_variables
70
79
  assert_equal '1', bind(':a', :a => 1) # ' ruby-mode
71
80
  assert_equal '1 1', bind(':a :a', :a => 1) # ' ruby-mode
72
-
73
- assert_kind_of Firm, Company.find_first(["name = :name", { :name => "37signals" }])
74
- assert_nil Company.find_first(["name = :name", { :name => "37signals!" }])
75
- assert_nil Company.find_first(["name = :name", { :name => "37signals!' OR 1=1" }])
76
- assert_kind_of Time, Topic.find_first(["id = :id", { :id => 1 }]).written_on
81
+
82
+ assert_deprecated do
83
+ assert_kind_of Firm, Company.find_first(["name = :name", { :name => "37signals" }])
84
+ assert_nil Company.find_first(["name = :name", { :name => "37signals!" }])
85
+ assert_nil Company.find_first(["name = :name", { :name => "37signals!' OR 1=1" }])
86
+ assert_kind_of Time, Topic.find_first(["id = :id", { :id => 1 }]).written_on
87
+ end
77
88
  end
78
89
 
79
90
  def test_count
80
- assert_equal(0, Entrant.count("id > 3"))
81
- assert_equal(1, Entrant.count(["id > ?", 2]))
82
- assert_equal(2, Entrant.count(["id > ?", 1]))
91
+ assert_equal(0, Entrant.count(:conditions => "id > 3"))
92
+ assert_equal(1, Entrant.count(:conditions => ["id > ?", 2]))
93
+ assert_equal(2, Entrant.count(:conditions => ["id > ?", 1]))
83
94
  end
84
95
 
85
96
  def test_count_by_sql
@@ -89,38 +100,44 @@ class DeprecatedFinderTest < Test::Unit::TestCase
89
100
  end
90
101
 
91
102
  def test_find_all_with_limit
92
- first_five_developers = Developer.find_all nil, 'id ASC', 5
93
- assert_equal 5, first_five_developers.length
94
- assert_equal 'David', first_five_developers.first.name
95
- assert_equal 'fixture_5', first_five_developers.last.name
96
-
97
- no_developers = Developer.find_all nil, 'id ASC', 0
98
- assert_equal 0, no_developers.length
99
-
100
- assert_equal first_five_developers, Developer.find_all(nil, 'id ASC', [5])
101
- assert_equal no_developers, Developer.find_all(nil, 'id ASC', [0])
103
+ assert_deprecated do
104
+ first_five_developers = Developer.find_all nil, 'id ASC', 5
105
+ assert_equal 5, first_five_developers.length
106
+ assert_equal 'David', first_five_developers.first.name
107
+ assert_equal 'fixture_5', first_five_developers.last.name
108
+
109
+ no_developers = Developer.find_all nil, 'id ASC', 0
110
+ assert_equal 0, no_developers.length
111
+
112
+ assert_equal first_five_developers, Developer.find_all(nil, 'id ASC', [5])
113
+ assert_equal no_developers, Developer.find_all(nil, 'id ASC', [0])
114
+ end
102
115
  end
103
116
 
104
117
  def test_find_all_with_limit_and_offset
105
- first_three_developers = Developer.find_all nil, 'id ASC', [3, 0]
106
- second_three_developers = Developer.find_all nil, 'id ASC', [3, 3]
107
- last_two_developers = Developer.find_all nil, 'id ASC', [2, 8]
108
-
109
- assert_equal 3, first_three_developers.length
110
- assert_equal 3, second_three_developers.length
111
- assert_equal 2, last_two_developers.length
112
-
113
- assert_equal 'David', first_three_developers.first.name
114
- assert_equal 'fixture_4', second_three_developers.first.name
115
- assert_equal 'fixture_9', last_two_developers.first.name
118
+ assert_deprecated do
119
+ first_three_developers = Developer.find_all nil, 'id ASC', [3, 0]
120
+ second_three_developers = Developer.find_all nil, 'id ASC', [3, 3]
121
+ last_two_developers = Developer.find_all nil, 'id ASC', [2, 8]
122
+
123
+ assert_equal 3, first_three_developers.length
124
+ assert_equal 3, second_three_developers.length
125
+ assert_equal 2, last_two_developers.length
126
+
127
+ assert_equal 'David', first_three_developers.first.name
128
+ assert_equal 'fixture_4', second_three_developers.first.name
129
+ assert_equal 'fixture_9', last_two_developers.first.name
130
+ end
116
131
  end
117
132
 
118
133
  def test_find_all_by_one_attribute_with_options
119
- topics = Topic.find_all_by_content("Have a nice day", "id DESC")
120
- assert topics(:first), topics.last
134
+ assert_not_deprecated do
135
+ topics = Topic.find_all_by_content("Have a nice day", "id DESC")
136
+ assert topics(:first), topics.last
121
137
 
122
- topics = Topic.find_all_by_content("Have a nice day", "id DESC")
123
- assert topics(:first), topics.first
138
+ topics = Topic.find_all_by_content("Have a nice day", "id DESC")
139
+ assert topics(:first), topics.first
140
+ end
124
141
  end
125
142
 
126
143
  protected
@@ -0,0 +1,25 @@
1
+ require 'abstract_unit'
2
+ require 'fixtures/topic'
3
+ require 'fixtures/task'
4
+
5
+ class EmptyDateTimeTest < Test::Unit::TestCase
6
+ def test_assign_empty_date_time
7
+ task = Task.new
8
+ task.starting = ''
9
+ task.ending = nil
10
+ assert_nil task.starting
11
+ assert_nil task.ending
12
+ end
13
+
14
+ def test_assign_empty_date
15
+ topic = Topic.new
16
+ topic.last_read = ''
17
+ assert_nil topic.last_read
18
+ end
19
+
20
+ def test_assign_empty_time
21
+ topic = Topic.new
22
+ topic.bonus_time = ''
23
+ assert_nil topic.bonus_time
24
+ end
25
+ end
@@ -13,11 +13,21 @@ class FinderTest < Test::Unit::TestCase
13
13
  assert_equal(topics(:first).title, Topic.find(1).title)
14
14
  end
15
15
 
16
+ # find should handle strings that come from URLs
17
+ # (example: Category.find(params[:id]))
18
+ def test_find_with_string
19
+ assert_equal(Topic.find(1).title,Topic.find("1").title)
20
+ end
21
+
16
22
  def test_exists
17
- assert (Topic.exists?(1))
18
- assert !(Topic.exists?(45))
19
- assert !(Topic.exists?("foo"))
20
- assert !(Topic.exists?([1,2]))
23
+ assert Topic.exists?(1)
24
+ assert Topic.exists?("1")
25
+ assert Topic.exists?(:author_name => "David")
26
+ assert Topic.exists?(:author_name => "Mary", :approved => true)
27
+ assert Topic.exists?(["parent_id = ?", 1])
28
+ assert !Topic.exists?(45)
29
+ assert !Topic.exists?("foo")
30
+ assert_raise(NoMethodError) { Topic.exists?([1,2]) }
21
31
  end
22
32
 
23
33
  def test_find_by_array_of_one_id
@@ -83,6 +93,11 @@ class FinderTest < Test::Unit::TestCase
83
93
  assert_equal(topics(:second).title, topics.first.title)
84
94
  end
85
95
 
96
+ def test_find_by_sql_with_sti_on_joined_table
97
+ accounts = Account.find_by_sql("SELECT * FROM accounts INNER JOIN companies ON companies.id = accounts.firm_id")
98
+ assert_equal [Account], accounts.collect(&:class).uniq
99
+ end
100
+
86
101
  def test_find_first
87
102
  first = Topic.find(:first, :conditions => "title = 'The First Topic'")
88
103
  assert_equal(topics(:first).title, first.title)
@@ -111,17 +126,58 @@ class FinderTest < Test::Unit::TestCase
111
126
  assert topic.respond_to?("author_name")
112
127
  end
113
128
 
114
- def test_find_on_conditions
129
+ def test_find_on_array_conditions
115
130
  assert Topic.find(1, :conditions => ["approved = ?", false])
116
131
  assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => ["approved = ?", true]) }
117
132
  end
118
133
 
119
- def test_condition_interpolation
134
+ def test_find_on_hash_conditions
135
+ assert Topic.find(1, :conditions => { :approved => false })
136
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :approved => true }) }
137
+ end
138
+
139
+ def test_find_on_multiple_hash_conditions
140
+ assert Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => false })
141
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }) }
142
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "HHC", :replies_count => 1, :approved => false }) }
143
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }) }
144
+ end
145
+
146
+ def test_condition_array_interpolation
120
147
  assert_kind_of Firm, Company.find(:first, :conditions => ["name = '%s'", "37signals"])
121
148
  assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!"])
122
149
  assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!' OR 1=1"])
123
150
  assert_kind_of Time, Topic.find(:first, :conditions => ["id = %d", 1]).written_on
124
151
  end
152
+
153
+ def test_condition_hash_interpolation
154
+ assert_kind_of Firm, Company.find(:first, :conditions => { :name => "37signals"})
155
+ assert_nil Company.find(:first, :conditions => { :name => "37signals!"})
156
+ assert_kind_of Time, Topic.find(:first, :conditions => {:id => 1}).written_on
157
+ end
158
+
159
+ def test_hash_condition_find_malformed
160
+ assert_raises(ActiveRecord::StatementInvalid) {
161
+ Company.find(:first, :conditions => { :id => 2, :dhh => true })
162
+ }
163
+ end
164
+
165
+ def test_hash_condition_find_with_escaped_characters
166
+ Company.create("name" => "Ain't noth'n like' \#stuff")
167
+ assert Company.find(:first, :conditions => { :name => "Ain't noth'n like' \#stuff" })
168
+ end
169
+
170
+ def test_hash_condition_find_with_array
171
+ p1, p2 = Post.find(:all, :limit => 2, :order => 'id asc')
172
+ assert_equal [p1, p2], Post.find(:all, :conditions => { :id => [p1, p2] }, :order => 'id asc')
173
+ assert_equal [p1, p2], Post.find(:all, :conditions => { :id => [p1, p2.id] }, :order => 'id asc')
174
+ end
175
+
176
+ def test_hash_condition_find_with_nil
177
+ topic = Topic.find(:first, :conditions => { :last_read => nil } )
178
+ assert_not_nil topic
179
+ assert_nil topic.last_read
180
+ end
125
181
 
126
182
  def test_bind_variables
127
183
  assert_kind_of Firm, Company.find(:first, :conditions => ["name = ?", "37signals"])
@@ -180,19 +236,34 @@ class FinderTest < Test::Unit::TestCase
180
236
  assert_equal %('a','b','c'), bind(':a', :a => Set.new(%w(a b c))) # '
181
237
  end
182
238
 
239
+ def test_bind_empty_enumerable
240
+ quoted_nil = ActiveRecord::Base.connection.quote(nil)
241
+ assert_equal quoted_nil, bind('?', [])
242
+ assert_equal " in (#{quoted_nil})", bind(' in (?)', [])
243
+ assert_equal "foo in (#{quoted_nil})", bind('foo in (?)', [])
244
+ end
245
+
183
246
  def test_bind_string
184
247
  assert_equal "''", bind('?', '')
185
248
  end
186
249
 
250
+ def test_bind_record
251
+ o = Struct.new(:quoted_id).new(1)
252
+ assert_equal '1', bind('?', o)
253
+
254
+ os = [o] * 3
255
+ assert_equal '1,1,1', bind('?', os)
256
+ end
257
+
187
258
  def test_string_sanitation
188
259
  assert_not_equal "'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1")
189
260
  assert_equal "'something; select table'", ActiveRecord::Base.sanitize("something; select table")
190
261
  end
191
262
 
192
263
  def test_count
193
- assert_equal(0, Entrant.count("id > 3"))
194
- assert_equal(1, Entrant.count(["id > ?", 2]))
195
- assert_equal(2, Entrant.count(["id > ?", 1]))
264
+ assert_equal(0, Entrant.count(:conditions => "id > 3"))
265
+ assert_equal(1, Entrant.count(:conditions => ["id > ?", 2]))
266
+ assert_equal(2, Entrant.count(:conditions => ["id > ?", 1]))
196
267
  end
197
268
 
198
269
  def test_count_by_sql
@@ -222,6 +293,13 @@ class FinderTest < Test::Unit::TestCase
222
293
  def test_find_by_one_missing_attribute
223
294
  assert_raises(NoMethodError) { Topic.find_by_undertitle("The First Topic!") }
224
295
  end
296
+
297
+ def test_find_by_invalid_method_syntax
298
+ assert_raises(NoMethodError) { Topic.fail_to_find_by_title("The First Topic") }
299
+ assert_raises(NoMethodError) { Topic.find_by_title?("The First Topic") }
300
+ assert_raises(NoMethodError) { Topic.fail_to_find_or_create_by_title("Nonexistent Title") }
301
+ assert_raises(NoMethodError) { Topic.find_or_create_by_title?("Nonexistent Title") }
302
+ end
225
303
 
226
304
  def test_find_by_two_attributes
227
305
  assert_equal topics(:first), Topic.find_by_title_and_author_name("The First Topic", "David")
@@ -286,6 +364,7 @@ class FinderTest < Test::Unit::TestCase
286
364
  sig38 = Company.find_or_create_by_name("38signals")
287
365
  assert_equal number_of_companies + 1, Company.count
288
366
  assert_equal sig38, Company.find_or_create_by_name("38signals")
367
+ assert !sig38.new_record?
289
368
  end
290
369
 
291
370
  def test_find_or_create_from_two_attributes
@@ -293,6 +372,20 @@ class FinderTest < Test::Unit::TestCase
293
372
  another = Topic.find_or_create_by_title_and_author_name("Another topic","John")
294
373
  assert_equal number_of_topics + 1, Topic.count
295
374
  assert_equal another, Topic.find_or_create_by_title_and_author_name("Another topic", "John")
375
+ assert !another.new_record?
376
+ end
377
+
378
+ def test_find_or_initialize_from_one_attribute
379
+ sig38 = Company.find_or_initialize_by_name("38signals")
380
+ assert_equal "38signals", sig38.name
381
+ assert sig38.new_record?
382
+ end
383
+
384
+ def test_find_or_initialize_from_two_attributes
385
+ another = Topic.find_or_initialize_by_title_and_author_name("Another topic","John")
386
+ assert_equal "Another topic", another.title
387
+ assert_equal "John", another.author_name
388
+ assert another.new_record?
296
389
  end
297
390
 
298
391
  def test_find_with_bad_sql
@@ -357,6 +450,20 @@ class FinderTest < Test::Unit::TestCase
357
450
  end
358
451
  end
359
452
 
453
+ def test_find_by_empty_ids
454
+ assert_equal [], Post.find([])
455
+ end
456
+
457
+ def test_find_by_empty_in_condition
458
+ assert_equal [], Post.find(:all, :conditions => ['id in (?)', []])
459
+ end
460
+
461
+ def test_find_by_records
462
+ p1, p2 = Post.find(:all, :limit => 2, :order => 'id asc')
463
+ assert_equal [p1, p2], Post.find(:all, :conditions => ['id in (?)', [p1, p2]], :order => 'id asc')
464
+ assert_equal [p1, p2], Post.find(:all, :conditions => ['id in (?)', [p1, p2.id]], :order => 'id asc')
465
+ end
466
+
360
467
  def test_select_value
361
468
  assert_equal "37signals", Company.connection.select_value("SELECT name FROM companies WHERE id = 1")
362
469
  assert_nil Company.connection.select_value("SELECT name FROM companies WHERE id = -1")
@@ -366,8 +473,8 @@ class FinderTest < Test::Unit::TestCase
366
473
  end
367
474
 
368
475
  def test_select_values
369
- assert_equal ["1","2","3","4","5","6","7","8"], Company.connection.select_values("SELECT id FROM companies ORDER BY id").map! { |i| i.to_s }
370
- assert_equal ["37signals","Summit","Microsoft", "Flamboyant Software", "Ex Nihilo", "RailsCore", "Leetsoft", "Jadedpixel"], Company.connection.select_values("SELECT name FROM companies ORDER BY id")
476
+ assert_equal ["1","2","3","4","5","6","7","8","9"], Company.connection.select_values("SELECT id FROM companies ORDER BY id").map! { |i| i.to_s }
477
+ assert_equal ["37signals","Summit","Microsoft", "Flamboyant Software", "Ex Nihilo", "RailsCore", "Leetsoft", "Jadedpixel", "Odegy"], Company.connection.select_values("SELECT name FROM companies ORDER BY id")
371
478
  end
372
479
 
373
480
  protected
@@ -20,4 +20,9 @@ last_account:
20
20
  rails_core_account_2:
21
21
  id: 5
22
22
  firm_id: 6
23
- credit_limit: 55
23
+ credit_limit: 55
24
+
25
+ odegy_account:
26
+ id: 6
27
+ firm_id: 9
28
+ credit_limit: 53