rubocop-rspec 2.27.1 → 2.29.0

Sign up to get free protection for your applications and to get access to all the features.
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