rubocop-rspec 2.27.1 → 2.28.0

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