shoulda-matchers 1.4.2 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. data/.travis.yml +11 -3
  2. data/Appraisals +3 -3
  3. data/Gemfile +1 -1
  4. data/Gemfile.lock +69 -70
  5. data/MIT-LICENSE +1 -1
  6. data/NEWS.md +22 -4
  7. data/README.md +3 -1
  8. data/Rakefile +9 -5
  9. data/features/step_definitions/rails_steps.rb +7 -7
  10. data/features/support/env.rb +1 -1
  11. data/gemfiles/3.0.gemfile +1 -1
  12. data/gemfiles/3.0.gemfile.lock +25 -22
  13. data/gemfiles/3.1.gemfile +1 -1
  14. data/gemfiles/3.1.gemfile.lock +27 -24
  15. data/gemfiles/3.2.gemfile +1 -1
  16. data/gemfiles/3.2.gemfile.lock +56 -52
  17. data/lib/shoulda/matchers/action_controller.rb +3 -2
  18. data/lib/shoulda/matchers/action_controller/assign_to_matcher.rb +10 -8
  19. data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +2 -4
  20. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +3 -4
  21. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +3 -4
  22. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +6 -6
  23. data/lib/shoulda/matchers/action_controller/respond_with_content_type_matcher.rb +5 -2
  24. data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +2 -2
  25. data/lib/shoulda/matchers/action_controller/route_matcher.rb +12 -12
  26. data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +3 -4
  27. data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +10 -11
  28. data/lib/shoulda/matchers/action_controller/strong_parameters_matcher.rb +121 -0
  29. data/lib/shoulda/matchers/action_mailer/have_sent_email_matcher.rb +7 -4
  30. data/lib/shoulda/matchers/active_model.rb +1 -1
  31. data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +8 -8
  32. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +5 -4
  33. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +3 -3
  34. data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +2 -2
  35. data/lib/shoulda/matchers/active_model/exception_message_finder.rb +0 -1
  36. data/lib/shoulda/matchers/active_model/helpers.rb +16 -7
  37. data/lib/shoulda/matchers/active_model/only_integer_matcher.rb +3 -3
  38. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +8 -6
  39. data/lib/shoulda/matchers/active_model/validate_format_of_matcher.rb +19 -10
  40. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +4 -4
  41. data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +19 -21
  42. data/lib/shoulda/matchers/active_model/validation_matcher.rb +7 -7
  43. data/lib/shoulda/matchers/active_model/validation_message_finder.rb +1 -1
  44. data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +5 -5
  45. data/lib/shoulda/matchers/active_record/association_matcher.rb +3 -3
  46. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +11 -7
  47. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +2 -2
  48. data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +5 -5
  49. data/lib/shoulda/matchers/active_record/query_the_database_matcher.rb +5 -2
  50. data/lib/shoulda/matchers/active_record/serialize_matcher.rb +3 -3
  51. data/lib/shoulda/matchers/assertion_error.rb +4 -1
  52. data/lib/shoulda/matchers/independent/delegate_matcher.rb +17 -7
  53. data/lib/shoulda/matchers/integrations/rspec.rb +19 -33
  54. data/lib/shoulda/matchers/version.rb +1 -1
  55. data/shoulda-matchers.gemspec +6 -4
  56. data/spec/shoulda/matchers/action_controller/assign_to_matcher_spec.rb +66 -0
  57. data/spec/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +22 -0
  58. data/spec/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +42 -0
  59. data/spec/shoulda/matchers/action_controller/render_template_matcher_spec.rb +78 -0
  60. data/spec/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +58 -0
  61. data/spec/shoulda/matchers/action_controller/respond_with_content_type_matcher_spec.rb +31 -0
  62. data/spec/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +31 -0
  63. data/spec/shoulda/matchers/action_controller/route_matcher_spec.rb +65 -0
  64. data/spec/shoulda/matchers/action_controller/set_session_matcher_spec.rb +51 -0
  65. data/spec/shoulda/matchers/action_controller/set_the_flash_matcher_spec.rb +153 -0
  66. data/spec/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +142 -0
  67. data/spec/shoulda/matchers/action_mailer/have_sent_email_spec.rb +324 -0
  68. data/spec/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +111 -0
  69. data/spec/shoulda/matchers/active_model/allow_value_matcher_spec.rb +124 -0
  70. data/spec/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +43 -0
  71. data/spec/shoulda/matchers/active_model/ensure_exclusion_of_matcher_spec.rb +74 -0
  72. data/spec/shoulda/matchers/active_model/ensure_inclusion_of_matcher_spec.rb +171 -0
  73. data/spec/shoulda/matchers/active_model/ensure_length_of_matcher_spec.rb +113 -0
  74. data/spec/shoulda/{active_model → matchers/active_model}/exception_message_finder_spec.rb +2 -2
  75. data/spec/shoulda/matchers/active_model/helpers_spec.rb +158 -0
  76. data/spec/shoulda/matchers/active_model/only_integer_matcher_spec.rb +52 -0
  77. data/spec/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +41 -0
  78. data/spec/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +41 -0
  79. data/spec/shoulda/matchers/active_model/validate_format_of_matcher_spec.rb +75 -0
  80. data/spec/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +73 -0
  81. data/spec/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +127 -0
  82. data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +175 -0
  83. data/spec/shoulda/{active_model → matchers/active_model}/validation_message_finder_spec.rb +0 -1
  84. data/spec/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb +106 -0
  85. data/spec/shoulda/matchers/active_record/association_matcher_spec.rb +534 -0
  86. data/spec/shoulda/matchers/active_record/have_db_column_matcher_spec.rb +111 -0
  87. data/spec/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +78 -0
  88. data/spec/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb +41 -0
  89. data/spec/shoulda/{active_record → matchers/active_record}/query_the_database_matcher_spec.rb +10 -10
  90. data/spec/shoulda/matchers/active_record/serialize_matcher_spec.rb +86 -0
  91. data/spec/shoulda/{independent → matchers/independent}/delegate_matcher_spec.rb +55 -34
  92. data/spec/spec_helper.rb +1 -2
  93. data/spec/support/active_model_versions.rb +4 -0
  94. data/spec/support/activemodel_helpers.rb +19 -0
  95. data/spec/support/controller_builder.rb +38 -12
  96. data/spec/support/model_builder.rb +8 -2
  97. metadata +106 -98
  98. data/spec/fixtures/addresses.yml +0 -3
  99. data/spec/fixtures/friendships.yml +0 -0
  100. data/spec/fixtures/posts.yml +0 -5
  101. data/spec/fixtures/products.yml +0 -0
  102. data/spec/fixtures/taggings.yml +0 -0
  103. data/spec/fixtures/tags.yml +0 -9
  104. data/spec/fixtures/users.yml +0 -6
  105. data/spec/shoulda/action_controller/assign_to_matcher_spec.rb +0 -63
  106. data/spec/shoulda/action_controller/filter_param_matcher_spec.rb +0 -20
  107. data/spec/shoulda/action_controller/redirect_to_matcher_spec.rb +0 -40
  108. data/spec/shoulda/action_controller/render_template_matcher_spec.rb +0 -69
  109. data/spec/shoulda/action_controller/render_with_layout_matcher_spec.rb +0 -55
  110. data/spec/shoulda/action_controller/respond_with_content_type_matcher_spec.rb +0 -28
  111. data/spec/shoulda/action_controller/respond_with_matcher_spec.rb +0 -83
  112. data/spec/shoulda/action_controller/route_matcher_spec.rb +0 -65
  113. data/spec/shoulda/action_controller/set_session_matcher_spec.rb +0 -46
  114. data/spec/shoulda/action_controller/set_the_flash_matcher_spec.rb +0 -130
  115. data/spec/shoulda/action_mailer/have_sent_email_spec.rb +0 -333
  116. data/spec/shoulda/active_model/allow_mass_assignment_of_matcher_spec.rb +0 -115
  117. data/spec/shoulda/active_model/allow_value_matcher_spec.rb +0 -131
  118. data/spec/shoulda/active_model/disallow_value_matcher_spec.rb +0 -65
  119. data/spec/shoulda/active_model/ensure_exclusion_of_matcher_spec.rb +0 -79
  120. data/spec/shoulda/active_model/ensure_inclusion_of_matcher_spec.rb +0 -181
  121. data/spec/shoulda/active_model/ensure_length_of_matcher_spec.rb +0 -138
  122. data/spec/shoulda/active_model/helpers_spec.rb +0 -129
  123. data/spec/shoulda/active_model/only_integer_matcher_spec.rb +0 -69
  124. data/spec/shoulda/active_model/validate_acceptance_of_matcher_spec.rb +0 -43
  125. data/spec/shoulda/active_model/validate_confirmation_of_matcher_spec.rb +0 -48
  126. data/spec/shoulda/active_model/validate_format_of_matcher_spec.rb +0 -79
  127. data/spec/shoulda/active_model/validate_numericality_of_matcher_spec.rb +0 -112
  128. data/spec/shoulda/active_model/validate_presence_of_matcher_spec.rb +0 -135
  129. data/spec/shoulda/active_model/validate_uniqueness_of_matcher_spec.rb +0 -154
  130. data/spec/shoulda/active_record/accept_nested_attributes_for_matcher_spec.rb +0 -84
  131. data/spec/shoulda/active_record/association_matcher_spec.rb +0 -642
  132. data/spec/shoulda/active_record/have_db_column_matcher_spec.rb +0 -185
  133. data/spec/shoulda/active_record/have_db_index_matcher_spec.rb +0 -105
  134. data/spec/shoulda/active_record/have_readonly_attributes_matcher_spec.rb +0 -46
  135. data/spec/shoulda/active_record/serialize_matcher_spec.rb +0 -81
@@ -0,0 +1,534 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do
4
+ context 'belong_to' do
5
+ it 'accepts a good association with the default foreign key' do
6
+ belonging_to_parent.should belong_to(:parent)
7
+ end
8
+
9
+ it 'rejects a nonexistent association' do
10
+ define_model(:child).new.should_not belong_to(:parent)
11
+ end
12
+
13
+ it 'rejects an association of the wrong type' do
14
+ define_model :parent, :child_id => :integer
15
+ define_model(:child) { has_one :parent }.new.should_not belong_to(:parent)
16
+ end
17
+
18
+ it 'rejects an association that has a nonexistent foreign key' do
19
+ define_model :parent
20
+ define_model(:child) { belongs_to :parent }.new.should_not belong_to(:parent)
21
+ end
22
+
23
+ it 'accepts an association with an existing custom foreign key' do
24
+ define_model :parent
25
+ define_model :child, :guardian_id => :integer do
26
+ belongs_to :parent, :foreign_key => 'guardian_id'
27
+ end
28
+
29
+ Child.new.should belong_to(:parent)
30
+ end
31
+
32
+ it 'accepts a polymorphic association' do
33
+ define_model :child, :parent_type => :string, :parent_id => :integer do
34
+ belongs_to :parent, :polymorphic => true
35
+ end
36
+
37
+ Child.new.should belong_to(:parent)
38
+ end
39
+
40
+ it 'accepts an association with a valid :dependent option' do
41
+ belonging_to_parent(:dependent => :destroy).
42
+ should belong_to(:parent).dependent(:destroy)
43
+ end
44
+
45
+ it 'rejects an association with a bad :dependent option' do
46
+ belonging_to_parent.should_not belong_to(:parent).dependent(:destroy)
47
+ end
48
+
49
+ it 'accepts an association with a valid :conditions option' do
50
+ define_model :parent, :adopter => :boolean
51
+ define_model :child, :parent_id => :integer do
52
+ belongs_to :parent, :conditions => { :adopter => true }
53
+ end
54
+
55
+ Child.new.should belong_to(:parent).conditions(:adopter => true)
56
+ end
57
+
58
+ it 'rejects an association with a bad :conditions option' do
59
+ define_model :parent, :adopter => :boolean
60
+ define_model :child, :parent_id => :integer do
61
+ belongs_to :parent
62
+ end
63
+
64
+ Child.new.should_not belong_to(:parent).conditions(:adopter => true)
65
+ end
66
+
67
+ it 'accepts an association with a valid :class_name option' do
68
+ belonging_to_parent(:class_name => 'TreeParent').
69
+ should belong_to(:parent).class_name('TreeParent')
70
+ end
71
+
72
+ it 'rejects an association with a bad :class_name option' do
73
+ belonging_to_parent(:class_name => 'TreeParent').
74
+ should_not belong_to(:parent).class_name('TreeChild')
75
+ end
76
+
77
+ context 'validate' do
78
+ [false, true].each do |validate_value|
79
+ context 'when the model has :validate => #{validate_value}' do
80
+ it 'accepts a matching validate option' do
81
+ belonging_to_parent(:validate => validate_value).
82
+ should belong_to(:parent).validate(validate_value)
83
+ end
84
+
85
+ it 'rejects a non-matching validate option' do
86
+ belonging_to_parent(:validate => validate_value).
87
+ should_not belong_to(:parent).validate(!validate_value)
88
+ end
89
+
90
+ it 'defaults to validate(true)' do
91
+ if validate_value
92
+ belonging_to_parent(:validate => validate_value).
93
+ should belong_to(:parent).validate
94
+ else
95
+ belonging_to_parent(:validate => validate_value).
96
+ should_not belong_to(:parent).validate
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ context 'an association without a :validate option' do
104
+ it 'accepts validate(false)' do
105
+ belonging_to_parent.should belong_to(:parent).validate(false)
106
+ end
107
+
108
+ it 'rejects validate(true)' do
109
+ belonging_to_parent.should_not belong_to(:parent).validate(true)
110
+ end
111
+
112
+ it 'rejects validate()' do
113
+ belonging_to_parent.should_not belong_to(:parent).validate
114
+ end
115
+ end
116
+
117
+ def belonging_to_parent(options = {})
118
+ define_model :parent
119
+ define_model :child, :parent_id => :integer do
120
+ belongs_to :parent, options
121
+ end.new
122
+ end
123
+ end
124
+
125
+ context 'have_many' do
126
+ it 'accepts a valid association without any options' do
127
+ having_many_children.should have_many(:children)
128
+ end
129
+
130
+ it 'accepts a valid association with a :through option' do
131
+ define_model :child
132
+ define_model :conception, :child_id => :integer,
133
+ :parent_id => :integer do
134
+ belongs_to :child
135
+ end
136
+ define_model :parent do
137
+ has_many :conceptions
138
+ has_many :children, :through => :conceptions
139
+ end
140
+ Parent.new.should have_many(:children)
141
+ end
142
+
143
+ it 'accepts a valid association with an :as option' do
144
+ define_model :child, :guardian_type => :string, :guardian_id => :integer
145
+ define_model :parent do
146
+ has_many :children, :as => :guardian
147
+ end
148
+
149
+ Parent.new.should have_many(:children)
150
+ end
151
+
152
+ it 'rejects an association that has a nonexistent foreign key' do
153
+ define_model :child
154
+ define_model :parent do
155
+ has_many :children
156
+ end
157
+
158
+ Parent.new.should_not have_many(:children)
159
+ end
160
+
161
+ it 'rejects an association with a bad :as option' do
162
+ define_model :child, :caretaker_type => :string,
163
+ :caretaker_id => :integer
164
+ define_model :parent do
165
+ has_many :children, :as => :guardian
166
+ end
167
+
168
+ Parent.new.should_not have_many(:children)
169
+ end
170
+
171
+ it 'rejects an association that has a bad :through option' do
172
+ matcher = have_many(:children).through(:conceptions)
173
+
174
+ matcher.matches?(having_many_children).should be_false
175
+
176
+ matcher.failure_message_for_should.should =~ /does not have any relationship to conceptions/
177
+ end
178
+
179
+ it 'rejects an association that has the wrong :through option' do
180
+ define_model :child
181
+ define_model :conception, :child_id => :integer,
182
+ :parent_id => :integer do
183
+ belongs_to :child
184
+ end
185
+ define_model :parent do
186
+ has_many :conceptions
187
+ has_many :relationships
188
+ has_many :children, :through => :conceptions
189
+ end
190
+
191
+ matcher = have_many(:children).through(:relationships)
192
+ matcher.matches?(Parent.new).should be_false
193
+ matcher.failure_message_for_should.should =~ /through relationships, but got it through conceptions/
194
+ end
195
+
196
+ it 'accepts an association with a valid :dependent option' do
197
+ having_many_children(:dependent => :destroy).
198
+ should have_many(:children).dependent(:destroy)
199
+ end
200
+
201
+ it 'rejects an association with a bad :dependent option' do
202
+ having_many_children.should_not have_many(:children).dependent(:destroy)
203
+ end
204
+
205
+ it 'accepts an association with a valid :order option' do
206
+ having_many_children(:order => :id).
207
+ should have_many(:children).order(:id)
208
+ end
209
+
210
+ it 'rejects an association with a bad :order option' do
211
+ having_many_children.should_not have_many(:children).order(:id)
212
+ end
213
+
214
+ it 'accepts an association with a valid :conditions option' do
215
+ define_model :child, :parent_id => :integer, :adopted => :boolean
216
+ define_model :parent do
217
+ has_many :children, :conditions => { :adopted => true }
218
+ end
219
+
220
+ Parent.new.should have_many(:children).conditions(:adopted => true)
221
+ end
222
+
223
+ it 'rejects an association with a bad :conditions option' do
224
+ define_model :child, :parent_id => :integer, :adopted => :boolean
225
+ define_model :parent do
226
+ has_many :children
227
+ end
228
+
229
+ Parent.new.should_not have_many(:children).conditions(:adopted => true)
230
+ end
231
+
232
+ it 'accepts an association with a valid :class_name option' do
233
+ define_model :node, :parent_id => :integer
234
+ define_model :parent do
235
+ has_many :children, :class_name => 'Node'
236
+ end
237
+
238
+ Parent.new.should have_many(:children).class_name('Node')
239
+ end
240
+
241
+ it 'rejects an association with a bad :class_name option' do
242
+ having_many_children.should_not have_many(:children).class_name('Node')
243
+ end
244
+
245
+ context 'validate' do
246
+ it 'accepts when the :validate option matches' do
247
+ having_many_children(:validate => false).should have_many(:children).validate(false)
248
+ end
249
+
250
+ it 'rejects when the :validate option does not match' do
251
+ having_many_children(:validate => true).should_not have_many(:children).validate(false)
252
+ end
253
+
254
+ it 'assumes validate() means validate(true)' do
255
+ having_many_children(:validate => false).should_not have_many(:children).validate
256
+ end
257
+
258
+ it 'matches validate(false) to having no validate option specified' do
259
+ having_many_children.should have_many(:children).validate(false)
260
+ end
261
+ end
262
+
263
+ it 'accepts an association with a nonstandard reverse foreign key, using :inverse_of' do
264
+ define_model :child, :ancestor_id => :integer do
265
+ belongs_to :ancestor, :inverse_of => :children, :class_name => :Parent
266
+ end
267
+ define_model :parent do
268
+ has_many :children, :inverse_of => :ancestor
269
+ end
270
+
271
+ Parent.new.should have_many(:children)
272
+ end
273
+
274
+ it 'rejects an association with a nonstandard reverse foreign key, if :inverse_of is not correct' do
275
+ define_model :child, :mother_id => :integer do
276
+ belongs_to :mother, :inverse_of => :children, :class_name => :Parent
277
+ end
278
+ define_model :parent do
279
+ has_many :children, :inverse_of => :ancestor
280
+ end
281
+
282
+ Parent.new.should_not have_many(:children)
283
+ end
284
+
285
+ def having_many_children(options = {})
286
+ define_model :child, :parent_id => :integer
287
+ define_model :parent do
288
+ has_many :children, options
289
+ end.new
290
+ end
291
+ end
292
+
293
+ context 'have_one' do
294
+ it 'accepts a valid association without any options' do
295
+ having_one_detail.should have_one(:detail)
296
+ end
297
+
298
+ it 'accepts a valid association with an :as option' do
299
+ define_model :detail, :detailable_id => :integer,
300
+ :detailable_type => :string
301
+ define_model :person do
302
+ has_one :detail, :as => :detailable
303
+ end
304
+
305
+ Person.new.should have_one(:detail)
306
+ end
307
+
308
+ it 'rejects an association that has a nonexistent foreign key' do
309
+ define_model :detail
310
+ define_model :person do
311
+ has_one :detail
312
+ end
313
+
314
+ Person.new.should_not have_one(:detail)
315
+ end
316
+
317
+ it 'accepts an association with an existing custom foreign key' do
318
+ define_model :detail, :detailed_person_id => :integer
319
+ define_model :person do
320
+ has_one :detail, :foreign_key => :detailed_person_id
321
+ end
322
+ Person.new.should have_one(:detail).with_foreign_key(:detailed_person_id)
323
+ end
324
+
325
+ it 'rejects an association with a bad :as option' do
326
+ define_model :detail, :detailable_id => :integer,
327
+ :detailable_type => :string
328
+ define_model :person do
329
+ has_one :detail, :as => :describable
330
+ end
331
+
332
+ Person.new.should_not have_one(:detail)
333
+ end
334
+
335
+ it 'accepts an association with a valid :dependent option' do
336
+ having_one_detail(:dependent => :destroy).
337
+ should have_one(:detail).dependent(:destroy)
338
+ end
339
+
340
+ it 'rejects an association with a bad :dependent option' do
341
+ having_one_detail.should_not have_one(:detail).dependent(:destroy)
342
+ end
343
+
344
+ it 'accepts an association with a valid :order option' do
345
+ having_one_detail(:order => :id).should have_one(:detail).order(:id)
346
+ end
347
+
348
+ it 'rejects an association with a bad :order option' do
349
+ having_one_detail.should_not have_one(:detail).order(:id)
350
+ end
351
+
352
+ it 'accepts an association with a valid :conditions option' do
353
+ define_model :detail, :person_id => :integer, :disabled => :boolean
354
+ define_model :person do
355
+ has_one :detail, :conditions => { :disabled => true}
356
+ end
357
+
358
+ Person.new.should have_one(:detail).conditions(:disabled => true)
359
+ end
360
+
361
+ it 'rejects an association with a bad :conditions option' do
362
+ define_model :detail, :person_id => :integer, :disabled => :boolean
363
+ define_model :person do
364
+ has_one :detail
365
+ end
366
+
367
+ Person.new.should_not have_one(:detail).conditions(:disabled => true)
368
+ end
369
+
370
+ it 'accepts an association with a valid :class_name option' do
371
+ define_model :person_detail, :person_id => :integer
372
+ define_model :person do
373
+ has_one :detail, :class_name => 'PersonDetail'
374
+ end
375
+
376
+ Person.new.should have_one(:detail).class_name('PersonDetail')
377
+ end
378
+
379
+ it 'rejects an association with a bad :class_name option' do
380
+ having_one_detail.should_not have_one(:detail).class_name('NotSet')
381
+ end
382
+
383
+ it 'accepts an association with a through' do
384
+ define_model :detail
385
+
386
+ define_model :account do
387
+ has_one :detail
388
+ end
389
+
390
+ define_model :person do
391
+ has_one :account
392
+ has_one :detail, :through => :account
393
+ end
394
+
395
+ Person.new.should have_one(:detail).through(:account)
396
+ end
397
+
398
+ it 'rejects an association with a bad through' do
399
+ having_one_detail.should_not have_one(:detail).through(:account)
400
+ end
401
+
402
+ context 'validate' do
403
+ it 'accepts when the :validate option matches' do
404
+ having_one_detail(:validate => false).
405
+ should have_one(:detail).validate(false)
406
+ end
407
+
408
+ it 'rejects when the :validate option does not match' do
409
+ having_one_detail(:validate => true).
410
+ should_not have_one(:detail).validate(false)
411
+ end
412
+
413
+ it 'assumes validate() means validate(true)' do
414
+ having_one_detail(:validate => false).
415
+ should_not have_one(:detail).validate
416
+ end
417
+
418
+ it 'matches validate(false) to having no validate option specified' do
419
+ having_one_detail.should have_one(:detail).validate(false)
420
+ end
421
+ end
422
+
423
+ def having_one_detail(options = {})
424
+ define_model :detail, :person_id => :integer
425
+ define_model :person do
426
+ has_one :detail, options
427
+ end.new
428
+ end
429
+ end
430
+
431
+ context 'have_and_belong_to_many' do
432
+ it 'accepts a valid association' do
433
+ having_and_belonging_to_many_relatives.
434
+ should have_and_belong_to_many(:relatives)
435
+ end
436
+
437
+ it 'rejects a nonexistent association' do
438
+ define_model :relatives
439
+ define_model :person
440
+ define_model :people_relative, :id => false, :person_id => :integer,
441
+ :relative_id => :integer
442
+
443
+ Person.new.should_not have_and_belong_to_many(:relatives)
444
+ end
445
+
446
+ it 'rejects an association with a nonexistent join table' do
447
+ define_model :relatives
448
+ define_model :person do
449
+ has_and_belongs_to_many :relatives
450
+ end
451
+
452
+ Person.new.should_not have_and_belong_to_many(:relatives)
453
+ end
454
+
455
+ it 'rejects an association of the wrong type' do
456
+ define_model :relatives, :person_id => :integer
457
+ define_model :person do
458
+ has_many :relatives
459
+ end
460
+
461
+ Person.new.should_not have_and_belong_to_many(:relatives)
462
+ end
463
+
464
+ it 'accepts an association with a valid :conditions option' do
465
+ define_model :relatives, :adopted => :boolean
466
+ define_model :person do
467
+ has_and_belongs_to_many :relatives, :conditions => { :adopted => true }
468
+ end
469
+ define_model :people_relative, :id => false, :person_id => :integer,
470
+ :relative_id => :integer
471
+
472
+ Person.new.should have_and_belong_to_many(:relatives).conditions(:adopted => true)
473
+ end
474
+
475
+ it 'rejects an association with a bad :conditions option' do
476
+ define_model :relatives, :adopted => :boolean
477
+ define_model :person do
478
+ has_and_belongs_to_many :relatives
479
+ end
480
+ define_model :people_relative, :id => false, :person_id => :integer,
481
+ :relative_id => :integer
482
+
483
+ Person.new.should_not have_and_belong_to_many(:relatives).conditions(:adopted => true)
484
+ end
485
+
486
+ it 'accepts an association with a valid :class_name option' do
487
+ define_model :person_relatives, :adopted => :boolean
488
+ define_model :person do
489
+ has_and_belongs_to_many :relatives, :class_name => 'PersonRelatives'
490
+ end
491
+
492
+ define_model :people_person_relative, :person_id => :integer,
493
+ :person_relative_id => :integer
494
+
495
+ Person.new.should have_and_belong_to_many(:relatives).class_name('PersonRelatives')
496
+ end
497
+
498
+ it 'rejects an association with a bad :class_name option' do
499
+ having_and_belonging_to_many_relatives.
500
+ should_not have_and_belong_to_many(:relatives).class_name('PersonRelatives')
501
+ end
502
+
503
+ context 'validate' do
504
+ it 'accepts when the :validate option matches' do
505
+ having_and_belonging_to_many_relatives(:validate => false).
506
+ should have_and_belong_to_many(:relatives).validate(false)
507
+ end
508
+
509
+ it 'rejects when the :validate option does not match' do
510
+ having_and_belonging_to_many_relatives(:validate => true).
511
+ should have_and_belong_to_many(:relatives).validate(false)
512
+ end
513
+
514
+ it 'assumes validate() means validate(true)' do
515
+ having_and_belonging_to_many_relatives(:validate => false).
516
+ should_not have_and_belong_to_many(:relatives).validate
517
+ end
518
+
519
+ it 'matches validate(false) to having no validate option specified' do
520
+ having_and_belonging_to_many_relatives.
521
+ should have_and_belong_to_many(:relatives).validate(false)
522
+ end
523
+ end
524
+
525
+ def having_and_belonging_to_many_relatives(options = {})
526
+ define_model :relatives
527
+ define_model :people_relative, :id => false, :person_id => :integer,
528
+ :relative_id => :integer
529
+ define_model :person do
530
+ has_and_belongs_to_many :relatives
531
+ end.new
532
+ end
533
+ end
534
+ end