shoulda-matchers 5.2.0 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +22 -7
  4. data/lib/shoulda/matchers/action_controller/permit_matcher.rb +1 -1
  5. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +9 -0
  6. data/lib/shoulda/matchers/active_model/comparison_matcher.rb +162 -0
  7. data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +3 -5
  8. data/lib/shoulda/matchers/active_model/numericality_matchers/range_matcher.rb +71 -0
  9. data/lib/shoulda/matchers/active_model/numericality_matchers/submatchers.rb +58 -0
  10. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +2 -1
  11. data/lib/shoulda/matchers/active_model/validate_comparison_of_matcher.rb +534 -0
  12. data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +5 -5
  13. data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +9 -6
  14. data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +64 -9
  15. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +72 -80
  16. data/lib/shoulda/matchers/active_model/validation_matcher.rb +6 -0
  17. data/lib/shoulda/matchers/active_model/validator.rb +4 -0
  18. data/lib/shoulda/matchers/active_model.rb +4 -1
  19. data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +0 -8
  20. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +46 -6
  21. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +14 -3
  22. data/lib/shoulda/matchers/active_record/have_implicit_order_column.rb +3 -5
  23. data/lib/shoulda/matchers/active_record/normalize_matcher.rb +151 -0
  24. data/lib/shoulda/matchers/active_record.rb +1 -0
  25. data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +1 -1
  26. data/lib/shoulda/matchers/rails_shim.rb +10 -8
  27. data/lib/shoulda/matchers/util/word_wrap.rb +2 -2
  28. data/lib/shoulda/matchers/util.rb +1 -1
  29. data/lib/shoulda/matchers/version.rb +1 -1
  30. data/lib/shoulda/matchers.rb +2 -2
  31. data/shoulda-matchers.gemspec +1 -1
  32. metadata +12 -8
  33. data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +0 -157
@@ -3,7 +3,7 @@ module Shoulda
3
3
  module ActiveModel
4
4
  # The `validate_length_of` matcher tests usage of the
5
5
  # `validates_length_of` matcher. Note that this matcher is intended to be
6
- # used against string columns and not integer columns.
6
+ # used against string columns and associations and not integer columns.
7
7
  #
8
8
  # #### Qualifiers
9
9
  #
@@ -36,7 +36,8 @@ module Shoulda
36
36
  #
37
37
  # Use `is_at_least` to test usage of the `:minimum` option. This asserts
38
38
  # that the attribute can take a string which is equal to or longer than
39
- # the given length and cannot take a string which is shorter.
39
+ # the given length and cannot take a string which is shorter. This qualifier
40
+ # also works for associations.
40
41
  #
41
42
  # class User
42
43
  # include ActiveModel::Model
@@ -61,7 +62,8 @@ module Shoulda
61
62
  #
62
63
  # Use `is_at_most` to test usage of the `:maximum` option. This asserts
63
64
  # that the attribute can take a string which is equal to or shorter than
64
- # the given length and cannot take a string which is longer.
65
+ # the given length and cannot take a string which is longer. This qualifier
66
+ # also works for associations.
65
67
  #
66
68
  # class User
67
69
  # include ActiveModel::Model
@@ -84,7 +86,8 @@ module Shoulda
84
86
  #
85
87
  # Use `is_equal_to` to test usage of the `:is` option. This asserts that
86
88
  # the attribute can take a string which is exactly equal to the given
87
- # length and cannot take a string which is shorter or longer.
89
+ # length and cannot take a string which is shorter or longer. This qualifier
90
+ # also works for associations.
88
91
  #
89
92
  # class User
90
93
  # include ActiveModel::Model
@@ -106,7 +109,7 @@ module Shoulda
106
109
  # ##### is_at_least + is_at_most
107
110
  #
108
111
  # Use `is_at_least` and `is_at_most` together to test usage of the `:in`
109
- # option.
112
+ # option. This qualifies also works for associations.
110
113
  #
111
114
  # class User
112
115
  # include ActiveModel::Model
@@ -260,6 +263,29 @@ module Shoulda
260
263
  # should validate_length_of(:bio).is_at_least(15).allow_blank
261
264
  # end
262
265
  #
266
+ # ##### as_array
267
+ #
268
+ # Use `as_array` if you have an ActiveModel model and the attribute being validated
269
+ # is designed to store an array. (This is not necessary if you have an ActiveRecord
270
+ # model with an array column, as the matcher will detect this automatically.)
271
+ #
272
+ # class User
273
+ # include ActiveModel::Model
274
+ # attribute :arr, array: true
275
+ #
276
+ # validates_length_of :arr, minimum: 15
277
+ # end
278
+ #
279
+ # # RSpec
280
+ # describe User do
281
+ # it { should validate_length_of(:arr).as_array.is_at_least(15) }
282
+ # end
283
+ #
284
+ # # Minitest (Shoulda)
285
+ # class UserTest < ActiveSupport::TestCase
286
+ # should validate_length_of(:arr).as_array.is_at_least(15)
287
+ # end
288
+ #
263
289
  def validate_length_of(attr)
264
290
  ValidateLengthOfMatcher.new(attr)
265
291
  end
@@ -275,6 +301,11 @@ module Shoulda
275
301
  @long_message = nil
276
302
  end
277
303
 
304
+ def as_array
305
+ @options[:array] = true
306
+ self
307
+ end
308
+
278
309
  def is_at_least(length)
279
310
  @options[:minimum] = length
280
311
  @short_message ||= :too_short
@@ -451,15 +482,39 @@ module Shoulda
451
482
  end
452
483
 
453
484
  def allows_length_of?(length, message)
454
- allows_value_of(string_of_length(length), message)
485
+ allows_value_of(value_of_length(length), message)
455
486
  end
456
487
 
457
488
  def disallows_length_of?(length, message)
458
- disallows_value_of(string_of_length(length), message)
489
+ disallows_value_of(value_of_length(length), message)
490
+ end
491
+
492
+ def value_of_length(length)
493
+ if array_column?
494
+ ['x'] * length
495
+ elsif collection_association?
496
+ Array.new(length) { association_reflection.klass.new }
497
+ else
498
+ 'x' * length
499
+ end
500
+ end
501
+
502
+ def array_column?
503
+ @options[:array] || super
504
+ end
505
+
506
+ def collection_association?
507
+ association? && [:has_many, :has_and_belongs_to_many].include?(
508
+ association_reflection.macro,
509
+ )
510
+ end
511
+
512
+ def association?
513
+ association_reflection.present?
459
514
  end
460
515
 
461
- def string_of_length(length)
462
- 'x' * length
516
+ def association_reflection
517
+ model.try(:reflect_on_association, @attribute)
463
518
  end
464
519
 
465
520
  def translated_short_message
@@ -276,6 +276,33 @@ module Shoulda
276
276
  # should validate_numericality_of(:birth_day).odd
277
277
  # end
278
278
  #
279
+ # ##### is_in
280
+ #
281
+ # Use `is_in` to test usage of the `:in` option.
282
+ # This asserts that the attribute can take a number which is contained
283
+ # in the given range.
284
+ #
285
+ # class Person
286
+ # include ActiveModel::Model
287
+ # attr_accessor :legal_age
288
+ #
289
+ # validates_numericality_of :birth_month, in: 1..12
290
+ # end
291
+ #
292
+ # # RSpec
293
+ # RSpec.describe Person, type: :model do
294
+ # it do
295
+ # should validate_numericality_of(:birth_month).
296
+ # is_in(1..12)
297
+ # end
298
+ # end
299
+ #
300
+ # # Minitest (Shoulda)
301
+ # class PersonTest < ActiveSupport::TestCase
302
+ # should validate_numericality_of(:birth_month).
303
+ # is_in(1..12)
304
+ # end
305
+ #
279
306
  # ##### with_message
280
307
  #
281
308
  # Use `with_message` if you are using a custom validation message.
@@ -330,51 +357,33 @@ module Shoulda
330
357
  end
331
358
 
332
359
  # @private
333
- class ValidateNumericalityOfMatcher
360
+ class ValidateNumericalityOfMatcher < ValidationMatcher
334
361
  NUMERIC_NAME = 'number'.freeze
335
362
  DEFAULT_DIFF_TO_COMPARE = 1
336
363
 
337
- include Qualifiers::IgnoringInterferenceByWriter
338
-
339
364
  attr_reader :diff_to_compare
340
365
 
341
366
  def initialize(attribute)
342
367
  super
343
- @attribute = attribute
344
368
  @submatchers = []
345
369
  @diff_to_compare = DEFAULT_DIFF_TO_COMPARE
346
- @expects_custom_validation_message = false
347
370
  @expects_to_allow_nil = false
348
- @expects_strict = false
349
371
  @allowed_type_adjective = nil
350
372
  @allowed_type_name = 'number'
351
- @context = nil
352
- @expected_message = nil
353
- end
354
-
355
- def strict
356
- @expects_strict = true
357
- self
358
- end
359
373
 
360
- def expects_strict?
361
- @expects_strict
374
+ add_disallow_non_numeric_value_matcher
362
375
  end
363
376
 
364
377
  def only_integer
365
378
  prepare_submatcher(
366
- NumericalityMatchers::OnlyIntegerMatcher.new(self, @attribute),
379
+ NumericalityMatchers::OnlyIntegerMatcher.new(self, attribute),
367
380
  )
368
381
  self
369
382
  end
370
383
 
371
384
  def allow_nil
372
385
  @expects_to_allow_nil = true
373
- prepare_submatcher(
374
- AllowValueMatcher.new(nil).
375
- for(@attribute).
376
- with_message(:not_a_number),
377
- )
386
+ prepare_submatcher(allow_value_matcher(nil, :not_a_number))
378
387
  self
379
388
  end
380
389
 
@@ -384,60 +393,52 @@ module Shoulda
384
393
 
385
394
  def odd
386
395
  prepare_submatcher(
387
- NumericalityMatchers::OddNumberMatcher.new(self, @attribute),
396
+ NumericalityMatchers::OddNumberMatcher.new(self, attribute),
388
397
  )
389
398
  self
390
399
  end
391
400
 
392
401
  def even
393
402
  prepare_submatcher(
394
- NumericalityMatchers::EvenNumberMatcher.new(self, @attribute),
403
+ NumericalityMatchers::EvenNumberMatcher.new(self, attribute),
395
404
  )
396
405
  self
397
406
  end
398
407
 
399
408
  def is_greater_than(value)
400
- prepare_submatcher(comparison_matcher_for(value, :>).for(@attribute))
409
+ prepare_submatcher(comparison_matcher_for(value, :>).for(attribute))
401
410
  self
402
411
  end
403
412
 
404
413
  def is_greater_than_or_equal_to(value)
405
- prepare_submatcher(comparison_matcher_for(value, :>=).for(@attribute))
414
+ prepare_submatcher(comparison_matcher_for(value, :>=).for(attribute))
406
415
  self
407
416
  end
408
417
 
409
418
  def is_equal_to(value)
410
- prepare_submatcher(comparison_matcher_for(value, :==).for(@attribute))
419
+ prepare_submatcher(comparison_matcher_for(value, :==).for(attribute))
411
420
  self
412
421
  end
413
422
 
414
423
  def is_less_than(value)
415
- prepare_submatcher(comparison_matcher_for(value, :<).for(@attribute))
424
+ prepare_submatcher(comparison_matcher_for(value, :<).for(attribute))
416
425
  self
417
426
  end
418
427
 
419
428
  def is_less_than_or_equal_to(value)
420
- prepare_submatcher(comparison_matcher_for(value, :<=).for(@attribute))
429
+ prepare_submatcher(comparison_matcher_for(value, :<=).for(attribute))
421
430
  self
422
431
  end
423
432
 
424
433
  def is_other_than(value)
425
- prepare_submatcher(comparison_matcher_for(value, :!=).for(@attribute))
426
- self
427
- end
428
-
429
- def with_message(message)
430
- @expects_custom_validation_message = true
431
- @expected_message = message
434
+ prepare_submatcher(comparison_matcher_for(value, :!=).for(attribute))
432
435
  self
433
436
  end
434
437
 
435
- def expects_custom_validation_message?
436
- @expects_custom_validation_message
437
- end
438
-
439
- def on(context)
440
- @context = context
438
+ def is_in(range)
439
+ prepare_submatcher(
440
+ NumericalityMatchers::RangeMatcher.new(self, attribute, range),
441
+ )
441
442
  self
442
443
  end
443
444
 
@@ -454,9 +455,13 @@ module Shoulda
454
455
  def simple_description
455
456
  description = ''
456
457
 
457
- description << "validate that :#{@attribute} looks like "
458
+ description << "validate that :#{attribute} looks like "
458
459
  description << Shoulda::Matchers::Util.a_or_an(full_allowed_type)
459
460
 
461
+ if range_description.present?
462
+ description << " #{range_description}"
463
+ end
464
+
460
465
  if comparison_descriptions.present?
461
466
  description << " #{comparison_descriptions}"
462
467
  end
@@ -464,10 +469,6 @@ module Shoulda
464
469
  description
465
470
  end
466
471
 
467
- def description
468
- ValidationMatcher::BuildDescription.call(self, simple_description)
469
- end
470
-
471
472
  def failure_message
472
473
  overall_failure_message.dup.tap do |message|
473
474
  message << "\n"
@@ -494,44 +495,29 @@ module Shoulda
494
495
  @subject = subject
495
496
  @number_of_submatchers = @submatchers.size
496
497
 
497
- add_disallow_value_matcher
498
498
  qualify_submatchers
499
499
  end
500
500
 
501
- def overall_failure_message
502
- Shoulda::Matchers.word_wrap(
503
- "Expected #{model.name} to #{description}, but this could not "\
504
- 'be proved.',
505
- )
506
- end
507
-
508
- def overall_failure_message_when_negated
509
- Shoulda::Matchers.word_wrap(
510
- "Expected #{model.name} not to #{description}, but this could not "\
511
- 'be proved.',
512
- )
513
- end
514
-
515
501
  def attribute_is_active_record_column?
516
- columns_hash.key?(@attribute.to_s)
502
+ columns_hash.key?(attribute.to_s)
517
503
  end
518
504
 
519
505
  def column_type
520
- columns_hash[@attribute.to_s].type
506
+ columns_hash[attribute.to_s].type
521
507
  end
522
508
 
523
509
  def columns_hash
524
- if @subject.class.respond_to?(:columns_hash)
525
- @subject.class.columns_hash
510
+ if subject.class.respond_to?(:columns_hash)
511
+ subject.class.columns_hash
526
512
  else
527
513
  {}
528
514
  end
529
515
  end
530
516
 
531
- def add_disallow_value_matcher
517
+ def add_disallow_non_numeric_value_matcher
532
518
  disallow_value_matcher = DisallowValueMatcher.
533
519
  new(non_numeric_value).
534
- for(@attribute).
520
+ for(attribute).
535
521
  with_message(:not_a_number)
536
522
 
537
523
  add_submatcher(disallow_value_matcher)
@@ -543,9 +529,9 @@ module Shoulda
543
529
  end
544
530
 
545
531
  def comparison_matcher_for(value, operator)
546
- NumericalityMatchers::ComparisonMatcher.
532
+ ComparisonMatcher.
547
533
  new(self, value, operator).
548
- for(@attribute)
534
+ for(attribute)
549
535
  end
550
536
 
551
537
  def add_submatcher(submatcher)
@@ -577,8 +563,8 @@ module Shoulda
577
563
  submatcher.with_message(@expected_message)
578
564
  end
579
565
 
580
- if @context
581
- submatcher.on(@context)
566
+ if context
567
+ submatcher.on(context)
582
568
  end
583
569
 
584
570
  submatcher.ignoring_interference_by_writer(
@@ -596,23 +582,25 @@ module Shoulda
596
582
  end
597
583
 
598
584
  def has_been_qualified?
599
- @submatchers.any? do |submatcher|
600
- Shoulda::Matchers::RailsShim.parent_of(submatcher.class) ==
601
- NumericalityMatchers
602
- end
585
+ @submatchers.any? { |submatcher| submatcher_qualified?(submatcher) }
586
+ end
587
+
588
+ def submatcher_qualified?(submatcher)
589
+ Shoulda::Matchers::RailsShim.parent_of(submatcher.class) ==
590
+ NumericalityMatchers || submatcher.instance_of?(ComparisonMatcher)
603
591
  end
604
592
 
605
593
  def first_submatcher_that_fails_to_match
606
594
  @_first_submatcher_that_fails_to_match ||=
607
595
  @submatchers.detect do |submatcher|
608
- !submatcher.matches?(@subject)
596
+ !submatcher.matches?(subject)
609
597
  end
610
598
  end
611
599
 
612
600
  def first_submatcher_that_fails_to_not_match
613
601
  @_first_submatcher_that_fails_to_not_match ||=
614
602
  @submatchers.detect do |submatcher|
615
- !submatcher.does_not_match?(@subject)
603
+ !submatcher.does_not_match?(subject)
616
604
  end
617
605
  end
618
606
 
@@ -673,8 +661,12 @@ module Shoulda
673
661
  end
674
662
  end
675
663
 
676
- def model
677
- @subject.class
664
+ def range_description
665
+ range_submatcher = @submatchers.detect do |submatcher|
666
+ submatcher.respond_to? :range_description
667
+ end
668
+
669
+ range_submatcher&.range_description
678
670
  end
679
671
 
680
672
  def non_numeric_value
@@ -186,6 +186,12 @@ module Shoulda
186
186
  def blank_values
187
187
  ['', ' ', "\n", "\r", "\t", "\f"]
188
188
  end
189
+
190
+ def array_column?
191
+ @subject.class.respond_to?(:columns_hash) &&
192
+ @subject.class.columns_hash[@attribute.to_s].respond_to?(:array) &&
193
+ @subject.class.columns_hash[@attribute.to_s].array
194
+ end
189
195
  end
190
196
  end
191
197
  end
@@ -25,6 +25,10 @@ module Shoulda
25
25
  messages.any?
26
26
  end
27
27
 
28
+ def has_any_errors?
29
+ record.errors.any?
30
+ end
31
+
28
32
  def captured_validation_exception?
29
33
  @captured_validation_exception
30
34
  end
@@ -21,11 +21,14 @@ require 'shoulda/matchers/active_model/validate_presence_of_matcher'
21
21
  require 'shoulda/matchers/active_model/validate_acceptance_of_matcher'
22
22
  require 'shoulda/matchers/active_model/validate_confirmation_of_matcher'
23
23
  require 'shoulda/matchers/active_model/validate_numericality_of_matcher'
24
+ require 'shoulda/matchers/active_model/validate_comparison_of_matcher'
25
+ require 'shoulda/matchers/active_model/comparison_matcher'
24
26
  require 'shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher'
25
- require 'shoulda/matchers/active_model/numericality_matchers/comparison_matcher'
26
27
  require 'shoulda/matchers/active_model/numericality_matchers/odd_number_matcher'
27
28
  require 'shoulda/matchers/active_model/numericality_matchers/even_number_matcher'
28
29
  require 'shoulda/matchers/active_model/numericality_matchers/only_integer_matcher'
30
+ require 'shoulda/matchers/active_model/numericality_matchers/range_matcher'
31
+ require 'shoulda/matchers/active_model/numericality_matchers/submatchers'
29
32
  require 'shoulda/matchers/active_model/errors'
30
33
  require 'shoulda/matchers/active_model/have_secure_password_matcher'
31
34
 
@@ -227,14 +227,6 @@ module Shoulda
227
227
  self
228
228
  end
229
229
 
230
- def with(expected_enum_values)
231
- Shoulda::Matchers.warn_about_deprecated_method(
232
- 'The `with` qualifier on `define_enum_for`',
233
- '`with_values`',
234
- )
235
- with_values(expected_enum_values)
236
- end
237
-
238
230
  def with_prefix(expected_prefix = true)
239
231
  options[:prefix] = expected_prefix
240
232
  self
@@ -48,6 +48,30 @@ module Shoulda
48
48
  # should have_db_column(:camera_aperture).of_type(:decimal)
49
49
  # end
50
50
  #
51
+ # ##### of_sql_type
52
+ #
53
+ # Use `of_sql_type` to assert that a column is defined as a certain sql_type.
54
+ #
55
+ # class CreatePhones < ActiveRecord::Migration
56
+ # def change
57
+ # create_table :phones do |t|
58
+ # t.string :camera_aperture, limit: 36
59
+ # end
60
+ # end
61
+ # end
62
+ #
63
+ # # RSpec
64
+ # RSpec.describe Phone, type: :model do
65
+ # it do
66
+ # should have_db_column(:camera_aperture).of_sql_type('varchar(36)')
67
+ # end
68
+ # end
69
+ #
70
+ # # Minitest (Shoulda)
71
+ # class PhoneTest < ActiveSupport::TestCase
72
+ # should have_db_column(:camera_aperture).of_sql_type('varchar(36)')
73
+ # end
74
+ #
51
75
  # ##### with_options
52
76
  #
53
77
  # Use `with_options` to assert that a column has been defined with
@@ -96,6 +120,11 @@ module Shoulda
96
120
  self
97
121
  end
98
122
 
123
+ def of_sql_type(sql_column_type)
124
+ @options[:sql_column_type] = sql_column_type
125
+ self
126
+ end
127
+
99
128
  def with_options(opts = {})
100
129
  validate_options(opts)
101
130
  OPTIONS.each do |attribute|
@@ -110,6 +139,7 @@ module Shoulda
110
139
  @subject = subject
111
140
  column_exists? &&
112
141
  correct_column_type? &&
142
+ correct_sql_column_type? &&
113
143
  correct_precision? &&
114
144
  correct_limit? &&
115
145
  correct_default? &&
@@ -129,12 +159,9 @@ module Shoulda
129
159
 
130
160
  def description
131
161
  desc = "have db column named #{@column}"
132
- if @options.key?(:column_type)
133
- desc << " of type #{@options[:column_type]}"
134
- end
135
- if @options.key?(:precision)
136
- desc << " of precision #{@options[:precision]}"
137
- end
162
+ desc << " of type #{@options[:column_type]}" if @options.key?(:column_type)
163
+ desc << " of sql_type #{@options[:sql_column_type]}" if @options.key?(:sql_column_type)
164
+ desc << " of precision #{@options[:precision]}" if @options.key?(:precision)
138
165
  desc << " of limit #{@options[:limit]}" if @options.key?(:limit)
139
166
  desc << " of default #{@options[:default]}" if @options.key?(:default)
140
167
  desc << " of null #{@options[:null]}" if @options.key?(:null)
@@ -178,6 +205,19 @@ module Shoulda
178
205
  end
179
206
  end
180
207
 
208
+ def correct_sql_column_type?
209
+ return true unless @options.key?(:sql_column_type)
210
+
211
+ if matched_column.sql_type.to_s == @options[:sql_column_type].to_s
212
+ true
213
+ else
214
+ @missing =
215
+ "#{model_class} has a db column named #{@column} " <<
216
+ "of sql type #{matched_column.sql_type}, not #{@options[:sql_column_type]}."
217
+ false
218
+ end
219
+ end
220
+
181
221
  def correct_precision?
182
222
  return true unless @options.key?(:precision)
183
223
 
@@ -197,17 +197,28 @@ module Shoulda
197
197
  def matched_index
198
198
  @_matched_index ||=
199
199
  if expected_columns.one?
200
- actual_indexes.detect do |index|
200
+ sorted_indexes.detect do |index|
201
201
  Array.wrap(index.columns) == expected_columns
202
202
  end
203
203
  else
204
- actual_indexes.detect do |index|
204
+ sorted_indexes.detect do |index|
205
205
  index.columns == expected_columns
206
206
  end
207
207
  end
208
208
  end
209
209
 
210
- def actual_indexes
210
+ def sorted_indexes
211
+ if qualifiers.include?(:unique)
212
+ # return indexes with unique matching the qualifier first
213
+ unsorted_indexes.sort_by do |index|
214
+ index.unique == qualifiers[:unique] ? 0 : 1
215
+ end
216
+ else
217
+ unsorted_indexes
218
+ end
219
+ end
220
+
221
+ def unsorted_indexes
211
222
  model.connection.indexes(table_name)
212
223
  end
213
224
 
@@ -2,7 +2,7 @@ module Shoulda
2
2
  module Matchers
3
3
  module ActiveRecord
4
4
  # The `have_implicit_order_column` matcher tests that the model has `implicit_order_column`
5
- # assigned to one of the table columns. (Rails 6+ only)
5
+ # assigned to one of the table columns.
6
6
  #
7
7
  # class Product < ApplicationRecord
8
8
  # self.implicit_order_column = :created_at
@@ -20,10 +20,8 @@ module Shoulda
20
20
  #
21
21
  # @return [HaveImplicitOrderColumnMatcher]
22
22
  #
23
- if RailsShim.active_record_gte_6?
24
- def have_implicit_order_column(column_name)
25
- HaveImplicitOrderColumnMatcher.new(column_name)
26
- end
23
+ def have_implicit_order_column(column_name)
24
+ HaveImplicitOrderColumnMatcher.new(column_name)
27
25
  end
28
26
 
29
27
  # @private