rubocop-rspec 2.27.1 → 2.29.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 629669f9a1d9d41dae7bc62c630f3a6cdae80623d3213c8e79ac8eb207f79e59
4
- data.tar.gz: 5005161c3684fcd8b794284bcaeedc50253a545d649be9e0e0a82958fdd125b0
3
+ metadata.gz: 17925b2c404825ce202d012a1b5176358a7328cbdf5c956426b2be463c07707a
4
+ data.tar.gz: bf216b0348237ccb7020b7dad2cb79c700c46f7bdbc85bdf65c5a2740aea12e8
5
5
  SHA512:
6
- metadata.gz: 8af331d4b31697228397a1122cbe331223d3f040f44d2260e5148d73177df5ba08ae2aea1d481b27f698b5d59c9522d1c5f4c5e08e14b473a548de75ccf218c6
7
- data.tar.gz: 0f86ea257bcd14e73c57b2e431f618e0959cf9dbeca6e22c4b75bd8d4945f670d8fdb65212ff12969b351b62c35f845ca28041d4b1b30627e7d64dda5932b365
6
+ metadata.gz: fb4265f89166d4df1e75b2eef2a2b3d709e93834511dde371765cf21d0efb7af158bc2a165b98dc0106ffb979003b2d924543074c00268445df924a6d3ec8cc0
7
+ data.tar.gz: 90fc7033f83e79d3aa77eab277247ce0c6b66b20db115d24834ed28940f584c656eb6588f93250e1abea901ad4b83cac012d0339e64b4a5633b48abed9c4b568
data/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## Master (Unreleased)
4
4
 
5
+ ## 2.29.0 (2024-04-04)
6
+
7
+ - Fix an autocorrect error for `RSpec/ExpectActual`. ([@bquorning])
8
+ - Add new `RSpec/UndescriptiveLiteralsDescription` cop. ([@ydah])
9
+ - Add new `RSpec/EmptyOutput` cop. ([@bquorning])
10
+
11
+ ## 2.28.0 (2024-03-30)
12
+
13
+ - Extract RSpec Rails cops to a separate repository, [`rubocop-rspec_rails`](https://github.com/rubocop/rubocop-rspec_rails). The `rubocop-rspec_rails` repository is a dependency of `rubocop-rspec` and the cops related to rspec-rails are aliased (`RSpec/Rails/Foo` == `RSpecRails/Foo`) until v3.0 is released, so the change will be invisible to users until then. ([@ydah])
14
+
5
15
  ## 2.27.1 (2024-03-03)
6
16
 
7
17
  - Fix a false positive for `RSpec/RepeatedSubjectCall` when `subject.method_call`. ([@ydah])
data/config/default.yml CHANGED
@@ -366,6 +366,12 @@ RSpec/EmptyMetadata:
366
366
  VersionAdded: '2.24'
367
367
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyMetadata
368
368
 
369
+ RSpec/EmptyOutput:
370
+ Description: Check that the `output` matcher is not called with an empty string.
371
+ Enabled: pending
372
+ VersionAdded: "<<next>>"
373
+ Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyOutput
374
+
369
375
  RSpec/Eq:
370
376
  Description: Use `eq` instead of `be ==` to compare objects.
371
377
  Enabled: pending
@@ -932,6 +938,12 @@ RSpec/SubjectStub:
932
938
  StyleGuide: https://rspec.rubystyle.guide/#dont-stub-subject
933
939
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SubjectStub
934
940
 
941
+ RSpec/UndescriptiveLiteralsDescription:
942
+ Description: Description should be descriptive.
943
+ Enabled: pending
944
+ VersionAdded: '2.29'
945
+ Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/UndescriptiveLiteralsDescription
946
+
935
947
  RSpec/UnspecifiedException:
936
948
  Description: Checks for a specified error in checking raised errors.
937
949
  Enabled: true
@@ -27,3 +27,10 @@ renamed:
27
27
  RSpec/FactoryBot/FactoryClassName: FactoryBot/FactoryClassName
28
28
  RSpec/FactoryBot/FactoryNameStyle: FactoryBot/FactoryNameStyle
29
29
  RSpec/FactoryBot/SyntaxMethods: FactoryBot/SyntaxMethods
30
+ RSpec/Rails/AvoidSetupHook: RSpecRails/AvoidSetupHook
31
+ RSpec/Rails/HaveHttpStatus: RSpecRails/HaveHttpStatus
32
+ RSpec/Rails/HttpStatus: RSpecRails/HttpStatus
33
+ RSpec/Rails/InferredSpecType: RSpecRails/InferredSpecType
34
+ RSpec/Rails/MinitestAssertions: RSpecRails/MinitestAssertions
35
+ RSpec/Rails/NegationBeValid: RSpecRails/NegationBeValid
36
+ RSpec/Rails/TravelAround: RSpecRails/TravelAround
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
- # Checks for empty before and after hooks.
6
+ # Checks for empty before and after hooks.
7
7
  #
8
8
  # @example
9
9
  # # bad
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Check that the `output` matcher is not called with an empty string.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # expect { foo }.to output('').to_stdout
11
+ # expect { bar }.not_to output('').to_stderr
12
+ #
13
+ # # good
14
+ # expect { foo }.not_to output.to_stdout
15
+ # expect { bar }.to output.to_stderr
16
+ #
17
+ class EmptyOutput < Base
18
+ extend AutoCorrector
19
+
20
+ MSG = 'Use `%<runner>s` instead of matching on an empty output.'
21
+ RESTRICT_ON_SEND = Runners.all
22
+
23
+ # @!method matching_empty_output(node)
24
+ def_node_matcher :matching_empty_output, <<~PATTERN
25
+ (send
26
+ (block
27
+ (send nil? :expect) ...
28
+ )
29
+ #Runners.all
30
+ (send $(send nil? :output (str empty?)) ...)
31
+ )
32
+ PATTERN
33
+
34
+ def on_send(send_node)
35
+ matching_empty_output(send_node) do |node|
36
+ runner = send_node.method?(:to) ? 'not_to' : 'to'
37
+ message = format(MSG, runner: runner)
38
+ add_offense(node, message: message) do |corrector|
39
+ corrector.replace(send_node.loc.selector, runner)
40
+ corrector.replace(node, 'output')
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -58,22 +58,27 @@ module RuboCop
58
58
  (send
59
59
  (send nil? :expect $#literal?)
60
60
  #Runners.all
61
- {
61
+ ${
62
62
  (send (send nil? $:be) :== $_)
63
63
  (send nil? $_ $_ ...)
64
64
  }
65
65
  )
66
66
  PATTERN
67
67
 
68
- def on_send(node)
69
- expect_literal(node) do |actual, matcher, expected|
68
+ def on_send(node) # rubocop:disable Metrics/MethodLength
69
+ expect_literal(node) do |actual, send_node, matcher, expected|
70
70
  next if SKIPPED_MATCHERS.include?(matcher)
71
71
 
72
72
  add_offense(actual.source_range) do |corrector|
73
73
  next unless CORRECTABLE_MATCHERS.include?(matcher)
74
74
  next if literal?(expected)
75
75
 
76
- swap(corrector, actual, expected)
76
+ corrector.replace(actual, expected.source)
77
+ if matcher == :be
78
+ corrector.replace(expected, actual.source)
79
+ else
80
+ corrector.replace(send_node, "#{matcher}(#{actual.source})")
81
+ end
77
82
  end
78
83
  end
79
84
  end
@@ -94,11 +99,6 @@ module RuboCop
94
99
  COMPLEX_LITERALS.include?(node.type) &&
95
100
  node.each_child_node.all?(&method(:literal?))
96
101
  end
97
-
98
- def swap(corrector, actual, expected)
99
- corrector.replace(actual, expected.source)
100
- corrector.replace(expected, actual.source)
101
- end
102
102
  end
103
103
  end
104
104
  end
@@ -26,7 +26,7 @@ module RuboCop
26
26
  # @example with AssignmentOnly configuration
27
27
  # # rubocop.yml
28
28
  # # RSpec/InstanceVariable:
29
- # # AssignmentOnly: false
29
+ # # AssignmentOnly: true
30
30
  #
31
31
  # # bad
32
32
  # describe MyClass do
@@ -31,7 +31,7 @@ module RuboCop
31
31
  # end
32
32
  #
33
33
  # @example `aggregate_failures: true` (default)
34
- # # good - the cop ignores when RSpec aggregates failures
34
+ # # good - the cop ignores when RSpec aggregates failures
35
35
  # describe UserCreator do
36
36
  # it 'builds a user', :aggregate_failures do
37
37
  # expect(user.name).to eq("John")
@@ -40,7 +40,7 @@ module RuboCop
40
40
  # end
41
41
  #
42
42
  # @example `aggregate_failures: false`
43
- # # Detected as an offense
43
+ # # Detected as an offense
44
44
  # describe UserCreator do
45
45
  # it 'builds a user', aggregate_failures: false do
46
46
  # expect(user.name).to eq("John")
@@ -4,39 +4,23 @@ module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
6
  module Rails
7
- # Checks that tests use RSpec `before` hook over Rails `setup` method.
8
- #
9
- # @example
10
- # # bad
11
- # setup do
12
- # allow(foo).to receive(:bar)
13
- # end
14
- #
15
- # # good
16
- # before do
17
- # allow(foo).to receive(:bar)
18
- # end
19
- #
20
- class AvoidSetupHook < Base
21
- extend AutoCorrector
22
-
23
- MSG = 'Use `before` instead of `setup`.'
24
-
25
- # @!method setup_call(node)
26
- def_node_matcher :setup_call, <<~PATTERN
27
- (block
28
- $(send nil? :setup)
29
- (args) _)
30
- PATTERN
31
-
32
- def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
33
- setup_call(node) do |setup|
34
- add_offense(node) do |corrector|
35
- corrector.replace setup, 'before'
36
- end
37
- end
38
- end
39
- end
7
+ # @!parse
8
+ # # Checks that tests use RSpec `before` hook over Rails `setup`
9
+ # # method.
10
+ # #
11
+ # # @example
12
+ # # # bad
13
+ # # setup do
14
+ # # allow(foo).to receive(:bar)
15
+ # # end
16
+ # #
17
+ # # # good
18
+ # # before do
19
+ # # allow(foo).to receive(:bar)
20
+ # # end
21
+ # #
22
+ # class AvoidSetupHook < RuboCop::Cop::RSpec::Base; end
23
+ AvoidSetupHook = ::RuboCop::Cop::RSpecRails::AvoidSetupHook
40
24
  end
41
25
  end
42
26
  end
@@ -4,75 +4,31 @@ module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
6
  module Rails
7
- # Checks that tests use `have_http_status` instead of equality matchers.
8
- #
9
- # @example ResponseMethods: ['response', 'last_response'] (default)
10
- # # bad
11
- # expect(response.status).to be(200)
12
- # expect(last_response.code).to eq("200")
13
- #
14
- # # good
15
- # expect(response).to have_http_status(200)
16
- # expect(last_response).to have_http_status(200)
17
- #
18
- # @example ResponseMethods: ['foo_response']
19
- # # bad
20
- # expect(foo_response.status).to be(200)
21
- #
22
- # # good
23
- # expect(foo_response).to have_http_status(200)
24
- #
25
- # # also good
26
- # expect(response).to have_http_status(200)
27
- # expect(last_response).to have_http_status(200)
28
- #
29
- class HaveHttpStatus < ::RuboCop::Cop::Base
30
- extend AutoCorrector
31
-
32
- MSG =
33
- 'Prefer `expect(%<response>s).%<to>s ' \
34
- 'have_http_status(%<status>s)` over `%<bad_code>s`.'
35
-
36
- RUNNERS = %i[to to_not not_to].to_set
37
- RESTRICT_ON_SEND = RUNNERS
38
-
39
- # @!method match_status(node)
40
- def_node_matcher :match_status, <<~PATTERN
41
- (send
42
- (send nil? :expect
43
- $(send $(send nil? #response_methods?) {:status :code})
44
- )
45
- $RUNNERS
46
- $(send nil? {:be :eq :eql :equal} ({int str} $_))
47
- )
48
- PATTERN
49
-
50
- def on_send(node) # rubocop:disable Metrics/MethodLength
51
- match_status(node) do
52
- |response_status, response_method, to, match, status|
53
- return unless status.to_s.match?(/\A\d+\z/)
54
-
55
- message = format(MSG, response: response_method.method_name,
56
- to: to, status: status,
57
- bad_code: node.source)
58
- add_offense(node, message: message) do |corrector|
59
- corrector.replace(response_status, response_method.method_name)
60
- corrector.replace(match.loc.selector, 'have_http_status')
61
- corrector.replace(match.first_argument, status.to_s)
62
- end
63
- end
64
- end
65
-
66
- private
67
-
68
- def response_methods?(name)
69
- response_methods.include?(name.to_s)
70
- end
71
-
72
- def response_methods
73
- cop_config.fetch('ResponseMethods', [])
74
- end
75
- end
7
+ # @!parse
8
+ # # Checks that tests use `have_http_status` instead of equality matchers.
9
+ # #
10
+ # # @example ResponseMethods: ['response', 'last_response'] (default)
11
+ # # # bad
12
+ # # expect(response.status).to be(200)
13
+ # # expect(last_response.code).to eq("200")
14
+ # #
15
+ # # # good
16
+ # # expect(response).to have_http_status(200)
17
+ # # expect(last_response).to have_http_status(200)
18
+ # #
19
+ # # @example ResponseMethods: ['foo_response']
20
+ # # # bad
21
+ # # expect(foo_response.status).to be(200)
22
+ # #
23
+ # # # good
24
+ # # expect(foo_response).to have_http_status(200)
25
+ # #
26
+ # # # also good
27
+ # # expect(response).to have_http_status(200)
28
+ # # expect(last_response).to have_http_status(200)
29
+ # #
30
+ # class HaveHttpStatus < ::RuboCop::Cop::Base; end
31
+ HaveHttpStatus = ::RuboCop::Cop::RSpecRails::HaveHttpStatus
76
32
  end
77
33
  end
78
34
  end
@@ -1,213 +1,60 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rack/utils'
4
-
5
3
  module RuboCop
6
4
  module Cop
7
5
  module RSpec
8
6
  module Rails
9
- # Enforces use of symbolic or numeric value to describe HTTP status.
10
- #
11
- # This cop inspects only `have_http_status` calls.
12
- # So, this cop does not check if a method starting with `be_*` is used
13
- # when setting for `EnforcedStyle: symbolic` or
14
- # `EnforcedStyle: numeric`.
15
- #
16
- # @example `EnforcedStyle: symbolic` (default)
17
- # # bad
18
- # it { is_expected.to have_http_status 200 }
19
- # it { is_expected.to have_http_status 404 }
20
- # it { is_expected.to have_http_status "403" }
21
- #
22
- # # good
23
- # it { is_expected.to have_http_status :ok }
24
- # it { is_expected.to have_http_status :not_found }
25
- # it { is_expected.to have_http_status :forbidden }
26
- # it { is_expected.to have_http_status :success }
27
- # it { is_expected.to have_http_status :error }
28
- #
29
- # @example `EnforcedStyle: numeric`
30
- # # bad
31
- # it { is_expected.to have_http_status :ok }
32
- # it { is_expected.to have_http_status :not_found }
33
- # it { is_expected.to have_http_status "forbidden" }
34
- #
35
- # # good
36
- # it { is_expected.to have_http_status 200 }
37
- # it { is_expected.to have_http_status 404 }
38
- # it { is_expected.to have_http_status 403 }
39
- # it { is_expected.to have_http_status :success }
40
- # it { is_expected.to have_http_status :error }
41
- #
42
- # @example `EnforcedStyle: be_status`
43
- # # bad
44
- # it { is_expected.to have_http_status :ok }
45
- # it { is_expected.to have_http_status :not_found }
46
- # it { is_expected.to have_http_status "forbidden" }
47
- # it { is_expected.to have_http_status 200 }
48
- # it { is_expected.to have_http_status 404 }
49
- # it { is_expected.to have_http_status "403" }
50
- #
51
- # # good
52
- # it { is_expected.to be_ok }
53
- # it { is_expected.to be_not_found }
54
- # it { is_expected.to have_http_status :success }
55
- # it { is_expected.to have_http_status :error }
56
- #
57
- class HttpStatus < Base
58
- extend AutoCorrector
59
- include ConfigurableEnforcedStyle
60
- RESTRICT_ON_SEND = %i[have_http_status].freeze
61
-
62
- # @!method http_status(node)
63
- def_node_matcher :http_status, <<~PATTERN
64
- (send nil? :have_http_status ${int sym str})
65
- PATTERN
66
-
67
- def on_send(node)
68
- http_status(node) do |arg|
69
- return if arg.str_type? && arg.heredoc?
70
-
71
- checker = checker_class.new(arg)
72
- return unless checker.offensive?
73
-
74
- add_offense(checker.offense_range,
75
- message: checker.message) do |corrector|
76
- corrector.replace(checker.offense_range, checker.prefer)
77
- end
78
- end
79
- end
80
-
81
- private
82
-
83
- def checker_class
84
- case style
85
- when :symbolic
86
- SymbolicStyleChecker
87
- when :numeric
88
- NumericStyleChecker
89
- when :be_status
90
- BeStatusStyleChecker
91
- end
92
- end
93
-
94
- # :nodoc:
95
- class StyleCheckerBase
96
- MSG = 'Prefer `%<prefer>s` over `%<current>s` ' \
97
- 'to describe HTTP status code.'
98
- ALLOWED_STATUSES = %i[error success missing redirect].freeze
99
-
100
- attr_reader :node
101
-
102
- def initialize(node)
103
- @node = node
104
- end
105
-
106
- def message
107
- format(MSG, prefer: prefer, current: current)
108
- end
109
-
110
- def current
111
- offense_range.source
112
- end
113
-
114
- def offense_range
115
- node
116
- end
117
-
118
- def allowed_symbol?
119
- node.sym_type? && ALLOWED_STATUSES.include?(node.value)
120
- end
121
-
122
- def custom_http_status_code?
123
- node.int_type? &&
124
- !::Rack::Utils::SYMBOL_TO_STATUS_CODE.value?(node.source.to_i)
125
- end
126
- end
127
-
128
- # :nodoc:
129
- class SymbolicStyleChecker < StyleCheckerBase
130
- def offensive?
131
- !node.sym_type? && !custom_http_status_code?
132
- end
133
-
134
- def prefer
135
- symbol.inspect
136
- end
137
-
138
- private
139
-
140
- def symbol
141
- ::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(number)
142
- end
143
-
144
- def number
145
- node.value.to_i
146
- end
147
- end
148
-
149
- # :nodoc:
150
- class NumericStyleChecker < StyleCheckerBase
151
- def offensive?
152
- !node.int_type? && !allowed_symbol?
153
- end
154
-
155
- def prefer
156
- number.to_s
157
- end
158
-
159
- private
160
-
161
- def symbol
162
- node.value
163
- end
164
-
165
- def number
166
- ::Rack::Utils::SYMBOL_TO_STATUS_CODE[symbol.to_sym]
167
- end
168
- end
169
-
170
- # :nodoc:
171
- class BeStatusStyleChecker < StyleCheckerBase
172
- def offensive?
173
- (!node.sym_type? && !custom_http_status_code?) ||
174
- (!node.int_type? && !allowed_symbol?)
175
- end
176
-
177
- def offense_range
178
- node.parent
179
- end
180
-
181
- def prefer
182
- if node.sym_type?
183
- "be_#{node.value}"
184
- elsif node.int_type?
185
- "be_#{symbol}"
186
- elsif node.str_type?
187
- "be_#{normalize_str}"
188
- end
189
- end
190
-
191
- private
192
-
193
- def symbol
194
- ::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(number)
195
- end
196
-
197
- def number
198
- node.value.to_i
199
- end
200
-
201
- def normalize_str
202
- str = node.value.to_s
203
- if str.match?(/\A\d+\z/)
204
- ::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(str.to_i)
205
- else
206
- str
207
- end
208
- end
209
- end
210
- end
7
+ # @!parse
8
+ # # Enforces use of symbolic or numeric value to describe HTTP status.
9
+ # #
10
+ # # This cop inspects only `have_http_status` calls.
11
+ # # So, this cop does not check if a method starting with `be_*` is
12
+ # # used when setting for `EnforcedStyle: symbolic` or
13
+ # # `EnforcedStyle: numeric`.
14
+ # #
15
+ # # @example `EnforcedStyle: symbolic` (default)
16
+ # # # bad
17
+ # # it { is_expected.to have_http_status 200 }
18
+ # # it { is_expected.to have_http_status 404 }
19
+ # # it { is_expected.to have_http_status "403" }
20
+ # #
21
+ # # # good
22
+ # # it { is_expected.to have_http_status :ok }
23
+ # # it { is_expected.to have_http_status :not_found }
24
+ # # it { is_expected.to have_http_status :forbidden }
25
+ # # it { is_expected.to have_http_status :success }
26
+ # # it { is_expected.to have_http_status :error }
27
+ # #
28
+ # # @example `EnforcedStyle: numeric`
29
+ # # # bad
30
+ # # it { is_expected.to have_http_status :ok }
31
+ # # it { is_expected.to have_http_status :not_found }
32
+ # # it { is_expected.to have_http_status "forbidden" }
33
+ # #
34
+ # # # good
35
+ # # it { is_expected.to have_http_status 200 }
36
+ # # it { is_expected.to have_http_status 404 }
37
+ # # it { is_expected.to have_http_status 403 }
38
+ # # it { is_expected.to have_http_status :success }
39
+ # # it { is_expected.to have_http_status :error }
40
+ # #
41
+ # # @example `EnforcedStyle: be_status`
42
+ # # # bad
43
+ # # it { is_expected.to have_http_status :ok }
44
+ # # it { is_expected.to have_http_status :not_found }
45
+ # # it { is_expected.to have_http_status "forbidden" }
46
+ # # it { is_expected.to have_http_status 200 }
47
+ # # it { is_expected.to have_http_status 404 }
48
+ # # it { is_expected.to have_http_status "403" }
49
+ # #
50
+ # # # good
51
+ # # it { is_expected.to be_ok }
52
+ # # it { is_expected.to be_not_found }
53
+ # # it { is_expected.to have_http_status :success }
54
+ # # it { is_expected.to have_http_status :error }
55
+ # #
56
+ # class HttpStatus < RuboCop::Cop::RSpec::Base; end
57
+ HttpStatus = ::RuboCop::Cop::RSpecRails::HttpStatus
211
58
  end
212
59
  end
213
60
  end