shoulda-matchers 5.2.0 → 6.0.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 +22 -7
- data/lib/shoulda/matchers/action_controller/permit_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +9 -0
- data/lib/shoulda/matchers/active_model/comparison_matcher.rb +162 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +3 -5
- data/lib/shoulda/matchers/active_model/numericality_matchers/range_matcher.rb +71 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/submatchers.rb +58 -0
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +2 -1
- data/lib/shoulda/matchers/active_model/validate_comparison_of_matcher.rb +534 -0
- data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +5 -5
- data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +9 -6
- data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +64 -9
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +72 -80
- 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 +4 -1
- data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +0 -8
- data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +46 -6
- data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +14 -3
- data/lib/shoulda/matchers/active_record/have_implicit_order_column.rb +3 -5
- data/lib/shoulda/matchers/active_record/normalize_matcher.rb +151 -0
- data/lib/shoulda/matchers/active_record.rb +1 -0
- data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +1 -1
- data/lib/shoulda/matchers/rails_shim.rb +10 -8
- data/lib/shoulda/matchers/util/word_wrap.rb +2 -2
- data/lib/shoulda/matchers/util.rb +1 -1
- data/lib/shoulda/matchers/version.rb +1 -1
- data/lib/shoulda/matchers.rb +2 -2
- data/shoulda-matchers.gemspec +1 -1
- metadata +12 -8
- data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +0 -157
@@ -0,0 +1,534 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
module ActiveModel
|
4
|
+
# The `validate_comparison_of` matcher tests usage of the
|
5
|
+
# `validates_comparison_of` validation.
|
6
|
+
#
|
7
|
+
# class Person
|
8
|
+
# include ActiveModel::Model
|
9
|
+
# attr_accessor :gpa
|
10
|
+
#
|
11
|
+
# validates_comparison_of :gpa, greater_than: 10
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# # RSpec
|
15
|
+
# RSpec.describe Person, type: :model do
|
16
|
+
# it { should validate_comparison_of(:gpa).greater_than(10) }
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# # Minitest (Shoulda)
|
20
|
+
# class PersonTest < ActiveSupport::TestCase
|
21
|
+
# should validate_comparison_of(:gpa).greater_than(10)
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# #### Qualifiers
|
25
|
+
#
|
26
|
+
# ##### on
|
27
|
+
#
|
28
|
+
# Use `on` if your validation applies only under a certain context.
|
29
|
+
#
|
30
|
+
# class Person
|
31
|
+
# include ActiveModel::Model
|
32
|
+
# attribute :number_of_dependents, :integer
|
33
|
+
# attr_accessor :number_of_dependents
|
34
|
+
#
|
35
|
+
# validates_comparison_of :number_of_dependents, on: :create, greater_than: 0
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# # RSpec
|
39
|
+
# RSpec.describe Person, type: :model do
|
40
|
+
# it do
|
41
|
+
# should validate_comparison_of(:number_of_dependents).
|
42
|
+
# greater_than(0).
|
43
|
+
# on(:create)
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# # Minitest (Shoulda)
|
48
|
+
# class PersonTest < ActiveSupport::TestCase
|
49
|
+
# should validate_comparison_of(:number_of_dependents).greater_than(0).on(:create)
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# ##### is_less_than
|
53
|
+
#
|
54
|
+
# Use `is_less_than` to test usage of the the `:less_than` option. This
|
55
|
+
# asserts that the attribute can take a value which is less than the
|
56
|
+
# given value and cannot take a value which is greater than or equal to
|
57
|
+
# it. It can also accept methods or procs that returns a given value.
|
58
|
+
#
|
59
|
+
# class Person
|
60
|
+
# include ActiveModel::Model
|
61
|
+
# attribute :number_of_cars, :integer
|
62
|
+
# attr_accessor :number_of_cars
|
63
|
+
#
|
64
|
+
# validates_comparison_of :number_of_cars, less_than: :current_number_of_cars
|
65
|
+
#
|
66
|
+
# def current_number_of_cars
|
67
|
+
# 10
|
68
|
+
# end
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# # RSpec
|
72
|
+
# RSpec.describe Person, type: :model do
|
73
|
+
# it do
|
74
|
+
# should validate_comparison_of(:number_of_cars).
|
75
|
+
# is_less_than(:current_number_of_cars)
|
76
|
+
# end
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
# # Minitest (Shoulda)
|
80
|
+
# class PersonTest < ActiveSupport::TestCase
|
81
|
+
# should validate_comparison_of(:number_of_cars).
|
82
|
+
# is_less_than(:current_number_of_cars)
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# ##### is_less_than_or_equal_to
|
86
|
+
#
|
87
|
+
# Use `is_less_than_or_equal_to` to test usage of the
|
88
|
+
# `:less_than_or_equal_to` option. This asserts that the attribute can
|
89
|
+
# take a value which is less than or equal to the given value and cannot
|
90
|
+
# take a value which is greater than it. It can also accept methods or
|
91
|
+
# procs that returns a given value.
|
92
|
+
#
|
93
|
+
# class Person
|
94
|
+
# include ActiveModel::Model
|
95
|
+
# attr_accessor :birth_date
|
96
|
+
#
|
97
|
+
# validates_comparison_of :birth_date, less_than_or_equal_to: Date.new(1987, 12, 31)
|
98
|
+
# end
|
99
|
+
#
|
100
|
+
# # RSpec
|
101
|
+
# RSpec.describe Person, type: :model do
|
102
|
+
# it do
|
103
|
+
# should validate_comparison_of(:birth_date).
|
104
|
+
# is_less_than_or_equal_to(Date.new(1987, 12, 31))
|
105
|
+
# end
|
106
|
+
# end
|
107
|
+
#
|
108
|
+
# # Minitest (Shoulda)
|
109
|
+
# class PersonTest < ActiveSupport::TestCase
|
110
|
+
# should validate_comparison_of(:birth_date).
|
111
|
+
# is_less_than_or_equal_to(Date.new(1987, 12, 31))
|
112
|
+
# end
|
113
|
+
#
|
114
|
+
# ##### is_greater_than_or_equal_to
|
115
|
+
#
|
116
|
+
# Use `is_greater_than_or_equal_to` to test usage of the
|
117
|
+
# `:greater_than_or_equal_to` option. This asserts that the attribute can
|
118
|
+
# take a value which is greater than or equal to the given value and
|
119
|
+
# cannot take a value which is less than it.
|
120
|
+
#
|
121
|
+
# class Person
|
122
|
+
# include ActiveModel::Model
|
123
|
+
# attribute :birth_date, :date
|
124
|
+
# attr_accessor :birth_date
|
125
|
+
#
|
126
|
+
# validates_comparison_of :birth_date,
|
127
|
+
# greater_than_or_equal_to: -> { 18.years.ago.to_date }
|
128
|
+
# end
|
129
|
+
#
|
130
|
+
# # RSpec
|
131
|
+
# RSpec.describe Person, type: :model do
|
132
|
+
# it do
|
133
|
+
# should validate_comparison_of(:birth_date).
|
134
|
+
# is_greater_than_or_equal_to(-> { 18.years.ago.to_date })
|
135
|
+
# end
|
136
|
+
# end
|
137
|
+
#
|
138
|
+
# # Minitest (Shoulda)
|
139
|
+
# class PersonTest < ActiveSupport::TestCase
|
140
|
+
# should validate_comparison_of(:birth_date).
|
141
|
+
# is_greater_than_or_equal_to(-> { 18.years.ago.to_date })
|
142
|
+
# end
|
143
|
+
#
|
144
|
+
# ##### is_greater_than
|
145
|
+
#
|
146
|
+
# Use `is_greater_than` to test usage of the `:greater_than` option.
|
147
|
+
# This asserts that the attribute can take a value which is greater than
|
148
|
+
# the given value and cannot take a value less than or equal to it.
|
149
|
+
# It can also accept methods or procs that returns a given value.
|
150
|
+
#
|
151
|
+
# class Person
|
152
|
+
# include ActiveModel::Model
|
153
|
+
# attribute :legal_age, :integer
|
154
|
+
# attr_accessor :legal_age
|
155
|
+
#
|
156
|
+
# validates_comparison_of :legal_age, greater_than: 21
|
157
|
+
# end
|
158
|
+
#
|
159
|
+
# # RSpec
|
160
|
+
# RSpec.describe Person, type: :model do
|
161
|
+
# it do
|
162
|
+
# should validate_comparison_of(:legal_age).
|
163
|
+
# is_greater_than(21)
|
164
|
+
# end
|
165
|
+
# end
|
166
|
+
#
|
167
|
+
# # Minitest (Shoulda)
|
168
|
+
# class PersonTest < ActiveSupport::TestCase
|
169
|
+
# should validate_comparison_of(:legal_age).
|
170
|
+
# is_greater_than(21)
|
171
|
+
# end
|
172
|
+
#
|
173
|
+
# ##### is_equal_to
|
174
|
+
#
|
175
|
+
# Use `is_equal_to` to test usage of the `:equal_to` option. This asserts
|
176
|
+
# that the attribute can take a value which is equal to the given value
|
177
|
+
# and cannot take a value which is not equal. It can also accept methods or
|
178
|
+
# procs that returns a given value.
|
179
|
+
#
|
180
|
+
# class Person
|
181
|
+
# include ActiveModel::Model
|
182
|
+
# attribute :favorite_color, :string
|
183
|
+
# attr_accessor :favorite_color
|
184
|
+
#
|
185
|
+
# validates_comparison_of :favorite_color, equal_to: "blue"
|
186
|
+
# end
|
187
|
+
#
|
188
|
+
# # RSpec
|
189
|
+
# RSpec.describe Person, type: :model do
|
190
|
+
# it { should validate_comparison_of(:favorite_color).is_equal_to("blue") }
|
191
|
+
# end
|
192
|
+
#
|
193
|
+
# # Minitest (Shoulda)
|
194
|
+
# class PersonTest < ActiveSupport::TestCase
|
195
|
+
# should validate_comparison_of(:favorite_color).is_equal_to("blue")
|
196
|
+
# end
|
197
|
+
#
|
198
|
+
#
|
199
|
+
# ##### is_other_than
|
200
|
+
#
|
201
|
+
# Use `is_other_than` to test usage of the `:other_than` option.
|
202
|
+
# This asserts that the attribute can take a number which is not equal to
|
203
|
+
# the given value.
|
204
|
+
#
|
205
|
+
# class Person
|
206
|
+
# include ActiveModel::Model
|
207
|
+
# attr_accessor :legal_age
|
208
|
+
#
|
209
|
+
# validates_comparison_of :legal_age, other_than: 21
|
210
|
+
# end
|
211
|
+
#
|
212
|
+
# # RSpec
|
213
|
+
# RSpec.describe Person, type: :model do
|
214
|
+
# it do
|
215
|
+
# should validate_comparison_of(:legal_age).
|
216
|
+
# is_other_than(21)
|
217
|
+
# end
|
218
|
+
# end
|
219
|
+
#
|
220
|
+
# # Minitest (Shoulda)
|
221
|
+
# class PersonTest < ActiveSupport::TestCase
|
222
|
+
# should validate_comparison_of(:legal_age).
|
223
|
+
# is_other_than(21)
|
224
|
+
# end
|
225
|
+
#
|
226
|
+
# ##### with_message
|
227
|
+
#
|
228
|
+
# Use `with_message` if you are using a custom validation message.
|
229
|
+
#
|
230
|
+
# class Person
|
231
|
+
# include ActiveModel::Model
|
232
|
+
# attr_accessor :number_of_dependents
|
233
|
+
#
|
234
|
+
# validates_comparison_of :number_of_dependents, greater_than: 0
|
235
|
+
# message: 'Number of dependents must be a number'
|
236
|
+
# end
|
237
|
+
#
|
238
|
+
# # RSpec
|
239
|
+
# RSpec.describe Person, type: :model do
|
240
|
+
# it do
|
241
|
+
# should validate_comparison_of(:number_of_dependents).
|
242
|
+
# is_greater_than(0).
|
243
|
+
# with_message('Number of dependents must be a number')
|
244
|
+
# end
|
245
|
+
# end
|
246
|
+
#
|
247
|
+
# # Minitest (Shoulda)
|
248
|
+
# class PersonTest < ActiveSupport::TestCase
|
249
|
+
# should validate_comparison_of(:number_of_dependents).
|
250
|
+
# is_greater_than(0).
|
251
|
+
# with_message('Number of dependents must be a number')
|
252
|
+
# end
|
253
|
+
#
|
254
|
+
# ##### allow_nil
|
255
|
+
#
|
256
|
+
# Use `allow_nil` to assert that the attribute allows nil.
|
257
|
+
#
|
258
|
+
# class Post
|
259
|
+
# include ActiveModel::Model
|
260
|
+
# attr_accessor :age
|
261
|
+
#
|
262
|
+
# validates_comparison_of :age, greater_than: 0, allow_nil: true
|
263
|
+
# end
|
264
|
+
#
|
265
|
+
# # RSpec
|
266
|
+
# RSpec.describe Post, type: :model do
|
267
|
+
# it { should validate_comparison_of(:age).is_greater_than(0).allow_nil }
|
268
|
+
# end
|
269
|
+
#
|
270
|
+
# # Minitest (Shoulda)
|
271
|
+
# class PostTest < ActiveSupport::TestCase
|
272
|
+
# should validate_comparison_of(:age).is_greater_than(0).allow_nil
|
273
|
+
# end
|
274
|
+
#
|
275
|
+
# @return [ValidateComparisonOfMatcher]
|
276
|
+
#
|
277
|
+
def validate_comparison_of(attr)
|
278
|
+
ValidateComparisonOfMatcher.new(attr)
|
279
|
+
end
|
280
|
+
|
281
|
+
# @private
|
282
|
+
class ValidateComparisonOfMatcher < ValidationMatcher
|
283
|
+
NUMERIC_NAME = 'number'.freeze
|
284
|
+
DEFAULT_DIFF_TO_COMPARE = 1
|
285
|
+
|
286
|
+
attr_reader :diff_to_compare, :number_of_submatchers
|
287
|
+
|
288
|
+
def initialize(attribute)
|
289
|
+
super
|
290
|
+
@submatchers = []
|
291
|
+
@diff_to_compare = DEFAULT_DIFF_TO_COMPARE
|
292
|
+
@expects_to_allow_nil = false
|
293
|
+
@comparison_submatcher = false
|
294
|
+
end
|
295
|
+
|
296
|
+
def allow_nil
|
297
|
+
@expects_to_allow_nil = true
|
298
|
+
prepare_submatcher(allow_value_matcher(nil))
|
299
|
+
self
|
300
|
+
end
|
301
|
+
|
302
|
+
def expects_to_allow_nil?
|
303
|
+
@expects_to_allow_nil
|
304
|
+
end
|
305
|
+
|
306
|
+
def is_greater_than(value)
|
307
|
+
prepare_submatcher(comparison_matcher_for(value, :>).for(attribute))
|
308
|
+
self
|
309
|
+
end
|
310
|
+
|
311
|
+
def is_greater_than_or_equal_to(value)
|
312
|
+
prepare_submatcher(comparison_matcher_for(value, :>=).for(attribute))
|
313
|
+
self
|
314
|
+
end
|
315
|
+
|
316
|
+
def is_equal_to(value)
|
317
|
+
prepare_submatcher(comparison_matcher_for(value, :==).for(attribute))
|
318
|
+
self
|
319
|
+
end
|
320
|
+
|
321
|
+
def is_less_than(value)
|
322
|
+
prepare_submatcher(comparison_matcher_for(value, :<).for(attribute))
|
323
|
+
self
|
324
|
+
end
|
325
|
+
|
326
|
+
def is_less_than_or_equal_to(value)
|
327
|
+
prepare_submatcher(comparison_matcher_for(value, :<=).for(attribute))
|
328
|
+
self
|
329
|
+
end
|
330
|
+
|
331
|
+
def is_other_than(value)
|
332
|
+
prepare_submatcher(comparison_matcher_for(value, :!=).for(attribute))
|
333
|
+
self
|
334
|
+
end
|
335
|
+
|
336
|
+
def matches?(subject)
|
337
|
+
@subject = subject
|
338
|
+
@number_of_submatchers = @submatchers.size
|
339
|
+
unless @comparison_matcher
|
340
|
+
raise(ArgumentError, "matcher isn't qualified with any comparison matcher")
|
341
|
+
end
|
342
|
+
|
343
|
+
qualify_submatchers
|
344
|
+
first_submatcher_that_fails_to_match.nil?
|
345
|
+
end
|
346
|
+
|
347
|
+
def does_not_match?(subject)
|
348
|
+
@subject = subject
|
349
|
+
@number_of_submatchers = @submatchers.size
|
350
|
+
|
351
|
+
qualify_submatchers
|
352
|
+
first_submatcher_that_fails_to_not_match.nil?
|
353
|
+
end
|
354
|
+
|
355
|
+
def simple_description
|
356
|
+
description = ''
|
357
|
+
|
358
|
+
description << "validate that :#{attribute} looks like "
|
359
|
+
description << Shoulda::Matchers::Util.a_or_an(allowed_type_name)
|
360
|
+
|
361
|
+
if comparison_descriptions.present?
|
362
|
+
description << " #{comparison_descriptions}"
|
363
|
+
end
|
364
|
+
|
365
|
+
description
|
366
|
+
end
|
367
|
+
|
368
|
+
def failure_message
|
369
|
+
overall_failure_message.dup.tap do |message|
|
370
|
+
message << "\n"
|
371
|
+
message << failure_message_for_first_submatcher_that_fails_to_match
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
def failure_message_when_negated
|
376
|
+
overall_failure_message_when_negated.dup.tap do |message|
|
377
|
+
message << "\n"
|
378
|
+
message <<
|
379
|
+
failure_message_for_first_submatcher_that_fails_to_not_match
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
def given_numeric_column?
|
384
|
+
attribute_is_active_record_column? &&
|
385
|
+
[:integer, :float, :decimal].include?(column_type)
|
386
|
+
end
|
387
|
+
|
388
|
+
private
|
389
|
+
|
390
|
+
def attribute_is_active_record_column?
|
391
|
+
columns_hash.key?(attribute.to_s)
|
392
|
+
end
|
393
|
+
|
394
|
+
def column_type
|
395
|
+
columns_hash[attribute.to_s].type
|
396
|
+
end
|
397
|
+
|
398
|
+
def columns_hash
|
399
|
+
if subject.class.respond_to?(:columns_hash)
|
400
|
+
subject.class.columns_hash
|
401
|
+
else
|
402
|
+
{}
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
def prepare_submatcher(submatcher)
|
407
|
+
add_submatcher(submatcher)
|
408
|
+
submatcher
|
409
|
+
end
|
410
|
+
|
411
|
+
def comparison_matcher_for(value, operator)
|
412
|
+
@comparison_matcher = true
|
413
|
+
ComparisonMatcher.
|
414
|
+
new(self, value, operator).
|
415
|
+
for(attribute)
|
416
|
+
end
|
417
|
+
|
418
|
+
def add_submatcher(submatcher)
|
419
|
+
@submatchers << submatcher
|
420
|
+
end
|
421
|
+
|
422
|
+
def qualify_submatchers
|
423
|
+
@submatchers.each do |submatcher|
|
424
|
+
if @expects_strict
|
425
|
+
submatcher.strict
|
426
|
+
end
|
427
|
+
|
428
|
+
if @expected_message.present?
|
429
|
+
submatcher.with_message(@expected_message)
|
430
|
+
end
|
431
|
+
|
432
|
+
if @context
|
433
|
+
submatcher.on(@context)
|
434
|
+
end
|
435
|
+
|
436
|
+
submatcher.ignoring_interference_by_writer(
|
437
|
+
ignore_interference_by_writer,
|
438
|
+
)
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
def number_of_submatchers_for_failure_message
|
443
|
+
if has_been_qualified?
|
444
|
+
number_of_submatchers - 1
|
445
|
+
else
|
446
|
+
number_of_submatchers
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
def has_been_qualified?
|
451
|
+
@submatchers.any? { |submatcher| submatcher_qualified?(submatcher) }
|
452
|
+
end
|
453
|
+
|
454
|
+
def submatcher_qualified?(submatcher)
|
455
|
+
submatcher.instance_of?(ComparisonMatcher)
|
456
|
+
end
|
457
|
+
|
458
|
+
def first_submatcher_that_fails_to_match
|
459
|
+
@_first_submatcher_that_fails_to_match ||=
|
460
|
+
@submatchers.detect do |submatcher|
|
461
|
+
!submatcher.matches?(subject)
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
def first_submatcher_that_fails_to_not_match
|
466
|
+
@_first_submatcher_that_fails_to_not_match ||=
|
467
|
+
@submatchers.detect do |submatcher|
|
468
|
+
!submatcher.does_not_match?(subject)
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
def failure_message_for_first_submatcher_that_fails_to_match
|
473
|
+
build_submatcher_failure_message_for(
|
474
|
+
first_submatcher_that_fails_to_match,
|
475
|
+
:failure_message,
|
476
|
+
)
|
477
|
+
end
|
478
|
+
|
479
|
+
def failure_message_for_first_submatcher_that_fails_to_not_match
|
480
|
+
build_submatcher_failure_message_for(
|
481
|
+
first_submatcher_that_fails_to_not_match,
|
482
|
+
:failure_message_when_negated,
|
483
|
+
)
|
484
|
+
end
|
485
|
+
|
486
|
+
def build_submatcher_failure_message_for(
|
487
|
+
submatcher,
|
488
|
+
failure_message_method
|
489
|
+
)
|
490
|
+
failure_message = submatcher.public_send(failure_message_method)
|
491
|
+
submatcher_description = submatcher.simple_description.
|
492
|
+
sub(/\bvalidate that\b/, 'validates').
|
493
|
+
sub(/\bdisallow\b/, 'disallows').
|
494
|
+
sub(/\ballow\b/, 'allows')
|
495
|
+
submatcher_message =
|
496
|
+
if number_of_submatchers_for_failure_message > 1
|
497
|
+
"In checking that #{model.name} #{submatcher_description}, " +
|
498
|
+
failure_message[0].downcase +
|
499
|
+
failure_message[1..]
|
500
|
+
else
|
501
|
+
failure_message
|
502
|
+
end
|
503
|
+
|
504
|
+
Shoulda::Matchers.word_wrap(submatcher_message, indent: 2)
|
505
|
+
end
|
506
|
+
|
507
|
+
def comparison_descriptions
|
508
|
+
description_array = submatcher_comparison_descriptions
|
509
|
+
if description_array.empty?
|
510
|
+
''
|
511
|
+
else
|
512
|
+
submatcher_comparison_descriptions.join(' and ')
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
def submatcher_comparison_descriptions
|
517
|
+
@submatchers.inject([]) do |arr, submatcher|
|
518
|
+
arr << if submatcher.respond_to? :comparison_description
|
519
|
+
submatcher.comparison_description
|
520
|
+
end
|
521
|
+
end
|
522
|
+
end
|
523
|
+
|
524
|
+
def allowed_type_name
|
525
|
+
'value'
|
526
|
+
end
|
527
|
+
|
528
|
+
def non_numeric_value
|
529
|
+
'abcd'
|
530
|
+
end
|
531
|
+
end
|
532
|
+
end
|
533
|
+
end
|
534
|
+
end
|
@@ -3,10 +3,10 @@ module Shoulda
|
|
3
3
|
module ActiveModel
|
4
4
|
# The `validate_exclusion_of` matcher tests usage of the
|
5
5
|
# `validates_exclusion_of` validation, asserting that an attribute cannot
|
6
|
-
# take a
|
6
|
+
# take a blocklist of values, and inversely, can take values outside of
|
7
7
|
# this list.
|
8
8
|
#
|
9
|
-
# If your
|
9
|
+
# If your blocklist an array of values, use `in_array`:
|
10
10
|
#
|
11
11
|
# class Game
|
12
12
|
# include ActiveModel::Model
|
@@ -29,13 +29,13 @@ module Shoulda
|
|
29
29
|
# in_array(['Mac', 'Linux'])
|
30
30
|
# end
|
31
31
|
#
|
32
|
-
# If your
|
32
|
+
# If your blocklist is a range of values, use `in_range`:
|
33
33
|
#
|
34
34
|
# class Game
|
35
35
|
# include ActiveModel::Model
|
36
|
-
# attr_accessor :
|
36
|
+
# attr_accessor :floors_with_enemies
|
37
37
|
#
|
38
|
-
# validates_exclusion_of :
|
38
|
+
# validates_exclusion_of :floors_with_enemies, in: 5..8
|
39
39
|
# end
|
40
40
|
#
|
41
41
|
# # RSpec
|
@@ -3,12 +3,15 @@ require 'date'
|
|
3
3
|
|
4
4
|
module Shoulda
|
5
5
|
module Matchers
|
6
|
+
# @private
|
7
|
+
class ExampleClass; end
|
8
|
+
|
6
9
|
module ActiveModel
|
7
10
|
# The `validate_inclusion_of` matcher tests usage of the
|
8
11
|
# `validates_inclusion_of` validation, asserting that an attribute can
|
9
|
-
# take a
|
12
|
+
# take a allowlist of values and cannot take values outside of this list.
|
10
13
|
#
|
11
|
-
# If your
|
14
|
+
# If your allowlist is an array of values, use `in_array`:
|
12
15
|
#
|
13
16
|
# class Issue
|
14
17
|
# include ActiveModel::Model
|
@@ -32,7 +35,7 @@ module Shoulda
|
|
32
35
|
# in_array(['open', 'resolved', 'unresolved'])
|
33
36
|
# end
|
34
37
|
#
|
35
|
-
# If your
|
38
|
+
# If your allowlist is a range of values, use `in_range`:
|
36
39
|
#
|
37
40
|
# class Issue
|
38
41
|
# include ActiveModel::Model
|
@@ -43,12 +46,12 @@ module Shoulda
|
|
43
46
|
#
|
44
47
|
# # RSpec
|
45
48
|
# RSpec.describe Issue, type: :model do
|
46
|
-
# it { should validate_inclusion_of(:
|
49
|
+
# it { should validate_inclusion_of(:priority).in_range(1..5) }
|
47
50
|
# end
|
48
51
|
#
|
49
52
|
# # Minitest (Shoulda)
|
50
53
|
# class IssueTest < ActiveSupport::TestCase
|
51
|
-
# should validate_inclusion_of(:
|
54
|
+
# should validate_inclusion_of(:priority).in_range(1..5)
|
52
55
|
# end
|
53
56
|
#
|
54
57
|
# #### Caveats
|
@@ -269,7 +272,7 @@ module Shoulda
|
|
269
272
|
# @private
|
270
273
|
class ValidateInclusionOfMatcher < ValidationMatcher
|
271
274
|
BLANK_VALUES = ['', ' ', "\n", "\r", "\t", "\f"].freeze
|
272
|
-
ARBITRARY_OUTSIDE_STRING =
|
275
|
+
ARBITRARY_OUTSIDE_STRING = Shoulda::Matchers::ExampleClass.name
|
273
276
|
ARBITRARY_OUTSIDE_INTEGER = 123456789
|
274
277
|
ARBITRARY_OUTSIDE_DECIMAL = BigDecimal('0.123456789')
|
275
278
|
ARBITRARY_OUTSIDE_DATE = Date.jd(9999999)
|