reflection_test.rb 15.6 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'
21
require 'models/edge'
D
Initial  
David Heinemeier Hansson 已提交
22

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

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

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

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

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

D
Initial  
David Heinemeier Hansson 已提交
44
  def test_columns
A
Alvaro Bautista 已提交
45
    assert_equal 17, Topic.columns.length
D
Initial  
David Heinemeier Hansson 已提交
46 47
  end

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

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

D
Initial  
David Heinemeier Hansson 已提交
60 61 62 63
  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 已提交
64

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

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

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

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

86 87 88 89 90 91 92 93 94
  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

95
  def test_has_many_reflection
96
    reflection_for_clients = AssociationReflection.new(:has_many, :clients, nil, { :order => "id", :dependent => :destroy }, Firm)
D
Initial  
David Heinemeier Hansson 已提交
97 98 99 100

    assert_equal reflection_for_clients, Firm.reflect_on_association(:clients)

    assert_equal Client, Firm.reflect_on_association(:clients).klass
101 102
    assert_equal 'companies', Firm.reflect_on_association(:clients).table_name

D
Initial  
David Heinemeier Hansson 已提交
103
    assert_equal Client, Firm.reflect_on_association(:clients_of_firm).klass
104 105 106 107
    assert_equal 'companies', Firm.reflect_on_association(:clients_of_firm).table_name
  end

  def test_has_one_reflection
108
    reflection_for_account = AssociationReflection.new(:has_one, :account, nil, { :foreign_key => "firm_id", :dependent => :destroy }, Firm)
109 110 111 112
    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 已提交
113
  end
114

115 116
  def test_belongs_to_inferred_foreign_key_from_assoc_name
    Company.belongs_to :foo
117
    assert_equal "foo_id", Company.reflect_on_association(:foo).foreign_key
118
    Company.belongs_to :bar, :class_name => "Xyzzy"
119
    assert_equal "bar_id", Company.reflect_on_association(:bar).foreign_key
120
    Company.belongs_to :baz, :class_name => "Xyzzy", :foreign_key => "xyzzy_id"
121
    assert_equal "xyzzy_id", Company.reflect_on_association(:baz).foreign_key
122 123
  end

D
Initial  
David Heinemeier Hansson 已提交
124
  def test_association_reflection_in_modules
125
    ActiveRecord::Base.store_full_sti_class = false
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
    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'
162 163
  ensure
    ActiveRecord::Base.store_full_sti_class = true
D
Initial  
David Heinemeier Hansson 已提交
164
  end
J
Jeremy Kemper 已提交
165

166
  def test_reflection_of_all_associations
167
    # FIXME these assertions bust a lot
168 169
    assert_equal 34, Firm.reflect_on_all_associations.size
    assert_equal 24, Firm.reflect_on_all_associations(:has_many).size
170
    assert_equal 10, Firm.reflect_on_all_associations(:has_one).size
171
    assert_equal 0, Firm.reflect_on_all_associations(:belongs_to).size
172
  end
173

174 175 176 177
  def test_reflection_should_not_raise_error_when_compared_to_other_object
    assert_nothing_raised { Firm.reflections[:clients] == Object.new }
  end

178
  def test_has_many_through_reflection
179
    assert_kind_of ThroughReflection, Subscriber.reflect_on_association(:books)
180
  end
J
Jon Leighton 已提交
181

182
  def test_chain
183
    expected = [
184
      Organization.reflect_on_association(:author_essay_categories),
185 186 187
      Author.reflect_on_association(:essays),
      Organization.reflect_on_association(:authors)
    ]
188
    actual = Organization.reflect_on_association(:author_essay_categories).chain
J
Jon Leighton 已提交
189

190 191
    assert_equal expected, actual
  end
J
Jon Leighton 已提交
192

193
  def test_scope_chain
194
    expected = [
195 196 197
      [Tagging.reflect_on_association(:tag).scope, Post.reflect_on_association(:first_blue_tags).scope],
      [Post.reflect_on_association(:first_taggings).scope],
      [Author.reflect_on_association(:misc_posts).scope]
198
    ]
199
    actual = Author.reflect_on_association(:misc_post_first_blue_tags).scope_chain
200
    assert_equal expected, actual
J
Jon Leighton 已提交
201

202
    expected = [
203 204 205 206 207
      [
        Tagging.reflect_on_association(:blue_tag).scope,
        Post.reflect_on_association(:first_blue_tags_2).scope,
        Author.reflect_on_association(:misc_post_first_blue_tags_2).scope
      ],
208
      [],
209 210
      []
    ]
211
    actual = Author.reflect_on_association(:misc_post_first_blue_tags_2).scope_chain
212 213
    assert_equal expected, actual
  end
J
Jon Leighton 已提交
214

215 216 217
  def test_nested?
    assert !Author.reflect_on_association(:comments).nested?
    assert Author.reflect_on_association(:tags).nested?
J
Jon Leighton 已提交
218

219 220 221 222
    # 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 已提交
223

224 225 226 227
  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
228
    assert_equal "name", Essay.reflect_on_association(:writer).association_primary_key.to_s
J
Jon Leighton 已提交
229

230 231 232 233 234
    # 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 已提交
235

236
  def test_association_primary_key_raises_when_missing_primary_key
237
    reflection = ActiveRecord::Reflection::AssociationReflection.new(:fuu, :edge, nil, {}, Author)
238 239
    assert_raises(ActiveRecord::UnknownPrimaryKey) { reflection.association_primary_key }

240
    through = ActiveRecord::Reflection::ThroughReflection.new(:fuu, :edge, nil, {}, Author)
241 242 243 244
    through.stubs(:source_reflection).returns(stub_everything(:options => {}, :class_name => 'Edge'))
    assert_raises(ActiveRecord::UnknownPrimaryKey) { through.association_primary_key }
  end

245 246 247 248
  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
249

250
  def test_active_record_primary_key_raises_when_missing_primary_key
251
    reflection = ActiveRecord::Reflection::AssociationReflection.new(:fuu, :author, nil, {}, Edge)
252 253 254
    assert_raises(ActiveRecord::UnknownPrimaryKey) { reflection.active_record_primary_key }
  end

255 256 257 258 259
  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

260
  def test_collection_association
261 262
    assert Pirate.reflect_on_association(:birds).collection?
    assert Pirate.reflect_on_association(:parrots).collection?
263

264 265
    assert !Pirate.reflect_on_association(:ship).collection?
    assert !Ship.reflect_on_association(:pirate).collection?
266 267
  end

268
  def test_default_association_validation
269
    assert AssociationReflection.new(:has_many, :clients, nil, {}, Firm).validate?
270

271 272 273
    assert !AssociationReflection.new(:has_one, :client, nil, {}, Firm).validate?
    assert !AssociationReflection.new(:belongs_to, :client, nil, {}, Firm).validate?
    assert !AssociationReflection.new(:has_and_belongs_to_many, :clients, nil, {}, Firm).validate?
274 275 276
  end

  def test_always_validate_association_if_explicit
277 278 279 280
    assert AssociationReflection.new(:has_one, :client, nil, { :validate => true }, Firm).validate?
    assert AssociationReflection.new(:belongs_to, :client, nil, { :validate => true }, Firm).validate?
    assert AssociationReflection.new(:has_many, :clients, nil, { :validate => true }, Firm).validate?
    assert AssociationReflection.new(:has_and_belongs_to_many, :clients, nil, { :validate => true }, Firm).validate?
281 282 283
  end

  def test_validate_association_if_autosave
284 285 286 287
    assert AssociationReflection.new(:has_one, :client, nil, { :autosave => true }, Firm).validate?
    assert AssociationReflection.new(:belongs_to, :client, nil, { :autosave => true }, Firm).validate?
    assert AssociationReflection.new(:has_many, :clients, nil, { :autosave => true }, Firm).validate?
    assert AssociationReflection.new(:has_and_belongs_to_many, :clients, nil, { :autosave => true }, Firm).validate?
288 289 290
  end

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

297 298 299 300 301
  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

302 303 304 305
  def test_through_reflection_scope_chain_does_not_modify_other_reflections
    orig_conds = Post.reflect_on_association(:first_blue_tags_2).scope_chain.inspect
    Author.reflect_on_association(:misc_post_first_blue_tags_2).scope_chain
    assert_equal orig_conds, Post.reflect_on_association(:first_blue_tags_2).scope_chain.inspect
J
Jon Leighton 已提交
306 307
  end

308 309 310 311
  def test_symbol_for_class_name
    assert_equal Client, Firm.reflect_on_association(:unsorted_clients_with_symbol).klass
  end

312 313 314 315
  def test_join_table
    category = Struct.new(:table_name, :pluralize_table_names).new('categories', true)
    product = Struct.new(:table_name, :pluralize_table_names).new('products', true)

316
    reflection = AssociationReflection.new(:has_and_belongs_to_many, :categories, nil, {}, product)
317 318 319
    reflection.stubs(:klass).returns(category)
    assert_equal 'categories_products', reflection.join_table

320
    reflection = AssociationReflection.new(:has_and_belongs_to_many, :products, nil, {}, category)
321 322 323 324 325 326 327 328
    reflection.stubs(:klass).returns(product)
    assert_equal 'categories_products', reflection.join_table
  end

  def test_join_table_with_common_prefix
    category = Struct.new(:table_name, :pluralize_table_names).new('catalog_categories', true)
    product = Struct.new(:table_name, :pluralize_table_names).new('catalog_products', true)

329
    reflection = AssociationReflection.new(:has_and_belongs_to_many, :categories, nil, {}, product)
330 331 332
    reflection.stubs(:klass).returns(category)
    assert_equal 'catalog_categories_products', reflection.join_table

333
    reflection = AssociationReflection.new(:has_and_belongs_to_many, :products, nil, {}, category)
334 335 336 337 338 339 340 341
    reflection.stubs(:klass).returns(product)
    assert_equal 'catalog_categories_products', reflection.join_table
  end

  def test_join_table_with_different_prefix
    category = Struct.new(:table_name, :pluralize_table_names).new('catalog_categories', true)
    page = Struct.new(:table_name, :pluralize_table_names).new('content_pages', true)

342
    reflection = AssociationReflection.new(:has_and_belongs_to_many, :categories, nil, {}, page)
343 344 345
    reflection.stubs(:klass).returns(category)
    assert_equal 'catalog_categories_content_pages', reflection.join_table

346
    reflection = AssociationReflection.new(:has_and_belongs_to_many, :pages, nil, {}, category)
347 348 349 350 351 352 353 354
    reflection.stubs(:klass).returns(page)
    assert_equal 'catalog_categories_content_pages', reflection.join_table
  end

  def test_join_table_can_be_overridden
    category = Struct.new(:table_name, :pluralize_table_names).new('categories', true)
    product = Struct.new(:table_name, :pluralize_table_names).new('products', true)

355
    reflection = AssociationReflection.new(:has_and_belongs_to_many, :categories, nil, { :join_table => 'product_categories' }, product)
356 357 358
    reflection.stubs(:klass).returns(category)
    assert_equal 'product_categories', reflection.join_table

359
    reflection = AssociationReflection.new(:has_and_belongs_to_many, :products, nil, { :join_table => 'product_categories' }, category)
360 361 362 363
    reflection.stubs(:klass).returns(product)
    assert_equal 'product_categories', reflection.join_table
  end

364 365 366 367 368 369 370
  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
371
end