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.
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