mcmire-shoulda-matchers 2.5.0 → 2.6.1.docs.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +9 -0
- data/.yardopts +2 -1
- data/Appraisals +62 -22
- data/Gemfile +1 -1
- data/Gemfile.lock +3 -3
- data/NEWS.md +87 -4
- data/README.md +2 -2
- data/Rakefile +18 -0
- data/features/activemodel_integration.feature +15 -0
- data/features/rails_integration.feature +1 -1
- data/features/step_definitions/activemodel_steps.rb +21 -0
- data/features/step_definitions/rails_steps.rb +5 -4
- data/gemfiles/3.0.gemfile +6 -3
- data/gemfiles/3.0.gemfile.lock +14 -4
- data/gemfiles/3.1.gemfile +10 -4
- data/gemfiles/3.1.gemfile.lock +32 -5
- data/gemfiles/3.1_1.9.2.gemfile +21 -0
- data/gemfiles/3.1_1.9.2.gemfile.lock +191 -0
- data/gemfiles/3.2.gemfile +9 -4
- data/gemfiles/3.2.gemfile.lock +28 -5
- data/gemfiles/4.0.0.gemfile +11 -3
- data/gemfiles/4.0.0.gemfile.lock +42 -5
- data/gemfiles/4.0.1.gemfile +11 -3
- data/gemfiles/4.0.1.gemfile.lock +42 -5
- data/gemfiles/4.1.gemfile +37 -0
- data/gemfiles/4.1.gemfile.lock +216 -0
- data/lib/shoulda/matchers/action_controller/callback_matcher.rb +202 -0
- data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +1 -1
- data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +2 -1
- data/lib/shoulda/matchers/action_controller/strong_parameters_matcher.rb +165 -0
- data/lib/shoulda/matchers/action_controller.rb +2 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +26 -4
- data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +6 -0
- data/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb +2 -0
- data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +60 -18
- data/lib/shoulda/matchers/active_model/errors.rb +43 -1
- data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +14 -3
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +2 -1
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +100 -45
- data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +38 -5
- data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +27 -20
- data/lib/shoulda/matchers/active_record/association_matcher.rb +12 -2
- data/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +41 -0
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +24 -1
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +1 -1
- data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record.rb +1 -0
- data/lib/shoulda/matchers/assertion_error.rb +8 -3
- data/lib/shoulda/matchers/doublespeak/double.rb +75 -0
- data/lib/shoulda/matchers/doublespeak/double_collection.rb +55 -0
- data/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +28 -0
- data/lib/shoulda/matchers/doublespeak/object_double.rb +33 -0
- data/lib/shoulda/matchers/doublespeak/proxy_implementation.rb +31 -0
- data/lib/shoulda/matchers/doublespeak/structs.rb +10 -0
- data/lib/shoulda/matchers/doublespeak/stub_implementation.rb +35 -0
- data/lib/shoulda/matchers/doublespeak/world.rb +39 -0
- data/lib/shoulda/matchers/doublespeak.rb +28 -0
- data/lib/shoulda/matchers/error.rb +20 -1
- data/lib/shoulda/matchers/independent/delegate_matcher/stubbed_target.rb +35 -0
- data/lib/shoulda/matchers/independent/delegate_matcher.rb +293 -0
- data/lib/shoulda/matchers/independent.rb +10 -0
- data/lib/shoulda/matchers/integrations/nunit_test_case_detection.rb +38 -0
- data/lib/shoulda/matchers/integrations/rspec.rb +13 -14
- data/lib/shoulda/matchers/integrations/test_unit.rb +19 -15
- data/lib/shoulda/matchers/integrations.rb +13 -0
- data/lib/shoulda/matchers/rails_shim.rb +16 -0
- data/lib/shoulda/matchers/version.rb +1 -1
- data/lib/shoulda/matchers.rb +15 -3
- data/spec/shoulda/matchers/action_controller/callback_matcher_spec.rb +82 -0
- data/spec/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +2 -2
- data/spec/shoulda/matchers/action_controller/render_template_matcher_spec.rb +5 -5
- data/spec/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +4 -4
- data/spec/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb +38 -11
- data/spec/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +1 -1
- data/spec/shoulda/matchers/action_controller/set_session_matcher_spec.rb +1 -1
- data/spec/shoulda/matchers/action_controller/set_the_flash_matcher_spec.rb +6 -6
- data/spec/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +314 -0
- data/spec/shoulda/matchers/active_model/allow_value_matcher_spec.rb +32 -0
- data/spec/shoulda/matchers/active_model/ensure_inclusion_of_matcher_spec.rb +553 -211
- data/spec/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +22 -0
- data/spec/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +38 -0
- data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +42 -36
- data/spec/shoulda/matchers/active_record/association_matcher_spec.rb +15 -1
- data/spec/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +4 -0
- data/spec/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +4 -0
- data/spec/shoulda/matchers/doublespeak/double_collection_spec.rb +102 -0
- data/spec/shoulda/matchers/doublespeak/double_implementation_registry_spec.rb +21 -0
- data/spec/shoulda/matchers/doublespeak/double_spec.rb +144 -0
- data/spec/shoulda/matchers/doublespeak/object_double_spec.rb +77 -0
- data/spec/shoulda/matchers/doublespeak/proxy_implementation_spec.rb +40 -0
- data/spec/shoulda/matchers/doublespeak/stub_implementation_spec.rb +88 -0
- data/spec/shoulda/matchers/doublespeak/world_spec.rb +88 -0
- data/spec/shoulda/matchers/doublespeak_spec.rb +19 -0
- data/spec/shoulda/matchers/independent/delegate_matcher/stubbed_target_spec.rb +43 -0
- data/spec/shoulda/matchers/independent/delegate_matcher_spec.rb +250 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/activemodel_helpers.rb +6 -2
- data/spec/support/controller_builder.rb +29 -1
- data/spec/support/rails_versions.rb +4 -0
- data/spec/support/test_application.rb +1 -1
- metadata +59 -10
@@ -4,7 +4,9 @@ module Shoulda
|
|
4
4
|
# The `validate_numericality_of` matcher tests usage of the
|
5
5
|
# `validates_numericality_of` validation.
|
6
6
|
#
|
7
|
-
# class Person
|
7
|
+
# class Person
|
8
|
+
# include ActiveModel::Model
|
9
|
+
#
|
8
10
|
# validates_numericality_of :gpa
|
9
11
|
# end
|
10
12
|
#
|
@@ -57,7 +59,10 @@ module Shoulda
|
|
57
59
|
#
|
58
60
|
# # RSpec
|
59
61
|
# describe Person do
|
60
|
-
# it
|
62
|
+
# it do
|
63
|
+
# should validate_numericality_of(:number_of_cars).
|
64
|
+
# is_less_than(2)
|
65
|
+
# end
|
61
66
|
# end
|
62
67
|
#
|
63
68
|
# # Test::Unit
|
@@ -80,12 +85,16 @@ module Shoulda
|
|
80
85
|
#
|
81
86
|
# # RSpec
|
82
87
|
# describe Person do
|
83
|
-
# it
|
88
|
+
# it do
|
89
|
+
# should validate_numericality_of(:birth_year).
|
90
|
+
# is_less_than_or_equal_to(1987)
|
91
|
+
# end
|
84
92
|
# end
|
85
93
|
#
|
86
94
|
# # Test::Unit
|
87
95
|
# class PersonTest < ActiveSupport::TestCase
|
88
|
-
# should validate_numericality_of(:birth_year).
|
96
|
+
# should validate_numericality_of(:birth_year).
|
97
|
+
# is_less_than_or_equal_to(1987)
|
89
98
|
# end
|
90
99
|
#
|
91
100
|
# ##### is_equal_to
|
@@ -125,12 +134,16 @@ module Shoulda
|
|
125
134
|
#
|
126
135
|
# # RSpec
|
127
136
|
# describe Person do
|
128
|
-
# it
|
137
|
+
# it do
|
138
|
+
# should validate_numericality_of(:height).
|
139
|
+
# is_greater_than_or_equal_to(55)
|
140
|
+
# end
|
129
141
|
# end
|
130
142
|
#
|
131
143
|
# # Test::Unit
|
132
144
|
# class PersonTest < ActiveSupport::TestCase
|
133
|
-
# should validate_numericality_of(:height).
|
145
|
+
# should validate_numericality_of(:height).
|
146
|
+
# is_greater_than_or_equal_to(55)
|
134
147
|
# end
|
135
148
|
#
|
136
149
|
# ##### is_greater_than
|
@@ -147,12 +160,16 @@ module Shoulda
|
|
147
160
|
#
|
148
161
|
# # RSpec
|
149
162
|
# describe Person do
|
150
|
-
# it
|
163
|
+
# it do
|
164
|
+
# should validate_numericality_of(:legal_age).
|
165
|
+
# is_greater_than(21)
|
166
|
+
# end
|
151
167
|
# end
|
152
168
|
#
|
153
169
|
# # Test::Unit
|
154
170
|
# class PersonTest < ActiveSupport::TestCase
|
155
|
-
# should validate_numericality_of(:legal_age).
|
171
|
+
# should validate_numericality_of(:legal_age).
|
172
|
+
# is_greater_than(21)
|
156
173
|
# end
|
157
174
|
#
|
158
175
|
# ##### even
|
@@ -198,49 +215,49 @@ module Shoulda
|
|
198
215
|
# should validate_numericality_of(:birth_day).odd
|
199
216
|
# end
|
200
217
|
#
|
201
|
-
# #####
|
218
|
+
# ##### with_message
|
202
219
|
#
|
203
|
-
# Use `
|
220
|
+
# Use `with_message` if you are using a custom validation message.
|
204
221
|
#
|
205
222
|
# class Person
|
206
223
|
# include ActiveModel::Model
|
207
224
|
#
|
208
|
-
#
|
225
|
+
# validates_numericality_of :number_of_dependents,
|
226
|
+
# message: 'Number of dependents must be a number'
|
209
227
|
# end
|
210
228
|
#
|
211
229
|
# # RSpec
|
212
230
|
# describe Person do
|
213
|
-
# it
|
231
|
+
# it do
|
232
|
+
# should validate_numericality_of(:number_of_dependents).
|
233
|
+
# with_message('Number of dependents must be a number')
|
234
|
+
# end
|
214
235
|
# end
|
215
236
|
#
|
216
237
|
# # Test::Unit
|
217
238
|
# class PersonTest < ActiveSupport::TestCase
|
218
|
-
# should
|
239
|
+
# should validate_numericality_of(:number_of_dependents).
|
240
|
+
# with_message('Number of dependents must be a number')
|
219
241
|
# end
|
220
242
|
#
|
221
|
-
# #####
|
243
|
+
# ##### allow_nil
|
222
244
|
#
|
223
|
-
# Use `
|
245
|
+
# Use `allow_nil` to assert that the attribute allows nil.
|
224
246
|
#
|
225
|
-
# class
|
247
|
+
# class Post
|
226
248
|
# include ActiveModel::Model
|
227
249
|
#
|
228
|
-
#
|
229
|
-
# message: 'Number of dependents must be a number'
|
250
|
+
# validates_uniqueness_of :author_id, allow_nil: true
|
230
251
|
# end
|
231
252
|
#
|
232
253
|
# # RSpec
|
233
|
-
# describe
|
234
|
-
# it
|
235
|
-
# should validate_numericality_of(:number_of_dependents).
|
236
|
-
# with_message('Number of dependents must be a number')
|
237
|
-
# end
|
254
|
+
# describe Post do
|
255
|
+
# it { should validate_uniqueness_of(:author_id).allow_nil }
|
238
256
|
# end
|
239
257
|
#
|
240
258
|
# # Test::Unit
|
241
|
-
# class
|
242
|
-
# should
|
243
|
-
# with_message('Number of dependents must be a number')
|
259
|
+
# class PostTest < ActiveSupport::TestCase
|
260
|
+
# should validate_uniqueness_of(:author_id).allow_nil
|
244
261
|
# end
|
245
262
|
#
|
246
263
|
# @return [ValidateNumericalityOfMatcher]
|
@@ -253,53 +270,69 @@ module Shoulda
|
|
253
270
|
class ValidateNumericalityOfMatcher
|
254
271
|
NUMERIC_NAME = 'numbers'
|
255
272
|
NON_NUMERIC_VALUE = 'abcd'
|
273
|
+
DEFAULT_DIFF_TO_COMPARE = 1
|
274
|
+
|
275
|
+
attr_reader :diff_to_compare
|
256
276
|
|
257
277
|
def initialize(attribute)
|
258
278
|
@attribute = attribute
|
259
279
|
@submatchers = []
|
260
|
-
|
280
|
+
@diff_to_compare = DEFAULT_DIFF_TO_COMPARE
|
261
281
|
add_disallow_value_matcher
|
262
282
|
end
|
263
283
|
|
264
284
|
def only_integer
|
265
|
-
|
285
|
+
prepare_submatcher(
|
286
|
+
NumericalityMatchers::OnlyIntegerMatcher.new(@attribute)
|
287
|
+
)
|
266
288
|
self
|
267
289
|
end
|
268
290
|
|
269
|
-
def
|
270
|
-
|
291
|
+
def allow_nil
|
292
|
+
prepare_submatcher(
|
293
|
+
AllowValueMatcher.new(nil)
|
294
|
+
.for(@attribute)
|
295
|
+
.with_message(:not_a_number)
|
296
|
+
)
|
271
297
|
self
|
272
298
|
end
|
273
299
|
|
274
|
-
def
|
275
|
-
|
300
|
+
def odd
|
301
|
+
prepare_submatcher(
|
302
|
+
NumericalityMatchers::OddNumberMatcher.new(@attribute)
|
303
|
+
)
|
276
304
|
self
|
277
305
|
end
|
278
306
|
|
279
|
-
def
|
280
|
-
|
307
|
+
def even
|
308
|
+
prepare_submatcher(
|
309
|
+
NumericalityMatchers::EvenNumberMatcher.new(@attribute)
|
310
|
+
)
|
281
311
|
self
|
282
312
|
end
|
283
313
|
|
284
|
-
def
|
285
|
-
|
314
|
+
def is_greater_than(value)
|
315
|
+
prepare_submatcher(comparison_matcher_for(value, :>).for(@attribute))
|
286
316
|
self
|
287
317
|
end
|
288
318
|
|
289
|
-
def
|
290
|
-
|
319
|
+
def is_greater_than_or_equal_to(value)
|
320
|
+
prepare_submatcher(comparison_matcher_for(value, :>=).for(@attribute))
|
291
321
|
self
|
292
322
|
end
|
293
323
|
|
294
|
-
def
|
295
|
-
|
296
|
-
add_submatcher(odd_number_matcher)
|
324
|
+
def is_equal_to(value)
|
325
|
+
prepare_submatcher(comparison_matcher_for(value, :==).for(@attribute))
|
297
326
|
self
|
298
327
|
end
|
299
328
|
|
300
|
-
def
|
301
|
-
|
302
|
-
|
329
|
+
def is_less_than(value)
|
330
|
+
prepare_submatcher(comparison_matcher_for(value, :<).for(@attribute))
|
331
|
+
self
|
332
|
+
end
|
333
|
+
|
334
|
+
def is_less_than_or_equal_to(value)
|
335
|
+
prepare_submatcher(comparison_matcher_for(value, :<=).for(@attribute))
|
303
336
|
self
|
304
337
|
end
|
305
338
|
|
@@ -337,10 +370,27 @@ module Shoulda
|
|
337
370
|
add_submatcher(disallow_value_matcher)
|
338
371
|
end
|
339
372
|
|
373
|
+
def prepare_submatcher(submatcher)
|
374
|
+
add_submatcher(submatcher)
|
375
|
+
if submatcher.respond_to?(:diff_to_compare)
|
376
|
+
update_diff_to_compare(submatcher)
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
def comparison_matcher_for(value, operator)
|
381
|
+
NumericalityMatchers::ComparisonMatcher
|
382
|
+
.new(self, value, operator)
|
383
|
+
.for(@attribute)
|
384
|
+
end
|
385
|
+
|
340
386
|
def add_submatcher(submatcher)
|
341
387
|
@submatchers << submatcher
|
342
388
|
end
|
343
389
|
|
390
|
+
def update_diff_to_compare(matcher)
|
391
|
+
@diff_to_compare = [@diff_to_compare, matcher.diff_to_compare].max
|
392
|
+
end
|
393
|
+
|
344
394
|
def submatchers_match?
|
345
395
|
failing_submatchers.empty?
|
346
396
|
end
|
@@ -372,7 +422,12 @@ module Shoulda
|
|
372
422
|
end
|
373
423
|
|
374
424
|
def submatcher_comparison_descriptions
|
375
|
-
@submatchers.inject([])
|
425
|
+
@submatchers.inject([]) do |arr, submatcher|
|
426
|
+
if submatcher.respond_to? :comparison_description
|
427
|
+
arr << submatcher.comparison_description
|
428
|
+
end
|
429
|
+
arr
|
430
|
+
end
|
376
431
|
end
|
377
432
|
end
|
378
433
|
end
|
@@ -4,7 +4,9 @@ module Shoulda
|
|
4
4
|
# The `validate_presence_of` matcher tests usage of the
|
5
5
|
# `validates_presence_of` validation.
|
6
6
|
#
|
7
|
-
# class Robot
|
7
|
+
# class Robot
|
8
|
+
# include ActiveModel::Model
|
9
|
+
#
|
8
10
|
# validates_presence_of :arms
|
9
11
|
# end
|
10
12
|
#
|
@@ -24,18 +26,24 @@ module Shoulda
|
|
24
26
|
#
|
25
27
|
# Use `with_message` if you are using a custom validation message.
|
26
28
|
#
|
27
|
-
# class Robot
|
29
|
+
# class Robot
|
30
|
+
# include ActiveModel::Model
|
31
|
+
#
|
28
32
|
# validates_presence_of :legs, message: 'Robot has no legs'
|
29
33
|
# end
|
30
34
|
#
|
31
35
|
# # RSpec
|
32
36
|
# describe Robot do
|
33
|
-
# it
|
37
|
+
# it do
|
38
|
+
# should validate_presence_of(:legs).
|
39
|
+
# with_message('Robot has no legs')
|
40
|
+
# end
|
34
41
|
# end
|
35
42
|
#
|
36
43
|
# # Test::Unit
|
37
44
|
# class RobotTest < ActiveSupport::TestCase
|
38
|
-
# should validate_presence_of(:legs).
|
45
|
+
# should validate_presence_of(:legs).
|
46
|
+
# with_message('Robot has no legs')
|
39
47
|
# end
|
40
48
|
#
|
41
49
|
# @return [ValidatePresenceOfMatcher]
|
@@ -54,7 +62,12 @@ module Shoulda
|
|
54
62
|
def matches?(subject)
|
55
63
|
super(subject)
|
56
64
|
@expected_message ||= :blank
|
57
|
-
|
65
|
+
|
66
|
+
if secure_password_being_validated?
|
67
|
+
disallows_and_double_checks_value_of!(blank_value, @expected_message)
|
68
|
+
else
|
69
|
+
disallows_value_of(blank_value, @expected_message)
|
70
|
+
end
|
58
71
|
end
|
59
72
|
|
60
73
|
def description
|
@@ -63,6 +76,26 @@ module Shoulda
|
|
63
76
|
|
64
77
|
private
|
65
78
|
|
79
|
+
def secure_password_being_validated?
|
80
|
+
defined?(::ActiveModel::SecurePassword) &&
|
81
|
+
@subject.class.ancestors.include?(::ActiveModel::SecurePassword::InstanceMethodsOnActivation) &&
|
82
|
+
@attribute == :password
|
83
|
+
end
|
84
|
+
|
85
|
+
def disallows_and_double_checks_value_of!(value, message)
|
86
|
+
error_class = Shoulda::Matchers::ActiveModel::CouldNotSetPasswordError
|
87
|
+
|
88
|
+
disallows_value_of(value, message) do |matcher|
|
89
|
+
matcher._after_setting_value do
|
90
|
+
actual_value = @subject.__send__(@attribute)
|
91
|
+
|
92
|
+
if !actual_value.nil?
|
93
|
+
raise error_class.create(@subject.class)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
66
99
|
def blank_value
|
67
100
|
if collection?
|
68
101
|
[]
|
@@ -9,7 +9,9 @@ module Shoulda
|
|
9
9
|
# values which are the same as those of the pre-existing record (thereby
|
10
10
|
# failing the uniqueness check).
|
11
11
|
#
|
12
|
-
# class Post
|
12
|
+
# class Post
|
13
|
+
# include ActiveModel::Model
|
14
|
+
#
|
13
15
|
# validates_uniqueness_of :permalink
|
14
16
|
# end
|
15
17
|
#
|
@@ -43,7 +45,9 @@ module Shoulda
|
|
43
45
|
# end
|
44
46
|
# end
|
45
47
|
#
|
46
|
-
# class Post
|
48
|
+
# class Post
|
49
|
+
# include ActiveModel::Model
|
50
|
+
#
|
47
51
|
# validates :title, uniqueness: true
|
48
52
|
# end
|
49
53
|
#
|
@@ -88,8 +92,11 @@ module Shoulda
|
|
88
92
|
#
|
89
93
|
# Use `with_message` if you are using a custom validation message.
|
90
94
|
#
|
91
|
-
# class Post
|
92
|
-
#
|
95
|
+
# class Post
|
96
|
+
# include ActiveModel::Model
|
97
|
+
#
|
98
|
+
# validates_uniqueness_of :title,
|
99
|
+
# message: 'Please choose another title'
|
93
100
|
# end
|
94
101
|
#
|
95
102
|
# # RSpec
|
@@ -112,7 +119,9 @@ module Shoulda
|
|
112
119
|
# a new record fails validation if not only the primary attribute is not
|
113
120
|
# unique, but the scoped attributes are not unique either.
|
114
121
|
#
|
115
|
-
# class Post
|
122
|
+
# class Post
|
123
|
+
# include ActiveModel::Model
|
124
|
+
#
|
116
125
|
# validates_uniqueness_of :slug, scope: :user_id
|
117
126
|
# end
|
118
127
|
#
|
@@ -133,7 +142,9 @@ module Shoulda
|
|
133
142
|
# validation even if their values are a different case than corresponding
|
134
143
|
# attributes in the pre-existing record.
|
135
144
|
#
|
136
|
-
# class Post
|
145
|
+
# class Post
|
146
|
+
# include ActiveModel::Model
|
147
|
+
#
|
137
148
|
# validates_uniqueness_of :key, case_sensitive: false
|
138
149
|
# end
|
139
150
|
#
|
@@ -151,7 +162,9 @@ module Shoulda
|
|
151
162
|
#
|
152
163
|
# Use `allow_nil` to assert that the attribute allows nil.
|
153
164
|
#
|
154
|
-
# class Post
|
165
|
+
# class Post
|
166
|
+
# include ActiveModel::Model
|
167
|
+
#
|
155
168
|
# validates_uniqueness_of :author_id, allow_nil: true
|
156
169
|
# end
|
157
170
|
#
|
@@ -255,11 +268,6 @@ module Shoulda
|
|
255
268
|
|
256
269
|
@subject.class.new.tap do |instance|
|
257
270
|
instance.__send__("#{@attribute}=", value)
|
258
|
-
|
259
|
-
other_non_nullable_columns.each do |non_nullable_column|
|
260
|
-
instance.__send__("#{non_nullable_column.name}=", correct_type_for_column(non_nullable_column))
|
261
|
-
end
|
262
|
-
|
263
271
|
if has_secure_password?
|
264
272
|
instance.password = 'password'
|
265
273
|
instance.password_confirmation = 'password'
|
@@ -313,7 +321,12 @@ module Shoulda
|
|
313
321
|
previous_value ||= correct_type_for_column(@subject.class.columns_hash[scope.to_s])
|
314
322
|
|
315
323
|
next_value =
|
316
|
-
if
|
324
|
+
if @subject.class.respond_to?(:defined_enums) && @subject.defined_enums[scope.to_s]
|
325
|
+
available_values = @subject.defined_enums[scope.to_s].reject do |key, _|
|
326
|
+
key == previous_value
|
327
|
+
end
|
328
|
+
available_values.keys.last
|
329
|
+
elsif previous_value.respond_to?(:next)
|
317
330
|
previous_value.next
|
318
331
|
elsif previous_value.respond_to?(:to_datetime)
|
319
332
|
previous_value.to_datetime.next
|
@@ -338,7 +351,7 @@ module Shoulda
|
|
338
351
|
end
|
339
352
|
|
340
353
|
def correct_type_for_column(column)
|
341
|
-
if column.type == :string
|
354
|
+
if column.type == :string
|
342
355
|
'0'
|
343
356
|
elsif column.type == :datetime
|
344
357
|
DateTime.now
|
@@ -360,12 +373,6 @@ module Shoulda
|
|
360
373
|
end
|
361
374
|
value
|
362
375
|
end
|
363
|
-
|
364
|
-
def other_non_nullable_columns
|
365
|
-
@subject.class.columns.select do |column|
|
366
|
-
column.name != @attribute && !column.null && !column.primary
|
367
|
-
end
|
368
|
-
end
|
369
376
|
end
|
370
377
|
end
|
371
378
|
end
|
@@ -610,7 +610,7 @@ module Shoulda
|
|
610
610
|
# @private
|
611
611
|
class AssociationMatcher
|
612
612
|
delegate :reflection, :model_class, :associated_class, :through?,
|
613
|
-
:join_table, to: :reflector
|
613
|
+
:join_table, :polymorphic?, to: :reflector
|
614
614
|
|
615
615
|
def initialize(macro, name)
|
616
616
|
@macro = macro
|
@@ -644,6 +644,13 @@ module Shoulda
|
|
644
644
|
self
|
645
645
|
end
|
646
646
|
|
647
|
+
def inverse_of(inverse_of)
|
648
|
+
inverse_of_matcher =
|
649
|
+
AssociationMatchers::InverseOfMatcher.new(inverse_of, name)
|
650
|
+
add_submatcher(inverse_of_matcher)
|
651
|
+
self
|
652
|
+
end
|
653
|
+
|
647
654
|
def source(source)
|
648
655
|
source_matcher = AssociationMatchers::SourceMatcher.new(source, name)
|
649
656
|
add_submatcher(source_matcher)
|
@@ -700,7 +707,7 @@ module Shoulda
|
|
700
707
|
@subject = subject
|
701
708
|
association_exists? &&
|
702
709
|
macro_correct? &&
|
703
|
-
class_exists? &&
|
710
|
+
(polymorphic? || class_exists?) &&
|
704
711
|
foreign_key_exists? &&
|
705
712
|
class_name_correct? &&
|
706
713
|
autosave_correct? &&
|
@@ -766,6 +773,9 @@ module Shoulda
|
|
766
773
|
def macro_correct?
|
767
774
|
if reflection.macro == macro
|
768
775
|
true
|
776
|
+
elsif reflection.macro == :has_many
|
777
|
+
macro == :has_and_belongs_to_many &&
|
778
|
+
reflection.name == @name
|
769
779
|
else
|
770
780
|
@missing = "actual association type was #{reflection.macro}"
|
771
781
|
false
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
module ActiveRecord
|
4
|
+
module AssociationMatchers
|
5
|
+
# @private
|
6
|
+
class InverseOfMatcher
|
7
|
+
attr_accessor :missing_option
|
8
|
+
|
9
|
+
def initialize(inverse_of, name)
|
10
|
+
@inverse_of = inverse_of
|
11
|
+
@name = name
|
12
|
+
@missing_option = ''
|
13
|
+
end
|
14
|
+
|
15
|
+
def description
|
16
|
+
"inverse_of => #{inverse_of}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def matches?(subject)
|
20
|
+
self.subject = ModelReflector.new(subject, name)
|
21
|
+
|
22
|
+
if option_verifier.correct_for_string?(:inverse_of, inverse_of)
|
23
|
+
true
|
24
|
+
else
|
25
|
+
self.missing_option = "#{name} should have #{description}"
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_accessor :subject, :inverse_of, :name
|
33
|
+
|
34
|
+
def option_verifier
|
35
|
+
@option_verifier ||= OptionVerifier.new(subject)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -16,13 +16,19 @@ module Shoulda
|
|
16
16
|
reflection.klass
|
17
17
|
end
|
18
18
|
|
19
|
+
def polymorphic?
|
20
|
+
reflection.options[:polymorphic]
|
21
|
+
end
|
22
|
+
|
19
23
|
def through?
|
20
24
|
reflection.options[:through]
|
21
25
|
end
|
22
26
|
|
23
27
|
def join_table
|
24
28
|
join_table =
|
25
|
-
if
|
29
|
+
if has_and_belongs_to_many_name_table_name
|
30
|
+
has_and_belongs_to_many_name_table_name
|
31
|
+
elsif reflection.respond_to?(:join_table)
|
26
32
|
reflection.join_table
|
27
33
|
else
|
28
34
|
reflection.options[:join_table]
|
@@ -74,6 +80,23 @@ module Shoulda
|
|
74
80
|
relation
|
75
81
|
end
|
76
82
|
end
|
83
|
+
|
84
|
+
def has_and_belongs_to_many_name
|
85
|
+
reflection.options[:through]
|
86
|
+
end
|
87
|
+
|
88
|
+
def has_and_belongs_to_many_name_table_name
|
89
|
+
if has_and_belongs_to_many_reflection
|
90
|
+
has_and_belongs_to_many_reflection.table_name
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def has_and_belongs_to_many_reflection
|
95
|
+
@_has_and_belongs_to_many_reflection ||=
|
96
|
+
if has_and_belongs_to_many_name
|
97
|
+
@subject.reflect_on_association(has_and_belongs_to_many_name)
|
98
|
+
end
|
99
|
+
end
|
77
100
|
end
|
78
101
|
end
|
79
102
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'shoulda/matchers/active_record/association_matcher'
|
2
2
|
require 'shoulda/matchers/active_record/association_matchers'
|
3
3
|
require 'shoulda/matchers/active_record/association_matchers/counter_cache_matcher'
|
4
|
+
require 'shoulda/matchers/active_record/association_matchers/inverse_of_matcher'
|
4
5
|
require 'shoulda/matchers/active_record/association_matchers/order_matcher'
|
5
6
|
require 'shoulda/matchers/active_record/association_matchers/through_matcher'
|
6
7
|
require 'shoulda/matchers/active_record/association_matchers/dependent_matcher'
|
@@ -9,9 +9,14 @@ module Shoulda
|
|
9
9
|
# @private
|
10
10
|
AssertionError = Test::Unit::AssertionFailedError
|
11
11
|
elsif Gem.ruby_version >= Gem::Version.new("1.9")
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
begin
|
13
|
+
require 'minitest'
|
14
|
+
rescue LoadError
|
15
|
+
require 'minitest/unit'
|
16
|
+
ensure
|
17
|
+
# @private
|
18
|
+
AssertionError = MiniTest::Assertion
|
19
|
+
end
|
15
20
|
else
|
16
21
|
raise 'No unit test library available'
|
17
22
|
end
|