shoulda-matchers 1.4.2 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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