shoulda-matchers 6.0.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/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
@@ -13,7 +13,11 @@ module Shoulda
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def associated_class
|
16
|
-
|
16
|
+
if polymorphic?
|
17
|
+
subject
|
18
|
+
else
|
19
|
+
reflection.klass
|
20
|
+
end
|
17
21
|
end
|
18
22
|
|
19
23
|
def polymorphic?
|
@@ -70,6 +74,10 @@ module Shoulda
|
|
70
74
|
reflection.options[:through]
|
71
75
|
end
|
72
76
|
|
77
|
+
def strict_loading?
|
78
|
+
reflection.options.fetch(:strict_loading, subject.strict_loading_by_default)
|
79
|
+
end
|
80
|
+
|
73
81
|
protected
|
74
82
|
|
75
83
|
attr_reader :reflection, :subject
|
@@ -22,44 +22,48 @@ module Shoulda
|
|
22
22
|
if submatcher_passes?(subject)
|
23
23
|
true
|
24
24
|
else
|
25
|
-
@missing_option =
|
25
|
+
@missing_option = build_missing_option
|
26
26
|
|
27
|
-
|
27
|
+
false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_reader :attribute_name, :optional, :submatcher
|
34
|
+
|
35
|
+
def submatcher_passes?(subject)
|
36
|
+
if optional
|
37
|
+
submatcher.matches?(subject)
|
38
|
+
else
|
39
|
+
submatcher.does_not_match?(subject)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def build_missing_option
|
44
|
+
String.new('and for the record ').tap do |missing_option_string|
|
45
|
+
missing_option_string <<
|
28
46
|
if optional
|
29
47
|
'not to '
|
30
48
|
else
|
31
49
|
'to '
|
32
50
|
end
|
33
51
|
|
34
|
-
|
52
|
+
missing_option_string << (
|
35
53
|
'fail validation if '\
|
36
54
|
":#{attribute_name} is unset; i.e., either the association "\
|
37
55
|
'should have been defined with `optional: '\
|
38
56
|
"#{optional.inspect}`, or there "
|
39
57
|
)
|
40
58
|
|
41
|
-
|
59
|
+
missing_option_string <<
|
42
60
|
if optional
|
43
61
|
'should not '
|
44
62
|
else
|
45
63
|
'should '
|
46
64
|
end
|
47
65
|
|
48
|
-
|
49
|
-
|
50
|
-
false
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
private
|
55
|
-
|
56
|
-
attr_reader :attribute_name, :optional, :submatcher
|
57
|
-
|
58
|
-
def submatcher_passes?(subject)
|
59
|
-
if optional
|
60
|
-
submatcher.matches?(subject)
|
61
|
-
else
|
62
|
-
submatcher.does_not_match?(subject)
|
66
|
+
missing_option_string << "be a presence validation on :#{attribute_name}"
|
63
67
|
end
|
64
68
|
end
|
65
69
|
end
|
@@ -23,50 +23,54 @@ module Shoulda
|
|
23
23
|
if submatcher_passes?(subject)
|
24
24
|
true
|
25
25
|
else
|
26
|
-
@missing_option =
|
26
|
+
@missing_option = build_missing_option
|
27
27
|
|
28
|
-
|
28
|
+
false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_reader :attribute_name, :required, :submatcher
|
35
|
+
|
36
|
+
def submatcher_passes?(subject)
|
37
|
+
if required
|
38
|
+
submatcher.matches?(subject)
|
39
|
+
else
|
40
|
+
submatcher.does_not_match?(subject)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def validation_message_key
|
45
|
+
:required
|
46
|
+
end
|
47
|
+
|
48
|
+
def build_missing_option
|
49
|
+
String.new('and for the record ').tap do |missing_option_string|
|
50
|
+
missing_option_string <<
|
29
51
|
if required
|
30
52
|
'to '
|
31
53
|
else
|
32
54
|
'not to '
|
33
55
|
end
|
34
56
|
|
35
|
-
|
57
|
+
missing_option_string << (
|
36
58
|
'fail validation if '\
|
37
59
|
":#{attribute_name} is unset; i.e., either the association "\
|
38
60
|
'should have been defined with `required: '\
|
39
61
|
"#{required.inspect}`, or there "
|
40
62
|
)
|
41
63
|
|
42
|
-
|
64
|
+
missing_option_string <<
|
43
65
|
if required
|
44
66
|
'should '
|
45
67
|
else
|
46
68
|
'should not '
|
47
69
|
end
|
48
70
|
|
49
|
-
|
50
|
-
|
51
|
-
false
|
71
|
+
missing_option_string << "be a presence validation on :#{attribute_name}"
|
52
72
|
end
|
53
73
|
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
attr_reader :attribute_name, :required, :submatcher
|
58
|
-
|
59
|
-
def submatcher_passes?(subject)
|
60
|
-
if required
|
61
|
-
submatcher.matches?(subject)
|
62
|
-
else
|
63
|
-
submatcher.does_not_match?(subject)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def validation_message_key
|
68
|
-
:required
|
69
|
-
end
|
70
74
|
end
|
71
75
|
end
|
72
76
|
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
module ActiveRecord
|
4
|
+
# The `encrypt` matcher tests usage of the
|
5
|
+
# `encrypts` macro (Rails 7+ only).
|
6
|
+
#
|
7
|
+
# class Survey < ActiveRecord::Base
|
8
|
+
# encrypts :access_code
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# # RSpec
|
12
|
+
# RSpec.describe Survey, type: :model do
|
13
|
+
# it { should encrypt(:access_code) }
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# # Minitest (Shoulda)
|
17
|
+
# class SurveyTest < ActiveSupport::TestCase
|
18
|
+
# should encrypt(:access_code)
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# #### Qualifiers
|
22
|
+
#
|
23
|
+
# ##### deterministic
|
24
|
+
#
|
25
|
+
# class Survey < ActiveRecord::Base
|
26
|
+
# encrypts :access_code, deterministic: true
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# # RSpec
|
30
|
+
# RSpec.describe Survey, type: :model do
|
31
|
+
# it { should encrypt(:access_code).deterministic(true) }
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# # Minitest (Shoulda)
|
35
|
+
# class SurveyTest < ActiveSupport::TestCase
|
36
|
+
# should encrypt(:access_code).deterministic(true)
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# ##### downcase
|
40
|
+
#
|
41
|
+
# class Survey < ActiveRecord::Base
|
42
|
+
# encrypts :access_code, downcase: true
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# # RSpec
|
46
|
+
# RSpec.describe Survey, type: :model do
|
47
|
+
# it { should encrypt(:access_code).downcase(true) }
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# # Minitest (Shoulda)
|
51
|
+
# class SurveyTest < ActiveSupport::TestCase
|
52
|
+
# should encrypt(:access_code).downcase(true)
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# ##### ignore_case
|
56
|
+
#
|
57
|
+
# class Survey < ActiveRecord::Base
|
58
|
+
# encrypts :access_code, deterministic: true, ignore_case: true
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
# # RSpec
|
62
|
+
# RSpec.describe Survey, type: :model do
|
63
|
+
# it { should encrypt(:access_code).ignore_case(true) }
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# # Minitest (Shoulda)
|
67
|
+
# class SurveyTest < ActiveSupport::TestCase
|
68
|
+
# should encrypt(:access_code).ignore_case(true)
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# @return [EncryptMatcher]
|
72
|
+
#
|
73
|
+
def encrypt(value)
|
74
|
+
EncryptMatcher.new(value)
|
75
|
+
end
|
76
|
+
|
77
|
+
# @private
|
78
|
+
class EncryptMatcher
|
79
|
+
def initialize(attribute)
|
80
|
+
@attribute = attribute.to_sym
|
81
|
+
@options = {}
|
82
|
+
end
|
83
|
+
|
84
|
+
attr_reader :failure_message, :failure_message_when_negated
|
85
|
+
|
86
|
+
def deterministic(deterministic)
|
87
|
+
with_option(:deterministic, deterministic)
|
88
|
+
end
|
89
|
+
|
90
|
+
def downcase(downcase)
|
91
|
+
with_option(:downcase, downcase)
|
92
|
+
end
|
93
|
+
|
94
|
+
def ignore_case(ignore_case)
|
95
|
+
with_option(:ignore_case, ignore_case)
|
96
|
+
end
|
97
|
+
|
98
|
+
def matches?(subject)
|
99
|
+
@subject = subject
|
100
|
+
result = encrypted_attributes_included? &&
|
101
|
+
options_correct?(
|
102
|
+
:deterministic,
|
103
|
+
:downcase,
|
104
|
+
:ignore_case,
|
105
|
+
)
|
106
|
+
|
107
|
+
if result
|
108
|
+
@failure_message_when_negated = "Did not expect to #{description} of #{class_name}"
|
109
|
+
if @options.present?
|
110
|
+
@failure_message_when_negated += "
|
111
|
+
using "
|
112
|
+
@failure_message_when_negated += @options.map { |opt, expected|
|
113
|
+
":#{opt} option as ‹#{expected}›"
|
114
|
+
}.join(' and
|
115
|
+
')
|
116
|
+
end
|
117
|
+
|
118
|
+
@failure_message_when_negated += ",
|
119
|
+
but it did"
|
120
|
+
end
|
121
|
+
|
122
|
+
result
|
123
|
+
end
|
124
|
+
|
125
|
+
def description
|
126
|
+
"encrypt :#{@attribute}"
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def encrypted_attributes_included?
|
132
|
+
if encrypted_attributes.include?(@attribute)
|
133
|
+
true
|
134
|
+
else
|
135
|
+
@failure_message = "Expected to #{description} of #{class_name}, but it did not"
|
136
|
+
false
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def with_option(option_name, value)
|
141
|
+
@options[option_name] = value
|
142
|
+
self
|
143
|
+
end
|
144
|
+
|
145
|
+
def options_correct?(*opts)
|
146
|
+
opts.all? do |opt|
|
147
|
+
next true unless @options.key?(opt)
|
148
|
+
|
149
|
+
expected = @options[opt]
|
150
|
+
actual = encrypted_attribute_scheme.send("#{opt}?")
|
151
|
+
next true if expected == actual
|
152
|
+
|
153
|
+
@failure_message = "Expected to #{description} of #{class_name} using :#{opt} option
|
154
|
+
as ‹#{expected}›, but got ‹#{actual}›"
|
155
|
+
|
156
|
+
false
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def encrypted_attributes
|
161
|
+
@_encrypted_attributes ||= @subject.class.encrypted_attributes || []
|
162
|
+
end
|
163
|
+
|
164
|
+
def encrypted_attribute_scheme
|
165
|
+
@subject.class.type_for_attribute(@attribute).scheme
|
166
|
+
end
|
167
|
+
|
168
|
+
def class_name
|
169
|
+
@subject.class.name
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
@@ -152,18 +152,18 @@ module Shoulda
|
|
152
152
|
end
|
153
153
|
|
154
154
|
def description
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
end
|
155
|
+
String.new('have ').tap do |description|
|
156
|
+
description <<
|
157
|
+
if qualifiers.include?(:unique)
|
158
|
+
"#{Shoulda::Matchers::Util.a_or_an(index_type)} "
|
159
|
+
else
|
160
|
+
'an '
|
161
|
+
end
|
163
162
|
|
164
|
-
|
163
|
+
description << 'index on '
|
165
164
|
|
166
|
-
|
165
|
+
description << inspected_expected_columns
|
166
|
+
end
|
167
167
|
end
|
168
168
|
|
169
169
|
private
|
@@ -40,7 +40,7 @@ module Shoulda
|
|
40
40
|
#
|
41
41
|
# # Minitest (Shoulda)
|
42
42
|
# class User < ActiveSupport::TestCase
|
43
|
-
# should normalize(:email, handle).from(" Example\n").to("example")
|
43
|
+
# should normalize(:email, :handle).from(" Example\n").to("example")
|
44
44
|
# end
|
45
45
|
#
|
46
46
|
# If the normalization accepts nil values with the `apply_to_nil` option,
|
@@ -411,9 +411,29 @@ module Shoulda
|
|
411
411
|
if scopes_match?
|
412
412
|
true
|
413
413
|
else
|
414
|
-
@failure_reason = 'Expected the validation '
|
414
|
+
@failure_reason = String.new('Expected the validation ').tap do |failure_reason_string|
|
415
|
+
failure_reason_string <<
|
416
|
+
if expected_scopes.empty?
|
417
|
+
'not to be scoped to anything, '
|
418
|
+
else
|
419
|
+
"to be scoped to #{inspected_expected_scopes}, "
|
420
|
+
end
|
421
|
+
|
422
|
+
if actual_sets_of_scopes.any?
|
423
|
+
failure_reason_string << 'but it was scoped to '
|
424
|
+
failure_reason_string << "#{inspected_actual_scopes} instead."
|
425
|
+
else
|
426
|
+
failure_reason_string << 'but it was not scoped to anything.'
|
427
|
+
end
|
428
|
+
end
|
415
429
|
|
416
|
-
|
430
|
+
false
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
def build_failure_reason
|
435
|
+
String.new('Expected the validation ').tap do |failure_reason_string|
|
436
|
+
failure_reason_string <<
|
417
437
|
if expected_scopes.empty?
|
418
438
|
'not to be scoped to anything, '
|
419
439
|
else
|
@@ -421,27 +441,25 @@ module Shoulda
|
|
421
441
|
end
|
422
442
|
|
423
443
|
if actual_sets_of_scopes.any?
|
424
|
-
|
425
|
-
|
444
|
+
failure_reason_string << 'but it was scoped to '
|
445
|
+
failure_reason_string << "#{inspected_actual_scopes} instead."
|
426
446
|
else
|
427
|
-
|
447
|
+
failure_reason_string << 'but it was not scoped to anything.'
|
428
448
|
end
|
429
|
-
|
430
|
-
false
|
431
449
|
end
|
432
450
|
end
|
433
451
|
|
434
452
|
def does_not_match_scopes_configuration?
|
435
453
|
if scopes_match?
|
436
|
-
@failure_reason = 'Expected the validation '
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
454
|
+
@failure_reason = String.new('Expected the validation ').tap do |failure_reason|
|
455
|
+
if expected_scopes.empty?
|
456
|
+
failure_reason << 'to be scoped to nothing, '
|
457
|
+
failure_reason << 'but it was scoped to '
|
458
|
+
failure_reason << "#{inspected_actual_scopes} instead."
|
459
|
+
else
|
460
|
+
failure_reason << 'not to be scoped to '
|
461
|
+
failure_reason << inspected_expected_scopes
|
462
|
+
end
|
445
463
|
end
|
446
464
|
|
447
465
|
false
|
@@ -618,20 +636,18 @@ module Shoulda
|
|
618
636
|
else
|
619
637
|
inspected_scopes = scopes_missing_on_model.map(&:inspect)
|
620
638
|
|
621
|
-
|
622
|
-
|
623
|
-
reason << inspected_scopes.to_sentence
|
624
|
-
|
625
|
-
reason <<
|
626
|
-
if inspected_scopes.many?
|
627
|
-
' do not seem to be attributes'
|
628
|
-
else
|
629
|
-
' does not seem to be an attribute'
|
630
|
-
end
|
639
|
+
@failure_reason = String.new.tap do |reason|
|
640
|
+
reason << inspected_scopes.to_sentence
|
631
641
|
|
632
|
-
|
642
|
+
reason <<
|
643
|
+
if inspected_scopes.many?
|
644
|
+
' do not seem to be attributes'
|
645
|
+
else
|
646
|
+
' does not seem to be an attribute'
|
647
|
+
end
|
633
648
|
|
634
|
-
|
649
|
+
reason << " on #{model.name}."
|
650
|
+
end
|
635
651
|
|
636
652
|
false
|
637
653
|
end
|
@@ -643,20 +659,18 @@ module Shoulda
|
|
643
659
|
else
|
644
660
|
inspected_scopes = scopes_present_on_model.map(&:inspect)
|
645
661
|
|
646
|
-
|
647
|
-
|
648
|
-
reason << inspected_scopes.to_sentence
|
649
|
-
|
650
|
-
reason <<
|
651
|
-
if inspected_scopes.many?
|
652
|
-
' seem to be attributes'
|
653
|
-
else
|
654
|
-
' seems to be an attribute'
|
655
|
-
end
|
662
|
+
@failure_reason = String.new.tap do |reason|
|
663
|
+
reason << inspected_scopes.to_sentence
|
656
664
|
|
657
|
-
|
665
|
+
reason <<
|
666
|
+
if inspected_scopes.many?
|
667
|
+
' seem to be attributes'
|
668
|
+
else
|
669
|
+
' seems to be an attribute'
|
670
|
+
end
|
658
671
|
|
659
|
-
|
672
|
+
reason << " on #{model.name}."
|
673
|
+
end
|
660
674
|
|
661
675
|
false
|
662
676
|
end
|
@@ -936,45 +950,43 @@ module Shoulda
|
|
936
950
|
end
|
937
951
|
|
938
952
|
def failure_message_preface # rubocop:disable Metrics/MethodLength
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
953
|
+
String.new.tap do |prefix|
|
954
|
+
if @existing_record_created
|
955
|
+
prefix << "After taking the given #{model.name}"
|
956
|
+
|
957
|
+
if attribute_setter_for_existing_record
|
958
|
+
prefix << ', setting '
|
959
|
+
prefix << description_for_attribute_setter(
|
960
|
+
attribute_setter_for_existing_record,
|
961
|
+
)
|
962
|
+
else
|
963
|
+
prefix << ", whose :#{attribute} is "
|
964
|
+
prefix << "‹#{existing_value_read.inspect}›"
|
965
|
+
end
|
943
966
|
|
944
|
-
|
945
|
-
|
967
|
+
prefix << ', and saving it as the existing record, then'
|
968
|
+
elsif attribute_setter_for_existing_record
|
969
|
+
prefix << "Given an existing #{model.name},"
|
970
|
+
prefix << ' after setting '
|
946
971
|
prefix << description_for_attribute_setter(
|
947
972
|
attribute_setter_for_existing_record,
|
948
973
|
)
|
974
|
+
prefix << ', then'
|
949
975
|
else
|
950
|
-
prefix << "
|
951
|
-
prefix <<
|
976
|
+
prefix << "Given an existing #{model.name} whose :#{attribute}"
|
977
|
+
prefix << ' is '
|
978
|
+
prefix << Shoulda::Matchers::Util.inspect_value(
|
979
|
+
existing_value_read,
|
980
|
+
)
|
981
|
+
prefix << ', after'
|
952
982
|
end
|
953
983
|
|
954
|
-
prefix <<
|
955
|
-
elsif attribute_setter_for_existing_record
|
956
|
-
prefix << "Given an existing #{model.name},"
|
957
|
-
prefix << ' after setting '
|
958
|
-
prefix << description_for_attribute_setter(
|
959
|
-
attribute_setter_for_existing_record,
|
960
|
-
)
|
961
|
-
prefix << ', then'
|
962
|
-
else
|
963
|
-
prefix << "Given an existing #{model.name} whose :#{attribute}"
|
964
|
-
prefix << ' is '
|
965
|
-
prefix << Shoulda::Matchers::Util.inspect_value(
|
966
|
-
existing_value_read,
|
967
|
-
)
|
968
|
-
prefix << ', after'
|
969
|
-
end
|
970
|
-
|
971
|
-
prefix << " making a new #{model.name} and setting "
|
984
|
+
prefix << " making a new #{model.name} and setting "
|
972
985
|
|
973
|
-
|
986
|
+
prefix << descriptions_for_attribute_setters_for_new_record
|
974
987
|
|
975
|
-
|
976
|
-
|
977
|
-
prefix
|
988
|
+
prefix << ", the matcher expected the new #{model.name} to be"
|
989
|
+
end
|
978
990
|
end
|
979
991
|
|
980
992
|
def attribute_changed_value_message
|
@@ -25,6 +25,7 @@ require 'shoulda/matchers/active_record/uniqueness'
|
|
25
25
|
require 'shoulda/matchers/active_record/validate_uniqueness_of_matcher'
|
26
26
|
require 'shoulda/matchers/active_record/have_attached_matcher'
|
27
27
|
require 'shoulda/matchers/active_record/normalize_matcher'
|
28
|
+
require 'shoulda/matchers/active_record/encrypt_matcher'
|
28
29
|
|
29
30
|
module Shoulda
|
30
31
|
module Matchers
|
@@ -18,15 +18,11 @@ module Shoulda
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def activate
|
21
|
-
doubles_by_method_name.
|
22
|
-
double.activate
|
23
|
-
end
|
21
|
+
doubles_by_method_name.each_value(&:activate)
|
24
22
|
end
|
25
23
|
|
26
24
|
def deactivate
|
27
|
-
doubles_by_method_name.
|
28
|
-
double.deactivate
|
29
|
-
end
|
25
|
+
doubles_by_method_name.each_value(&:deactivate)
|
30
26
|
end
|
31
27
|
|
32
28
|
def calls_by_method_name
|
@@ -39,15 +39,11 @@ module Shoulda
|
|
39
39
|
private
|
40
40
|
|
41
41
|
def activate
|
42
|
-
double_collections_by_class.
|
43
|
-
double_collection.activate
|
44
|
-
end
|
42
|
+
double_collections_by_class.each_value(&:activate)
|
45
43
|
end
|
46
44
|
|
47
45
|
def deactivate
|
48
|
-
double_collections_by_class.
|
49
|
-
double_collection.deactivate
|
50
|
-
end
|
46
|
+
double_collections_by_class.each_value(&:deactivate)
|
51
47
|
end
|
52
48
|
|
53
49
|
def double_collections_by_class
|