shoulda-matchers 3.0.1 → 3.1.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/.gitignore +1 -0
- data/.travis.yml +3 -3
- data/CONTRIBUTING.md +60 -28
- data/Gemfile +1 -0
- data/Gemfile.lock +15 -12
- data/NEWS.md +111 -0
- data/README.md +94 -6
- data/Rakefile +10 -8
- data/custom_plan.rb +88 -0
- data/gemfiles/4.0.0.gemfile +1 -0
- data/gemfiles/4.0.0.gemfile.lock +21 -18
- data/gemfiles/4.0.1.gemfile +1 -0
- data/gemfiles/4.0.1.gemfile.lock +21 -18
- data/gemfiles/4.1.gemfile +1 -0
- data/gemfiles/4.1.gemfile.lock +21 -18
- data/gemfiles/4.2.gemfile +1 -0
- data/gemfiles/4.2.gemfile.lock +24 -21
- data/lib/shoulda/matchers/action_controller/permit_matcher.rb +6 -11
- data/lib/shoulda/matchers/active_model.rb +10 -1
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +258 -180
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_changed_value_error.rb +45 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_does_not_exist_error.rb +23 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +236 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter_and_validator.rb +62 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb +40 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb +48 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/successful_check.rb +14 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/successful_setting.rb +14 -0
- data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +34 -14
- data/lib/shoulda/matchers/active_model/helpers.rb +9 -17
- data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +13 -6
- data/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +13 -2
- data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +19 -35
- data/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +13 -2
- data/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +12 -2
- data/lib/shoulda/matchers/active_model/qualifiers.rb +12 -0
- data/lib/shoulda/matchers/active_model/qualifiers/ignore_interference_by_writer.rb +101 -0
- data/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb +21 -0
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +30 -32
- data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +5 -8
- data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +22 -22
- data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +27 -16
- data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +58 -15
- data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +22 -12
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +165 -87
- data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +7 -9
- data/lib/shoulda/matchers/active_model/validation_matcher.rb +111 -49
- data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +60 -0
- data/lib/shoulda/matchers/active_model/validator.rb +71 -52
- data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +19 -5
- data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +450 -124
- data/lib/shoulda/matchers/util.rb +43 -0
- data/lib/shoulda/matchers/util/word_wrap.rb +59 -31
- data/lib/shoulda/matchers/version.rb +1 -1
- data/script/update_gem_in_all_appraisals +1 -1
- data/script/update_gems_in_all_appraisals +1 -1
- data/spec/acceptance/multiple_libraries_integration_spec.rb +5 -2
- data/spec/acceptance/rails_integration_spec.rb +6 -2
- data/spec/spec_helper.rb +1 -3
- data/spec/support/acceptance/helpers/step_helpers.rb +4 -1
- data/spec/support/tests/current_bundle.rb +21 -7
- data/spec/support/unit/active_record/create_table.rb +54 -0
- data/spec/support/unit/attribute.rb +47 -0
- data/spec/support/unit/capture.rb +6 -0
- data/spec/support/unit/change_value.rb +111 -0
- data/spec/support/unit/create_model_arguments/basic.rb +135 -0
- data/spec/support/unit/create_model_arguments/has_many.rb +15 -0
- data/spec/support/unit/create_model_arguments/uniqueness_matcher.rb +74 -0
- data/spec/support/unit/helpers/active_record_versions.rb +1 -1
- data/spec/support/unit/helpers/class_builder.rb +61 -47
- data/spec/support/unit/helpers/database_helpers.rb +5 -3
- data/spec/support/unit/helpers/model_builder.rb +77 -97
- data/spec/support/unit/helpers/validation_matcher_scenario_helpers.rb +44 -0
- data/spec/support/unit/load_environment.rb +12 -0
- data/spec/support/unit/matchers/fail_with_message_including_matcher.rb +2 -2
- data/spec/support/unit/matchers/fail_with_message_matcher.rb +12 -1
- data/spec/support/unit/model_creation_strategies/active_model.rb +111 -0
- data/spec/support/unit/model_creation_strategies/active_record.rb +77 -0
- data/spec/support/unit/model_creators.rb +19 -0
- data/spec/support/unit/model_creators/active_model.rb +39 -0
- data/spec/support/unit/model_creators/active_record.rb +43 -0
- data/spec/support/unit/model_creators/active_record/has_and_belongs_to_many.rb +95 -0
- data/spec/support/unit/model_creators/active_record/has_many.rb +67 -0
- data/spec/support/unit/model_creators/active_record/uniqueness_matcher.rb +42 -0
- data/spec/support/unit/model_creators/basic.rb +97 -0
- data/spec/support/unit/rails_application.rb +1 -1
- data/spec/support/unit/record_validating_confirmation_builder.rb +3 -7
- data/spec/support/unit/shared_examples/ignoring_interference_by_writer.rb +79 -0
- data/spec/support/unit/validation_matcher_scenario.rb +62 -0
- data/spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +4 -0
- data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +575 -140
- data/spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +115 -15
- data/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +42 -4
- data/spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +92 -6
- data/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb +122 -10
- data/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +306 -58
- data/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb +122 -3
- data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +805 -131
- data/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +196 -29
- data/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +82 -40
- data/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb +600 -101
- data/spec/unit/shoulda/matchers/util/word_wrap_spec.rb +88 -33
- data/spec/unit_spec_helper.rb +10 -22
- data/zeus.json +11 -0
- metadata +64 -23
- data/lib/shoulda/matchers/active_model/strict_validator.rb +0 -51
- data/spec/support/unit/shared_examples/numerical_type_submatcher.rb +0 -15
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +0 -288
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb +0 -100
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb +0 -100
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb +0 -100
@@ -32,14 +32,42 @@ describe Shoulda::Matchers::ActiveModel::ValidateAbsenceOfMatcher, type: :model
|
|
32
32
|
expect(validating_absence_of(:attr, {}, type: type)).
|
33
33
|
to validate_absence_of(:attr)
|
34
34
|
end
|
35
|
+
|
36
|
+
it_supports(
|
37
|
+
'ignoring_interference_by_writer',
|
38
|
+
tests: {
|
39
|
+
accept_if_qualified_but_changing_value_does_not_interfere: {
|
40
|
+
changing_values_with: :next_value
|
41
|
+
},
|
42
|
+
}
|
43
|
+
)
|
44
|
+
|
45
|
+
define_method(:validation_matcher_scenario_args) do |*args|
|
46
|
+
super(*args).deep_merge(column_type: type)
|
47
|
+
end
|
35
48
|
end
|
36
49
|
end
|
50
|
+
|
51
|
+
def validation_matcher_scenario_args
|
52
|
+
super.deep_merge(model_creator: :active_record)
|
53
|
+
end
|
37
54
|
end
|
38
55
|
|
39
56
|
context 'a model without an absence validation' do
|
40
|
-
it 'rejects' do
|
41
|
-
|
42
|
-
|
57
|
+
it 'rejects with the correct failure message' do
|
58
|
+
record = define_model(:example, attr: :string).new
|
59
|
+
|
60
|
+
message = <<-MESSAGE
|
61
|
+
Example did not properly validate that :attr is empty/falsy.
|
62
|
+
After setting :attr to ‹"an arbitrary value"›, the matcher expected
|
63
|
+
the Example to be invalid, but it was valid instead.
|
64
|
+
MESSAGE
|
65
|
+
|
66
|
+
assertion = lambda do
|
67
|
+
expect(record).to validate_absence_of(:attr)
|
68
|
+
end
|
69
|
+
|
70
|
+
expect(&assertion).to fail_with_message(message)
|
43
71
|
end
|
44
72
|
end
|
45
73
|
|
@@ -51,17 +79,34 @@ describe Shoulda::Matchers::ActiveModel::ValidateAbsenceOfMatcher, type: :model
|
|
51
79
|
it 'does not override the default message with a blank' do
|
52
80
|
expect(active_model_validating_absence_of(:attr)).to validate_absence_of(:attr).with_message(nil)
|
53
81
|
end
|
82
|
+
|
83
|
+
it_supports(
|
84
|
+
'ignoring_interference_by_writer',
|
85
|
+
tests: {
|
86
|
+
accept_if_qualified_but_changing_value_does_not_interfere: {
|
87
|
+
changing_values_with: :upcase
|
88
|
+
},
|
89
|
+
}
|
90
|
+
)
|
91
|
+
|
92
|
+
def validation_matcher_scenario_args
|
93
|
+
super.deep_merge(model_creator: :active_model)
|
94
|
+
end
|
54
95
|
end
|
55
96
|
|
56
97
|
context 'an ActiveModel class without an absence validation' do
|
57
|
-
it 'rejects' do
|
58
|
-
|
59
|
-
|
98
|
+
it 'rejects with the correct failure message' do
|
99
|
+
message = <<-MESSAGE
|
100
|
+
Example did not properly validate that :attr is empty/falsy.
|
101
|
+
After setting :attr to ‹"an arbitrary value"›, the matcher expected
|
102
|
+
the Example to be invalid, but it was valid instead.
|
103
|
+
MESSAGE
|
60
104
|
|
61
|
-
|
62
|
-
|
105
|
+
assertion = lambda do
|
106
|
+
expect(active_model_with(:attr)).to validate_absence_of(:attr)
|
107
|
+
end
|
63
108
|
|
64
|
-
expect
|
109
|
+
expect(&assertion).to fail_with_message(message)
|
65
110
|
end
|
66
111
|
end
|
67
112
|
|
@@ -69,6 +114,19 @@ describe Shoulda::Matchers::ActiveModel::ValidateAbsenceOfMatcher, type: :model
|
|
69
114
|
it 'requires the attribute to not be set' do
|
70
115
|
expect(having_many(:children, absence: true)).to validate_absence_of(:children)
|
71
116
|
end
|
117
|
+
|
118
|
+
it_supports(
|
119
|
+
'ignoring_interference_by_writer',
|
120
|
+
tests: {
|
121
|
+
accept_if_qualified_but_changing_value_does_not_interfere: {
|
122
|
+
changing_values_with: :next_value
|
123
|
+
},
|
124
|
+
}
|
125
|
+
)
|
126
|
+
|
127
|
+
def validation_matcher_scenario_args
|
128
|
+
super.deep_merge(model_creator: :"active_record/has_many")
|
129
|
+
end
|
72
130
|
end
|
73
131
|
|
74
132
|
context 'a has_many association without an absence validation' do
|
@@ -83,12 +141,36 @@ describe Shoulda::Matchers::ActiveModel::ValidateAbsenceOfMatcher, type: :model
|
|
83
141
|
model = having_and_belonging_to_many(:children, absence: true)
|
84
142
|
expect(model).to validate_absence_of(:children)
|
85
143
|
end
|
144
|
+
|
145
|
+
it_supports(
|
146
|
+
'ignoring_interference_by_writer',
|
147
|
+
tests: {
|
148
|
+
accept_if_qualified_but_changing_value_does_not_interfere: {
|
149
|
+
changing_values_with: :next_value
|
150
|
+
},
|
151
|
+
}
|
152
|
+
)
|
153
|
+
|
154
|
+
def validation_matcher_scenario_args
|
155
|
+
super.deep_merge(model_creator: :"active_record/habtm")
|
156
|
+
end
|
86
157
|
end
|
87
158
|
|
88
159
|
context 'a non-absent has_and_belongs_to_many association' do
|
89
|
-
it 'rejects' do
|
160
|
+
it 'rejects with the correct failure message' do
|
90
161
|
model = having_and_belonging_to_many(:children, absence: false)
|
91
|
-
|
162
|
+
|
163
|
+
message = <<-MESSAGE
|
164
|
+
Parent did not properly validate that :children is empty/falsy.
|
165
|
+
After setting :children to ‹[#<Child id: nil>]›, the matcher expected
|
166
|
+
the Parent to be invalid, but it was valid instead.
|
167
|
+
MESSAGE
|
168
|
+
|
169
|
+
assertion = lambda do
|
170
|
+
expect(model).to validate_absence_of(:children)
|
171
|
+
end
|
172
|
+
|
173
|
+
expect(&assertion).to fail_with_message(message)
|
92
174
|
end
|
93
175
|
end
|
94
176
|
|
@@ -119,14 +201,28 @@ describe Shoulda::Matchers::ActiveModel::ValidateAbsenceOfMatcher, type: :model
|
|
119
201
|
end
|
120
202
|
end
|
121
203
|
|
122
|
-
def
|
204
|
+
def define_model_validating_absence_of(attr, validation_options = {}, given_column_options = {})
|
123
205
|
default_column_options = { type: :string, options: {} }
|
124
206
|
column_options = default_column_options.merge(given_column_options)
|
125
207
|
|
126
|
-
define_model :example, attr => column_options do
|
127
|
-
validates_absence_of
|
128
|
-
|
208
|
+
define_model :example, attr => column_options do |model|
|
209
|
+
model.validates_absence_of(attr, validation_options)
|
210
|
+
|
211
|
+
if block_given?
|
212
|
+
yield model
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def validating_absence_of(attr, validation_options = {}, given_column_options = {})
|
218
|
+
model = define_model_validating_absence_of(
|
219
|
+
attr,
|
220
|
+
validation_options,
|
221
|
+
given_column_options
|
222
|
+
)
|
223
|
+
model.new
|
129
224
|
end
|
225
|
+
alias_method :build_record_validating_absence_of, :validating_absence_of
|
130
226
|
|
131
227
|
def active_model_with(attr, &block)
|
132
228
|
define_active_model_class('Example', accessors: [attr], &block).new
|
@@ -162,5 +258,9 @@ describe Shoulda::Matchers::ActiveModel::ValidateAbsenceOfMatcher, type: :model
|
|
162
258
|
end
|
163
259
|
end.new
|
164
260
|
end
|
261
|
+
|
262
|
+
def validation_matcher_scenario_args
|
263
|
+
super.deep_merge(matcher_name: :validate_absence_of)
|
264
|
+
end
|
165
265
|
end
|
166
266
|
end
|
@@ -9,6 +9,32 @@ describe Shoulda::Matchers::ActiveModel::ValidateAcceptanceOfMatcher, type: :mod
|
|
9
9
|
it 'does not overwrite the default message with nil' do
|
10
10
|
expect(record_validating_acceptance).to matcher.with_message(nil)
|
11
11
|
end
|
12
|
+
|
13
|
+
it_supports(
|
14
|
+
'ignoring_interference_by_writer',
|
15
|
+
tests: {
|
16
|
+
accept_if_qualified_but_changing_value_does_not_interfere: {
|
17
|
+
changing_values_with: :never_falsy,
|
18
|
+
},
|
19
|
+
reject_if_qualified_but_changing_value_interferes: {
|
20
|
+
model_name: 'Example',
|
21
|
+
attribute_name: :attr,
|
22
|
+
changing_values_with: :always_nil,
|
23
|
+
expected_message: <<-MESSAGE.strip
|
24
|
+
Example did not properly validate that :attr has been set to "1".
|
25
|
+
After setting :attr to ‹false› -- which was read back as ‹nil› -- the
|
26
|
+
matcher expected the Example to be invalid, but it was valid instead.
|
27
|
+
|
28
|
+
As indicated in the message above, :attr seems to be changing certain
|
29
|
+
values as they are set, and this could have something to do with why
|
30
|
+
this test is failing. If you've overridden the writer method for this
|
31
|
+
attribute, then you may need to change it to make this test pass, or
|
32
|
+
do something else entirely.
|
33
|
+
MESSAGE
|
34
|
+
},
|
35
|
+
},
|
36
|
+
model_creator: :active_model
|
37
|
+
)
|
12
38
|
end
|
13
39
|
|
14
40
|
context 'a model without an acceptance validation' do
|
@@ -33,8 +59,9 @@ describe Shoulda::Matchers::ActiveModel::ValidateAcceptanceOfMatcher, type: :mod
|
|
33
59
|
validate_acceptance_of(:attr)
|
34
60
|
end
|
35
61
|
|
36
|
-
def model_validating_nothing(&block)
|
37
|
-
|
62
|
+
def model_validating_nothing(options = {}, &block)
|
63
|
+
attribute_name = options.fetch(:attribute_name, :attr)
|
64
|
+
define_active_model_class(:example, accessors: [attribute_name], &block)
|
38
65
|
end
|
39
66
|
|
40
67
|
def record_validating_nothing
|
@@ -42,12 +69,23 @@ describe Shoulda::Matchers::ActiveModel::ValidateAcceptanceOfMatcher, type: :mod
|
|
42
69
|
end
|
43
70
|
|
44
71
|
def model_validating_acceptance(options = {})
|
45
|
-
|
46
|
-
|
72
|
+
attribute_name = options.fetch(:attribute_name, :attr)
|
73
|
+
|
74
|
+
model_validating_nothing(attribute_name: attribute_name) do
|
75
|
+
validates_acceptance_of attribute_name, options
|
47
76
|
end
|
48
77
|
end
|
49
78
|
|
79
|
+
alias_method :define_model_validating_acceptance, :model_validating_acceptance
|
80
|
+
|
50
81
|
def record_validating_acceptance(options = {})
|
51
82
|
model_validating_acceptance(options).new
|
52
83
|
end
|
84
|
+
|
85
|
+
alias_method :build_record_validating_acceptance,
|
86
|
+
:record_validating_acceptance
|
87
|
+
|
88
|
+
def validation_matcher_scenario_args
|
89
|
+
{ matcher_name: :validate_acceptance_of }
|
90
|
+
end
|
53
91
|
end
|
@@ -6,7 +6,7 @@ describe Shoulda::Matchers::ActiveModel::ValidateConfirmationOfMatcher, type: :m
|
|
6
6
|
context '#description' do
|
7
7
|
it 'states that the confirmation must match its base attribute' do
|
8
8
|
builder = builder_for_record_validating_confirmation
|
9
|
-
message = "
|
9
|
+
message = "validate that :#{builder.confirmation_attribute} matches :#{builder.attribute_to_confirm}"
|
10
10
|
matcher = described_class.new(builder.attribute_to_confirm)
|
11
11
|
expect(matcher.description).to eq(message)
|
12
12
|
end
|
@@ -27,13 +27,95 @@ describe Shoulda::Matchers::ActiveModel::ValidateConfirmationOfMatcher, type: :m
|
|
27
27
|
with_message(nil)
|
28
28
|
end
|
29
29
|
end
|
30
|
+
|
31
|
+
it_supports(
|
32
|
+
'ignoring_interference_by_writer',
|
33
|
+
tests: {
|
34
|
+
reject_if_qualified_but_changing_value_interferes: {
|
35
|
+
model_name: 'Example',
|
36
|
+
attribute_name: :password,
|
37
|
+
changing_values_with: :next_value,
|
38
|
+
expected_message: <<-MESSAGE.strip
|
39
|
+
Example did not properly validate that :password_confirmation matches
|
40
|
+
:password.
|
41
|
+
After setting :password_confirmation to ‹"same value"›, then setting
|
42
|
+
:password to ‹"same value"› -- which was read back as ‹"same valuf"›
|
43
|
+
-- the matcher expected the Example to be valid, but it was invalid
|
44
|
+
instead, producing these validation errors:
|
45
|
+
|
46
|
+
* password_confirmation: ["doesn't match Password"]
|
47
|
+
|
48
|
+
As indicated in the message above, :password seems to be changing
|
49
|
+
certain values as they are set, and this could have something to do
|
50
|
+
with why this test is failing. If you've overridden the writer method
|
51
|
+
for this attribute, then you may need to change it to make this test
|
52
|
+
pass, or do something else entirely.
|
53
|
+
MESSAGE
|
54
|
+
},
|
55
|
+
},
|
56
|
+
model_creator: :active_model
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'when the model does not have a confirmation attribute' do
|
61
|
+
it 'raises an AttributeDoesNotExistError' do
|
62
|
+
model = define_model(:example)
|
63
|
+
|
64
|
+
assertion = lambda do
|
65
|
+
expect(model.new).to validate_confirmation_of(:attribute_to_confirm)
|
66
|
+
end
|
67
|
+
|
68
|
+
message = <<-MESSAGE.rstrip
|
69
|
+
The matcher attempted to set :attribute_to_confirm_confirmation on the
|
70
|
+
Example to "some value", but that attribute does not exist.
|
71
|
+
MESSAGE
|
72
|
+
|
73
|
+
expect(&assertion).to raise_error(
|
74
|
+
Shoulda::Matchers::ActiveModel::AllowValueMatcher::AttributeDoesNotExistError,
|
75
|
+
message
|
76
|
+
)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'when the model does not have the attribute under test' do
|
81
|
+
it 'raises an AttributeDoesNotExistError' do
|
82
|
+
model = define_model(:example, attribute_to_confirm_confirmation: :string)
|
83
|
+
|
84
|
+
assertion = lambda do
|
85
|
+
expect(model.new).to validate_confirmation_of(:attribute_to_confirm)
|
86
|
+
end
|
87
|
+
|
88
|
+
message = <<-MESSAGE.rstrip
|
89
|
+
The matcher attempted to set :attribute_to_confirm on the Example to
|
90
|
+
"different value", but that attribute does not exist.
|
91
|
+
MESSAGE
|
92
|
+
|
93
|
+
expect(&assertion).to raise_error(
|
94
|
+
Shoulda::Matchers::ActiveModel::AllowValueMatcher::AttributeDoesNotExistError,
|
95
|
+
message
|
96
|
+
)
|
97
|
+
end
|
30
98
|
end
|
31
99
|
|
32
|
-
context 'when the model does not have
|
33
|
-
it 'fails' do
|
34
|
-
model = define_model(:example, attribute_to_confirm: :string)
|
35
|
-
|
36
|
-
|
100
|
+
context 'when the model has all attributes, but does not have the validation' do
|
101
|
+
it 'fails with an appropriate failure message' do
|
102
|
+
model = define_model(:example, attribute_to_confirm: :string) do
|
103
|
+
attr_accessor :attribute_to_confirm_confirmation
|
104
|
+
end
|
105
|
+
|
106
|
+
assertion = lambda do
|
107
|
+
expect(model.new).to validate_confirmation_of(:attribute_to_confirm)
|
108
|
+
end
|
109
|
+
|
110
|
+
message = <<-MESSAGE
|
111
|
+
Example did not properly validate that
|
112
|
+
:attribute_to_confirm_confirmation matches :attribute_to_confirm.
|
113
|
+
After setting :attribute_to_confirm_confirmation to ‹"some value"›,
|
114
|
+
then setting :attribute_to_confirm to ‹"different value"›, the matcher
|
115
|
+
expected the Example to be invalid, but it was valid instead.
|
116
|
+
MESSAGE
|
117
|
+
|
118
|
+
expect(&assertion).to fail_with_message(message)
|
37
119
|
end
|
38
120
|
end
|
39
121
|
|
@@ -60,4 +142,8 @@ describe Shoulda::Matchers::ActiveModel::ValidateConfirmationOfMatcher, type: :m
|
|
60
142
|
to validate_confirmation_of(builder.attribute_to_confirm)
|
61
143
|
end
|
62
144
|
end
|
145
|
+
|
146
|
+
def validation_matcher_scenario_args
|
147
|
+
super.deep_merge(matcher_name: :validate_confirmation_of)
|
148
|
+
end
|
63
149
|
end
|
@@ -16,6 +16,41 @@ describe Shoulda::Matchers::ActiveModel::ValidateExclusionOfMatcher, type: :mode
|
|
16
16
|
expect(validating_exclusion(in: 2..5)).
|
17
17
|
to validate_exclusion_of(:attr).in_range(2..5).with_message(nil)
|
18
18
|
end
|
19
|
+
|
20
|
+
it_supports(
|
21
|
+
'ignoring_interference_by_writer',
|
22
|
+
tests: {
|
23
|
+
reject_if_qualified_but_changing_value_interferes: {
|
24
|
+
model_name: 'Example',
|
25
|
+
attribute_name: :attr,
|
26
|
+
changing_values_with: :next_value,
|
27
|
+
expected_message: <<-MESSAGE.strip
|
28
|
+
Example did not properly validate that :attr lies outside the range ‹2›
|
29
|
+
to ‹5›.
|
30
|
+
After setting :attr to ‹1› -- which was read back as ‹2› -- the
|
31
|
+
matcher expected the Example to be valid, but it was invalid instead,
|
32
|
+
producing these validation errors:
|
33
|
+
|
34
|
+
* attr: ["is reserved"]
|
35
|
+
|
36
|
+
As indicated in the message above, :attr seems to be changing certain
|
37
|
+
values as they are set, and this could have something to do with why
|
38
|
+
this test is failing. If you've overridden the writer method for this
|
39
|
+
attribute, then you may need to change it to make this test pass, or
|
40
|
+
do something else entirely.
|
41
|
+
MESSAGE
|
42
|
+
},
|
43
|
+
},
|
44
|
+
model_creator: :active_model
|
45
|
+
) do
|
46
|
+
def validation_matcher_scenario_args
|
47
|
+
super.deep_merge(validation_options: { in: 2..5 })
|
48
|
+
end
|
49
|
+
|
50
|
+
def configure_validation_matcher(matcher)
|
51
|
+
matcher.in_range(2..5)
|
52
|
+
end
|
53
|
+
end
|
19
54
|
end
|
20
55
|
|
21
56
|
context 'an attribute which must be excluded from a range with excluded end' do
|
@@ -57,6 +92,14 @@ describe Shoulda::Matchers::ActiveModel::ValidateExclusionOfMatcher, type: :mode
|
|
57
92
|
expect(model).to validate_exclusion_of(:attr).in_range(2...5).
|
58
93
|
with_message(/should be out of this range/)
|
59
94
|
end
|
95
|
+
|
96
|
+
it 'has correct description' do
|
97
|
+
matcher = validate_exclusion_of(:attr).in_range(1..10)
|
98
|
+
|
99
|
+
expect(matcher.description).to eq(
|
100
|
+
'validate that :attr lies outside the range ‹1› to ‹10›'
|
101
|
+
)
|
102
|
+
end
|
60
103
|
end
|
61
104
|
|
62
105
|
context 'an attribute which must be excluded from an array' do
|
@@ -75,21 +118,90 @@ describe Shoulda::Matchers::ActiveModel::ValidateExclusionOfMatcher, type: :mode
|
|
75
118
|
not_to validate_exclusion_of(:attr).in_array(%w(cat dog))
|
76
119
|
end
|
77
120
|
|
78
|
-
|
79
|
-
|
80
|
-
|
121
|
+
context 'when there is one value' do
|
122
|
+
it 'has correct description' do
|
123
|
+
expect(validate_exclusion_of(:attr).in_array([true]).description).
|
124
|
+
to eq 'validate that :attr is not ‹true›'
|
125
|
+
end
|
81
126
|
end
|
82
127
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
128
|
+
context 'when there are two values' do
|
129
|
+
it 'has correct description' do
|
130
|
+
matcher = validate_exclusion_of(:attr).in_array([true, 'dog'])
|
131
|
+
|
132
|
+
expect(matcher.description).to eq(
|
133
|
+
'validate that :attr is neither ‹true› nor ‹"dog"›'
|
134
|
+
)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'when there are three or more values' do
|
139
|
+
it 'has correct description' do
|
140
|
+
matcher = validate_exclusion_of(:attr).in_array([true, 'dog', 'cat'])
|
141
|
+
|
142
|
+
expect(matcher.description).to eq(
|
143
|
+
'validate that :attr is neither ‹true›, ‹"dog"›, nor ‹"cat"›'
|
144
|
+
)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
it_supports(
|
149
|
+
'ignoring_interference_by_writer',
|
150
|
+
tests: {
|
151
|
+
reject_if_qualified_but_changing_value_interferes: {
|
152
|
+
model_name: 'Example',
|
153
|
+
attribute_name: :attr,
|
154
|
+
changing_values_with: :next_value,
|
155
|
+
expected_message: <<-MESSAGE.strip
|
156
|
+
Example did not properly validate that :attr is neither ‹"one"› nor
|
157
|
+
‹"two"›.
|
158
|
+
After setting :attr to ‹"one"› -- which was read back as ‹"onf"› --
|
159
|
+
the matcher expected the Example to be invalid, but it was valid
|
160
|
+
instead.
|
161
|
+
|
162
|
+
As indicated in the message above, :attr seems to be changing certain
|
163
|
+
values as they are set, and this could have something to do with why
|
164
|
+
this test is failing. If you've overridden the writer method for this
|
165
|
+
attribute, then you may need to change it to make this test pass, or
|
166
|
+
do something else entirely.
|
167
|
+
MESSAGE
|
168
|
+
},
|
169
|
+
},
|
170
|
+
model_creator: :active_model
|
171
|
+
) do
|
172
|
+
def validation_matcher_scenario_args
|
173
|
+
super.deep_merge(validation_options: { in: ['one', 'two'] })
|
174
|
+
end
|
175
|
+
|
176
|
+
def configure_validation_matcher(matcher)
|
177
|
+
matcher.in_array(['one', 'two'])
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def define_model_validating_exclusion(options)
|
182
|
+
options = options.dup
|
183
|
+
column_type = options.delete(:column_type) { :string }
|
184
|
+
super options.merge(column_type: column_type)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def define_model_validating_exclusion(options)
|
189
|
+
options = options.dup
|
190
|
+
attribute_name = options.delete(:attribute_name) { :attr }
|
191
|
+
column_type = options.delete(:column_type) { :integer }
|
192
|
+
|
193
|
+
define_model(:example, attribute_name => column_type) do |model|
|
194
|
+
model.validates_exclusion_of(attribute_name, options)
|
87
195
|
end
|
88
196
|
end
|
89
197
|
|
90
198
|
def validating_exclusion(options)
|
91
|
-
|
92
|
-
|
93
|
-
|
199
|
+
define_model_validating_exclusion(options).new
|
200
|
+
end
|
201
|
+
|
202
|
+
alias_method :build_record_validating_exclusion, :validating_exclusion
|
203
|
+
|
204
|
+
def validation_matcher_scenario_args
|
205
|
+
super.deep_merge(matcher_name: :validate_exclusion_of)
|
94
206
|
end
|
95
207
|
end
|