rubocop-rspec 1.12.0 → 1.13.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.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/config/default.yml +15 -1
  4. data/lib/rubocop-rspec.rb +2 -0
  5. data/lib/rubocop/cop/rspec/any_instance.rb +7 -10
  6. data/lib/rubocop/cop/rspec/around_block.rb +19 -30
  7. data/lib/rubocop/cop/rspec/be_eql.rb +3 -7
  8. data/lib/rubocop/cop/rspec/before_after_all.rb +10 -16
  9. data/lib/rubocop/cop/rspec/cop.rb +5 -1
  10. data/lib/rubocop/cop/rspec/describe_class.rb +8 -8
  11. data/lib/rubocop/cop/rspec/describe_method.rb +6 -5
  12. data/lib/rubocop/cop/rspec/described_class.rb +2 -2
  13. data/lib/rubocop/cop/rspec/example_length.rb +5 -8
  14. data/lib/rubocop/cop/rspec/example_wording.rb +57 -23
  15. data/lib/rubocop/cop/rspec/expect_actual.rb +3 -9
  16. data/lib/rubocop/cop/rspec/expect_output.rb +2 -2
  17. data/lib/rubocop/cop/rspec/file_path.rb +30 -29
  18. data/lib/rubocop/cop/rspec/hook_argument.rb +1 -1
  19. data/lib/rubocop/cop/rspec/instance_spy.rb +12 -12
  20. data/lib/rubocop/cop/rspec/instance_variable.rb +2 -2
  21. data/lib/rubocop/cop/rspec/it_behaves_like.rb +47 -0
  22. data/lib/rubocop/cop/rspec/leading_subject.rb +1 -1
  23. data/lib/rubocop/cop/rspec/message_chain.rb +7 -4
  24. data/lib/rubocop/cop/rspec/message_spies.rb +6 -5
  25. data/lib/rubocop/cop/rspec/multiple_describes.rb +1 -1
  26. data/lib/rubocop/cop/rspec/multiple_expectations.rb +38 -6
  27. data/lib/rubocop/cop/rspec/named_subject.rb +2 -2
  28. data/lib/rubocop/cop/rspec/nested_groups.rb +10 -6
  29. data/lib/rubocop/cop/rspec/not_to_not.rb +12 -23
  30. data/lib/rubocop/cop/rspec/shared_context.rb +107 -0
  31. data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +16 -23
  32. data/lib/rubocop/cop/rspec/subject_stub.rb +4 -4
  33. data/lib/rubocop/cop/rspec/verified_doubles.rb +4 -3
  34. data/lib/rubocop/rspec/example_group.rb +1 -1
  35. data/lib/rubocop/rspec/language.rb +25 -7
  36. data/lib/rubocop/rspec/version.rb +1 -1
  37. data/spec/expect_violation/expectation_spec.rb +16 -16
  38. data/spec/project/changelog_spec.rb +1 -1
  39. data/spec/project/default_config_spec.rb +1 -1
  40. data/spec/project/project_requires_spec.rb +1 -1
  41. data/spec/rubocop/cop/rspec/any_instance_spec.rb +4 -4
  42. data/spec/rubocop/cop/rspec/around_block_spec.rb +115 -26
  43. data/spec/rubocop/cop/rspec/be_eql_spec.rb +9 -9
  44. data/spec/rubocop/cop/rspec/before_after_all_spec.rb +38 -80
  45. data/spec/rubocop/cop/rspec/describe_class_spec.rb +1 -1
  46. data/spec/rubocop/cop/rspec/describe_method_spec.rb +2 -2
  47. data/spec/rubocop/cop/rspec/described_class_spec.rb +13 -13
  48. data/spec/rubocop/cop/rspec/empty_example_group_spec.rb +1 -1
  49. data/spec/rubocop/cop/rspec/example_length_spec.rb +3 -32
  50. data/spec/rubocop/cop/rspec/example_wording_spec.rb +21 -2
  51. data/spec/rubocop/cop/rspec/expect_actual_spec.rb +33 -18
  52. data/spec/rubocop/cop/rspec/expect_output_spec.rb +3 -3
  53. data/spec/rubocop/cop/rspec/file_path_spec.rb +119 -170
  54. data/spec/rubocop/cop/rspec/focus_spec.rb +1 -1
  55. data/spec/rubocop/cop/rspec/hook_argument_spec.rb +1 -3
  56. data/spec/rubocop/cop/rspec/implicit_expect_spec.rb +1 -1
  57. data/spec/rubocop/cop/rspec/instance_spy_spec.rb +11 -11
  58. data/spec/rubocop/cop/rspec/instance_variable_spec.rb +4 -4
  59. data/spec/rubocop/cop/rspec/it_behaves_like_spec.rb +51 -0
  60. data/spec/rubocop/cop/rspec/leading_subject_spec.rb +1 -1
  61. data/spec/rubocop/cop/rspec/let_setup_spec.rb +1 -1
  62. data/spec/rubocop/cop/rspec/message_chain_spec.rb +3 -3
  63. data/spec/rubocop/cop/rspec/message_expectation_spec.rb +5 -23
  64. data/spec/rubocop/cop/rspec/message_spies_spec.rb +9 -23
  65. data/spec/rubocop/cop/rspec/multiple_describes_spec.rb +1 -1
  66. data/spec/rubocop/cop/rspec/multiple_expectations_spec.rb +66 -3
  67. data/spec/rubocop/cop/rspec/nested_groups_spec.rb +4 -4
  68. data/spec/rubocop/cop/rspec/not_to_not_spec.rb +3 -3
  69. data/spec/rubocop/cop/rspec/repeated_description_spec.rb +1 -1
  70. data/spec/rubocop/cop/rspec/repeated_example_spec.rb +1 -1
  71. data/spec/rubocop/cop/rspec/scattered_setup_spec.rb +1 -1
  72. data/spec/rubocop/cop/rspec/shared_context_spec.rb +142 -0
  73. data/spec/rubocop/cop/rspec/single_argument_message_chain_spec.rb +5 -5
  74. data/spec/rubocop/cop/rspec/subject_stub_spec.rb +1 -1
  75. data/spec/rubocop/cop/rspec/verified_doubles_spec.rb +2 -2
  76. data/spec/rubocop/rspec/config_formatter_spec.rb +12 -12
  77. data/spec/rubocop/rspec/description_extractor_spec.rb +23 -23
  78. data/spec/rubocop/rspec/example_group_spec.rb +11 -11
  79. data/spec/rubocop/rspec/example_spec.rb +1 -1
  80. data/spec/rubocop/rspec/language/selector_set_spec.rb +1 -1
  81. data/spec/rubocop/rspec/util/one_spec.rb +1 -1
  82. data/spec/rubocop/rspec/wording_spec.rb +1 -1
  83. data/spec/shared/detects_style_behavior.rb +3 -4
  84. data/spec/spec_helper.rb +10 -0
  85. 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 RuboCop::Cop::ConfigurableEnforcedStyle
17
+ include ConfigurableEnforcedStyle
18
18
 
19
- MSG = 'Prefer `%s` over `%s`'.freeze
19
+ MSG = 'Prefer `%s` over `%s`.'.freeze
20
20
 
21
- METHOD_NAMES = [:not_to, :to_not].freeze
21
+ def_node_matcher :not_to_not_offense, '(send _ % ...)'
22
22
 
23
23
  def on_send(node)
24
- _receiver, method_name, *_args = *node
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
- _receiver, method_name, *_args = *node
44
- lambda do |corrector|
45
- corrector.replace(node.loc.selector,
46
- method_name.equal?(:not_to) ? 'to_not' : 'not_to')
47
- end
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
- MESSAGE = 'Use `%<recommended_method>s` instead of calling ' \
19
- '`%<called_method>s` with a single argument'.freeze
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
- _receiver, method_name, *args = *node
23
- return unless Matchers::MESSAGE_CHAIN.include?(method_name)
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
- add_offense(node, :selector, message(method_name))
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 multi_argument_string?(args)
43
- args.size == 1 &&
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(method)
49
- recommendation = method == :receive_message_chain ? :receive : :stub
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
- (block (send nil :subject (sym $_)) args ...)
44
- (block (send nil $:subject) args ...)
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
- return unless (name = unverified_double(node))
29
- return if name.type.equal?(:sym) && cop_config['IgnoreSymbolicNames']
28
+ unverified_double(node) do |name|
29
+ return if name.sym_type? && cop_config['IgnoreSymbolicNames']
30
30
 
31
- add_offense(node, :expression)
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
- (block {$(send nil #{Hooks::ALL.node_pattern_union} ...)} ...)
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
- ALL = SelectorSet.new(
60
- %i(shared_examples shared_context shared_examples_for)
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
- ALL = SelectorSet.new(
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(%i(after around before))
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
@@ -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 = '1.12.0'.freeze
7
+ STRING = '1.13.0'.freeze
8
8
  end
9
9
  end
10
10
  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
- class Foo
10
- end
11
- ^^^ The end of `Foo` should be annotated.
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(6...9)
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
- class Foo
36
- end
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
- foo bar
45
- ^ Charlie
46
- ^^ Charlie
47
- ^^ Bronco
48
- ^^ Alpha
49
- baz
50
- ^ Delta
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
- [9...11, 10...11, 10...12, 10...12, 6...7]
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
- foo bar
81
- baz
80
+ foo bar
81
+ baz
82
82
  RUBY
83
83
  end
84
84
  end
@@ -1,4 +1,4 @@
1
- describe 'CHANGELOG.md' do
1
+ RSpec.describe 'CHANGELOG.md' do
2
2
  subject(:changelog) { SpecHelper::ROOT.join('CHANGELOG.md').read }
3
3
 
4
4
  it 'has link definitions for all implicit links' do
@@ -1,4 +1,4 @@
1
- describe 'config/default.yml' do
1
+ RSpec.describe 'config/default.yml' do
2
2
  subject(:default_config) do
3
3
  RuboCop::ConfigLoader.load_file('config/default.yml')
4
4
  end
@@ -1,4 +1,4 @@
1
- describe 'Project requires' do
1
+ RSpec.describe 'Project requires' do
2
2
  it 'alphabetizes cop requires' do
3
3
  source = SpecHelper::ROOT.join('lib', 'rubocop-rspec.rb').read
4
4
  requires = source.split("\n").grep(%r{rubocop/cop/rspec/[^(?:cop)]})
@@ -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