reflection_test.rb 13.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(
P
Pratik Naik 已提交
39
      %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,
40
      @first.attribute_names.sort
D
Initial  
David Heinemeier Hansson 已提交
41 42
    )
  end
43

D
Initial  
David Heinemeier Hansson 已提交
44
  def test_columns
P
Pratik Naik 已提交
45
    assert_equal 16, 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 }
P
Pratik Naik 已提交
50
    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
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}
P
Pratik Naik 已提交
56 57
    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 已提交
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 66 67 68 69
  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 已提交
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, { :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

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

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

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

99 100 101
    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)
102

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

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

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

110 111 112 113 114 115 116 117 118
  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

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

    assert_equal reflection_for_clients, Firm.reflect_on_association(:clients)

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

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

  def test_has_one_reflection
132
    reflection_for_account = AssociationReflection.new(:has_one, :account, { :foreign_key => "firm_id", :dependent => :destroy }, Firm)
133 134 135 136
    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 已提交
137
  end
138

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

D
Initial  
David Heinemeier Hansson 已提交
148
  def test_association_reflection_in_modules
149
    ActiveRecord::Base.store_full_sti_class = false
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
    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'
186 187
  ensure
    ActiveRecord::Base.store_full_sti_class = true
D
Initial  
David Heinemeier Hansson 已提交
188
  end
J
Jeremy Kemper 已提交
189

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

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

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

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

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

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

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

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

239 240 241 242
    # 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 已提交
243

244 245 246 247
  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
248
    assert_equal "name", Essay.reflect_on_association(:writer).association_primary_key.to_s
J
Jon Leighton 已提交
249

250 251 252 253 254
    # 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 已提交
255

256 257 258 259 260 261 262 263 264
  def test_association_primary_key_raises_when_missing_primary_key
    reflection = ActiveRecord::Reflection::AssociationReflection.new(:fuu, :edge, {}, Author)
    assert_raises(ActiveRecord::UnknownPrimaryKey) { reflection.association_primary_key }

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

265 266 267 268
  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
269

270 271 272 273 274
  def test_active_record_primary_key_raises_when_missing_primary_key
    reflection = ActiveRecord::Reflection::AssociationReflection.new(:fuu, :author, {}, Edge)
    assert_raises(ActiveRecord::UnknownPrimaryKey) { reflection.active_record_primary_key }
  end

275 276 277 278 279
  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

280
  def test_collection_association
281 282
    assert Pirate.reflect_on_association(:birds).collection?
    assert Pirate.reflect_on_association(:parrots).collection?
283

284 285
    assert !Pirate.reflect_on_association(:ship).collection?
    assert !Ship.reflect_on_association(:pirate).collection?
286 287
  end

288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
  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

317 318 319 320 321
  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 已提交
322 323 324 325 326 327
  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

328 329 330 331 332 333 334
  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
335
end