finder_test.rb 43.2 KB
Newer Older
1
require "cases/helper"
2
require 'models/post'
J
Jeremy Kemper 已提交
3
require 'models/author'
4
require 'models/categorization'
J
Jeremy Kemper 已提交
5 6 7 8 9
require 'models/comment'
require 'models/company'
require 'models/topic'
require 'models/reply'
require 'models/entrant'
10
require 'models/project'
J
Jeremy Kemper 已提交
11
require 'models/developer'
12
require 'models/customer'
13
require 'models/toy'
D
David Heinemeier Hansson 已提交
14

15
class FinderTest < ActiveRecord::TestCase
16
  fixtures :companies, :topics, :entrants, :developers, :developers_projects, :posts, :comments, :accounts, :authors, :customers, :categories, :categorizations
D
David Heinemeier Hansson 已提交
17 18

  def test_find
19
    assert_equal(topics(:first).title, Topic.find(1).title)
D
David Heinemeier Hansson 已提交
20
  end
21

22 23 24 25 26
  # find should handle strings that come from URLs
  # (example: Category.find(params[:id]))
  def test_find_with_string
    assert_equal(Topic.find(1).title,Topic.find("1").title)
  end
27

D
David Heinemeier Hansson 已提交
28
  def test_exists
29 30 31 32 33 34
    assert Topic.exists?(1)
    assert Topic.exists?("1")
    assert Topic.exists?(:author_name => "David")
    assert Topic.exists?(:author_name => "Mary", :approved => true)
    assert Topic.exists?(["parent_id = ?", 1])
    assert !Topic.exists?(45)
35 36 37 38 39 40 41 42 43

    begin
      assert !Topic.exists?("foo")
    rescue ActiveRecord::StatementInvalid
      # PostgreSQL complains about string comparison with integer field
    rescue Exception
      flunk
    end

44
    assert_raise(NoMethodError) { Topic.exists?([1,2]) }
D
David Heinemeier Hansson 已提交
45
  end
46

47 48 49
  def test_exists_returns_true_with_one_record_and_no_args
    assert Topic.exists?
  end
50

51 52 53 54 55 56 57 58 59
  # exists? should handle nil for id's that come from URLs and always return false
  # (example: Topic.exists?(params[:id])) where params[:id] is nil
  def test_exists_with_nil_arg
    assert !Topic.exists?(nil)
    assert Topic.exists?
    assert !Topic.first.replies.exists?(nil)
    assert Topic.first.replies.exists?
  end

60 61 62 63 64
  # ensures +exists?+ runs valid SQL by excluding order value
  def test_exists_with_order
    assert Topic.order(:id).uniq.exists?
  end

65 66 67 68
  def test_does_not_exist_with_empty_table_and_no_args_given
    Topic.delete_all
    assert !Topic.exists?
  end
69

70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
  def test_exists_with_aggregate_having_three_mappings
    existing_address = customers(:david).address
    assert Customer.exists?(:address => existing_address)
  end

  def test_exists_with_aggregate_having_three_mappings_with_one_difference
    existing_address = customers(:david).address
    assert !Customer.exists?(:address =>
      Address.new(existing_address.street, existing_address.city, existing_address.country + "1"))
    assert !Customer.exists?(:address =>
      Address.new(existing_address.street, existing_address.city + "1", existing_address.country))
    assert !Customer.exists?(:address =>
      Address.new(existing_address.street + "1", existing_address.city, existing_address.country))
  end

85 86 87 88 89
  def test_exists_does_not_instantiate_records
    Developer.expects(:instantiate).never
    Developer.exists?
  end

D
David Heinemeier Hansson 已提交
90 91 92 93
  def test_find_by_array_of_one_id
    assert_kind_of(Array, Topic.find([ 1 ]))
    assert_equal(1, Topic.find([ 1 ]).length)
  end
94

D
David Heinemeier Hansson 已提交
95
  def test_find_by_ids
96 97 98 99 100
    assert_equal 2, Topic.find(1, 2).size
    assert_equal topics(:second).title, Topic.find([2]).first.title
  end

  def test_find_by_ids_with_limit_and_offset
J
Jon Leighton 已提交
101 102
    assert_equal 2, Entrant.scoped(:limit => 2).find([1,3,2]).size
    assert_equal 1, Entrant.scoped(:limit => 3, :offset => 2).find([1,3,2]).size
103 104 105 106

    # Also test an edge case: If you have 11 results, and you set a
    #   limit of 3 and offset of 9, then you should find that there
    #   will be only 2 results, regardless of the limit.
107
    devs = Developer.all
J
Jon Leighton 已提交
108
    last_devs = Developer.scoped(:limit => 3, :offset => 9).find devs.map(&:id)
109
    assert_equal 2, last_devs.size
D
David Heinemeier Hansson 已提交
110 111
  end

112 113 114 115
  def test_find_an_empty_array
    assert_equal [], Topic.find([])
  end

D
David Heinemeier Hansson 已提交
116
  def test_find_by_ids_missing_one
117
    assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, 2, 45) }
D
David Heinemeier Hansson 已提交
118
  end
119

120 121 122 123 124 125 126
  def test_find_with_group_and_sanitized_having_method
    developers = Developer.group(:salary).having("sum(salary) > ?", 10000).select('salary').all
    assert_equal 3, developers.size
    assert_equal 3, developers.map(&:salary).uniq.size
    assert developers.all? { |developer| developer.salary > 10000 }
  end

D
David Heinemeier Hansson 已提交
127 128
  def test_find_with_entire_select_statement
    topics = Topic.find_by_sql "SELECT * FROM topics WHERE author_name = 'Mary'"
129

D
David Heinemeier Hansson 已提交
130
    assert_equal(1, topics.size)
131
    assert_equal(topics(:second).title, topics.first.title)
D
David Heinemeier Hansson 已提交
132
  end
133

D
David Heinemeier Hansson 已提交
134 135
  def test_find_with_prepared_select_statement
    topics = Topic.find_by_sql ["SELECT * FROM topics WHERE author_name = ?", "Mary"]
136

D
David Heinemeier Hansson 已提交
137
    assert_equal(1, topics.size)
138
    assert_equal(topics(:second).title, topics.first.title)
D
David Heinemeier Hansson 已提交
139
  end
140

141 142 143 144
  def test_find_by_sql_with_sti_on_joined_table
    accounts = Account.find_by_sql("SELECT * FROM accounts INNER JOIN companies ON companies.id = accounts.firm_id")
    assert_equal [Account], accounts.collect(&:class).uniq
  end
145

146
  def test_first
147
    assert_equal topics(:second).title, Topic.where("title = 'The Second Topic of the day'").first.title
148
  end
149

150
  def test_first_failing
151
    assert_nil Topic.where("title = 'The Second Topic of the day!'").first
152
  end
D
David Heinemeier Hansson 已提交
153

154 155 156 157 158 159 160 161 162 163 164 165
  def test_first_bang_present
    assert_nothing_raised do
      assert_equal topics(:second), Topic.where("title = 'The Second Topic of the day'").first!
    end
  end

  def test_first_bang_missing
    assert_raises ActiveRecord::RecordNotFound do
      Topic.where("title = 'This title does not exist'").first!
    end
  end

166
  def test_model_class_responds_to_first_bang
167 168
    assert Topic.first!
    Topic.delete_all
169 170 171 172 173
    assert_raises ActiveRecord::RecordNotFound do
      Topic.first!
    end
  end

174 175 176 177 178 179 180 181 182 183 184 185
  def test_last_bang_present
    assert_nothing_raised do
      assert_equal topics(:second), Topic.where("title = 'The Second Topic of the day'").last!
    end
  end

  def test_last_bang_missing
    assert_raises ActiveRecord::RecordNotFound do
      Topic.where("title = 'This title does not exist'").last!
    end
  end

186 187 188 189 190 191 192 193
  def test_model_class_responds_to_last_bang
    assert_equal topics(:fourth), Topic.last!
    assert_raises ActiveRecord::RecordNotFound do
      Topic.delete_all
      Topic.last!
    end
  end

194
  def test_first_and_last_with_integer_should_use_sql_limit
195 196
    assert_sql(/LIMIT 2|ROWNUM <= 2/) { Topic.first(2).entries }
    assert_sql(/LIMIT 5|ROWNUM <= 5/) { Topic.last(5).entries }
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
  end

  def test_last_with_integer_and_order_should_keep_the_order
    assert_equal Topic.order("title").to_a.last(2), Topic.order("title").last(2)
  end

  def test_last_with_integer_and_order_should_not_use_sql_limit
    query = assert_sql { Topic.order("title").last(5).entries }
    assert_equal 1, query.length
    assert_no_match(/LIMIT/, query.first)
  end

  def test_last_with_integer_and_reorder_should_not_use_sql_limit
    query = assert_sql { Topic.reorder("title").last(5).entries }
    assert_equal 1, query.length
    assert_no_match(/LIMIT/, query.first)
213 214 215 216 217 218 219
  end

  def test_first_and_last_with_integer_should_return_an_array
    assert_kind_of Array, Topic.first(5)
    assert_kind_of Array, Topic.last(5)
  end

D
David Heinemeier Hansson 已提交
220
  def test_unexisting_record_exception_handling
221
    assert_raise(ActiveRecord::RecordNotFound) {
D
David Heinemeier Hansson 已提交
222 223
      Topic.find(1).parent
    }
224

225
    Topic.find(2).topic
D
David Heinemeier Hansson 已提交
226
  end
227

228
  def test_find_only_some_columns
J
Jon Leighton 已提交
229
    topic = Topic.scoped(:select => "author_name").find(1)
230
    assert_raise(ActiveModel::MissingAttributeError) {topic.title}
231
    assert_nil topic.read_attribute("title")
232 233
    assert_equal "David", topic.author_name
    assert !topic.attribute_present?("title")
234
    assert !topic.attribute_present?(:title)
235
    assert topic.attribute_present?("author_name")
236
    assert_respond_to topic, "author_name"
237
  end
J
Jeremy Kemper 已提交
238

239
  def test_find_on_array_conditions
J
Jon Leighton 已提交
240 241
    assert Topic.scoped(:where => ["approved = ?", false]).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => ["approved = ?", true]).find(1) }
D
David Heinemeier Hansson 已提交
242
  end
243

244
  def test_find_on_hash_conditions
J
Jon Leighton 已提交
245 246
    assert Topic.scoped(:where => { :approved => false }).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { :approved => true }).find(1) }
247
  end
248

249
  def test_find_on_hash_conditions_with_explicit_table_name
J
Jon Leighton 已提交
250 251
    assert Topic.scoped(:where => { 'topics.approved' => false }).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { 'topics.approved' => true }).find(1) }
252 253
  end

254
  def test_find_on_hash_conditions_with_hashed_table_name
J
Jon Leighton 已提交
255 256
    assert Topic.scoped(:where => {:topics => { :approved => false }}).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => {:topics => { :approved => true }}).find(1) }
257 258 259
  end

  def test_find_with_hash_conditions_on_joined_table
260
    firms = Firm.joins(:account).where(:accounts => { :credit_limit => 50 })
261 262 263 264 265
    assert_equal 1, firms.size
    assert_equal companies(:first_firm), firms.first
  end

  def test_find_with_hash_conditions_on_joined_table_and_with_range
J
Jon Leighton 已提交
266
    firms = DependentFirm.scoped :joins => :account, :where => {:name => 'RailsCore', :accounts => { :credit_limit => 55..60 }}
267 268 269 270
    assert_equal 1, firms.size
    assert_equal companies(:rails_core), firms.first
  end

271 272
  def test_find_on_hash_conditions_with_explicit_table_name_and_aggregate
    david = customers(:david)
J
Jon Leighton 已提交
273
    assert Customer.scoped(:where => { 'customers.name' => david.name, :address => david.address }).find(david.id)
274
    assert_raise(ActiveRecord::RecordNotFound) {
J
Jon Leighton 已提交
275
      Customer.scoped(:where => { 'customers.name' => david.name + "1", :address => david.address }).find(david.id)
276 277 278
    }
  end

279
  def test_find_on_association_proxy_conditions
280
    assert_equal [1, 2, 3, 5, 6, 7, 8, 9, 10, 12], Comment.find_all_by_post_id(authors(:david).posts).map(&:id).sort
281 282
  end

283
  def test_find_on_hash_conditions_with_range
J
Jon Leighton 已提交
284
    assert_equal [1,2], Topic.scoped(:where => { :id => 1..2 }).all.map(&:id).sort
J
Jon Leighton 已提交
285
    assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { :id => 2..3 }).find(1) }
286
  end
287

288
  def test_find_on_hash_conditions_with_end_exclusive_range
J
Jon Leighton 已提交
289 290
    assert_equal [1,2,3], Topic.scoped(:where => { :id => 1..3 }).all.map(&:id).sort
    assert_equal [1,2], Topic.scoped(:where => { :id => 1...3 }).all.map(&:id).sort
J
Jon Leighton 已提交
291
    assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { :id => 2...3 }).find(3) }
292 293
  end

294
  def test_find_on_hash_conditions_with_multiple_ranges
J
Jon Leighton 已提交
295 296
    assert_equal [1,2,3], Comment.scoped(:where => { :id => 1..3, :post_id => 1..2 }).all.map(&:id).sort
    assert_equal [1], Comment.scoped(:where => { :id => 1..1, :post_id => 1..10 }).all.map(&:id).sort
297
  end
298

299
  def test_find_on_hash_conditions_with_array_of_integers_and_ranges
J
Jon Leighton 已提交
300
    assert_equal [1,2,3,5,6,7,8,9], Comment.scoped(:where => {:id => [1..2, 3, 5, 6..8, 9]}).all.map(&:id).sort
301 302
  end

303
  def test_find_on_multiple_hash_conditions
J
Jon Leighton 已提交
304 305 306 307
    assert Topic.scoped(:where => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => false }).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }).find(1) }
    assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { :author_name => "David", :title => "HHC", :replies_count => 1, :approved => false }).find(1) }
    assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }).find(1) }
308
  end
309

310
  def test_condition_interpolation
311
    assert_kind_of Firm, Company.where("name = '%s'", "37signals").first
J
Jon Leighton 已提交
312 313 314
    assert_nil Company.scoped(:where => ["name = '%s'", "37signals!"]).first
    assert_nil Company.scoped(:where => ["name = '%s'", "37signals!' OR 1=1"]).first
    assert_kind_of Time, Topic.scoped(:where => ["id = %d", 1]).first.written_on
315 316
  end

317
  def test_condition_array_interpolation
J
Jon Leighton 已提交
318 319 320 321
    assert_kind_of Firm, Company.scoped(:where => ["name = '%s'", "37signals"]).first
    assert_nil Company.scoped(:where => ["name = '%s'", "37signals!"]).first
    assert_nil Company.scoped(:where => ["name = '%s'", "37signals!' OR 1=1"]).first
    assert_kind_of Time, Topic.scoped(:where => ["id = %d", 1]).first.written_on
D
David Heinemeier Hansson 已提交
322
  end
323

324
  def test_condition_hash_interpolation
J
Jon Leighton 已提交
325 326 327
    assert_kind_of Firm, Company.scoped(:where => { :name => "37signals"}).first
    assert_nil Company.scoped(:where => { :name => "37signals!"}).first
    assert_kind_of Time, Topic.scoped(:where => {:id => 1}).first.written_on
328
  end
329

330
  def test_hash_condition_find_malformed
331
    assert_raise(ActiveRecord::StatementInvalid) {
J
Jon Leighton 已提交
332
      Company.scoped(:where => { :id => 2, :dhh => true }).first
333 334
    }
  end
335

336 337
  def test_hash_condition_find_with_escaped_characters
    Company.create("name" => "Ain't noth'n like' \#stuff")
J
Jon Leighton 已提交
338
    assert Company.scoped(:where => { :name => "Ain't noth'n like' \#stuff" }).first
339 340 341
  end

  def test_hash_condition_find_with_array
342
    p1, p2 = Post.scoped(:limit => 2, :order => 'id asc').all
J
Jon Leighton 已提交
343 344
    assert_equal [p1, p2], Post.scoped(:where => { :id => [p1, p2] }, :order => 'id asc').all
    assert_equal [p1, p2], Post.scoped(:where => { :id => [p1, p2.id] }, :order => 'id asc').all
345 346 347
  end

  def test_hash_condition_find_with_nil
J
Jon Leighton 已提交
348
    topic = Topic.scoped(:where => { :last_read => nil } ).first
349 350
    assert_not_nil topic
    assert_nil topic.last_read
351
  end
D
David Heinemeier Hansson 已提交
352

353 354 355
  def test_hash_condition_find_with_aggregate_having_one_mapping
    balance = customers(:david).balance
    assert_kind_of Money, balance
J
Jon Leighton 已提交
356
    found_customer = Customer.scoped(:where => {:balance => balance}).first
357 358 359 360 361 362
    assert_equal customers(:david), found_customer
  end

  def test_hash_condition_find_with_aggregate_attribute_having_same_name_as_field_and_key_value_being_aggregate
    gps_location = customers(:david).gps_location
    assert_kind_of GpsLocation, gps_location
J
Jon Leighton 已提交
363
    found_customer = Customer.scoped(:where => {:gps_location => gps_location}).first
364 365 366 367 368 369
    assert_equal customers(:david), found_customer
  end

  def test_hash_condition_find_with_aggregate_having_one_mapping_and_key_value_being_attribute_value
    balance = customers(:david).balance
    assert_kind_of Money, balance
J
Jon Leighton 已提交
370
    found_customer = Customer.scoped(:where => {:balance => balance.amount}).first
371 372 373 374 375 376
    assert_equal customers(:david), found_customer
  end

  def test_hash_condition_find_with_aggregate_attribute_having_same_name_as_field_and_key_value_being_attribute_value
    gps_location = customers(:david).gps_location
    assert_kind_of GpsLocation, gps_location
J
Jon Leighton 已提交
377
    found_customer = Customer.scoped(:where => {:gps_location => gps_location.gps_location}).first
378 379 380 381 382 383
    assert_equal customers(:david), found_customer
  end

  def test_hash_condition_find_with_aggregate_having_three_mappings
    address = customers(:david).address
    assert_kind_of Address, address
J
Jon Leighton 已提交
384
    found_customer = Customer.scoped(:where => {:address => address}).first
385 386 387 388 389 390
    assert_equal customers(:david), found_customer
  end

  def test_hash_condition_find_with_one_condition_being_aggregate_and_another_not
    address = customers(:david).address
    assert_kind_of Address, address
J
Jon Leighton 已提交
391
    found_customer = Customer.scoped(:where => {:address => address, :name => customers(:david).name}).first
392 393 394
    assert_equal customers(:david), found_customer
  end

395 396 397 398
  def test_condition_utc_time_interpolation_with_default_timezone_local
    with_env_tz 'America/New_York' do
      with_active_record_default_timezone :local do
        topic = Topic.first
J
Jon Leighton 已提交
399
        assert_equal topic, Topic.scoped(:where => ['written_on = ?', topic.written_on.getutc]).first
400 401 402 403 404 405 406 407
      end
    end
  end

  def test_hash_condition_utc_time_interpolation_with_default_timezone_local
    with_env_tz 'America/New_York' do
      with_active_record_default_timezone :local do
        topic = Topic.first
J
Jon Leighton 已提交
408
        assert_equal topic, Topic.scoped(:where => {:written_on => topic.written_on.getutc}).first
409 410 411 412 413 414 415 416
      end
    end
  end

  def test_condition_local_time_interpolation_with_default_timezone_utc
    with_env_tz 'America/New_York' do
      with_active_record_default_timezone :utc do
        topic = Topic.first
J
Jon Leighton 已提交
417
        assert_equal topic, Topic.scoped(:where => ['written_on = ?', topic.written_on.getlocal]).first
418 419 420 421 422 423 424 425
      end
    end
  end

  def test_hash_condition_local_time_interpolation_with_default_timezone_utc
    with_env_tz 'America/New_York' do
      with_active_record_default_timezone :utc do
        topic = Topic.first
J
Jon Leighton 已提交
426
        assert_equal topic, Topic.scoped(:where => {:written_on => topic.written_on.getlocal}).first
427 428 429 430
      end
    end
  end

D
David Heinemeier Hansson 已提交
431
  def test_bind_variables
J
Jon Leighton 已提交
432 433 434 435
    assert_kind_of Firm, Company.scoped(:where => ["name = ?", "37signals"]).first
    assert_nil Company.scoped(:where => ["name = ?", "37signals!"]).first
    assert_nil Company.scoped(:where => ["name = ?", "37signals!' OR 1=1"]).first
    assert_kind_of Time, Topic.scoped(:where => ["id = ?", 1]).first.written_on
436
    assert_raise(ActiveRecord::PreparedStatementInvalid) {
J
Jon Leighton 已提交
437
      Company.scoped(:where => ["id=? AND name = ?", 2]).first
D
David Heinemeier Hansson 已提交
438
    }
439
    assert_raise(ActiveRecord::PreparedStatementInvalid) {
J
Jon Leighton 已提交
440
     Company.scoped(:where => ["id=?", 2, 3, 4]).first
D
David Heinemeier Hansson 已提交
441 442
    }
  end
443

D
David Heinemeier Hansson 已提交
444 445
  def test_bind_variables_with_quotes
    Company.create("name" => "37signals' go'es agains")
J
Jon Leighton 已提交
446
    assert Company.scoped(:where => ["name = ?", "37signals' go'es agains"]).first
D
David Heinemeier Hansson 已提交
447 448 449 450
  end

  def test_named_bind_variables_with_quotes
    Company.create("name" => "37signals' go'es agains")
J
Jon Leighton 已提交
451
    assert Company.scoped(:where => ["name = :name", {:name => "37signals' go'es agains"}]).first
D
David Heinemeier Hansson 已提交
452 453 454 455
  end

  def test_bind_arity
    assert_nothing_raised                                 { bind '' }
456
    assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '', 1 }
457

458
    assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '?' }
D
David Heinemeier Hansson 已提交
459
    assert_nothing_raised                                 { bind '?', 1 }
460
    assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '?', 1, 1  }
D
David Heinemeier Hansson 已提交
461
  end
462

D
David Heinemeier Hansson 已提交
463 464 465
  def test_named_bind_variables
    assert_equal '1', bind(':a', :a => 1) # ' ruby-mode
    assert_equal '1 1', bind(':a :a', :a => 1)  # ' ruby-mode
466

467
    assert_nothing_raised { bind("'+00:00'", :foo => "bar") }
468

J
Jon Leighton 已提交
469 470 471 472
    assert_kind_of Firm, Company.scoped(:where => ["name = :name", { :name => "37signals" }]).first
    assert_nil Company.scoped(:where => ["name = :name", { :name => "37signals!" }]).first
    assert_nil Company.scoped(:where => ["name = :name", { :name => "37signals!' OR 1=1" }]).first
    assert_kind_of Time, Topic.scoped(:where => ["id = :id", { :id => 1 }]).first.written_on
D
David Heinemeier Hansson 已提交
473 474
  end

475 476 477 478 479 480 481 482 483 484 485 486
  class SimpleEnumerable
    include Enumerable

    def initialize(ary)
      @ary = ary
    end

    def each(&b)
      @ary.each(&b)
    end
  end

487
  def test_bind_enumerable
488 489
    quoted_abc = %(#{ActiveRecord::Base.connection.quote('a')},#{ActiveRecord::Base.connection.quote('b')},#{ActiveRecord::Base.connection.quote('c')})

D
David Heinemeier Hansson 已提交
490
    assert_equal '1,2,3', bind('?', [1, 2, 3])
491
    assert_equal quoted_abc, bind('?', %w(a b c))
D
David Heinemeier Hansson 已提交
492 493

    assert_equal '1,2,3', bind(':a', :a => [1, 2, 3])
494
    assert_equal quoted_abc, bind(':a', :a => %w(a b c)) # '
495

496 497
    assert_equal '1,2,3', bind('?', SimpleEnumerable.new([1, 2, 3]))
    assert_equal quoted_abc, bind('?', SimpleEnumerable.new(%w(a b c)))
498

499 500
    assert_equal '1,2,3', bind(':a', :a => SimpleEnumerable.new([1, 2, 3]))
    assert_equal quoted_abc, bind(':a', :a => SimpleEnumerable.new(%w(a b c))) # '
D
David Heinemeier Hansson 已提交
501 502
  end

503 504 505 506 507 508 509
  def test_bind_empty_enumerable
    quoted_nil = ActiveRecord::Base.connection.quote(nil)
    assert_equal quoted_nil, bind('?', [])
    assert_equal " in (#{quoted_nil})", bind(' in (?)', [])
    assert_equal "foo in (#{quoted_nil})", bind('foo in (?)', [])
  end

J
Jeremy Kemper 已提交
510 511 512
  def test_bind_empty_string
    quoted_empty = ActiveRecord::Base.connection.quote('')
    assert_equal quoted_empty, bind('?', '')
513 514
  end

515 516 517 518 519
  def test_bind_chars
    quoted_bambi = ActiveRecord::Base.connection.quote("Bambi")
    quoted_bambi_and_thumper = ActiveRecord::Base.connection.quote("Bambi\nand\nThumper")
    assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi")
    assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper")
520 521
    assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi".mb_chars)
    assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper".mb_chars)
522 523
  end

524 525 526 527 528 529 530 531
  def test_bind_record
    o = Struct.new(:quoted_id).new(1)
    assert_equal '1', bind('?', o)

    os = [o] * 3
    assert_equal '1,1,1', bind('?', os)
  end

532 533 534 535 536 537
  def test_named_bind_with_postgresql_type_casts
    l = Proc.new { bind(":a::integer '2009-01-01'::date", :a => '10') }
    assert_nothing_raised(&l)
    assert_equal "#{ActiveRecord::Base.quote_value('10')}::integer '2009-01-01'::date", l.call
  end

D
David Heinemeier Hansson 已提交
538
  def test_string_sanitation
539 540
    assert_not_equal "'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1")
    assert_equal "'something; select table'", ActiveRecord::Base.sanitize("something; select table")
D
David Heinemeier Hansson 已提交
541 542 543 544 545 546 547 548 549
  end

  def test_count_by_sql
    assert_equal(0, Entrant.count_by_sql("SELECT COUNT(*) FROM entrants WHERE id > 3"))
    assert_equal(1, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 2]))
    assert_equal(2, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 1]))
  end

  def test_find_by_one_attribute
550
    assert_equal topics(:first), Topic.find_by_title("The First Topic")
D
David Heinemeier Hansson 已提交
551 552
    assert_nil Topic.find_by_title("The First Topic!")
  end
J
Jeremy Kemper 已提交
553

554 555
  def test_find_by_one_attribute_bang
    assert_equal topics(:first), Topic.find_by_title!("The First Topic")
556
    assert_raise(ActiveRecord::RecordNotFound) { Topic.find_by_title!("The First Topic!") }
557 558
  end

559
  def test_find_by_one_attribute_with_order_option
560
    assert_equal accounts(:signals37), Account.find_by_credit_limit(50, :order => 'id')
561 562 563 564
    assert_equal accounts(:rails_core_account), Account.find_by_credit_limit(50, :order => 'id DESC')
  end

  def test_find_by_one_attribute_with_conditions
J
Jon Leighton 已提交
565
    assert_equal accounts(:rails_core_account), Account.where('firm_id = ?', 6).find_by_credit_limit(50)
566 567
  end

568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
  def test_find_by_one_attribute_that_is_an_aggregate
    address = customers(:david).address
    assert_kind_of Address, address
    found_customer = Customer.find_by_address(address)
    assert_equal customers(:david), found_customer
  end

  def test_find_by_one_attribute_that_is_an_aggregate_with_one_attribute_difference
    address = customers(:david).address
    assert_kind_of Address, address
    missing_address = Address.new(address.street, address.city, address.country + "1")
    assert_nil Customer.find_by_address(missing_address)
    missing_address = Address.new(address.street, address.city + "1", address.country)
    assert_nil Customer.find_by_address(missing_address)
    missing_address = Address.new(address.street + "1", address.city, address.country)
    assert_nil Customer.find_by_address(missing_address)
  end

  def test_find_by_two_attributes_that_are_both_aggregates
    balance = customers(:david).balance
    address = customers(:david).address
    assert_kind_of Money, balance
    assert_kind_of Address, address
    found_customer = Customer.find_by_balance_and_address(balance, address)
    assert_equal customers(:david), found_customer
  end

  def test_find_by_two_attributes_with_one_being_an_aggregate
    balance = customers(:david).balance
    assert_kind_of Money, balance
    found_customer = Customer.find_by_balance_and_name(balance, customers(:david).name)
    assert_equal customers(:david), found_customer
  end

602 603
  def test_dynamic_finder_on_one_attribute_with_conditions_returns_same_results_after_caching
    # ensure this test can run independently of order
604
    class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.public_methods.any? { |m| m.to_s == 'find_by_credit_limit' }
J
Jon Leighton 已提交
605 606
    a = Account.where('firm_id = ?', 6).find_by_credit_limit(50)
    assert_equal a, Account.where('firm_id = ?', 6).find_by_credit_limit(50) # find_by_credit_limit has been cached
607 608
  end

609
  def test_find_by_one_attribute_with_several_options
J
Jon Leighton 已提交
610
    assert_equal accounts(:unknown), Account.order('id DESC').where('id != ?', 3).find_by_credit_limit(50)
611
  end
612

D
David Heinemeier Hansson 已提交
613
  def test_find_by_one_missing_attribute
614
    assert_raise(NoMethodError) { Topic.find_by_undertitle("The First Topic!") }
D
David Heinemeier Hansson 已提交
615
  end
616

617
  def test_find_by_invalid_method_syntax
618 619 620 621
    assert_raise(NoMethodError) { Topic.fail_to_find_by_title("The First Topic") }
    assert_raise(NoMethodError) { Topic.find_by_title?("The First Topic") }
    assert_raise(NoMethodError) { Topic.fail_to_find_or_create_by_title("Nonexistent Title") }
    assert_raise(NoMethodError) { Topic.find_or_create_by_title?("Nonexistent Title") }
622
  end
D
David Heinemeier Hansson 已提交
623 624

  def test_find_by_two_attributes
625
    assert_equal topics(:first), Topic.find_by_title_and_author_name("The First Topic", "David")
D
David Heinemeier Hansson 已提交
626 627 628
    assert_nil Topic.find_by_title_and_author_name("The First Topic", "Mary")
  end

629 630 631 632
  def test_find_by_two_attributes_but_passing_only_one
    assert_raise(ArgumentError) { Topic.find_by_title_and_author_name("The First Topic") }
  end

633 634 635 636 637 638
  def test_find_last_by_one_attribute
    assert_equal Topic.last, Topic.find_last_by_title(Topic.last.title)
    assert_nil Topic.find_last_by_title("A title with no matches")
  end

  def test_find_last_by_invalid_method_syntax
639 640
    assert_raise(NoMethodError) { Topic.fail_to_find_last_by_title("The First Topic") }
    assert_raise(NoMethodError) { Topic.find_last_by_title?("The First Topic") }
641 642 643
  end

  def test_find_last_by_one_attribute_with_several_options
J
Jon Leighton 已提交
644
    assert_equal accounts(:signals37), Account.order('id DESC').where('id != ?', 3).find_last_by_credit_limit(50)
645 646 647
  end

  def test_find_last_by_one_missing_attribute
648
    assert_raise(NoMethodError) { Topic.find_last_by_undertitle("The Last Topic!") }
649 650 651 652 653 654 655 656
  end

  def test_find_last_by_two_attributes
    topic = Topic.last
    assert_equal topic, Topic.find_last_by_title_and_author_name(topic.title, topic.author_name)
    assert_nil Topic.find_last_by_title_and_author_name(topic.title, "Anonymous")
  end

N
Nick Howard 已提交
657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
  def test_find_last_with_limit_gives_same_result_when_loaded_and_unloaded
    scope = Topic.limit(2)
    unloaded_last = scope.last
    loaded_last = scope.all.last
    assert_equal loaded_last, unloaded_last
  end

  def test_find_last_with_limit_and_offset_gives_same_result_when_loaded_and_unloaded
    scope = Topic.offset(2).limit(2)
    unloaded_last = scope.last
    loaded_last = scope.all.last
    assert_equal loaded_last, unloaded_last
  end

  def test_find_last_with_offset_gives_same_result_when_loaded_and_unloaded
    scope = Topic.offset(3)
    unloaded_last = scope.last
    loaded_last = scope.all.last
    assert_equal loaded_last, unloaded_last
  end

D
David Heinemeier Hansson 已提交
678 679 680
  def test_find_all_by_one_attribute
    topics = Topic.find_all_by_content("Have a nice day")
    assert_equal 2, topics.size
681
    assert topics.include?(topics(:first))
D
David Heinemeier Hansson 已提交
682 683 684

    assert_equal [], Topic.find_all_by_title("The First Topic!!")
  end
685

686 687 688 689 690 691 692 693
  def test_find_all_by_one_attribute_which_is_a_symbol
    topics = Topic.find_all_by_content("Have a nice day".to_sym)
    assert_equal 2, topics.size
    assert topics.include?(topics(:first))

    assert_equal [], Topic.find_all_by_title("The First Topic!!")
  end

694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
  def test_find_all_by_one_attribute_that_is_an_aggregate
    balance = customers(:david).balance
    assert_kind_of Money, balance
    found_customers = Customer.find_all_by_balance(balance)
    assert_equal 1, found_customers.size
    assert_equal customers(:david), found_customers.first
  end

  def test_find_all_by_two_attributes_that_are_both_aggregates
    balance = customers(:david).balance
    address = customers(:david).address
    assert_kind_of Money, balance
    assert_kind_of Address, address
    found_customers = Customer.find_all_by_balance_and_address(balance, address)
    assert_equal 1, found_customers.size
    assert_equal customers(:david), found_customers.first
  end

  def test_find_all_by_two_attributes_with_one_being_an_aggregate
    balance = customers(:david).balance
    assert_kind_of Money, balance
    found_customers = Customer.find_all_by_balance_and_name(balance, customers(:david).name)
    assert_equal 1, found_customers.size
    assert_equal customers(:david), found_customers.first
  end

720 721
  def test_find_all_by_one_attribute_with_options
    topics = Topic.find_all_by_content("Have a nice day", :order => "id DESC")
722
    assert_equal topics(:first), topics.last
723 724

    topics = Topic.find_all_by_content("Have a nice day", :order => "id")
725
    assert_equal topics(:first), topics.first
726
  end
D
David Heinemeier Hansson 已提交
727

728
  def test_find_all_by_array_attribute
729
    assert_equal 2, Topic.find_all_by_title(["The First Topic", "The Second Topic of the day"]).size
730 731
  end

D
David Heinemeier Hansson 已提交
732 733 734
  def test_find_all_by_boolean_attribute
    topics = Topic.find_all_by_approved(false)
    assert_equal 1, topics.size
735
    assert topics.include?(topics(:first))
D
David Heinemeier Hansson 已提交
736 737

    topics = Topic.find_all_by_approved(true)
738
    assert_equal 3, topics.size
739
    assert topics.include?(topics(:second))
D
David Heinemeier Hansson 已提交
740
  end
741

D
David Heinemeier Hansson 已提交
742 743 744 745 746
  def test_find_by_nil_attribute
    topic = Topic.find_by_last_read nil
    assert_not_nil topic
    assert_nil topic.last_read
  end
747

D
David Heinemeier Hansson 已提交
748 749
  def test_find_all_by_nil_attribute
    topics = Topic.find_all_by_last_read nil
750 751
    assert_equal 3, topics.size
    assert topics.collect(&:last_read).all?(&:nil?)
D
David Heinemeier Hansson 已提交
752
  end
753

D
David Heinemeier Hansson 已提交
754 755 756 757 758 759 760 761 762 763 764
  def test_find_by_nil_and_not_nil_attributes
    topic = Topic.find_by_last_read_and_author_name nil, "Mary"
    assert_equal "Mary", topic.author_name
  end

  def test_find_all_by_nil_and_not_nil_attributes
    topics = Topic.find_all_by_last_read_and_author_name nil, "Mary"
    assert_equal 1, topics.size
    assert_equal "Mary", topics[0].author_name
  end

765 766 767 768 769
  def test_find_or_create_from_one_attribute
    number_of_companies = Company.count
    sig38 = Company.find_or_create_by_name("38signals")
    assert_equal number_of_companies + 1, Company.count
    assert_equal sig38, Company.find_or_create_by_name("38signals")
770
    assert sig38.persisted?
771 772 773
  end

  def test_find_or_create_from_two_attributes
774 775 776 777
    number_of_topics = Topic.count
    another = Topic.find_or_create_by_title_and_author_name("Another topic","John")
    assert_equal number_of_topics + 1, Topic.count
    assert_equal another, Topic.find_or_create_by_title_and_author_name("Another topic", "John")
778
    assert another.persisted?
779
  end
780

781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
  def test_find_or_create_from_one_attribute_bang
    number_of_companies = Company.count
    assert_raises(ActiveRecord::RecordInvalid) { Company.find_or_create_by_name!("") }
    assert_equal number_of_companies, Company.count
    sig38 = Company.find_or_create_by_name!("38signals")
    assert_equal number_of_companies + 1, Company.count
    assert_equal sig38, Company.find_or_create_by_name!("38signals")
    assert sig38.persisted?
  end

  def test_find_or_create_from_two_attributes_bang
    number_of_companies = Company.count
    assert_raises(ActiveRecord::RecordInvalid) { Company.find_or_create_by_name_and_firm_id!("", 17) }
    assert_equal number_of_companies, Company.count
    sig38 = Company.find_or_create_by_name_and_firm_id!("38signals", 17)
    assert_equal number_of_companies + 1, Company.count
    assert_equal sig38, Company.find_or_create_by_name_and_firm_id!("38signals", 17)
    assert sig38.persisted?
    assert_equal "38signals", sig38.name
    assert_equal 17, sig38.firm_id
  end

803 804 805 806 807
  def test_find_or_create_from_two_attributes_with_one_being_an_aggregate
    number_of_customers = Customer.count
    created_customer = Customer.find_or_create_by_balance_and_name(Money.new(123), "Elizabeth")
    assert_equal number_of_customers + 1, Customer.count
    assert_equal created_customer, Customer.find_or_create_by_balance(Money.new(123), "Elizabeth")
808
    assert created_customer.persisted?
809 810
  end

811 812 813 814 815
  def test_find_or_create_from_one_attribute_and_hash
    number_of_companies = Company.count
    sig38 = Company.find_or_create_by_name({:name => "38signals", :firm_id => 17, :client_of => 23})
    assert_equal number_of_companies + 1, Company.count
    assert_equal sig38, Company.find_or_create_by_name({:name => "38signals", :firm_id => 17, :client_of => 23})
816
    assert sig38.persisted?
817 818 819 820 821
    assert_equal "38signals", sig38.name
    assert_equal 17, sig38.firm_id
    assert_equal 23, sig38.client_of
  end

P
Paul McMahon 已提交
822 823 824 825 826 827 828 829 830 831 832
  def test_find_or_create_from_two_attributes_and_hash
    number_of_companies = Company.count
    sig38 = Company.find_or_create_by_name_and_firm_id({:name => "38signals", :firm_id => 17, :client_of => 23})
    assert_equal number_of_companies + 1, Company.count
    assert_equal sig38, Company.find_or_create_by_name_and_firm_id({:name => "38signals", :firm_id => 17, :client_of => 23})
    assert sig38.persisted?
    assert_equal "38signals", sig38.name
    assert_equal 17, sig38.firm_id
    assert_equal 23, sig38.client_of
  end

833 834 835 836 837
  def test_find_or_create_from_one_aggregate_attribute
    number_of_customers = Customer.count
    created_customer = Customer.find_or_create_by_balance(Money.new(123))
    assert_equal number_of_customers + 1, Customer.count
    assert_equal created_customer, Customer.find_or_create_by_balance(Money.new(123))
838
    assert created_customer.persisted?
839 840 841 842 843 844 845 846 847
  end

  def test_find_or_create_from_one_aggregate_attribute_and_hash
    number_of_customers = Customer.count
    balance = Money.new(123)
    name = "Elizabeth"
    created_customer = Customer.find_or_create_by_balance({:balance => balance, :name => name})
    assert_equal number_of_customers + 1, Customer.count
    assert_equal created_customer, Customer.find_or_create_by_balance({:balance => balance, :name => name})
848
    assert created_customer.persisted?
849 850 851 852
    assert_equal balance, created_customer.balance
    assert_equal name, created_customer.name
  end

853 854 855
  def test_find_or_initialize_from_one_attribute
    sig38 = Company.find_or_initialize_by_name("38signals")
    assert_equal "38signals", sig38.name
856
    assert !sig38.persisted?
857
  end
J
Jeremy Kemper 已提交
858

859 860 861
  def test_find_or_initialize_from_one_aggregate_attribute
    new_customer = Customer.find_or_initialize_by_balance(Money.new(123))
    assert_equal 123, new_customer.balance.amount
862
    assert !new_customer.persisted?
863 864
  end

865 866 867 868 869
  def test_find_or_initialize_from_one_attribute_should_not_set_attribute_even_when_protected
    c = Company.find_or_initialize_by_name({:name => "Fortune 1000", :rating => 1000})
    assert_equal "Fortune 1000", c.name
    assert_not_equal 1000, c.rating
    assert c.valid?
870
    assert !c.persisted?
871 872
  end

873
  def test_find_or_create_from_one_attribute_should_not_set_attribute_even_when_protected
874 875 876 877
    c = Company.find_or_create_by_name({:name => "Fortune 1000", :rating => 1000})
    assert_equal "Fortune 1000", c.name
    assert_not_equal 1000, c.rating
    assert c.valid?
878
    assert c.persisted?
879 880
  end

881 882 883 884 885
  def test_find_or_initialize_from_one_attribute_should_set_attribute_even_when_protected
    c = Company.find_or_initialize_by_name_and_rating("Fortune 1000", 1000)
    assert_equal "Fortune 1000", c.name
    assert_equal 1000, c.rating
    assert c.valid?
886
    assert !c.persisted?
887 888 889 890 891 892 893
  end

  def test_find_or_create_from_one_attribute_should_set_attribute_even_when_protected
    c = Company.find_or_create_by_name_and_rating("Fortune 1000", 1000)
    assert_equal "Fortune 1000", c.name
    assert_equal 1000, c.rating
    assert c.valid?
894
    assert c.persisted?
895
  end
896

897 898 899 900 901
  def test_find_or_initialize_from_one_attribute_should_set_attribute_even_when_protected_and_also_set_the_hash
    c = Company.find_or_initialize_by_rating(1000, {:name => "Fortune 1000"})
    assert_equal "Fortune 1000", c.name
    assert_equal 1000, c.rating
    assert c.valid?
902
    assert !c.persisted?
903 904 905 906 907 908 909
  end

  def test_find_or_create_from_one_attribute_should_set_attribute_even_when_protected_and_also_set_the_hash
    c = Company.find_or_create_by_rating(1000, {:name => "Fortune 1000"})
    assert_equal "Fortune 1000", c.name
    assert_equal 1000, c.rating
    assert c.valid?
910
    assert c.persisted?
911 912
  end

913 914 915 916 917
  def test_find_or_initialize_should_set_protected_attributes_if_given_as_block
    c = Company.find_or_initialize_by_name(:name => "Fortune 1000") { |f| f.rating = 1000 }
    assert_equal "Fortune 1000", c.name
    assert_equal 1000.to_f, c.rating.to_f
    assert c.valid?
918
    assert !c.persisted?
919 920 921 922 923 924 925
  end

  def test_find_or_create_should_set_protected_attributes_if_given_as_block
    c = Company.find_or_create_by_name(:name => "Fortune 1000") { |f| f.rating = 1000 }
    assert_equal "Fortune 1000", c.name
    assert_equal 1000.to_f, c.rating.to_f
    assert c.valid?
926
    assert c.persisted?
927
  end
928

929 930 931 932 933 934 935 936
  def test_find_or_create_should_work_with_block_on_first_call
	  class << Company
		undef_method(:find_or_create_by_name) if method_defined?(:find_or_create_by_name)
	  end
    c = Company.find_or_create_by_name(:name => "Fortune 1000") { |f| f.rating = 1000 }
    assert_equal "Fortune 1000", c.name
    assert_equal 1000.to_f, c.rating.to_f
    assert c.valid?
937
    assert c.persisted?
938 939
  end

940 941 942 943
  def test_find_or_initialize_from_two_attributes
    another = Topic.find_or_initialize_by_title_and_author_name("Another topic","John")
    assert_equal "Another topic", another.title
    assert_equal "John", another.author_name
944
    assert !another.persisted?
945
  end
946

947 948 949 950
  def test_find_or_initialize_from_two_attributes_but_passing_only_one
    assert_raise(ArgumentError) { Topic.find_or_initialize_by_title_and_author_name("Another topic") }
  end

951 952 953 954
  def test_find_or_initialize_from_one_aggregate_attribute_and_one_not
    new_customer = Customer.find_or_initialize_by_balance_and_name(Money.new(123), "Elizabeth")
    assert_equal 123, new_customer.balance.amount
    assert_equal "Elizabeth", new_customer.name
955
    assert !new_customer.persisted?
956 957
  end

958 959 960 961 962
  def test_find_or_initialize_from_one_attribute_and_hash
    sig38 = Company.find_or_initialize_by_name({:name => "38signals", :firm_id => 17, :client_of => 23})
    assert_equal "38signals", sig38.name
    assert_equal 17, sig38.firm_id
    assert_equal 23, sig38.client_of
963
    assert !sig38.persisted?
964
  end
965

966 967 968 969 970 971
  def test_find_or_initialize_from_one_aggregate_attribute_and_hash
    balance = Money.new(123)
    name = "Elizabeth"
    new_customer = Customer.find_or_initialize_by_balance({:balance => balance, :name => name})
    assert_equal balance, new_customer.balance
    assert_equal name, new_customer.name
972
    assert !new_customer.persisted?
973 974
  end

D
David Heinemeier Hansson 已提交
975
  def test_find_with_bad_sql
976
    assert_raise(ActiveRecord::StatementInvalid) { Topic.find_by_sql "select 1 from badtable" }
D
David Heinemeier Hansson 已提交
977 978
  end

979
  def test_dynamic_finder_with_invalid_params
980
    assert_raise(ArgumentError) { Topic.find_by_title 'No Title', :join => "It should be `joins'" }
981 982
  end

983
  def test_find_all_with_join
J
Jon Leighton 已提交
984
    developers_on_project_one = Developer.scoped(
985
      :joins => 'LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id',
J
Jon Leighton 已提交
986 987
      :where => 'project_id=1'
    ).all
988
    assert_equal 3, developers_on_project_one.length
989 990 991
    developer_names = developers_on_project_one.map { |d| d.name }
    assert developer_names.include?('David')
    assert developer_names.include?('Jamis')
992
  end
993

994
  def test_joins_dont_clobber_id
J
Jon Leighton 已提交
995
    first = Firm.scoped(
996
      :joins => 'INNER JOIN companies clients ON clients.firm_id = companies.id',
J
Jon Leighton 已提交
997 998
      :where => 'companies.id = 1'
    ).first
999 1000 1001
    assert_equal 1, first.id
  end

1002
  def test_joins_with_string_array
J
Jon Leighton 已提交
1003
    person_with_reader_and_post = Post.scoped(
1004 1005 1006 1007 1008 1009 1010 1011
      :joins => [
        "INNER JOIN categorizations ON categorizations.post_id = posts.id",
        "INNER JOIN categories ON categories.id = categorizations.category_id AND categories.type = 'SpecialCategory'"
      ]
    )
    assert_equal 1, person_with_reader_and_post.size
  end

1012 1013
  def test_find_by_id_with_conditions_with_or
    assert_nothing_raised do
J
Jon Leighton 已提交
1014
      Post.where("posts.id <= 3 OR posts.#{QUOTED_TYPE} = 'Post'").find([1,2,3])
1015 1016
    end
  end
1017

1018 1019
  # http://dev.rubyonrails.org/ticket/6778
  def test_find_ignores_previously_inserted_record
A
Aaron Patterson 已提交
1020
    Post.create!(:title => 'test', :body => 'it out')
1021 1022 1023
    assert_equal [], Post.find_all_by_id(nil)
  end

1024 1025 1026 1027 1028
  def test_find_by_empty_ids
    assert_equal [], Post.find([])
  end

  def test_find_by_empty_in_condition
1029
    assert_equal [], Post.where('id in (?)', [])
1030 1031 1032
  end

  def test_find_by_records
1033
    p1, p2 = Post.scoped(:limit => 2, :order => 'id asc').all
J
Jon Leighton 已提交
1034 1035
    assert_equal [p1, p2], Post.scoped(:where => ['id in (?)', [p1, p2]], :order => 'id asc')
    assert_equal [p1, p2], Post.scoped(:where => ['id in (?)', [p1, p2.id]], :order => 'id asc')
1036 1037
  end

1038 1039 1040 1041 1042 1043 1044 1045 1046
  def test_select_value
    assert_equal "37signals", Company.connection.select_value("SELECT name FROM companies WHERE id = 1")
    assert_nil Company.connection.select_value("SELECT name FROM companies WHERE id = -1")
    # make sure we didn't break count...
    assert_equal 0, Company.count_by_sql("SELECT COUNT(*) FROM companies WHERE name = 'Halliburton'")
    assert_equal 1, Company.count_by_sql("SELECT COUNT(*) FROM companies WHERE name = '37signals'")
  end

  def test_select_values
1047 1048
    assert_equal ["1","2","3","4","5","6","7","8","9", "10"], Company.connection.select_values("SELECT id FROM companies ORDER BY id").map! { |i| i.to_s }
    assert_equal ["37signals","Summit","Microsoft", "Flamboyant Software", "Ex Nihilo", "RailsCore", "Leetsoft", "Jadedpixel", "Odegy", "Ex Nihilo Part Deux"], Company.connection.select_values("SELECT name FROM companies ORDER BY id")
1049 1050
  end

1051 1052
  def test_select_rows
    assert_equal(
1053
      [["1", "1", nil, "37signals"],
1054 1055
       ["2", "1", "2", "Summit"],
       ["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 1060
  end

1061
  def test_find_with_order_on_included_associations_with_construct_finder_sql_for_association_limiting_and_is_distinct
J
Jon Leighton 已提交
1062
    assert_equal 2, Post.scoped(:includes => { :authors => :author_address }, :order => 'author_addresses.id DESC ', :limit => 2).all.size
1063

J
Jon Leighton 已提交
1064
    assert_equal 3, Post.scoped(:includes => { :author => :author_address, :authors => :author_address},
1065
                              :order => 'author_addresses_authors.id DESC ', :limit => 3).all.size
1066 1067
  end

1068
  def test_find_with_nil_inside_set_passed_for_one_attribute
J
Jon Leighton 已提交
1069 1070
    client_of = Company.scoped(
      :where => {
1071 1072 1073 1074 1075
        :client_of => [2, 1, nil],
        :name => ['37signals', 'Summit', 'Microsoft'] },
      :order => 'client_of DESC'
    ).map { |x| x.client_of }

1076 1077
    assert client_of.include?(nil)
    assert_equal [2, 1].sort, client_of.compact.sort
1078 1079 1080
  end

  def test_find_with_nil_inside_set_passed_for_attribute
J
Jon Leighton 已提交
1081 1082
    client_of = Company.scoped(
      :where => { :client_of => [nil] },
1083 1084 1085
      :order => 'client_of DESC'
    ).map { |x| x.client_of }

1086
    assert_equal [], client_of.compact
1087 1088
  end

1089
  def test_with_limiting_with_custom_select
J
Jon Leighton 已提交
1090 1091
    posts = Post.references(:authors).scoped(
      :includes => :author, :select => ' posts.*, authors.id as "author_id"',
J
Jon Leighton 已提交
1092
      :limit => 3, :order => 'posts.id'
J
Jon Leighton 已提交
1093
    ).all
1094 1095
    assert_equal 3, posts.size
    assert_equal [0, 1, 1], posts.map(&:author_id).sort
1096
  end
1097

1098
  def test_find_one_message_with_custom_primary_key
1099
    Toy.primary_key = :name
1100 1101 1102 1103 1104 1105 1106
    begin
      Toy.find 'Hello World!'
    rescue ActiveRecord::RecordNotFound => e
      assert_equal 'Couldn\'t find Toy with name=Hello World!', e.message
    end
  end

1107
  def test_finder_with_offset_string
1108
    assert_nothing_raised(ActiveRecord::StatementInvalid) { Topic.scoped(:offset => "3").all }
1109 1110
  end

D
David Heinemeier Hansson 已提交
1111 1112 1113 1114 1115 1116 1117 1118
  protected
    def bind(statement, *vars)
      if vars.first.is_a?(Hash)
        ActiveRecord::Base.send(:replace_named_bind_variables, statement, vars.first)
      else
        ActiveRecord::Base.send(:replace_bind_variables, statement, vars)
      end
    end
1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132

    def with_env_tz(new_tz = 'US/Eastern')
      old_tz, ENV['TZ'] = ENV['TZ'], new_tz
      yield
    ensure
      old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
    end

    def with_active_record_default_timezone(zone)
      old_zone, ActiveRecord::Base.default_timezone = ActiveRecord::Base.default_timezone, zone
      yield
    ensure
      ActiveRecord::Base.default_timezone = old_zone
    end
D
David Heinemeier Hansson 已提交
1133
end