finder_test.rb 44.3 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
require 'models/comment'
require 'models/company'
7
require 'models/tagging'
J
Jeremy Kemper 已提交
8 9 10
require 'models/topic'
require 'models/reply'
require 'models/entrant'
11
require 'models/project'
J
Jeremy Kemper 已提交
12
require 'models/developer'
A
Arun Agrawal 已提交
13
require 'models/computer'
14
require 'models/customer'
15
require 'models/toy'
16
require 'models/matey'
17
require 'models/dog'
18 19
require 'models/car'
require 'models/tyre'
D
David Heinemeier Hansson 已提交
20

21
class FinderTest < ActiveRecord::TestCase
R
Fix...  
Ryuta Kamizono 已提交
22
  fixtures :companies, :topics, :entrants, :developers, :developers_projects, :posts, :comments, :accounts, :authors, :author_addresses, :customers, :categories, :categorizations, :cars
D
David Heinemeier Hansson 已提交
23

24 25 26 27 28 29 30 31 32 33 34 35
  def test_find_by_id_with_hash
    assert_raises(ActiveRecord::StatementInvalid) do
      Post.find_by_id(:limit => 1)
    end
  end

  def test_find_by_title_and_id_with_hash
    assert_raises(ActiveRecord::StatementInvalid) do
      Post.find_by_title_and_id('foo', :limit => 1)
    end
  end

D
David Heinemeier Hansson 已提交
36
  def test_find
37
    assert_equal(topics(:first).title, Topic.find(1).title)
D
David Heinemeier Hansson 已提交
38
  end
39

40
  def test_find_with_proc_parameter_and_block
S
Sean Griffin 已提交
41
    exception = assert_raises(RuntimeError) do
42 43
      Topic.all.find(-> { raise "should happen" }) { |e| e.title == "non-existing-title" }
    end
S
Sean Griffin 已提交
44
    assert_equal "should happen", exception.message
45

46
    assert_nothing_raised do
47 48 49 50
      Topic.all.find(-> { raise "should not happen" }) { |e| e.title == topics(:first).title }
    end
  end

51 52 53 54 55 56 57 58 59 60
  def test_find_with_ids_returning_ordered
    records = Topic.find([4,2,5])
    assert_equal 'The Fourth Topic of the day', records[0].title
    assert_equal 'The Second Topic of the day', records[1].title
    assert_equal 'The Fifth Topic of the day', records[2].title

    records = Topic.find(4,2,5)
    assert_equal 'The Fourth Topic of the day', records[0].title
    assert_equal 'The Second Topic of the day', records[1].title
    assert_equal 'The Fifth Topic of the day', records[2].title
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78

    records = Topic.find(['4','2','5'])
    assert_equal 'The Fourth Topic of the day', records[0].title
    assert_equal 'The Second Topic of the day', records[1].title
    assert_equal 'The Fifth Topic of the day', records[2].title

    records = Topic.find('4','2','5')
    assert_equal 'The Fourth Topic of the day', records[0].title
    assert_equal 'The Second Topic of the day', records[1].title
    assert_equal 'The Fifth Topic of the day', records[2].title
  end

  def test_find_with_ids_and_order_clause
    # The order clause takes precedence over the informed ids
    records = Topic.order(:author_name).find([5,3,1])
    assert_equal 'The Third Topic of the day', records[0].title
    assert_equal 'The First Topic',            records[1].title
    assert_equal 'The Fifth Topic of the day', records[2].title
79 80 81 82 83

    records = Topic.order(:id).find([5,3,1])
    assert_equal 'The First Topic',            records[0].title
    assert_equal 'The Third Topic of the day', records[1].title
    assert_equal 'The Fifth Topic of the day', records[2].title
84 85
  end

86 87 88
  def test_find_with_ids_with_limit_and_order_clause
    # The order clause takes precedence over the informed ids
    records = Topic.limit(2).order(:id).find([5,3,1])
89
    assert_equal 2, records.size
90 91 92 93 94 95 96 97
    assert_equal 'The First Topic',            records[0].title
    assert_equal 'The Third Topic of the day', records[1].title
  end

  def test_find_with_ids_and_limit
    records = Topic.limit(3).find([3,2,5,1,4])
    assert_equal 3, records.size
    assert_equal 'The Third Topic of the day',  records[0].title
98
    assert_equal 'The Second Topic of the day', records[1].title
99 100 101
    assert_equal 'The Fifth Topic of the day',  records[2].title
  end

102 103
  def test_find_with_ids_where_and_limit
    # Please note that Topic 1 is the only not approved so
104
    # if it were among the first 3 it would raise an ActiveRecord::RecordNotFound
105 106 107 108 109 110 111
    records = Topic.where(approved: true).limit(3).find([3,2,5,1,4])
    assert_equal 3, records.size
    assert_equal 'The Third Topic of the day',  records[0].title
    assert_equal 'The Second Topic of the day', records[1].title
    assert_equal 'The Fifth Topic of the day',  records[2].title
  end

112
  def test_find_with_ids_and_offset
113 114 115 116 117
    records = Topic.offset(2).find([3,2,5,1,4])
    assert_equal 3, records.size
    assert_equal 'The Fifth Topic of the day',  records[0].title
    assert_equal 'The First Topic',             records[1].title
    assert_equal 'The Fourth Topic of the day', records[2].title
118 119
  end

120 121 122 123 124 125
  def test_find_passing_active_record_object_is_deprecated
    assert_deprecated do
      Topic.find(Topic.last)
    end
  end

126
  def test_symbols_table_ref
127
    gc_disabled = GC.disable
128
    Post.where("author_id" => nil)  # warm up
129 130 131
    x = Symbol.all_symbols.count
    Post.where("title" => {"xxxqqqq" => "bar"})
    assert_equal x, Symbol.all_symbols.count
R
Ryuta Kamizono 已提交
132 133
  ensure
    GC.enable if gc_disabled == false
134 135
  end

136 137 138 139 140
  # 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
141

D
David Heinemeier Hansson 已提交
142
  def test_exists
143 144 145 146 147 148
    assert_equal true, Topic.exists?(1)
    assert_equal true, Topic.exists?("1")
    assert_equal true, Topic.exists?(title: "The First Topic")
    assert_equal true, Topic.exists?(heading: "The First Topic")
    assert_equal true, Topic.exists?(:author_name => "Mary", :approved => true)
    assert_equal true, Topic.exists?(["parent_id = ?", 1])
149
    assert_equal true, Topic.exists?(id: [1, 9999])
150 151

    assert_equal false, Topic.exists?(45)
152
    assert_equal false, Topic.exists?(Topic.new.id)
153

154 155 156
    assert_raise(NoMethodError) { Topic.exists?([1,2]) }
  end

157 158 159 160 161 162 163 164 165 166 167 168 169
  def test_exists_with_polymorphic_relation
    post = Post.create!(title: 'Post', body: 'default', taggings: [Tagging.new(comment: 'tagging comment')])
    relation = Post.tagged_with_comment('tagging comment')

    assert_equal true, relation.exists?(title: ['Post'])
    assert_equal true, relation.exists?(['title LIKE ?', 'Post%'])
    assert_equal true, relation.exists?
    assert_equal true, relation.exists?(post.id)
    assert_equal true, relation.exists?(post.id.to_s)

    assert_equal false, relation.exists?(false)
  end

170 171 172 173 174 175
  def test_exists_passing_active_record_object_is_deprecated
    assert_deprecated do
      Topic.exists?(Topic.new)
    end
  end

176
  def test_exists_returns_false_when_parameter_has_invalid_type
177
    assert_equal false, Topic.exists?("foo")
178
    assert_equal false, Topic.exists?(("9"*53).to_i) # number that's bigger than int
D
David Heinemeier Hansson 已提交
179
  end
180

181
  def test_exists_does_not_select_columns_without_alias
182
    assert_sql(/SELECT\W+1 AS one FROM ["`]topics["`]/i) do
183 184 185 186
      Topic.exists?
    end
  end

187
  def test_exists_returns_true_with_one_record_and_no_args
188
    assert_equal true, Topic.exists?
189
  end
190

E
Egor Lynko 已提交
191
  def test_exists_returns_false_with_false_arg
192
    assert_equal false, Topic.exists?(false)
E
Egor Lynko 已提交
193 194
  end

195 196 197
  # 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
198 199 200 201 202
    assert_equal false, Topic.exists?(nil)
    assert_equal true, Topic.exists?

    assert_equal false, Topic.first.replies.exists?(nil)
    assert_equal true, Topic.first.replies.exists?
203 204
  end

205 206
  # ensures +exists?+ runs valid SQL by excluding order value
  def test_exists_with_order
207
    assert_equal true, Topic.order(:id).distinct.exists?
208 209
  end

210
  def test_exists_with_includes_limit_and_empty_result
211 212
    assert_equal false, Topic.includes(:replies).limit(0).exists?
    assert_equal false, Topic.includes(:replies).limit(1).where('0 = 1').exists?
213 214
  end

215 216
  def test_exists_with_distinct_association_includes_and_limit
    author = Author.first
217 218
    assert_equal false, author.unique_categorized_posts.includes(:special_comments).limit(0).exists?
    assert_equal true, author.unique_categorized_posts.includes(:special_comments).limit(1).exists?
219 220 221 222
  end

  def test_exists_with_distinct_association_includes_limit_and_order
    author = Author.first
223 224
    assert_equal false, author.unique_categorized_posts.includes(:special_comments).order('comments.tags_count DESC').limit(0).exists?
    assert_equal true, author.unique_categorized_posts.includes(:special_comments).order('comments.tags_count DESC').limit(1).exists?
225 226
  end

227
  def test_exists_with_empty_table_and_no_args_given
228
    Topic.delete_all
229
    assert_equal false, Topic.exists?
230
  end
231

232 233
  def test_exists_with_aggregate_having_three_mappings
    existing_address = customers(:david).address
234
    assert_equal true, Customer.exists?(:address => existing_address)
235 236 237 238
  end

  def test_exists_with_aggregate_having_three_mappings_with_one_difference
    existing_address = customers(:david).address
239
    assert_equal false, Customer.exists?(:address =>
240
      Address.new(existing_address.street, existing_address.city, existing_address.country + "1"))
241
    assert_equal false, Customer.exists?(:address =>
242
      Address.new(existing_address.street, existing_address.city + "1", existing_address.country))
243
    assert_equal false, Customer.exists?(:address =>
244 245 246
      Address.new(existing_address.street + "1", existing_address.city, existing_address.country))
  end

247
  def test_exists_does_not_instantiate_records
248 249 250
    assert_not_called(Developer, :instantiate) do
      Developer.exists?
    end
251 252
  end

D
David Heinemeier Hansson 已提交
253 254 255 256
  def test_find_by_array_of_one_id
    assert_kind_of(Array, Topic.find([ 1 ]))
    assert_equal(1, Topic.find([ 1 ]).length)
  end
257

D
David Heinemeier Hansson 已提交
258
  def test_find_by_ids
259 260 261 262 263
    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
264
    assert_equal 2, Entrant.limit(2).find([1,3,2]).size
265 266 267
    entrants = Entrant.limit(3).offset(2).find([1,3,2])
    assert_equal 1, entrants.size
    assert_equal 'Ruby Guru', entrants.first.name
268 269 270 271

    # 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.
J
Jon Leighton 已提交
272
    devs = Developer.all
273
    last_devs = Developer.limit(3).offset(9).find devs.map(&:id)
274
    assert_equal 2, last_devs.size
275 276
    assert_equal 'fixture_10', last_devs[0].name
    assert_equal 'Jamis', last_devs[1].name
D
David Heinemeier Hansson 已提交
277 278
  end

279 280 281 282 283 284 285 286 287 288 289 290
  def test_find_with_large_number
    assert_raises(ActiveRecord::RecordNotFound) { Topic.find('9999999999999999999999999999999') }
  end

  def test_find_by_with_large_number
    assert_nil Topic.find_by(id: '9999999999999999999999999999999')
  end

  def test_find_by_id_with_large_number
    assert_nil Topic.find_by_id('9999999999999999999999999999999')
  end

291 292 293 294 295 296 297 298 299 300
  def test_find_on_relation_with_large_number
    assert_nil Topic.where('1=1').find_by(id: 9999999999999999999999999999999)
  end

  def test_find_by_bang_on_relation_with_large_number
    assert_raises(ActiveRecord::RecordNotFound) do
      Topic.where('1=1').find_by!(id: 9999999999999999999999999999999)
    end
  end

301 302 303 304
  def test_find_an_empty_array
    assert_equal [], Topic.find([])
  end

305 306 307 308
  def test_find_doesnt_have_implicit_ordering
    assert_sql(/^((?!ORDER).)*$/) { Topic.find(1) }
  end

D
David Heinemeier Hansson 已提交
309
  def test_find_by_ids_missing_one
310
    assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, 2, 45) }
D
David Heinemeier Hansson 已提交
311
  end
312

313
  def test_find_with_group_and_sanitized_having_method
314
    developers = Developer.group(:salary).having("sum(salary) > ?", 10000).select('salary').to_a
315 316 317 318 319
    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 已提交
320 321
  def test_find_with_entire_select_statement
    topics = Topic.find_by_sql "SELECT * FROM topics WHERE author_name = 'Mary'"
322

D
David Heinemeier Hansson 已提交
323
    assert_equal(1, topics.size)
324
    assert_equal(topics(:second).title, topics.first.title)
D
David Heinemeier Hansson 已提交
325
  end
326

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

D
David Heinemeier Hansson 已提交
330
    assert_equal(1, topics.size)
331
    assert_equal(topics(:second).title, topics.first.title)
D
David Heinemeier Hansson 已提交
332
  end
333

334 335 336 337
  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
338

339 340 341 342 343 344
  def test_find_by_association_subquery
    author = authors(:david)
    assert_equal author.post, Post.find_by(author: Author.where(id: author))
    assert_equal author.post, Post.find_by(author_id: Author.where(id: author))
  end

345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
  def test_take
    assert_equal topics(:first), Topic.take
  end

  def test_take_failing
    assert_nil Topic.where("title = 'This title does not exist'").take
  end

  def test_take_bang_present
    assert_nothing_raised do
      assert_equal topics(:second), Topic.where("title = 'The Second Topic of the day'").take!
    end
  end

  def test_take_bang_missing
360
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
361 362 363 364
      Topic.where("title = 'This title does not exist'").take!
    end
  end

365
  def test_first
366
    assert_equal topics(:second).title, Topic.where("title = 'The Second Topic of the day'").first.title
367
  end
368

369
  def test_first_failing
370
    assert_nil Topic.where("title = 'The Second Topic of the day!'").first
371
  end
D
David Heinemeier Hansson 已提交
372

373 374 375 376 377 378 379
  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
380
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
381 382 383 384
      Topic.where("title = 'This title does not exist'").first!
    end
  end

385 386 387 388 389 390
  def test_first_have_primary_key_order_by_default
    expected = topics(:first)
    expected.touch # PostgreSQL changes the default order if no order clause is used
    assert_equal expected, Topic.first
  end

391
  def test_model_class_responds_to_first_bang
392 393
    assert Topic.first!
    Topic.delete_all
394
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
395 396 397 398
      Topic.first!
    end
  end

399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415
  def test_second
    assert_equal topics(:second).title, Topic.second.title
  end

  def test_second_with_offset
    assert_equal topics(:fifth), Topic.offset(3).second
  end

  def test_second_have_primary_key_order_by_default
    expected = topics(:second)
    expected.touch # PostgreSQL changes the default order if no order clause is used
    assert_equal expected, Topic.second
  end

  def test_model_class_responds_to_second_bang
    assert Topic.second!
    Topic.delete_all
416
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
      Topic.second!
    end
  end

  def test_third
    assert_equal topics(:third).title, Topic.third.title
  end

  def test_third_with_offset
    assert_equal topics(:fifth), Topic.offset(2).third
  end

  def test_third_have_primary_key_order_by_default
    expected = topics(:third)
    expected.touch # PostgreSQL changes the default order if no order clause is used
    assert_equal expected, Topic.third
  end

  def test_model_class_responds_to_third_bang
    assert Topic.third!
    Topic.delete_all
438
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
      Topic.third!
    end
  end

  def test_fourth
    assert_equal topics(:fourth).title, Topic.fourth.title
  end

  def test_fourth_with_offset
    assert_equal topics(:fifth), Topic.offset(1).fourth
  end

  def test_fourth_have_primary_key_order_by_default
    expected = topics(:fourth)
    expected.touch # PostgreSQL changes the default order if no order clause is used
    assert_equal expected, Topic.fourth
  end

  def test_model_class_responds_to_fourth_bang
    assert Topic.fourth!
    Topic.delete_all
460
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
      Topic.fourth!
    end
  end

  def test_fifth
    assert_equal topics(:fifth).title, Topic.fifth.title
  end

  def test_fifth_with_offset
    assert_equal topics(:fifth), Topic.offset(0).fifth
  end

  def test_fifth_have_primary_key_order_by_default
    expected = topics(:fifth)
    expected.touch # PostgreSQL changes the default order if no order clause is used
    assert_equal expected, Topic.fifth
  end

  def test_model_class_responds_to_fifth_bang
    assert Topic.fifth!
    Topic.delete_all
482
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
483 484 485 486
      Topic.fifth!
    end
  end

487 488
  def test_second_to_last
    assert_equal topics(:fourth).title, Topic.second_to_last.title
489 490 491

    # test with offset
    assert_equal topics(:fourth), Topic.offset(1).second_to_last
492 493 494
    assert_equal topics(:fourth), Topic.offset(2).second_to_last
    assert_equal topics(:fourth), Topic.offset(3).second_to_last
    assert_equal nil, Topic.offset(4).second_to_last
495 496 497
    assert_equal nil, Topic.offset(5).second_to_last

    #test with limit
498
    # assert_equal nil, Topic.limit(1).second # TODO: currently failing
499
    assert_equal nil, Topic.limit(1).second_to_last
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
  end

  def test_second_to_last_have_primary_key_order_by_default
    expected = topics(:fourth)
    expected.touch # PostgreSQL changes the default order if no order clause is used
    assert_equal expected, Topic.second_to_last
  end

  def test_model_class_responds_to_second_to_last_bang
    assert Topic.second_to_last!
    Topic.delete_all
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
      Topic.second_to_last!
    end
  end

  def test_third_to_last
    assert_equal topics(:third).title, Topic.third_to_last.title
518 519 520

    # test with offset
    assert_equal topics(:third), Topic.offset(1).third_to_last
521 522 523
    assert_equal topics(:third), Topic.offset(2).third_to_last
    assert_equal nil, Topic.offset(3).third_to_last
    assert_equal nil, Topic.offset(4).third_to_last
524 525 526
    assert_equal nil, Topic.offset(5).third_to_last

    # test with limit
527
    # assert_equal nil, Topic.limit(1).third # TODO: currently failing
528
    assert_equal nil, Topic.limit(1).third_to_last
529
    # assert_equal nil, Topic.limit(2).third # TODO: currently failing
530
    assert_equal nil, Topic.limit(2).third_to_last
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
  end

  def test_third_to_last_have_primary_key_order_by_default
    expected = topics(:third)
    expected.touch # PostgreSQL changes the default order if no order clause is used
    assert_equal expected, Topic.third_to_last
  end

  def test_model_class_responds_to_third_to_last_bang
    assert Topic.third_to_last!
    Topic.delete_all
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
      Topic.third_to_last!
    end
  end

547 548 549 550 551 552 553
  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
554
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
555 556 557 558
      Topic.where("title = 'This title does not exist'").last!
    end
  end

559
  def test_model_class_responds_to_last_bang
560
    assert_equal topics(:fifth), Topic.last!
561
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
562 563 564 565 566
      Topic.delete_all
      Topic.last!
    end
  end

567
  def test_take_and_first_and_last_with_integer_should_use_sql_limit
568 569 570
    assert_sql(/LIMIT|ROWNUM <=/) { Topic.take(3).entries }
    assert_sql(/LIMIT|ROWNUM <=/) { Topic.first(2).entries }
    assert_sql(/LIMIT|ROWNUM <=/) { Topic.last(5).entries }
571 572 573 574 575 576
  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

577 578 579 580
  def test_last_with_integer_and_order_should_use_sql_limit
    relation = Topic.order("title")
    assert_queries(1) { relation.last(5) }
    assert !relation.loaded?
581 582
  end

583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
  def test_last_with_integer_and_reorder_should_use_sql_limit
    relation = Topic.reorder("title")
    assert_queries(1) { relation.last(5) }
    assert !relation.loaded?
  end

  def test_last_on_loaded_relation_should_not_use_sql
    relation  = Topic.limit(10).load
    assert_no_queries do
      relation.last
      relation.last(2)
    end
  end

  def test_last_with_irreversible_order
    assert_deprecated do
      Topic.order("coalesce(author_name, title)").last
    end
601
  end
602 603 604 605 606 607 608 609 610 611 612 613 614

  def test_last_on_relation_with_limit_and_offset
    post = posts('sti_comments')

    comments = post.comments.order(id: :asc)
    assert_equal comments.limit(2).to_a.last, comments.limit(2).last
    assert_equal comments.limit(2).to_a.last(2), comments.limit(2).last(2)
    assert_equal comments.limit(2).to_a.last(3), comments.limit(2).last(3)

    comments = comments.offset(1)
    assert_equal comments.limit(2).to_a.last, comments.limit(2).last
    assert_equal comments.limit(2).to_a.last(2), comments.limit(2).last(2)
    assert_equal comments.limit(2).to_a.last(3), comments.limit(2).last(3)
615 616
  end

617 618
  def test_take_and_first_and_last_with_integer_should_return_an_array
    assert_kind_of Array, Topic.take(5)
619 620 621 622
    assert_kind_of Array, Topic.first(5)
    assert_kind_of Array, Topic.last(5)
  end

D
David Heinemeier Hansson 已提交
623
  def test_unexisting_record_exception_handling
624
    assert_raise(ActiveRecord::RecordNotFound) {
D
David Heinemeier Hansson 已提交
625 626
      Topic.find(1).parent
    }
627

628
    Topic.find(2).topic
D
David Heinemeier Hansson 已提交
629
  end
630

631
  def test_find_only_some_columns
632
    topic = Topic.select("author_name").find(1)
633
    assert_raise(ActiveModel::MissingAttributeError) {topic.title}
634
    assert_raise(ActiveModel::MissingAttributeError) {topic.title?}
635
    assert_nil topic.read_attribute("title")
636 637
    assert_equal "David", topic.author_name
    assert !topic.attribute_present?("title")
638
    assert !topic.attribute_present?(:title)
639
    assert topic.attribute_present?("author_name")
640
    assert_respond_to topic, "author_name"
641
  end
J
Jeremy Kemper 已提交
642

643
  def test_find_on_array_conditions
644 645
    assert Topic.where(["approved = ?", false]).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where(["approved = ?", true]).find(1) }
D
David Heinemeier Hansson 已提交
646
  end
647

648
  def test_find_on_hash_conditions
649 650
    assert Topic.where(approved: false).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where(approved: true).find(1) }
651
  end
652

653
  def test_find_on_hash_conditions_with_qualified_attribute_dot_notation_string
654 655
    assert Topic.where('topics.approved' => false).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where('topics.approved' => true).find(1) }
656 657
  end

658 659 660 661 662
  def test_find_on_hash_conditions_with_qualified_attribute_dot_notation_symbol
    assert Topic.where('topics.approved': false).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where('topics.approved': true).find(1) }
  end

663
  def test_find_on_hash_conditions_with_hashed_table_name
664 665
    assert Topic.where(topics: { approved: false }).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where(topics: { approved: true }).find(1) }
666 667
  end

668 669 670 671 672 673
  def test_find_on_combined_explicit_and_hashed_table_names
    assert Topic.where('topics.approved' => false, topics: { author_name: "David" }).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where('topics.approved' => true, topics: { author_name: "David" }).find(1) }
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where('topics.approved' => false, topics: { author_name: "Melanie" }).find(1) }
  end

674
  def test_find_with_hash_conditions_on_joined_table
675
    firms = Firm.joins(:account).where(:accounts => { :credit_limit => 50 })
676 677 678 679 680
    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
681
    firms = DependentFirm.joins(:account).where(name: 'RailsCore', accounts: { credit_limit: 55..60 })
682 683 684 685
    assert_equal 1, firms.size
    assert_equal companies(:rails_core), firms.first
  end

686 687 688 689 690 691 692 693
  def test_find_on_hash_conditions_with_explicit_table_name_and_aggregate
    david = customers(:david)
    assert Customer.where('customers.name' => david.name, :address => david.address).find(david.id)
    assert_raise(ActiveRecord::RecordNotFound) {
      Customer.where('customers.name' => david.name + "1", :address => david.address).find(david.id)
    }
  end

694
  def test_find_on_association_proxy_conditions
J
Jon Leighton 已提交
695
    assert_equal [1, 2, 3, 5, 6, 7, 8, 9, 10, 12], Comment.where(post_id: authors(:david).posts).map(&:id).sort
696 697
  end

698
  def test_find_on_hash_conditions_with_range
699 700
    assert_equal [1,2], Topic.where(id: 1..2).to_a.map(&:id).sort
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where(id: 2..3).find(1) }
701
  end
702

703
  def test_find_on_hash_conditions_with_end_exclusive_range
704 705 706
    assert_equal [1,2,3], Topic.where(id: 1..3).to_a.map(&:id).sort
    assert_equal [1,2], Topic.where(id: 1...3).to_a.map(&:id).sort
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where(id: 2...3).find(3) }
707 708
  end

709
  def test_find_on_hash_conditions_with_multiple_ranges
710 711
    assert_equal [1,2,3], Comment.where(id: 1..3, post_id: 1..2).to_a.map(&:id).sort
    assert_equal [1], Comment.where(id: 1..1, post_id: 1..10).to_a.map(&:id).sort
712
  end
713

714
  def test_find_on_hash_conditions_with_array_of_integers_and_ranges
715
    assert_equal [1,2,3,5,6,7,8,9], Comment.where(id: [1..2, 3, 5, 6..8, 9]).to_a.map(&:id).sort
716 717
  end

718 719 720 721
  def test_find_on_hash_conditions_with_array_of_ranges
    assert_equal [1,2,6,7,8], Comment.where(id: [1..2, 6..8]).to_a.map(&:id).sort
  end

722
  def test_find_on_multiple_hash_conditions
723 724 725 726
    assert Topic.where(author_name: "David", title: "The First Topic", replies_count: 1, approved: false).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where(author_name: "David", title: "The First Topic", replies_count: 1, approved: true).find(1) }
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where(author_name: "David", title: "HHC", replies_count: 1, approved: false).find(1) }
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where(author_name: "David", title: "The First Topic", replies_count: 1, approved: true).find(1) }
727
  end
728

729
  def test_condition_interpolation
730
    assert_kind_of Firm, Company.where("name = '%s'", "37signals").first
731 732 733
    assert_nil Company.where(["name = '%s'", "37signals!"]).first
    assert_nil Company.where(["name = '%s'", "37signals!' OR 1=1"]).first
    assert_kind_of Time, Topic.where(["id = %d", 1]).first.written_on
734 735
  end

736
  def test_condition_array_interpolation
737 738 739 740
    assert_kind_of Firm, Company.where(["name = '%s'", "37signals"]).first
    assert_nil Company.where(["name = '%s'", "37signals!"]).first
    assert_nil Company.where(["name = '%s'", "37signals!' OR 1=1"]).first
    assert_kind_of Time, Topic.where(["id = %d", 1]).first.written_on
D
David Heinemeier Hansson 已提交
741
  end
742

743
  def test_condition_hash_interpolation
744 745 746
    assert_kind_of Firm, Company.where(name: "37signals").first
    assert_nil Company.where(name: "37signals!").first
    assert_kind_of Time, Topic.where(id: 1).first.written_on
747
  end
748

749
  def test_hash_condition_find_malformed
750
    assert_raise(ActiveRecord::StatementInvalid) {
751
      Company.where(id: 2, dhh: true).first
752 753
    }
  end
754

755 756
  def test_hash_condition_find_with_escaped_characters
    Company.create("name" => "Ain't noth'n like' \#stuff")
757
    assert Company.where(name: "Ain't noth'n like' \#stuff").first
758 759 760
  end

  def test_hash_condition_find_with_array
761 762 763
    p1, p2 = Post.limit(2).order('id asc').to_a
    assert_equal [p1, p2], Post.where(id: [p1, p2]).order('id asc').to_a
    assert_equal [p1, p2], Post.where(id: [p1, p2.id]).order('id asc').to_a
764 765 766
  end

  def test_hash_condition_find_with_nil
767
    topic = Topic.where(last_read: nil).first
768 769
    assert_not_nil topic
    assert_nil topic.last_read
770
  end
D
David Heinemeier Hansson 已提交
771

772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
  def test_hash_condition_find_with_aggregate_having_one_mapping
    balance = customers(:david).balance
    assert_kind_of Money, balance
    found_customer = Customer.where(:balance => balance).first
    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
    found_customer = Customer.where(:gps_location => gps_location).first
    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
    found_customer = Customer.where(:balance => balance.amount).first
    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
    found_customer = Customer.where(:gps_location => gps_location.gps_location).first
    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
    found_customer = Customer.where(:address => address).first
    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
    found_customer = Customer.where(:address => address, :name => customers(:david).name).first
    assert_equal customers(:david), found_customer
  end

814 815
  def test_condition_utc_time_interpolation_with_default_timezone_local
    with_env_tz 'America/New_York' do
816
      with_timezone_config default: :local do
817
        topic = Topic.first
818
        assert_equal topic, Topic.where(['written_on = ?', topic.written_on.getutc]).first
819 820 821 822 823 824
      end
    end
  end

  def test_hash_condition_utc_time_interpolation_with_default_timezone_local
    with_env_tz 'America/New_York' do
825
      with_timezone_config default: :local do
826
        topic = Topic.first
827
        assert_equal topic, Topic.where(written_on: topic.written_on.getutc).first
828 829 830 831 832 833
      end
    end
  end

  def test_condition_local_time_interpolation_with_default_timezone_utc
    with_env_tz 'America/New_York' do
834
      with_timezone_config default: :utc do
835
        topic = Topic.first
836
        assert_equal topic, Topic.where(['written_on = ?', topic.written_on.getlocal]).first
837 838 839 840 841 842
      end
    end
  end

  def test_hash_condition_local_time_interpolation_with_default_timezone_utc
    with_env_tz 'America/New_York' do
843
      with_timezone_config default: :utc do
844
        topic = Topic.first
845
        assert_equal topic, Topic.where(written_on: topic.written_on.getlocal).first
846 847 848 849
      end
    end
  end

D
David Heinemeier Hansson 已提交
850
  def test_bind_variables
851 852 853 854
    assert_kind_of Firm, Company.where(["name = ?", "37signals"]).first
    assert_nil Company.where(["name = ?", "37signals!"]).first
    assert_nil Company.where(["name = ?", "37signals!' OR 1=1"]).first
    assert_kind_of Time, Topic.where(["id = ?", 1]).first.written_on
855
    assert_raise(ActiveRecord::PreparedStatementInvalid) {
856
      Company.where(["id=? AND name = ?", 2]).first
D
David Heinemeier Hansson 已提交
857
    }
858
    assert_raise(ActiveRecord::PreparedStatementInvalid) {
859
     Company.where(["id=?", 2, 3, 4]).first
D
David Heinemeier Hansson 已提交
860 861
    }
  end
862

D
David Heinemeier Hansson 已提交
863 864
  def test_bind_variables_with_quotes
    Company.create("name" => "37signals' go'es agains")
865
    assert Company.where(["name = ?", "37signals' go'es agains"]).first
D
David Heinemeier Hansson 已提交
866 867 868 869
  end

  def test_named_bind_variables_with_quotes
    Company.create("name" => "37signals' go'es agains")
870
    assert Company.where(["name = :name", {name: "37signals' go'es agains"}]).first
D
David Heinemeier Hansson 已提交
871 872 873
  end

  def test_named_bind_variables
874 875 876 877
    assert_kind_of Firm, Company.where(["name = :name", { name: "37signals" }]).first
    assert_nil Company.where(["name = :name", { name: "37signals!" }]).first
    assert_nil Company.where(["name = :name", { name: "37signals!' OR 1=1" }]).first
    assert_kind_of Time, Topic.where(["id = :id", { id: 1 }]).first.written_on
D
David Heinemeier Hansson 已提交
878 879 880
  end

  def test_string_sanitation
881 882
    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 已提交
883 884 885 886 887 888 889 890 891
  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
892
    assert_equal topics(:first), Topic.find_by_title("The First Topic")
D
David Heinemeier Hansson 已提交
893 894
    assert_nil Topic.find_by_title("The First Topic!")
  end
J
Jeremy Kemper 已提交
895

896 897
  def test_find_by_one_attribute_bang
    assert_equal topics(:first), Topic.find_by_title!("The First Topic")
898 899 900
    assert_raises_with_message(ActiveRecord::RecordNotFound, "Couldn't find Topic") do
      Topic.find_by_title!("The First Topic!")
    end
901 902
  end

903 904 905 906 907 908 909
  def test_find_by_on_attribute_that_is_a_reserved_word
    dog_alias = 'Dog'
    dog = Dog.create(alias: dog_alias)

    assert_equal dog, Dog.find_by_alias(dog_alias)
  end

910 911 912 913 914
  def test_find_by_one_attribute_that_is_an_alias
    assert_equal topics(:first), Topic.find_by_heading("The First Topic")
    assert_nil Topic.find_by_heading("The First Topic!")
  end

N
Nikita Afanasenko 已提交
915
  def test_find_by_one_attribute_bang_with_blank_defined
916 917
    blank_topic = BlankTopic.create(title: "The Blank One")
    assert_equal blank_topic, BlankTopic.find_by_title!("The Blank One")
N
Nikita Afanasenko 已提交
918 919
  end

920
  def test_find_by_one_attribute_with_conditions
J
Jon Leighton 已提交
921
    assert_equal accounts(:rails_core_account), Account.where('firm_id = ?', 6).find_by_credit_limit(50)
922 923
  end

924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957
  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

958 959
  def test_dynamic_finder_on_one_attribute_with_conditions_returns_same_results_after_caching
    # ensure this test can run independently of order
A
Akira Matsuda 已提交
960
    class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.public_methods.include?(:find_by_credit_limit)
J
Jon Leighton 已提交
961 962
    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
963 964
  end

965
  def test_find_by_one_attribute_with_several_options
J
Jon Leighton 已提交
966
    assert_equal accounts(:unknown), Account.order('id DESC').where('id != ?', 3).find_by_credit_limit(50)
967
  end
968

D
David Heinemeier Hansson 已提交
969
  def test_find_by_one_missing_attribute
970
    assert_raise(NoMethodError) { Topic.find_by_undertitle("The First Topic!") }
D
David Heinemeier Hansson 已提交
971
  end
972

973
  def test_find_by_invalid_method_syntax
974 975 976 977
    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") }
978
  end
D
David Heinemeier Hansson 已提交
979 980

  def test_find_by_two_attributes
981
    assert_equal topics(:first), Topic.find_by_title_and_author_name("The First Topic", "David")
D
David Heinemeier Hansson 已提交
982 983 984
    assert_nil Topic.find_by_title_and_author_name("The First Topic", "Mary")
  end

985 986 987 988
  def test_find_by_two_attributes_but_passing_only_one
    assert_raise(ArgumentError) { Topic.find_by_title_and_author_name("The First Topic") }
  end

L
Lauro Caetano 已提交
989
  def test_find_last_with_offset
990
    devs = Developer.order('id')
L
Lauro Caetano 已提交
991 992 993 994 995 996 997

    assert_equal devs[2], Developer.offset(2).first
    assert_equal devs[-3], Developer.offset(2).last
    assert_equal devs[-3], Developer.offset(2).last
    assert_equal devs[-3], Developer.offset(2).order('id DESC').first
  end

D
David Heinemeier Hansson 已提交
998 999 1000 1001 1002
  def test_find_by_nil_attribute
    topic = Topic.find_by_last_read nil
    assert_not_nil topic
    assert_nil topic.last_read
  end
1003

D
David Heinemeier Hansson 已提交
1004 1005 1006 1007 1008 1009
  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_with_bad_sql
1010
    assert_raise(ActiveRecord::StatementInvalid) { Topic.find_by_sql "select 1 from badtable" }
D
David Heinemeier Hansson 已提交
1011 1012
  end

1013
  def test_find_all_with_join
1014 1015 1016
    developers_on_project_one = Developer.
      joins('LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id').
      where('project_id=1').to_a
1017
    assert_equal 3, developers_on_project_one.length
1018
    developer_names = developers_on_project_one.map(&:name)
1019 1020
    assert developer_names.include?('David')
    assert developer_names.include?('Jamis')
1021
  end
1022

1023
  def test_joins_dont_clobber_id
1024 1025 1026
    first = Firm.
      joins('INNER JOIN companies clients ON clients.firm_id = companies.id').
      where('companies.id = 1').first
1027 1028 1029
    assert_equal 1, first.id
  end

1030
  def test_joins_with_string_array
1031 1032 1033 1034
    person_with_reader_and_post = Post.
      joins(["INNER JOIN categorizations ON categorizations.post_id = posts.id",
             "INNER JOIN categories ON categories.id = categorizations.category_id AND categories.type = 'SpecialCategory'"
            ])
1035 1036 1037
    assert_equal 1, person_with_reader_and_post.size
  end

1038 1039
  def test_find_by_id_with_conditions_with_or
    assert_nothing_raised do
J
Jon Leighton 已提交
1040
      Post.where("posts.id <= 3 OR posts.#{QUOTED_TYPE} = 'Post'").find([1,2,3])
1041 1042
    end
  end
1043

1044
  def test_find_ignores_previously_inserted_record
A
Aaron Patterson 已提交
1045
    Post.create!(:title => 'test', :body => 'it out')
J
Jon Leighton 已提交
1046
    assert_equal [], Post.where(id: nil)
1047 1048
  end

1049 1050 1051 1052 1053
  def test_find_by_empty_ids
    assert_equal [], Post.find([])
  end

  def test_find_by_empty_in_condition
1054
    assert_equal [], Post.where('id in (?)', [])
1055 1056 1057
  end

  def test_find_by_records
1058 1059 1060
    p1, p2 = Post.limit(2).order('id asc').to_a
    assert_equal [p1, p2], Post.where(['id in (?)', [p1, p2]]).order('id asc')
    assert_equal [p1, p2], Post.where(['id in (?)', [p1, p2.id]]).order('id asc')
1061 1062
  end

1063 1064 1065 1066 1067 1068 1069 1070 1071
  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
1072
    assert_equal ["1","2","3","4","5","6","7","8","9", "10", "11"], Company.connection.select_values("SELECT id FROM companies ORDER BY id").map!(&:to_s)
1073
    assert_equal ["37signals","Summit","Microsoft", "Flamboyant Software", "Ex Nihilo", "RailsCore", "Leetsoft", "Jadedpixel", "Odegy", "Ex Nihilo Part Deux", "Apex"], Company.connection.select_values("SELECT name FROM companies ORDER BY id")
1074 1075
  end

1076 1077
  def test_select_rows
    assert_equal(
1078
      [["1", "1", nil, "37signals"],
1079 1080
       ["2", "1", "2", "Summit"],
       ["3", "1", "1", "Microsoft"]],
1081
      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?}})
1082
    assert_equal [["1", "37signals"], ["2", "Summit"], ["3", "Microsoft"]],
1083
      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?}}
1084 1085
  end

1086
  def test_find_with_order_on_included_associations_with_construct_finder_sql_for_association_limiting_and_is_distinct
R
Fix...  
Ryuta Kamizono 已提交
1087 1088 1089
    assert_equal 2, Post.includes(authors: :author_address).
      where.not(author_addresses: { id: nil }).
      order('author_addresses.id DESC').limit(2).to_a.size
1090

1091
    assert_equal 3, Post.includes(author: :author_address, authors: :author_address).
R
Fix...  
Ryuta Kamizono 已提交
1092 1093
      where.not(author_addresses_authors: { id: nil }).
      order('author_addresses_authors.id DESC').limit(3).to_a.size
1094 1095
  end

1096
  def test_find_with_nil_inside_set_passed_for_one_attribute
1097 1098 1099 1100
    client_of = Company.
      where(client_of: [2, 1, nil],
            name: ['37signals', 'Summit', 'Microsoft']).
      order('client_of DESC').
1101
      map(&:client_of)
1102

1103 1104
    assert client_of.include?(nil)
    assert_equal [2, 1].sort, client_of.compact.sort
1105 1106
  end

1107
  def test_find_with_nil_inside_set_passed_for_attribute
1108 1109 1110
    client_of = Company.
      where(client_of: [nil]).
      order('client_of DESC').
1111
      map(&:client_of)
1112 1113 1114 1115

    assert_equal [], client_of.compact
  end

1116
  def test_with_limiting_with_custom_select
1117
    posts = Post.references(:authors).merge(
1118
      :includes => :author, :select => 'posts.*, authors.id as "author_id"',
J
Jon Leighton 已提交
1119
      :limit => 3, :order => 'posts.id'
1120
    ).to_a
1121 1122
    assert_equal 3, posts.size
    assert_equal [0, 1, 1], posts.map(&:author_id).sort
1123
  end
1124

1125
  def test_find_one_message_with_custom_primary_key
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
    table_with_custom_primary_key do |model|
      model.primary_key = :name
      e = assert_raises(ActiveRecord::RecordNotFound) do
        model.find 'Hello World!'
      end
      assert_equal %Q{Couldn't find MercedesCar with 'name'=Hello World!}, e.message
    end
  end

  def test_find_some_message_with_custom_primary_key
    table_with_custom_primary_key do |model|
      model.primary_key = :name
      e = assert_raises(ActiveRecord::RecordNotFound) do
        model.find 'Hello', 'World!'
      end
      assert_equal %Q{Couldn't find all MercedesCars with 'name': (Hello, World!) (found 0 results, but was looking for 2)}, e.message
1142 1143 1144
    end
  end

1145 1146 1147 1148 1149 1150
  def test_find_without_primary_key
    assert_raises(ActiveRecord::UnknownPrimaryKey) do
      Matey.find(1)
    end
  end

1151
  def test_finder_with_offset_string
1152
    assert_nothing_raised { Topic.offset("3").to_a }
1153 1154
  end

1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
  test "find_by with hash conditions returns the first matching record" do
    assert_equal posts(:eager_other), Post.find_by(id: posts(:eager_other).id)
  end

  test "find_by with non-hash conditions returns the first matching record" do
    assert_equal posts(:eager_other), Post.find_by("id = #{posts(:eager_other).id}")
  end

  test "find_by with multi-arg conditions returns the first matching record" do
    assert_equal posts(:eager_other), Post.find_by('id = ?', posts(:eager_other).id)
  end

  test "find_by returns nil if the record is missing" do
    assert_equal nil, Post.find_by("1 = 0")
  end

1171 1172 1173 1174 1175
  test "find_by with associations" do
    assert_equal authors(:david), Post.find_by(author: authors(:david)).author
    assert_equal authors(:mary) , Post.find_by(author: authors(:mary) ).author
  end

1176 1177 1178 1179
  test "find_by doesn't have implicit ordering" do
    assert_sql(/^((?!ORDER).)*$/) { Post.find_by(id: posts(:eager_other).id) }
  end

1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
  test "find_by! with hash conditions returns the first matching record" do
    assert_equal posts(:eager_other), Post.find_by!(id: posts(:eager_other).id)
  end

  test "find_by! with non-hash conditions returns the first matching record" do
    assert_equal posts(:eager_other), Post.find_by!("id = #{posts(:eager_other).id}")
  end

  test "find_by! with multi-arg conditions returns the first matching record" do
    assert_equal posts(:eager_other), Post.find_by!('id = ?', posts(:eager_other).id)
  end

  test "find_by! doesn't have implicit ordering" do
    assert_sql(/^((?!ORDER).)*$/) { Post.find_by!(id: posts(:eager_other).id) }
  end

  test "find_by! raises RecordNotFound if the record is missing" do
    assert_raises(ActiveRecord::RecordNotFound) do
      Post.find_by!("1 = 0")
    end
  end

1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221
  test "find on a scope does not perform statement caching" do
    honda = cars(:honda)
    zyke = cars(:zyke)
    tyre = honda.tyres.create!
    tyre2 = zyke.tyres.create!

    assert_equal tyre, honda.tyres.custom_find(tyre.id)
    assert_equal tyre2, zyke.tyres.custom_find(tyre2.id)
  end

  test "find_by on a scope does not perform statement caching" do
    honda = cars(:honda)
    zyke = cars(:zyke)
    tyre = honda.tyres.create!
    tyre2 = zyke.tyres.create!

    assert_equal tyre, honda.tyres.custom_find_by(id: tyre.id)
    assert_equal tyre2, zyke.tyres.custom_find_by(id: tyre2.id)
  end

D
David Heinemeier Hansson 已提交
1222
  protected
1223 1224 1225 1226 1227 1228 1229
    def table_with_custom_primary_key
      yield(Class.new(Toy) do
        def self.name
          'MercedesCar'
        end
      end)
    end
1230 1231 1232 1233 1234 1235

    def assert_raises_with_message(exception_class, message, &block)
      err = assert_raises(exception_class) { block.call }
      assert_match message, err.message
    end

D
David Heinemeier Hansson 已提交
1236
end