ibm_db 1.1.1-mswin32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/CHANGES +155 -0
  2. data/LICENSE +18 -0
  3. data/MANIFEST +14 -0
  4. data/README +274 -0
  5. data/ext/Makefile.nt32 +181 -0
  6. data/ext/extconf.rb +58 -0
  7. data/ext/ibm_db.c +6553 -0
  8. data/ext/ruby_ibm_db.h +214 -0
  9. data/init.rb +42 -0
  10. data/lib/IBM_DB.rb +2 -0
  11. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +2218 -0
  12. data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -0
  13. data/lib/mswin32/ibm_db.so +0 -0
  14. data/test/cases/adapter_test.rb +180 -0
  15. data/test/cases/associations/cascaded_eager_loading_test.rb +133 -0
  16. data/test/cases/associations/eager_test.rb +842 -0
  17. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +874 -0
  18. data/test/cases/associations/has_many_through_associations_test.rb +281 -0
  19. data/test/cases/associations/join_model_test.rb +801 -0
  20. data/test/cases/attribute_methods_test.rb +312 -0
  21. data/test/cases/base_test.rb +2114 -0
  22. data/test/cases/calculations_test.rb +346 -0
  23. data/test/cases/finder_test.rb +1092 -0
  24. data/test/cases/fixtures_test.rb +660 -0
  25. data/test/cases/migration_test.rb +1618 -0
  26. data/test/cases/schema_dumper_test.rb +197 -0
  27. data/test/cases/validations_test.rb +1604 -0
  28. data/test/connections/native_ibm_db/connection.rb +40 -0
  29. data/test/ibm_db_test.rb +25 -0
  30. data/test/models/warehouse_thing.rb +5 -0
  31. data/test/schema/i5/ibm_db_specific_schema.rb +134 -0
  32. data/test/schema/ids/ibm_db_specific_schema.rb +137 -0
  33. data/test/schema/luw/ibm_db_specific_schema.rb +134 -0
  34. data/test/schema/schema.rb +499 -0
  35. data/test/schema/zOS/ibm_db_specific_schema.rb +205 -0
  36. metadata +115 -0
@@ -0,0 +1,346 @@
1
+ require "cases/helper"
2
+ require 'models/company'
3
+ require 'models/topic'
4
+ require 'models/edge'
5
+ require 'models/owner'
6
+ require 'models/pet'
7
+ require 'models/toy'
8
+
9
+ Company.has_many :accounts
10
+
11
+ class NumericData < ActiveRecord::Base
12
+ self.table_name = 'numeric_data'
13
+ end
14
+
15
+ class CalculationsTest < ActiveRecord::TestCase
16
+ fixtures :companies, :accounts, :topics, :owners, :pets, :toys
17
+
18
+ def test_should_sum_field
19
+ assert_equal 318, Account.sum(:credit_limit)
20
+ end
21
+
22
+ def test_should_average_field
23
+ value = Account.average(:credit_limit)
24
+ assert_kind_of BigDecimal, value
25
+ assert_equal BigDecimal.new('53.0'), value
26
+ end
27
+
28
+ def test_should_return_nil_as_average
29
+ assert_nil NumericData.average(:bank_balance)
30
+ end
31
+
32
+ def test_type_cast_calculated_value_should_convert_db_averages_of_fixnum_class_to_decimal
33
+ assert_equal 0, NumericData.send(:type_cast_calculated_value, 0, nil, 'avg')
34
+ assert_equal 53.0, NumericData.send(:type_cast_calculated_value, 53, nil, 'avg')
35
+ end
36
+
37
+ def test_should_get_maximum_of_field
38
+ assert_equal 60, Account.maximum(:credit_limit)
39
+ end
40
+
41
+ def test_should_get_maximum_of_field_with_include
42
+ assert_equal 50, Account.maximum(:credit_limit, :include => :firm, :conditions => "companies.name != 'Summit'")
43
+ end
44
+
45
+ def test_should_get_maximum_of_field_with_scoped_include
46
+ Account.with_scope :find => { :include => :firm, :conditions => "companies.name != 'Summit'" } do
47
+ assert_equal 50, Account.maximum(:credit_limit)
48
+ end
49
+ end
50
+
51
+ def test_should_get_minimum_of_field
52
+ assert_equal 50, Account.minimum(:credit_limit)
53
+ end
54
+
55
+ def test_should_group_by_field
56
+ c = Account.sum(:credit_limit, :group => :firm_id)
57
+ [1,6,2].each { |firm_id| assert c.keys.include?(firm_id) }
58
+ end
59
+
60
+ def test_should_group_by_summed_field
61
+ c = Account.sum(:credit_limit, :group => :firm_id)
62
+ assert_equal 50, c[1]
63
+ assert_equal 105, c[6]
64
+ assert_equal 60, c[2]
65
+ end
66
+
67
+ def test_should_order_by_grouped_field
68
+ c = Account.sum(:credit_limit, :group => :firm_id, :order => "firm_id")
69
+ assert_equal [1, 2, 6, 9], c.keys.compact
70
+ end
71
+
72
+ def test_should_order_by_calculation
73
+ c = Account.sum(:credit_limit, :group => :firm_id, :order => "sum_credit_limit desc, firm_id")
74
+ assert_equal [105, 60, 53, 50, 50], c.keys.collect { |k| c[k] }
75
+ assert_equal [6, 2, 9, 1], c.keys.compact
76
+ end
77
+
78
+ def test_should_limit_calculation
79
+ c = Account.sum(:credit_limit, :conditions => "firm_id IS NOT NULL",
80
+ :group => :firm_id, :order => "firm_id", :limit => 2)
81
+ assert_equal [1, 2], c.keys.compact
82
+ end
83
+
84
+ def test_should_limit_calculation_with_offset
85
+ c = Account.sum(:credit_limit, :conditions => "firm_id IS NOT NULL",
86
+ :group => :firm_id, :order => "firm_id", :limit => 2, :offset => 1)
87
+ assert_equal [2, 6], c.keys.compact
88
+ end
89
+
90
+ def test_should_group_by_summed_field_having_condition
91
+ c = Account.sum(:credit_limit, :group => :firm_id,
92
+ :having => 'sum(credit_limit) > 50')
93
+ assert_nil c[1]
94
+ assert_equal 105, c[6]
95
+ assert_equal 60, c[2]
96
+ end
97
+
98
+ def test_should_group_by_summed_field_having_sanitized_condition
99
+ c = Account.sum(:credit_limit, :group => :firm_id,
100
+ :having => ['sum(credit_limit) > ?', 50])
101
+ assert_nil c[1]
102
+ assert_equal 105, c[6]
103
+ assert_equal 60, c[2]
104
+ end
105
+
106
+ def test_should_group_by_summed_association
107
+ c = Account.sum(:credit_limit, :group => :firm)
108
+ assert_equal 50, c[companies(:first_firm)]
109
+ assert_equal 105, c[companies(:rails_core)]
110
+ assert_equal 60, c[companies(:first_client)]
111
+ end
112
+
113
+ def test_should_sum_field_with_conditions
114
+ assert_equal 105, Account.sum(:credit_limit, :conditions => 'firm_id = 6')
115
+ end
116
+
117
+ def test_should_return_zero_if_sum_conditions_return_nothing
118
+ assert_equal 0, Account.sum(:credit_limit, :conditions => '1 = 2')
119
+ assert_equal 0, companies(:rails_core).companies.sum(:id, :conditions => '1 = 2')
120
+ end
121
+
122
+ def test_sum_should_return_valid_values_for_decimals
123
+ NumericData.create(:bank_balance => 19.83)
124
+ assert_equal 19.83, NumericData.sum(:bank_balance)
125
+ end
126
+
127
+ def test_should_group_by_summed_field_with_conditions
128
+ c = Account.sum(:credit_limit, :conditions => 'firm_id > 1',
129
+ :group => :firm_id)
130
+ assert_nil c[1]
131
+ assert_equal 105, c[6]
132
+ assert_equal 60, c[2]
133
+ end
134
+
135
+ def test_should_group_by_summed_field_with_conditions_and_having
136
+ c = Account.sum(:credit_limit, :conditions => 'firm_id > 1',
137
+ :group => :firm_id,
138
+ :having => 'sum(credit_limit) > 60')
139
+ assert_nil c[1]
140
+ assert_equal 105, c[6]
141
+ assert_nil c[2]
142
+ end
143
+
144
+ def test_should_group_by_fields_with_table_alias
145
+ c = Account.sum(:credit_limit, :group => 'accounts.firm_id')
146
+ assert_equal 50, c[1]
147
+ assert_equal 105, c[6]
148
+ assert_equal 60, c[2]
149
+ end
150
+
151
+ def test_should_calculate_with_invalid_field
152
+ assert_equal 6, Account.calculate(:count, '*')
153
+ assert_equal 6, Account.calculate(:count, :all)
154
+ end
155
+
156
+ def test_should_calculate_grouped_with_invalid_field
157
+ c = Account.count(:all, :group => 'accounts.firm_id')
158
+ assert_equal 1, c[1]
159
+ assert_equal 2, c[6]
160
+ assert_equal 1, c[2]
161
+ end
162
+
163
+ def test_should_calculate_grouped_association_with_invalid_field
164
+ c = Account.count(:all, :group => :firm)
165
+ assert_equal 1, c[companies(:first_firm)]
166
+ assert_equal 2, c[companies(:rails_core)]
167
+ assert_equal 1, c[companies(:first_client)]
168
+ end
169
+
170
+ def test_should_group_by_association_with_non_numeric_foreign_key
171
+ ActiveRecord::Base.connection.expects(:select_all).returns([{"count_all" => 1, "firm_id" => "ABC"}])
172
+
173
+ firm = mock()
174
+ firm.expects(:id).returns("ABC")
175
+ firm.expects(:class).returns(Firm)
176
+ Company.expects(:find).with(["ABC"]).returns([firm])
177
+
178
+ column = mock()
179
+ column.expects(:name).at_least_once.returns(:firm_id)
180
+ column.expects(:type_cast).with("ABC").returns("ABC")
181
+ Account.expects(:columns).at_least_once.returns([column])
182
+
183
+ c = Account.count(:all, :group => :firm)
184
+ first_key = c.keys.first
185
+ assert_equal Firm, first_key.class
186
+ assert_equal 1, c[first_key]
187
+ end
188
+
189
+ def test_should_calculate_grouped_association_with_foreign_key_option
190
+ Account.belongs_to :another_firm, :class_name => 'Firm', :foreign_key => 'firm_id'
191
+ c = Account.count(:all, :group => :another_firm)
192
+ assert_equal 1, c[companies(:first_firm)]
193
+ assert_equal 2, c[companies(:rails_core)]
194
+ assert_equal 1, c[companies(:first_client)]
195
+ end
196
+
197
+ def test_should_not_modify_options_when_using_includes
198
+ options = {:conditions => 'companies.id > 1', :include => :firm}
199
+ options_copy = options.dup
200
+
201
+ Account.count(:all, options)
202
+ assert_equal options_copy, options
203
+ end
204
+
205
+ def test_should_calculate_grouped_by_function
206
+ c = Company.count(:all, :group => "UPPER(#{QUOTED_TYPE})")
207
+ assert_equal 2, c[nil]
208
+ assert_equal 1, c['DEPENDENTFIRM']
209
+ assert_equal 3, c['CLIENT']
210
+ assert_equal 2, c['FIRM']
211
+ end
212
+
213
+ def test_should_calculate_grouped_by_function_with_table_alias
214
+ c = Company.count(:all, :group => "UPPER(companies.#{QUOTED_TYPE})")
215
+ assert_equal 2, c[nil]
216
+ assert_equal 1, c['DEPENDENTFIRM']
217
+ assert_equal 3, c['CLIENT']
218
+ assert_equal 2, c['FIRM']
219
+ end
220
+
221
+ def test_should_not_overshadow_enumerable_sum
222
+ assert_equal 6, [1, 2, 3].sum(&:abs)
223
+ end
224
+
225
+ def test_should_sum_scoped_field
226
+ assert_equal 15, companies(:rails_core).companies.sum(:id)
227
+ end
228
+
229
+ def test_should_sum_scoped_field_with_conditions
230
+ assert_equal 8, companies(:rails_core).companies.sum(:id, :conditions => 'id > 7')
231
+ end
232
+
233
+ def test_should_group_by_scoped_field
234
+ c = companies(:rails_core).companies.sum(:id, :group => :name)
235
+ assert_equal 7, c['Leetsoft']
236
+ assert_equal 8, c['Jadedpixel']
237
+ end
238
+
239
+ def test_should_group_by_summed_field_with_conditions_and_having
240
+ c = companies(:rails_core).companies.sum(:id, :group => :name,
241
+ :having => 'sum(id) > 7')
242
+ assert_nil c['Leetsoft']
243
+ assert_equal 8, c['Jadedpixel']
244
+ end
245
+
246
+ def test_should_reject_invalid_options
247
+ assert_nothing_raised do
248
+ [:count, :sum].each do |func|
249
+ # empty options are valid
250
+ Company.send(:validate_calculation_options, func)
251
+ # these options are valid for all calculations
252
+ [:select, :conditions, :joins, :order, :group, :having, :distinct].each do |opt|
253
+ Company.send(:validate_calculation_options, func, opt => true)
254
+ end
255
+ end
256
+
257
+ # :include is only valid on :count
258
+ Company.send(:validate_calculation_options, :count, :include => true)
259
+ end
260
+
261
+ assert_raise(ArgumentError) { Company.send(:validate_calculation_options, :sum, :foo => :bar) }
262
+ assert_raise(ArgumentError) { Company.send(:validate_calculation_options, :count, :foo => :bar) }
263
+ end
264
+
265
+ def test_should_count_selected_field_with_include
266
+ assert_equal 6, Account.count(:distinct => true, :include => :firm)
267
+ assert_equal 4, Account.count(:distinct => true, :include => :firm, :select => :credit_limit)
268
+ end
269
+
270
+ def test_should_count_manual_select_with_include
271
+ assert_equal 6, Account.count(:select => "DISTINCT accounts.id", :include => :firm)
272
+ end
273
+
274
+ def test_count_with_column_parameter
275
+ assert_equal 5, Account.count(:firm_id)
276
+ end
277
+
278
+ def test_count_with_column_and_options_parameter
279
+ assert_equal 2, Account.count(:firm_id, :conditions => "credit_limit = 50")
280
+ end
281
+
282
+ def test_count_with_no_parameters_isnt_deprecated
283
+ assert_not_deprecated { Account.count }
284
+ end
285
+
286
+ def test_count_with_too_many_parameters_raises
287
+ assert_raise(ArgumentError) { Account.count(1, 2, 3) }
288
+ end
289
+
290
+ def test_count_with_scoped_has_many_through_association
291
+ assert_equal 1, owners(:blackbeard).toys.with_name('Bone').count
292
+ end
293
+
294
+ def test_should_sum_expression
295
+ if current_adapter?(:IBM_DBAdapter) && !ActiveRecord::Base.connection.servertype.class.name.include?('::IBM_IDS')
296
+ assert_equal 636, Account.sum("2 * credit_limit")
297
+ else
298
+ assert_equal '636', Account.sum("2 * credit_limit")
299
+ end
300
+ end
301
+
302
+ def test_count_with_from_option
303
+ assert_equal Company.count(:all), Company.count(:all, :from => 'companies')
304
+ assert_equal Account.count(:all, :conditions => "credit_limit = 50"),
305
+ Account.count(:all, :from => 'accounts', :conditions => "credit_limit = 50")
306
+ assert_equal Company.count(:type, :conditions => {:type => "Firm"}),
307
+ Company.count(:type, :conditions => {:type => "Firm"}, :from => 'companies')
308
+ end
309
+
310
+ def test_sum_with_from_option
311
+ assert_equal Account.sum(:credit_limit), Account.sum(:credit_limit, :from => 'accounts')
312
+ assert_equal Account.sum(:credit_limit, :conditions => "credit_limit > 50"),
313
+ Account.sum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
314
+ end
315
+
316
+ def test_average_with_from_option
317
+ assert_equal Account.average(:credit_limit), Account.average(:credit_limit, :from => 'accounts')
318
+ assert_equal Account.average(:credit_limit, :conditions => "credit_limit > 50"),
319
+ Account.average(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
320
+ end
321
+
322
+ def test_minimum_with_from_option
323
+ assert_equal Account.minimum(:credit_limit), Account.minimum(:credit_limit, :from => 'accounts')
324
+ assert_equal Account.minimum(:credit_limit, :conditions => "credit_limit > 50"),
325
+ Account.minimum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
326
+ end
327
+
328
+ def test_maximum_with_from_option
329
+ assert_equal Account.maximum(:credit_limit), Account.maximum(:credit_limit, :from => 'accounts')
330
+ assert_equal Account.maximum(:credit_limit, :conditions => "credit_limit > 50"),
331
+ Account.maximum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
332
+ end
333
+
334
+ def test_from_option_with_specified_index
335
+ if Edge.connection.adapter_name == 'MySQL'
336
+ assert_equal Edge.count(:all), Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)')
337
+ assert_equal Edge.count(:all, :conditions => 'sink_id < 5'),
338
+ Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)', :conditions => 'sink_id < 5')
339
+ end
340
+ end
341
+
342
+ def test_from_option_with_table_different_than_class
343
+ assert_equal Account.count(:all), Company.count(:all, :from => 'accounts')
344
+ end
345
+
346
+ end
@@ -0,0 +1,1092 @@
1
+ require "cases/helper"
2
+ require 'models/author'
3
+ require 'models/categorization'
4
+ require 'models/comment'
5
+ require 'models/company'
6
+ require 'models/topic'
7
+ require 'models/reply'
8
+ require 'models/entrant'
9
+ require 'models/developer'
10
+ require 'models/post'
11
+ require 'models/customer'
12
+ require 'models/job'
13
+ require 'models/categorization'
14
+
15
+ class DynamicFinderMatchTest < ActiveRecord::TestCase
16
+ def test_find_no_match
17
+ assert_nil ActiveRecord::DynamicFinderMatch.match("not_a_finder")
18
+ end
19
+
20
+ def test_find_by
21
+ match = ActiveRecord::DynamicFinderMatch.match("find_by_age_and_sex_and_location")
22
+ assert_not_nil match
23
+ assert match.finder?
24
+ assert_equal :first, match.finder
25
+ assert_equal %w(age sex location), match.attribute_names
26
+ end
27
+
28
+ def find_by_bang
29
+ match = ActiveRecord::DynamicFinderMatch.match("find_by_age_and_sex_and_location!")
30
+ assert_not_nil match
31
+ assert match.finder?
32
+ assert match.bang?
33
+ assert_equal :first, match.finder
34
+ assert_equal %w(age sex location), match.attribute_names
35
+ end
36
+
37
+ def test_find_all_by
38
+ match = ActiveRecord::DynamicFinderMatch.match("find_all_by_age_and_sex_and_location")
39
+ assert_not_nil match
40
+ assert match.finder?
41
+ assert_equal :all, match.finder
42
+ assert_equal %w(age sex location), match.attribute_names
43
+ end
44
+
45
+ def test_find_or_initialize_by
46
+ match = ActiveRecord::DynamicFinderMatch.match("find_or_initialize_by_age_and_sex_and_location")
47
+ assert_not_nil match
48
+ assert !match.finder?
49
+ assert match.instantiator?
50
+ assert_equal :first, match.finder
51
+ assert_equal :new, match.instantiator
52
+ assert_equal %w(age sex location), match.attribute_names
53
+ end
54
+
55
+ def test_find_or_create_by
56
+ match = ActiveRecord::DynamicFinderMatch.match("find_or_create_by_age_and_sex_and_location")
57
+ assert_not_nil match
58
+ assert !match.finder?
59
+ assert match.instantiator?
60
+ assert_equal :first, match.finder
61
+ assert_equal :create, match.instantiator
62
+ assert_equal %w(age sex location), match.attribute_names
63
+ end
64
+ end
65
+
66
+ class FinderTest < ActiveRecord::TestCase
67
+ fixtures :companies, :topics, :entrants, :developers, :developers_projects, :posts, :comments, :accounts, :authors, :customers
68
+
69
+ def test_find
70
+ assert_equal(topics(:first).title, Topic.find(1).title)
71
+ end
72
+
73
+ # find should handle strings that come from URLs
74
+ # (example: Category.find(params[:id]))
75
+ def test_find_with_string
76
+ assert_equal(Topic.find(1).title,Topic.find("1").title)
77
+ end
78
+
79
+ def test_exists
80
+ assert Topic.exists?(1)
81
+ assert Topic.exists?("1")
82
+ assert Topic.exists?(:author_name => "David")
83
+ assert Topic.exists?(:author_name => "Mary", :approved => true)
84
+ assert Topic.exists?(["parent_id = ?", 1])
85
+ assert !Topic.exists?(45)
86
+
87
+ begin
88
+ assert !Topic.exists?("foo")
89
+ rescue ActiveRecord::StatementInvalid
90
+ # PostgreSQL complains about string comparison with integer field
91
+ rescue Exception
92
+ flunk
93
+ end
94
+
95
+ assert_raise(NoMethodError) { Topic.exists?([1,2]) }
96
+ end
97
+
98
+ def test_exists_returns_true_with_one_record_and_no_args
99
+ assert Topic.exists?
100
+ end
101
+
102
+ def test_does_not_exist_with_empty_table_and_no_args_given
103
+ Topic.delete_all
104
+ assert !Topic.exists?
105
+ end
106
+
107
+ def test_exists_with_aggregate_having_three_mappings
108
+ existing_address = customers(:david).address
109
+ assert Customer.exists?(:address => existing_address)
110
+ end
111
+
112
+ def test_exists_with_aggregate_having_three_mappings_with_one_difference
113
+ existing_address = customers(:david).address
114
+ assert !Customer.exists?(:address =>
115
+ Address.new(existing_address.street, existing_address.city, existing_address.country + "1"))
116
+ assert !Customer.exists?(:address =>
117
+ Address.new(existing_address.street, existing_address.city + "1", existing_address.country))
118
+ assert !Customer.exists?(:address =>
119
+ Address.new(existing_address.street + "1", existing_address.city, existing_address.country))
120
+ end
121
+
122
+ def test_exists_with_scoped_include
123
+ Developer.with_scope(:find => { :include => :projects, :order => "projects.name" }) do
124
+ assert Developer.exists?
125
+ end
126
+ end
127
+
128
+ def test_find_by_array_of_one_id
129
+ assert_kind_of(Array, Topic.find([ 1 ]))
130
+ assert_equal(1, Topic.find([ 1 ]).length)
131
+ end
132
+
133
+ def test_find_by_ids
134
+ assert_equal 2, Topic.find(1, 2).size
135
+ assert_equal topics(:second).title, Topic.find([2]).first.title
136
+ end
137
+
138
+ def test_find_by_ids_with_limit_and_offset
139
+ assert_equal 2, Entrant.find([1,3,2], :limit => 2).size
140
+ assert_equal 1, Entrant.find([1,3,2], :limit => 3, :offset => 2).size
141
+
142
+ # Also test an edge case: If you have 11 results, and you set a
143
+ # limit of 3 and offset of 9, then you should find that there
144
+ # will be only 2 results, regardless of the limit.
145
+ devs = Developer.find :all
146
+ last_devs = Developer.find devs.map(&:id), :limit => 3, :offset => 9
147
+ assert_equal 2, last_devs.size
148
+ end
149
+
150
+ def test_find_an_empty_array
151
+ assert_equal [], Topic.find([])
152
+ end
153
+
154
+ def test_find_by_ids_missing_one
155
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, 2, 45) }
156
+ end
157
+
158
+ def test_find_all_with_limit
159
+ entrants = Entrant.find(:all, :order => "id ASC", :limit => 2)
160
+
161
+ assert_equal(2, entrants.size)
162
+ assert_equal(entrants(:first).name, entrants.first.name)
163
+ end
164
+
165
+ def test_find_all_with_prepared_limit_and_offset
166
+ entrants = Entrant.find(:all, :order => "id ASC", :limit => 2, :offset => 1)
167
+
168
+ assert_equal(2, entrants.size)
169
+ assert_equal(entrants(:second).name, entrants.first.name)
170
+
171
+ entrants = Entrant.find(:all, :order => "id ASC", :limit => 2, :offset => 2)
172
+ assert_equal(1, entrants.size)
173
+ assert_equal(entrants(:third).name, entrants.first.name)
174
+ end
175
+
176
+ def test_find_all_with_limit_and_offset_and_multiple_orderings
177
+ developers = Developer.find(:all, :order => "salary ASC, id DESC", :limit => 3, :offset => 1)
178
+ assert_equal ["David", "fixture_10", "fixture_9"], developers.collect {|d| d.name}
179
+ end
180
+
181
+ def test_find_with_limit_and_condition
182
+ developers = Developer.find(:all, :order => "id DESC", :conditions => "salary = 100000", :limit => 3, :offset =>7)
183
+ assert_equal(1, developers.size)
184
+ assert_equal("fixture_3", developers.first.name)
185
+ end
186
+
187
+ def test_find_with_group
188
+ developers = Developer.find(:all, :group => "salary", :select => "salary")
189
+ assert_equal 4, developers.size
190
+ assert_equal 4, developers.map(&:salary).uniq.size
191
+ end
192
+
193
+ def test_find_with_group_and_having
194
+ developers = Developer.find(:all, :group => "salary", :having => "sum(salary) > 10000", :select => "salary")
195
+ assert_equal 3, developers.size
196
+ assert_equal 3, developers.map(&:salary).uniq.size
197
+ assert developers.all? { |developer| developer.salary > 10000 }
198
+ end
199
+
200
+ def test_find_with_group_and_sanitized_having
201
+ developers = Developer.find(:all, :group => "salary", :having => ["sum(salary) > ?", 10000], :select => "salary")
202
+ assert_equal 3, developers.size
203
+ assert_equal 3, developers.map(&:salary).uniq.size
204
+ assert developers.all? { |developer| developer.salary > 10000 }
205
+ end
206
+
207
+ def test_find_with_entire_select_statement
208
+ topics = Topic.find_by_sql "SELECT * FROM topics WHERE author_name = 'Mary'"
209
+
210
+ assert_equal(1, topics.size)
211
+ assert_equal(topics(:second).title, topics.first.title)
212
+ end
213
+
214
+ def test_find_with_prepared_select_statement
215
+ topics = Topic.find_by_sql ["SELECT * FROM topics WHERE author_name = ?", "Mary"]
216
+
217
+ assert_equal(1, topics.size)
218
+ assert_equal(topics(:second).title, topics.first.title)
219
+ end
220
+
221
+ def test_find_by_sql_with_sti_on_joined_table
222
+ accounts = Account.find_by_sql("SELECT * FROM accounts INNER JOIN companies ON companies.id = accounts.firm_id")
223
+ assert_equal [Account], accounts.collect(&:class).uniq
224
+ end
225
+
226
+ def test_find_first
227
+ first = Topic.find(:first, :conditions => "title = 'The First Topic'")
228
+ assert_equal(topics(:first).title, first.title)
229
+ end
230
+
231
+ def test_find_first_failing
232
+ first = Topic.find(:first, :conditions => "title = 'The First Topic!'")
233
+ assert_nil(first)
234
+ end
235
+
236
+ def test_first
237
+ assert_equal topics(:second).title, Topic.first(:conditions => "title = 'The Second Topic of the day'").title
238
+ end
239
+
240
+ def test_first_failing
241
+ assert_nil Topic.first(:conditions => "title = 'The Second Topic of the day!'")
242
+ end
243
+
244
+ def test_unexisting_record_exception_handling
245
+ assert_raise(ActiveRecord::RecordNotFound) {
246
+ Topic.find(1).parent
247
+ }
248
+
249
+ Topic.find(2).topic
250
+ end
251
+
252
+ def test_find_only_some_columns
253
+ topic = Topic.find(1, :select => "author_name")
254
+ assert_raise(ActiveRecord::MissingAttributeError) {topic.title}
255
+ assert_equal "David", topic.author_name
256
+ assert !topic.attribute_present?("title")
257
+ #assert !topic.respond_to?("title")
258
+ assert topic.attribute_present?("author_name")
259
+ assert topic.respond_to?("author_name")
260
+ end
261
+
262
+ def test_find_on_blank_conditions
263
+ [nil, " ", [], {}].each do |blank|
264
+ assert_nothing_raised { Topic.find(:first, :conditions => blank) }
265
+ end
266
+ end
267
+
268
+ def test_find_on_blank_bind_conditions
269
+ [ [""], ["",{}] ].each do |blank|
270
+ assert_nothing_raised { Topic.find(:first, :conditions => blank) }
271
+ end
272
+ end
273
+
274
+ def test_find_on_array_conditions
275
+ assert Topic.find(1, :conditions => ["approved = ?", false])
276
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => ["approved = ?", true]) }
277
+ end
278
+
279
+ def test_find_on_hash_conditions
280
+ assert Topic.find(1, :conditions => { :approved => false })
281
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :approved => true }) }
282
+ end
283
+
284
+ def test_find_on_hash_conditions_with_explicit_table_name
285
+ assert Topic.find(1, :conditions => { 'topics.approved' => false })
286
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { 'topics.approved' => true }) }
287
+ end
288
+
289
+ def test_find_on_hash_conditions_with_hashed_table_name
290
+ assert Topic.find(1, :conditions => {:topics => { :approved => false }})
291
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => {:topics => { :approved => true }}) }
292
+ end
293
+
294
+ def test_find_with_hash_conditions_on_joined_table
295
+ firms = Firm.all :joins => :account, :conditions => {:accounts => { :credit_limit => 50 }}
296
+ assert_equal 1, firms.size
297
+ assert_equal companies(:first_firm), firms.first
298
+ end
299
+
300
+ def test_find_with_hash_conditions_on_joined_table_and_with_range
301
+ firms = DependentFirm.all :joins => :account, :conditions => {:name => 'RailsCore', :accounts => { :credit_limit => 55..60 }}
302
+ assert_equal 1, firms.size
303
+ assert_equal companies(:rails_core), firms.first
304
+ end
305
+
306
+ def test_find_on_hash_conditions_with_explicit_table_name_and_aggregate
307
+ david = customers(:david)
308
+ assert Customer.find(david.id, :conditions => { 'customers.name' => david.name, :address => david.address })
309
+ assert_raise(ActiveRecord::RecordNotFound) {
310
+ Customer.find(david.id, :conditions => { 'customers.name' => david.name + "1", :address => david.address })
311
+ }
312
+ end
313
+
314
+ def test_find_on_association_proxy_conditions
315
+ assert_equal [1, 2, 3, 5, 6, 7, 8, 9, 10], Comment.find_all_by_post_id(authors(:david).posts).map(&:id).sort
316
+ end
317
+
318
+ def test_find_on_hash_conditions_with_range
319
+ assert_equal [1,2], Topic.find(:all, :conditions => { :id => 1..2 }).map(&:id).sort
320
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :id => 2..3 }) }
321
+ end
322
+
323
+ def test_find_on_hash_conditions_with_end_exclusive_range
324
+ assert_equal [1,2,3], Topic.find(:all, :conditions => { :id => 1..3 }).map(&:id).sort
325
+ assert_equal [1,2], Topic.find(:all, :conditions => { :id => 1...3 }).map(&:id).sort
326
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.find(3, :conditions => { :id => 2...3 }) }
327
+ end
328
+
329
+ def test_find_on_hash_conditions_with_multiple_ranges
330
+ assert_equal [1,2,3], Comment.find(:all, :conditions => { :id => 1..3, :post_id => 1..2 }).map(&:id).sort
331
+ assert_equal [1], Comment.find(:all, :conditions => { :id => 1..1, :post_id => 1..10 }).map(&:id).sort
332
+ end
333
+
334
+ def test_find_on_multiple_hash_conditions
335
+ assert Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => false })
336
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }) }
337
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "HHC", :replies_count => 1, :approved => false }) }
338
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }) }
339
+ end
340
+
341
+
342
+ def test_condition_interpolation
343
+ assert_kind_of Firm, Company.find(:first, :conditions => ["name = '%s'", "37signals"])
344
+ assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!"])
345
+ assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!' OR 1=1"])
346
+ assert_kind_of Time, Topic.find(:first, :conditions => ["id = %d", 1]).written_on
347
+ end
348
+
349
+ def test_condition_array_interpolation
350
+ assert_kind_of Firm, Company.find(:first, :conditions => ["name = '%s'", "37signals"])
351
+ assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!"])
352
+ assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!' OR 1=1"])
353
+ assert_kind_of Time, Topic.find(:first, :conditions => ["id = %d", 1]).written_on
354
+ end
355
+
356
+ def test_condition_hash_interpolation
357
+ assert_kind_of Firm, Company.find(:first, :conditions => { :name => "37signals"})
358
+ assert_nil Company.find(:first, :conditions => { :name => "37signals!"})
359
+ assert_kind_of Time, Topic.find(:first, :conditions => {:id => 1}).written_on
360
+ end
361
+
362
+ def test_hash_condition_find_malformed
363
+ assert_raise(ActiveRecord::StatementInvalid) {
364
+ Company.find(:first, :conditions => { :id => 2, :dhh => true })
365
+ }
366
+ end
367
+
368
+ def test_hash_condition_find_with_escaped_characters
369
+ Company.create("name" => "Ain't noth'n like' \#stuff")
370
+ assert Company.find(:first, :conditions => { :name => "Ain't noth'n like' \#stuff" })
371
+ end
372
+
373
+ def test_hash_condition_find_with_array
374
+ p1, p2 = Post.find(:all, :limit => 2, :order => 'id asc')
375
+ assert_equal [p1, p2], Post.find(:all, :conditions => { :id => [p1, p2] }, :order => 'id asc')
376
+ assert_equal [p1, p2], Post.find(:all, :conditions => { :id => [p1, p2.id] }, :order => 'id asc')
377
+ end
378
+
379
+ def test_hash_condition_find_with_nil
380
+ topic = Topic.find(:first, :conditions => { :last_read => nil } )
381
+ assert_not_nil topic
382
+ assert_nil topic.last_read
383
+ end
384
+
385
+ def test_hash_condition_find_with_aggregate_having_one_mapping
386
+ balance = customers(:david).balance
387
+ assert_kind_of Money, balance
388
+ found_customer = Customer.find(:first, :conditions => {:balance => balance})
389
+ assert_equal customers(:david), found_customer
390
+ end
391
+
392
+ def test_hash_condition_find_with_aggregate_attribute_having_same_name_as_field_and_key_value_being_aggregate
393
+ gps_location = customers(:david).gps_location
394
+ assert_kind_of GpsLocation, gps_location
395
+ found_customer = Customer.find(:first, :conditions => {:gps_location => gps_location})
396
+ assert_equal customers(:david), found_customer
397
+ end
398
+
399
+ def test_hash_condition_find_with_aggregate_having_one_mapping_and_key_value_being_attribute_value
400
+ balance = customers(:david).balance
401
+ assert_kind_of Money, balance
402
+ found_customer = Customer.find(:first, :conditions => {:balance => balance.amount})
403
+ assert_equal customers(:david), found_customer
404
+ end
405
+
406
+ def test_hash_condition_find_with_aggregate_attribute_having_same_name_as_field_and_key_value_being_attribute_value
407
+ gps_location = customers(:david).gps_location
408
+ assert_kind_of GpsLocation, gps_location
409
+ found_customer = Customer.find(:first, :conditions => {:gps_location => gps_location.gps_location})
410
+ assert_equal customers(:david), found_customer
411
+ end
412
+
413
+ def test_hash_condition_find_with_aggregate_having_three_mappings
414
+ address = customers(:david).address
415
+ assert_kind_of Address, address
416
+ found_customer = Customer.find(:first, :conditions => {:address => address})
417
+ assert_equal customers(:david), found_customer
418
+ end
419
+
420
+ def test_hash_condition_find_with_one_condition_being_aggregate_and_another_not
421
+ address = customers(:david).address
422
+ assert_kind_of Address, address
423
+ found_customer = Customer.find(:first, :conditions => {:address => address, :name => customers(:david).name})
424
+ assert_equal customers(:david), found_customer
425
+ end
426
+
427
+ def test_bind_variables
428
+ assert_kind_of Firm, Company.find(:first, :conditions => ["name = ?", "37signals"])
429
+ assert_nil Company.find(:first, :conditions => ["name = ?", "37signals!"])
430
+ assert_nil Company.find(:first, :conditions => ["name = ?", "37signals!' OR 1=1"])
431
+ assert_kind_of Time, Topic.find(:first, :conditions => ["id = ?", 1]).written_on
432
+ assert_raise(ActiveRecord::PreparedStatementInvalid) {
433
+ Company.find(:first, :conditions => ["id=? AND name = ?", 2])
434
+ }
435
+ assert_raise(ActiveRecord::PreparedStatementInvalid) {
436
+ Company.find(:first, :conditions => ["id=?", 2, 3, 4])
437
+ }
438
+ end
439
+
440
+ def test_bind_variables_with_quotes
441
+ Company.create("name" => "37signals' go'es agains")
442
+ assert Company.find(:first, :conditions => ["name = ?", "37signals' go'es agains"])
443
+ end
444
+
445
+ def test_named_bind_variables_with_quotes
446
+ Company.create("name" => "37signals' go'es agains")
447
+ assert Company.find(:first, :conditions => ["name = :name", {:name => "37signals' go'es agains"}])
448
+ end
449
+
450
+ def test_bind_arity
451
+ assert_nothing_raised { bind '' }
452
+ assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '', 1 }
453
+
454
+ assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '?' }
455
+ assert_nothing_raised { bind '?', 1 }
456
+ assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '?', 1, 1 }
457
+ end
458
+
459
+ def test_named_bind_variables
460
+ assert_equal '1', bind(':a', :a => 1) # ' ruby-mode
461
+ assert_equal '1 1', bind(':a :a', :a => 1) # ' ruby-mode
462
+
463
+ assert_nothing_raised { bind("'+00:00'", :foo => "bar") }
464
+
465
+ assert_kind_of Firm, Company.find(:first, :conditions => ["name = :name", { :name => "37signals" }])
466
+ assert_nil Company.find(:first, :conditions => ["name = :name", { :name => "37signals!" }])
467
+ assert_nil Company.find(:first, :conditions => ["name = :name", { :name => "37signals!' OR 1=1" }])
468
+ assert_kind_of Time, Topic.find(:first, :conditions => ["id = :id", { :id => 1 }]).written_on
469
+ end
470
+
471
+ def test_bind_enumerable
472
+ quoted_abc = %(#{ActiveRecord::Base.connection.quote('a')},#{ActiveRecord::Base.connection.quote('b')},#{ActiveRecord::Base.connection.quote('c')})
473
+
474
+ assert_equal '1,2,3', bind('?', [1, 2, 3])
475
+ assert_equal quoted_abc, bind('?', %w(a b c))
476
+
477
+ assert_equal '1,2,3', bind(':a', :a => [1, 2, 3])
478
+ assert_equal quoted_abc, bind(':a', :a => %w(a b c)) # '
479
+
480
+ require 'set'
481
+ assert_equal '1,2,3', bind('?', Set.new([1, 2, 3]))
482
+ assert_equal quoted_abc, bind('?', Set.new(%w(a b c)))
483
+
484
+ assert_equal '1,2,3', bind(':a', :a => Set.new([1, 2, 3]))
485
+ assert_equal quoted_abc, bind(':a', :a => Set.new(%w(a b c))) # '
486
+ end
487
+
488
+ def test_bind_empty_enumerable
489
+ quoted_nil = ActiveRecord::Base.connection.quote(nil)
490
+ assert_equal quoted_nil, bind('?', [])
491
+ assert_equal " in (#{quoted_nil})", bind(' in (?)', [])
492
+ assert_equal "foo in (#{quoted_nil})", bind('foo in (?)', [])
493
+ end
494
+
495
+ def test_bind_string
496
+ assert_equal ActiveRecord::Base.connection.quote(''), bind('?', '')
497
+ end
498
+
499
+ def test_bind_chars
500
+ quoted_bambi = ActiveRecord::Base.connection.quote("Bambi")
501
+ quoted_bambi_and_thumper = ActiveRecord::Base.connection.quote("Bambi\nand\nThumper")
502
+ assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi")
503
+ assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper")
504
+ assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi".mb_chars)
505
+ assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper".mb_chars)
506
+ end
507
+
508
+ def test_bind_record
509
+ o = Struct.new(:quoted_id).new(1)
510
+ assert_equal '1', bind('?', o)
511
+
512
+ os = [o] * 3
513
+ assert_equal '1,1,1', bind('?', os)
514
+ end
515
+
516
+ def test_named_bind_with_postgresql_type_casts
517
+ l = Proc.new { bind(":a::integer '2009-01-01'::date", :a => '10') }
518
+ assert_nothing_raised(&l)
519
+ assert_equal "#{ActiveRecord::Base.quote_value('10')}::integer '2009-01-01'::date", l.call
520
+ end
521
+
522
+ def test_string_sanitation
523
+ assert_not_equal "#{ActiveRecord::Base.connection.quoted_string_prefix}'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1")
524
+ assert_equal "#{ActiveRecord::Base.connection.quoted_string_prefix}'something; select table'", ActiveRecord::Base.sanitize("something; select table")
525
+ end
526
+
527
+ def test_count
528
+ assert_equal(0, Entrant.count(:conditions => "id > 3"))
529
+ assert_equal(1, Entrant.count(:conditions => ["id > ?", 2]))
530
+ assert_equal(2, Entrant.count(:conditions => ["id > ?", 1]))
531
+ end
532
+
533
+ def test_count_by_sql
534
+ assert_equal(0, Entrant.count_by_sql("SELECT COUNT(*) FROM entrants WHERE id > 3"))
535
+ assert_equal(1, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 2]))
536
+ assert_equal(2, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 1]))
537
+ end
538
+
539
+ def test_dynamic_finders_should_go_through_the_find_class_method
540
+ Topic.expects(:find).with(:first, :conditions => { :title => 'The First Topic!' })
541
+ Topic.find_by_title("The First Topic!")
542
+
543
+ Topic.expects(:find).with(:last, :conditions => { :title => 'The Last Topic!' })
544
+ Topic.find_last_by_title("The Last Topic!")
545
+
546
+ Topic.expects(:find).with(:all, :conditions => { :title => 'A Topic.' })
547
+ Topic.find_all_by_title("A Topic.")
548
+
549
+ Topic.expects(:find).with(:first, :conditions => { :title => 'Does not exist yet for sure!' }).times(2)
550
+ Topic.find_or_initialize_by_title('Does not exist yet for sure!')
551
+ Topic.find_or_create_by_title('Does not exist yet for sure!')
552
+ end
553
+
554
+ def test_find_by_one_attribute
555
+ assert_equal topics(:first), Topic.find_by_title("The First Topic")
556
+ assert_nil Topic.find_by_title("The First Topic!")
557
+ end
558
+
559
+ def test_find_by_one_attribute_bang
560
+ assert_equal topics(:first), Topic.find_by_title!("The First Topic")
561
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.find_by_title!("The First Topic!") }
562
+ end
563
+
564
+ def test_find_by_one_attribute_caches_dynamic_finder
565
+ # ensure this test can run independently of order
566
+ class << Topic; self; end.send(:remove_method, :find_by_title) if Topic.public_methods.any? { |m| m.to_s == 'find_by_title' }
567
+ assert !Topic.public_methods.any? { |m| m.to_s == 'find_by_title' }
568
+ t = Topic.find_by_title("The First Topic")
569
+ assert Topic.public_methods.any? { |m| m.to_s == 'find_by_title' }
570
+ end
571
+
572
+ def test_dynamic_finder_returns_same_results_after_caching
573
+ # ensure this test can run independently of order
574
+ class << Topic; self; end.send(:remove_method, :find_by_title) if Topic.public_method_defined?(:find_by_title)
575
+ t = Topic.find_by_title("The First Topic")
576
+ assert_equal t, Topic.find_by_title("The First Topic") # find_by_title has been cached
577
+ end
578
+
579
+ def test_find_by_one_attribute_with_order_option
580
+ assert_equal accounts(:signals37), Account.find_by_credit_limit(50, :order => 'id')
581
+ assert_equal accounts(:rails_core_account), Account.find_by_credit_limit(50, :order => 'id DESC')
582
+ end
583
+
584
+ def test_find_by_one_attribute_with_conditions
585
+ assert_equal accounts(:rails_core_account), Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6])
586
+ end
587
+
588
+ def test_find_by_one_attribute_that_is_an_aggregate
589
+ address = customers(:david).address
590
+ assert_kind_of Address, address
591
+ found_customer = Customer.find_by_address(address)
592
+ assert_equal customers(:david), found_customer
593
+ end
594
+
595
+ def test_find_by_one_attribute_that_is_an_aggregate_with_one_attribute_difference
596
+ address = customers(:david).address
597
+ assert_kind_of Address, address
598
+ missing_address = Address.new(address.street, address.city, address.country + "1")
599
+ assert_nil Customer.find_by_address(missing_address)
600
+ missing_address = Address.new(address.street, address.city + "1", address.country)
601
+ assert_nil Customer.find_by_address(missing_address)
602
+ missing_address = Address.new(address.street + "1", address.city, address.country)
603
+ assert_nil Customer.find_by_address(missing_address)
604
+ end
605
+
606
+ def test_find_by_two_attributes_that_are_both_aggregates
607
+ balance = customers(:david).balance
608
+ address = customers(:david).address
609
+ assert_kind_of Money, balance
610
+ assert_kind_of Address, address
611
+ found_customer = Customer.find_by_balance_and_address(balance, address)
612
+ assert_equal customers(:david), found_customer
613
+ end
614
+
615
+ def test_find_by_two_attributes_with_one_being_an_aggregate
616
+ balance = customers(:david).balance
617
+ assert_kind_of Money, balance
618
+ found_customer = Customer.find_by_balance_and_name(balance, customers(:david).name)
619
+ assert_equal customers(:david), found_customer
620
+ end
621
+
622
+ def test_dynamic_finder_on_one_attribute_with_conditions_caches_method
623
+ # ensure this test can run independently of order
624
+ class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.public_methods.any? { |m| m.to_s == 'find_by_credit_limit' }
625
+ assert !Account.public_methods.any? { |m| m.to_s == 'find_by_credit_limit' }
626
+ a = Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6])
627
+ assert Account.public_methods.any? { |m| m.to_s == 'find_by_credit_limit' }
628
+ end
629
+
630
+ def test_dynamic_finder_on_one_attribute_with_conditions_returns_same_results_after_caching
631
+ # ensure this test can run independently of order
632
+ class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.public_methods.any? { |m| m.to_s == 'find_by_credit_limit' }
633
+ a = Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6])
634
+ assert_equal a, Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6]) # find_by_credit_limit has been cached
635
+ end
636
+
637
+ def test_find_by_one_attribute_with_several_options
638
+ assert_equal accounts(:unknown), Account.find_by_credit_limit(50, :order => 'id DESC', :conditions => ['id != ?', 3])
639
+ end
640
+
641
+ def test_find_by_one_missing_attribute
642
+ assert_raise(NoMethodError) { Topic.find_by_undertitle("The First Topic!") }
643
+ end
644
+
645
+ def test_find_by_invalid_method_syntax
646
+ assert_raise(NoMethodError) { Topic.fail_to_find_by_title("The First Topic") }
647
+ assert_raise(NoMethodError) { Topic.find_by_title?("The First Topic") }
648
+ assert_raise(NoMethodError) { Topic.fail_to_find_or_create_by_title("Nonexistent Title") }
649
+ assert_raise(NoMethodError) { Topic.find_or_create_by_title?("Nonexistent Title") }
650
+ end
651
+
652
+ def test_find_by_two_attributes
653
+ assert_equal topics(:first), Topic.find_by_title_and_author_name("The First Topic", "David")
654
+ assert_nil Topic.find_by_title_and_author_name("The First Topic", "Mary")
655
+ end
656
+
657
+ def test_find_last_by_one_attribute
658
+ assert_equal Topic.last, Topic.find_last_by_title(Topic.last.title)
659
+ assert_nil Topic.find_last_by_title("A title with no matches")
660
+ end
661
+
662
+ def test_find_last_by_one_attribute_caches_dynamic_finder
663
+ # ensure this test can run independently of order
664
+ class << Topic; self; end.send(:remove_method, :find_last_by_title) if Topic.public_methods.any? { |m| m.to_s == 'find_last_by_title' }
665
+ assert !Topic.public_methods.any? { |m| m.to_s == 'find_last_by_title' }
666
+ t = Topic.find_last_by_title(Topic.last.title)
667
+ assert Topic.public_methods.any? { |m| m.to_s == 'find_last_by_title' }
668
+ end
669
+
670
+ def test_find_last_by_invalid_method_syntax
671
+ assert_raise(NoMethodError) { Topic.fail_to_find_last_by_title("The First Topic") }
672
+ assert_raise(NoMethodError) { Topic.find_last_by_title?("The First Topic") }
673
+ end
674
+
675
+ def test_find_last_by_one_attribute_with_several_options
676
+ assert_equal accounts(:signals37), Account.find_last_by_credit_limit(50, :order => 'id DESC', :conditions => ['id != ?', 3])
677
+ end
678
+
679
+ def test_find_last_by_one_missing_attribute
680
+ assert_raise(NoMethodError) { Topic.find_last_by_undertitle("The Last Topic!") }
681
+ end
682
+
683
+ def test_find_last_by_two_attributes
684
+ topic = Topic.last
685
+ assert_equal topic, Topic.find_last_by_title_and_author_name(topic.title, topic.author_name)
686
+ assert_nil Topic.find_last_by_title_and_author_name(topic.title, "Anonymous")
687
+ end
688
+
689
+ def test_find_all_by_one_attribute
690
+ topics = Topic.find_all_by_content("Have a nice day")
691
+ assert_equal 2, topics.size
692
+ assert topics.include?(topics(:first))
693
+
694
+ assert_equal [], Topic.find_all_by_title("The First Topic!!")
695
+ end
696
+
697
+ def test_find_all_by_one_attribute_that_is_an_aggregate
698
+ balance = customers(:david).balance
699
+ assert_kind_of Money, balance
700
+ found_customers = Customer.find_all_by_balance(balance)
701
+ assert_equal 1, found_customers.size
702
+ assert_equal customers(:david), found_customers.first
703
+ end
704
+
705
+ def test_find_all_by_two_attributes_that_are_both_aggregates
706
+ balance = customers(:david).balance
707
+ address = customers(:david).address
708
+ assert_kind_of Money, balance
709
+ assert_kind_of Address, address
710
+ found_customers = Customer.find_all_by_balance_and_address(balance, address)
711
+ assert_equal 1, found_customers.size
712
+ assert_equal customers(:david), found_customers.first
713
+ end
714
+
715
+ def test_find_all_by_two_attributes_with_one_being_an_aggregate
716
+ balance = customers(:david).balance
717
+ assert_kind_of Money, balance
718
+ found_customers = Customer.find_all_by_balance_and_name(balance, customers(:david).name)
719
+ assert_equal 1, found_customers.size
720
+ assert_equal customers(:david), found_customers.first
721
+ end
722
+
723
+ def test_find_all_by_one_attribute_with_options
724
+ topics = Topic.find_all_by_content("Have a nice day", :order => "id DESC")
725
+ assert topics(:first), topics.last
726
+
727
+ topics = Topic.find_all_by_content("Have a nice day", :order => "id")
728
+ assert topics(:first), topics.first
729
+ end
730
+
731
+ def test_find_all_by_array_attribute
732
+ assert_equal 2, Topic.find_all_by_title(["The First Topic", "The Second Topic of the day"]).size
733
+ end
734
+
735
+ def test_find_all_by_boolean_attribute
736
+ topics = Topic.find_all_by_approved(false)
737
+ assert_equal 1, topics.size
738
+ assert topics.include?(topics(:first))
739
+
740
+ topics = Topic.find_all_by_approved(true)
741
+ assert_equal 3, topics.size
742
+ assert topics.include?(topics(:second))
743
+ end
744
+
745
+ def test_find_by_nil_attribute
746
+ topic = Topic.find_by_last_read nil
747
+ assert_not_nil topic
748
+ assert_nil topic.last_read
749
+ end
750
+
751
+ def test_find_all_by_nil_attribute
752
+ topics = Topic.find_all_by_last_read nil
753
+ assert_equal 3, topics.size
754
+ assert topics.collect(&:last_read).all?(&:nil?)
755
+ end
756
+
757
+ def test_find_by_nil_and_not_nil_attributes
758
+ topic = Topic.find_by_last_read_and_author_name nil, "Mary"
759
+ assert_equal "Mary", topic.author_name
760
+ end
761
+
762
+ def test_find_all_by_nil_and_not_nil_attributes
763
+ topics = Topic.find_all_by_last_read_and_author_name nil, "Mary"
764
+ assert_equal 1, topics.size
765
+ assert_equal "Mary", topics[0].author_name
766
+ end
767
+
768
+ def test_find_or_create_from_one_attribute
769
+ number_of_companies = Company.count
770
+ sig38 = Company.find_or_create_by_name("38signals")
771
+ assert_equal number_of_companies + 1, Company.count
772
+ assert_equal sig38, Company.find_or_create_by_name("38signals")
773
+ assert !sig38.new_record?
774
+ end
775
+
776
+ def test_find_or_create_from_two_attributes
777
+ number_of_topics = Topic.count
778
+ another = Topic.find_or_create_by_title_and_author_name("Another topic","John")
779
+ assert_equal number_of_topics + 1, Topic.count
780
+ assert_equal another, Topic.find_or_create_by_title_and_author_name("Another topic", "John")
781
+ assert !another.new_record?
782
+ end
783
+
784
+ def test_find_or_create_from_two_attributes_with_one_being_an_aggregate
785
+ number_of_customers = Customer.count
786
+ created_customer = Customer.find_or_create_by_balance_and_name(Money.new(123), "Elizabeth")
787
+ assert_equal number_of_customers + 1, Customer.count
788
+ assert_equal created_customer, Customer.find_or_create_by_balance(Money.new(123), "Elizabeth")
789
+ assert !created_customer.new_record?
790
+ end
791
+
792
+ def test_find_or_create_from_one_attribute_and_hash
793
+ number_of_companies = Company.count
794
+ sig38 = Company.find_or_create_by_name({:name => "38signals", :firm_id => 17, :client_of => 23})
795
+ assert_equal number_of_companies + 1, Company.count
796
+ assert_equal sig38, Company.find_or_create_by_name({:name => "38signals", :firm_id => 17, :client_of => 23})
797
+ assert !sig38.new_record?
798
+ assert_equal "38signals", sig38.name
799
+ assert_equal 17, sig38.firm_id
800
+ assert_equal 23, sig38.client_of
801
+ end
802
+
803
+ def test_find_or_create_from_one_aggregate_attribute
804
+ number_of_customers = Customer.count
805
+ created_customer = Customer.find_or_create_by_balance(Money.new(123))
806
+ assert_equal number_of_customers + 1, Customer.count
807
+ assert_equal created_customer, Customer.find_or_create_by_balance(Money.new(123))
808
+ assert !created_customer.new_record?
809
+ end
810
+
811
+ def test_find_or_create_from_one_aggregate_attribute_and_hash
812
+ number_of_customers = Customer.count
813
+ balance = Money.new(123)
814
+ name = "Elizabeth"
815
+ created_customer = Customer.find_or_create_by_balance({:balance => balance, :name => name})
816
+ assert_equal number_of_customers + 1, Customer.count
817
+ assert_equal created_customer, Customer.find_or_create_by_balance({:balance => balance, :name => name})
818
+ assert !created_customer.new_record?
819
+ assert_equal balance, created_customer.balance
820
+ assert_equal name, created_customer.name
821
+ end
822
+
823
+ def test_find_or_initialize_from_one_attribute
824
+ sig38 = Company.find_or_initialize_by_name("38signals")
825
+ assert_equal "38signals", sig38.name
826
+ assert sig38.new_record?
827
+ end
828
+
829
+ def test_find_or_initialize_from_one_aggregate_attribute
830
+ new_customer = Customer.find_or_initialize_by_balance(Money.new(123))
831
+ assert_equal 123, new_customer.balance.amount
832
+ assert new_customer.new_record?
833
+ end
834
+
835
+ def test_find_or_initialize_from_one_attribute_should_not_set_attribute_even_when_protected
836
+ c = Company.find_or_initialize_by_name({:name => "Fortune 1000", :rating => 1000})
837
+ assert_equal "Fortune 1000", c.name
838
+ assert_not_equal 1000, c.rating
839
+ assert c.valid?
840
+ assert c.new_record?
841
+ end
842
+
843
+ def test_find_or_create_from_one_attribute_should_set_not_attribute_even_when_protected
844
+ c = Company.find_or_create_by_name({:name => "Fortune 1000", :rating => 1000})
845
+ assert_equal "Fortune 1000", c.name
846
+ assert_not_equal 1000, c.rating
847
+ assert c.valid?
848
+ assert !c.new_record?
849
+ end
850
+
851
+ def test_find_or_initialize_from_one_attribute_should_set_attribute_even_when_protected
852
+ c = Company.find_or_initialize_by_name_and_rating("Fortune 1000", 1000)
853
+ assert_equal "Fortune 1000", c.name
854
+ assert_equal 1000, c.rating
855
+ assert c.valid?
856
+ assert c.new_record?
857
+ end
858
+
859
+ def test_find_or_create_from_one_attribute_should_set_attribute_even_when_protected
860
+ c = Company.find_or_create_by_name_and_rating("Fortune 1000", 1000)
861
+ assert_equal "Fortune 1000", c.name
862
+ assert_equal 1000, c.rating
863
+ assert c.valid?
864
+ assert !c.new_record?
865
+ end
866
+
867
+ def test_find_or_initialize_should_set_protected_attributes_if_given_as_block
868
+ c = Company.find_or_initialize_by_name(:name => "Fortune 1000") { |f| f.rating = 1000 }
869
+ assert_equal "Fortune 1000", c.name
870
+ assert_equal 1000.to_f, c.rating.to_f
871
+ assert c.valid?
872
+ assert c.new_record?
873
+ end
874
+
875
+ def test_find_or_create_should_set_protected_attributes_if_given_as_block
876
+ c = Company.find_or_create_by_name(:name => "Fortune 1000") { |f| f.rating = 1000 }
877
+ assert_equal "Fortune 1000", c.name
878
+ assert_equal 1000.to_f, c.rating.to_f
879
+ assert c.valid?
880
+ assert !c.new_record?
881
+ end
882
+
883
+ def test_find_or_create_should_work_with_block_on_first_call
884
+ class << Company
885
+ undef_method(:find_or_create_by_name) if method_defined?(:find_or_create_by_name)
886
+ end
887
+ c = Company.find_or_create_by_name(:name => "Fortune 1000") { |f| f.rating = 1000 }
888
+ assert_equal "Fortune 1000", c.name
889
+ assert_equal 1000.to_f, c.rating.to_f
890
+ assert c.valid?
891
+ assert !c.new_record?
892
+ end
893
+
894
+ def test_dynamic_find_or_initialize_from_one_attribute_caches_method
895
+ class << Company; self; end.send(:remove_method, :find_or_initialize_by_name) if Company.public_methods.any? { |m| m.to_s == 'find_or_initialize_by_name' }
896
+ assert !Company.public_methods.any? { |m| m.to_s == 'find_or_initialize_by_name' }
897
+ sig38 = Company.find_or_initialize_by_name("38signals")
898
+ assert Company.public_methods.any? { |m| m.to_s == 'find_or_initialize_by_name' }
899
+ end
900
+
901
+ def test_find_or_initialize_from_two_attributes
902
+ another = Topic.find_or_initialize_by_title_and_author_name("Another topic","John")
903
+ assert_equal "Another topic", another.title
904
+ assert_equal "John", another.author_name
905
+ assert another.new_record?
906
+ end
907
+
908
+ def test_find_or_initialize_from_one_aggregate_attribute_and_one_not
909
+ new_customer = Customer.find_or_initialize_by_balance_and_name(Money.new(123), "Elizabeth")
910
+ assert_equal 123, new_customer.balance.amount
911
+ assert_equal "Elizabeth", new_customer.name
912
+ assert new_customer.new_record?
913
+ end
914
+
915
+ def test_find_or_initialize_from_one_attribute_and_hash
916
+ sig38 = Company.find_or_initialize_by_name({:name => "38signals", :firm_id => 17, :client_of => 23})
917
+ assert_equal "38signals", sig38.name
918
+ assert_equal 17, sig38.firm_id
919
+ assert_equal 23, sig38.client_of
920
+ assert sig38.new_record?
921
+ end
922
+
923
+ def test_find_or_initialize_from_one_aggregate_attribute_and_hash
924
+ balance = Money.new(123)
925
+ name = "Elizabeth"
926
+ new_customer = Customer.find_or_initialize_by_balance({:balance => balance, :name => name})
927
+ assert_equal balance, new_customer.balance
928
+ assert_equal name, new_customer.name
929
+ assert new_customer.new_record?
930
+ end
931
+
932
+ def test_find_with_bad_sql
933
+ assert_raise(ActiveRecord::StatementInvalid) { Topic.find_by_sql "select 1 from badtable" }
934
+ end
935
+
936
+ def test_find_with_invalid_params
937
+ assert_raise(ArgumentError) { Topic.find :first, :join => "It should be `joins'" }
938
+ assert_raise(ArgumentError) { Topic.find :first, :conditions => '1 = 1', :join => "It should be `joins'" }
939
+ end
940
+
941
+ def test_dynamic_finder_with_invalid_params
942
+ assert_raise(ArgumentError) { Topic.find_by_title 'No Title', :join => "It should be `joins'" }
943
+ end
944
+
945
+ def test_find_all_with_limit
946
+ first_five_developers = Developer.find :all, :order => 'id ASC', :limit => 5
947
+ assert_equal 5, first_five_developers.length
948
+ assert_equal 'David', first_five_developers.first.name
949
+ assert_equal 'fixture_5', first_five_developers.last.name
950
+
951
+ no_developers = Developer.find :all, :order => 'id ASC', :limit => 0
952
+ assert_equal 0, no_developers.length
953
+ end
954
+
955
+ def test_find_all_with_limit_and_offset
956
+ first_three_developers = Developer.find :all, :order => 'id ASC', :limit => 3, :offset => 0
957
+ second_three_developers = Developer.find :all, :order => 'id ASC', :limit => 3, :offset => 3
958
+ last_two_developers = Developer.find :all, :order => 'id ASC', :limit => 2, :offset => 8
959
+
960
+ assert_equal 3, first_three_developers.length
961
+ assert_equal 3, second_three_developers.length
962
+ assert_equal 2, last_two_developers.length
963
+
964
+ assert_equal 'David', first_three_developers.first.name
965
+ assert_equal 'fixture_4', second_three_developers.first.name
966
+ assert_equal 'fixture_9', last_two_developers.first.name
967
+ end
968
+
969
+ def test_find_all_with_limit_and_offset_and_multiple_order_clauses
970
+ first_three_posts = Post.find :all, :order => 'author_id, id', :limit => 3, :offset => 0
971
+ second_three_posts = Post.find :all, :order => ' author_id,id ', :limit => 3, :offset => 3
972
+ last_posts = Post.find :all, :order => ' author_id, id ', :limit => 3, :offset => 6
973
+
974
+ assert_equal [[0,3],[1,1],[1,2]], first_three_posts.map { |p| [p.author_id, p.id] }
975
+ assert_equal [[1,4],[1,5],[1,6]], second_three_posts.map { |p| [p.author_id, p.id] }
976
+ assert_equal [[2,7]], last_posts.map { |p| [p.author_id, p.id] }
977
+ end
978
+
979
+ def test_find_all_with_join
980
+ developers_on_project_one = Developer.find(
981
+ :all,
982
+ :joins => 'LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id',
983
+ :conditions => 'project_id=1'
984
+ )
985
+ assert_equal 3, developers_on_project_one.length
986
+ developer_names = developers_on_project_one.map { |d| d.name }
987
+ assert developer_names.include?('David')
988
+ assert developer_names.include?('Jamis')
989
+ end
990
+
991
+ def test_joins_dont_clobber_id
992
+ first = Firm.find(
993
+ :first,
994
+ :joins => 'INNER JOIN companies AS clients ON clients.firm_id = companies.id',
995
+ :conditions => 'companies.id = 1'
996
+ )
997
+ assert_equal 1, first.id
998
+ end
999
+
1000
+ def test_joins_with_string_array
1001
+ person_with_reader_and_post = Post.find(
1002
+ :all,
1003
+ :joins => [
1004
+ "INNER JOIN categorizations ON categorizations.post_id = posts.id",
1005
+ "INNER JOIN categories ON categories.id = categorizations.category_id AND categories.type = 'SpecialCategory'"
1006
+ ]
1007
+ )
1008
+ assert_equal 1, person_with_reader_and_post.size
1009
+ end
1010
+
1011
+ def test_find_by_id_with_conditions_with_or
1012
+ assert_nothing_raised do
1013
+ Post.find([1,2,3],
1014
+ :conditions => "posts.id <= 3 OR posts.#{QUOTED_TYPE} = 'Post'")
1015
+ end
1016
+ end
1017
+
1018
+ # http://dev.rubyonrails.org/ticket/6778
1019
+ def test_find_ignores_previously_inserted_record
1020
+ post = Post.create!(:title => 'test', :body => 'it out')
1021
+ assert_equal [], Post.find_all_by_id(nil)
1022
+ end
1023
+
1024
+ def test_find_by_empty_ids
1025
+ assert_equal [], Post.find([])
1026
+ end
1027
+
1028
+ def test_find_by_empty_in_condition
1029
+ assert_equal [], Post.find(:all, :conditions => ['id in (?)', []])
1030
+ end
1031
+
1032
+ def test_find_by_records
1033
+ p1, p2 = Post.find(:all, :limit => 2, :order => 'id asc')
1034
+ assert_equal [p1, p2], Post.find(:all, :conditions => ['id in (?)', [p1, p2]], :order => 'id asc')
1035
+ assert_equal [p1, p2], Post.find(:all, :conditions => ['id in (?)', [p1, p2.id]], :order => 'id asc')
1036
+ end
1037
+
1038
+ def test_select_value
1039
+ assert_equal "37signals", Company.connection.select_value("SELECT name FROM companies WHERE id = 1")
1040
+ assert_nil Company.connection.select_value("SELECT name FROM companies WHERE id = -1")
1041
+ # make sure we didn't break count...
1042
+ assert_equal 0, Company.count_by_sql("SELECT COUNT(*) FROM companies WHERE name = 'Halliburton'")
1043
+ assert_equal 1, Company.count_by_sql("SELECT COUNT(*) FROM companies WHERE name = '37signals'")
1044
+ end
1045
+
1046
+ def test_select_values
1047
+ 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 }
1048
+ assert_equal ["37signals","Summit","Microsoft", "Flamboyant Software", "Ex Nihilo", "RailsCore", "Leetsoft", "Jadedpixel", "Odegy"], Company.connection.select_values("SELECT name FROM companies ORDER BY id")
1049
+ end
1050
+
1051
+ def test_select_rows
1052
+ assert_equal(
1053
+ [["1", nil, nil, "37signals"],
1054
+ ["2", "1", "2", "Summit"],
1055
+ ["3", "1", "1", "Microsoft"]],
1056
+ Company.connection.select_rows("SELECT id, firm_id, client_of, name FROM companies WHERE id IN (1,2,3) ORDER BY id").map! {|i| i.map! {|j| j.to_s unless j.nil?}})
1057
+ assert_equal [["1", "37signals"], ["2", "Summit"], ["3", "Microsoft"]],
1058
+ Company.connection.select_rows("SELECT id, name FROM companies WHERE id IN (1,2,3) ORDER BY id").map! {|i| i.map! {|j| j.to_s unless j.nil?}}
1059
+ end
1060
+
1061
+ unless current_adapter?(:IBM_DBAdapter)
1062
+ def test_find_with_order_on_included_associations_with_construct_finder_sql_for_association_limiting_and_is_distinct
1063
+ assert_equal 2, Post.find(:all, :include => { :authors => :author_address }, :order => ' author_addresses.id DESC ', :limit => 2).size
1064
+
1065
+ assert_equal 3, Post.find(:all, :include => { :author => :author_address, :authors => :author_address},
1066
+ :order => ' author_addresses_authors.id DESC ', :limit => 3).size
1067
+ end
1068
+ end
1069
+
1070
+ def test_with_limiting_with_custom_select
1071
+ posts = Post.find(:all, :include => :author, :select => ' posts.*, authors.id as "author_id"', :limit => 3, :order => 'posts.id')
1072
+ assert_equal 3, posts.size
1073
+ assert_equal [0, 1, 1], posts.map(&:author_id).sort
1074
+ end
1075
+
1076
+ def test_finder_with_scoped_from
1077
+ all_topics = Topic.all
1078
+
1079
+ Topic.with_scope(:find => { :from => 'fake_topics' }) do
1080
+ assert_equal all_topics, Topic.all(:from => 'topics')
1081
+ end
1082
+ end
1083
+
1084
+ protected
1085
+ def bind(statement, *vars)
1086
+ if vars.first.is_a?(Hash)
1087
+ ActiveRecord::Base.send(:replace_named_bind_variables, statement, vars.first)
1088
+ else
1089
+ ActiveRecord::Base.send(:replace_bind_variables, statement, vars)
1090
+ end
1091
+ end
1092
+ end