reflection_test.rb 12.4 KB
Newer Older
1
require "cases/helper"
J
Jeremy Kemper 已提交
2 3 4 5 6
require 'models/topic'
require 'models/customer'
require 'models/company'
require 'models/company_in_module'
require 'models/subscriber'
7
require 'models/ship'
8
require 'models/pirate'
9
require 'models/price_estimate'
10 11 12 13 14 15 16 17 18 19
require 'models/essay'
require 'models/author'
require 'models/organization'
require 'models/post'
require 'models/tagging'
require 'models/category'
require 'models/book'
require 'models/subscriber'
require 'models/subscription'
require 'models/tag'
20
require 'models/sponsor'
D
Initial  
David Heinemeier Hansson 已提交
21

22
class ReflectionTest < ActiveRecord::TestCase
23 24
  include ActiveRecord::Reflection

25
  fixtures :topics, :customers, :companies, :subscribers, :price_estimates
26

D
Initial  
David Heinemeier Hansson 已提交
27 28 29 30
  def setup
    @first = Topic.find(1)
  end

31
  def test_human_name
32 33
    assert_equal "Price estimate", PriceEstimate.model_name.human
    assert_equal "Subscriber", Subscriber.model_name.human
34 35
  end

D
Initial  
David Heinemeier Hansson 已提交
36 37
  def test_read_attribute_names
    assert_equal(
P
Pratik Naik 已提交
38
      %w( id title author_name author_email_address bonus_time written_on last_read content group approved replies_count parent_id parent_title type created_at updated_at ).sort,
39
      @first.attribute_names.sort
D
Initial  
David Heinemeier Hansson 已提交
40 41
    )
  end
42

D
Initial  
David Heinemeier Hansson 已提交
43
  def test_columns
P
Pratik Naik 已提交
44
    assert_equal 16, Topic.columns.length
D
Initial  
David Heinemeier Hansson 已提交
45 46
  end

47 48
  def test_columns_are_returned_in_the_order_they_were_declared
    column_names = Topic.columns.map { |column| column.name }
P
Pratik Naik 已提交
49
    assert_equal %w(id title author_name author_email_address written_on bonus_time last_read content approved replies_count parent_id parent_title type group created_at updated_at), column_names
50 51
  end

D
Initial  
David Heinemeier Hansson 已提交
52
  def test_content_columns
53 54
    content_columns        = Topic.content_columns
    content_column_names   = content_columns.map {|column| column.name}
P
Pratik Naik 已提交
55 56
    assert_equal 12, content_columns.length
    assert_equal %w(title author_name author_email_address written_on bonus_time last_read content group approved parent_title created_at updated_at).sort, content_column_names.sort
D
Initial  
David Heinemeier Hansson 已提交
57
  end
58

D
Initial  
David Heinemeier Hansson 已提交
59 60 61 62
  def test_column_string_type_and_limit
    assert_equal :string, @first.column_for_attribute("title").type
    assert_equal 255, @first.column_for_attribute("title").limit
  end
J
Jeremy Kemper 已提交
63

64 65 66 67 68
  def test_column_null_not_null
    subscriber = Subscriber.find(:first)
    assert subscriber.column_for_attribute("name").null
    assert !subscriber.column_for_attribute("nick").null
  end
D
Initial  
David Heinemeier Hansson 已提交
69 70 71 72

  def test_human_name_for_column
    assert_equal "Author name", @first.column_for_attribute("author_name").human_name
  end
73

D
Initial  
David Heinemeier Hansson 已提交
74 75
  def test_integer_columns
    assert_equal :integer, @first.column_for_attribute("id").type
76
  end
D
Initial  
David Heinemeier Hansson 已提交
77

78
  def test_reflection_klass_for_nested_class_name
79
    reflection = MacroReflection.new(:company, nil, { :class_name => 'MyApplication::Business::Company' }, ActiveRecord::Base)
80 81 82 83 84
    assert_nothing_raised do
      assert_equal MyApplication::Business::Company, reflection.klass
    end
  end

D
Initial  
David Heinemeier Hansson 已提交
85
  def test_aggregation_reflection
86
    reflection_for_address = AggregateReflection.new(
87
      :composed_of, :address, { :mapping => [ %w(address_street street), %w(address_city city), %w(address_country country) ] }, Customer
D
Initial  
David Heinemeier Hansson 已提交
88 89
    )

90
    reflection_for_balance = AggregateReflection.new(
91
      :composed_of, :balance, { :class_name => "Money", :mapping => %w(balance amount) }, Customer
D
Initial  
David Heinemeier Hansson 已提交
92 93
    )

94
    reflection_for_gps_location = AggregateReflection.new(
95 96 97
      :composed_of, :gps_location, { }, Customer
    )

98 99 100
    assert Customer.reflect_on_all_aggregations.include?(reflection_for_gps_location)
    assert Customer.reflect_on_all_aggregations.include?(reflection_for_balance)
    assert Customer.reflect_on_all_aggregations.include?(reflection_for_address)
101

D
Initial  
David Heinemeier Hansson 已提交
102
    assert_equal reflection_for_address, Customer.reflect_on_aggregation(:address)
103

D
Initial  
David Heinemeier Hansson 已提交
104
    assert_equal Address, Customer.reflect_on_aggregation(:address).klass
J
Jeremy Kemper 已提交
105

106
    assert_equal Money, Customer.reflect_on_aggregation(:balance).klass
D
Initial  
David Heinemeier Hansson 已提交
107
  end
108

109 110 111 112 113 114 115 116 117
  def test_reflect_on_all_autosave_associations
    expected = Pirate.reflect_on_all_associations.select { |r| r.options[:autosave] }
    received = Pirate.reflect_on_all_autosave_associations

    assert !received.empty?
    assert_not_equal Pirate.reflect_on_all_associations.length, received.length
    assert_equal expected, received
  end

118
  def test_has_many_reflection
119
    reflection_for_clients = AssociationReflection.new(:has_many, :clients, { :order => "id", :dependent => :destroy }, Firm)
D
Initial  
David Heinemeier Hansson 已提交
120 121 122 123

    assert_equal reflection_for_clients, Firm.reflect_on_association(:clients)

    assert_equal Client, Firm.reflect_on_association(:clients).klass
124 125
    assert_equal 'companies', Firm.reflect_on_association(:clients).table_name

D
Initial  
David Heinemeier Hansson 已提交
126
    assert_equal Client, Firm.reflect_on_association(:clients_of_firm).klass
127 128 129 130
    assert_equal 'companies', Firm.reflect_on_association(:clients_of_firm).table_name
  end

  def test_has_one_reflection
131
    reflection_for_account = AssociationReflection.new(:has_one, :account, { :foreign_key => "firm_id", :dependent => :destroy }, Firm)
132 133 134 135
    assert_equal reflection_for_account, Firm.reflect_on_association(:account)

    assert_equal Account, Firm.reflect_on_association(:account).klass
    assert_equal 'accounts', Firm.reflect_on_association(:account).table_name
D
Initial  
David Heinemeier Hansson 已提交
136
  end
137

138 139
  def test_belongs_to_inferred_foreign_key_from_assoc_name
    Company.belongs_to :foo
140
    assert_equal "foo_id", Company.reflect_on_association(:foo).foreign_key
141
    Company.belongs_to :bar, :class_name => "Xyzzy"
142
    assert_equal "bar_id", Company.reflect_on_association(:bar).foreign_key
143
    Company.belongs_to :baz, :class_name => "Xyzzy", :foreign_key => "xyzzy_id"
144
    assert_equal "xyzzy_id", Company.reflect_on_association(:baz).foreign_key
145 146
  end

D
Initial  
David Heinemeier Hansson 已提交
147
  def test_association_reflection_in_modules
148
    ActiveRecord::Base.store_full_sti_class = false
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
    assert_reflection MyApplication::Business::Firm,
      :clients_of_firm,
      :klass      => MyApplication::Business::Client,
      :class_name => 'Client',
      :table_name => 'companies'

    assert_reflection MyApplication::Billing::Account,
      :firm,
      :klass      => MyApplication::Business::Firm,
      :class_name => 'MyApplication::Business::Firm',
      :table_name => 'companies'

    assert_reflection MyApplication::Billing::Account,
      :qualified_billing_firm,
      :klass      => MyApplication::Billing::Firm,
      :class_name => 'MyApplication::Billing::Firm',
      :table_name => 'companies'

    assert_reflection MyApplication::Billing::Account,
      :unqualified_billing_firm,
      :klass      => MyApplication::Billing::Firm,
      :class_name => 'Firm',
      :table_name => 'companies'

    assert_reflection MyApplication::Billing::Account,
      :nested_qualified_billing_firm,
      :klass      => MyApplication::Billing::Nested::Firm,
      :class_name => 'MyApplication::Billing::Nested::Firm',
      :table_name => 'companies'

    assert_reflection MyApplication::Billing::Account,
      :nested_unqualified_billing_firm,
      :klass      => MyApplication::Billing::Nested::Firm,
      :class_name => 'Nested::Firm',
      :table_name => 'companies'
185 186
  ensure
    ActiveRecord::Base.store_full_sti_class = true
D
Initial  
David Heinemeier Hansson 已提交
187
  end
J
Jeremy Kemper 已提交
188

189
  def test_reflection_of_all_associations
190
    # FIXME these assertions bust a lot
191 192
    assert_equal 36, Firm.reflect_on_all_associations.size
    assert_equal 26, Firm.reflect_on_all_associations(:has_many).size
193
    assert_equal 10, Firm.reflect_on_all_associations(:has_one).size
194
    assert_equal 0, Firm.reflect_on_all_associations(:belongs_to).size
195
  end
196

197 198 199 200
  def test_reflection_should_not_raise_error_when_compared_to_other_object
    assert_nothing_raised { Firm.reflections[:clients] == Object.new }
  end

201
  def test_has_many_through_reflection
202
    assert_kind_of ThroughReflection, Subscriber.reflect_on_association(:books)
203
  end
J
Jon Leighton 已提交
204

205
  def test_chain
206
    expected = [
207
      Organization.reflect_on_association(:author_essay_categories),
208 209 210
      Author.reflect_on_association(:essays),
      Organization.reflect_on_association(:authors)
    ]
211
    actual = Organization.reflect_on_association(:author_essay_categories).chain
J
Jon Leighton 已提交
212

213 214
    assert_equal expected, actual
  end
J
Jon Leighton 已提交
215

216
  def test_conditions
217
    expected = [
J
Jon Leighton 已提交
218
      [{ :tags => { :name => 'Blue' } }],
219
      [{ :taggings => { :comment => 'first' } }],
J
Jon Leighton 已提交
220
      [{ :posts => { :title => ['misc post by bob', 'misc post by mary'] } }]
221
    ]
222
    actual = Author.reflect_on_association(:misc_post_first_blue_tags).conditions
223
    assert_equal expected, actual
J
Jon Leighton 已提交
224

225
    expected = [
J
Jon Leighton 已提交
226
      [{ :tags => { :name => 'Blue' } }, { :taggings => { :comment => 'first' } }, { :posts => { :title => ['misc post by bob', 'misc post by mary'] } }],
227
      [],
228 229
      []
    ]
230
    actual = Author.reflect_on_association(:misc_post_first_blue_tags_2).conditions
231 232
    assert_equal expected, actual
  end
J
Jon Leighton 已提交
233

234 235 236
  def test_nested?
    assert !Author.reflect_on_association(:comments).nested?
    assert Author.reflect_on_association(:tags).nested?
J
Jon Leighton 已提交
237

238 239 240 241
    # Only goes :through once, but the through_reflection is a has_and_belongs_to_many, so this is
    # a nested through association
    assert Category.reflect_on_association(:post_comments).nested?
  end
J
Jon Leighton 已提交
242

243 244 245 246
  def test_association_primary_key
    # Normal association
    assert_equal "id",   Author.reflect_on_association(:posts).association_primary_key.to_s
    assert_equal "name", Author.reflect_on_association(:essay).association_primary_key.to_s
J
Jon Leighton 已提交
247

248 249 250 251 252
    # Through association (uses the :primary_key option from the source reflection)
    assert_equal "nick", Author.reflect_on_association(:subscribers).association_primary_key.to_s
    assert_equal "name", Author.reflect_on_association(:essay_category).association_primary_key.to_s
    assert_equal "custom_primary_key", Author.reflect_on_association(:tags_with_primary_key).association_primary_key.to_s # nested
  end
J
Jon Leighton 已提交
253

254 255 256 257
  def test_active_record_primary_key
    assert_equal "nick", Subscriber.reflect_on_association(:subscriptions).active_record_primary_key.to_s
    assert_equal "name", Author.reflect_on_association(:essay).active_record_primary_key.to_s
  end
258

259 260 261 262 263
  def test_foreign_type
    assert_equal "sponsorable_type", Sponsor.reflect_on_association(:sponsorable).foreign_type.to_s
    assert_equal "sponsorable_type", Sponsor.reflect_on_association(:thing).foreign_type.to_s
  end

264
  def test_collection_association
265 266
    assert Pirate.reflect_on_association(:birds).collection?
    assert Pirate.reflect_on_association(:parrots).collection?
267

268 269
    assert !Pirate.reflect_on_association(:ship).collection?
    assert !Ship.reflect_on_association(:pirate).collection?
270 271
  end

272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
  def test_default_association_validation
    assert AssociationReflection.new(:has_many, :clients, {}, Firm).validate?

    assert !AssociationReflection.new(:has_one, :client, {}, Firm).validate?
    assert !AssociationReflection.new(:belongs_to, :client, {}, Firm).validate?
    assert !AssociationReflection.new(:has_and_belongs_to_many, :clients, {}, Firm).validate?
  end

  def test_always_validate_association_if_explicit
    assert AssociationReflection.new(:has_one, :client, { :validate => true }, Firm).validate?
    assert AssociationReflection.new(:belongs_to, :client, { :validate => true }, Firm).validate?
    assert AssociationReflection.new(:has_many, :clients, { :validate => true }, Firm).validate?
    assert AssociationReflection.new(:has_and_belongs_to_many, :clients, { :validate => true }, Firm).validate?
  end

  def test_validate_association_if_autosave
    assert AssociationReflection.new(:has_one, :client, { :autosave => true }, Firm).validate?
    assert AssociationReflection.new(:belongs_to, :client, { :autosave => true }, Firm).validate?
    assert AssociationReflection.new(:has_many, :clients, { :autosave => true }, Firm).validate?
    assert AssociationReflection.new(:has_and_belongs_to_many, :clients, { :autosave => true }, Firm).validate?
  end

  def test_never_validate_association_if_explicit
    assert !AssociationReflection.new(:has_one, :client, { :autosave => true, :validate => false }, Firm).validate?
    assert !AssociationReflection.new(:belongs_to, :client, { :autosave => true, :validate => false }, Firm).validate?
    assert !AssociationReflection.new(:has_many, :clients, { :autosave => true, :validate => false }, Firm).validate?
    assert !AssociationReflection.new(:has_and_belongs_to_many, :clients, { :autosave => true, :validate => false }, Firm).validate?
  end

301 302 303 304 305
  def test_foreign_key
    assert_equal "author_id", Author.reflect_on_association(:posts).foreign_key.to_s
    assert_equal "category_id", Post.reflect_on_association(:categorizations).foreign_key.to_s
  end

306 307 308 309 310 311 312
  private
    def assert_reflection(klass, association, options)
      assert reflection = klass.reflect_on_association(association)
      options.each do |method, value|
        assert_equal(value, reflection.send(method))
      end
    end
313
end