shoulda-matchers 5.3.0 → 6.2.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.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/README.md +39 -15
- data/lib/shoulda/matchers/action_controller/permit_matcher.rb +7 -9
- data/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +13 -15
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +46 -1
- data/lib/shoulda/matchers/active_model/comparison_matcher.rb +157 -0
- data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +7 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/range_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_model/numericality_matchers/submatchers.rb +16 -6
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +0 -6
- data/lib/shoulda/matchers/active_model/validate_comparison_of_matcher.rb +532 -0
- data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +3 -3
- data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +24 -11
- data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +64 -9
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +40 -96
- data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +6 -7
- data/lib/shoulda/matchers/active_model/validation_matcher.rb +6 -0
- data/lib/shoulda/matchers/active_model/validator.rb +4 -0
- data/lib/shoulda/matchers/active_model.rb +2 -1
- 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/define_enum_for_matcher.rb +0 -8
- data/lib/shoulda/matchers/active_record/encrypt_matcher.rb +174 -0
- data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +46 -6
- data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +24 -13
- data/lib/shoulda/matchers/active_record/have_implicit_order_column.rb +3 -5
- data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record/normalize_matcher.rb +151 -0
- 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 +2 -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 +13 -15
- 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/rails_shim.rb +8 -6
- data/lib/shoulda/matchers/util/word_wrap.rb +1 -1
- data/lib/shoulda/matchers/util.rb +18 -20
- data/lib/shoulda/matchers/version.rb +1 -1
- data/lib/shoulda/matchers.rb +2 -2
- data/shoulda-matchers.gemspec +1 -1
- metadata +11 -8
- data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +0 -136
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/LICENSE
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
[version-badge]: https://img.shields.io/gem/v/shoulda-matchers.svg
|
4
4
|
[rubygems]: https://rubygems.org/gems/shoulda-matchers
|
5
|
-
[github-actions-badge]: https://img.shields.io/github/workflow/status/thoughtbot/shoulda-matchers/
|
5
|
+
[github-actions-badge]: https://img.shields.io/github/actions/workflow/status/thoughtbot/shoulda-matchers/ci.yml?branch=main
|
6
6
|
[github-actions]: https://github.com/thoughtbot/shoulda-matchers/actions
|
7
7
|
[downloads-total]: https://img.shields.io/gem/dt/shoulda-matchers.svg
|
8
8
|
[downloads-badge]: https://img.shields.io/gem/dtv/shoulda-matchers.svg
|
@@ -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
|
|
@@ -374,6 +374,8 @@ about any of them, make sure to [consult the documentation][rubydocs]!
|
|
374
374
|
tests usage of `validates_numericality_of`.
|
375
375
|
* **[validate_presence_of](lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb)**
|
376
376
|
tests usage of `validates_presence_of`.
|
377
|
+
* **[validate_comparison_of](lib/shoulda/matchers/active_model/validate_comparison_of_matcher.rb)**
|
378
|
+
tests usage of `validates_comparison_of`.
|
377
379
|
|
378
380
|
### ActiveRecord matchers
|
379
381
|
|
@@ -383,8 +385,10 @@ about any of them, make sure to [consult the documentation][rubydocs]!
|
|
383
385
|
tests your `belongs_to` associations.
|
384
386
|
* **[define_enum_for](lib/shoulda/matchers/active_record/define_enum_for_matcher.rb)**
|
385
387
|
tests usage of the `enum` macro.
|
386
|
-
* **[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)**
|
387
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.
|
388
392
|
* **[have_db_column](lib/shoulda/matchers/active_record/have_db_column_matcher.rb)**
|
389
393
|
tests that the table that backs your model has a specific column.
|
390
394
|
* **[have_db_index](lib/shoulda/matchers/active_record/have_db_index_matcher.rb)**
|
@@ -407,6 +411,10 @@ about any of them, make sure to [consult the documentation][rubydocs]!
|
|
407
411
|
usage of the `serialize` macro.
|
408
412
|
* **[validate_uniqueness_of](lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb)**
|
409
413
|
tests usage of `validates_uniqueness_of`.
|
414
|
+
* **[normalize](lib/shoulda/matchers/active_record/normalize_matcher.rb)** tests
|
415
|
+
usage of the `normalize` macro
|
416
|
+
* **[encrypt](lib/shoulda/matchers/active_record/encrypt_matcher.rb)**
|
417
|
+
tests usage of the `encrypts` macro.
|
410
418
|
|
411
419
|
### ActionController matchers
|
412
420
|
|
@@ -468,8 +476,8 @@ machine, understanding the codebase, and creating a good pull request.
|
|
468
476
|
|
469
477
|
## Compatibility
|
470
478
|
|
471
|
-
Shoulda Matchers is tested and supported against Ruby
|
472
|
-
|
479
|
+
Shoulda Matchers is tested and supported against Ruby 3.0+, Rails
|
480
|
+
6.1+, RSpec 3.x, and Minitest 5.x.
|
473
481
|
|
474
482
|
- For Ruby < 2.4 and Rails < 4.1 compatibility, please use [v3.1.3][v3.1.3].
|
475
483
|
- For Ruby < 3.0 and Rails < 6.1 compatibility, please use [v4.5.1][v4.5.1].
|
@@ -484,30 +492,46 @@ Shoulda Matchers follows Semantic Versioning 2.0 as defined at
|
|
484
492
|
|
485
493
|
## Team
|
486
494
|
|
487
|
-
Shoulda Matchers is maintained by [
|
488
|
-
|
495
|
+
Shoulda Matchers is currently maintained by [Pedro Paiva][VSPPedro] and [Matheus
|
496
|
+
Sales][matsales28]. Previous maintainers include [Elliot Winkler][mcmire],
|
497
|
+
[Gui Albuk][guialbuk], [Jason Draper][drapergeek], [Melissa Xie][mxie],
|
498
|
+
[Gabe Berke-Williams][gabebw], [Ryan McGeary][rmm5t], [Joe Ferris][jferris], and
|
499
|
+
[Tammer Saleh][tammersaleh].
|
489
500
|
|
501
|
+
[VSPPedro]: https://github.com/VSPPedro
|
502
|
+
[matsales28]: https://github.com/matsales28
|
490
503
|
[mcmire]: https://github.com/mcmire
|
491
504
|
[guialbuk]: https://github.com/guialbuk
|
505
|
+
[drapergeek]: https://github.com/drapergeek
|
506
|
+
[mxie]: https://github.com/mxie
|
507
|
+
[gabebw]: https://github.com/gabebw
|
508
|
+
[rmm5t]: https://github.com/rmm5t
|
509
|
+
[jferris]: https://github.com/jferris
|
510
|
+
[tammersaleh]: https://github.com/tammersaleh
|
492
511
|
|
493
512
|
## Copyright/License
|
494
513
|
|
495
|
-
Shoulda Matchers is copyright ©
|
514
|
+
Shoulda Matchers is copyright © Tammer Saleh and [thoughtbot,
|
496
515
|
inc][thoughtbot-website]. It is free and opensource software and may be
|
497
516
|
redistributed under the terms specified in the [LICENSE](LICENSE) file.
|
498
517
|
|
499
518
|
[thoughtbot-website]: https://thoughtbot.com
|
500
519
|
|
520
|
+
<!-- START /templates/footer.md -->
|
501
521
|
## About thoughtbot
|
502
522
|
|
503
|
-
![thoughtbot]
|
504
|
-
|
505
|
-
[thoughtbot-logo]: https://presskit.thoughtbot.com/images/thoughtbot-logo-for-readmes.svg
|
523
|
+

|
506
524
|
|
525
|
+
This repo is maintained and funded by thoughtbot, inc.
|
507
526
|
The names and logos for thoughtbot are trademarks of thoughtbot, inc.
|
508
527
|
|
509
|
-
We
|
510
|
-
|
528
|
+
We love open source software!
|
529
|
+
See [our other projects][community].
|
530
|
+
|
531
|
+
We are [available for hire][hire].
|
511
532
|
|
512
533
|
[community]: https://thoughtbot.com/community?utm_source=github
|
513
|
-
[hire]: https://thoughtbot.com?utm_source=github
|
534
|
+
[hire]: https://thoughtbot.com/hire-us?utm_source=github
|
535
|
+
|
536
|
+
|
537
|
+
<!-- END /templates/footer.md -->
|
@@ -11,7 +11,7 @@ module Shoulda
|
|
11
11
|
module Matchers
|
12
12
|
module ActionController
|
13
13
|
# The `permit` matcher tests that an action in your controller receives a
|
14
|
-
#
|
14
|
+
# allowlist of parameters using Rails' Strong Parameters feature
|
15
15
|
# (specifically that `permit` was called with the correct arguments).
|
16
16
|
#
|
17
17
|
# Here's an example:
|
@@ -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
|
@@ -402,6 +438,10 @@ module Shoulda
|
|
402
438
|
@result.nil?
|
403
439
|
end
|
404
440
|
|
441
|
+
def has_any_errors?
|
442
|
+
validator.record.errors.any?
|
443
|
+
end
|
444
|
+
|
405
445
|
def failure_message
|
406
446
|
attribute_setter = result.attribute_setter
|
407
447
|
|
@@ -480,6 +520,11 @@ module Shoulda
|
|
480
520
|
message << " it produced these validation errors instead:\n\n"
|
481
521
|
message << validator.all_formatted_validation_error_messages
|
482
522
|
end
|
523
|
+
elsif validator.has_any_errors?
|
524
|
+
message << ", placing a validation error on :#{attribute_setter.attribute_name}"
|
525
|
+
message << '. The Example was invalid,'
|
526
|
+
message << " but it had errors involving other attributes:\n\n"
|
527
|
+
message << validator.all_formatted_validation_error_messages
|
483
528
|
else
|
484
529
|
message << ', but it was valid instead.'
|
485
530
|
end
|
@@ -541,7 +586,7 @@ module Shoulda
|
|
541
586
|
end
|
542
587
|
|
543
588
|
def default_failure_message_preface
|
544
|
-
|
589
|
+
String.new.tap do |preface|
|
545
590
|
if descriptions_for_preset_values.any?
|
546
591
|
preface << 'After setting '
|
547
592
|
preface << descriptions_for_preset_values.to_sentence
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'active_support/core_ext/module/delegation'
|
2
|
+
|
3
|
+
module Shoulda
|
4
|
+
module Matchers
|
5
|
+
module ActiveModel
|
6
|
+
# @private
|
7
|
+
class ComparisonMatcher < ValidationMatcher
|
8
|
+
ERROR_MESSAGES = {
|
9
|
+
:> => {
|
10
|
+
label: :greater_than,
|
11
|
+
assertions: [false, false, true],
|
12
|
+
},
|
13
|
+
:>= => {
|
14
|
+
label: :greater_than_or_equal_to,
|
15
|
+
assertions: [false, true, true],
|
16
|
+
},
|
17
|
+
:< => {
|
18
|
+
label: :less_than,
|
19
|
+
assertions: [true, false, false],
|
20
|
+
},
|
21
|
+
:<= => {
|
22
|
+
label: :less_than_or_equal_to,
|
23
|
+
assertions: [true, true, false],
|
24
|
+
},
|
25
|
+
:== => {
|
26
|
+
label: :equal_to,
|
27
|
+
assertions: [false, true, false],
|
28
|
+
},
|
29
|
+
:!= => {
|
30
|
+
label: :other_than,
|
31
|
+
assertions: [true, false, true],
|
32
|
+
},
|
33
|
+
}.freeze
|
34
|
+
|
35
|
+
delegate :failure_message, :failure_message_when_negated, to: :comparison_submatchers
|
36
|
+
|
37
|
+
def initialize(matcher, value, operator)
|
38
|
+
super(nil)
|
39
|
+
unless matcher.respond_to? :diff_to_compare
|
40
|
+
raise ArgumentError, 'matcher is invalid'
|
41
|
+
end
|
42
|
+
|
43
|
+
@matcher = matcher
|
44
|
+
@value = value
|
45
|
+
@operator = operator
|
46
|
+
@message = ERROR_MESSAGES[operator][:label]
|
47
|
+
end
|
48
|
+
|
49
|
+
def simple_description
|
50
|
+
description = ''
|
51
|
+
|
52
|
+
if expects_strict?
|
53
|
+
description = ' strictly'
|
54
|
+
end
|
55
|
+
|
56
|
+
description +
|
57
|
+
"disallow :#{attribute} from being a number that is not " +
|
58
|
+
"#{comparison_expectation} #{@value}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def for(attribute)
|
62
|
+
@attribute = attribute
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
def with_message(message)
|
67
|
+
@expects_custom_validation_message = true
|
68
|
+
@message = message
|
69
|
+
self
|
70
|
+
end
|
71
|
+
|
72
|
+
def expects_custom_validation_message?
|
73
|
+
@expects_custom_validation_message
|
74
|
+
end
|
75
|
+
|
76
|
+
def matches?(subject)
|
77
|
+
@subject = subject
|
78
|
+
comparison_submatchers.matches?(subject)
|
79
|
+
end
|
80
|
+
|
81
|
+
def comparison_description
|
82
|
+
"#{comparison_expectation} #{@value}"
|
83
|
+
end
|
84
|
+
|
85
|
+
def comparison_submatchers
|
86
|
+
@_comparison_submatchers ||=
|
87
|
+
NumericalityMatchers::Submatchers.new(build_comparison_submatchers)
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def build_comparison_submatchers
|
93
|
+
comparison_combos.map do |diff, submatcher_method_name|
|
94
|
+
matcher = __send__(submatcher_method_name, diff, nil)
|
95
|
+
matcher.with_message(@message, values: { count: option_value })
|
96
|
+
matcher
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def comparison_combos
|
101
|
+
diffs_to_compare.zip(submatcher_method_names)
|
102
|
+
end
|
103
|
+
|
104
|
+
def submatcher_method_names
|
105
|
+
assertions.map do |value|
|
106
|
+
if value
|
107
|
+
:allow_value_matcher
|
108
|
+
else
|
109
|
+
:disallow_value_matcher
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def assertions
|
115
|
+
ERROR_MESSAGES[@operator][:assertions]
|
116
|
+
end
|
117
|
+
|
118
|
+
def option_value
|
119
|
+
if defined?(@_option_value)
|
120
|
+
@_option_value
|
121
|
+
else
|
122
|
+
@_option_value =
|
123
|
+
case @value
|
124
|
+
when Proc then @value.call(@subject)
|
125
|
+
when Symbol then @subject.send(@value)
|
126
|
+
else @value
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def diffs_to_compare
|
132
|
+
diff_to_compare = @matcher.diff_to_compare
|
133
|
+
values = case option_value
|
134
|
+
when String then diffs_when_string(diff_to_compare)
|
135
|
+
else [-1, 0, 1].map { |sign| option_value + (diff_to_compare * sign) }
|
136
|
+
end
|
137
|
+
|
138
|
+
if @matcher.given_numeric_column?
|
139
|
+
values
|
140
|
+
else
|
141
|
+
values.map(&:to_s)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def diffs_when_string(diff_to_compare)
|
146
|
+
[-1, 0, 1].map do |sign|
|
147
|
+
option_value[0..-2] + (option_value[-1].ord + diff_to_compare * sign).chr
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def comparison_expectation
|
152
|
+
ERROR_MESSAGES[@operator][:label].to_s.tr('_', ' ')
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
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
|
@@ -59,7 +59,7 @@ module Shoulda
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def build_comparison_submatcher(value, operator)
|
62
|
-
|
62
|
+
ComparisonMatcher.new(@numericality_matcher, value, operator).
|
63
63
|
for(@attribute).
|
64
64
|
with_message(@message).
|
65
65
|
on(@context)
|
@@ -14,21 +14,17 @@ module Shoulda
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def failure_message
|
17
|
-
|
17
|
+
failing_submatcher.failure_message
|
18
18
|
end
|
19
19
|
|
20
20
|
def failure_message_when_negated
|
21
|
-
|
21
|
+
non_failing_submatcher.failure_message_when_negated
|
22
22
|
end
|
23
23
|
|
24
24
|
def add(submatcher)
|
25
25
|
@submatchers << submatcher
|
26
26
|
end
|
27
27
|
|
28
|
-
def last_failing_submatcher
|
29
|
-
failing_submatchers.last
|
30
|
-
end
|
31
|
-
|
32
28
|
private
|
33
29
|
|
34
30
|
def failing_submatchers
|
@@ -36,6 +32,20 @@ module Shoulda
|
|
36
32
|
submatcher.matches?(@subject)
|
37
33
|
end
|
38
34
|
end
|
35
|
+
|
36
|
+
def non_failing_submatchers
|
37
|
+
@_non_failing_submatchers ||= @submatchers.reject do |submatcher|
|
38
|
+
submatcher.does_not_match?(@subject)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def failing_submatcher
|
43
|
+
failing_submatchers.last
|
44
|
+
end
|
45
|
+
|
46
|
+
def non_failing_submatcher
|
47
|
+
non_failing_submatchers.last
|
48
|
+
end
|
39
49
|
end
|
40
50
|
end
|
41
51
|
end
|
@@ -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)
|