rubocop-rspec 1.7.0 → 3.0.2
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 +5 -5
- data/CHANGELOG.md +955 -79
- data/CODE_OF_CONDUCT.md +17 -0
- data/MIT-LICENSE.md +1 -2
- data/README.md +35 -35
- data/config/default.yml +940 -52
- data/config/obsoletion.yml +30 -0
- data/lib/rubocop/cop/rspec/align_left_let_brace.rb +49 -0
- data/lib/rubocop/cop/rspec/align_right_let_brace.rb +49 -0
- data/lib/rubocop/cop/rspec/any_instance.rb +10 -13
- data/lib/rubocop/cop/rspec/around_block.rb +97 -0
- data/lib/rubocop/cop/rspec/base.rb +26 -0
- data/lib/rubocop/cop/rspec/be.rb +39 -0
- data/lib/rubocop/cop/rspec/be_empty.rb +45 -0
- data/lib/rubocop/cop/rspec/be_eq.rb +47 -0
- data/lib/rubocop/cop/rspec/be_eql.rb +18 -15
- data/lib/rubocop/cop/rspec/be_nil.rb +74 -0
- data/lib/rubocop/cop/rspec/before_after_all.rb +45 -0
- data/lib/rubocop/cop/rspec/change_by_zero.rb +184 -0
- data/lib/rubocop/cop/rspec/class_check.rb +101 -0
- data/lib/rubocop/cop/rspec/contain_exactly.rb +56 -0
- data/lib/rubocop/cop/rspec/context_method.rb +57 -0
- data/lib/rubocop/cop/rspec/context_wording.rb +117 -0
- data/lib/rubocop/cop/rspec/describe_class.rb +52 -21
- data/lib/rubocop/cop/rspec/describe_method.rb +26 -11
- data/lib/rubocop/cop/rspec/describe_symbol.rb +37 -0
- data/lib/rubocop/cop/rspec/described_class.rb +181 -34
- data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +38 -0
- data/lib/rubocop/cop/rspec/dialect.rb +84 -0
- data/lib/rubocop/cop/rspec/duplicated_metadata.rb +58 -0
- data/lib/rubocop/cop/rspec/empty_example_group.rb +134 -47
- data/lib/rubocop/cop/rspec/empty_hook.rb +49 -0
- data/lib/rubocop/cop/rspec/empty_line_after_example.rb +82 -0
- data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +42 -0
- data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +40 -0
- data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +82 -0
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +36 -0
- data/lib/rubocop/cop/rspec/empty_metadata.rb +46 -0
- data/lib/rubocop/cop/rspec/empty_output.rb +47 -0
- data/lib/rubocop/cop/rspec/eq.rb +47 -0
- data/lib/rubocop/cop/rspec/example_length.rb +38 -20
- data/lib/rubocop/cop/rspec/example_without_description.rb +98 -0
- data/lib/rubocop/cop/rspec/example_wording.rb +117 -27
- data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +110 -0
- data/lib/rubocop/cop/rspec/expect_actual.rb +46 -20
- data/lib/rubocop/cop/rspec/expect_change.rb +86 -0
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +50 -0
- data/lib/rubocop/cop/rspec/expect_in_let.rb +42 -0
- data/lib/rubocop/cop/rspec/expect_output.rb +50 -0
- data/lib/rubocop/cop/rspec/focus.rb +79 -25
- data/lib/rubocop/cop/rspec/hook_argument.rb +48 -36
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +81 -0
- data/lib/rubocop/cop/rspec/identical_equality_assertion.rb +37 -0
- data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +68 -0
- data/lib/rubocop/cop/rspec/implicit_expect.rb +100 -0
- data/lib/rubocop/cop/rspec/implicit_subject.rb +167 -0
- data/lib/rubocop/cop/rspec/indexed_let.rb +112 -0
- data/lib/rubocop/cop/rspec/instance_spy.rb +74 -0
- data/lib/rubocop/cop/rspec/instance_variable.rb +28 -14
- data/lib/rubocop/cop/rspec/is_expected_specify.rb +45 -0
- data/lib/rubocop/cop/rspec/it_behaves_like.rb +49 -0
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +74 -0
- data/lib/rubocop/cop/rspec/leading_subject.rb +57 -29
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +127 -0
- data/lib/rubocop/cop/rspec/let_before_examples.rb +101 -0
- data/lib/rubocop/cop/rspec/let_setup.rb +32 -16
- data/lib/rubocop/cop/rspec/match_array.rb +59 -0
- data/lib/rubocop/cop/rspec/message_chain.rb +10 -15
- data/lib/rubocop/cop/rspec/message_expectation.rb +12 -9
- data/lib/rubocop/cop/rspec/message_spies.rb +88 -0
- data/lib/rubocop/cop/rspec/metadata_style.rb +202 -0
- data/lib/rubocop/cop/rspec/missing_example_group_argument.rb +35 -0
- data/lib/rubocop/cop/rspec/missing_expectation_target_method.rb +54 -0
- data/lib/rubocop/cop/rspec/mixin/comments_help.rb +38 -0
- data/lib/rubocop/cop/rspec/mixin/empty_line_separation.rb +59 -0
- data/lib/rubocop/cop/rspec/mixin/file_help.rb +14 -0
- data/lib/rubocop/cop/rspec/mixin/final_end_location.rb +19 -0
- data/lib/rubocop/cop/rspec/mixin/inside_example_group.rb +29 -0
- data/lib/rubocop/cop/rspec/mixin/location_help.rb +37 -0
- data/lib/rubocop/cop/rspec/mixin/metadata.rb +63 -0
- data/lib/rubocop/cop/rspec/mixin/namespace.rb +23 -0
- data/lib/rubocop/cop/rspec/mixin/skip_or_pending.rb +39 -0
- data/lib/rubocop/cop/rspec/mixin/top_level_group.rb +54 -0
- data/lib/rubocop/cop/rspec/mixin/variable.rb +21 -0
- data/lib/rubocop/cop/rspec/multiple_describes.rb +14 -12
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +86 -26
- data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +146 -0
- data/lib/rubocop/cop/rspec/multiple_subjects.rb +97 -0
- data/lib/rubocop/cop/rspec/named_subject.rb +107 -27
- data/lib/rubocop/cop/rspec/nested_groups.rb +84 -47
- data/lib/rubocop/cop/rspec/no_expectation_example.rb +102 -0
- data/lib/rubocop/cop/rspec/not_to_not.rb +30 -27
- data/lib/rubocop/cop/rspec/overwriting_setup.rb +74 -0
- data/lib/rubocop/cop/rspec/pending.rb +80 -0
- data/lib/rubocop/cop/rspec/pending_without_reason.rb +159 -0
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +341 -0
- data/lib/rubocop/cop/rspec/receive_counts.rb +89 -0
- data/lib/rubocop/cop/rspec/receive_messages.rb +161 -0
- data/lib/rubocop/cop/rspec/receive_never.rb +41 -0
- data/lib/rubocop/cop/rspec/redundant_around.rb +65 -0
- data/lib/rubocop/cop/rspec/redundant_predicate_matcher.rb +67 -0
- data/lib/rubocop/cop/rspec/remove_const.rb +39 -0
- data/lib/rubocop/cop/rspec/repeated_description.rb +98 -0
- data/lib/rubocop/cop/rspec/repeated_example.rb +53 -0
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +100 -0
- data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +96 -0
- data/lib/rubocop/cop/rspec/repeated_include_example.rb +105 -0
- data/lib/rubocop/cop/rspec/repeated_subject_call.rb +125 -0
- data/lib/rubocop/cop/rspec/return_from_stub.rb +169 -0
- data/lib/rubocop/cop/rspec/scattered_let.rb +59 -0
- data/lib/rubocop/cop/rspec/scattered_setup.rb +92 -0
- data/lib/rubocop/cop/rspec/shared_context.rb +107 -0
- data/lib/rubocop/cop/rspec/shared_examples.rb +125 -0
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +93 -0
- data/lib/rubocop/cop/rspec/skip_block_inside_example.rb +46 -0
- data/lib/rubocop/cop/rspec/sort_metadata.rb +71 -0
- data/lib/rubocop/cop/rspec/spec_file_path_format.rb +133 -0
- data/lib/rubocop/cop/rspec/spec_file_path_suffix.rb +40 -0
- data/lib/rubocop/cop/rspec/stubbed_mock.rb +176 -0
- data/lib/rubocop/cop/rspec/subject_declaration.rb +46 -0
- data/lib/rubocop/cop/rspec/subject_stub.rb +93 -74
- data/lib/rubocop/cop/rspec/undescriptive_literals_description.rb +69 -0
- data/lib/rubocop/cop/rspec/unspecified_exception.rb +67 -0
- data/lib/rubocop/cop/rspec/variable_definition.rb +77 -0
- data/lib/rubocop/cop/rspec/variable_name.rb +68 -0
- data/lib/rubocop/cop/rspec/verified_double_reference.rb +111 -0
- data/lib/rubocop/cop/rspec/verified_doubles.rb +28 -14
- data/lib/rubocop/cop/rspec/void_expect.rb +60 -0
- data/lib/rubocop/cop/rspec/yield.rb +82 -0
- data/lib/rubocop/cop/rspec_cops.rb +112 -0
- data/lib/rubocop/rspec/align_let_brace.rb +63 -0
- data/lib/rubocop/rspec/concept.rb +33 -0
- data/lib/rubocop/rspec/config_formatter.rb +27 -4
- data/lib/rubocop/rspec/cop/generator.rb +25 -0
- data/lib/rubocop/rspec/corrector/move_node.rb +51 -0
- data/lib/rubocop/rspec/description_extractor.rb +60 -18
- data/lib/rubocop/rspec/example.rb +37 -0
- data/lib/rubocop/rspec/example_group.rb +67 -0
- data/lib/rubocop/rspec/hook.rb +79 -0
- data/lib/rubocop/rspec/inject.rb +3 -1
- data/lib/rubocop/rspec/language.rb +184 -41
- data/lib/rubocop/rspec/node.rb +19 -0
- data/lib/rubocop/rspec/shared_contexts/default_rspec_language_config_context.rb +29 -0
- data/lib/rubocop/rspec/version.rb +1 -1
- data/lib/rubocop/rspec/wording.rb +61 -19
- data/lib/rubocop/rspec.rb +6 -2
- data/lib/rubocop-rspec.rb +45 -34
- metadata +130 -195
- data/Gemfile +0 -13
- data/Rakefile +0 -48
- data/lib/rubocop/cop/rspec/file_path.rb +0 -83
- data/lib/rubocop/rspec/language/node_pattern.rb +0 -16
- data/lib/rubocop/rspec/spec_only.rb +0 -61
- data/lib/rubocop/rspec/top_level_describe.rb +0 -61
- data/lib/rubocop/rspec/util.rb +0 -19
- data/rubocop-rspec.gemspec +0 -42
- data/spec/expect_violation/expectation_spec.rb +0 -85
- data/spec/project/changelog_spec.rb +0 -81
- data/spec/project/default_config_spec.rb +0 -52
- data/spec/project/project_requires_spec.rb +0 -8
- data/spec/rubocop/cop/rspec/any_instance_spec.rb +0 -30
- data/spec/rubocop/cop/rspec/be_eql_spec.rb +0 -59
- data/spec/rubocop/cop/rspec/describe_class_spec.rb +0 -113
- data/spec/rubocop/cop/rspec/describe_method_spec.rb +0 -32
- data/spec/rubocop/cop/rspec/described_class_spec.rb +0 -219
- data/spec/rubocop/cop/rspec/empty_example_group_spec.rb +0 -79
- data/spec/rubocop/cop/rspec/example_length_spec.rb +0 -117
- data/spec/rubocop/cop/rspec/example_wording_spec.rb +0 -82
- data/spec/rubocop/cop/rspec/expect_actual_spec.rb +0 -136
- data/spec/rubocop/cop/rspec/file_path_spec.rb +0 -236
- data/spec/rubocop/cop/rspec/focus_spec.rb +0 -130
- data/spec/rubocop/cop/rspec/hook_argument_spec.rb +0 -189
- data/spec/rubocop/cop/rspec/instance_variable_spec.rb +0 -75
- data/spec/rubocop/cop/rspec/leading_subject_spec.rb +0 -54
- data/spec/rubocop/cop/rspec/let_setup_spec.rb +0 -66
- data/spec/rubocop/cop/rspec/message_chain_spec.rb +0 -21
- data/spec/rubocop/cop/rspec/message_expectation_spec.rb +0 -63
- data/spec/rubocop/cop/rspec/multiple_describes_spec.rb +0 -28
- data/spec/rubocop/cop/rspec/multiple_expectations_spec.rb +0 -84
- data/spec/rubocop/cop/rspec/named_subject_spec.rb +0 -62
- data/spec/rubocop/cop/rspec/nested_groups_spec.rb +0 -55
- data/spec/rubocop/cop/rspec/not_to_not_spec.rb +0 -57
- data/spec/rubocop/cop/rspec/subject_stub_spec.rb +0 -183
- data/spec/rubocop/cop/rspec/verified_doubles_spec.rb +0 -71
- data/spec/rubocop/rspec/config_formatter_spec.rb +0 -48
- data/spec/rubocop/rspec/description_extractor_spec.rb +0 -35
- data/spec/rubocop/rspec/language/selector_set_spec.rb +0 -29
- data/spec/rubocop/rspec/spec_only_spec.rb +0 -97
- data/spec/rubocop/rspec/util/one_spec.rb +0 -21
- data/spec/rubocop/rspec/wording_spec.rb +0 -44
- data/spec/shared/rspec_only_cop_behavior.rb +0 -68
- data/spec/spec_helper.rb +0 -41
- data/spec/support/expect_violation.rb +0 -166
@@ -5,6 +5,8 @@ module RuboCop
|
|
5
5
|
module RSpec
|
6
6
|
# Checks if examples are focused.
|
7
7
|
#
|
8
|
+
# This cop does not support autocorrection in some cases.
|
9
|
+
#
|
8
10
|
# @example
|
9
11
|
# # bad
|
10
12
|
# describe MyClass, focus: true do
|
@@ -19,37 +21,74 @@ module RuboCop
|
|
19
21
|
# # good
|
20
22
|
# describe MyClass do
|
21
23
|
# end
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
24
|
+
#
|
25
|
+
# # bad
|
26
|
+
# fdescribe 'test' do; end
|
27
|
+
#
|
28
|
+
# # good
|
29
|
+
# describe 'test' do; end
|
30
|
+
#
|
31
|
+
# # bad
|
32
|
+
# fdescribe 'test' do; end
|
33
|
+
#
|
34
|
+
# # good
|
35
|
+
# describe 'test' do; end
|
36
|
+
#
|
37
|
+
# # bad
|
38
|
+
# shared_examples 'test', focus: true do; end
|
39
|
+
#
|
40
|
+
# # good
|
41
|
+
# shared_examples 'test' do; end
|
42
|
+
#
|
43
|
+
# # bad
|
44
|
+
# shared_context 'test', focus: true do; end
|
45
|
+
#
|
46
|
+
# # good
|
47
|
+
# shared_context 'test' do; end
|
48
|
+
#
|
49
|
+
# # bad (does not support autocorrection)
|
50
|
+
# focus 'test' do; end
|
51
|
+
#
|
52
|
+
class Focus < Base
|
53
|
+
extend AutoCorrector
|
54
|
+
include RangeHelp
|
34
55
|
|
35
|
-
|
36
|
-
FOCUSING_SELECTORS = focused.to_node_pattern
|
56
|
+
MSG = 'Focused spec found.'
|
37
57
|
|
38
|
-
|
39
|
-
|
58
|
+
# @!method focusable_selector?(node)
|
59
|
+
def_node_matcher :focusable_selector?, <<~PATTERN
|
60
|
+
{
|
61
|
+
#ExampleGroups.regular
|
62
|
+
#ExampleGroups.skipped
|
63
|
+
#Examples.regular
|
64
|
+
#Examples.skipped
|
65
|
+
#Examples.pending
|
66
|
+
#SharedGroups.all
|
67
|
+
}
|
68
|
+
PATTERN
|
40
69
|
|
41
|
-
|
42
|
-
|
43
|
-
|
70
|
+
# @!method metadata(node)
|
71
|
+
def_node_matcher :metadata, <<~PATTERN
|
72
|
+
{(send #rspec? #focusable_selector? <$(sym :focus) ...>)
|
73
|
+
(send #rspec? #focusable_selector? ... (hash <$(pair (sym :focus) true) ...>))}
|
44
74
|
PATTERN
|
45
75
|
|
46
|
-
|
47
|
-
|
76
|
+
# @!method focused_block?(node)
|
77
|
+
def_node_matcher :focused_block?, <<~PATTERN
|
78
|
+
(send #rspec? {#ExampleGroups.focused #Examples.focused} ...)
|
48
79
|
PATTERN
|
49
80
|
|
50
81
|
def on_send(node)
|
82
|
+
return if node.chained? || node.each_ancestor(:def, :defs).any?
|
83
|
+
|
51
84
|
focus_metadata(node) do |focus|
|
52
|
-
add_offense(focus
|
85
|
+
add_offense(focus) do |corrector|
|
86
|
+
if focus.pair_type? || focus.str_type? || focus.sym_type?
|
87
|
+
corrector.remove(with_surrounding(focus))
|
88
|
+
elsif focus.send_type?
|
89
|
+
correct_send(corrector, focus)
|
90
|
+
end
|
91
|
+
end
|
53
92
|
end
|
54
93
|
end
|
55
94
|
|
@@ -58,10 +97,25 @@ module RuboCop
|
|
58
97
|
def focus_metadata(node, &block)
|
59
98
|
yield(node) if focused_block?(node)
|
60
99
|
|
61
|
-
metadata(node)
|
62
|
-
|
63
|
-
|
100
|
+
metadata(node, &block)
|
101
|
+
end
|
102
|
+
|
103
|
+
def with_surrounding(focus)
|
104
|
+
range_with_space =
|
105
|
+
range_with_surrounding_space(focus.source_range, side: :left)
|
106
|
+
|
107
|
+
range_with_surrounding_comma(range_with_space, :left)
|
108
|
+
end
|
109
|
+
|
110
|
+
def correct_send(corrector, focus)
|
111
|
+
range = focus.loc.selector
|
112
|
+
unfocused = focus.method_name.to_s.sub(/^f/, '')
|
113
|
+
unless Examples.regular(unfocused) || ExampleGroups.regular(unfocused)
|
114
|
+
return
|
64
115
|
end
|
116
|
+
|
117
|
+
corrector.replace(range,
|
118
|
+
range.source.sub(focus.method_name.to_s, unfocused))
|
65
119
|
end
|
66
120
|
end
|
67
121
|
end
|
@@ -10,68 +10,70 @@ module RuboCop
|
|
10
10
|
# styles: "implicit", "each", and "example." All styles have
|
11
11
|
# the same behavior.
|
12
12
|
#
|
13
|
-
# @example
|
13
|
+
# @example `EnforcedStyle: implicit` (default)
|
14
14
|
# # bad
|
15
15
|
# before(:each) do
|
16
|
-
# ...
|
16
|
+
# # ...
|
17
17
|
# end
|
18
18
|
#
|
19
19
|
# # bad
|
20
20
|
# before(:example) do
|
21
|
-
# ...
|
21
|
+
# # ...
|
22
22
|
# end
|
23
23
|
#
|
24
24
|
# # good
|
25
25
|
# before do
|
26
|
-
# ...
|
26
|
+
# # ...
|
27
27
|
# end
|
28
28
|
#
|
29
|
-
# @example
|
29
|
+
# @example `EnforcedStyle: each`
|
30
30
|
# # bad
|
31
31
|
# before(:example) do
|
32
|
-
# ...
|
32
|
+
# # ...
|
33
33
|
# end
|
34
34
|
#
|
35
|
-
# #
|
35
|
+
# # bad
|
36
36
|
# before do
|
37
|
-
# ...
|
37
|
+
# # ...
|
38
38
|
# end
|
39
39
|
#
|
40
40
|
# # good
|
41
41
|
# before(:each) do
|
42
|
-
# ...
|
42
|
+
# # ...
|
43
43
|
# end
|
44
44
|
#
|
45
|
-
# @example
|
45
|
+
# @example `EnforcedStyle: example`
|
46
46
|
# # bad
|
47
47
|
# before(:each) do
|
48
|
-
# ...
|
48
|
+
# # ...
|
49
49
|
# end
|
50
50
|
#
|
51
51
|
# # bad
|
52
52
|
# before do
|
53
|
-
# ...
|
53
|
+
# # ...
|
54
54
|
# end
|
55
55
|
#
|
56
56
|
# # good
|
57
57
|
# before(:example) do
|
58
|
-
# ...
|
58
|
+
# # ...
|
59
59
|
# end
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
IMPLICIT_MSG = 'Omit the default `%p` argument for RSpec hooks.'.freeze
|
66
|
-
EXPLICIT_MSG = 'Use `%p` for RSpec hooks.'.freeze
|
60
|
+
#
|
61
|
+
class HookArgument < Base
|
62
|
+
extend AutoCorrector
|
63
|
+
include ConfigurableEnforcedStyle
|
67
64
|
|
68
|
-
|
65
|
+
IMPLICIT_MSG = 'Omit the default `%<scope>p` argument for RSpec hooks.'
|
66
|
+
EXPLICIT_MSG = 'Use `%<scope>p` for RSpec hooks.'
|
69
67
|
|
70
|
-
|
71
|
-
|
68
|
+
# @!method scoped_hook(node)
|
69
|
+
def_node_matcher :scoped_hook, <<~PATTERN
|
70
|
+
({block numblock} $(send _ #Hooks.all (sym ${:each :example})) ...)
|
72
71
|
PATTERN
|
73
72
|
|
74
|
-
|
73
|
+
# @!method unscoped_hook(node)
|
74
|
+
def_node_matcher :unscoped_hook, <<~PATTERN
|
75
|
+
({block numblock} $(send _ #Hooks.all) ...)
|
76
|
+
PATTERN
|
75
77
|
|
76
78
|
def on_block(node)
|
77
79
|
hook(node) do |method_send, scope_name|
|
@@ -79,33 +81,43 @@ module RuboCop
|
|
79
81
|
return check_implicit(method_send) unless scope_name
|
80
82
|
|
81
83
|
style_detected(scope_name)
|
82
|
-
|
84
|
+
msg = explicit_message(scope_name)
|
85
|
+
add_offense(method_send, message: msg) do |corrector|
|
86
|
+
autocorrect(corrector, node, method_send)
|
87
|
+
end
|
83
88
|
end
|
84
89
|
end
|
85
90
|
|
86
|
-
|
87
|
-
scope = "(#{style.inspect})" unless implicit_style?
|
88
|
-
hook = "#{node.method_name}#{scope}"
|
89
|
-
|
90
|
-
lambda do |corrector|
|
91
|
-
corrector.replace(node.loc.expression, hook)
|
92
|
-
end
|
93
|
-
end
|
91
|
+
alias on_numblock on_block
|
94
92
|
|
95
93
|
private
|
96
94
|
|
95
|
+
def autocorrect(corrector, _node, method_send)
|
96
|
+
scope = implicit_style? ? '' : "(#{style.inspect})"
|
97
|
+
corrector.replace(
|
98
|
+
LocationHelp.arguments_with_whitespace(method_send), scope
|
99
|
+
)
|
100
|
+
end
|
101
|
+
|
97
102
|
def check_implicit(method_send)
|
98
103
|
style_detected(:implicit)
|
99
104
|
return if implicit_style?
|
100
105
|
|
101
|
-
|
106
|
+
msg = explicit_message(nil)
|
107
|
+
add_offense(method_send.loc.selector, message: msg) do |corrector|
|
108
|
+
scope = "(#{style.inspect})"
|
109
|
+
corrector.replace(
|
110
|
+
LocationHelp.arguments_with_whitespace(method_send),
|
111
|
+
scope
|
112
|
+
)
|
113
|
+
end
|
102
114
|
end
|
103
115
|
|
104
116
|
def explicit_message(scope)
|
105
117
|
if implicit_style?
|
106
|
-
format(IMPLICIT_MSG, scope)
|
118
|
+
format(IMPLICIT_MSG, scope: scope)
|
107
119
|
else
|
108
|
-
format(EXPLICIT_MSG, style)
|
120
|
+
format(EXPLICIT_MSG, scope: style)
|
109
121
|
end
|
110
122
|
end
|
111
123
|
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks for before/around/after hooks that come after an example.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# it 'checks what foo does' do
|
11
|
+
# expect(foo).to be
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# before { prepare }
|
15
|
+
# after { clean_up }
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# before { prepare }
|
19
|
+
# after { clean_up }
|
20
|
+
#
|
21
|
+
# it 'checks what foo does' do
|
22
|
+
# expect(foo).to be
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
class HooksBeforeExamples < Base
|
26
|
+
extend AutoCorrector
|
27
|
+
|
28
|
+
MSG = 'Move `%<hook>s` above the examples in the group.'
|
29
|
+
|
30
|
+
# @!method example_or_group?(node)
|
31
|
+
def_node_matcher :example_or_group?, <<~PATTERN
|
32
|
+
{
|
33
|
+
({block numblock} {
|
34
|
+
(send #rspec? #ExampleGroups.all ...)
|
35
|
+
(send nil? #Examples.all ...)
|
36
|
+
} ...)
|
37
|
+
(send nil? #Includes.examples ...)
|
38
|
+
}
|
39
|
+
PATTERN
|
40
|
+
|
41
|
+
def on_block(node)
|
42
|
+
return unless example_group_with_body?(node)
|
43
|
+
|
44
|
+
check_hooks(node.body) if multiline_block?(node.body)
|
45
|
+
end
|
46
|
+
|
47
|
+
alias on_numblock on_block
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def multiline_block?(block)
|
52
|
+
block.begin_type?
|
53
|
+
end
|
54
|
+
|
55
|
+
def check_hooks(node)
|
56
|
+
first_example = find_first_example(node)
|
57
|
+
return unless first_example
|
58
|
+
|
59
|
+
first_example.right_siblings.each do |sibling|
|
60
|
+
next unless hook?(sibling)
|
61
|
+
|
62
|
+
msg = format(MSG, hook: sibling.method_name)
|
63
|
+
add_offense(sibling, message: msg) do |corrector|
|
64
|
+
autocorrect(corrector, sibling, first_example)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def find_first_example(node)
|
70
|
+
node.children.find { |sibling| example_or_group?(sibling) }
|
71
|
+
end
|
72
|
+
|
73
|
+
def autocorrect(corrector, node, first_example)
|
74
|
+
RuboCop::RSpec::Corrector::MoveNode.new(
|
75
|
+
node, corrector, processed_source
|
76
|
+
).move_before(first_example)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks for equality assertions with identical expressions on both sides.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# expect(foo.bar).to eq(foo.bar)
|
11
|
+
# expect(foo.bar).to eql(foo.bar)
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# expect(foo.bar).to eq(2)
|
15
|
+
# expect(foo.bar).to eql(2)
|
16
|
+
#
|
17
|
+
class IdenticalEqualityAssertion < Base
|
18
|
+
MSG = 'Identical expressions on both sides of the equality ' \
|
19
|
+
'may indicate a flawed test.'
|
20
|
+
RESTRICT_ON_SEND = %i[to].freeze
|
21
|
+
|
22
|
+
# @!method equality_check?(node)
|
23
|
+
def_node_matcher :equality_check?, <<~PATTERN
|
24
|
+
(send (send nil? :expect $_) :to
|
25
|
+
{(send nil? {:eql :eq :be} $_)
|
26
|
+
(send (send nil? :be) :== $_)})
|
27
|
+
PATTERN
|
28
|
+
|
29
|
+
def on_send(node)
|
30
|
+
equality_check?(node) do |left, right|
|
31
|
+
add_offense(node) if left == right
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Check that implicit block expectation syntax is not used.
|
7
|
+
#
|
8
|
+
# Prefer using explicit block expectations.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# # bad
|
12
|
+
# subject { -> { do_something } }
|
13
|
+
# it { is_expected.to change(something).to(new_value) }
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# it 'changes something to a new value' do
|
17
|
+
# expect { do_something }.to change(something).to(new_value)
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
class ImplicitBlockExpectation < Base
|
21
|
+
MSG = 'Avoid implicit block expectations.'
|
22
|
+
RESTRICT_ON_SEND = %i[is_expected should should_not].freeze
|
23
|
+
|
24
|
+
# @!method lambda?(node)
|
25
|
+
def_node_matcher :lambda?, <<~PATTERN
|
26
|
+
{
|
27
|
+
(send (const nil? :Proc) :new)
|
28
|
+
(send nil? {:proc :lambda})
|
29
|
+
}
|
30
|
+
PATTERN
|
31
|
+
|
32
|
+
# @!method lambda_subject?(node)
|
33
|
+
def_node_matcher :lambda_subject?, '(block #lambda? ...)'
|
34
|
+
|
35
|
+
# @!method implicit_expect(node)
|
36
|
+
def_node_matcher :implicit_expect, <<~PATTERN
|
37
|
+
$(send nil? {:is_expected :should :should_not} ...)
|
38
|
+
PATTERN
|
39
|
+
|
40
|
+
def on_send(node)
|
41
|
+
implicit_expect(node) do |implicit_expect|
|
42
|
+
subject = nearest_subject(implicit_expect)
|
43
|
+
add_offense(implicit_expect) if lambda_subject?(subject&.body)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def nearest_subject(node)
|
50
|
+
node
|
51
|
+
.each_ancestor(:block)
|
52
|
+
.lazy
|
53
|
+
.select { |block_node| multi_statement_example_group?(block_node) }
|
54
|
+
.map { |block_node| find_subject(block_node) }
|
55
|
+
.find(&:itself)
|
56
|
+
end
|
57
|
+
|
58
|
+
def multi_statement_example_group?(node)
|
59
|
+
example_group_with_body?(node) && node.body.begin_type?
|
60
|
+
end
|
61
|
+
|
62
|
+
def find_subject(block_node)
|
63
|
+
block_node.body.child_nodes.find { |send_node| subject?(send_node) }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Check that a consistent implicit expectation style is used.
|
7
|
+
#
|
8
|
+
# This cop can be configured using the `EnforcedStyle` option
|
9
|
+
# and supports the `--auto-gen-config` flag.
|
10
|
+
#
|
11
|
+
# @example `EnforcedStyle: is_expected` (default)
|
12
|
+
# # bad
|
13
|
+
# it { should be_truthy }
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# it { is_expected.to be_truthy }
|
17
|
+
#
|
18
|
+
# @example `EnforcedStyle: should`
|
19
|
+
# # bad
|
20
|
+
# it { is_expected.to be_truthy }
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# it { should be_truthy }
|
24
|
+
#
|
25
|
+
class ImplicitExpect < Base
|
26
|
+
extend AutoCorrector
|
27
|
+
include ConfigurableEnforcedStyle
|
28
|
+
|
29
|
+
MSG = 'Prefer `%<good>s` over `%<bad>s`.'
|
30
|
+
|
31
|
+
RESTRICT_ON_SEND = Runners.all + %i[should should_not]
|
32
|
+
|
33
|
+
# @!method implicit_expect(node)
|
34
|
+
def_node_matcher :implicit_expect, <<~PATTERN
|
35
|
+
{
|
36
|
+
(send nil? ${:should :should_not} ...)
|
37
|
+
(send (send nil? $:is_expected) #Runners.all ...)
|
38
|
+
}
|
39
|
+
PATTERN
|
40
|
+
|
41
|
+
alternatives = {
|
42
|
+
'is_expected.to' => 'should',
|
43
|
+
'is_expected.not_to' => 'should_not',
|
44
|
+
'is_expected.to_not' => 'should_not'
|
45
|
+
}
|
46
|
+
|
47
|
+
ENFORCED_REPLACEMENTS = alternatives.merge(alternatives.invert).freeze
|
48
|
+
|
49
|
+
def on_send(node) # rubocop:disable Metrics/MethodLength
|
50
|
+
return unless (source_range = offending_expect(node))
|
51
|
+
|
52
|
+
expectation_source = source_range.source
|
53
|
+
|
54
|
+
if expectation_source.start_with?(style.to_s)
|
55
|
+
correct_style_detected
|
56
|
+
else
|
57
|
+
opposite_style_detected
|
58
|
+
|
59
|
+
msg = offense_message(expectation_source)
|
60
|
+
add_offense(source_range, message: msg) do |corrector|
|
61
|
+
replacement = replacement_source(expectation_source)
|
62
|
+
corrector.replace(source_range, replacement)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def offending_expect(node)
|
70
|
+
case implicit_expect(node)
|
71
|
+
when :is_expected
|
72
|
+
is_expected_range(node.loc)
|
73
|
+
when :should, :should_not
|
74
|
+
node.loc.selector
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def is_expected_range(source_map) # rubocop:disable Naming/PredicateName
|
79
|
+
Parser::Source::Range.new(
|
80
|
+
source_map.expression.source_buffer,
|
81
|
+
source_map.expression.begin_pos,
|
82
|
+
source_map.selector.end_pos
|
83
|
+
)
|
84
|
+
end
|
85
|
+
|
86
|
+
def offense_message(offending_source)
|
87
|
+
format(
|
88
|
+
MSG,
|
89
|
+
good: replacement_source(offending_source),
|
90
|
+
bad: offending_source
|
91
|
+
)
|
92
|
+
end
|
93
|
+
|
94
|
+
def replacement_source(offending_source)
|
95
|
+
ENFORCED_REPLACEMENTS.fetch(offending_source)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|