~michaelforrest/use-case-mapper/trunk

« back to all changes in this revision

Viewing changes to vendor/rails/activerecord/test/cases/associations/has_many_through_associations_test.rb

  • Committer: Richard Lee (Canonical)
  • Date: 2010-10-15 15:17:58 UTC
  • mfrom: (190.1.3 use-case-mapper)
  • Revision ID: richard.lee@canonical.com-20101015151758-wcvmfxrexsongf9d
Merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
require "cases/helper"
2
 
require 'models/post'
3
 
require 'models/person'
4
 
require 'models/reference'
5
 
require 'models/job'
6
 
require 'models/reader'
7
 
require 'models/comment'
8
 
require 'models/tag'
9
 
require 'models/tagging'
10
 
require 'models/author'
11
 
require 'models/owner'
12
 
require 'models/pet'
13
 
require 'models/toy'
14
 
require 'models/contract'
15
 
require 'models/company'
16
 
require 'models/developer'
17
 
 
18
 
class HasManyThroughAssociationsTest < ActiveRecord::TestCase
19
 
  fixtures :posts, :readers, :people, :comments, :authors, :owners, :pets, :toys,
20
 
           :companies
21
 
 
22
 
  def test_associate_existing
23
 
    assert_queries(2) { posts(:thinking);people(:david) }
24
 
 
25
 
    posts(:thinking).people
26
 
 
27
 
    assert_queries(1) do
28
 
      posts(:thinking).people << people(:david)
29
 
    end
30
 
    
31
 
    assert_queries(1) do
32
 
      assert posts(:thinking).people.include?(people(:david))
33
 
    end
34
 
    
35
 
    assert posts(:thinking).reload.people(true).include?(people(:david))
36
 
  end
37
 
 
38
 
  def test_associating_new
39
 
    assert_queries(1) { posts(:thinking) }
40
 
    new_person = nil # so block binding catches it
41
 
    
42
 
    assert_queries(0) do
43
 
      new_person = Person.new :first_name => 'bob'
44
 
    end
45
 
    
46
 
    # Associating new records always saves them
47
 
    # Thus, 1 query for the new person record, 1 query for the new join table record
48
 
    assert_queries(2) do
49
 
      posts(:thinking).people << new_person
50
 
    end
51
 
    
52
 
    assert_queries(1) do
53
 
      assert posts(:thinking).people.include?(new_person)
54
 
    end
55
 
    
56
 
    assert posts(:thinking).reload.people(true).include?(new_person)
57
 
  end
58
 
 
59
 
  def test_associate_new_by_building
60
 
    assert_queries(1) { posts(:thinking) }
61
 
    
62
 
    assert_queries(0) do
63
 
      posts(:thinking).people.build(:first_name=>"Bob")
64
 
      posts(:thinking).people.new(:first_name=>"Ted")
65
 
    end
66
 
    
67
 
    # Should only need to load the association once
68
 
    assert_queries(1) do
69
 
      assert posts(:thinking).people.collect(&:first_name).include?("Bob")
70
 
      assert posts(:thinking).people.collect(&:first_name).include?("Ted")
71
 
    end
72
 
    
73
 
    # 2 queries for each new record (1 to save the record itself, 1 for the join model)
74
 
    #    * 2 new records = 4
75
 
    # + 1 query to save the actual post = 5
76
 
    assert_queries(5) do
77
 
      posts(:thinking).body += '-changed'
78
 
      posts(:thinking).save
79
 
    end
80
 
    
81
 
    assert posts(:thinking).reload.people(true).collect(&:first_name).include?("Bob")
82
 
    assert posts(:thinking).reload.people(true).collect(&:first_name).include?("Ted")
83
 
  end
84
 
 
85
 
  def test_delete_association
86
 
    assert_queries(2){posts(:welcome);people(:michael); }
87
 
    
88
 
    assert_queries(1) do
89
 
      posts(:welcome).people.delete(people(:michael))
90
 
    end
91
 
    
92
 
    assert_queries(1) do
93
 
      assert posts(:welcome).people.empty?
94
 
    end
95
 
    
96
 
    assert posts(:welcome).reload.people(true).empty?
97
 
  end
98
 
 
99
 
  def test_destroy_association
100
 
    assert_difference "Person.count", -1 do
101
 
      posts(:welcome).people.destroy(people(:michael))
102
 
    end
103
 
 
104
 
    assert posts(:welcome).reload.people.empty?
105
 
    assert posts(:welcome).people(true).empty?
106
 
  end
107
 
 
108
 
  def test_destroy_all
109
 
    assert_difference "Person.count", -1 do
110
 
      posts(:welcome).people.destroy_all
111
 
    end
112
 
 
113
 
    assert posts(:welcome).reload.people.empty?
114
 
    assert posts(:welcome).people(true).empty?
115
 
  end
116
 
 
117
 
  def test_replace_association
118
 
    assert_queries(4){posts(:welcome);people(:david);people(:michael); posts(:welcome).people(true)}
119
 
    
120
 
    # 1 query to delete the existing reader (michael)
121
 
    # 1 query to associate the new reader (david)
122
 
    assert_queries(2) do
123
 
      posts(:welcome).people = [people(:david)]
124
 
    end
125
 
    
126
 
    assert_queries(0){
127
 
      assert posts(:welcome).people.include?(people(:david))
128
 
      assert !posts(:welcome).people.include?(people(:michael))
129
 
    }
130
 
    
131
 
    assert posts(:welcome).reload.people(true).include?(people(:david))
132
 
    assert !posts(:welcome).reload.people(true).include?(people(:michael))
133
 
  end
134
 
 
135
 
  def test_replace_order_is_preserved
136
 
    posts(:welcome).people.clear
137
 
    posts(:welcome).people = [people(:david), people(:michael)]
138
 
    assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.all(:order => 'id').map(&:person_id)
139
 
 
140
 
    # Test the inverse order in case the first success was a coincidence
141
 
    posts(:welcome).people.clear
142
 
    posts(:welcome).people = [people(:michael), people(:david)]
143
 
    assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.all(:order => 'id').map(&:person_id)
144
 
  end
145
 
 
146
 
  def test_replace_by_id_order_is_preserved
147
 
    posts(:welcome).people.clear
148
 
    posts(:welcome).person_ids = [people(:david).id, people(:michael).id]
149
 
    assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.all(:order => 'id').map(&:person_id)
150
 
 
151
 
    # Test the inverse order in case the first success was a coincidence
152
 
    posts(:welcome).people.clear
153
 
    posts(:welcome).person_ids = [people(:michael).id, people(:david).id]
154
 
    assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.all(:order => 'id').map(&:person_id)
155
 
  end
156
 
 
157
 
  def test_associate_with_create
158
 
    assert_queries(1) { posts(:thinking) }
159
 
    
160
 
    # 1 query for the new record, 1 for the join table record
161
 
    # No need to update the actual collection yet!
162
 
    assert_queries(2) do
163
 
      posts(:thinking).people.create(:first_name=>"Jeb")
164
 
    end
165
 
    
166
 
    # *Now* we actually need the collection so it's loaded
167
 
    assert_queries(1) do
168
 
      assert posts(:thinking).people.collect(&:first_name).include?("Jeb")
169
 
    end
170
 
    
171
 
    assert posts(:thinking).reload.people(true).collect(&:first_name).include?("Jeb")
172
 
  end
173
 
 
174
 
  def test_associate_with_create_and_no_options
175
 
    peeps = posts(:thinking).people.count
176
 
    posts(:thinking).people.create(:first_name => 'foo')
177
 
    assert_equal peeps + 1, posts(:thinking).people.count
178
 
  end
179
 
 
180
 
  def test_associate_with_create_exclamation_and_no_options
181
 
    peeps = posts(:thinking).people.count
182
 
    posts(:thinking).people.create!(:first_name => 'foo')
183
 
    assert_equal peeps + 1, posts(:thinking).people.count
184
 
  end
185
 
 
186
 
  def test_associate_with_create_and_invalid_options
187
 
    peeps = companies(:first_firm).developers.count
188
 
    assert_nothing_raised { companies(:first_firm).developers.create(:name => '0') }
189
 
    assert_equal peeps, companies(:first_firm).developers.count
190
 
  end
191
 
 
192
 
  def test_associate_with_create_and_valid_options
193
 
    peeps = companies(:first_firm).developers.count
194
 
    assert_nothing_raised { companies(:first_firm).developers.create(:name => 'developer') }
195
 
    assert_equal peeps + 1, companies(:first_firm).developers.count
196
 
  end
197
 
 
198
 
  def test_associate_with_create_bang_and_invalid_options
199
 
    peeps = companies(:first_firm).developers.count
200
 
    assert_raises(ActiveRecord::RecordInvalid) { companies(:first_firm).developers.create!(:name => '0') }
201
 
    assert_equal peeps, companies(:first_firm).developers.count
202
 
  end
203
 
 
204
 
  def test_associate_with_create_bang_and_valid_options
205
 
    peeps = companies(:first_firm).developers.count
206
 
    assert_nothing_raised { companies(:first_firm).developers.create!(:name => 'developer') }
207
 
    assert_equal peeps + 1, companies(:first_firm).developers.count
208
 
  end
209
 
 
210
 
  def test_clear_associations
211
 
    assert_queries(2) { posts(:welcome);posts(:welcome).people(true) }
212
 
    
213
 
    assert_queries(1) do
214
 
      posts(:welcome).people.clear
215
 
    end
216
 
    
217
 
    assert_queries(0) do
218
 
      assert posts(:welcome).people.empty?
219
 
    end
220
 
    
221
 
    assert posts(:welcome).reload.people(true).empty?
222
 
  end
223
 
 
224
 
  def test_association_callback_ordering
225
 
    Post.reset_log
226
 
    log = Post.log
227
 
    post = posts(:thinking)
228
 
 
229
 
    post.people_with_callbacks << people(:michael)
230
 
    assert_equal [
231
 
      [:added, :before, "Michael"],
232
 
      [:added, :after, "Michael"]
233
 
    ], log.last(2)
234
 
 
235
 
    post.people_with_callbacks.push(people(:david), Person.create!(:first_name => "Bob"), Person.new(:first_name => "Lary"))
236
 
    assert_equal [
237
 
      [:added, :before, "David"],
238
 
      [:added, :after, "David"],
239
 
      [:added, :before, "Bob"],
240
 
      [:added, :after, "Bob"],
241
 
      [:added, :before, "Lary"],
242
 
      [:added, :after, "Lary"]
243
 
    ],log.last(6)
244
 
 
245
 
    post.people_with_callbacks.build(:first_name => "Ted")
246
 
    assert_equal [
247
 
      [:added, :before, "Ted"],
248
 
      [:added, :after, "Ted"]
249
 
    ], log.last(2)
250
 
 
251
 
    post.people_with_callbacks.create(:first_name => "Sam")
252
 
    assert_equal [
253
 
      [:added, :before, "Sam"],
254
 
      [:added, :after, "Sam"]
255
 
    ], log.last(2)
256
 
 
257
 
    post.people_with_callbacks = [people(:michael),people(:david), Person.new(:first_name => "Julian"), Person.create!(:first_name => "Roger")]
258
 
    assert_equal (%w(Ted Bob Sam Lary) * 2).sort, log[-12..-5].collect(&:last).sort
259
 
    assert_equal [
260
 
      [:added, :before, "Julian"],
261
 
      [:added, :after, "Julian"],
262
 
      [:added, :before, "Roger"],
263
 
      [:added, :after, "Roger"]
264
 
    ], log.last(4)
265
 
 
266
 
    post.people_with_callbacks.clear
267
 
    assert_equal (%w(Michael David Julian Roger) * 2).sort, log.last(8).collect(&:last).sort
268
 
  end
269
 
 
270
 
  def test_dynamic_find_should_respect_association_include
271
 
    # SQL error in sort clause if :include is not included
272
 
    # due to Unknown column 'comments.id'
273
 
    assert Person.find(1).posts_with_comments_sorted_by_comment_id.find_by_title('Welcome to the weblog')
274
 
  end
275
 
 
276
 
  def test_count_with_include_should_alias_join_table
277
 
    assert_equal 2, people(:michael).posts.count(:include => :readers)
278
 
  end
279
 
 
280
 
  def test_inner_join_with_quoted_table_name
281
 
    assert_equal 2, people(:michael).jobs.size
282
 
  end
283
 
 
284
 
  def test_get_ids
285
 
    assert_equal [posts(:welcome).id, posts(:authorless).id].sort, people(:michael).post_ids.sort
286
 
  end
287
 
 
288
 
  def test_get_ids_for_loaded_associations
289
 
    person = people(:michael)
290
 
    person.posts(true)
291
 
    assert_queries(0) do
292
 
      person.post_ids
293
 
      person.post_ids
294
 
    end
295
 
  end
296
 
 
297
 
  def test_get_ids_for_unloaded_associations_does_not_load_them
298
 
    person = people(:michael)
299
 
    assert !person.posts.loaded?
300
 
    assert_equal [posts(:welcome).id, posts(:authorless).id].sort, person.post_ids.sort
301
 
    assert !person.posts.loaded?
302
 
  end
303
 
 
304
 
  def test_association_proxy_transaction_method_starts_transaction_in_association_class
305
 
    Tag.expects(:transaction)
306
 
    Post.find(:first).tags.transaction do
307
 
      # nothing
308
 
    end
309
 
  end
310
 
 
311
 
  def test_has_many_association_through_a_belongs_to_association_where_the_association_doesnt_exist
312
 
    author = authors(:mary)
313
 
    post = Post.create!(:title => "TITLE", :body => "BODY")
314
 
    assert_equal [], post.author_favorites
315
 
  end
316
 
 
317
 
  def test_has_many_association_through_a_belongs_to_association
318
 
    author = authors(:mary)
319
 
    post = Post.create!(:author => author, :title => "TITLE", :body => "BODY")
320
 
    author.author_favorites.create(:favorite_author_id => 1)
321
 
    author.author_favorites.create(:favorite_author_id => 2)
322
 
    author.author_favorites.create(:favorite_author_id => 3)
323
 
    assert_equal post.author.author_favorites, post.author_favorites
324
 
  end
325
 
 
326
 
  def test_has_many_association_through_a_has_many_association_with_nonstandard_primary_keys
327
 
    assert_equal 1, owners(:blackbeard).toys.count
328
 
  end
329
 
 
330
 
  def test_find_on_has_many_association_collection_with_include_and_conditions
331
 
    post_with_no_comments = people(:michael).posts_with_no_comments.first
332
 
    assert_equal post_with_no_comments, posts(:authorless)
333
 
  end
334
 
 
335
 
  def test_has_many_through_has_one_reflection
336
 
    assert_equal [comments(:eager_sti_on_associations_vs_comment)], authors(:david).very_special_comments
337
 
  end
338
 
 
339
 
  def test_modifying_has_many_through_has_one_reflection_should_raise
340
 
    [
341
 
      lambda { authors(:david).very_special_comments = [VerySpecialComment.create!(:body => "Gorp!", :post_id => 1011), VerySpecialComment.create!(:body => "Eep!", :post_id => 1012)] },
342
 
      lambda { authors(:david).very_special_comments << VerySpecialComment.create!(:body => "Hoohah!", :post_id => 1013) },
343
 
      lambda { authors(:david).very_special_comments.delete(authors(:david).very_special_comments.first) },
344
 
    ].each {|block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection, &block) }
345
 
  end
346
 
end