reflection_test.rb 15.5 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
G
gregolsen 已提交
168 169
    assert_equal 39, Firm.reflect_on_all_associations.size
    assert_equal 29, 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_conditions
194
    expected = [
J
Jon Leighton 已提交
195
      [{ :tags => { :name => 'Blue' } }],
196
      [{ :taggings => { :comment => 'first' } }],
J
Jon Leighton 已提交
197
      [{ :posts => { :title => ['misc post by bob', 'misc post by mary'] } }]
198
    ]
199
    actual = Author.reflect_on_association(:misc_post_first_blue_tags).conditions
200
    assert_equal expected, actual
J
Jon Leighton 已提交
201

202
    expected = [
J
Jon Leighton 已提交
203
      [{ :tags => { :name => 'Blue' } }, { :taggings => { :comment => 'first' } }, { :posts => { :title => ['misc post by bob', 'misc post by mary'] } }],
204
      [],
205 206
      []
    ]
207
    actual = Author.reflect_on_association(:misc_post_first_blue_tags_2).conditions
208 209
    assert_equal expected, actual
  end
J
Jon Leighton 已提交
210

211 212 213
  def test_nested?
    assert !Author.reflect_on_association(:comments).nested?
    assert Author.reflect_on_association(:tags).nested?
J
Jon Leighton 已提交
214

215 216 217 218
    # 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 已提交
219

220 221 222 223
  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
224
    assert_equal "name", Essay.reflect_on_association(:writer).association_primary_key.to_s
J
Jon Leighton 已提交
225

226 227 228 229 230
    # 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 已提交
231

232
  def test_association_primary_key_raises_when_missing_primary_key
233
    reflection = ActiveRecord::Reflection::AssociationReflection.new(:fuu, :edge, nil, {}, Author)
234 235
    assert_raises(ActiveRecord::UnknownPrimaryKey) { reflection.association_primary_key }

236
    through = ActiveRecord::Reflection::ThroughReflection.new(:fuu, :edge, nil, {}, Author)
237 238 239 240
    through.stubs(:source_reflection).returns(stub_everything(:options => {}, :class_name => 'Edge'))
    assert_raises(ActiveRecord::UnknownPrimaryKey) { through.association_primary_key }
  end

241 242 243 244
  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
245

246
  def test_active_record_primary_key_raises_when_missing_primary_key
247
    reflection = ActiveRecord::Reflection::AssociationReflection.new(:fuu, :author, nil, {}, Edge)
248 249 250
    assert_raises(ActiveRecord::UnknownPrimaryKey) { reflection.active_record_primary_key }
  end

251 252 253 254 255
  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

256
  def test_collection_association
257 258
    assert Pirate.reflect_on_association(:birds).collection?
    assert Pirate.reflect_on_association(:parrots).collection?
259

260 261
    assert !Pirate.reflect_on_association(:ship).collection?
    assert !Ship.reflect_on_association(:pirate).collection?
262 263
  end

264
  def test_default_association_validation
265
    assert AssociationReflection.new(:has_many, :clients, nil, {}, Firm).validate?
266

267 268 269
    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?
270 271 272
  end

  def test_always_validate_association_if_explicit
273 274 275 276
    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?
277 278 279
  end

  def test_validate_association_if_autosave
280 281 282 283
    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?
284 285 286
  end

  def test_never_validate_association_if_explicit
287 288 289 290
    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?
291 292
  end

293 294 295 296 297
  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

J
Jon Leighton 已提交
298 299 300 301 302 303
  def test_through_reflection_conditions_do_not_modify_other_reflections
    orig_conds = Post.reflect_on_association(:first_blue_tags_2).conditions.inspect
    Author.reflect_on_association(:misc_post_first_blue_tags_2).conditions
    assert_equal orig_conds, Post.reflect_on_association(:first_blue_tags_2).conditions.inspect
  end

304 305 306 307
  def test_symbol_for_class_name
    assert_equal Client, Firm.reflect_on_association(:unsorted_clients_with_symbol).klass
  end

308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
  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)

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

    reflection = AssociationReflection.new(:has_and_belongs_to_many, :products, {}, category)
    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)

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

    reflection = AssociationReflection.new(:has_and_belongs_to_many, :products, {}, category)
    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)

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

    reflection = AssociationReflection.new(:has_and_belongs_to_many, :pages, {}, category)
    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)

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

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

360 361 362 363 364 365 366
  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
367
end