shoulda-matchers 4.4.1 → 4.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.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +22 -0
  3. data/README.md +7 -9
  4. data/lib/shoulda/matchers/action_controller/callback_matcher.rb +4 -2
  5. data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +3 -2
  6. data/lib/shoulda/matchers/action_controller/permit_matcher.rb +26 -21
  7. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +6 -8
  8. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +6 -8
  9. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +16 -13
  10. data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +2 -1
  11. data/lib/shoulda/matchers/action_controller/route_matcher.rb +5 -6
  12. data/lib/shoulda/matchers/action_controller/route_params.rb +1 -1
  13. data/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +19 -13
  14. data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +18 -16
  15. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +29 -27
  16. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_changed_value_error.rb +1 -1
  17. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +5 -5
  18. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter_and_validator.rb +2 -2
  19. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb +1 -1
  20. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb +1 -1
  21. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +1 -1
  22. data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +51 -25
  23. data/lib/shoulda/matchers/active_model/helpers.rb +1 -1
  24. data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +32 -34
  25. data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +1 -1
  26. data/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb +1 -1
  27. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +9 -1
  28. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +2 -2
  29. data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +8 -7
  30. data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +26 -25
  31. data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +6 -6
  32. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +39 -26
  33. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +2 -2
  34. data/lib/shoulda/matchers/active_model/validation_matcher.rb +6 -6
  35. data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +2 -4
  36. data/lib/shoulda/matchers/active_model/validation_message_finder.rb +2 -4
  37. data/lib/shoulda/matchers/active_model/validator.rb +3 -3
  38. data/lib/shoulda/matchers/active_record.rb +26 -26
  39. data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +6 -3
  40. data/lib/shoulda/matchers/active_record/association_matcher.rb +80 -40
  41. data/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +5 -2
  42. data/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +4 -4
  43. data/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +1 -1
  44. data/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +11 -6
  45. data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +2 -9
  46. data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +12 -7
  47. data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +23 -5
  48. data/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +3 -3
  49. data/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +1 -1
  50. data/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +3 -3
  51. data/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +3 -2
  52. data/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +7 -5
  53. data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +8 -8
  54. data/lib/shoulda/matchers/active_record/have_attached_matcher.rb +46 -8
  55. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +39 -17
  56. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +1 -1
  57. data/lib/shoulda/matchers/active_record/have_implicit_order_column.rb +7 -7
  58. data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +12 -10
  59. data/lib/shoulda/matchers/active_record/have_rich_text_matcher.rb +11 -7
  60. data/lib/shoulda/matchers/active_record/have_secure_token_matcher.rb +2 -0
  61. data/lib/shoulda/matchers/active_record/serialize_matcher.rb +13 -9
  62. data/lib/shoulda/matchers/active_record/uniqueness.rb +1 -1
  63. data/lib/shoulda/matchers/active_record/uniqueness/test_model_creator.rb +1 -3
  64. data/lib/shoulda/matchers/active_record/uniqueness/test_models.rb +0 -2
  65. data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +78 -71
  66. data/lib/shoulda/matchers/doublespeak.rb +2 -1
  67. data/lib/shoulda/matchers/doublespeak/double.rb +1 -1
  68. data/lib/shoulda/matchers/doublespeak/double_collection.rb +3 -3
  69. data/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +8 -5
  70. data/lib/shoulda/matchers/doublespeak/object_double.rb +1 -1
  71. data/lib/shoulda/matchers/doublespeak/stub_implementation.rb +1 -5
  72. data/lib/shoulda/matchers/doublespeak/world.rb +2 -2
  73. data/lib/shoulda/matchers/error.rb +1 -1
  74. data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +14 -13
  75. data/lib/shoulda/matchers/integrations/configuration.rb +1 -1
  76. data/lib/shoulda/matchers/integrations/libraries/action_controller.rb +1 -1
  77. data/lib/shoulda/matchers/integrations/libraries/rails.rb +2 -2
  78. data/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb +1 -1
  79. data/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb +1 -1
  80. data/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb +1 -1
  81. data/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb +1 -1
  82. data/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb +1 -1
  83. data/lib/shoulda/matchers/rails_shim.rb +5 -3
  84. data/lib/shoulda/matchers/util.rb +7 -2
  85. data/lib/shoulda/matchers/util/word_wrap.rb +7 -7
  86. data/lib/shoulda/matchers/version.rb +1 -1
  87. data/lib/shoulda/matchers/warn.rb +3 -3
  88. data/shoulda-matchers.gemspec +10 -7
  89. metadata +11 -10
@@ -34,7 +34,7 @@ module Shoulda
34
34
  private
35
35
 
36
36
  def option_verifier
37
- @option_verifier ||= OptionVerifier.new(subject)
37
+ @_option_verifier ||= OptionVerifier.new(subject)
38
38
  end
39
39
 
40
40
  def option_matches?
@@ -43,8 +43,8 @@ module Shoulda
43
43
 
44
44
  def option_type
45
45
  case dependent
46
- when true, false then :boolean
47
- else :string
46
+ when true, false then :boolean
47
+ else :string
48
48
  end
49
49
  end
50
50
 
@@ -52,7 +52,7 @@ module Shoulda
52
52
  [
53
53
  "#{name} should have",
54
54
  (dependent == true ? 'a' : dependent),
55
- 'dependency'
55
+ 'dependency',
56
56
  ].join(' ')
57
57
  end
58
58
  end
@@ -32,7 +32,7 @@ module Shoulda
32
32
  attr_accessor :subject, :inverse_of, :name
33
33
 
34
34
  def option_verifier
35
- @option_verifier ||= OptionVerifier.new(subject)
35
+ @_option_verifier ||= OptionVerifier.new(subject)
36
36
  end
37
37
  end
38
38
  end
@@ -18,7 +18,7 @@ module Shoulda
18
18
  @reflector = reflector
19
19
  end
20
20
 
21
- def matches?(subject)
21
+ def matches?(_subject)
22
22
  join_table_option_correct? &&
23
23
  join_table_exists? &&
24
24
  join_table_has_correct_columns?
@@ -26,10 +26,14 @@ module Shoulda
26
26
 
27
27
  def join_table_option_correct?
28
28
  if options.key?(:join_table_name)
29
- if option_verifier.correct_for_string?(:join_table, options[:join_table_name])
29
+ if option_verifier.correct_for_string?(
30
+ :join_table,
31
+ options[:join_table_name],
32
+ )
30
33
  true
31
34
  else
32
- @failure_message = "#{name} should use #{options[:join_table_name].inspect} for :join_table option"
35
+ @failure_message = "#{name} should use"\
36
+ " #{options[:join_table_name].inspect} for :join_table option"
33
37
  false
34
38
  end
35
39
  else
@@ -38,7 +42,8 @@ module Shoulda
38
42
  end
39
43
 
40
44
  def join_table_exists?
41
- if RailsShim.tables_and_views(connection).include?(join_table_name.to_s)
45
+ if RailsShim.tables_and_views(connection).
46
+ include?(join_table_name.to_s)
42
47
  true
43
48
  else
44
49
  @failure_message = missing_table_message
@@ -64,8 +69,8 @@ module Shoulda
64
69
  delegate :foreign_key, :association_foreign_key, to: :reflector
65
70
 
66
71
  def missing_columns
67
- @missing_columns ||= expected_join_table_columns.select do |key|
68
- !actual_join_table_columns.include?(key.to_s)
72
+ @_missing_columns ||= expected_join_table_columns.reject do |key|
73
+ actual_join_table_columns.include?(key.to_s)
69
74
  end
70
75
  end
71
76
 
@@ -26,12 +26,7 @@ module Shoulda
26
26
 
27
27
  def join_table_name
28
28
  join_table_name =
29
- if has_and_belongs_to_many_name_table_name
30
- has_and_belongs_to_many_name_table_name
31
- else
32
- reflection.join_table
33
- end
34
-
29
+ has_and_belongs_to_many_name_table_name || reflection.join_table
35
30
  join_table_name.to_s
36
31
  end
37
32
 
@@ -82,9 +77,7 @@ module Shoulda
82
77
  private
83
78
 
84
79
  def has_and_belongs_to_many_name_table_name
85
- if has_and_belongs_to_many_reflection
86
- has_and_belongs_to_many_reflection.table_name
87
- end
80
+ has_and_belongs_to_many_reflection&.table_name
88
81
  end
89
82
 
90
83
  def has_and_belongs_to_many_reflection
@@ -12,13 +12,13 @@ module Shoulda
12
12
  :join_table_name,
13
13
  :polymorphic?,
14
14
  :validate_inverse_of_through_association!,
15
- to: :reflection
15
+ to: :reflection,
16
16
  )
17
17
 
18
18
  delegate(
19
19
  :through?,
20
20
  to: :reflection,
21
- allow_nil: true
21
+ allow_nil: true,
22
22
  )
23
23
 
24
24
  def initialize(subject, name)
@@ -31,7 +31,7 @@ module Shoulda
31
31
  end
32
32
 
33
33
  def reflection
34
- @reflection ||= reflect_on_association(name)
34
+ @_reflection ||= reflect_on_association(name)
35
35
  end
36
36
 
37
37
  def reflect_on_association(name)
@@ -48,9 +48,12 @@ module Shoulda
48
48
 
49
49
  def build_relation_with_clause(name, value)
50
50
  case name
51
- when :conditions then associated_class.where(value)
52
- when :order then associated_class.order(value)
53
- else raise ArgumentError, "Unknown clause '#{name}'"
51
+ when :conditions
52
+ associated_class.where(value)
53
+ when :order
54
+ associated_class.order(value)
55
+ else
56
+ raise ArgumentError, "Unknown clause '#{name}'"
54
57
  end
55
58
  end
56
59
 
@@ -59,7 +62,9 @@ module Shoulda
59
62
  when :conditions
60
63
  relation.where_values_hash
61
64
  when :order
62
- relation.order_values.map { |value| value_as_sql(value) }.join(', ')
65
+ relation.order_values.map do |value|
66
+ value_as_sql(value)
67
+ end.join(', ')
63
68
  else
64
69
  raise ArgumentError, "Unknown clause '#{name}'"
65
70
  end
@@ -6,7 +6,12 @@ module Shoulda
6
6
  class OptionVerifier
7
7
  delegate :reflection, to: :reflector
8
8
 
9
- RELATION_OPTIONS = [:conditions, :order]
9
+ DEFAULT_VALUE_OF_OPTIONS = {
10
+ has_many: {
11
+ validate: true,
12
+ },
13
+ }.freeze
14
+ RELATION_OPTIONS = [:conditions, :order].freeze
10
15
 
11
16
  def initialize(reflector)
12
17
  @reflector = reflector
@@ -40,7 +45,7 @@ module Shoulda
40
45
  else
41
46
  type_cast_expected_value = type_cast(
42
47
  type,
43
- expected_value_for(type, name, expected_value)
48
+ expected_value_for(type, name, expected_value),
44
49
  )
45
50
  actual_value = type_cast(type, actual_value_for(name))
46
51
  type_cast_expected_value == actual_value
@@ -55,7 +60,7 @@ module Shoulda
55
60
  if respond_to?(method_name, true)
56
61
  __send__(method_name)
57
62
  else
58
- reflection.options[name]
63
+ actual_value_for_option(name)
59
64
  end
60
65
  end
61
66
  end
@@ -94,7 +99,7 @@ module Shoulda
94
99
 
95
100
  def expected_value_for_constant(name)
96
101
  namespace = Shoulda::Matchers::Util.deconstantize(
97
- reflector.model_class.to_s
102
+ reflector.model_class.to_s,
98
103
  )
99
104
 
100
105
  ["#{namespace}::#{name}", name].each do |path|
@@ -107,12 +112,25 @@ module Shoulda
107
112
  end
108
113
 
109
114
  def actual_value_for_relation_clause(name)
110
- reflector.extract_relation_clause_from(reflector.association_relation, name)
115
+ reflector.extract_relation_clause_from(
116
+ reflector.association_relation,
117
+ name,
118
+ )
111
119
  end
112
120
 
113
121
  def actual_value_for_class_name
114
122
  reflector.associated_class
115
123
  end
124
+
125
+ def actual_value_for_option(name)
126
+ option_value = reflection.options[name]
127
+
128
+ if option_value.nil?
129
+ DEFAULT_VALUE_OF_OPTIONS.dig(reflection.macro, name)
130
+ else
131
+ option_value
132
+ end
133
+ end
116
134
  end
117
135
  end
118
136
  end
@@ -32,9 +32,9 @@ module Shoulda
32
32
  end
33
33
 
34
34
  missing_option << (
35
- 'fail validation if ' +
36
- ":#{attribute_name} is unset; i.e., either the association " +
37
- 'should have been defined with `optional: ' +
35
+ 'fail validation if '\
36
+ ":#{attribute_name} is unset; i.e., either the association "\
37
+ 'should have been defined with `optional: '\
38
38
  "#{optional.inspect}`, or there "
39
39
  )
40
40
 
@@ -32,7 +32,7 @@ module Shoulda
32
32
  attr_accessor :subject, :order, :name
33
33
 
34
34
  def option_verifier
35
- @option_verifier ||= OptionVerifier.new(subject)
35
+ @_option_verifier ||= OptionVerifier.new(subject)
36
36
  end
37
37
  end
38
38
  end
@@ -33,9 +33,9 @@ module Shoulda
33
33
  end
34
34
 
35
35
  missing_option << (
36
- 'fail validation if ' +
37
- ":#{attribute_name} is unset; i.e., either the association " +
38
- 'should have been defined with `required: ' +
36
+ 'fail validation if '\
37
+ ":#{attribute_name} is unset; i.e., either the association "\
38
+ 'should have been defined with `required: '\
39
39
  "#{required.inspect}`, or there "
40
40
  )
41
41
 
@@ -22,7 +22,8 @@ module Shoulda
22
22
  if option_verifier.correct_for_string?(:source, source)
23
23
  true
24
24
  else
25
- self.missing_option = "#{name} should have #{source} as source option"
25
+ self.missing_option =
26
+ "#{name} should have #{source} as source option"
26
27
  false
27
28
  end
28
29
  end
@@ -32,7 +33,7 @@ module Shoulda
32
33
  attr_accessor :subject, :source, :name
33
34
 
34
35
  def option_verifier
35
- @option_verifier ||= OptionVerifier.new(subject)
36
+ @_option_verifier ||= OptionVerifier.new(subject)
36
37
  end
37
38
  end
38
39
  end
@@ -29,13 +29,14 @@ module Shoulda
29
29
  if through_reflection.present?
30
30
  true
31
31
  else
32
- self.missing_option = "#{name} does not have any relationship to #{through}"
32
+ self.missing_option =
33
+ "#{name} does not have any relationship to #{through}"
33
34
  false
34
35
  end
35
36
  end
36
37
 
37
38
  def through_reflection
38
- @through_reflection ||= subject.reflect_on_association(through)
39
+ @_through_reflection ||= subject.reflect_on_association(through)
39
40
  end
40
41
 
41
42
  def through_association_correct?
@@ -43,8 +44,9 @@ module Shoulda
43
44
  true
44
45
  else
45
46
  self.missing_option =
46
- "Expected #{name} to have #{name} through #{through}, " +
47
- "but got it through #{option_verifier.actual_value_for(:through)}"
47
+ "Expected #{name} to have #{name} through #{through}, "\
48
+ 'but got it through ' +
49
+ option_verifier.actual_value_for(:through).to_s
48
50
  false
49
51
  end
50
52
  end
@@ -54,7 +56,7 @@ module Shoulda
54
56
  attr_accessor :through, :name, :subject
55
57
 
56
58
  def option_verifier
57
- @option_verifier ||= OptionVerifier.new(subject)
59
+ @_option_verifier ||= OptionVerifier.new(subject)
58
60
  end
59
61
  end
60
62
  end
@@ -237,7 +237,7 @@ module Shoulda
237
237
  "Expected #{model} to #{expectation}, but "
238
238
  end
239
239
 
240
- message << failure_message_continuation + '.'
240
+ message << "#{failure_message_continuation}."
241
241
 
242
242
  Shoulda::Matchers.word_wrap(message)
243
243
  end
@@ -252,7 +252,7 @@ module Shoulda
252
252
  attr_reader :attribute_name, :options, :record,
253
253
  :failure_message_continuation
254
254
 
255
- def expectation
255
+ def expectation # rubocop:disable Metrics/MethodLength
256
256
  if enum_defined?
257
257
  expectation = "#{simple_description} backed by "
258
258
  expectation << Shoulda::Matchers::Util.a_or_an(expected_column_type)
@@ -358,8 +358,8 @@ module Shoulda
358
358
  true
359
359
  else
360
360
  @failure_message_continuation =
361
- "However, #{attribute_name.inspect} is " +
362
- Shoulda::Matchers::Util.a_or_an(column.type) +
361
+ "However, #{attribute_name.inspect} is "\
362
+ "#{Shoulda::Matchers::Util.a_or_an(column.type)}"\
363
363
  ' column'
364
364
  false
365
365
  end
@@ -421,9 +421,9 @@ module Shoulda
421
421
  def expected_prefix
422
422
  if options.include?(:prefix)
423
423
  if options[:prefix] == true
424
- attribute_name#.to_sym
424
+ attribute_name
425
425
  else
426
- options[:prefix]#.to_sym
426
+ options[:prefix]
427
427
  end
428
428
  end
429
429
  end
@@ -431,9 +431,9 @@ module Shoulda
431
431
  def expected_suffix
432
432
  if options.include?(:suffix)
433
433
  if options[:suffix] == true
434
- attribute_name#.to_sym
434
+ attribute_name
435
435
  else
436
- options[:suffix]#.to_sym
436
+ options[:suffix]
437
437
  end
438
438
  end
439
439
  end
@@ -1,10 +1,52 @@
1
1
  module Shoulda
2
2
  module Matchers
3
3
  module ActiveRecord
4
+ # The `have_one_attached` matcher tests usage of the
5
+ # `has_one_attached` macro.
6
+ #
7
+ # #### Example
8
+ #
9
+ # class User < ApplicationRecord
10
+ # has_one_attached :avatar
11
+ # end
12
+ #
13
+ # # RSpec
14
+ # RSpec.describe User, type: :model do
15
+ # it { should have_one_attached(:avatar) }
16
+ # end
17
+ #
18
+ # # Minitest (Shoulda)
19
+ # class UserTest < ActiveSupport::TestCase
20
+ # should have_one_attached(:avatar)
21
+ # end
22
+ #
23
+ # @return [HaveAttachedMatcher]
24
+ #
4
25
  def have_one_attached(name)
5
26
  HaveAttachedMatcher.new(:one, name)
6
27
  end
7
28
 
29
+ # The `have_many_attached` matcher tests usage of the
30
+ # `has_many_attached` macro.
31
+ #
32
+ # #### Example
33
+ #
34
+ # class Message < ApplicationRecord
35
+ # has_many_attached :images
36
+ # end
37
+ #
38
+ # # RSpec
39
+ # RSpec.describe Message, type: :model do
40
+ # it { should have_many_attached(:images) }
41
+ # end
42
+ #
43
+ # # Minitest (Shoulda)
44
+ # class MessageTest < ActiveSupport::TestCase
45
+ # should have_many_attached(:images)
46
+ # end
47
+ #
48
+ # @return [HaveAttachedMatcher]
49
+ #
8
50
  def have_many_attached(name)
9
51
  HaveAttachedMatcher.new(:many, name)
10
52
  end
@@ -92,10 +134,8 @@ Did not expect #{expectation}, but it does.
92
134
 
93
135
  def attachments_association_name
94
136
  case macro
95
- when :one then
96
- "#{name}_attachment"
97
- when :many then
98
- "#{name}_attachments"
137
+ when :one then "#{name}_attachment"
138
+ when :many then "#{name}_attachments"
99
139
  end
100
140
  end
101
141
 
@@ -121,10 +161,8 @@ Did not expect #{expectation}, but it does.
121
161
 
122
162
  def blobs_association_name
123
163
  case macro
124
- when :one then
125
- "#{name}_blob"
126
- when :many then
127
- "#{name}_blobs"
164
+ when :one then "#{name}_blob"
165
+ when :many then "#{name}_blobs"
128
166
  end
129
167
  end
130
168