Updated to latest will_paginate
[gitorious:dgiuntas-clone.git] / vendor / plugins / will_paginate / test / finder_test.rb
1 require 'helper'
2 require 'lib/activerecord_test_case'
3
4 require 'will_paginate'
5 WillPaginate.enable_activerecord
6 WillPaginate.enable_named_scope
7
8 class FinderTest < ActiveRecordTestCase
9   fixtures :topics, :replies, :users, :projects, :developers_projects
10
11   def test_new_methods_presence
12     assert_respond_to_all Topic, %w(per_page paginate paginate_by_sql)
13   end
14   
15   def test_simple_paginate
16     assert_queries(1) do
17       entries = Topic.paginate :page => nil
18       assert_equal 1, entries.current_page
19       assert_equal 1, entries.total_pages
20       assert_equal 4, entries.size
21     end
22     
23     assert_queries(2) do
24       entries = Topic.paginate :page => 2
25       assert_equal 1, entries.total_pages
26       assert entries.empty?
27     end
28   end
29
30   def test_parameter_api
31     # :page parameter in options is required!
32     assert_raise(ArgumentError){ Topic.paginate }
33     assert_raise(ArgumentError){ Topic.paginate({}) }
34     
35     # explicit :all should not break anything
36     assert_equal Topic.paginate(:page => nil), Topic.paginate(:all, :page => 1)
37
38     # :count could be nil and we should still not cry
39     assert_nothing_raised { Topic.paginate :page => 1, :count => nil }
40   end
41   
42   def test_paginate_with_per_page
43     entries = Topic.paginate :page => 1, :per_page => 1
44     assert_equal 1, entries.size
45     assert_equal 4, entries.total_pages
46
47     # Developer class has explicit per_page at 10
48     entries = Developer.paginate :page => 1
49     assert_equal 10, entries.size
50     assert_equal 2, entries.total_pages
51
52     entries = Developer.paginate :page => 1, :per_page => 5
53     assert_equal 11, entries.total_entries
54     assert_equal 5, entries.size
55     assert_equal 3, entries.total_pages
56   end
57   
58   def test_paginate_with_order
59     entries = Topic.paginate :page => 1, :order => 'created_at desc'
60     expected = [topics(:futurama), topics(:harvey_birdman), topics(:rails), topics(:ar)].reverse
61     assert_equal expected, entries.to_a
62     assert_equal 1, entries.total_pages
63   end
64   
65   def test_paginate_with_conditions
66     entries = Topic.paginate :page => 1, :conditions => ["created_at > ?", 30.minutes.ago]
67     expected = [topics(:rails), topics(:ar)]
68     assert_equal expected, entries.to_a
69     assert_equal 1, entries.total_pages
70   end
71
72   def test_paginate_with_include_and_conditions
73     entries = Topic.paginate \
74       :page     => 1, 
75       :include  => :replies,  
76       :conditions => "replies.content LIKE 'Bird%' ", 
77       :per_page => 10
78
79     expected = Topic.find :all, 
80       :include => 'replies', 
81       :conditions => "replies.content LIKE 'Bird%' ", 
82       :limit   => 10
83
84     assert_equal expected, entries.to_a
85     assert_equal 1, entries.total_entries
86   end
87   
88   def test_paginate_with_include_and_order
89     entries = nil
90     assert_queries(2) do
91       entries = Topic.paginate \
92         :page     => 1, 
93         :include  => :replies,  
94         :order    => 'replies.created_at asc, topics.created_at asc', 
95         :per_page => 10
96     end
97
98     expected = Topic.find :all, 
99       :include => 'replies', 
100       :order   => 'replies.created_at asc, topics.created_at asc', 
101       :limit   => 10
102
103     assert_equal expected, entries.to_a
104     assert_equal 4, entries.total_entries
105   end
106
107   def test_paginate_associations_with_include
108     entries, project = nil, projects(:active_record)
109
110     assert_nothing_raised "THIS IS A BUG in Rails 1.2.3 that was fixed in [7326]. " +
111         "Please upgrade to a newer version of Rails." do
112       entries = project.topics.paginate \
113         :page     => 1, 
114         :include  => :replies,  
115         :conditions => "replies.content LIKE 'Nice%' ", 
116         :per_page => 10
117     end
118
119     expected = Topic.find :all, 
120       :include => 'replies', 
121       :conditions => "project_id = #{project.id} AND replies.content LIKE 'Nice%' ", 
122       :limit   => 10
123
124     assert_equal expected, entries.to_a
125   end
126
127   def test_paginate_associations
128     dhh = users :david
129     expected_name_ordered = [projects(:action_controller), projects(:active_record)]
130     expected_id_ordered   = [projects(:active_record), projects(:action_controller)]
131
132     assert_queries(2) do
133       # with association-specified order
134       entries = dhh.projects.paginate(:page => 1)
135       assert_equal expected_name_ordered, entries
136       assert_equal 2, entries.total_entries
137     end
138
139     # with explicit order
140     entries = dhh.projects.paginate(:page => 1, :order => 'projects.id')
141     assert_equal expected_id_ordered, entries
142     assert_equal 2, entries.total_entries
143
144     assert_nothing_raised { dhh.projects.find(:all, :order => 'projects.id', :limit => 4) }
145     entries = dhh.projects.paginate(:page => 1, :order => 'projects.id', :per_page => 4)
146     assert_equal expected_id_ordered, entries
147
148     # has_many with implicit order
149     topic = Topic.find(1)
150     expected = [replies(:spam), replies(:witty_retort)]
151     assert_equal expected.map(&:id).sort, topic.replies.paginate(:page => 1).map(&:id).sort
152     assert_equal expected.reverse, topic.replies.paginate(:page => 1, :order => 'replies.id ASC')
153   end
154
155   def test_paginate_association_extension
156     project = Project.find(:first)
157     
158     assert_queries(2) do
159       entries = project.replies.paginate_recent :page => 1
160       assert_equal [replies(:brave)], entries
161     end
162   end
163   
164   def test_paginate_with_joins
165     entries = nil
166     
167     assert_queries(1) do
168       entries = Developer.paginate :page => 1,
169                           :joins => 'LEFT JOIN developers_projects ON users.id = developers_projects.developer_id',
170                           :conditions => 'project_id = 1'        
171       assert_equal 2, entries.size
172       developer_names = entries.map &:name
173       assert developer_names.include?('David')
174       assert developer_names.include?('Jamis')
175     end
176
177     assert_queries(1) do
178       expected = entries.to_a
179       entries = Developer.paginate :page => 1,
180                           :joins => 'LEFT JOIN developers_projects ON users.id = developers_projects.developer_id',
181                           :conditions => 'project_id = 1', :count => { :select => "users.id" }
182       assert_equal expected, entries.to_a
183       assert_equal 2, entries.total_entries
184     end
185   end
186
187   def test_paginate_with_group
188     entries = nil
189     assert_queries(1) do
190       entries = Developer.paginate :page => 1, :per_page => 10,
191                                    :group => 'salary', :select => 'salary', :order => 'salary'
192     end
193     
194     expected = [ users(:david), users(:jamis), users(:dev_10), users(:poor_jamis) ].map(&:salary).sort
195     assert_equal expected, entries.map(&:salary)
196   end
197
198   def test_paginate_with_dynamic_finder
199     expected = [replies(:witty_retort), replies(:spam)]
200     assert_equal expected, Reply.paginate_by_topic_id(1, :page => 1)
201
202     entries = Developer.paginate :conditions => { :salary => 100000 }, :page => 1, :per_page => 5
203     assert_equal 8, entries.total_entries
204     assert_equal entries, Developer.paginate_by_salary(100000, :page => 1, :per_page => 5)
205
206     # dynamic finder + conditions
207     entries = Developer.paginate_by_salary(100000, :page => 1,
208                                            :conditions => ['id > ?', 6])
209     assert_equal 4, entries.total_entries
210     assert_equal (7..10).to_a, entries.map(&:id)
211
212     assert_raises NoMethodError do
213       Developer.paginate_by_inexistent_attribute 100000, :page => 1
214     end
215   end
216
217   def test_scoped_paginate
218     entries = Developer.with_poor_ones { Developer.paginate :page => 1 }
219
220     assert_equal 2, entries.size
221     assert_equal 2, entries.total_entries
222   end
223
224   ## named_scope ##
225   
226   def test_paginate_in_named_scope
227     entries = Developer.poor.paginate :page => 1, :per_page => 1
228
229     assert_equal 1, entries.size
230     assert_equal 2, entries.total_entries
231   end
232   
233   def test_paginate_in_named_scope_on_habtm_association
234     project = projects(:active_record)
235     assert_queries(2) do
236       entries = project.developers.poor.paginate :page => 1, :per_page => 1
237
238       assert_equal 1, entries.size, 'one developer should be found'
239       assert_equal 1, entries.total_entries, 'only one developer should be found'
240     end
241   end
242
243   def test_paginate_in_named_scope_on_hmt_association
244     project = projects(:active_record)
245     expected = [replies(:brave)]
246     
247     assert_queries(2) do
248       entries = project.replies.recent.paginate :page => 1, :per_page => 1
249       assert_equal expected, entries
250       assert_equal 1, entries.total_entries, 'only one reply should be found'
251     end
252   end
253
254   def test_paginate_in_named_scope_on_has_many_association
255     project = projects(:active_record)
256     expected = [topics(:ar)]
257     
258     assert_queries(2) do
259       entries = project.topics.mentions_activerecord.paginate :page => 1, :per_page => 1
260       assert_equal expected, entries
261       assert_equal 1, entries.total_entries, 'only one topic should be found'
262     end
263   end
264
265   ## misc ##
266
267   def test_count_and_total_entries_options_are_mutually_exclusive
268     e = assert_raise ArgumentError do
269       Developer.paginate :page => 1, :count => {}, :total_entries => 1
270     end
271     assert_match /exclusive/, e.to_s
272   end
273   
274   def test_readonly
275     assert_nothing_raised { Developer.paginate :readonly => true, :page => 1 }
276   end
277
278   # this functionality is temporarily removed
279   def xtest_pagination_defines_method
280     pager = "paginate_by_created_at"
281     assert !User.methods.include?(pager), "User methods should not include `#{pager}` method"
282     # paginate!
283     assert 0, User.send(pager, nil, :page => 1).total_entries
284     # the paging finder should now be defined
285     assert User.methods.include?(pager), "`#{pager}` method should be defined on User"
286   end
287
288   # Is this Rails 2.0? Find out by testing find_all which was removed in [6998]
289   unless ActiveRecord::Base.respond_to? :find_all
290     def test_paginate_array_of_ids
291       # AR finders also accept arrays of IDs
292       # (this was broken in Rails before [6912])
293       assert_queries(1) do
294         entries = Developer.paginate((1..8).to_a, :per_page => 3, :page => 2, :order => 'id')
295         assert_equal (4..6).to_a, entries.map(&:id)
296         assert_equal 8, entries.total_entries
297       end
298     end
299   end
300
301   uses_mocha 'internals' do
302     def test_implicit_all_with_dynamic_finders
303       Topic.expects(:find_all_by_foo).returns([])
304       Topic.expects(:count).returns(0)
305       Topic.paginate_by_foo :page => 2
306     end
307     
308     def test_guessing_the_total_count
309       Topic.expects(:find).returns(Array.new(2))
310       Topic.expects(:count).never
311       
312       entries = Topic.paginate :page => 2, :per_page => 4
313       assert_equal 6, entries.total_entries
314     end
315     
316     def test_guessing_that_there_are_no_records
317       Topic.expects(:find).returns([])
318       Topic.expects(:count).never
319       
320       entries = Topic.paginate :page => 1, :per_page => 4
321       assert_equal 0, entries.total_entries
322     end
323     
324     def test_extra_parameters_stay_untouched
325       Topic.expects(:find).with(:all, {:foo => 'bar', :limit => 4, :offset => 0 }).returns(Array.new(5))
326       Topic.expects(:count).with({:foo => 'bar'}).returns(1)
327
328       Topic.paginate :foo => 'bar', :page => 1, :per_page => 4
329     end
330
331     def test_count_skips_select
332       Developer.stubs(:find).returns([])
333       Developer.expects(:count).with({}).returns(0)
334       Developer.paginate :select => 'salary', :page => 2
335     end
336
337     def test_count_select_when_distinct
338       Developer.stubs(:find).returns([])
339       Developer.expects(:count).with(:select => 'DISTINCT salary').returns(0)
340       Developer.paginate :select => 'DISTINCT salary', :page => 2
341     end
342
343     def test_should_use_scoped_finders_if_present
344       # scope-out compatibility
345       Topic.expects(:find_best).returns(Array.new(5))
346       Topic.expects(:with_best).returns(1)
347       
348       Topic.paginate_best :page => 1, :per_page => 4
349     end
350
351     def test_paginate_by_sql
352       assert_respond_to Developer, :paginate_by_sql
353       Developer.expects(:find_by_sql).with(regexp_matches(/sql LIMIT 3(,| OFFSET) 3/)).returns([])
354       Developer.expects(:count_by_sql).with('SELECT COUNT(*) FROM (sql) AS count_table').returns(0)
355       
356       entries = Developer.paginate_by_sql 'sql', :page => 2, :per_page => 3
357     end
358
359     def test_paginate_by_sql_respects_total_entries_setting
360       Developer.expects(:find_by_sql).returns([])
361       Developer.expects(:count_by_sql).never
362       
363       entries = Developer.paginate_by_sql 'sql', :page => 1, :total_entries => 999
364       assert_equal 999, entries.total_entries
365     end
366
367     def test_paginate_by_sql_strips_order_by_when_counting
368       Developer.expects(:find_by_sql).returns([])
369       Developer.expects(:count_by_sql).with("SELECT COUNT(*) FROM (sql\n ) AS count_table").returns(0)
370       
371       Developer.paginate_by_sql "sql\n ORDER\nby foo, bar, `baz` ASC", :page => 2
372     end
373
374     # TODO: counts are still wrong
375     def test_ability_to_use_with_custom_finders
376       # acts_as_taggable defines find_tagged_with(tag, options)
377       Topic.expects(:find_tagged_with).with('will_paginate', :offset => 5, :limit => 5).returns([])
378       Topic.expects(:count).with({}).returns(0)
379       
380       Topic.paginate_tagged_with 'will_paginate', :page => 2, :per_page => 5
381     end
382     
383     def test_array_argument_doesnt_eliminate_count
384       ids = (1..8).to_a
385       Developer.expects(:find_all_by_id).returns([])
386       Developer.expects(:count).returns(0)
387       
388       Developer.paginate_by_id(ids, :per_page => 3, :page => 2, :order => 'id')
389     end
390
391     def test_paginating_finder_doesnt_mangle_options
392       Developer.expects(:find).returns([])
393       options = { :page => 1 }
394       options.expects(:delete).never
395       options_before = options.dup
396       
397       Developer.paginate(options)
398       assert_equal options, options_before
399     end
400
401     def test_paginated_each
402       collection = stub('collection', :size => 5, :empty? => false, :per_page => 5)
403       collection.expects(:each).times(2).returns(collection)
404       last_collection = stub('collection', :size => 4, :empty? => false, :per_page => 5)
405       last_collection.expects(:each).returns(last_collection)
406       
407       params = { :order => 'id', :total_entries => 0 }
408       
409       Developer.expects(:paginate).with(params.merge(:page => 2)).returns(collection)
410       Developer.expects(:paginate).with(params.merge(:page => 3)).returns(collection)
411       Developer.expects(:paginate).with(params.merge(:page => 4)).returns(last_collection)
412       
413       assert_equal 14, Developer.paginated_each(:page => '2') { }
414     end
415
416     # detect ActiveRecord 2.1
417     if ActiveRecord::Base.private_methods.include?('references_eager_loaded_tables?')
418       def test_removes_irrelevant_includes_in_count
419         Developer.expects(:find).returns([1])
420         Developer.expects(:count).with({}).returns(0)
421
422         Developer.paginate :page => 1, :per_page => 1, :include => :projects
423       end
424
425       def test_doesnt_remove_referenced_includes_in_count
426         Developer.expects(:find).returns([1])
427         Developer.expects(:count).with({ :include => :projects, :conditions => 'projects.id > 2' }).returns(0)
428
429         Developer.paginate :page => 1, :per_page => 1,
430           :include => :projects, :conditions => 'projects.id > 2'
431       end
432     end
433   end
434 end