rubocop-rspec 2.29.1 → 3.5.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 +4 -4
- data/CHANGELOG.md +92 -3
- data/README.md +21 -5
- data/config/default.yml +64 -269
- data/config/obsoletion.yml +20 -21
- data/lib/rubocop/cop/rspec/around_block.rb +2 -4
- data/lib/rubocop/cop/rspec/base.rb +0 -1
- data/lib/rubocop/cop/rspec/be_eq.rb +1 -1
- data/lib/rubocop/cop/rspec/be_eql.rb +1 -1
- data/lib/rubocop/cop/rspec/be_nil.rb +4 -0
- data/lib/rubocop/cop/rspec/change_by_zero.rb +4 -5
- data/lib/rubocop/cop/rspec/contain_exactly.rb +1 -0
- data/lib/rubocop/cop/rspec/context_wording.rb +15 -9
- data/lib/rubocop/cop/rspec/dialect.rb +13 -0
- data/lib/rubocop/cop/rspec/empty_example_group.rb +2 -0
- data/lib/rubocop/cop/rspec/empty_metadata.rb +1 -0
- data/lib/rubocop/cop/rspec/example_wording.rb +3 -5
- data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +1 -1
- data/lib/rubocop/cop/rspec/expect_actual.rb +3 -3
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +1 -1
- data/lib/rubocop/cop/rspec/expect_in_let.rb +42 -0
- data/lib/rubocop/cop/rspec/focus.rb +14 -16
- data/lib/rubocop/cop/rspec/implicit_expect.rb +3 -3
- data/lib/rubocop/cop/rspec/implicit_subject.rb +8 -0
- data/lib/rubocop/cop/rspec/indexed_let.rb +6 -3
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +1 -1
- data/lib/rubocop/cop/rspec/match_array.rb +1 -0
- data/lib/rubocop/cop/rspec/message_spies.rb +4 -0
- data/lib/rubocop/cop/rspec/metadata_style.rb +1 -6
- data/lib/rubocop/cop/rspec/missing_expectation_target_method.rb +54 -0
- data/lib/rubocop/cop/rspec/mixin/metadata.rb +5 -8
- data/lib/rubocop/cop/rspec/mixin/top_level_group.rb +7 -0
- data/lib/rubocop/cop/rspec/multiple_describes.rb +1 -1
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +4 -4
- data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +4 -5
- data/lib/rubocop/cop/rspec/named_subject.rb +5 -2
- data/lib/rubocop/cop/rspec/nested_groups.rb +2 -1
- data/lib/rubocop/cop/rspec/pending_without_reason.rb +0 -5
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +25 -11
- data/lib/rubocop/cop/rspec/remove_const.rb +0 -1
- data/lib/rubocop/cop/rspec/repeated_subject_call.rb +1 -0
- data/lib/rubocop/cop/rspec/return_from_stub.rb +5 -4
- data/lib/rubocop/cop/rspec/scattered_setup.rb +7 -1
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +3 -4
- data/lib/rubocop/cop/rspec/sort_metadata.rb +22 -8
- data/lib/rubocop/cop/rspec/stubbed_mock.rb +15 -10
- data/lib/rubocop/cop/rspec/subject_stub.rb +2 -2
- data/lib/rubocop/cop/rspec/unspecified_exception.rb +21 -14
- data/lib/rubocop/cop/rspec/verified_double_reference.rb +14 -53
- data/lib/rubocop/cop/rspec/void_expect.rb +6 -1
- data/lib/rubocop/cop/rspec_cops.rb +2 -25
- data/lib/rubocop/rspec/concept.rb +0 -1
- data/lib/rubocop/rspec/config_formatter.rb +4 -32
- data/lib/rubocop/rspec/cop/generator.rb +25 -0
- data/lib/rubocop/rspec/description_extractor.rb +2 -2
- data/lib/rubocop/rspec/hook.rb +1 -1
- data/lib/rubocop/rspec/language.rb +0 -1
- data/lib/rubocop/rspec/node.rb +1 -1
- data/lib/rubocop/rspec/plugin.rb +37 -0
- data/lib/rubocop/rspec/shared_contexts/default_rspec_language_config_context.rb +1 -1
- data/lib/rubocop/rspec/version.rb +1 -1
- data/lib/rubocop/rspec/wording.rb +2 -4
- data/lib/rubocop/rspec.rb +0 -7
- data/lib/rubocop-rspec.rb +2 -20
- metadata +18 -62
- data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +0 -39
- data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +0 -104
- data/lib/rubocop/cop/rspec/capybara/match_style.rb +0 -38
- data/lib/rubocop/cop/rspec/capybara/negation_matcher.rb +0 -33
- data/lib/rubocop/cop/rspec/capybara/specific_actions.rb +0 -29
- data/lib/rubocop/cop/rspec/capybara/specific_finders.rb +0 -24
- data/lib/rubocop/cop/rspec/capybara/specific_matcher.rb +0 -35
- data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +0 -36
- data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +0 -35
- data/lib/rubocop/cop/rspec/factory_bot/consistent_parentheses_style.rb +0 -50
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +0 -40
- data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +0 -29
- data/lib/rubocop/cop/rspec/factory_bot/factory_name_style.rb +0 -33
- data/lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb +0 -55
- data/lib/rubocop/cop/rspec/file_path.rb +0 -179
- data/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb +0 -27
- data/lib/rubocop/cop/rspec/rails/have_http_status.rb +0 -35
- data/lib/rubocop/cop/rspec/rails/http_status.rb +0 -61
- data/lib/rubocop/cop/rspec/rails/inferred_spec_type.rb +0 -62
- data/lib/rubocop/cop/rspec/rails/minitest_assertions.rb +0 -39
- data/lib/rubocop/cop/rspec/rails/negation_be_valid.rb +0 -39
- data/lib/rubocop/cop/rspec/rails/travel_around.rb +0 -34
- data/lib/rubocop/rspec/inject.rb +0 -18
- data/lib/rubocop/rspec/language/node_pattern.rb +0 -48
@@ -94,11 +94,6 @@ module RuboCop
|
|
94
94
|
(send #rspec? ${#ExampleGroups.skipped} ...)
|
95
95
|
PATTERN
|
96
96
|
|
97
|
-
# @!method pending_step_without_reason?(node)
|
98
|
-
def_node_matcher :pending_step_without_reason?, <<~PATTERN
|
99
|
-
(send nil? {:skip :pending})
|
100
|
-
PATTERN
|
101
|
-
|
102
97
|
def on_send(node)
|
103
98
|
on_pending_by_metadata(node)
|
104
99
|
return unless (parent = parent_node(node))
|
@@ -15,6 +15,8 @@ module RuboCop
|
|
15
15
|
|
16
16
|
def check_inflected(node)
|
17
17
|
predicate_in_actual?(node) do |predicate, to, matcher|
|
18
|
+
next if cannot_replace_predicate?(predicate)
|
19
|
+
|
18
20
|
msg = message_inflected(predicate)
|
19
21
|
add_offense(node, message: msg) do |corrector|
|
20
22
|
remove_predicate(corrector, predicate)
|
@@ -32,12 +34,16 @@ module RuboCop
|
|
32
34
|
(block $(send !nil? #predicate? ...) ...)
|
33
35
|
$(send !nil? #predicate? ...)})
|
34
36
|
$#Runners.all
|
35
|
-
$#boolean_matcher?)
|
37
|
+
$#boolean_matcher? ...)
|
36
38
|
PATTERN
|
37
39
|
|
40
|
+
def cannot_replace_predicate?(send_node)
|
41
|
+
send_node.method?(:respond_to?) && send_node.arguments.length > 1
|
42
|
+
end
|
43
|
+
|
38
44
|
# @!method be_bool?(node)
|
39
45
|
def_node_matcher :be_bool?, <<~PATTERN
|
40
|
-
(send nil? {:be :eq :eql :equal}
|
46
|
+
(send nil? {:be :eq :eql :equal} boolean)
|
41
47
|
PATTERN
|
42
48
|
|
43
49
|
# @!method be_boolthy?(node)
|
@@ -63,7 +69,6 @@ module RuboCop
|
|
63
69
|
matcher_name: to_predicate_matcher(predicate.method_name))
|
64
70
|
end
|
65
71
|
|
66
|
-
# rubocop:disable Metrics/MethodLength
|
67
72
|
def to_predicate_matcher(name)
|
68
73
|
case name = name.to_s
|
69
74
|
when 'is_a?'
|
@@ -80,7 +85,6 @@ module RuboCop
|
|
80
85
|
"be_#{name[0..-2]}"
|
81
86
|
end
|
82
87
|
end
|
83
|
-
# rubocop:enable Metrics/MethodLength
|
84
88
|
|
85
89
|
def remove_predicate(corrector, predicate)
|
86
90
|
range = predicate.loc.dot.with(
|
@@ -106,12 +110,16 @@ module RuboCop
|
|
106
110
|
|
107
111
|
def true?(to_symbol, matcher)
|
108
112
|
result = case matcher.method_name
|
109
|
-
when :be, :eq
|
113
|
+
when :be, :eq, :eql, :equal
|
110
114
|
matcher.first_argument.true_type?
|
111
115
|
when :be_truthy, :a_truthy_value
|
112
116
|
true
|
113
117
|
when :be_falsey, :be_falsy, :a_falsey_value, :a_falsy_value
|
114
118
|
false
|
119
|
+
else
|
120
|
+
# :nocov:
|
121
|
+
:noop
|
122
|
+
# :nocov:
|
115
123
|
end
|
116
124
|
to_symbol == :to ? result : !result
|
117
125
|
end
|
@@ -174,7 +182,7 @@ module RuboCop
|
|
174
182
|
|
175
183
|
def heredoc_argument?(matcher)
|
176
184
|
matcher.arguments.select do |arg|
|
177
|
-
|
185
|
+
arg.str_type? || arg.dstr_type? || arg.xstr_type?
|
178
186
|
end.any?(&:heredoc?)
|
179
187
|
end
|
180
188
|
|
@@ -183,8 +191,12 @@ module RuboCop
|
|
183
191
|
(send
|
184
192
|
(send nil? :expect $!nil?)
|
185
193
|
#Runners.all
|
186
|
-
{
|
187
|
-
|
194
|
+
{
|
195
|
+
$(send nil? #predicate_matcher_name? ...)
|
196
|
+
(block $(send nil? #predicate_matcher_name? ...) ...)
|
197
|
+
}
|
198
|
+
...
|
199
|
+
)
|
188
200
|
PATTERN
|
189
201
|
|
190
202
|
# @!method predicate_matcher_block?(node)
|
@@ -229,7 +241,6 @@ module RuboCop
|
|
229
241
|
corrector.insert_after(actual, ".#{predicate}" + args + block)
|
230
242
|
end
|
231
243
|
|
232
|
-
# rubocop:disable Metrics/MethodLength
|
233
244
|
def to_predicate_method(matcher)
|
234
245
|
case matcher = matcher.to_s
|
235
246
|
when 'be_a', 'be_an', 'be_a_kind_of', 'a_kind_of', 'be_kind_of'
|
@@ -246,7 +257,6 @@ module RuboCop
|
|
246
257
|
"#{matcher[/\Abe_(.+)/, 1]}?"
|
247
258
|
end
|
248
259
|
end
|
249
|
-
# rubocop:enable Metrics/MethodLength
|
250
260
|
|
251
261
|
def replacement_matcher(node)
|
252
262
|
case [cop_config['Strict'], node.method?(:to)]
|
@@ -256,7 +266,7 @@ module RuboCop
|
|
256
266
|
'be(false)'
|
257
267
|
when [false, true]
|
258
268
|
'be_truthy'
|
259
|
-
|
269
|
+
else
|
260
270
|
'be_falsey'
|
261
271
|
end
|
262
272
|
end
|
@@ -325,6 +335,10 @@ module RuboCop
|
|
325
335
|
check_inflected(node)
|
326
336
|
when :explicit
|
327
337
|
check_explicit(node)
|
338
|
+
else
|
339
|
+
# :nocov:
|
340
|
+
:noop
|
341
|
+
# :nocov:
|
328
342
|
end
|
329
343
|
end
|
330
344
|
|
@@ -80,10 +80,10 @@ module RuboCop
|
|
80
80
|
|
81
81
|
def check_block_body(block)
|
82
82
|
body = block.body
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
83
|
+
return if dynamic?(body)
|
84
|
+
|
85
|
+
add_offense(block.loc.begin, message: MSG_AND_RETURN) do |corrector|
|
86
|
+
BlockBodyCorrector.new(block).call(corrector)
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
@@ -162,6 +162,7 @@ module RuboCop
|
|
162
162
|
end
|
163
163
|
|
164
164
|
NULL_BLOCK_BODY = Struct.new(:loc, :source).new(nil, 'nil')
|
165
|
+
private_constant :NULL_BLOCK_BODY
|
165
166
|
end
|
166
167
|
end
|
167
168
|
end
|
@@ -23,6 +23,7 @@ module RuboCop
|
|
23
23
|
# end
|
24
24
|
#
|
25
25
|
class ScatteredSetup < Base
|
26
|
+
include FinalEndLocation
|
26
27
|
include RangeHelp
|
27
28
|
extend AutoCorrector
|
28
29
|
|
@@ -75,8 +76,13 @@ module RuboCop
|
|
75
76
|
def autocorrect(corrector, first_occurrence, occurrence)
|
76
77
|
return if first_occurrence == occurrence || !first_occurrence.body
|
77
78
|
|
79
|
+
# Take heredocs into account
|
80
|
+
body = occurrence.body&.source_range&.with(
|
81
|
+
end_pos: final_end_location(occurrence).begin_pos
|
82
|
+
)
|
83
|
+
|
78
84
|
corrector.insert_after(first_occurrence.body,
|
79
|
-
"\n#{
|
85
|
+
"\n#{body&.source}")
|
80
86
|
corrector.remove(range_by_whole_lines(occurrence.source_range,
|
81
87
|
include_final_newline: true))
|
82
88
|
end
|
@@ -67,11 +67,10 @@ module RuboCop
|
|
67
67
|
end
|
68
68
|
|
69
69
|
def autocorrect_hash_arg(corrector, arg)
|
70
|
-
|
71
|
-
|
72
|
-
corrector.replace(arg, key_to_arg(key))
|
70
|
+
pair = arg.pairs.first
|
71
|
+
corrector.replace(arg, key_to_arg(pair.key))
|
73
72
|
corrector.insert_after(arg.parent.loc.end,
|
74
|
-
".and_return(#{value.source})")
|
73
|
+
".and_return(#{pair.value.source})")
|
75
74
|
end
|
76
75
|
|
77
76
|
def autocorrect_array_arg(corrector, arg)
|
@@ -5,6 +5,8 @@ module RuboCop
|
|
5
5
|
module RSpec
|
6
6
|
# Sort RSpec metadata alphabetically.
|
7
7
|
#
|
8
|
+
# Only the trailing metadata is sorted.
|
9
|
+
#
|
8
10
|
# @example
|
9
11
|
# # bad
|
10
12
|
# describe 'Something', :b, :a
|
@@ -16,6 +18,9 @@ module RuboCop
|
|
16
18
|
# context 'Something', baz: true, foo: 'bar'
|
17
19
|
# it 'works', :a, :b, baz: true, foo: 'bar'
|
18
20
|
#
|
21
|
+
# # good, trailing metadata is sorted
|
22
|
+
# describe 'Something', 'description', :a, :b, :z
|
23
|
+
# context 'Something', :z, variable, :a, :b
|
19
24
|
class SortMetadata < Base
|
20
25
|
extend AutoCorrector
|
21
26
|
include Metadata
|
@@ -23,8 +28,14 @@ module RuboCop
|
|
23
28
|
|
24
29
|
MSG = 'Sort metadata alphabetically.'
|
25
30
|
|
26
|
-
|
31
|
+
# @!method match_ambiguous_trailing_metadata?(node)
|
32
|
+
def_node_matcher :match_ambiguous_trailing_metadata?, <<~PATTERN
|
33
|
+
(send _ _ _ ... !{hash sym str dstr xstr})
|
34
|
+
PATTERN
|
35
|
+
|
36
|
+
def on_metadata(args, hash)
|
27
37
|
pairs = hash&.pairs || []
|
38
|
+
symbols = trailing_symbols(args)
|
28
39
|
return if sorted?(symbols, pairs)
|
29
40
|
|
30
41
|
crime_scene = crime_scene(symbols, pairs)
|
@@ -35,6 +46,15 @@ module RuboCop
|
|
35
46
|
|
36
47
|
private
|
37
48
|
|
49
|
+
def trailing_symbols(args)
|
50
|
+
args = args[...-1] if last_arg_could_be_a_hash?(args)
|
51
|
+
args.reverse.take_while(&:sym_type?).reverse
|
52
|
+
end
|
53
|
+
|
54
|
+
def last_arg_could_be_a_hash?(args)
|
55
|
+
args.last && match_ambiguous_trailing_metadata?(args.last.parent)
|
56
|
+
end
|
57
|
+
|
38
58
|
def crime_scene(symbols, pairs)
|
39
59
|
metadata = symbols + pairs
|
40
60
|
|
@@ -57,13 +77,7 @@ module RuboCop
|
|
57
77
|
end
|
58
78
|
|
59
79
|
def sort_symbols(symbols)
|
60
|
-
symbols.sort_by
|
61
|
-
if %i[str sym].include?(symbol.type)
|
62
|
-
symbol.value.to_s.downcase
|
63
|
-
else
|
64
|
-
symbol.source.downcase
|
65
|
-
end
|
66
|
-
end
|
80
|
+
symbols.sort_by { |symbol| symbol.value.to_s.downcase }
|
67
81
|
end
|
68
82
|
end
|
69
83
|
end
|
@@ -14,8 +14,9 @@ module RuboCop
|
|
14
14
|
# expect(foo).to receive(:bar).with(42)
|
15
15
|
#
|
16
16
|
class StubbedMock < Base
|
17
|
-
MSG = 'Prefer
|
17
|
+
MSG = 'Prefer %<replacement>s over `%<method_name>s` when ' \
|
18
18
|
'configuring a response.'
|
19
|
+
RESTRICT_ON_SEND = %i[to].freeze
|
19
20
|
|
20
21
|
# @!method message_expectation?(node)
|
21
22
|
# Match message expectation matcher
|
@@ -133,10 +134,10 @@ module RuboCop
|
|
133
134
|
}
|
134
135
|
PATTERN
|
135
136
|
|
136
|
-
RESTRICT_ON_SEND = %i[to].freeze
|
137
|
-
|
138
137
|
def on_send(node)
|
139
|
-
expectation(node,
|
138
|
+
expectation(node) do |expectation, method_name, matcher|
|
139
|
+
on_expectation(expectation, method_name, matcher)
|
140
|
+
end
|
140
141
|
end
|
141
142
|
|
142
143
|
private
|
@@ -153,19 +154,23 @@ module RuboCop
|
|
153
154
|
end
|
154
155
|
|
155
156
|
def msg(method_name)
|
156
|
-
format(
|
157
|
-
|
158
|
-
|
157
|
+
format(
|
158
|
+
MSG,
|
159
|
+
method_name: method_name,
|
160
|
+
replacement: replacement(method_name)
|
161
|
+
)
|
159
162
|
end
|
160
163
|
|
161
164
|
def replacement(method_name)
|
162
165
|
case method_name
|
163
166
|
when :expect
|
164
|
-
|
167
|
+
'`allow`'
|
165
168
|
when :is_expected
|
166
|
-
'allow(subject)'
|
169
|
+
'`allow(subject)`'
|
167
170
|
when :expect_any_instance_of
|
168
|
-
|
171
|
+
'`allow_any_instance_of`'
|
172
|
+
else
|
173
|
+
'an allow statement'
|
169
174
|
end
|
170
175
|
end
|
171
176
|
end
|
@@ -113,8 +113,8 @@ module RuboCop
|
|
113
113
|
PATTERN
|
114
114
|
|
115
115
|
def on_top_level_group(node)
|
116
|
-
@explicit_subjects = find_all_explicit(node
|
117
|
-
@subject_overrides = find_all_explicit(node
|
116
|
+
@explicit_subjects = find_all_explicit(node) { |n| subject?(n) }
|
117
|
+
@subject_overrides = find_all_explicit(node) { |n| let?(n) }
|
118
118
|
|
119
119
|
find_subject_expectations(node) do |stub|
|
120
120
|
add_offense(stub)
|
@@ -32,34 +32,41 @@ module RuboCop
|
|
32
32
|
#
|
33
33
|
class UnspecifiedException < Base
|
34
34
|
MSG = 'Specify the exception being captured'
|
35
|
-
RESTRICT_ON_SEND = %i[to].freeze
|
36
35
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
)
|
36
|
+
RESTRICT_ON_SEND = %i[
|
37
|
+
raise_exception
|
38
|
+
raise_error
|
39
|
+
].freeze
|
40
|
+
|
41
|
+
# @!method expect_to?(node)
|
42
|
+
def_node_matcher :expect_to?, <<~PATTERN
|
43
|
+
(send (block (send nil? :expect) ...) :to ...)
|
45
44
|
PATTERN
|
46
45
|
|
47
46
|
def on_send(node)
|
48
47
|
return unless empty_exception_matcher?(node)
|
49
48
|
|
50
|
-
add_offense(node
|
49
|
+
add_offense(node)
|
51
50
|
end
|
52
51
|
|
53
52
|
private
|
54
53
|
|
55
54
|
def empty_exception_matcher?(node)
|
56
|
-
|
55
|
+
return false if node.arguments? || node.block_literal?
|
56
|
+
|
57
|
+
expect_to = find_expect_to(node)
|
58
|
+
return false unless expect_to
|
59
|
+
return false if expect_to.block_node&.arguments?
|
60
|
+
|
61
|
+
true
|
57
62
|
end
|
58
63
|
|
59
|
-
def
|
60
|
-
|
64
|
+
def find_expect_to(node)
|
65
|
+
node.each_ancestor.find do |ancestor|
|
66
|
+
break if ancestor.block_type?
|
61
67
|
|
62
|
-
|
68
|
+
expect_to?(ancestor)
|
69
|
+
end
|
63
70
|
end
|
64
71
|
end
|
65
72
|
end
|
@@ -5,14 +5,14 @@ module RuboCop
|
|
5
5
|
module RSpec
|
6
6
|
# Checks for consistent verified double reference style.
|
7
7
|
#
|
8
|
-
# Only investigates references that are one of the supported styles.
|
9
|
-
#
|
10
8
|
# @see https://rspec.info/features/3-12/rspec-mocks/verifying-doubles
|
11
9
|
#
|
12
|
-
#
|
13
|
-
#
|
10
|
+
# @safety
|
11
|
+
# This cop is unsafe because the correction requires loading the class.
|
12
|
+
# Loading before stubbing causes RSpec to only allow instance methods
|
13
|
+
# to be stubbed.
|
14
14
|
#
|
15
|
-
# @example
|
15
|
+
# @example
|
16
16
|
# # bad
|
17
17
|
# let(:foo) do
|
18
18
|
# instance_double('ClassName', method_name: 'returned_value')
|
@@ -23,18 +23,7 @@ module RuboCop
|
|
23
23
|
# instance_double(ClassName, method_name: 'returned_value')
|
24
24
|
# end
|
25
25
|
#
|
26
|
-
# @example
|
27
|
-
# # bad
|
28
|
-
# let(:foo) do
|
29
|
-
# instance_double(ClassName, method_name: 'returned_value')
|
30
|
-
# end
|
31
|
-
#
|
32
|
-
# # good
|
33
|
-
# let(:foo) do
|
34
|
-
# instance_double('ClassName', method_name: 'returned_value')
|
35
|
-
# end
|
36
|
-
#
|
37
|
-
# @example Reference is not in the supported style list. No enforcement
|
26
|
+
# @example Reference is any dynamic variable. No enforcement
|
38
27
|
#
|
39
28
|
# # good
|
40
29
|
# let(:foo) do
|
@@ -42,9 +31,9 @@ module RuboCop
|
|
42
31
|
# end
|
43
32
|
class VerifiedDoubleReference < Base
|
44
33
|
extend AutoCorrector
|
45
|
-
include ConfigurableEnforcedStyle
|
46
34
|
|
47
|
-
MSG = 'Use a
|
35
|
+
MSG = 'Use a constant class reference for verified doubles. ' \
|
36
|
+
'String references are not verifying unless the class is loaded.'
|
48
37
|
|
49
38
|
RESTRICT_ON_SEND = Set[
|
50
39
|
:class_double,
|
@@ -57,53 +46,25 @@ module RuboCop
|
|
57
46
|
:stub_model
|
58
47
|
].freeze
|
59
48
|
|
60
|
-
REFERENCE_TYPE_STYLES = {
|
61
|
-
str: :string,
|
62
|
-
const: :constant
|
63
|
-
}.freeze
|
64
|
-
|
65
49
|
# @!method verified_double(node)
|
66
50
|
def_node_matcher :verified_double, <<~PATTERN
|
67
51
|
(send
|
68
52
|
nil?
|
69
53
|
RESTRICT_ON_SEND
|
70
|
-
$
|
54
|
+
$str
|
71
55
|
...)
|
72
56
|
PATTERN
|
73
57
|
|
74
58
|
def on_send(node)
|
75
|
-
verified_double(node) do |
|
76
|
-
|
77
|
-
|
78
|
-
message = format(MSG, style: style)
|
79
|
-
expression = class_reference.source_range
|
80
|
-
|
81
|
-
add_offense(expression, message: message) do |corrector|
|
82
|
-
offense = class_reference.source
|
83
|
-
corrector.replace(expression, correct_style(offense))
|
84
|
-
|
85
|
-
opposite_style_detected
|
59
|
+
verified_double(node) do |string_argument_node|
|
60
|
+
add_offense(string_argument_node) do |corrector|
|
61
|
+
autocorrect(corrector, string_argument_node)
|
86
62
|
end
|
87
63
|
end
|
88
64
|
end
|
89
65
|
|
90
|
-
|
91
|
-
|
92
|
-
def opposing_style?(class_reference)
|
93
|
-
class_reference_style = REFERENCE_TYPE_STYLES[class_reference.type]
|
94
|
-
|
95
|
-
# Only enforce supported styles
|
96
|
-
return false unless class_reference_style
|
97
|
-
|
98
|
-
class_reference_style != style
|
99
|
-
end
|
100
|
-
|
101
|
-
def correct_style(offense)
|
102
|
-
if style == :string
|
103
|
-
"'#{offense}'"
|
104
|
-
else
|
105
|
-
offense.gsub(/^['"]|['"]$/, '')
|
106
|
-
end
|
66
|
+
def autocorrect(corrector, node)
|
67
|
+
corrector.replace(node, node.value)
|
107
68
|
end
|
108
69
|
end
|
109
70
|
end
|
@@ -29,12 +29,14 @@ module RuboCop
|
|
29
29
|
|
30
30
|
def on_send(node)
|
31
31
|
return unless expect?(node)
|
32
|
+
return unless inside_example?(node)
|
32
33
|
|
33
34
|
check_expect(node)
|
34
35
|
end
|
35
36
|
|
36
37
|
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
37
38
|
return unless expect_block?(node)
|
39
|
+
return unless inside_example?(node)
|
38
40
|
|
39
41
|
check_expect(node)
|
40
42
|
end
|
@@ -49,11 +51,14 @@ module RuboCop
|
|
49
51
|
|
50
52
|
def void?(expect)
|
51
53
|
parent = expect.parent
|
52
|
-
return true unless parent
|
53
54
|
return true if parent.begin_type?
|
54
55
|
|
55
56
|
parent.block_type? && parent.body == expect
|
56
57
|
end
|
58
|
+
|
59
|
+
def inside_example?(node)
|
60
|
+
node.each_ancestor(:block).any? { |ancestor| example?(ancestor) }
|
61
|
+
end
|
57
62
|
end
|
58
63
|
end
|
59
64
|
end
|
@@ -1,29 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'rspec/capybara/current_path_expectation'
|
4
|
-
require_relative 'rspec/capybara/feature_methods'
|
5
|
-
require_relative 'rspec/capybara/match_style'
|
6
|
-
require_relative 'rspec/capybara/negation_matcher'
|
7
|
-
require_relative 'rspec/capybara/specific_actions'
|
8
|
-
require_relative 'rspec/capybara/specific_finders'
|
9
|
-
require_relative 'rspec/capybara/specific_matcher'
|
10
|
-
require_relative 'rspec/capybara/visibility_matcher'
|
11
|
-
|
12
|
-
require_relative 'rspec/factory_bot/attribute_defined_statically'
|
13
|
-
require_relative 'rspec/factory_bot/consistent_parentheses_style'
|
14
|
-
require_relative 'rspec/factory_bot/create_list'
|
15
|
-
require_relative 'rspec/factory_bot/factory_class_name'
|
16
|
-
require_relative 'rspec/factory_bot/factory_name_style'
|
17
|
-
require_relative 'rspec/factory_bot/syntax_methods'
|
18
|
-
|
19
|
-
require_relative 'rspec/rails/avoid_setup_hook'
|
20
|
-
require_relative 'rspec/rails/have_http_status'
|
21
|
-
require_relative 'rspec/rails/http_status'
|
22
|
-
require_relative 'rspec/rails/inferred_spec_type'
|
23
|
-
require_relative 'rspec/rails/minitest_assertions'
|
24
|
-
require_relative 'rspec/rails/negation_be_valid'
|
25
|
-
require_relative 'rspec/rails/travel_around'
|
26
|
-
|
27
3
|
require_relative 'rspec/align_left_let_brace'
|
28
4
|
require_relative 'rspec/align_right_let_brace'
|
29
5
|
require_relative 'rspec/any_instance'
|
@@ -63,8 +39,8 @@ require_relative 'rspec/excessive_docstring_spacing'
|
|
63
39
|
require_relative 'rspec/expect_actual'
|
64
40
|
require_relative 'rspec/expect_change'
|
65
41
|
require_relative 'rspec/expect_in_hook'
|
42
|
+
require_relative 'rspec/expect_in_let'
|
66
43
|
require_relative 'rspec/expect_output'
|
67
|
-
require_relative 'rspec/file_path'
|
68
44
|
require_relative 'rspec/focus'
|
69
45
|
require_relative 'rspec/hook_argument'
|
70
46
|
require_relative 'rspec/hooks_before_examples'
|
@@ -88,6 +64,7 @@ require_relative 'rspec/message_expectation'
|
|
88
64
|
require_relative 'rspec/message_spies'
|
89
65
|
require_relative 'rspec/metadata_style'
|
90
66
|
require_relative 'rspec/missing_example_group_argument'
|
67
|
+
require_relative 'rspec/missing_expectation_target_method'
|
91
68
|
require_relative 'rspec/multiple_describes'
|
92
69
|
require_relative 'rspec/multiple_expectations'
|
93
70
|
require_relative 'rspec/multiple_memoized_helpers'
|
@@ -6,31 +6,7 @@ module RuboCop
|
|
6
6
|
module RSpec
|
7
7
|
# Builds a YAML config file from two config hashes
|
8
8
|
class ConfigFormatter
|
9
|
-
EXTENSION_ROOT_DEPARTMENT = %r{^
|
10
|
-
SUBDEPARTMENTS = %(RSpec/Capybara RSpec/FactoryBot RSpec/Rails)
|
11
|
-
EXTRACTED_COPS = %(
|
12
|
-
RSpec/Capybara/CurrentPathExpectation
|
13
|
-
RSpec/Capybara/MatchStyle
|
14
|
-
RSpec/Capybara/NegationMatcher
|
15
|
-
RSpec/Capybara/SpecificActions
|
16
|
-
RSpec/Capybara/SpecificFinders
|
17
|
-
RSpec/Capybara/SpecificMatcher
|
18
|
-
RSpec/Capybara/VisibilityMatcher
|
19
|
-
RSpec/FactoryBot/AttributeDefinedStatically
|
20
|
-
RSpec/FactoryBot/ConsistentParenthesesStyle
|
21
|
-
RSpec/FactoryBot/CreateList
|
22
|
-
RSpec/FactoryBot/FactoryClassName
|
23
|
-
RSpec/FactoryBot/FactoryNameStyle
|
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
|
32
|
-
)
|
33
|
-
AMENDMENTS = %(Metrics/BlockLength)
|
9
|
+
EXTENSION_ROOT_DEPARTMENT = %r{^RSpec/}.freeze
|
34
10
|
COP_DOC_BASE_URL = 'https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/'
|
35
11
|
|
36
12
|
def initialize(config, descriptions)
|
@@ -40,19 +16,15 @@ module RuboCop
|
|
40
16
|
|
41
17
|
def dump
|
42
18
|
YAML.dump(unified_config)
|
43
|
-
.gsub(
|
44
|
-
.gsub(
|
45
|
-
.gsub(
|
46
|
-
.gsub('"~"', '~')
|
19
|
+
.gsub(%r{^\w+/}, "\n\\0") # Add an extra newline before each cop.
|
20
|
+
.gsub(/^(\s+)- /, '\1 - ') # Add 2 spaces before each array element.
|
21
|
+
.gsub('"~"', '~') # Don't quote tilde, YAML's null value.
|
47
22
|
end
|
48
23
|
|
49
24
|
private
|
50
25
|
|
51
26
|
def unified_config
|
52
27
|
cops.each_with_object(config.dup) do |cop, unified|
|
53
|
-
next if SUBDEPARTMENTS.include?(cop) || AMENDMENTS.include?(cop)
|
54
|
-
next if EXTRACTED_COPS.include?(cop)
|
55
|
-
|
56
28
|
replace_nil(unified[cop])
|
57
29
|
unified[cop].merge!(descriptions.fetch(cop))
|
58
30
|
unified[cop]['Reference'] = reference(cop)
|