named_scope_test.rb 7.6 KB
Newer Older
1 2 3 4 5 6 7 8
require "cases/helper"
require 'models/post'
require 'models/topic'
require 'models/comment'
require 'models/reply'
require 'models/author'

class NamedScopeTest < ActiveRecord::TestCase
9
  fixtures :posts, :authors, :topics, :comments, :author_addresses
10

11 12
  def test_implements_enumerable
    assert !Topic.find(:all).empty?
13

14 15 16 17
    assert_equal Topic.find(:all),   Topic.base
    assert_equal Topic.find(:all),   Topic.base.to_a
    assert_equal Topic.find(:first), Topic.base.first
    assert_equal Topic.find(:all),   Topic.base.each { |i| i }
18
  end
19

20 21
  def test_found_items_are_cached
    Topic.columns
22
    all_posts = Topic.base
23

24 25 26 27 28
    assert_queries(1) do
      all_posts.collect
      all_posts.collect
    end
  end
29

30
  def test_reload_expires_cache_of_found_items
31
    all_posts = Topic.base
32
    all_posts.inspect
33

34 35 36 37
    new_post = Topic.create!
    assert !all_posts.include?(new_post)
    assert all_posts.reload.include?(new_post)
  end
38

39 40
  def test_delegates_finds_and_calculations_to_the_base_class
    assert !Topic.find(:all).empty?
41

42 43 44 45
    assert_equal Topic.find(:all),               Topic.base.find(:all)
    assert_equal Topic.find(:first),             Topic.base.find(:first)
    assert_equal Topic.count,                    Topic.base.count
    assert_equal Topic.average(:replies_count), Topic.base.average(:replies_count)
46
  end
47

48
  def test_subclasses_inherit_scopes
49
    assert Topic.scopes.include?(:base)
50

51 52
    assert Reply.scopes.include?(:base)
    assert_equal Reply.find(:all), Reply.base
53
  end
54

55 56
  def test_scopes_with_options_limit_finds_to_those_matching_the_criteria_specified
    assert !Topic.find(:all, :conditions => {:approved => true}).empty?
57

58 59 60
    assert_equal Topic.find(:all, :conditions => {:approved => true}), Topic.approved
    assert_equal Topic.count(:conditions => {:approved => true}), Topic.approved.count
  end
61

62 63 64 65 66 67
  def test_scopes_with_string_name_can_be_composed
    # NOTE that scopes defined with a string as a name worked on their own
    # but when called on another scope the other scope was completely replaced
    assert_equal Topic.replied.approved, Topic.replied.approved_as_string
  end

68 69 70 71
  def test_scopes_can_be_specified_with_deep_hash_conditions
    assert_equal Topic.replied.approved, Topic.replied.approved_as_hash_condition
  end

72 73 74
  def test_scopes_are_composable
    assert_equal (approved = Topic.find(:all, :conditions => {:approved => true})), Topic.approved
    assert_equal (replied = Topic.find(:all, :conditions => 'replies_count > 0')), Topic.replied
75
    assert !(approved == replied)
76
    assert !(approved & replied).empty?
77

78 79 80 81 82 83 84
    assert_equal approved & replied, Topic.approved.replied
  end

  def test_procedural_scopes
    topics_written_before_the_third = Topic.find(:all, :conditions => ['written_on < ?', topics(:third).written_on])
    topics_written_before_the_second = Topic.find(:all, :conditions => ['written_on < ?', topics(:second).written_on])
    assert_not_equal topics_written_before_the_second, topics_written_before_the_third
85

86 87 88
    assert_equal topics_written_before_the_third, Topic.written_before(topics(:third).written_on)
    assert_equal topics_written_before_the_second, Topic.written_before(topics(:second).written_on)
  end
89

90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
  def test_scopes_with_joins
    address = author_addresses(:david_address)
    posts_with_authors_at_address = Post.find(
      :all, :joins => 'JOIN authors ON authors.id = posts.author_id',
      :conditions => [ 'authors.author_address_id = ?', address.id ]
    )
    assert_equal posts_with_authors_at_address, Post.with_authors_at_address(address)
  end

  def test_scopes_with_joins_respects_custom_select
    address = author_addresses(:david_address)
    posts_with_authors_at_address_titles = Post.find(:all,
      :select => 'title',
      :joins => 'JOIN authors ON authors.id = posts.author_id',
      :conditions => [ 'authors.author_address_id = ?', address.id ]
    )
    assert_equal posts_with_authors_at_address_titles, Post.with_authors_at_address(address).find(:all, :select => 'title')
  end

109 110 111 112
  def test_extensions
    assert_equal 1, Topic.anonymous_extension.one
    assert_equal 2, Topic.named_extension.two
  end
113

114 115
  def test_multiple_extensions
    assert_equal 2, Topic.multiple_extensions.extension_two
116
    assert_equal 1, Topic.multiple_extensions.extension_one
117
  end
118

119 120 121
  def test_has_many_associations_have_access_to_named_scopes
    assert_not_equal Post.containing_the_letter_a, authors(:david).posts
    assert !Post.containing_the_letter_a.empty?
122

123 124
    assert_equal authors(:david).posts & Post.containing_the_letter_a, authors(:david).posts.containing_the_letter_a
  end
125

126
  def test_has_many_through_associations_have_access_to_named_scopes
127
    assert_not_equal Comment.containing_the_letter_e, authors(:david).comments
128
    assert !Comment.containing_the_letter_e.empty?
129

130 131
    assert_equal authors(:david).comments & Comment.containing_the_letter_e, authors(:david).comments.containing_the_letter_e
  end
132

133 134
  def test_active_records_have_scope_named__all__
    assert !Topic.find(:all).empty?
135

136
    assert_equal Topic.find(:all), Topic.base
137
  end
138

139 140
  def test_active_records_have_scope_named__scoped__
    assert !Topic.find(:all, scope = {:conditions => "content LIKE '%Have%'"}).empty?
141

142 143
    assert_equal Topic.find(:all, scope), Topic.scoped(scope)
  end
144 145 146 147 148 149

  def test_proxy_options
    expected_proxy_options = { :conditions => { :approved => true } }
    assert_equal expected_proxy_options, Topic.approved.proxy_options
  end

150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
  def test_first_and_last_should_support_find_options
    assert_equal Topic.base.first(:order => 'title'), Topic.base.find(:first, :order => 'title')
    assert_equal Topic.base.last(:order => 'title'), Topic.base.find(:last, :order => 'title')
  end

  def test_first_and_last_should_allow_integers_for_limit
    assert_equal Topic.base.first(2), Topic.base.to_a.first(2)
    assert_equal Topic.base.last(2), Topic.base.to_a.last(2)
  end

  def test_first_and_last_should_not_use_query_when_results_are_loaded
    topics = Topic.base
    topics.reload # force load
    assert_no_queries do
      topics.first
      topics.last
    end
  end

  def test_first_and_last_find_options_should_use_query_when_results_are_loaded
    topics = Topic.base
    topics.reload # force load
    assert_queries(2) do
      topics.first(:order => 'title')
      topics.last(:order => 'title')
    end
  end

178 179 180 181 182 183 184 185
  def test_empty_should_not_load_results
    topics = Topic.base
    assert_queries(2) do
      topics.empty?  # use count query
      topics.collect # force load
      topics.empty?  # use loaded (no query)
    end
  end
186

187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
  def test_any_should_not_load_results
    topics = Topic.base
    assert_queries(1) do
      topics.expects(:empty?).returns(true)
      assert !topics.any?
    end
  end

  def test_any_should_call_proxy_found_if_using_a_block
    topics = Topic.base
    assert_queries(1) do
      topics.expects(:empty?).never
      topics.any? { true }
    end
  end

  def test_any_should_not_fire_query_if_named_scope_loaded
    topics = Topic.base
    topics.collect # force load
    assert_no_queries { assert topics.any? }
  end

209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
  def test_should_build_with_proxy_options
    topic = Topic.approved.build({})
    assert topic.approved
  end

  def test_should_build_new_with_proxy_options
    topic = Topic.approved.new
    assert topic.approved
  end

  def test_should_create_with_proxy_options
    topic = Topic.approved.create({})
    assert topic.approved
  end

  def test_should_create_with_bang_with_proxy_options
    topic = Topic.approved.create!({})
    assert topic.approved
  end
  
  def test_should_build_with_proxy_options_chained
    topic = Topic.approved.by_lifo.build({})
    assert topic.approved
    assert_equal 'lifo', topic.author_name
  end
234
end