shoulda-matchers 6.0.0 → 6.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +18 -9
- data/lib/shoulda/matchers/action_controller/permit_matcher.rb +6 -8
- data/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +13 -15
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +37 -1
- data/lib/shoulda/matchers/active_model/comparison_matcher.rb +1 -6
- data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +7 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/submatchers.rb +0 -5
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +0 -6
- data/lib/shoulda/matchers/active_model/validate_comparison_of_matcher.rb +11 -13
- data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +20 -8
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +9 -11
- data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +6 -7
- data/lib/shoulda/matchers/active_record/association_matcher.rb +543 -15
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +9 -1
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +1 -0
- data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +4 -0
- data/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +23 -19
- data/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +27 -23
- data/lib/shoulda/matchers/active_record/encrypt_matcher.rb +174 -0
- data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +10 -10
- data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record/normalize_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record/uniqueness/model.rb +1 -1
- data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +82 -70
- data/lib/shoulda/matchers/active_record.rb +1 -0
- data/lib/shoulda/matchers/doublespeak/double_collection.rb +2 -6
- data/lib/shoulda/matchers/doublespeak/world.rb +2 -6
- data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +12 -14
- data/lib/shoulda/matchers/integrations/libraries/action_controller.rb +7 -5
- data/lib/shoulda/matchers/integrations/libraries/routing.rb +5 -3
- data/lib/shoulda/matchers/util.rb +17 -19
- data/lib/shoulda/matchers/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d549ac8f3629ad37bc56d0d09daf37416ec23d78374a8ed6a630ea23e5c9e487
|
4
|
+
data.tar.gz: f09bc94b6be181564cdde56729c2055192a4725adee4ba8b6b7f8e84429fe9a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1f3ba08a6d15ad56cb583c0a8289e180854f5d89020b3182b2d6140289800d71bca467f187c9a4718ba26078cc2562f6377d77b00a0e84f2e683079d62ef60d3
|
7
|
+
data.tar.gz: 45d0141c79d9642439c9c03ffcd8e41d1aee993eafaea11fc72812456ead1dcf17d1698e9eb7f311c40945c54c77fc4e573a820ffa115fc344e9b0049ed69479
|
data/README.md
CHANGED
@@ -55,7 +55,7 @@ Start by including `shoulda-matchers` in your Gemfile:
|
|
55
55
|
|
56
56
|
```ruby
|
57
57
|
group :test do
|
58
|
-
gem 'shoulda-matchers', '~>
|
58
|
+
gem 'shoulda-matchers', '~> 6.0'
|
59
59
|
end
|
60
60
|
```
|
61
61
|
|
@@ -117,7 +117,7 @@ Otherwise, add `shoulda-matchers` to your Gemfile:
|
|
117
117
|
|
118
118
|
```ruby
|
119
119
|
group :test do
|
120
|
-
gem 'shoulda-matchers', '~>
|
120
|
+
gem 'shoulda-matchers', '~> 6.0'
|
121
121
|
end
|
122
122
|
```
|
123
123
|
|
@@ -385,8 +385,10 @@ about any of them, make sure to [consult the documentation][rubydocs]!
|
|
385
385
|
tests your `belongs_to` associations.
|
386
386
|
* **[define_enum_for](lib/shoulda/matchers/active_record/define_enum_for_matcher.rb)**
|
387
387
|
tests usage of the `enum` macro.
|
388
|
-
* **[have_and_belong_to_many](lib/shoulda/matchers/active_record/association_matcher.rb
|
388
|
+
* **[have_and_belong_to_many](lib/shoulda/matchers/active_record/association_matcher.rb)**
|
389
389
|
tests your `has_and_belongs_to_many` associations.
|
390
|
+
* **[have_delegated_type](lib/shoulda/matchers/active_record/association_matcher.rb#L687)**
|
391
|
+
tests usage of the `delegated_type` macro.
|
390
392
|
* **[have_db_column](lib/shoulda/matchers/active_record/have_db_column_matcher.rb)**
|
391
393
|
tests that the table that backs your model has a specific column.
|
392
394
|
* **[have_db_index](lib/shoulda/matchers/active_record/have_db_index_matcher.rb)**
|
@@ -411,6 +413,8 @@ about any of them, make sure to [consult the documentation][rubydocs]!
|
|
411
413
|
tests usage of `validates_uniqueness_of`.
|
412
414
|
* **[normalize](lib/shoulda/matchers/active_record/normalize_matcher.rb)** tests
|
413
415
|
usage of the `normalize` macro
|
416
|
+
* **[encrypt](lib/shoulda/matchers/active_record/encrypt_matcher.rb)**
|
417
|
+
tests usage of the `encrypts` macro.
|
414
418
|
|
415
419
|
### ActionController matchers
|
416
420
|
|
@@ -513,16 +517,21 @@ redistributed under the terms specified in the [LICENSE](LICENSE) file.
|
|
513
517
|
|
514
518
|
[thoughtbot-website]: https://thoughtbot.com
|
515
519
|
|
520
|
+
<!-- START /templates/footer.md -->
|
516
521
|
## About thoughtbot
|
517
522
|
|
518
|
-
![thoughtbot]
|
519
|
-
|
520
|
-
[thoughtbot-logo]: https://thoughtbot.com/brand_assets/93:44.svg
|
523
|
+
![thoughtbot](https://thoughtbot.com/thoughtbot-logo-for-readmes.svg)
|
521
524
|
|
525
|
+
This repo is maintained and funded by thoughtbot, inc.
|
522
526
|
The names and logos for thoughtbot are trademarks of thoughtbot, inc.
|
523
527
|
|
524
|
-
We
|
525
|
-
|
528
|
+
We love open source software!
|
529
|
+
See [our other projects][community].
|
530
|
+
|
531
|
+
We are [available for hire][hire].
|
526
532
|
|
527
533
|
[community]: https://thoughtbot.com/community?utm_source=github
|
528
|
-
[hire]: https://thoughtbot.com?utm_source=github
|
534
|
+
[hire]: https://thoughtbot.com/hire-us?utm_source=github
|
535
|
+
|
536
|
+
|
537
|
+
<!-- END /templates/footer.md -->
|
@@ -276,16 +276,14 @@ module Shoulda
|
|
276
276
|
:context, :subparameter_name, :parameters_double_registry
|
277
277
|
|
278
278
|
def expectation
|
279
|
-
|
279
|
+
String.new('restrict parameters ').tap do |message|
|
280
|
+
if subparameter_name
|
281
|
+
message << "on #{subparameter_name.inspect} "
|
282
|
+
end
|
280
283
|
|
281
|
-
|
282
|
-
|
284
|
+
message << 'to '\
|
285
|
+
"#{format_parameter_names(expected_permitted_parameter_names)}"
|
283
286
|
end
|
284
|
-
|
285
|
-
message << 'to '\
|
286
|
-
"#{format_parameter_names(expected_permitted_parameter_names)}"
|
287
|
-
|
288
|
-
message
|
289
287
|
end
|
290
288
|
|
291
289
|
def reality
|
@@ -83,25 +83,23 @@ module Shoulda
|
|
83
83
|
end
|
84
84
|
|
85
85
|
def expectation_description
|
86
|
-
|
87
|
-
|
88
|
-
string <<
|
89
|
-
if key_set?
|
90
|
-
" #{store.name}[#{key.inspect}]"
|
91
|
-
else
|
92
|
-
" any key in #{store.name}"
|
93
|
-
end
|
94
|
-
|
95
|
-
if expected_value_set?
|
86
|
+
String.new('set').tap do |string|
|
96
87
|
string <<
|
97
|
-
if
|
98
|
-
"
|
88
|
+
if key_set?
|
89
|
+
" #{store.name}[#{key.inspect}]"
|
99
90
|
else
|
100
|
-
"
|
91
|
+
" any key in #{store.name}"
|
101
92
|
end
|
102
|
-
end
|
103
93
|
|
104
|
-
|
94
|
+
if expected_value_set?
|
95
|
+
string <<
|
96
|
+
if expected_value.is_a?(Regexp)
|
97
|
+
" to a value matching #{expected_value.inspect}"
|
98
|
+
else
|
99
|
+
" to #{expected_value.inspect}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
105
103
|
end
|
106
104
|
end
|
107
105
|
end
|
@@ -169,6 +169,36 @@ module Shoulda
|
|
169
169
|
# on(:create)
|
170
170
|
# end
|
171
171
|
#
|
172
|
+
# ##### against
|
173
|
+
#
|
174
|
+
# Use `against` if the validation is on an attribute
|
175
|
+
# other than the attribute being validated:
|
176
|
+
#
|
177
|
+
# class UserProfile
|
178
|
+
# include ActiveModel::Model
|
179
|
+
# attr_accessor :website_url
|
180
|
+
#
|
181
|
+
# alias_attribute :url, :website_url
|
182
|
+
#
|
183
|
+
# validates_format_of :url, with: URI.regexp
|
184
|
+
# end
|
185
|
+
#
|
186
|
+
# # RSpec
|
187
|
+
# RSpec.describe UserProfile, type: :model do
|
188
|
+
# it do
|
189
|
+
# should allow_value('https://foo.com').
|
190
|
+
# for(:website_url).
|
191
|
+
# against(:url)
|
192
|
+
# end
|
193
|
+
# end
|
194
|
+
#
|
195
|
+
# # Minitest (Shoulda)
|
196
|
+
# class UserProfileTest < ActiveSupport::TestCase
|
197
|
+
# should allow_value('https://foo.com').
|
198
|
+
# for(:website_url).
|
199
|
+
# against(:url)
|
200
|
+
# end
|
201
|
+
#
|
172
202
|
# ##### with_message
|
173
203
|
#
|
174
204
|
# Use `with_message` if you are using a custom validation message.
|
@@ -349,6 +379,12 @@ module Shoulda
|
|
349
379
|
self
|
350
380
|
end
|
351
381
|
|
382
|
+
def against(attribute)
|
383
|
+
@attribute_to_check_message_against = attribute if attribute.present?
|
384
|
+
|
385
|
+
self
|
386
|
+
end
|
387
|
+
|
352
388
|
def with_message(message, given_options = {})
|
353
389
|
if message.present?
|
354
390
|
@expects_custom_validation_message = true
|
@@ -550,7 +586,7 @@ module Shoulda
|
|
550
586
|
end
|
551
587
|
|
552
588
|
def default_failure_message_preface
|
553
|
-
|
589
|
+
String.new.tap do |preface|
|
554
590
|
if descriptions_for_preset_values.any?
|
555
591
|
preface << 'After setting '
|
556
592
|
preface << descriptions_for_preset_values.to_sentence
|
@@ -50,7 +50,7 @@ module Shoulda
|
|
50
50
|
description = ''
|
51
51
|
|
52
52
|
if expects_strict?
|
53
|
-
description
|
53
|
+
description = ' strictly'
|
54
54
|
end
|
55
55
|
|
56
56
|
description +
|
@@ -78,11 +78,6 @@ module Shoulda
|
|
78
78
|
comparison_submatchers.matches?(subject)
|
79
79
|
end
|
80
80
|
|
81
|
-
def does_not_match?(subject)
|
82
|
-
@subject = subject
|
83
|
-
comparison_submatchers.does_not_match?(subject)
|
84
|
-
end
|
85
|
-
|
86
81
|
def comparison_description
|
87
82
|
"#{comparison_expectation} #{@value}"
|
88
83
|
end
|
@@ -47,6 +47,8 @@ module Shoulda
|
|
47
47
|
did_not_authenticate_correct_password: 'expected %{subject} to'\
|
48
48
|
' authenticate the correct %{attribute}',
|
49
49
|
method_not_found: 'expected %{subject} to respond to %{methods}',
|
50
|
+
should_not_have_secure_password: 'expected %{subject} to'\
|
51
|
+
' not %{description}!',
|
50
52
|
}.freeze
|
51
53
|
|
52
54
|
def initialize(attribute)
|
@@ -69,6 +71,11 @@ module Shoulda
|
|
69
71
|
failure.nil?
|
70
72
|
end
|
71
73
|
|
74
|
+
def failure_message_when_negated
|
75
|
+
MESSAGES[:should_not_have_secure_password] %
|
76
|
+
{ subject: @subject.class, description: description }
|
77
|
+
end
|
78
|
+
|
72
79
|
protected
|
73
80
|
|
74
81
|
attr_reader :subject
|
@@ -143,12 +143,6 @@ module Shoulda
|
|
143
143
|
@subject.class.reflect_on_association(@attribute)
|
144
144
|
end
|
145
145
|
|
146
|
-
def array_column?
|
147
|
-
@subject.class.respond_to?(:columns_hash) &&
|
148
|
-
@subject.class.columns_hash[@attribute.to_s].respond_to?(:array) &&
|
149
|
-
@subject.class.columns_hash[@attribute.to_s].array
|
150
|
-
end
|
151
|
-
|
152
146
|
def enum_column?
|
153
147
|
@subject.class.respond_to?(:defined_enums) &&
|
154
148
|
@subject.class.defined_enums.key?(@attribute.to_s)
|
@@ -13,12 +13,12 @@ module Shoulda
|
|
13
13
|
#
|
14
14
|
# # RSpec
|
15
15
|
# RSpec.describe Person, type: :model do
|
16
|
-
# it { should validate_comparison_of(:gpa).
|
16
|
+
# it { should validate_comparison_of(:gpa).is_greater_than(10) }
|
17
17
|
# end
|
18
18
|
#
|
19
19
|
# # Minitest (Shoulda)
|
20
20
|
# class PersonTest < ActiveSupport::TestCase
|
21
|
-
# should validate_comparison_of(:gpa).
|
21
|
+
# should validate_comparison_of(:gpa).is_greater_than(10)
|
22
22
|
# end
|
23
23
|
#
|
24
24
|
# #### Qualifiers
|
@@ -39,14 +39,14 @@ module Shoulda
|
|
39
39
|
# RSpec.describe Person, type: :model do
|
40
40
|
# it do
|
41
41
|
# should validate_comparison_of(:number_of_dependents).
|
42
|
-
#
|
42
|
+
# is_greater_than(0).
|
43
43
|
# on(:create)
|
44
44
|
# end
|
45
45
|
# end
|
46
46
|
#
|
47
47
|
# # Minitest (Shoulda)
|
48
48
|
# class PersonTest < ActiveSupport::TestCase
|
49
|
-
# should validate_comparison_of(:number_of_dependents).
|
49
|
+
# should validate_comparison_of(:number_of_dependents).is_greater_than(0).on(:create)
|
50
50
|
# end
|
51
51
|
#
|
52
52
|
# ##### is_less_than
|
@@ -353,16 +353,14 @@ module Shoulda
|
|
353
353
|
end
|
354
354
|
|
355
355
|
def simple_description
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
description << Shoulda::Matchers::Util.a_or_an(allowed_type_name)
|
356
|
+
String.new.tap do |description|
|
357
|
+
description << "validate that :#{attribute} looks like "
|
358
|
+
description << Shoulda::Matchers::Util.a_or_an(allowed_type_name)
|
360
359
|
|
361
|
-
|
362
|
-
|
360
|
+
if comparison_descriptions.present?
|
361
|
+
description << " #{comparison_descriptions}"
|
362
|
+
end
|
363
363
|
end
|
364
|
-
|
365
|
-
description
|
366
364
|
end
|
367
365
|
|
368
366
|
def failure_message
|
@@ -465,7 +463,7 @@ module Shoulda
|
|
465
463
|
def first_submatcher_that_fails_to_not_match
|
466
464
|
@_first_submatcher_that_fails_to_not_match ||=
|
467
465
|
@submatchers.detect do |submatcher|
|
468
|
-
|
466
|
+
submatcher.matches?(subject)
|
469
467
|
end
|
470
468
|
end
|
471
469
|
|
@@ -309,8 +309,8 @@ EOT
|
|
309
309
|
|
310
310
|
def in_range(range)
|
311
311
|
@range = range
|
312
|
-
@minimum =
|
313
|
-
@maximum =
|
312
|
+
@minimum = minimum_range_value
|
313
|
+
@maximum = maximum_range_value
|
314
314
|
self
|
315
315
|
end
|
316
316
|
|
@@ -400,6 +400,18 @@ EOT
|
|
400
400
|
|
401
401
|
private
|
402
402
|
|
403
|
+
def minimum_range_value
|
404
|
+
@range.begin
|
405
|
+
end
|
406
|
+
|
407
|
+
def maximum_range_value
|
408
|
+
if @range.exclude_end?
|
409
|
+
@range.end ? (@range.end - 1) : nil
|
410
|
+
else
|
411
|
+
@range.end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
403
415
|
def matches_for_range?
|
404
416
|
disallows_lower_value &&
|
405
417
|
allows_minimum_value &&
|
@@ -441,27 +453,27 @@ EOT
|
|
441
453
|
end
|
442
454
|
|
443
455
|
def allows_minimum_value
|
444
|
-
allows_value_of(@minimum, @low_message)
|
456
|
+
@minimum.nil? || allows_value_of(@minimum, @low_message)
|
445
457
|
end
|
446
458
|
|
447
459
|
def disallows_minimum_value
|
448
|
-
disallows_value_of(@minimum, @low_message)
|
460
|
+
@minimum.nil? || disallows_value_of(@minimum, @low_message)
|
449
461
|
end
|
450
462
|
|
451
463
|
def allows_maximum_value
|
452
|
-
allows_value_of(@maximum, @high_message)
|
464
|
+
@maximum.nil? || allows_value_of(@maximum, @high_message)
|
453
465
|
end
|
454
466
|
|
455
467
|
def disallows_maximum_value
|
456
|
-
disallows_value_of(@maximum, @high_message)
|
468
|
+
@maximum.nil? || disallows_value_of(@maximum, @high_message)
|
457
469
|
end
|
458
470
|
|
459
471
|
def allows_higher_value
|
460
|
-
allows_value_of(@maximum + 1, @high_message)
|
472
|
+
@maximum.nil? || allows_value_of(@maximum + 1, @high_message)
|
461
473
|
end
|
462
474
|
|
463
475
|
def disallows_higher_value
|
464
|
-
disallows_value_of(@maximum + 1, @high_message)
|
476
|
+
@maximum.nil? || disallows_value_of(@maximum + 1, @high_message)
|
465
477
|
end
|
466
478
|
|
467
479
|
def allows_all_values_in_array?
|
@@ -453,20 +453,18 @@ module Shoulda
|
|
453
453
|
end
|
454
454
|
|
455
455
|
def simple_description
|
456
|
-
|
456
|
+
String.new.tap do |description|
|
457
|
+
description << "validate that :#{attribute} looks like "
|
458
|
+
description << Shoulda::Matchers::Util.a_or_an(full_allowed_type)
|
457
459
|
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
if range_description.present?
|
462
|
-
description << " #{range_description}"
|
463
|
-
end
|
460
|
+
if range_description.present?
|
461
|
+
description << " #{range_description}"
|
462
|
+
end
|
464
463
|
|
465
|
-
|
466
|
-
|
464
|
+
if comparison_descriptions.present?
|
465
|
+
description << " #{comparison_descriptions}"
|
466
|
+
end
|
467
467
|
end
|
468
|
-
|
469
|
-
description
|
470
468
|
end
|
471
469
|
|
472
470
|
def failure_message
|
@@ -42,13 +42,12 @@ module Shoulda
|
|
42
42
|
description_clauses = []
|
43
43
|
|
44
44
|
if matcher.try(:expects_strict?)
|
45
|
-
description_clauses <<
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
description_clauses.last << ' on failure'
|
45
|
+
description_clauses <<
|
46
|
+
if matcher.try(:expects_custom_validation_message?)
|
47
|
+
'raising a validation exception with a custom message on failure'
|
48
|
+
else
|
49
|
+
'raising a validation exception on failure'
|
50
|
+
end
|
52
51
|
elsif matcher.try(:expects_custom_validation_message?)
|
53
52
|
description_clauses <<
|
54
53
|
'producing a custom validation error on failure'
|