aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/test/calculations_test.rb
blob: 7b89e8c62c4b83eba3ab5a3afda6360b83ebdde6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
require 'abstract_unit'
require 'fixtures/company'
require 'fixtures/topic'

Company.has_many :accounts

class CalculationsTest < Test::Unit::TestCase
  fixtures :companies, :accounts, :topics

  def test_should_sum_field
    assert_equal 265, Account.sum(:credit_limit)
  end

  def test_should_average_field
    value = Account.average(:credit_limit)
    assert_equal 53, value
    assert_kind_of Float, value
  end

  def test_should_get_maximum_of_field
    assert_equal 60, Account.maximum(:credit_limit)
  end

  def test_should_get_maximum_of_field_with_include
    assert_equal 50, Account.maximum(:credit_limit, :include => :firm, :conditions => "companies.name != 'Summit'")
  end

  def test_should_get_maximum_of_field_with_scoped_include
    Account.with_scope :find => { :include => :firm, :conditions => "companies.name != 'Summit'" } do
      assert_equal 50, Account.maximum(:credit_limit)
    end
  end

  def test_should_get_minimum_of_field
    assert_equal 50, Account.minimum(:credit_limit)
  end

  def test_should_group_by_field
    c = Account.sum(:credit_limit, :group => :firm_id)
    [1,6,2].each { |firm_id| assert c.keys.include?(firm_id) }
  end

  def test_should_group_by_summed_field
    c = Account.sum(:credit_limit, :group => :firm_id)
    assert_equal 50,   c[1]
    assert_equal 105,  c[6]
    assert_equal 60,   c[2]
  end

  def test_should_order_by_grouped_field
    c = Account.sum(:credit_limit, :group => :firm_id, :order => "firm_id")
    assert_equal [1, 2, 6], c.keys.compact
  end

  def test_should_order_by_calculation
    c = Account.sum(:credit_limit, :group => :firm_id, :order => "sum_credit_limit desc, firm_id")
    assert_equal [105, 60, 50, 50], c.keys.collect { |k| c[k] }
    assert_equal [6, 2, 1], c.keys.compact
  end

  def test_should_limit_calculation
    c = Account.sum(:credit_limit, :conditions => "firm_id IS NOT NULL",
                    :group => :firm_id, :order => "firm_id", :limit => 2)
    assert_equal [1, 2], c.keys.compact
  end

  def test_should_limit_calculation_with_offset
    c = Account.sum(:credit_limit, :conditions => "firm_id IS NOT NULL",
                    :group => :firm_id, :order => "firm_id", :limit => 2, :offset => 1)
    assert_equal [2, 6], c.keys.compact
  end

  def test_should_group_by_summed_field_having_condition
    c = Account.sum(:credit_limit, :group => :firm_id, 
                                   :having => 'sum(credit_limit) > 50')
    assert_nil        c[1]
    assert_equal 105, c[6]
    assert_equal 60,  c[2]
  end

  def test_should_group_by_summed_association
    c = Account.sum(:credit_limit, :group => :firm)
    assert_equal 50,   c[companies(:first_firm)]
    assert_equal 105,  c[companies(:rails_core)]
    assert_equal 60,   c[companies(:first_client)]
  end
  
  def test_should_sum_field_with_conditions
    assert_equal 105, Account.sum(:credit_limit, :conditions => 'firm_id = 6')
  end

  def test_should_group_by_summed_field_with_conditions
    c = Account.sum(:credit_limit, :conditions => 'firm_id > 1', 
                                   :group => :firm_id)
    assert_nil        c[1]
    assert_equal 105, c[6]
    assert_equal 60,  c[2]
  end
  
  def test_should_group_by_summed_field_with_conditions_and_having
    c = Account.sum(:credit_limit, :conditions => 'firm_id > 1', 
                                   :group => :firm_id, 
                                   :having => 'sum(credit_limit) > 60')
    assert_nil        c[1]
    assert_equal 105, c[6]
    assert_nil        c[2]
  end

  def test_should_group_by_fields_with_table_alias
    c = Account.sum(:credit_limit, :group => 'accounts.firm_id')
    assert_equal 50,  c[1]
    assert_equal 105, c[6]
    assert_equal 60,  c[2]
  end
  
  def test_should_calculate_with_invalid_field
    assert_equal 5, Account.calculate(:count, '*')
    assert_equal 5, Account.calculate(:count, :all)
  end
  
  def test_should_calculate_grouped_with_invalid_field
    c = Account.count(:all, :group => 'accounts.firm_id')
    assert_equal 1, c[1]
    assert_equal 2, c[6]
    assert_equal 1, c[2]
  end
  
  def test_should_calculate_grouped_association_with_invalid_field
    c = Account.count(:all, :group => :firm)
    assert_equal 1, c[companies(:first_firm)]
    assert_equal 2, c[companies(:rails_core)]
    assert_equal 1, c[companies(:first_client)]
  end

  def test_should_calculate_grouped_by_function
    c = Company.count(:all, :group => "UPPER(#{QUOTED_TYPE})")
    assert_equal 2, c[nil]
    assert_equal 1, c['DEPENDENTFIRM']
    assert_equal 3, c['CLIENT']
    assert_equal 2, c['FIRM']
  end
  
  def test_should_calculate_grouped_by_function_with_table_alias
    c = Company.count(:all, :group => "UPPER(companies.#{QUOTED_TYPE})")
    assert_equal 2, c[nil]
    assert_equal 1, c['DEPENDENTFIRM']
    assert_equal 3, c['CLIENT']
    assert_equal 2, c['FIRM']
  end
  
  def test_should_not_overshadow_enumerable_sum
    assert_equal 6, [1, 2, 3].sum(&:abs)
  end

  def test_should_sum_scoped_field
    assert_equal 15, companies(:rails_core).companies.sum(:id)
  end

  def test_should_sum_scoped_field_with_conditions
    assert_equal 8,  companies(:rails_core).companies.sum(:id, :conditions => 'id > 7')
  end

  def test_should_group_by_scoped_field
    c = companies(:rails_core).companies.sum(:id, :group => :name)
    assert_equal 7, c['Leetsoft']
    assert_equal 8, c['Jadedpixel']
  end

  def test_should_group_by_summed_field_with_conditions_and_having
    c = companies(:rails_core).companies.sum(:id, :group => :name,
                                                  :having => 'sum(id) > 7')
    assert_nil      c['Leetsoft']
    assert_equal 8, c['Jadedpixel']
  end

  def test_should_reject_invalid_options
    assert_nothing_raised do
      [:count, :sum].each do |func|
        # empty options are valid
        Company.send(:validate_calculation_options, func)
        # these options are valid for all calculations
        [:select, :conditions, :joins, :order, :group, :having, :distinct].each do |opt| 
          Company.send(:validate_calculation_options, func, opt => true)
        end
      end
      
      # :include is only valid on :count
      Company.send(:validate_calculation_options, :count, :include => true)
    end
    
    assert_raises(ArgumentError) { Company.send(:validate_calculation_options, :sum,   :foo => :bar) }
    assert_raises(ArgumentError) { Company.send(:validate_calculation_options, :count, :foo => :bar) }
  end

  def test_should_count_selected_field_with_include
    assert_equal 5, Account.count(:distinct => true, :include => :firm)
    assert_equal 3, Account.count(:distinct => true, :include => :firm, :select => :credit_limit)
  end
end