mcmire-shoulda-matchers 2.5.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 +7 -0
- data/.gitignore +12 -0
- data/.travis.yml +32 -0
- data/.yardopts +7 -0
- data/Appraisals +45 -0
- data/CONTRIBUTING.md +41 -0
- data/Gemfile +31 -0
- data/Gemfile.lock +166 -0
- data/MIT-LICENSE +22 -0
- data/NEWS.md +299 -0
- data/README.md +163 -0
- data/Rakefile +116 -0
- data/doc_config/gh-pages/index.html.erb +9 -0
- data/doc_config/yard/setup.rb +22 -0
- data/doc_config/yard/templates/default/fulldoc/html/css/bootstrap.css +5967 -0
- data/doc_config/yard/templates/default/fulldoc/html/css/full_list.css +12 -0
- data/doc_config/yard/templates/default/fulldoc/html/css/global.css +45 -0
- data/doc_config/yard/templates/default/fulldoc/html/css/solarized.css +69 -0
- data/doc_config/yard/templates/default/fulldoc/html/css/style.css +283 -0
- data/doc_config/yard/templates/default/fulldoc/html/full_list.erb +32 -0
- data/doc_config/yard/templates/default/fulldoc/html/full_list_class.erb +1 -0
- data/doc_config/yard/templates/default/fulldoc/html/full_list_method.erb +8 -0
- data/doc_config/yard/templates/default/fulldoc/html/js/app.js +300 -0
- data/doc_config/yard/templates/default/fulldoc/html/js/full_list.js +1 -0
- data/doc_config/yard/templates/default/fulldoc/html/js/jquery.stickyheaders.js +289 -0
- data/doc_config/yard/templates/default/fulldoc/html/js/underscore.min.js +6 -0
- data/doc_config/yard/templates/default/fulldoc/html/setup.rb +8 -0
- data/doc_config/yard/templates/default/layout/html/breadcrumb.erb +14 -0
- data/doc_config/yard/templates/default/layout/html/fonts.erb +1 -0
- data/doc_config/yard/templates/default/layout/html/layout.erb +23 -0
- data/doc_config/yard/templates/default/layout/html/search.erb +13 -0
- data/doc_config/yard/templates/default/layout/html/setup.rb +8 -0
- data/doc_config/yard/templates/default/method_details/html/source.erb +10 -0
- data/doc_config/yard/templates/default/module/html/box_info.erb +31 -0
- data/features/rails_integration.feature +113 -0
- data/features/step_definitions/rails_steps.rb +162 -0
- data/features/support/env.rb +5 -0
- data/gemfiles/3.0.gemfile +24 -0
- data/gemfiles/3.0.gemfile.lock +150 -0
- data/gemfiles/3.1.gemfile +27 -0
- data/gemfiles/3.1.gemfile.lock +173 -0
- data/gemfiles/3.2.gemfile +27 -0
- data/gemfiles/3.2.gemfile.lock +171 -0
- data/gemfiles/4.0.0.gemfile +28 -0
- data/gemfiles/4.0.0.gemfile.lock +172 -0
- data/gemfiles/4.0.1.gemfile +28 -0
- data/gemfiles/4.0.1.gemfile.lock +172 -0
- data/lib/shoulda-matchers.rb +1 -0
- data/lib/shoulda/matchers.rb +11 -0
- data/lib/shoulda/matchers/action_controller.rb +17 -0
- data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +64 -0
- data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +97 -0
- data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +81 -0
- data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +117 -0
- data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +114 -0
- data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +154 -0
- data/lib/shoulda/matchers/action_controller/route_matcher.rb +116 -0
- data/lib/shoulda/matchers/action_controller/route_params.rb +48 -0
- data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +164 -0
- data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +296 -0
- data/lib/shoulda/matchers/active_model.rb +30 -0
- data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +167 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +314 -0
- data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +46 -0
- data/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb +160 -0
- data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +417 -0
- data/lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb +337 -0
- data/lib/shoulda/matchers/active_model/errors.rb +10 -0
- data/lib/shoulda/matchers/active_model/exception_message_finder.rb +58 -0
- data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +92 -0
- data/lib/shoulda/matchers/active_model/helpers.rb +46 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers.rb +9 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +75 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +27 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +41 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +27 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +26 -0
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +112 -0
- data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +77 -0
- data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +121 -0
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +380 -0
- data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +89 -0
- data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +372 -0
- data/lib/shoulda/matchers/active_model/validation_matcher.rb +97 -0
- data/lib/shoulda/matchers/active_model/validation_message_finder.rb +69 -0
- data/lib/shoulda/matchers/active_record.rb +22 -0
- data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +204 -0
- data/lib/shoulda/matchers/active_record/association_matcher.rb +901 -0
- data/lib/shoulda/matchers/active_record/association_matchers.rb +9 -0
- data/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +41 -0
- data/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +41 -0
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +81 -0
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +65 -0
- data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +94 -0
- data/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +41 -0
- data/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +41 -0
- data/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +63 -0
- data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +261 -0
- data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +149 -0
- data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +72 -0
- data/lib/shoulda/matchers/active_record/serialize_matcher.rb +181 -0
- data/lib/shoulda/matchers/assertion_error.rb +19 -0
- data/lib/shoulda/matchers/error.rb +6 -0
- data/lib/shoulda/matchers/integrations/rspec.rb +20 -0
- data/lib/shoulda/matchers/integrations/test_unit.rb +30 -0
- data/lib/shoulda/matchers/rails_shim.rb +50 -0
- data/lib/shoulda/matchers/version.rb +6 -0
- data/lib/shoulda/matchers/warn.rb +8 -0
- data/shoulda-matchers.gemspec +23 -0
- data/spec/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +22 -0
- data/spec/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +42 -0
- data/spec/shoulda/matchers/action_controller/render_template_matcher_spec.rb +78 -0
- data/spec/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +63 -0
- data/spec/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb +63 -0
- data/spec/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +31 -0
- data/spec/shoulda/matchers/action_controller/route_matcher_spec.rb +70 -0
- data/spec/shoulda/matchers/action_controller/route_params_spec.rb +30 -0
- data/spec/shoulda/matchers/action_controller/set_session_matcher_spec.rb +51 -0
- data/spec/shoulda/matchers/action_controller/set_the_flash_matcher_spec.rb +153 -0
- data/spec/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +111 -0
- data/spec/shoulda/matchers/active_model/allow_value_matcher_spec.rb +170 -0
- data/spec/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +81 -0
- data/spec/shoulda/matchers/active_model/ensure_exclusion_of_matcher_spec.rb +95 -0
- data/spec/shoulda/matchers/active_model/ensure_inclusion_of_matcher_spec.rb +320 -0
- data/spec/shoulda/matchers/active_model/ensure_length_of_matcher_spec.rb +166 -0
- data/spec/shoulda/matchers/active_model/exception_message_finder_spec.rb +111 -0
- data/spec/shoulda/matchers/active_model/have_secure_password_matcher_spec.rb +20 -0
- data/spec/shoulda/matchers/active_model/helpers_spec.rb +158 -0
- data/spec/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +169 -0
- data/spec/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb +59 -0
- data/spec/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb +59 -0
- data/spec/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb +57 -0
- data/spec/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +139 -0
- data/spec/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +41 -0
- data/spec/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +47 -0
- data/spec/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +331 -0
- data/spec/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +180 -0
- data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +398 -0
- data/spec/shoulda/matchers/active_model/validation_message_finder_spec.rb +127 -0
- data/spec/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb +107 -0
- data/spec/shoulda/matchers/active_record/association_matcher_spec.rb +860 -0
- data/spec/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +247 -0
- data/spec/shoulda/matchers/active_record/have_db_column_matcher_spec.rb +111 -0
- data/spec/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +78 -0
- data/spec/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb +41 -0
- data/spec/shoulda/matchers/active_record/serialize_matcher_spec.rb +86 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/support/active_model_versions.rb +13 -0
- data/spec/support/active_resource_builder.rb +29 -0
- data/spec/support/activemodel_helpers.rb +19 -0
- data/spec/support/capture_helpers.rb +19 -0
- data/spec/support/class_builder.rb +42 -0
- data/spec/support/controller_builder.rb +74 -0
- data/spec/support/fail_with_message_including_matcher.rb +33 -0
- data/spec/support/fail_with_message_matcher.rb +32 -0
- data/spec/support/i18n_faker.rb +10 -0
- data/spec/support/mailer_builder.rb +10 -0
- data/spec/support/model_builder.rb +81 -0
- data/spec/support/rails_versions.rb +18 -0
- data/spec/support/shared_examples/numerical_submatcher.rb +19 -0
- data/spec/support/shared_examples/numerical_type_submatcher.rb +17 -0
- data/spec/support/test_application.rb +120 -0
- data/yard.watchr +5 -0
- metadata +281 -0
@@ -0,0 +1,337 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
module ActiveModel
|
4
|
+
# The `ensure_length_of` matcher tests usage of the `validates_length_of`
|
5
|
+
# matcher. Note that this matcher is intended to be used against string
|
6
|
+
# columns and not integer columns.
|
7
|
+
#
|
8
|
+
# #### Qualifiers
|
9
|
+
#
|
10
|
+
# One of `is_equal_to`, `is_at_least`, or `is_at_most` must be used.
|
11
|
+
#
|
12
|
+
# ##### is_at_least
|
13
|
+
#
|
14
|
+
# Use `is_at_least` to test usage of the `:minimum` option. This asserts
|
15
|
+
# that the attribute can take a string which is equal to or longer than
|
16
|
+
# the given length and cannot take a string which is shorter.
|
17
|
+
#
|
18
|
+
# class User
|
19
|
+
# include ActiveModel::Model
|
20
|
+
#
|
21
|
+
# validates_length_of :bio, minimum: 15
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# # RSpec
|
25
|
+
#
|
26
|
+
# describe User do
|
27
|
+
# it { should ensure_length_of(:bio).is_at_least(15) }
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# # Test::Unit
|
31
|
+
#
|
32
|
+
# class UserTest < ActiveSupport::TestCase
|
33
|
+
# should ensure_length_of(:bio).is_at_least(15)
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# ##### is_at_most
|
37
|
+
#
|
38
|
+
# Use `is_at_most` to test usage of the `:maximum` option. This asserts
|
39
|
+
# that the attribute can take a string which is equal to or shorter than
|
40
|
+
# the given length and cannot take a string which is longer.
|
41
|
+
#
|
42
|
+
# class User
|
43
|
+
# include ActiveModel::Model
|
44
|
+
#
|
45
|
+
# validates_length_of :status_update, maximum: 140
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# # RSpec
|
49
|
+
# describe User do
|
50
|
+
# it { should ensure_length_of(:status_update).is_at_most(140) }
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# # Test::Unit
|
54
|
+
# class UserTest < ActiveSupport::TestCase
|
55
|
+
# should ensure_length_of(:status_update).is_at_most(140)
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# ##### is_equal_to
|
59
|
+
#
|
60
|
+
# Use `is_at_equal` to test usage of the `:is` option. This asserts that
|
61
|
+
# the attribute can take a string which is exactly equal to the given
|
62
|
+
# length and cannot take a string which is shorter or longer.
|
63
|
+
#
|
64
|
+
# class User
|
65
|
+
# include ActiveModel::Model
|
66
|
+
#
|
67
|
+
# validates_length_of :favorite_superhero, is: 6
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# # RSpec
|
71
|
+
# describe User do
|
72
|
+
# it { should ensure_length_of(:favorite_superhero).is_equal_to(6) }
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# # Test::Unit
|
76
|
+
# class UserTest < ActiveSupport::TestCase
|
77
|
+
# should ensure_length_of(:favorite_superhero).is_equal_to(6)
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# ##### is_at_least + is_at_most
|
81
|
+
#
|
82
|
+
# Use `is_at_least` and `is_at_most` to test usage of the `:in` option.
|
83
|
+
#
|
84
|
+
# class User
|
85
|
+
# include ActiveModel::Model
|
86
|
+
#
|
87
|
+
# validates_length_of :password, in: 5..30
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# # RSpec
|
91
|
+
# describe User do
|
92
|
+
# it { should ensure_length_of(:password).is_at_least(5).is_at_most(30) }
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# # Test::Unit
|
96
|
+
# class UserTest < ActiveSupport::TestCase
|
97
|
+
# should ensure_length_of(:password).is_at_least(5).is_at_most(30)
|
98
|
+
# end
|
99
|
+
#
|
100
|
+
# ##### with_message
|
101
|
+
#
|
102
|
+
# Use `with_message` if you are using a custom validation message.
|
103
|
+
#
|
104
|
+
# class User
|
105
|
+
# include ActiveModel::Model
|
106
|
+
#
|
107
|
+
# validates_length_of :api_token,
|
108
|
+
# minimum: 10,
|
109
|
+
# message: "Password isn't long enough"
|
110
|
+
# end
|
111
|
+
#
|
112
|
+
# # RSpec
|
113
|
+
# describe User do
|
114
|
+
# it do
|
115
|
+
# should ensure_length_of(:password).
|
116
|
+
# is_at_least(10).
|
117
|
+
# with_message("Password isn't long enough")
|
118
|
+
# end
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# # Test::Unit
|
122
|
+
# class UserTest < ActiveSupport::TestCase
|
123
|
+
# should ensure_length_of(:password).
|
124
|
+
# is_at_least(10).
|
125
|
+
# with_message("Password isn't long enough")
|
126
|
+
# end
|
127
|
+
#
|
128
|
+
# ##### with_short_message
|
129
|
+
#
|
130
|
+
# Use `with_short_message` if you are using a custom "too short" message.
|
131
|
+
#
|
132
|
+
# class User
|
133
|
+
# include ActiveModel::Model
|
134
|
+
#
|
135
|
+
# validates_length_of :secret_key,
|
136
|
+
# in: 15..100,
|
137
|
+
# too_short: 'Secret key must be more than 15 characters'
|
138
|
+
# end
|
139
|
+
#
|
140
|
+
# # RSpec
|
141
|
+
# describe User do
|
142
|
+
# it do
|
143
|
+
# should ensure_length_of(:secret_key).
|
144
|
+
# is_at_least(15).
|
145
|
+
# with_short_message('Secret key must be more than 15 characters')
|
146
|
+
# end
|
147
|
+
# end
|
148
|
+
#
|
149
|
+
# # Test::Unit
|
150
|
+
# class UserTest < ActiveSupport::TestCase
|
151
|
+
# should ensure_length_of(:secret_key).
|
152
|
+
# is_at_least(15).
|
153
|
+
# with_short_message('Secret key must be more than 15 characters')
|
154
|
+
# end
|
155
|
+
#
|
156
|
+
# ##### with_long_message
|
157
|
+
#
|
158
|
+
# Use `with_long_message` if you are using a custom "too long" message.
|
159
|
+
#
|
160
|
+
# class User
|
161
|
+
# include ActiveModel::Model
|
162
|
+
#
|
163
|
+
# validates_length_of :secret_key,
|
164
|
+
# in: 15..100,
|
165
|
+
# too_long: 'Secret key must be less than 100 characters'
|
166
|
+
# end
|
167
|
+
#
|
168
|
+
# # RSpec
|
169
|
+
# describe User do
|
170
|
+
# it do
|
171
|
+
# should ensure_length_of(:secret_key).
|
172
|
+
# is_at_most(100).
|
173
|
+
# with_long_message('Secret key must be less than 100 characters')
|
174
|
+
# end
|
175
|
+
# end
|
176
|
+
#
|
177
|
+
# # Test::Unit
|
178
|
+
# class UserTest < ActiveSupport::TestCase
|
179
|
+
# should ensure_length_of(:secret_key).
|
180
|
+
# is_at_most(100).
|
181
|
+
# with_long_message('Secret key must be less than 100 characters')
|
182
|
+
# end
|
183
|
+
#
|
184
|
+
# @return [EnsureLengthOfMatcher]
|
185
|
+
#
|
186
|
+
def ensure_length_of(attr)
|
187
|
+
EnsureLengthOfMatcher.new(attr)
|
188
|
+
end
|
189
|
+
|
190
|
+
# @private
|
191
|
+
class EnsureLengthOfMatcher < ValidationMatcher
|
192
|
+
include Helpers
|
193
|
+
|
194
|
+
def initialize(attribute)
|
195
|
+
super(attribute)
|
196
|
+
@options = {}
|
197
|
+
end
|
198
|
+
|
199
|
+
def is_at_least(length)
|
200
|
+
@options[:minimum] = length
|
201
|
+
@short_message ||= :too_short
|
202
|
+
self
|
203
|
+
end
|
204
|
+
|
205
|
+
def is_at_most(length)
|
206
|
+
@options[:maximum] = length
|
207
|
+
@long_message ||= :too_long
|
208
|
+
self
|
209
|
+
end
|
210
|
+
|
211
|
+
def is_equal_to(length)
|
212
|
+
@options[:minimum] = length
|
213
|
+
@options[:maximum] = length
|
214
|
+
@short_message ||= :wrong_length
|
215
|
+
@long_message ||= :wrong_length
|
216
|
+
self
|
217
|
+
end
|
218
|
+
|
219
|
+
def with_short_message(message)
|
220
|
+
if message
|
221
|
+
@short_message = message
|
222
|
+
end
|
223
|
+
self
|
224
|
+
end
|
225
|
+
|
226
|
+
def with_long_message(message)
|
227
|
+
if message
|
228
|
+
@long_message = message
|
229
|
+
end
|
230
|
+
self
|
231
|
+
end
|
232
|
+
|
233
|
+
def with_message(message)
|
234
|
+
if message
|
235
|
+
@short_message = message
|
236
|
+
@long_message = message
|
237
|
+
end
|
238
|
+
self
|
239
|
+
end
|
240
|
+
|
241
|
+
def description
|
242
|
+
description = "ensure #{@attribute} has a length "
|
243
|
+
if @options.key?(:minimum) && @options.key?(:maximum)
|
244
|
+
if @options[:minimum] == @options[:maximum]
|
245
|
+
description << "of exactly #{@options[:minimum]}"
|
246
|
+
else
|
247
|
+
description << "between #{@options[:minimum]} and #{@options[:maximum]}"
|
248
|
+
end
|
249
|
+
else
|
250
|
+
description << "of at least #{@options[:minimum]}" if @options[:minimum]
|
251
|
+
description << "of at most #{@options[:maximum]}" if @options[:maximum]
|
252
|
+
end
|
253
|
+
description
|
254
|
+
end
|
255
|
+
|
256
|
+
def matches?(subject)
|
257
|
+
super(subject)
|
258
|
+
translate_messages!
|
259
|
+
lower_bound_matches? && upper_bound_matches?
|
260
|
+
end
|
261
|
+
|
262
|
+
private
|
263
|
+
|
264
|
+
def translate_messages!
|
265
|
+
if Symbol === @short_message
|
266
|
+
@short_message = default_error_message(@short_message,
|
267
|
+
model_name: @subject.class.to_s.underscore,
|
268
|
+
instance: @subject,
|
269
|
+
attribute: @attribute,
|
270
|
+
count: @options[:minimum])
|
271
|
+
end
|
272
|
+
|
273
|
+
if Symbol === @long_message
|
274
|
+
@long_message = default_error_message(@long_message,
|
275
|
+
model_name: @subject.class.to_s.underscore,
|
276
|
+
instance: @subject,
|
277
|
+
attribute: @attribute,
|
278
|
+
count: @options[:maximum])
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def lower_bound_matches?
|
283
|
+
disallows_lower_length? && allows_minimum_length?
|
284
|
+
end
|
285
|
+
|
286
|
+
def upper_bound_matches?
|
287
|
+
disallows_higher_length? && allows_maximum_length?
|
288
|
+
end
|
289
|
+
|
290
|
+
def disallows_lower_length?
|
291
|
+
if @options.key?(:minimum)
|
292
|
+
@options[:minimum] == 0 ||
|
293
|
+
disallows_length_of?(@options[:minimum] - 1, @short_message)
|
294
|
+
else
|
295
|
+
true
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def disallows_higher_length?
|
300
|
+
if @options.key?(:maximum)
|
301
|
+
disallows_length_of?(@options[:maximum] + 1, @long_message)
|
302
|
+
else
|
303
|
+
true
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
def allows_minimum_length?
|
308
|
+
if @options.key?(:minimum)
|
309
|
+
allows_length_of?(@options[:minimum], @short_message)
|
310
|
+
else
|
311
|
+
true
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
def allows_maximum_length?
|
316
|
+
if @options.key?(:maximum)
|
317
|
+
allows_length_of?(@options[:maximum], @long_message)
|
318
|
+
else
|
319
|
+
true
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
def allows_length_of?(length, message)
|
324
|
+
allows_value_of(string_of_length(length), message)
|
325
|
+
end
|
326
|
+
|
327
|
+
def disallows_length_of?(length, message)
|
328
|
+
disallows_value_of(string_of_length(length), message)
|
329
|
+
end
|
330
|
+
|
331
|
+
def string_of_length(length)
|
332
|
+
'x' * length
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
module ActiveModel
|
4
|
+
# @private
|
5
|
+
class ExceptionMessageFinder
|
6
|
+
def initialize(instance, attribute, context=nil)
|
7
|
+
@instance = instance
|
8
|
+
@attribute = attribute
|
9
|
+
@context = context
|
10
|
+
end
|
11
|
+
|
12
|
+
def allow_description(allowed_values)
|
13
|
+
"doesn't raise when #{@attribute} is set to #{allowed_values}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def messages_description
|
17
|
+
if has_messages?
|
18
|
+
messages.join
|
19
|
+
else
|
20
|
+
'no exception'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def has_messages?
|
25
|
+
messages.any?
|
26
|
+
end
|
27
|
+
|
28
|
+
def messages
|
29
|
+
@messages ||= validate_and_rescue
|
30
|
+
end
|
31
|
+
|
32
|
+
def source_description
|
33
|
+
'exception'
|
34
|
+
end
|
35
|
+
|
36
|
+
def expected_message_from(attribute_message)
|
37
|
+
"#{human_attribute_name} #{attribute_message}"
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def validate_and_rescue
|
43
|
+
@instance.valid?(@context)
|
44
|
+
[]
|
45
|
+
rescue ::ActiveModel::StrictValidationFailed => exception
|
46
|
+
[exception.message]
|
47
|
+
end
|
48
|
+
|
49
|
+
def human_attribute_name
|
50
|
+
@instance.class.human_attribute_name(@attribute)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
module ActiveModel
|
4
|
+
# The `have_secure_password` matcher tests usage of the
|
5
|
+
# `has_secure_password` macro.
|
6
|
+
#
|
7
|
+
# #### Example
|
8
|
+
#
|
9
|
+
# class User
|
10
|
+
# include ActiveModel::Model
|
11
|
+
#
|
12
|
+
# has_secure_password
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# # RSpec
|
16
|
+
# describe User do
|
17
|
+
# it { should have_secure_password }
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# # Test::Unit
|
21
|
+
# class UserTest < ActiveSupport::TestCase
|
22
|
+
# should have_secure_password
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# @return [HaveSecurePasswordMatcher]
|
26
|
+
#
|
27
|
+
def have_secure_password
|
28
|
+
HaveSecurePasswordMatcher.new
|
29
|
+
end
|
30
|
+
|
31
|
+
# @private
|
32
|
+
class HaveSecurePasswordMatcher
|
33
|
+
attr_reader :failure_message
|
34
|
+
|
35
|
+
alias failure_message_for_should failure_message
|
36
|
+
|
37
|
+
CORRECT_PASSWORD = "aBcDe12345"
|
38
|
+
INCORRECT_PASSWORD = "password"
|
39
|
+
|
40
|
+
EXPECTED_METHODS = [
|
41
|
+
:authenticate,
|
42
|
+
:password=,
|
43
|
+
:password_confirmation=,
|
44
|
+
:password_digest,
|
45
|
+
:password_digest=,
|
46
|
+
]
|
47
|
+
|
48
|
+
MESSAGES = {
|
49
|
+
authenticated_incorrect_password: "expected %{subject} to not authenticate an incorrect password",
|
50
|
+
did_not_authenticate_correct_password: "expected %{subject} to authenticate the correct password",
|
51
|
+
method_not_found: "expected %{subject} to respond to %{methods}"
|
52
|
+
}
|
53
|
+
|
54
|
+
def description
|
55
|
+
"have a secure password"
|
56
|
+
end
|
57
|
+
|
58
|
+
def matches?(subject)
|
59
|
+
@subject = subject
|
60
|
+
|
61
|
+
if failure = validate
|
62
|
+
key, params = failure
|
63
|
+
@failure_message = MESSAGES[key] % { subject: subject.class }.merge(params)
|
64
|
+
end
|
65
|
+
|
66
|
+
failure.nil?
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
attr_reader :subject
|
72
|
+
|
73
|
+
def validate
|
74
|
+
missing_methods = EXPECTED_METHODS.select {|m| !subject.respond_to?(m) }
|
75
|
+
|
76
|
+
if missing_methods.present?
|
77
|
+
[:method_not_found, { methods: missing_methods.to_sentence }]
|
78
|
+
else
|
79
|
+
subject.password = CORRECT_PASSWORD
|
80
|
+
subject.password_confirmation = CORRECT_PASSWORD
|
81
|
+
|
82
|
+
if not subject.authenticate(CORRECT_PASSWORD)
|
83
|
+
[:did_not_authenticate_correct_password, {}]
|
84
|
+
elsif subject.authenticate(INCORRECT_PASSWORD)
|
85
|
+
[:authenticated_incorrect_password, {}]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|