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.
@@ -4,141 +4,58 @@ module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
6
  module Rails
7
- # Identifies redundant spec type.
8
- #
9
- # After setting up rspec-rails, you will have enabled
10
- # `config.infer_spec_type_from_file_location!` by default in
11
- # spec/rails_helper.rb. This cop works in conjunction with this config.
12
- # If you disable this config, disable this cop as well.
13
- #
14
- # @safety
15
- # This cop is marked as unsafe because
16
- # `config.infer_spec_type_from_file_location!` may not be enabled.
17
- #
18
- # @example
19
- # # bad
20
- # # spec/models/user_spec.rb
21
- # RSpec.describe User, type: :model do
22
- # end
23
- #
24
- # # good
25
- # # spec/models/user_spec.rb
26
- # RSpec.describe User do
27
- # end
28
- #
29
- # # good
30
- # # spec/models/user_spec.rb
31
- # RSpec.describe User, type: :common do
32
- # end
33
- #
34
- # @example `Inferences` configuration
35
- # # .rubocop.yml
36
- # # RSpec/Rails/InferredSpecType:
37
- # # Inferences:
38
- # # services: service
39
- #
40
- # # bad
41
- # # spec/services/user_spec.rb
42
- # RSpec.describe User, type: :service do
43
- # end
44
- #
45
- # # good
46
- # # spec/services/user_spec.rb
47
- # RSpec.describe User do
48
- # end
49
- #
50
- # # good
51
- # # spec/services/user_spec.rb
52
- # RSpec.describe User, type: :common do
53
- # end
54
- class InferredSpecType < Base
55
- extend AutoCorrector
56
-
57
- MSG = 'Remove redundant spec type.'
58
-
59
- # @param [RuboCop::AST::BlockNode] node
60
- def on_block(node)
61
- return unless example_group?(node)
62
-
63
- pair_node = describe_with_type(node)
64
- return unless pair_node
65
- return unless inferred_type?(pair_node)
66
-
67
- removable_node = detect_removable_node(pair_node)
68
- add_offense(removable_node) do |corrector|
69
- autocorrect(corrector, removable_node)
70
- end
71
- end
72
- alias on_numblock on_block
73
-
74
- private
75
-
76
- # @!method describe_with_type(node)
77
- # @param [RuboCop::AST::BlockNode] node
78
- # @return [RuboCop::AST::PairNode, nil]
79
- def_node_matcher :describe_with_type, <<~PATTERN
80
- (block
81
- (send #rspec? #ExampleGroups.all
82
- ...
83
- (hash <$(pair (sym :type) sym) ...>)
84
- )
85
- ...
86
- )
87
- PATTERN
88
-
89
- # @param [RuboCop::AST::Corrector] corrector
90
- # @param [RuboCop::AST::Node] node
91
- def autocorrect(corrector, node)
92
- corrector.remove(remove_range(node))
93
- end
94
-
95
- # @param [RuboCop::AST::Node] node
96
- # @return [Parser::Source::Range]
97
- def remove_range(node)
98
- if node.left_sibling
99
- node.source_range.with(
100
- begin_pos: node.left_sibling.source_range.end_pos
101
- )
102
- elsif node.right_sibling
103
- node.source_range.with(
104
- end_pos: node.right_sibling.source_range.begin_pos
105
- )
106
- end
107
- end
108
-
109
- # @param [RuboCop::AST::PairNode] node
110
- # @return [RuboCop::AST::Node]
111
- def detect_removable_node(node)
112
- if node.parent.pairs.size == 1
113
- node.parent
114
- else
115
- node
116
- end
117
- end
118
-
119
- # @return [String]
120
- def file_path
121
- processed_source.file_path
122
- end
123
-
124
- # @param [RuboCop::AST::PairNode] node
125
- # @return [Boolean]
126
- def inferred_type?(node)
127
- inferred_type_from_file_path.inspect == node.value.source
128
- end
129
-
130
- # @return [Symbol, nil]
131
- def inferred_type_from_file_path
132
- inferences.find do |prefix, type|
133
- break type.to_sym if file_path.include?("spec/#{prefix}/")
134
- end
135
- end
136
-
137
- # @return [Hash]
138
- def inferences
139
- cop_config['Inferences'] || {}
140
- end
141
- end
7
+ # @!parse
8
+ # # Identifies redundant spec type.
9
+ # #
10
+ # # After setting up rspec-rails, you will have enabled
11
+ # # `config.infer_spec_type_from_file_location!` by default in
12
+ # # spec/rails_helper.rb. This cop works in conjunction with
13
+ # # this config.
14
+ # # If you disable this config, disable this cop as well.
15
+ # #
16
+ # # @safety
17
+ # # This cop is marked as unsafe because
18
+ # # `config.infer_spec_type_from_file_location!` may not be enabled.
19
+ # #
20
+ # # @example
21
+ # # # bad
22
+ # # # spec/models/user_spec.rb
23
+ # # RSpec.describe User, type: :model do
24
+ # # end
25
+ # #
26
+ # # # good
27
+ # # # spec/models/user_spec.rb
28
+ # # RSpec.describe User do
29
+ # # end
30
+ # #
31
+ # # # good
32
+ # # # spec/models/user_spec.rb
33
+ # # RSpec.describe User, type: :common do
34
+ # # end
35
+ # #
36
+ # # @example `Inferences` configuration
37
+ # # # .rubocop.yml
38
+ # # # RSpec/Rails/InferredSpecType:
39
+ # # # Inferences:
40
+ # # # services: service
41
+ # #
42
+ # # # bad
43
+ # # # spec/services/user_spec.rb
44
+ # # RSpec.describe User, type: :service do
45
+ # # end
46
+ # #
47
+ # # # good
48
+ # # # spec/services/user_spec.rb
49
+ # # RSpec.describe User do
50
+ # # end
51
+ # #
52
+ # # # good
53
+ # # # spec/services/user_spec.rb
54
+ # # RSpec.describe User, type: :common do
55
+ # # end
56
+ # #
57
+ # class InferredSpecType < RuboCop::Cop::RSpec::Base; end
58
+ InferredSpecType = ::RuboCop::Cop::RSpecRails::InferredSpecType
142
59
  end
143
60
  end
144
61
  end
@@ -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::RSpec::Base; end
35
+ MinitestAssertions = ::RuboCop::Cop::RSpecRails::MinitestAssertions
349
36
  end
350
37
  end
351
38
  end