shoulda-matchers 2.6.1 → 2.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +9 -0
  4. data/.yardopts +8 -0
  5. data/Appraisals +82 -33
  6. data/Gemfile +18 -2
  7. data/Gemfile.lock +13 -1
  8. data/NEWS.md +27 -2
  9. data/README.md +83 -1329
  10. data/Rakefile +118 -1
  11. data/cucumber.yml +1 -0
  12. data/doc_config/gh-pages/index.html.erb +9 -0
  13. data/doc_config/yard/setup.rb +22 -0
  14. data/doc_config/yard/templates/default/fulldoc/html/css/bootstrap.css +5967 -0
  15. data/doc_config/yard/templates/default/fulldoc/html/css/full_list.css +12 -0
  16. data/doc_config/yard/templates/default/fulldoc/html/css/global.css +45 -0
  17. data/doc_config/yard/templates/default/fulldoc/html/css/solarized.css +69 -0
  18. data/doc_config/yard/templates/default/fulldoc/html/css/style.css +283 -0
  19. data/doc_config/yard/templates/default/fulldoc/html/full_list.erb +32 -0
  20. data/doc_config/yard/templates/default/fulldoc/html/full_list_class.erb +1 -0
  21. data/doc_config/yard/templates/default/fulldoc/html/full_list_method.erb +8 -0
  22. data/doc_config/yard/templates/default/fulldoc/html/js/app.js +298 -0
  23. data/doc_config/yard/templates/default/fulldoc/html/js/full_list.js +1 -0
  24. data/doc_config/yard/templates/default/fulldoc/html/js/jquery.stickyheaders.js +289 -0
  25. data/doc_config/yard/templates/default/fulldoc/html/js/underscore.min.js +6 -0
  26. data/doc_config/yard/templates/default/fulldoc/html/setup.rb +8 -0
  27. data/doc_config/yard/templates/default/layout/html/breadcrumb.erb +14 -0
  28. data/doc_config/yard/templates/default/layout/html/fonts.erb +1 -0
  29. data/doc_config/yard/templates/default/layout/html/layout.erb +23 -0
  30. data/doc_config/yard/templates/default/layout/html/search.erb +13 -0
  31. data/doc_config/yard/templates/default/layout/html/setup.rb +40 -0
  32. data/doc_config/yard/templates/default/method_details/html/source.erb +10 -0
  33. data/doc_config/yard/templates/default/module/html/box_info.erb +31 -0
  34. data/docs.watchr +5 -0
  35. data/features/rails_integration.feature +32 -0
  36. data/features/step_definitions/rails_steps.rb +55 -9
  37. data/features/support/env.rb +1 -0
  38. data/gemfiles/3.0.gemfile +13 -1
  39. data/gemfiles/3.0.gemfile.lock +13 -1
  40. data/gemfiles/3.1.gemfile +17 -2
  41. data/gemfiles/3.1.gemfile.lock +31 -2
  42. data/gemfiles/3.1_1.9.2.gemfile +33 -0
  43. data/gemfiles/3.1_1.9.2.gemfile.lock +203 -0
  44. data/gemfiles/3.2.gemfile +18 -2
  45. data/gemfiles/3.2.gemfile.lock +32 -2
  46. data/gemfiles/3.2_1.9.2.gemfile +32 -0
  47. data/gemfiles/3.2_1.9.2.gemfile.lock +200 -0
  48. data/gemfiles/4.0.0.gemfile +20 -1
  49. data/gemfiles/4.0.0.gemfile.lock +46 -2
  50. data/gemfiles/4.0.1.gemfile +20 -1
  51. data/gemfiles/4.0.1.gemfile.lock +46 -2
  52. data/gemfiles/4.1.gemfile +21 -2
  53. data/gemfiles/4.1.gemfile.lock +47 -4
  54. data/lib/shoulda/matchers/action_controller.rb +0 -20
  55. data/lib/shoulda/matchers/action_controller/callback_matcher.rb +119 -28
  56. data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +22 -6
  57. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +43 -10
  58. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +40 -13
  59. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +63 -11
  60. data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +34 -1
  61. data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +84 -15
  62. data/lib/shoulda/matchers/action_controller/route_matcher.rb +84 -28
  63. data/lib/shoulda/matchers/action_controller/route_params.rb +4 -3
  64. data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +76 -13
  65. data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +147 -13
  66. data/lib/shoulda/matchers/action_controller/strong_parameters_matcher.rb +148 -2
  67. data/lib/shoulda/matchers/active_model.rb +0 -25
  68. data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +66 -9
  69. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +161 -19
  70. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +5 -5
  71. data/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb +92 -13
  72. data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +218 -16
  73. data/lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb +198 -32
  74. data/lib/shoulda/matchers/active_model/errors.rb +5 -2
  75. data/lib/shoulda/matchers/active_model/exception_message_finder.rb +1 -1
  76. data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +29 -8
  77. data/lib/shoulda/matchers/active_model/helpers.rb +20 -8
  78. data/lib/shoulda/matchers/active_model/numericality_matchers.rb +9 -0
  79. data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +4 -6
  80. data/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +4 -3
  81. data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +3 -2
  82. data/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +4 -3
  83. data/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +4 -3
  84. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +52 -14
  85. data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +51 -13
  86. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +53 -7
  87. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +275 -19
  88. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +84 -14
  89. data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +170 -41
  90. data/lib/shoulda/matchers/active_model/validation_matcher.rb +20 -15
  91. data/lib/shoulda/matchers/active_model/validation_message_finder.rb +1 -2
  92. data/lib/shoulda/matchers/active_record.rb +1 -12
  93. data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +89 -15
  94. data/lib/shoulda/matchers/active_record/association_matcher.rb +726 -70
  95. data/lib/shoulda/matchers/active_record/association_matchers.rb +9 -0
  96. data/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +4 -3
  97. data/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +4 -3
  98. data/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +4 -3
  99. data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +2 -1
  100. data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +4 -3
  101. data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +4 -5
  102. data/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +4 -3
  103. data/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +4 -3
  104. data/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +4 -3
  105. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +79 -15
  106. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +64 -15
  107. data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +21 -7
  108. data/lib/shoulda/matchers/active_record/serialize_matcher.rb +85 -10
  109. data/lib/shoulda/matchers/assertion_error.rb +7 -1
  110. data/lib/shoulda/matchers/doublespeak.rb +2 -1
  111. data/lib/shoulda/matchers/doublespeak/double.rb +3 -1
  112. data/lib/shoulda/matchers/doublespeak/double_collection.rb +2 -1
  113. data/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +1 -0
  114. data/lib/shoulda/matchers/doublespeak/object_double.rb +2 -1
  115. data/lib/shoulda/matchers/doublespeak/proxy_implementation.rb +2 -1
  116. data/lib/shoulda/matchers/doublespeak/structs.rb +2 -0
  117. data/lib/shoulda/matchers/doublespeak/stub_implementation.rb +2 -1
  118. data/lib/shoulda/matchers/doublespeak/world.rb +3 -4
  119. data/lib/shoulda/matchers/error.rb +1 -0
  120. data/lib/shoulda/matchers/independent/delegate_matcher.rb +108 -20
  121. data/lib/shoulda/matchers/independent/delegate_matcher/stubbed_target.rb +4 -3
  122. data/lib/shoulda/matchers/integrations/nunit_test_case_detection.rb +3 -0
  123. data/lib/shoulda/matchers/rails_shim.rb +3 -2
  124. data/lib/shoulda/matchers/version.rb +2 -1
  125. data/lib/shoulda/matchers/warn.rb +1 -0
  126. data/script/SUPPORTED_VERSIONS +1 -0
  127. data/script/install_gems_in_all_appraisals +14 -0
  128. data/script/run_all_tests +14 -0
  129. data/shoulda-matchers.gemspec +0 -10
  130. data/spec/report_warnings.rb +7 -0
  131. data/spec/shoulda/matchers/action_controller/route_matcher_spec.rb +1 -1
  132. data/spec/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +9 -0
  133. data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +0 -36
  134. data/spec/shoulda/matchers/active_model/validation_message_finder_spec.rb +2 -2
  135. data/spec/shoulda/matchers/doublespeak/double_spec.rb +1 -1
  136. data/spec/shoulda/matchers/doublespeak/world_spec.rb +11 -29
  137. data/spec/shoulda/matchers/doublespeak_spec.rb +3 -3
  138. data/spec/spec_helper.rb +17 -0
  139. data/spec/support/class_builder.rb +4 -0
  140. data/spec/support/test_application.rb +1 -1
  141. data/spec/warnings_spy.rb +64 -0
  142. data/spec/warnings_spy/filesystem.rb +45 -0
  143. data/spec/warnings_spy/partitioner.rb +29 -0
  144. data/spec/warnings_spy/reader.rb +64 -0
  145. data/spec/warnings_spy/reporter.rb +87 -0
  146. metadata +49 -134
@@ -1,26 +1,100 @@
1
1
  module Shoulda
2
2
  module Matchers
3
3
  module ActiveRecord
4
- # Ensures that the model can accept nested attributes for the specified
5
- # association.
6
- #
7
- # Options:
8
- # * <tt>allow_destroy</tt> - Whether or not to allow destroy
9
- # * <tt>limit</tt> - Max number of nested attributes
10
- # * <tt>update_only</tt> - Only allow updates
11
- #
12
- # Example:
13
- # it { should accept_nested_attributes_for(:friends) }
14
- # it { should accept_nested_attributes_for(:friends).
15
- # allow_destroy(true).
16
- # limit(4) }
17
- # it { should accept_nested_attributes_for(:friends).
18
- # update_only(true) }
4
+ # The `accept_nested_attributes_for` matcher tests usage of the
5
+ # `accepts_nested_attributes_for` macro.
6
+ #
7
+ # class Car < ActiveRecord::Base
8
+ # accept_nested_attributes_for :doors
9
+ # end
10
+ #
11
+ # # RSpec
12
+ # describe Car do
13
+ # it { should accept_nested_attributes_for(:doors) }
14
+ # end
15
+ #
16
+ # # Test::Unit (using Shoulda)
17
+ # class CarTest < ActiveSupport::TestCase
18
+ # should accept_nested_attributes_for(:doors)
19
+ # end
20
+ #
21
+ # #### Qualifiers
22
+ #
23
+ # ##### allow_destroy
24
+ #
25
+ # Use `allow_destroy` to assert that the `:allow_destroy` option was
26
+ # specified.
27
+ #
28
+ # class Car < ActiveRecord::Base
29
+ # accept_nested_attributes_for :mirrors, allow_destroy: true
30
+ # end
31
+ #
32
+ # # RSpec
33
+ # describe Car do
34
+ # it do
35
+ # should accept_nested_attributes_for(:mirrors).
36
+ # allow_destroy(true)
37
+ # end
38
+ # end
39
+ #
40
+ # # Test::Unit
41
+ # class CarTest < ActiveSupport::TestCase
42
+ # should accept_nested_attributes_for(:mirrors).
43
+ # allow_destroy(true)
44
+ # end
45
+ #
46
+ # ##### limit
47
+ #
48
+ # Use `limit` to assert that the `:limit` option was specified.
49
+ #
50
+ # class Car < ActiveRecord::Base
51
+ # accept_nested_attributes_for :windows, limit: 3
52
+ # end
53
+ #
54
+ # # RSpec
55
+ # describe Car do
56
+ # it do
57
+ # should accept_nested_attributes_for(:windows).
58
+ # limit(3)
59
+ # end
60
+ # end
61
+ #
62
+ # # Test::Unit
63
+ # class CarTest < ActiveSupport::TestCase
64
+ # should accept_nested_attributes_for(:windows).
65
+ # limit(3)
66
+ # end
67
+ #
68
+ # ##### update_only
69
+ #
70
+ # Use `update_only` to assert that the `:update_only` option was
71
+ # specified.
72
+ #
73
+ # class Car < ActiveRecord::Base
74
+ # accept_nested_attributes_for :engine, update_only: true
75
+ # end
76
+ #
77
+ # # RSpec
78
+ # describe Car do
79
+ # it do
80
+ # should accept_nested_attributes_for(:engine).
81
+ # update_only(true)
82
+ # end
83
+ # end
84
+ #
85
+ # # Test::Unit
86
+ # class CarTest < ActiveSupport::TestCase
87
+ # should accept_nested_attributes_for(:engine).
88
+ # update_only(true)
89
+ # end
90
+ #
91
+ # @return [AcceptNestedAttributesForMatcher]
19
92
  #
20
93
  def accept_nested_attributes_for(name)
21
94
  AcceptNestedAttributesForMatcher.new(name)
22
95
  end
23
96
 
97
+ # @private
24
98
  class AcceptNestedAttributesForMatcher
25
99
  def initialize(name)
26
100
  @name = name
@@ -1,95 +1,751 @@
1
1
  require 'active_support/core_ext/module/delegation'
2
2
 
3
- module Shoulda # :nodoc:
3
+ module Shoulda
4
4
  module Matchers
5
- module ActiveRecord # :nodoc:
6
- # Ensure that the belongs_to relationship exists.
7
- #
8
- # Options:
9
- # * <tt>class_name</tt> - tests that the association resolves to class_name.
10
- # * <tt>validate</tt> - tests that the association makes use of the validate
11
- # option.
12
- # * <tt>touch</tt> - tests that the association makes use of the touch
13
- # option.
14
- #
15
- # Example:
16
- # it { should belong_to(:parent) }
17
- # it { should belong_to(:parent).touch }
18
- # it { should belong_to(:parent).validate }
19
- # it { should belong_to(:parent).class_name("ModelClassName") }
5
+ module ActiveRecord
6
+ # The `belong_to` matcher is used to ensure that a `belong_to` association
7
+ # exists on your model.
8
+ #
9
+ # class Person < ActiveRecord::Base
10
+ # belongs_to :organization
11
+ # end
12
+ #
13
+ # # RSpec
14
+ # describe Person do
15
+ # it { should belong_to(:organization) }
16
+ # end
17
+ #
18
+ # # Test::Unit
19
+ # class PersonTest < ActiveSupport::TestCase
20
+ # should belong_to(:organization)
21
+ # end
22
+ #
23
+ # Note that polymorphic associations are automatically detected and do not
24
+ # need any qualifiers:
25
+ #
26
+ # class Comment < ActiveRecord::Base
27
+ # belongs_to :commentable, polymorphic: true
28
+ # end
29
+ #
30
+ # # RSpec
31
+ # describe Comment do
32
+ # it { should belong_to(:commentable) }
33
+ # end
34
+ #
35
+ # # Test::Unit
36
+ # class CommentTest < ActiveSupport::TestCase
37
+ # should belong_to(:commentable)
38
+ # end
39
+ #
40
+ # #### Qualifiers
41
+ #
42
+ # ##### conditions
43
+ #
44
+ # Use `conditions` if your association is defined with a scope that sets
45
+ # the `where` clause.
46
+ #
47
+ # class Person < ActiveRecord::Base
48
+ # belongs_to :family, -> { where(everyone_is_perfect: false) }
49
+ # end
50
+ #
51
+ # # RSpec
52
+ # describe Person do
53
+ # it do
54
+ # should belong_to(:family).
55
+ # conditions(everyone_is_perfect: false)
56
+ # end
57
+ # end
58
+ #
59
+ # # Test::Unit
60
+ # class PersonTest < ActiveSupport::TestCase
61
+ # should belong_to(:family).
62
+ # conditions(everyone_is_perfect: false)
63
+ # end
64
+ #
65
+ # ##### order
66
+ #
67
+ # Use `order` if your association is defined with a scope that sets the
68
+ # `order` clause.
69
+ #
70
+ # class Person < ActiveRecord::Base
71
+ # belongs_to :previous_company, -> { order('hired_on desc') }
72
+ # end
73
+ #
74
+ # # RSpec
75
+ # describe Person do
76
+ # it { should belong_to(:previous_company).order('hired_on desc') }
77
+ # end
78
+ #
79
+ # # Test::Unit
80
+ # class PersonTest < ActiveSupport::TestCase
81
+ # should belong_to(:previous_company).order('hired_on desc')
82
+ # end
83
+ #
84
+ # ##### class_name
85
+ #
86
+ # Use `class_name` to test usage of the `:class_name` option. This
87
+ # asserts that the model you're referring to actually exists.
88
+ #
89
+ # class Person < ActiveRecord::Base
90
+ # belongs_to :ancient_city, class_name: 'City'
91
+ # end
92
+ #
93
+ # # RSpec
94
+ # describe Person do
95
+ # it { should belong_to(:ancient_city).class_name('City') }
96
+ # end
97
+ #
98
+ # # Test::Unit
99
+ # class PersonTest < ActiveSupport::TestCase
100
+ # should belong_to(:ancient_city).class_name('City')
101
+ # end
102
+ #
103
+ # ##### with_foreign_key
104
+ #
105
+ # Use `with_foreign_key` to test usage of the `:foreign_key` option.
106
+ #
107
+ # class Person < ActiveRecord::Base
108
+ # belongs_to :great_country, foreign_key: 'country_id'
109
+ # end
110
+ #
111
+ # # RSpec
112
+ # describe Person do
113
+ # it do
114
+ # should belong_to(:great_country).
115
+ # with_foreign_key('country_id')
116
+ # end
117
+ # end
118
+ #
119
+ # # Test::Unit
120
+ # class PersonTest < ActiveSupport::TestCase
121
+ # should belong_to(:great_country).
122
+ # with_foreign_key('country_id')
123
+ # end
124
+ #
125
+ # ##### dependent
126
+ #
127
+ # Use `dependent` to assert that the `:dependent` option was specified.
128
+ #
129
+ # class Person < ActiveRecord::Base
130
+ # belongs_to :world, dependent: :destroy
131
+ # end
132
+ #
133
+ # # RSpec
134
+ # describe Person do
135
+ # it { should belong_to(:world).dependent(:destroy) }
136
+ # end
137
+ #
138
+ # # Test::Unit
139
+ # class PersonTest < ActiveSupport::TestCase
140
+ # should belong_to(:world).dependent(:destroy)
141
+ # end
142
+ #
143
+ # ##### counter_cache
144
+ #
145
+ # Use `counter_cache` to assert that the `:counter_cache` option was
146
+ # specified.
147
+ #
148
+ # class Person < ActiveRecord::Base
149
+ # belongs_to :organization, counter_cache: true
150
+ # end
151
+ #
152
+ # # RSpec
153
+ # describe Person do
154
+ # it { should belong_to(:organization).counter_cache(true) }
155
+ # end
156
+ #
157
+ # # Test::Unit
158
+ # class PersonTest < ActiveSupport::TestCase
159
+ # should belong_to(:organization).counter_cache(true)
160
+ # end
161
+ #
162
+ # ##### touch
163
+ #
164
+ # Use `touch` to assert that the `:touch` option was specified.
165
+ #
166
+ # class Person < ActiveRecord::Base
167
+ # belongs_to :organization, touch: true
168
+ # end
169
+ #
170
+ # # RSpec
171
+ # describe Person do
172
+ # it { should belong_to(:organization).touch(true) }
173
+ # end
174
+ #
175
+ # # Test::Unit
176
+ # class PersonTest < ActiveSupport::TestCase
177
+ # should belong_to(:organization).touch(true)
178
+ # end
179
+ #
180
+ # #### autosave
181
+ #
182
+ # Use `autosave` to assert that the `:autosave` option was specified.
183
+ #
184
+ # class Account < ActiveRecord::Base
185
+ # belongs_to :bank, autosave: true
186
+ # end
187
+ #
188
+ # # RSpec
189
+ # describe Account do
190
+ # it { should belong_to(:bank).autosave(true) }
191
+ # end
192
+ #
193
+ # # Test::Unit
194
+ # class AccountTest < ActiveSupport::TestCase
195
+ # should belong_to(:bank).autosave(true)
196
+ # end
197
+ #
198
+ # ##### inverse_of
199
+ #
200
+ # Use `inverse_of` to assert that the `:inverse_of` option was specified.
201
+ #
202
+ # class Person < ActiveRecord::Base
203
+ # belongs_to :organization, inverse_of: :employees
204
+ # end
205
+ #
206
+ # # RSpec
207
+ # describe Person
208
+ # it { should belong_to(:organization).inverse_of(:employees) }
209
+ # end
210
+ #
211
+ # # Test::Unit
212
+ # class PersonTest < ActiveSupport::TestCase
213
+ # should belong_to(:organization).inverse_of(:employees)
214
+ # end
215
+ #
216
+ # @return [AssociationMatcher]
20
217
  #
21
218
  def belong_to(name)
22
219
  AssociationMatcher.new(:belongs_to, name)
23
220
  end
24
221
 
25
- # Ensures that the has_many relationship exists. Will also test that the
26
- # associated table has the required columns. Works with polymorphic
27
- # associations.
28
- #
29
- # Options:
30
- # * <tt>through</tt> - association name for <tt>has_many :through</tt>
31
- # * <tt>dependent</tt> - tests that the association makes use of the
32
- # dependent option.
33
- # * <tt>class_name</tt> - tests that the association resoves to class_name.
34
- # * <tt>autosave</tt> - tests that the association makes use of the
35
- # autosave option.
36
- # * <tt>validate</tt> - tests that the association makes use of the validate
37
- # option.
38
- #
39
- # Example:
40
- # it { should have_many(:friends) }
41
- # it { should have_many(:enemies).through(:friends) }
42
- # it { should have_many(:enemies).dependent(:destroy) }
43
- # it { should have_many(:friends).autosave }
44
- # it { should have_many(:friends).validate }
45
- # it { should have_many(:friends).class_name("Friend") }
222
+ # The `have_many` matcher is used to test that a `has_many` or `has_many
223
+ # :through` association exists on your model.
224
+ #
225
+ # class Person < ActiveRecord::Base
226
+ # has_many :friends
227
+ # end
228
+ #
229
+ # # RSpec
230
+ # describe Person do
231
+ # it { should have_many(:friends) }
232
+ # end
233
+ #
234
+ # # Test::Unit
235
+ # class PersonTest < ActiveSupport::TestCase
236
+ # should have_many(:friends)
237
+ # end
238
+ #
239
+ # #### Qualifiers
240
+ #
241
+ # ##### conditions
242
+ #
243
+ # Use `conditions` if your association is defined with a scope that sets
244
+ # the `where` clause.
245
+ #
246
+ # class Person < ActiveRecord::Base
247
+ # has_many :coins, -> { where(quality: 'mint') }
248
+ # end
249
+ #
250
+ # # RSpec
251
+ # describe Person do
252
+ # it { should have_many(:coins).conditions(quality: 'mint') }
253
+ # end
254
+ #
255
+ # # Test::Unit
256
+ # class PersonTest < ActiveSupport::TestCase
257
+ # should have_many(:coins).conditions(quality: 'mint')
258
+ # end
259
+ #
260
+ # ##### order
261
+ #
262
+ # Use `order` if your association is defined with a scope that sets the
263
+ # `order` clause.
264
+ #
265
+ # class Person < ActiveRecord::Base
266
+ # has_many :shirts, -> { order('color') }
267
+ # end
268
+ #
269
+ # # RSpec
270
+ # describe Person do
271
+ # it { should have_many(:shirts).order('color') }
272
+ # end
273
+ #
274
+ # # Test::Unit
275
+ # class PersonTest < ActiveSupport::TestCase
276
+ # should have_many(:shirts).order('color')
277
+ # end
278
+ #
279
+ # ##### class_name
280
+ #
281
+ # Use `class_name` to test usage of the `:class_name` option. This
282
+ # asserts that the model you're referring to actually exists.
283
+ #
284
+ # class Person < ActiveRecord::Base
285
+ # has_many :hopes, class_name: 'Dream'
286
+ # end
287
+ #
288
+ # # RSpec
289
+ # describe Person do
290
+ # it { should have_many(:hopes).class_name('Dream') }
291
+ # end
292
+ #
293
+ # # Test::Unit
294
+ # class PersonTest < ActiveSupport::TestCase
295
+ # should have_many(:hopes).class_name('Dream')
296
+ # end
297
+ #
298
+ # ##### with_foreign_key
299
+ #
300
+ # Use `with_foreign_key` to test usage of the `:foreign_key` option.
301
+ #
302
+ # class Person < ActiveRecord::Base
303
+ # has_many :worries, foreign_key: 'worrier_id'
304
+ # end
305
+ #
306
+ # # RSpec
307
+ # describe Person do
308
+ # it { should have_many(:worries).with_foreign_key('worrier_id') }
309
+ # end
310
+ #
311
+ # # Test::Unit
312
+ # class PersonTest < ActiveSupport::TestCase
313
+ # should have_many(:worries).with_foreign_key('worrier_id')
314
+ # end
315
+ #
316
+ # ##### dependent
317
+ #
318
+ # Use `dependent` to assert that the `:dependent` option was specified.
319
+ #
320
+ # class Person < ActiveRecord::Base
321
+ # has_many :secret_documents, dependent: :destroy
322
+ # end
323
+ #
324
+ # # RSpec
325
+ # describe Person do
326
+ # it { should have_many(:secret_documents).dependent(:destroy) }
327
+ # end
328
+ #
329
+ # # Test::Unit
330
+ # class PersonTest < ActiveSupport::TestCase
331
+ # should have_many(:secret_documents).dependent(:destroy)
332
+ # end
333
+ #
334
+ # ##### through
335
+ #
336
+ # Use `through` to test usage of the `:through` option. This asserts that
337
+ # the association you are going through actually exists.
338
+ #
339
+ # class Person < ActiveRecord::Base
340
+ # has_many :acquaintances, through: :friends
341
+ # end
342
+ #
343
+ # # RSpec
344
+ # describe Person do
345
+ # it { should have_many(:acquaintances).through(:friends) }
346
+ # end
347
+ #
348
+ # # Test::Unit
349
+ # class PersonTest < ActiveSupport::TestCase
350
+ # should have_many(:acquaintances).through(:friends)
351
+ # end
352
+ #
353
+ # ##### source
354
+ #
355
+ # Use `source` to test usage of the `:source` option on a `:through`
356
+ # association.
357
+ #
358
+ # class Person < ActiveRecord::Base
359
+ # has_many :job_offers, through: :friends, source: :opportunities
360
+ # end
361
+ #
362
+ # # RSpec
363
+ # describe Person do
364
+ # it do
365
+ # should have_many(:job_offers).
366
+ # through(:friends).
367
+ # source(:opportunities)
368
+ # end
369
+ # end
370
+ #
371
+ # # Test::Unit
372
+ # class PersonTest < ActiveSupport::TestCase
373
+ # should have_many(:job_offers).
374
+ # through(:friends).
375
+ # source(:opportunities)
376
+ # end
377
+ #
378
+ # ##### validate
379
+ #
380
+ # Use `validate` to assert that the `:validate` option was specified.
381
+ #
382
+ # class Person < ActiveRecord::Base
383
+ # has_many :ideas, validate: false
384
+ # end
385
+ #
386
+ # # RSpec
387
+ # describe Person do
388
+ # it { should have_many(:ideas).validate(false) }
389
+ # end
390
+ #
391
+ # # Test::Unit
392
+ # class PersonTest < ActiveSupport::TestCase
393
+ # should have_many(:ideas).validate(false)
394
+ # end
395
+ #
396
+ # #### autosave
397
+ #
398
+ # Use `autosave` to assert that the `:autosave` option was specified.
399
+ #
400
+ # class Player < ActiveRecord::Base
401
+ # has_many :games, autosave: true
402
+ # end
403
+ #
404
+ # # RSpec
405
+ # describe Player do
406
+ # it { should have_many(:games).autosave(true) }
407
+ # end
408
+ #
409
+ # # Test::Unit
410
+ # class PlayerTest < ActiveSupport::TestCase
411
+ # should have_many(:games).autosave(true)
412
+ # end
413
+ #
414
+ # @return [AssociationMatcher]
46
415
  #
47
416
  def have_many(name)
48
417
  AssociationMatcher.new(:has_many, name)
49
418
  end
50
419
 
51
- # Ensure that the has_one relationship exists. Will also test that the
52
- # associated table has the required columns. Works with polymorphic
53
- # associations.
54
- #
55
- # Options:
56
- # * <tt>dependent</tt> - tests that the association makes use of the
57
- # dependent option.
58
- # * <tt>class_name</tt> - tests that the association resolves to class_name.
59
- # * <tt>autosave</tt> - tests that the association makes use of the
60
- # autosave option.
61
- # * <tt>validate</tt> - tests that the association makes use of the validate
62
- # option.
63
- #
64
- # Example:
65
- # it { should have_one(:god) } # unless hindu
66
- # it { should have_one(:god).dependent }
67
- # it { should have_one(:god).autosave }
68
- # it { should have_one(:god).validate }
69
- # it { should have_one(:god).class_name("JHVH1") }
420
+ # The `have_one` matcher is used to test that a `has_one` or `has_one
421
+ # :through` association exists on your model.
422
+ #
423
+ # class Person < ActiveRecord::Base
424
+ # has_one :partner
425
+ # end
426
+ #
427
+ # # RSpec
428
+ # describe Person do
429
+ # it { should have_one(:partner) }
430
+ # end
431
+ #
432
+ # # Test::Unit
433
+ # class PersonTest < ActiveSupport::TestCase
434
+ # should have_one(:partner)
435
+ # end
436
+ #
437
+ # #### Qualifiers
438
+ #
439
+ # ##### conditions
440
+ #
441
+ # Use `conditions` if your association is defined with a scope that sets
442
+ # the `where` clause.
443
+ #
444
+ # class Person < ActiveRecord::Base
445
+ # has_one :pet, -> { where('weight < 80') }
446
+ # end
447
+ #
448
+ # # RSpec
449
+ # describe Person do
450
+ # it { should have_one(:pet).conditions('weight < 80') }
451
+ # end
452
+ #
453
+ # # Test::Unit
454
+ # class PersonTest < ActiveSupport::TestCase
455
+ # should have_one(:pet).conditions('weight < 80')
456
+ # end
457
+ #
458
+ # ##### order
459
+ #
460
+ # Use `order` if your association is defined with a scope that sets the
461
+ # `order` clause.
462
+ #
463
+ # class Person < ActiveRecord::Base
464
+ # has_one :focus, -> { order('priority desc') }
465
+ # end
466
+ #
467
+ # # RSpec
468
+ # describe Person do
469
+ # it { should have_one(:focus).order('priority desc') }
470
+ # end
471
+ #
472
+ # # Test::Unit
473
+ # class PersonTest < ActiveSupport::TestCase
474
+ # should have_one(:focus).order('priority desc')
475
+ # end
476
+ #
477
+ # ##### class_name
478
+ #
479
+ # Use `class_name` to test usage of the `:class_name` option. This
480
+ # asserts that the model you're referring to actually exists.
481
+ #
482
+ # class Person < ActiveRecord::Base
483
+ # has_one :chance, class_name: 'Opportunity'
484
+ # end
485
+ #
486
+ # # RSpec
487
+ # describe Person do
488
+ # it { should have_one(:chance).class_name('Opportunity') }
489
+ # end
490
+ #
491
+ # # Test::Unit
492
+ # class PersonTest < ActiveSupport::TestCase
493
+ # should have_one(:chance).class_name('Opportunity')
494
+ # end
495
+ #
496
+ # ##### dependent
497
+ #
498
+ # Use `dependent` to test that the `:dependent` option was specified.
499
+ #
500
+ # class Person < ActiveRecord::Base
501
+ # has_one :contract, dependent: :nullify
502
+ # end
503
+ #
504
+ # # RSpec
505
+ # describe Person do
506
+ # it { should have_one(:contract).dependent(:nullify) }
507
+ # end
508
+ #
509
+ # # Test::Unit
510
+ # class PersonTest < ActiveSupport::TestCase
511
+ # should have_one(:contract).dependent(:nullify)
512
+ # end
513
+ #
514
+ # ##### with_foreign_key
515
+ #
516
+ # Use `with_foreign_key` to test usage of the `:foreign_key` option.
517
+ #
518
+ # class Person < ActiveRecord::Base
519
+ # has_one :job, foreign_key: 'worker_id'
520
+ # end
521
+ #
522
+ # # RSpec
523
+ # describe Person do
524
+ # it { should have_one(:job).with_foreign_key('worker_id') }
525
+ # end
526
+ #
527
+ # # Test::Unit
528
+ # class PersonTest < ActiveSupport::TestCase
529
+ # should have_one(:job).with_foreign_key('worker_id')
530
+ # end
531
+ #
532
+ # ##### through
533
+ #
534
+ # Use `through` to test usage of the `:through` option. This asserts that
535
+ # the association you are going through actually exists.
536
+ #
537
+ # class Person < ActiveRecord::Base
538
+ # has_one :life, through: :partner
539
+ # end
540
+ #
541
+ # # RSpec
542
+ # describe Person do
543
+ # it { should have_one(:life).through(:partner) }
544
+ # end
545
+ #
546
+ # # Test::Unit
547
+ # class PersonTest < ActiveSupport::TestCase
548
+ # should have_one(:life).through(:partner)
549
+ # end
550
+ #
551
+ # ##### source
552
+ #
553
+ # Use `source` to test usage of the `:source` option on a `:through`
554
+ # association.
555
+ #
556
+ # class Person < ActiveRecord::Base
557
+ # has_one :car, through: :partner, source: :vehicle
558
+ # end
559
+ #
560
+ # # RSpec
561
+ # describe Person do
562
+ # it { should have_one(:car).through(:partner).source(:vehicle) }
563
+ # end
564
+ #
565
+ # # Test::Unit
566
+ # class PersonTest < ActiveSupport::TestCase
567
+ # should have_one(:car).through(:partner).source(:vehicle)
568
+ # end
569
+ #
570
+ # ##### validate
571
+ #
572
+ # Use `validate` to assert that the the `:validate` option was specified.
573
+ #
574
+ # class Person < ActiveRecord::Base
575
+ # has_one :parking_card, validate: false
576
+ # end
577
+ #
578
+ # # RSpec
579
+ # describe Person do
580
+ # it { should have_one(:parking_card).validate(false) }
581
+ # end
582
+ #
583
+ # # Test::Unit
584
+ # class PersonTest < ActiveSupport::TestCase
585
+ # should have_one(:parking_card).validate(false)
586
+ # end
587
+ #
588
+ # #### autosave
589
+ #
590
+ # Use `autosave` to assert that the `:autosave` option was specified.
591
+ #
592
+ # class Account < ActiveRecord::Base
593
+ # has_one :bank, autosave: true
594
+ # end
595
+ #
596
+ # # RSpec
597
+ # describe Account do
598
+ # it { should have_one(:bank).autosave(true) }
599
+ # end
600
+ #
601
+ # # Test::Unit
602
+ # class AccountTest < ActiveSupport::TestCase
603
+ # should have_one(:bank).autosave(true)
604
+ # end
605
+ #
606
+ # @return [AssociationMatcher]
70
607
  #
71
608
  def have_one(name)
72
609
  AssociationMatcher.new(:has_one, name)
73
610
  end
74
611
 
75
- # Ensures that the has_and_belongs_to_many relationship exists, and that
76
- # the join table is in place.
612
+ # The `have_and_belong_to_many` matcher is used to test that a
613
+ # `has_and_belongs_to_many` association exists on your model and that the
614
+ # join table exists in the database.
615
+ #
616
+ # class Person < ActiveRecord::Base
617
+ # has_and_belongs_to_many :awards
618
+ # end
619
+ #
620
+ # # RSpec
621
+ # describe Person do
622
+ # it { should have_and_belong_to_many(:awards) }
623
+ # end
624
+ #
625
+ # # Test::Unit
626
+ # class PersonTest < ActiveSupport::TestCase
627
+ # should have_and_belong_to_many(:awards)
628
+ # end
629
+ #
630
+ # #### Qualifiers
631
+ #
632
+ # ##### conditions
633
+ #
634
+ # Use `conditions` if your association is defined with a scope that sets
635
+ # the `where` clause.
636
+ #
637
+ # class Person < ActiveRecord::Base
638
+ # has_and_belongs_to_many :issues, -> { where(difficulty: 'hard') }
639
+ # end
640
+ #
641
+ # # RSpec
642
+ # describe Person do
643
+ # it do
644
+ # should have_and_belong_to_many(:issues).
645
+ # conditions(difficulty: 'hard')
646
+ # end
647
+ # end
648
+ #
649
+ # # Test::Unit
650
+ # class PersonTest < ActiveSupport::TestCase
651
+ # should have_and_belong_to_many(:issues).
652
+ # conditions(difficulty: 'hard')
653
+ # end
654
+ #
655
+ # ##### order
656
+ #
657
+ # Use `order` if your association is defined with a scope that sets the
658
+ # `order` clause.
659
+ #
660
+ # class Person < ActiveRecord::Base
661
+ # has_and_belongs_to_many :projects, -> { order('time_spent') }
662
+ # end
663
+ #
664
+ # # RSpec
665
+ # describe Person do
666
+ # it do
667
+ # should have_and_belong_to_many(:projects).
668
+ # order('time_spent')
669
+ # end
670
+ # end
671
+ #
672
+ # # Test::Unit
673
+ # class PersonTest < ActiveSupport::TestCase
674
+ # should have_and_belong_to_many(:projects).
675
+ # order('time_spent')
676
+ # end
677
+ #
678
+ # ##### class_name
679
+ #
680
+ # Use `class_name` to test usage of the `:class_name` option. This
681
+ # asserts that the model you're referring to actually exists.
682
+ #
683
+ # class Person < ActiveRecord::Base
684
+ # has_and_belongs_to_many :places_visited, class_name: 'City'
685
+ # end
686
+ #
687
+ # # RSpec
688
+ # describe Person do
689
+ # it do
690
+ # should have_and_belong_to_many(:places_visited).
691
+ # class_name('City')
692
+ # end
693
+ # end
694
+ #
695
+ # # Test::Unit
696
+ # class PersonTest < ActiveSupport::TestCase
697
+ # should have_and_belong_to_many(:places_visited).
698
+ # class_name('City')
699
+ # end
700
+ #
701
+ # ##### validate
702
+ #
703
+ # Use `validate` to test that the `:validate` option was specified.
704
+ #
705
+ # class Person < ActiveRecord::Base
706
+ # has_and_belongs_to_many :interviews, validate: false
707
+ # end
708
+ #
709
+ # # RSpec
710
+ # describe Person do
711
+ # it do
712
+ # should have_and_belong_to_many(:interviews).
713
+ # validate(false)
714
+ # end
715
+ # end
716
+ #
717
+ # # Test::Unit
718
+ # class PersonTest < ActiveSupport::TestCase
719
+ # should have_and_belong_to_many(:interviews).
720
+ # validate(false)
721
+ # end
722
+ #
723
+ # #### autosave
724
+ #
725
+ # Use `autosave` to assert that the `:autosave` option was specified.
726
+ #
727
+ # class Publisher < ActiveRecord::Base
728
+ # has_and_belongs_to_many :advertisers, autosave: true
729
+ # end
730
+ #
731
+ # # RSpec
732
+ # describe Publisher do
733
+ # it { should have_and_belong_to_many(:advertisers).autosave(true) }
734
+ # end
77
735
  #
78
- # Options:
79
- # * <tt>class_name</tt> - tests that the association resolves to class_name.
80
- # * <tt>validate</tt> - tests that the association makes use of the validate
81
- # option.
736
+ # # Test::Unit
737
+ # class AccountTest < ActiveSupport::TestCase
738
+ # should have_and_belong_to_many(:advertisers).autosave(true)
739
+ # end
82
740
  #
83
- # Example:
84
- # it { should have_and_belong_to_many(:posts) }
85
- # it { should have_and_belong_to_many(:posts).validate }
86
- # it { should have_and_belong_to_many(:posts).class_name("Post") }
741
+ # @return [AssociationMatcher]
87
742
  #
88
743
  def have_and_belong_to_many(name)
89
744
  AssociationMatcher.new(:has_and_belongs_to_many, name)
90
745
  end
91
746
 
92
- class AssociationMatcher # :nodoc:
747
+ # @private
748
+ class AssociationMatcher
93
749
  delegate :reflection, :model_class, :associated_class, :through?,
94
750
  :join_table, :polymorphic?, to: :reflector
95
751
 
@@ -199,7 +855,7 @@ module Shoulda # :nodoc:
199
855
  submatchers_match?
200
856
  end
201
857
 
202
- private
858
+ protected
203
859
 
204
860
  attr_reader :submatchers, :missing, :subject, :macro, :name, :options
205
861
 
@@ -237,8 +893,8 @@ module Shoulda # :nodoc:
237
893
  end
238
894
 
239
895
  def failing_submatchers
240
- @failing_submatchers ||= submatchers.select do |matcher|
241
- !matcher.matches?(subject)
896
+ @failing_submatchers ||= submatchers.reject do |matcher|
897
+ matcher.matches?(subject)
242
898
  end
243
899
  end
244
900