rubocop-rspec 2.27.1 → 2.28.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.
@@ -4,348 +4,35 @@ module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
6
  module Rails
7
- # Check if using Minitest-like matchers.
8
- #
9
- # Check the use of minitest-like matchers
10
- # starting with `assert_` or `refute_`.
11
- #
12
- # @example
13
- # # bad
14
- # assert_equal(a, b)
15
- # assert_equal a, b, "must be equal"
16
- # assert_not_includes a, b
17
- # refute_equal(a, b)
18
- # assert_nil a
19
- # refute_empty(b)
20
- # assert_true(a)
21
- # assert_false(a)
22
- #
23
- # # good
24
- # expect(b).to eq(a)
25
- # expect(b).to(eq(a), "must be equal")
26
- # expect(a).not_to include(b)
27
- # expect(b).not_to eq(a)
28
- # expect(a).to eq(nil)
29
- # expect(a).not_to be_empty
30
- # expect(a).to be(true)
31
- # expect(a).to be(false)
32
- #
33
- class MinitestAssertions < Base
34
- extend AutoCorrector
35
-
36
- # :nodoc:
37
- class BasicAssertion
38
- extend NodePattern::Macros
39
-
40
- attr_reader :expected, :actual, :failure_message
41
-
42
- def self.minitest_assertion
43
- raise NotImplementedError
44
- end
45
-
46
- def initialize(expected, actual, failure_message)
47
- @expected = expected&.source
48
- @actual = actual.source
49
- @failure_message = failure_message&.source
50
- end
51
-
52
- def replaced(node)
53
- runner = negated?(node) ? 'not_to' : 'to'
54
- if failure_message.nil?
55
- "expect(#{actual}).#{runner} #{assertion}"
56
- else
57
- "expect(#{actual}).#{runner}(#{assertion}, #{failure_message})"
58
- end
59
- end
60
-
61
- def negated?(node)
62
- node.method_name.start_with?('assert_not_', 'refute_')
63
- end
64
-
65
- def assertion
66
- raise NotImplementedError
67
- end
68
- end
69
-
70
- # :nodoc:
71
- class EqualAssertion < BasicAssertion
72
- MATCHERS = %i[
73
- assert_equal
74
- assert_not_equal
75
- refute_equal
76
- ].freeze
77
-
78
- # @!method self.minitest_assertion(node)
79
- def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
80
- (send nil? {:assert_equal :assert_not_equal :refute_equal} $_ $_ $_?)
81
- PATTERN
82
-
83
- def self.match(expected, actual, failure_message)
84
- new(expected, actual, failure_message.first)
85
- end
86
-
87
- def assertion
88
- "eq(#{expected})"
89
- end
90
- end
91
-
92
- # :nodoc:
93
- class KindOfAssertion < BasicAssertion
94
- MATCHERS = %i[
95
- assert_kind_of
96
- assert_not_kind_of
97
- refute_kind_of
98
- ].freeze
99
-
100
- # @!method self.minitest_assertion(node)
101
- def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
102
- (send nil? {:assert_kind_of :assert_not_kind_of :refute_kind_of} $_ $_ $_?)
103
- PATTERN
104
-
105
- def self.match(expected, actual, failure_message)
106
- new(expected, actual, failure_message.first)
107
- end
108
-
109
- def assertion
110
- "be_a_kind_of(#{expected})"
111
- end
112
- end
113
-
114
- # :nodoc:
115
- class InstanceOfAssertion < BasicAssertion
116
- MATCHERS = %i[
117
- assert_instance_of
118
- assert_not_instance_of
119
- refute_instance_of
120
- ].freeze
121
-
122
- # @!method self.minitest_assertion(node)
123
- def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
124
- (send nil? {:assert_instance_of :assert_not_instance_of :refute_instance_of} $_ $_ $_?)
125
- PATTERN
126
-
127
- def self.match(expected, actual, failure_message)
128
- new(expected, actual, failure_message.first)
129
- end
130
-
131
- def assertion
132
- "be_an_instance_of(#{expected})"
133
- end
134
- end
135
-
136
- # :nodoc:
137
- class IncludesAssertion < BasicAssertion
138
- MATCHERS = %i[
139
- assert_includes
140
- assert_not_includes
141
- refute_includes
142
- ].freeze
143
-
144
- # @!method self.minitest_assertion(node)
145
- def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
146
- (send nil? {:assert_includes :assert_not_includes :refute_includes} $_ $_ $_?)
147
- PATTERN
148
-
149
- def self.match(collection, expected, failure_message)
150
- new(expected, collection, failure_message.first)
151
- end
152
-
153
- def assertion
154
- "include(#{expected})"
155
- end
156
- end
157
-
158
- # :nodoc:
159
- class InDeltaAssertion < BasicAssertion
160
- MATCHERS = %i[
161
- assert_in_delta
162
- assert_not_in_delta
163
- refute_in_delta
164
- ].freeze
165
-
166
- # @!method self.minitest_assertion(node)
167
- def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
168
- (send nil? {:assert_in_delta :assert_not_in_delta :refute_in_delta} $_ $_ $_? $_?)
169
- PATTERN
170
-
171
- def self.match(expected, actual, delta, failure_message)
172
- new(expected, actual, delta.first, failure_message.first)
173
- end
174
-
175
- def initialize(expected, actual, delta, fail_message)
176
- super(expected, actual, fail_message)
177
-
178
- @delta = delta&.source || '0.001'
179
- end
180
-
181
- def assertion
182
- "be_within(#{@delta}).of(#{expected})"
183
- end
184
- end
185
-
186
- # :nodoc:
187
- class PredicateAssertion < BasicAssertion
188
- MATCHERS = %i[
189
- assert_predicate
190
- assert_not_predicate
191
- refute_predicate
192
- ].freeze
193
-
194
- # @!method self.minitest_assertion(node)
195
- def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
196
- (send nil? {:assert_predicate :assert_not_predicate :refute_predicate} $_ ${sym} $_?)
197
- PATTERN
198
-
199
- def self.match(subject, predicate, failure_message)
200
- return nil unless predicate.value.end_with?('?')
201
-
202
- new(predicate, subject, failure_message.first)
203
- end
204
-
205
- def assertion
206
- "be_#{expected.delete_prefix(':').delete_suffix('?')}"
207
- end
208
- end
209
-
210
- # :nodoc:
211
- class MatchAssertion < BasicAssertion
212
- MATCHERS = %i[
213
- assert_match
214
- refute_match
215
- ].freeze
216
-
217
- # @!method self.minitest_assertion(node)
218
- def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
219
- (send nil? {:assert_match :refute_match} $_ $_ $_?)
220
- PATTERN
221
-
222
- def self.match(matcher, actual, failure_message)
223
- new(matcher, actual, failure_message.first)
224
- end
225
-
226
- def assertion
227
- "match(#{expected})"
228
- end
229
- end
230
-
231
- # :nodoc:
232
- class NilAssertion < BasicAssertion
233
- MATCHERS = %i[
234
- assert_nil
235
- assert_not_nil
236
- refute_nil
237
- ].freeze
238
-
239
- # @!method self.minitest_assertion(node)
240
- def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
241
- (send nil? {:assert_nil :assert_not_nil :refute_nil} $_ $_?)
242
- PATTERN
243
-
244
- def self.match(actual, failure_message)
245
- new(nil, actual, failure_message.first)
246
- end
247
-
248
- def assertion
249
- 'eq(nil)'
250
- end
251
- end
252
-
253
- # :nodoc:
254
- class EmptyAssertion < BasicAssertion
255
- MATCHERS = %i[
256
- assert_empty
257
- assert_not_empty
258
- refute_empty
259
- ].freeze
260
-
261
- # @!method self.minitest_assertion(node)
262
- def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
263
- (send nil? {:assert_empty :assert_not_empty :refute_empty} $_ $_?)
264
- PATTERN
265
-
266
- def self.match(actual, failure_message)
267
- new(nil, actual, failure_message.first)
268
- end
269
-
270
- def assertion
271
- 'be_empty'
272
- end
273
- end
274
-
275
- # :nodoc:
276
- class TrueAssertion < BasicAssertion
277
- MATCHERS = %i[
278
- assert_true
279
- ].freeze
280
-
281
- # @!method self.minitest_assertion(node)
282
- def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
283
- (send nil? {:assert_true} $_ $_?)
284
- PATTERN
285
-
286
- def self.match(actual, failure_message)
287
- new(nil, actual, failure_message.first)
288
- end
289
-
290
- def assertion
291
- 'be(true)'
292
- end
293
- end
294
-
295
- # :nodoc:
296
- class FalseAssertion < BasicAssertion
297
- MATCHERS = %i[
298
- assert_false
299
- ].freeze
300
-
301
- # @!method self.minitest_assertion(node)
302
- def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
303
- (send nil? {:assert_false} $_ $_?)
304
- PATTERN
305
-
306
- def self.match(actual, failure_message)
307
- new(nil, actual, failure_message.first)
308
- end
309
-
310
- def assertion
311
- 'be(false)'
312
- end
313
- end
314
-
315
- MSG = 'Use `%<prefer>s`.'
316
-
317
- # TODO: replace with `BasicAssertion.subclasses` in Ruby 3.1+
318
- ASSERTION_MATCHERS = constants(false).filter_map do |c|
319
- const = const_get(c)
320
-
321
- const if const.is_a?(Class) && const.superclass == BasicAssertion
322
- end
323
-
324
- RESTRICT_ON_SEND = ASSERTION_MATCHERS.flat_map { |m| m::MATCHERS }
325
-
326
- def on_send(node)
327
- ASSERTION_MATCHERS.each do |m|
328
- m.minitest_assertion(node) do |*args|
329
- assertion = m.match(*args)
330
-
331
- next if assertion.nil?
332
-
333
- on_assertion(node, assertion)
334
- end
335
- end
336
- end
337
-
338
- def on_assertion(node, assertion)
339
- preferred = assertion.replaced(node)
340
- add_offense(node, message: message(preferred)) do |corrector|
341
- corrector.replace(node, preferred)
342
- end
343
- end
344
-
345
- def message(preferred)
346
- format(MSG, prefer: preferred)
347
- end
348
- end
7
+ # @!parse
8
+ # # Check if using Minitest-like matchers.
9
+ # #
10
+ # # Check the use of minitest-like matchers
11
+ # # starting with `assert_` or `refute_`.
12
+ # #
13
+ # # @example
14
+ # # # bad
15
+ # # assert_equal(a, b)
16
+ # # assert_equal a, b, "must be equal"
17
+ # # assert_not_includes a, b
18
+ # # refute_equal(a, b)
19
+ # # assert_nil a
20
+ # # refute_empty(b)
21
+ # # assert_true(a)
22
+ # # assert_false(a)
23
+ # #
24
+ # # # good
25
+ # # expect(b).to eq(a)
26
+ # # expect(b).to(eq(a), "must be equal")
27
+ # # expect(a).not_to include(b)
28
+ # # expect(b).not_to eq(a)
29
+ # # expect(a).to eq(nil)
30
+ # # expect(a).not_to be_empty
31
+ # # expect(a).to be(true)
32
+ # # expect(a).to be(false)
33
+ # #
34
+ # class MinitestAssertions < RuboCop::Cop::RSpecRails::Base; end
35
+ MinitestAssertions = ::RuboCop::Cop::RSpecRails::MinitestAssertions
349
36
  end
350
37
  end
351
38
  end
@@ -4,98 +4,35 @@ module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
6
  module Rails
7
- # Enforces use of `be_invalid` or `not_to` for negated be_valid.
8
- #
9
- # @safety
10
- # This cop is unsafe because it cannot guarantee that
11
- # the test target is an instance of `ActiveModel::Validations``.
12
- #
13
- # @example EnforcedStyle: not_to (default)
14
- # # bad
15
- # expect(foo).to be_invalid
16
- #
17
- # # good
18
- # expect(foo).not_to be_valid
19
- #
20
- # # good (with method chain)
21
- # expect(foo).to be_invalid.and be_odd
22
- #
23
- # @example EnforcedStyle: be_invalid
24
- # # bad
25
- # expect(foo).not_to be_valid
26
- #
27
- # # good
28
- # expect(foo).to be_invalid
29
- #
30
- # # good (with method chain)
31
- # expect(foo).to be_invalid.or be_even
32
- #
33
- class NegationBeValid < Base
34
- extend AutoCorrector
35
- include ConfigurableEnforcedStyle
36
-
37
- MSG = 'Use `expect(...).%<runner>s %<matcher>s`.'
38
- RESTRICT_ON_SEND = %i[be_valid be_invalid].freeze
39
-
40
- # @!method not_to?(node)
41
- def_node_matcher :not_to?, <<~PATTERN
42
- (send ... :not_to (send nil? :be_valid ...))
43
- PATTERN
44
-
45
- # @!method be_invalid?(node)
46
- def_node_matcher :be_invalid?, <<~PATTERN
47
- (send ... :to (send nil? :be_invalid ...))
48
- PATTERN
49
-
50
- def on_send(node)
51
- return unless offense?(node.parent)
52
-
53
- add_offense(offense_range(node),
54
- message: message(node.method_name)) do |corrector|
55
- corrector.replace(node.parent.loc.selector, replaced_runner)
56
- corrector.replace(node.loc.selector, replaced_matcher)
57
- end
58
- end
59
-
60
- private
61
-
62
- def offense?(node)
63
- case style
64
- when :not_to
65
- be_invalid?(node)
66
- when :be_invalid
67
- not_to?(node)
68
- end
69
- end
70
-
71
- def offense_range(node)
72
- node.parent.loc.selector.with(end_pos: node.loc.selector.end_pos)
73
- end
74
-
75
- def message(_matcher)
76
- format(MSG,
77
- runner: replaced_runner,
78
- matcher: replaced_matcher)
79
- end
80
-
81
- def replaced_runner
82
- case style
83
- when :not_to
84
- 'not_to'
85
- when :be_invalid
86
- 'to'
87
- end
88
- end
89
-
90
- def replaced_matcher
91
- case style
92
- when :not_to
93
- 'be_valid'
94
- when :be_invalid
95
- 'be_invalid'
96
- end
97
- end
98
- end
7
+ # @!parse
8
+ # # Enforces use of `be_invalid` or `not_to` for negated be_valid.
9
+ # #
10
+ # # @safety
11
+ # # This cop is unsafe because it cannot guarantee that
12
+ # # the test target is an instance of `ActiveModel::Validations``.
13
+ # #
14
+ # # @example EnforcedStyle: not_to (default)
15
+ # # # bad
16
+ # # expect(foo).to be_invalid
17
+ # #
18
+ # # # good
19
+ # # expect(foo).not_to be_valid
20
+ # #
21
+ # # # good (with method chain)
22
+ # # expect(foo).to be_invalid.and be_odd
23
+ # #
24
+ # # @example EnforcedStyle: be_invalid
25
+ # # # bad
26
+ # # expect(foo).not_to be_valid
27
+ # #
28
+ # # # good
29
+ # # expect(foo).to be_invalid
30
+ # #
31
+ # # # good (with method chain)
32
+ # # expect(foo).to be_invalid.or be_even
33
+ # #
34
+ # class NegationBeValid < RuboCop::Cop::RSpecRails::Base; end
35
+ NegationBeValid = ::RuboCop::Cop::RSpecRails::NegationBeValid
99
36
  end
100
37
  end
101
38
  end
@@ -4,88 +4,30 @@ module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
6
  module Rails
7
- # Prefer to travel in `before` rather than `around`.
8
- #
9
- # @safety
10
- # This cop is unsafe because the automatic `travel_back` is only run
11
- # on test cases that are considered as Rails related.
12
- #
13
- # And also, this cop's autocorrection is unsafe because the order of
14
- # execution will change if other steps exist before traveling in
15
- # `around`.
16
- #
17
- # @example
18
- # # bad
19
- # around do |example|
20
- # freeze_time do
21
- # example.run
22
- # end
23
- # end
24
- #
25
- # # good
26
- # before { freeze_time }
27
- class TravelAround < Base
28
- extend AutoCorrector
29
-
30
- MSG = 'Prefer to travel in `before` rather than `around`.'
31
-
32
- TRAVEL_METHOD_NAMES = %i[
33
- freeze_time
34
- travel
35
- travel_to
36
- ].to_set.freeze
37
-
38
- # @!method extract_run_in_travel(node)
39
- def_node_matcher :extract_run_in_travel, <<~PATTERN
40
- (block
41
- $(send nil? TRAVEL_METHOD_NAMES ...)
42
- (args ...)
43
- (send _ :run)
44
- )
45
- PATTERN
46
-
47
- # @!method match_around_each?(node)
48
- def_node_matcher :match_around_each?, <<~PATTERN
49
- (block
50
- (send _ :around (sym :each)?)
51
- ...
52
- )
53
- PATTERN
54
-
55
- def on_block(node)
56
- run_node = extract_run_in_travel(node)
57
- return unless run_node
58
-
59
- around_node = extract_surrounding_around_block(run_node)
60
- return unless around_node
61
-
62
- add_offense(node) do |corrector|
63
- autocorrect(corrector, node, run_node, around_node)
64
- end
65
- end
66
- alias on_numblock on_block
67
-
68
- private
69
-
70
- def autocorrect(corrector, node, run_node, around_node)
71
- corrector.replace(
72
- node,
73
- node.body.source
74
- )
75
- corrector.insert_before(
76
- around_node,
77
- "before { #{run_node.source} }\n\n"
78
- )
79
- end
80
-
81
- # @param node [RuboCop::AST::BlockNode]
82
- # @return [RuboCop::AST::BlockNode, nil]
83
- def extract_surrounding_around_block(node)
84
- node.each_ancestor(:block).find do |ancestor|
85
- match_around_each?(ancestor)
86
- end
87
- end
88
- end
7
+ # @!parse
8
+ # # Prefer to travel in `before` rather than `around`.
9
+ # #
10
+ # # @safety
11
+ # # This cop is unsafe because the automatic `travel_back` is only
12
+ # # run on test cases that are considered as Rails related.
13
+ # #
14
+ # # And also, this cop's autocorrection is unsafe because the order
15
+ # # of execution will change if other steps exist before traveling
16
+ # # in `around`.
17
+ # #
18
+ # # @example
19
+ # # # bad
20
+ # # around do |example|
21
+ # # freeze_time do
22
+ # # example.run
23
+ # # end
24
+ # # end
25
+ # #
26
+ # # # good
27
+ # # before { freeze_time }
28
+ # #
29
+ # class TravelAround < RuboCop::Cop::RSpecRails::Base; end
30
+ TravelAround = ::RuboCop::Cop::RSpecRails::TravelAround
89
31
  end
90
32
  end
91
33
  end
@@ -18,14 +18,10 @@ require_relative 'rspec/factory_bot/syntax_methods'
18
18
 
19
19
  require_relative 'rspec/rails/avoid_setup_hook'
20
20
  require_relative 'rspec/rails/have_http_status'
21
- require_relative 'rspec/rails/negation_be_valid'
22
- begin
23
- require_relative 'rspec/rails/http_status'
24
- rescue LoadError
25
- # Rails/HttpStatus cannot be loaded if rack/utils is unavailable.
26
- end
21
+ require_relative 'rspec/rails/http_status'
27
22
  require_relative 'rspec/rails/inferred_spec_type'
28
23
  require_relative 'rspec/rails/minitest_assertions'
24
+ require_relative 'rspec/rails/negation_be_valid'
29
25
  require_relative 'rspec/rails/travel_around'
30
26
 
31
27
  require_relative 'rspec/align_left_let_brace'
@@ -22,6 +22,13 @@ module RuboCop
22
22
  RSpec/FactoryBot/FactoryClassName
23
23
  RSpec/FactoryBot/FactoryNameStyle
24
24
  RSpec/FactoryBot/SyntaxMethods
25
+ RSpec/Rails/AvoidSetupHook
26
+ RSpec/Rails/HaveHttpStatus
27
+ RSpec/Rails/HttpStatus
28
+ RSpec/Rails/InferredSpecType
29
+ RSpec/Rails/MinitestAssertions
30
+ RSpec/Rails/NegationBeValid
31
+ RSpec/Rails/TravelAround
25
32
  )
26
33
  AMENDMENTS = %(Metrics/BlockLength)
27
34
  COP_DOC_BASE_URL = 'https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/'
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module RSpec
5
5
  # Version information for the RSpec RuboCop plugin.
6
6
  module Version
7
- STRING = '2.27.1'
7
+ STRING = '2.28.0'
8
8
  end
9
9
  end
10
10
  end
data/lib/rubocop-rspec.rb CHANGED
@@ -39,6 +39,9 @@ require_relative 'rubocop/rspec/example'
39
39
  require_relative 'rubocop/rspec/example_group'
40
40
  require_relative 'rubocop/rspec/hook'
41
41
 
42
+ # need after `require 'rubocop/cop/rspec/base'``
43
+ require 'rubocop-rspec_rails'
44
+
42
45
  RuboCop::RSpec::Inject.defaults!
43
46
 
44
47
  require_relative 'rubocop/cop/rspec_cops'