calculations_test.rb 8.9 KB
Newer Older
1
require "cases/helper"
J
Jeremy Kemper 已提交
2 3
require 'models/company'
require 'models/topic'
4 5 6

Company.has_many :accounts

7 8 9 10
class NumericData < ActiveRecord::Base
  self.table_name = 'numeric_data'
end

11
class CalculationsTest < ActiveRecord::TestCase
12 13 14
  fixtures :companies, :accounts, :topics

  def test_should_sum_field
15
    assert_equal 318, Account.sum(:credit_limit)
16 17 18 19 20
  end

  def test_should_average_field
    value = Account.average(:credit_limit)
    assert_kind_of Float, value
21
    assert_in_delta 53.0, value, 0.001
22 23
  end

24 25 26 27
  def test_should_return_nil_as_average
    assert_nil NumericData.average(:bank_balance)
  end

28 29 30 31
  def test_should_get_maximum_of_field
    assert_equal 60, Account.maximum(:credit_limit)
  end

32 33 34 35 36 37 38 39 40 41
  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

42 43 44 45 46 47
  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)
48
    [1,6,2].each { |firm_id| assert c.keys.include?(firm_id) }
49 50 51 52
  end

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

58 59
  def test_should_order_by_grouped_field
    c = Account.sum(:credit_limit, :group => :firm_id, :order => "firm_id")
60
    assert_equal [1, 2, 6, 9], c.keys.compact
61 62 63 64
  end

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

69 70 71 72 73 74 75 76 77 78 79 80
  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

81
  def test_should_group_by_summed_field_having_condition
J
Jeremy Kemper 已提交
82
    c = Account.sum(:credit_limit, :group => :firm_id,
83
                                   :having => 'sum(credit_limit) > 50')
84 85 86
    assert_nil        c[1]
    assert_equal 105, c[6]
    assert_equal 60,  c[2]
87 88 89 90 91 92 93 94
  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
J
Jeremy Kemper 已提交
95

96 97 98 99
  def test_should_sum_field_with_conditions
    assert_equal 105, Account.sum(:credit_limit, :conditions => 'firm_id = 6')
  end

100 101 102 103
  def test_should_return_zero_if_sum_conditions_return_nothing
    assert_equal 0, Account.sum(:credit_limit, :conditions => '1 = 2')
  end

104
  def test_should_group_by_summed_field_with_conditions
J
Jeremy Kemper 已提交
105
    c = Account.sum(:credit_limit, :conditions => 'firm_id > 1',
106
                                   :group => :firm_id)
107 108 109
    assert_nil        c[1]
    assert_equal 105, c[6]
    assert_equal 60,  c[2]
110
  end
J
Jeremy Kemper 已提交
111

112
  def test_should_group_by_summed_field_with_conditions_and_having
J
Jeremy Kemper 已提交
113 114
    c = Account.sum(:credit_limit, :conditions => 'firm_id > 1',
                                   :group => :firm_id,
115
                                   :having => 'sum(credit_limit) > 60')
116 117 118
    assert_nil        c[1]
    assert_equal 105, c[6]
    assert_nil        c[2]
119 120 121 122
  end

  def test_should_group_by_fields_with_table_alias
    c = Account.sum(:credit_limit, :group => 'accounts.firm_id')
123 124 125
    assert_equal 50,  c[1]
    assert_equal 105, c[6]
    assert_equal 60,  c[2]
126
  end
J
Jeremy Kemper 已提交
127

128
  def test_should_calculate_with_invalid_field
129 130
    assert_equal 6, Account.calculate(:count, '*')
    assert_equal 6, Account.calculate(:count, :all)
131
  end
J
Jeremy Kemper 已提交
132

133 134
  def test_should_calculate_grouped_with_invalid_field
    c = Account.count(:all, :group => 'accounts.firm_id')
135 136 137
    assert_equal 1, c[1]
    assert_equal 2, c[6]
    assert_equal 1, c[2]
138
  end
J
Jeremy Kemper 已提交
139

140 141 142 143 144 145
  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
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165

  uses_mocha 'group_by_non_numeric_foreign_key_association' do
    def test_should_group_by_association_with_non_numeric_foreign_key
      ActiveRecord::Base.connection.expects(:select_all).returns([{"count_all" => 1, "firm_id" => "ABC"}])

      firm = mock()
      firm.expects(:id).returns("ABC")
      firm.expects(:class).returns(Firm)
      Company.expects(:find).with(["ABC"]).returns([firm])

      column = mock()
      column.expects(:name).at_least_once.returns(:firm_id)
      column.expects(:type_cast).with("ABC").returns("ABC")
      Account.expects(:columns).at_least_once.returns([column])

      c = Account.count(:all, :group => :firm)
      assert_equal Firm, c.first.first.class
      assert_equal 1, c.first.last
    end
  end
J
Jeremy Kemper 已提交
166

167 168 169 170 171 172 173 174
  def test_should_calculate_grouped_association_with_foreign_key_option
    Account.belongs_to :another_firm, :class_name => 'Firm', :foreign_key => 'firm_id'
    c = Account.count(:all, :group => :another_firm)
    assert_equal 1, c[companies(:first_firm)]
    assert_equal 2, c[companies(:rails_core)]
    assert_equal 1, c[companies(:first_client)]
  end

175 176 177
  def test_should_not_modify_options_when_using_includes
    options = {:conditions => 'companies.id > 1', :include => :firm}
    options_copy = options.dup
J
Jeremy Kemper 已提交
178

179 180 181
    Account.count(:all, options)
    assert_equal options_copy, options
  end
182 183

  def test_should_calculate_grouped_by_function
184
    c = Company.count(:all, :group => "UPPER(#{QUOTED_TYPE})")
185 186 187 188 189
    assert_equal 2, c[nil]
    assert_equal 1, c['DEPENDENTFIRM']
    assert_equal 3, c['CLIENT']
    assert_equal 2, c['FIRM']
  end
J
Jeremy Kemper 已提交
190

191
  def test_should_calculate_grouped_by_function_with_table_alias
192
    c = Company.count(:all, :group => "UPPER(companies.#{QUOTED_TYPE})")
193 194 195 196
    assert_equal 2, c[nil]
    assert_equal 1, c['DEPENDENTFIRM']
    assert_equal 3, c['CLIENT']
    assert_equal 2, c['FIRM']
197
  end
J
Jeremy Kemper 已提交
198

199 200 201
  def test_should_not_overshadow_enumerable_sum
    assert_equal 6, [1, 2, 3].sum(&:abs)
  end
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222

  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
223 224 225 226 227 228 229

  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
J
Jeremy Kemper 已提交
230
        [:select, :conditions, :joins, :order, :group, :having, :distinct].each do |opt|
231 232 233
          Company.send(:validate_calculation_options, func, opt => true)
        end
      end
J
Jeremy Kemper 已提交
234

235 236 237
      # :include is only valid on :count
      Company.send(:validate_calculation_options, :count, :include => true)
    end
J
Jeremy Kemper 已提交
238

239 240 241
    assert_raises(ArgumentError) { Company.send(:validate_calculation_options, :sum,   :foo => :bar) }
    assert_raises(ArgumentError) { Company.send(:validate_calculation_options, :count, :foo => :bar) }
  end
J
Jeremy Kemper 已提交
242

243
  def test_should_count_selected_field_with_include
244 245
    assert_equal 6, Account.count(:distinct => true, :include => :firm)
    assert_equal 4, Account.count(:distinct => true, :include => :firm, :select => :credit_limit)
246
  end
J
Jeremy Kemper 已提交
247

248 249 250 251
  def test_should_count_manual_select_with_include
    assert_equal 6, Account.count(:select => "DISTINCT accounts.id", :include => :firm)
  end

252 253 254
  def test_count_with_column_parameter
    assert_equal 5, Account.count(:firm_id)
  end
J
Jeremy Kemper 已提交
255

256 257 258
  def test_count_with_column_and_options_parameter
    assert_equal 2, Account.count(:firm_id, :conditions => "credit_limit = 50")
  end
J
Jeremy Kemper 已提交
259

260 261 262 263 264 265 266
  def test_count_with_no_parameters_isnt_deprecated
    assert_not_deprecated { Account.count }
  end

  def test_count_with_too_many_parameters_raises
    assert_raise(ArgumentError) { Account.count(1, 2, 3) }
  end
267 268 269 270

  def test_should_sum_expression
    assert_equal "636", Account.sum("2 * credit_limit")
  end
271
end