rubocop-rspec 1.12.0 → 1.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/config/default.yml +15 -1
- data/lib/rubocop-rspec.rb +2 -0
- data/lib/rubocop/cop/rspec/any_instance.rb +7 -10
- data/lib/rubocop/cop/rspec/around_block.rb +19 -30
- data/lib/rubocop/cop/rspec/be_eql.rb +3 -7
- data/lib/rubocop/cop/rspec/before_after_all.rb +10 -16
- data/lib/rubocop/cop/rspec/cop.rb +5 -1
- data/lib/rubocop/cop/rspec/describe_class.rb +8 -8
- data/lib/rubocop/cop/rspec/describe_method.rb +6 -5
- data/lib/rubocop/cop/rspec/described_class.rb +2 -2
- data/lib/rubocop/cop/rspec/example_length.rb +5 -8
- data/lib/rubocop/cop/rspec/example_wording.rb +57 -23
- data/lib/rubocop/cop/rspec/expect_actual.rb +3 -9
- data/lib/rubocop/cop/rspec/expect_output.rb +2 -2
- data/lib/rubocop/cop/rspec/file_path.rb +30 -29
- data/lib/rubocop/cop/rspec/hook_argument.rb +1 -1
- data/lib/rubocop/cop/rspec/instance_spy.rb +12 -12
- data/lib/rubocop/cop/rspec/instance_variable.rb +2 -2
- data/lib/rubocop/cop/rspec/it_behaves_like.rb +47 -0
- data/lib/rubocop/cop/rspec/leading_subject.rb +1 -1
- data/lib/rubocop/cop/rspec/message_chain.rb +7 -4
- data/lib/rubocop/cop/rspec/message_spies.rb +6 -5
- data/lib/rubocop/cop/rspec/multiple_describes.rb +1 -1
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +38 -6
- data/lib/rubocop/cop/rspec/named_subject.rb +2 -2
- data/lib/rubocop/cop/rspec/nested_groups.rb +10 -6
- data/lib/rubocop/cop/rspec/not_to_not.rb +12 -23
- data/lib/rubocop/cop/rspec/shared_context.rb +107 -0
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +16 -23
- data/lib/rubocop/cop/rspec/subject_stub.rb +4 -4
- data/lib/rubocop/cop/rspec/verified_doubles.rb +4 -3
- data/lib/rubocop/rspec/example_group.rb +1 -1
- data/lib/rubocop/rspec/language.rb +25 -7
- data/lib/rubocop/rspec/version.rb +1 -1
- data/spec/expect_violation/expectation_spec.rb +16 -16
- data/spec/project/changelog_spec.rb +1 -1
- data/spec/project/default_config_spec.rb +1 -1
- data/spec/project/project_requires_spec.rb +1 -1
- data/spec/rubocop/cop/rspec/any_instance_spec.rb +4 -4
- data/spec/rubocop/cop/rspec/around_block_spec.rb +115 -26
- data/spec/rubocop/cop/rspec/be_eql_spec.rb +9 -9
- data/spec/rubocop/cop/rspec/before_after_all_spec.rb +38 -80
- data/spec/rubocop/cop/rspec/describe_class_spec.rb +1 -1
- data/spec/rubocop/cop/rspec/describe_method_spec.rb +2 -2
- data/spec/rubocop/cop/rspec/described_class_spec.rb +13 -13
- data/spec/rubocop/cop/rspec/empty_example_group_spec.rb +1 -1
- data/spec/rubocop/cop/rspec/example_length_spec.rb +3 -32
- data/spec/rubocop/cop/rspec/example_wording_spec.rb +21 -2
- data/spec/rubocop/cop/rspec/expect_actual_spec.rb +33 -18
- data/spec/rubocop/cop/rspec/expect_output_spec.rb +3 -3
- data/spec/rubocop/cop/rspec/file_path_spec.rb +119 -170
- data/spec/rubocop/cop/rspec/focus_spec.rb +1 -1
- data/spec/rubocop/cop/rspec/hook_argument_spec.rb +1 -3
- data/spec/rubocop/cop/rspec/implicit_expect_spec.rb +1 -1
- data/spec/rubocop/cop/rspec/instance_spy_spec.rb +11 -11
- data/spec/rubocop/cop/rspec/instance_variable_spec.rb +4 -4
- data/spec/rubocop/cop/rspec/it_behaves_like_spec.rb +51 -0
- data/spec/rubocop/cop/rspec/leading_subject_spec.rb +1 -1
- data/spec/rubocop/cop/rspec/let_setup_spec.rb +1 -1
- data/spec/rubocop/cop/rspec/message_chain_spec.rb +3 -3
- data/spec/rubocop/cop/rspec/message_expectation_spec.rb +5 -23
- data/spec/rubocop/cop/rspec/message_spies_spec.rb +9 -23
- data/spec/rubocop/cop/rspec/multiple_describes_spec.rb +1 -1
- data/spec/rubocop/cop/rspec/multiple_expectations_spec.rb +66 -3
- data/spec/rubocop/cop/rspec/nested_groups_spec.rb +4 -4
- data/spec/rubocop/cop/rspec/not_to_not_spec.rb +3 -3
- data/spec/rubocop/cop/rspec/repeated_description_spec.rb +1 -1
- data/spec/rubocop/cop/rspec/repeated_example_spec.rb +1 -1
- data/spec/rubocop/cop/rspec/scattered_setup_spec.rb +1 -1
- data/spec/rubocop/cop/rspec/shared_context_spec.rb +142 -0
- data/spec/rubocop/cop/rspec/single_argument_message_chain_spec.rb +5 -5
- data/spec/rubocop/cop/rspec/subject_stub_spec.rb +1 -1
- data/spec/rubocop/cop/rspec/verified_doubles_spec.rb +2 -2
- data/spec/rubocop/rspec/config_formatter_spec.rb +12 -12
- data/spec/rubocop/rspec/description_extractor_spec.rb +23 -23
- data/spec/rubocop/rspec/example_group_spec.rb +11 -11
- data/spec/rubocop/rspec/example_spec.rb +1 -1
- data/spec/rubocop/rspec/language/selector_set_spec.rb +1 -1
- data/spec/rubocop/rspec/util/one_spec.rb +1 -1
- data/spec/rubocop/rspec/wording_spec.rb +1 -1
- data/spec/shared/detects_style_behavior.rb +3 -4
- data/spec/spec_helper.rb +10 -0
- metadata +8 -2
@@ -14,37 +14,26 @@ module RuboCop
|
|
14
14
|
# expect(false).not_to be_true
|
15
15
|
# end
|
16
16
|
class NotToNot < Cop
|
17
|
-
include
|
17
|
+
include ConfigurableEnforcedStyle
|
18
18
|
|
19
|
-
MSG = 'Prefer `%s` over `%s
|
19
|
+
MSG = 'Prefer `%s` over `%s`.'.freeze
|
20
20
|
|
21
|
-
|
21
|
+
def_node_matcher :not_to_not_offense, '(send _ % ...)'
|
22
22
|
|
23
23
|
def on_send(node)
|
24
|
-
|
25
|
-
|
26
|
-
return unless METHOD_NAMES.include?(method_name)
|
27
|
-
|
28
|
-
return if style.equal?(method_name)
|
29
|
-
add_offense(node, :expression)
|
30
|
-
end
|
31
|
-
|
32
|
-
def message(node)
|
33
|
-
_receiver, method_name, *_args = *node
|
34
|
-
|
35
|
-
if method_name.equal?(:not_to)
|
36
|
-
format(MSG, 'to_not', 'not_to')
|
37
|
-
else
|
38
|
-
format(MSG, 'not_to', 'to_not')
|
24
|
+
not_to_not_offense(node, alternative_style) do
|
25
|
+
add_offense(node, :expression)
|
39
26
|
end
|
40
27
|
end
|
41
28
|
|
42
29
|
def autocorrect(node)
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
30
|
+
->(corrector) { corrector.replace(node.loc.selector, style.to_s) }
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def message(_node)
|
36
|
+
format(MSG, style, alternative_style)
|
48
37
|
end
|
49
38
|
end
|
50
39
|
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks for proper shared_context and shared_examples usage.
|
7
|
+
#
|
8
|
+
# If there are no examples defined, use shared_context.
|
9
|
+
# If there is no setup defined, use shared_examples.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# # bad
|
13
|
+
# RSpec.shared_context 'only examples here' do
|
14
|
+
# it 'does x' do
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# it 'does 'y' do
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# # good
|
22
|
+
# RSpec.shared_examples 'only examples here' do
|
23
|
+
# it 'does x' do
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# it 'does 'y' do
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# @example
|
31
|
+
# # bad
|
32
|
+
# RSpec.shared_examples 'only setup here' do
|
33
|
+
# subject(:foo) { :bar }
|
34
|
+
#
|
35
|
+
# let(:baz) { :bazz }
|
36
|
+
#
|
37
|
+
# before do
|
38
|
+
# something
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# # good
|
43
|
+
# RSpec.shared_context 'only setup here' do
|
44
|
+
# subject(:foo) { :bar }
|
45
|
+
#
|
46
|
+
# let(:baz) { :bazz }
|
47
|
+
#
|
48
|
+
# before do
|
49
|
+
# something
|
50
|
+
# end
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
class SharedContext < Cop
|
54
|
+
MSG_EXAMPLES = "Use `shared_examples` when you don't "\
|
55
|
+
'define context.'.freeze
|
56
|
+
|
57
|
+
MSG_CONTEXT = "Use `shared_context` when you don't "\
|
58
|
+
'define examples.'.freeze
|
59
|
+
|
60
|
+
examples = (Examples::ALL + Includes::EXAMPLES)
|
61
|
+
def_node_search :examples?, examples.send_pattern
|
62
|
+
|
63
|
+
context = (Hooks::ALL + Helpers::ALL + Includes::CONTEXT + Subject::ALL)
|
64
|
+
def_node_search :context?, context.send_pattern
|
65
|
+
|
66
|
+
def_node_matcher :shared_context, SharedGroups::CONTEXT.block_pattern
|
67
|
+
def_node_matcher :shared_example, SharedGroups::EXAMPLES.block_pattern
|
68
|
+
|
69
|
+
def on_block(node)
|
70
|
+
context_with_only_examples(node) do
|
71
|
+
add_shared_item_offense(node, MSG_EXAMPLES)
|
72
|
+
end
|
73
|
+
|
74
|
+
examples_with_only_context(node) do
|
75
|
+
add_shared_item_offense(node, MSG_CONTEXT)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def autocorrect(node)
|
80
|
+
lambda do |corrector|
|
81
|
+
context_with_only_examples(node.parent) do
|
82
|
+
corrector.replace(node.loc.selector, 'shared_examples')
|
83
|
+
end
|
84
|
+
|
85
|
+
examples_with_only_context(node.parent) do
|
86
|
+
corrector.replace(node.loc.selector, 'shared_context')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def context_with_only_examples(node)
|
94
|
+
shared_context(node) { yield if examples?(node) && !context?(node) }
|
95
|
+
end
|
96
|
+
|
97
|
+
def examples_with_only_context(node)
|
98
|
+
shared_example(node) { yield if context?(node) && !examples?(node) }
|
99
|
+
end
|
100
|
+
|
101
|
+
def add_shared_item_offense(node, message)
|
102
|
+
add_offense(node.children.first, :expression, message)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -15,44 +15,37 @@ module RuboCop
|
|
15
15
|
# allow(foo).to receive("bar.baz")
|
16
16
|
#
|
17
17
|
class SingleArgumentMessageChain < Cop
|
18
|
-
|
19
|
-
|
18
|
+
MSG = 'Use `%<recommended>s` instead of calling '\
|
19
|
+
'`%<called>s` with a single argument.'.freeze
|
20
|
+
|
21
|
+
def_node_matcher :message_chain, <<-PATTERN
|
22
|
+
(send _ #{Matchers::MESSAGE_CHAIN.node_pattern_union} $...)
|
23
|
+
PATTERN
|
20
24
|
|
21
25
|
def on_send(node)
|
22
|
-
|
23
|
-
|
24
|
-
return if args.size > 1
|
25
|
-
return if multi_argument_string?(args)
|
26
|
+
message_chain(node) do |(first, *remaining)|
|
27
|
+
return if first.to_s.include?('.') || remaining.any?
|
26
28
|
|
27
|
-
|
29
|
+
add_offense(node, :selector)
|
30
|
+
end
|
28
31
|
end
|
29
32
|
|
30
33
|
def autocorrect(node)
|
31
|
-
_receiver, method_name, *_args = *node
|
32
34
|
lambda do |corrector|
|
33
|
-
corrector.replace(
|
34
|
-
node.loc.selector,
|
35
|
-
method_name.equal?(:receive_message_chain) ? 'receive' : 'stub'
|
36
|
-
)
|
35
|
+
corrector.replace(node.loc.selector, replacement(node.method_name))
|
37
36
|
end
|
38
37
|
end
|
39
38
|
|
40
39
|
private
|
41
40
|
|
42
|
-
def
|
43
|
-
|
44
|
-
args.first.type == :str &&
|
45
|
-
args.first.children.first.include?('.')
|
41
|
+
def replacement(method)
|
42
|
+
method.equal?(:receive_message_chain) ? 'receive' : 'stub'
|
46
43
|
end
|
47
44
|
|
48
|
-
def message(
|
49
|
-
|
45
|
+
def message(node)
|
46
|
+
method = node.method_name
|
50
47
|
|
51
|
-
format(
|
52
|
-
MESSAGE,
|
53
|
-
recommended_method: recommendation,
|
54
|
-
called_method: method
|
55
|
-
)
|
48
|
+
format(MSG, recommended: replacement(method), called: method)
|
56
49
|
end
|
57
50
|
end
|
58
51
|
end
|
@@ -39,10 +39,10 @@ module RuboCop
|
|
39
39
|
#
|
40
40
|
# @yield [Symbol] subject name
|
41
41
|
def_node_matcher :subject, <<-PATTERN
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
{
|
43
|
+
(block (send nil :subject (sym $_)) args ...)
|
44
|
+
(block (send nil $:subject) args ...)
|
45
|
+
}
|
46
46
|
PATTERN
|
47
47
|
|
48
48
|
# @!method message_expectation?(node, method_name)
|
@@ -25,10 +25,11 @@ module RuboCop
|
|
25
25
|
PATTERN
|
26
26
|
|
27
27
|
def on_send(node)
|
28
|
-
|
29
|
-
|
28
|
+
unverified_double(node) do |name|
|
29
|
+
return if name.sym_type? && cop_config['IgnoreSymbolicNames']
|
30
30
|
|
31
|
-
|
31
|
+
add_offense(node, :expression)
|
32
|
+
end
|
32
33
|
end
|
33
34
|
end
|
34
35
|
end
|
@@ -17,7 +17,7 @@ module RuboCop
|
|
17
17
|
#
|
18
18
|
# Detect if node is `before`, `after`, `around`
|
19
19
|
def_node_matcher :hook, <<-PATTERN
|
20
|
-
|
20
|
+
(block {$(send nil #{Hooks::ALL.node_pattern_union} ...)} ...)
|
21
21
|
PATTERN
|
22
22
|
|
23
23
|
def examples
|
@@ -56,20 +56,23 @@ module RuboCop
|
|
56
56
|
end
|
57
57
|
|
58
58
|
module SharedGroups
|
59
|
-
|
60
|
-
|
61
|
-
|
59
|
+
EXAMPLES = SelectorSet.new(%i(shared_examples shared_examples_for))
|
60
|
+
CONTEXT = SelectorSet.new(%i(shared_context))
|
61
|
+
|
62
|
+
ALL = EXAMPLES + CONTEXT
|
62
63
|
end
|
63
64
|
|
64
65
|
module Includes
|
65
|
-
|
66
|
+
EXAMPLES = SelectorSet.new(
|
66
67
|
%i(
|
67
68
|
it_behaves_like
|
68
69
|
it_should_behave_like
|
69
|
-
include_context
|
70
70
|
include_examples
|
71
71
|
)
|
72
72
|
)
|
73
|
+
CONTEXT = SelectorSet.new(%i(include_context))
|
74
|
+
|
75
|
+
ALL = EXAMPLES + CONTEXT
|
73
76
|
end
|
74
77
|
|
75
78
|
module Examples
|
@@ -82,19 +85,34 @@ module RuboCop
|
|
82
85
|
end
|
83
86
|
|
84
87
|
module Hooks
|
85
|
-
ALL = SelectorSet.new(
|
88
|
+
ALL = SelectorSet.new(
|
89
|
+
%i(
|
90
|
+
prepend_before
|
91
|
+
before
|
92
|
+
append_before
|
93
|
+
around
|
94
|
+
prepend_after
|
95
|
+
after
|
96
|
+
append_after
|
97
|
+
)
|
98
|
+
)
|
86
99
|
end
|
87
100
|
|
88
101
|
module Helpers
|
89
102
|
ALL = SelectorSet.new(%i(let let!))
|
90
103
|
end
|
91
104
|
|
105
|
+
module Subject
|
106
|
+
ALL = SelectorSet.new(%i(subject))
|
107
|
+
end
|
108
|
+
|
92
109
|
ALL =
|
93
110
|
ExampleGroups::ALL +
|
94
111
|
SharedGroups::ALL +
|
95
112
|
Examples::ALL +
|
96
113
|
Hooks::ALL +
|
97
|
-
Helpers::ALL
|
114
|
+
Helpers::ALL +
|
115
|
+
Subject::ALL
|
98
116
|
end
|
99
117
|
end
|
100
118
|
end
|
@@ -6,9 +6,9 @@ RSpec.describe ExpectViolation::Expectation do
|
|
6
6
|
context 'when given a single assertion on class end' do
|
7
7
|
let(:string) do
|
8
8
|
<<-SRC
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
class Foo
|
10
|
+
end
|
11
|
+
^^^ The end of `Foo` should be annotated.
|
12
12
|
SRC
|
13
13
|
end
|
14
14
|
|
@@ -23,7 +23,7 @@ RSpec.describe ExpectViolation::Expectation do
|
|
23
23
|
end
|
24
24
|
|
25
25
|
it 'has an assertion on column range 1-3' do
|
26
|
-
expect(assertion.column_range).to eql(
|
26
|
+
expect(assertion.column_range).to eql(8...11)
|
27
27
|
end
|
28
28
|
|
29
29
|
it 'has an assertion with correct violation message' do
|
@@ -32,8 +32,8 @@ RSpec.describe ExpectViolation::Expectation do
|
|
32
32
|
|
33
33
|
it 'recreates source' do
|
34
34
|
expect(expectation.source).to eql(<<-RUBY)
|
35
|
-
|
36
|
-
|
35
|
+
class Foo
|
36
|
+
end
|
37
37
|
RUBY
|
38
38
|
end
|
39
39
|
end
|
@@ -41,13 +41,13 @@ RSpec.describe ExpectViolation::Expectation do
|
|
41
41
|
context 'when given many assertions on two lines' do
|
42
42
|
let(:string) do
|
43
43
|
<<-SRC
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
44
|
+
foo bar
|
45
|
+
^ Charlie
|
46
|
+
^^ Charlie
|
47
|
+
^^ Bronco
|
48
|
+
^^ Alpha
|
49
|
+
baz
|
50
|
+
^ Delta
|
51
51
|
SRC
|
52
52
|
end
|
53
53
|
|
@@ -65,7 +65,7 @@ RSpec.describe ExpectViolation::Expectation do
|
|
65
65
|
|
66
66
|
it 'has assertions on column range 1-3' do
|
67
67
|
expect(assertions.map(&:column_range)).to eql(
|
68
|
-
[
|
68
|
+
[11...13, 12...13, 12...14, 12...14, 8...9]
|
69
69
|
)
|
70
70
|
end
|
71
71
|
|
@@ -77,8 +77,8 @@ RSpec.describe ExpectViolation::Expectation do
|
|
77
77
|
|
78
78
|
it 'recreates source' do
|
79
79
|
expect(expectation.source).to eql(<<-RUBY)
|
80
|
-
|
81
|
-
|
80
|
+
foo bar
|
81
|
+
baz
|
82
82
|
RUBY
|
83
83
|
end
|
84
84
|
end
|
@@ -1,11 +1,11 @@
|
|
1
|
-
describe RuboCop::Cop::RSpec::AnyInstance do
|
1
|
+
RSpec.describe RuboCop::Cop::RSpec::AnyInstance do
|
2
2
|
subject(:cop) { described_class.new }
|
3
3
|
|
4
4
|
it 'finds `allow_any_instance_of` instead of an instance double' do
|
5
5
|
expect_violation(<<-RUBY)
|
6
6
|
before do
|
7
7
|
allow_any_instance_of(Object).to receive(:foo)
|
8
|
-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid stubbing using `allow_any_instance_of
|
8
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid stubbing using `allow_any_instance_of`.
|
9
9
|
end
|
10
10
|
RUBY
|
11
11
|
end
|
@@ -14,7 +14,7 @@ describe RuboCop::Cop::RSpec::AnyInstance do
|
|
14
14
|
expect_violation(<<-RUBY)
|
15
15
|
before do
|
16
16
|
expect_any_instance_of(Object).to receive(:foo)
|
17
|
-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid stubbing using `expect_any_instance_of
|
17
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid stubbing using `expect_any_instance_of`.
|
18
18
|
end
|
19
19
|
RUBY
|
20
20
|
end
|
@@ -23,7 +23,7 @@ describe RuboCop::Cop::RSpec::AnyInstance do
|
|
23
23
|
expect_violation(<<-RUBY)
|
24
24
|
before do
|
25
25
|
Object.any_instance.should_receive(:foo)
|
26
|
-
^^^^^^^^^^^^^^^^^^^ Avoid stubbing using `any_instance
|
26
|
+
^^^^^^^^^^^^^^^^^^^ Avoid stubbing using `any_instance`.
|
27
27
|
end
|
28
28
|
RUBY
|
29
29
|
end
|