rubocop-rspec 1.15.1 → 1.16.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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +20 -1
  3. data/Gemfile +0 -1
  4. data/config/default.yml +105 -0
  5. data/lib/rubocop-rspec.rb +27 -0
  6. data/lib/rubocop/cop/rspec/align_left_let_brace.rb +51 -0
  7. data/lib/rubocop/cop/rspec/align_right_let_brace.rb +51 -0
  8. data/lib/rubocop/cop/rspec/any_instance.rb +1 -1
  9. data/lib/rubocop/cop/rspec/cop.rb +4 -2
  10. data/lib/rubocop/cop/rspec/expect_in_hook.rb +61 -0
  11. data/lib/rubocop/cop/rspec/factory_girl/dynamic_attribute_defined_statically.rb +84 -0
  12. data/lib/rubocop/cop/rspec/hook_argument.rb +11 -5
  13. data/lib/rubocop/cop/rspec/invalid_predicate_matcher.rb +42 -0
  14. data/lib/rubocop/cop/rspec/let_before_examples.rb +66 -0
  15. data/lib/rubocop/cop/rspec/multiple_expectations.rb +3 -5
  16. data/lib/rubocop/cop/rspec/multiple_subjects.rb +80 -0
  17. data/lib/rubocop/cop/rspec/named_subject.rb +5 -6
  18. data/lib/rubocop/cop/rspec/overwriting_setup.rb +1 -1
  19. data/lib/rubocop/cop/rspec/predicate_matcher.rb +337 -0
  20. data/lib/rubocop/cop/rspec/return_from_stub.rb +83 -0
  21. data/lib/rubocop/cop/rspec/void_expect.rb +52 -0
  22. data/lib/rubocop/rspec/align_let_brace.rb +64 -0
  23. data/lib/rubocop/rspec/config_formatter.rb +7 -4
  24. data/lib/rubocop/rspec/description_extractor.rb +2 -2
  25. data/lib/rubocop/rspec/example_group.rb +25 -2
  26. data/lib/rubocop/rspec/factory_girl.rb +7 -0
  27. data/lib/rubocop/rspec/language.rb +6 -1
  28. data/lib/rubocop/rspec/version.rb +1 -1
  29. data/rubocop-rspec.gemspec +1 -4
  30. data/spec/project/default_config_spec.rb +8 -4
  31. data/spec/rubocop/cop/rspec/align_left_let_brace_spec.rb +62 -0
  32. data/spec/rubocop/cop/rspec/align_right_let_brace_spec.rb +62 -0
  33. data/spec/rubocop/cop/rspec/any_instance_spec.rb +3 -3
  34. data/spec/rubocop/cop/rspec/around_block_spec.rb +11 -11
  35. data/spec/rubocop/cop/rspec/be_eql_spec.rb +7 -7
  36. data/spec/rubocop/cop/rspec/before_after_all_spec.rb +4 -4
  37. data/spec/rubocop/cop/rspec/cop_spec.rb +7 -7
  38. data/spec/rubocop/cop/rspec/describe_class_spec.rb +18 -18
  39. data/spec/rubocop/cop/rspec/describe_method_spec.rb +4 -4
  40. data/spec/rubocop/cop/rspec/describe_symbol_spec.rb +6 -6
  41. data/spec/rubocop/cop/rspec/described_class_spec.rb +18 -18
  42. data/spec/rubocop/cop/rspec/empty_example_group_spec.rb +5 -5
  43. data/spec/rubocop/cop/rspec/empty_line_after_final_let_spec.rb +9 -9
  44. data/spec/rubocop/cop/rspec/empty_line_after_subject_spec.rb +5 -5
  45. data/spec/rubocop/cop/rspec/example_length_spec.rb +6 -6
  46. data/spec/rubocop/cop/rspec/example_wording_spec.rb +10 -10
  47. data/spec/rubocop/cop/rspec/expect_actual_spec.rb +10 -10
  48. data/spec/rubocop/cop/rspec/expect_in_hook_spec.rb +79 -0
  49. data/spec/rubocop/cop/rspec/expect_output_spec.rb +7 -7
  50. data/spec/rubocop/cop/rspec/factory_girl/dynamic_attribute_defined_statically_spec.rb +87 -0
  51. data/spec/rubocop/cop/rspec/file_path_spec.rb +29 -29
  52. data/spec/rubocop/cop/rspec/focus_spec.rb +6 -6
  53. data/spec/rubocop/cop/rspec/hook_argument_spec.rb +35 -23
  54. data/spec/rubocop/cop/rspec/implicit_expect_spec.rb +10 -10
  55. data/spec/rubocop/cop/rspec/instance_spy_spec.rb +4 -4
  56. data/spec/rubocop/cop/rspec/instance_variable_spec.rb +7 -7
  57. data/spec/rubocop/cop/rspec/invalid_predicate_matcher_spec.rb +37 -0
  58. data/spec/rubocop/cop/rspec/it_behaves_like_spec.rb +4 -4
  59. data/spec/rubocop/cop/rspec/iterated_expectation_spec.rb +8 -8
  60. data/spec/rubocop/cop/rspec/leading_subject_spec.rb +5 -5
  61. data/spec/rubocop/cop/rspec/let_before_examples_spec.rb +83 -0
  62. data/spec/rubocop/cop/rspec/let_setup_spec.rb +4 -4
  63. data/spec/rubocop/cop/rspec/message_chain_spec.rb +2 -2
  64. data/spec/rubocop/cop/rspec/message_expectation_spec.rb +4 -4
  65. data/spec/rubocop/cop/rspec/message_spies_spec.rb +18 -18
  66. data/spec/rubocop/cop/rspec/multiple_describes_spec.rb +3 -3
  67. data/spec/rubocop/cop/rspec/multiple_expectations_spec.rb +45 -9
  68. data/spec/rubocop/cop/rspec/multiple_subjects_spec.rb +96 -0
  69. data/spec/rubocop/cop/rspec/named_subject_spec.rb +4 -4
  70. data/spec/rubocop/cop/rspec/nested_groups_spec.rb +3 -3
  71. data/spec/rubocop/cop/rspec/not_to_not_spec.rb +4 -4
  72. data/spec/rubocop/cop/rspec/overwriting_setup_spec.rb +4 -4
  73. data/spec/rubocop/cop/rspec/predicate_matcher_spec.rb +335 -0
  74. data/spec/rubocop/cop/rspec/repeated_description_spec.rb +5 -5
  75. data/spec/rubocop/cop/rspec/repeated_example_spec.rb +5 -5
  76. data/spec/rubocop/cop/rspec/return_from_stub_spec.rb +85 -0
  77. data/spec/rubocop/cop/rspec/scattered_let_spec.rb +2 -2
  78. data/spec/rubocop/cop/rspec/scattered_setup_spec.rb +8 -8
  79. data/spec/rubocop/cop/rspec/shared_context_spec.rb +10 -10
  80. data/spec/rubocop/cop/rspec/single_argument_message_chain_spec.rb +10 -10
  81. data/spec/rubocop/cop/rspec/subject_stub_spec.rb +9 -9
  82. data/spec/rubocop/cop/rspec/verified_doubles_spec.rb +7 -7
  83. data/spec/rubocop/cop/rspec/void_expect_spec.rb +47 -0
  84. data/spec/rubocop/rspec/config_formatter_spec.rb +2 -0
  85. data/spec/spec_helper.rb +1 -1
  86. data/spec/support/expect_offense.rb +17 -0
  87. metadata +39 -51
  88. data/spec/expect_violation/expectation_spec.rb +0 -85
  89. data/spec/support/expect_violation.rb +0 -170
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # This cop checks void `expect()`.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # expect(something)
11
+ #
12
+ # # good
13
+ # expect(something).to be(1)
14
+ class VoidExpect < Cop
15
+ MSG = 'Do not use `expect()` without `.to` or `.not_to`. ' \
16
+ 'Chain the methods or remove it.'.freeze
17
+
18
+ def_node_matcher :expect?, <<-PATTERN
19
+ (send nil :expect ...)
20
+ PATTERN
21
+
22
+ def_node_matcher :expect_block?, <<-PATTERN
23
+ (block #expect? (args) _body)
24
+ PATTERN
25
+
26
+ def on_send(node)
27
+ return unless expect?(node)
28
+ check_expect(node)
29
+ end
30
+
31
+ def on_block(node)
32
+ return unless expect_block?(node)
33
+ check_expect(node)
34
+ end
35
+
36
+ private
37
+
38
+ def check_expect(node)
39
+ return unless void?(node)
40
+ add_offense(node, :expression)
41
+ end
42
+
43
+ def void?(expect)
44
+ parent = expect.parent
45
+ return true unless parent
46
+ return true if parent.begin_type?
47
+ return true if parent.block_type? && parent.children[2] == expect
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module RSpec
5
+ # Shared behavior for aligning braces for single line lets
6
+ class AlignLetBrace
7
+ extend NodePattern::Macros
8
+
9
+ def_node_matcher :let?, Language::Helpers::ALL.block_pattern.freeze
10
+
11
+ def initialize(root, token)
12
+ @root = root
13
+ @token = token
14
+ end
15
+
16
+ def offending_tokens
17
+ single_line_lets.reject do |let|
18
+ target_column_for(let) == let_token(let).column
19
+ end
20
+ end
21
+
22
+ def indent_for(node)
23
+ ' ' * (target_column_for(node) - let_token(node).column)
24
+ end
25
+
26
+ private
27
+
28
+ def let_token(node)
29
+ node.loc.public_send(token)
30
+ end
31
+
32
+ def target_column_for(let)
33
+ let_group_for(let).map { |member| let_token(member).column }.max
34
+ end
35
+
36
+ def let_group_for(let)
37
+ adjacent_let_chunks.detect do |chunk|
38
+ chunk.any? do |member|
39
+ member == let && member.loc.line == let.loc.line
40
+ end
41
+ end
42
+ end
43
+
44
+ def adjacent_let_chunks
45
+ last_line = nil
46
+
47
+ single_line_lets.chunk do |node|
48
+ line = node.loc.line
49
+ last_line = (line if last_line.nil? || last_line + 1 == line)
50
+ last_line.nil?
51
+ end.map(&:last)
52
+ end
53
+
54
+ def single_line_lets
55
+ @single_line_lets ||=
56
+ root.each_node(:block).select do |node|
57
+ let?(node) && node.single_line?
58
+ end
59
+ end
60
+
61
+ attr_reader :root, :token
62
+ end
63
+ end
64
+ end
@@ -4,7 +4,8 @@ module RuboCop
4
4
  module RSpec
5
5
  # Builds a YAML config file from two config hashes
6
6
  class ConfigFormatter
7
- NAMESPACE = 'RSpec'.freeze
7
+ NAMESPACES = /^(#{Regexp.union('RSpec', 'FactoryGirl')})/
8
+ STYLE_GUIDE_BASE_URL = 'http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/'.freeze
8
9
 
9
10
  def initialize(config, descriptions)
10
11
  @config = config
@@ -12,19 +13,21 @@ module RuboCop
12
13
  end
13
14
 
14
15
  def dump
15
- YAML.dump(unified_config).gsub(/^#{NAMESPACE}/, "\n#{NAMESPACE}")
16
+ YAML.dump(unified_config).gsub(NAMESPACES, "\n\\1")
16
17
  end
17
18
 
18
19
  private
19
20
 
20
21
  def unified_config
21
22
  cops.each_with_object(config.dup) do |cop, unified|
22
- unified[cop] = config.fetch(cop).merge(descriptions.fetch(cop))
23
+ unified[cop] = config.fetch(cop)
24
+ .merge(descriptions.fetch(cop))
25
+ .merge('StyleGuide' => STYLE_GUIDE_BASE_URL + cop)
23
26
  end
24
27
  end
25
28
 
26
29
  def cops
27
- (descriptions.keys + config.keys).uniq.grep(/\A#{NAMESPACE}/)
30
+ (descriptions.keys | config.keys).grep(NAMESPACES)
28
31
  end
29
32
 
30
33
  attr_reader :config, :descriptions
@@ -19,7 +19,7 @@ module RuboCop
19
19
 
20
20
  # Decorator of a YARD code object for working with documented rspec cops
21
21
  class CodeObject
22
- COP_NAMESPACE = 'RuboCop::Cop::RSpec'.freeze
22
+ RSPEC_NAMESPACE = 'RuboCop::Cop::RSpec'.freeze
23
23
 
24
24
  def initialize(yardoc)
25
25
  @yardoc = yardoc
@@ -54,7 +54,7 @@ module RuboCop
54
54
  end
55
55
 
56
56
  def rspec_cop_namespace?
57
- documented_constant.start_with?(COP_NAMESPACE)
57
+ documented_constant.start_with?(RSPEC_NAMESPACE)
58
58
  end
59
59
 
60
60
  def documented_constant
@@ -10,8 +10,9 @@ module RuboCop
10
10
  #
11
11
  # Selectors which indicate that we should stop searching
12
12
  #
13
- def_node_matcher :scope_change?,
14
- (ExampleGroups::ALL + SharedGroups::ALL).block_pattern
13
+ def_node_matcher :scope_change?, (
14
+ ExampleGroups::ALL + SharedGroups::ALL + Includes::ALL
15
+ ).block_pattern
15
16
 
16
17
  # @!method hook(node)
17
18
  #
@@ -20,6 +21,12 @@ module RuboCop
20
21
  (block {$(send nil #{Hooks::ALL.node_pattern_union} ...)} ...)
21
22
  PATTERN
22
23
 
24
+ def_node_matcher :subject, Subject::ALL.block_pattern
25
+
26
+ def subjects
27
+ subjects_in_scope(node)
28
+ end
29
+
23
30
  def examples
24
31
  examples_in_scope(node).map(&Example.public_method(:new))
25
32
  end
@@ -30,6 +37,22 @@ module RuboCop
30
37
 
31
38
  private
32
39
 
40
+ def subjects_in_scope(node)
41
+ node.each_child_node.flat_map do |child|
42
+ find_subjects(child)
43
+ end
44
+ end
45
+
46
+ def find_subjects(node)
47
+ return [] if scope_change?(node)
48
+
49
+ if subject(node)
50
+ [node]
51
+ else
52
+ subjects_in_scope(node)
53
+ end
54
+ end
55
+
33
56
  def hooks_in_scope(node)
34
57
  node.each_child_node.flat_map do |child|
35
58
  find_hooks(child)
@@ -0,0 +1,7 @@
1
+ module RuboCop
2
+ module RSpec
3
+ # RuboCop FactoryGirl project namespace
4
+ module FactoryGirl
5
+ end
6
+ end
7
+ end
@@ -106,13 +106,18 @@ module RuboCop
106
106
  ALL = SelectorSet.new(%i[subject subject!])
107
107
  end
108
108
 
109
+ module Expectations
110
+ ALL = SelectorSet.new(%i[expect is_expected expect_any_instance_of])
111
+ end
112
+
109
113
  ALL =
110
114
  ExampleGroups::ALL +
111
115
  SharedGroups::ALL +
112
116
  Examples::ALL +
113
117
  Hooks::ALL +
114
118
  Helpers::ALL +
115
- Subject::ALL
119
+ Subject::ALL +
120
+ Expectations::ALL
116
121
  end
117
122
  end
118
123
  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.15.1'.freeze
7
+ STRING = '1.16.0'.freeze
8
8
  end
9
9
  end
10
10
  end
@@ -34,13 +34,10 @@ Gem::Specification.new do |spec|
34
34
  spec.test_files = spec.files.grep(%r{^spec/})
35
35
  spec.extra_rdoc_files = ['MIT-LICENSE.md', 'README.md']
36
36
 
37
- spec.add_runtime_dependency 'rubocop', '>= 0.42.0'
37
+ spec.add_runtime_dependency 'rubocop', '>= 0.49.0'
38
38
 
39
39
  spec.add_development_dependency 'rake'
40
40
  spec.add_development_dependency 'rspec', '>= 3.4'
41
41
  spec.add_development_dependency 'simplecov'
42
- spec.add_development_dependency 'anima'
43
- spec.add_development_dependency 'concord'
44
- spec.add_development_dependency 'adamantium'
45
42
  spec.add_development_dependency 'yard'
46
43
  end
@@ -4,14 +4,18 @@ RSpec.describe 'config/default.yml' do
4
4
  end
5
5
 
6
6
  let(:cop_names) do
7
- glob = SpecHelper::ROOT.join('lib', 'rubocop', 'cop', 'rspec', '*.rb')
8
-
7
+ namespaces = {
8
+ 'rspec' => 'RSpec',
9
+ 'factory_girl' => 'FactoryGirl'
10
+ }
11
+ glob = SpecHelper::ROOT.join('lib', 'rubocop', 'cop',
12
+ 'rspec', '{,factory_girl/}*.rb')
9
13
  cop_names =
10
14
  Pathname.glob(glob).map do |file|
11
15
  file_name = file.basename('.rb').to_s
12
16
  cop_name = file_name.gsub(/(^|_)(.)/) { Regexp.last_match(2).upcase }
13
-
14
- "RSpec/#{cop_name}"
17
+ namespace = namespaces[file.dirname.basename.to_s]
18
+ "#{namespace}/#{cop_name}"
15
19
  end
16
20
 
17
21
  cop_names - %w[RSpec/Cop]
@@ -0,0 +1,62 @@
1
+ RSpec.describe RuboCop::Cop::RSpec::AlignLeftLetBrace do
2
+ subject(:cop) { described_class.new }
3
+
4
+ it 'registers offense for unaligned braces' do
5
+ expect_offense(<<-RUBY)
6
+ let(:foo) { bar }
7
+ ^ Align left let brace
8
+ let(:hi) { baz }
9
+ ^ Align left let brace
10
+ let(:blahblah) { baz }
11
+
12
+ let(:thing) { ignore_this }
13
+ let(:other) {
14
+ ignore_this_too
15
+ }
16
+
17
+ describe 'blah' do
18
+ let(:blahblah) { baz }
19
+ let(:blah) { thing }
20
+ ^ Align left let brace
21
+ let(:a) { thing }
22
+ ^ Align left let brace
23
+ end
24
+ RUBY
25
+ end
26
+
27
+ offensive_source = <<-RUBY
28
+ let(:foo) { bar }
29
+ let(:hi) { baz }
30
+ let(:blahblah) { baz }
31
+
32
+ let(:thing) { ignore_this }
33
+ let(:other) {
34
+ ignore_this_too
35
+ }
36
+
37
+ describe 'blah' do
38
+ let(:long_name) { thing }
39
+ let(:blah) { thing }
40
+ let(:a) { thing }
41
+ end
42
+ RUBY
43
+
44
+ corrected_source = <<-RUBY
45
+ let(:foo) { bar }
46
+ let(:hi) { baz }
47
+ let(:blahblah) { baz }
48
+
49
+ let(:thing) { ignore_this }
50
+ let(:other) {
51
+ ignore_this_too
52
+ }
53
+
54
+ describe 'blah' do
55
+ let(:long_name) { thing }
56
+ let(:blah) { thing }
57
+ let(:a) { thing }
58
+ end
59
+ RUBY
60
+
61
+ include_examples 'autocorrect', offensive_source, corrected_source
62
+ end
@@ -0,0 +1,62 @@
1
+ RSpec.describe RuboCop::Cop::RSpec::AlignRightLetBrace do
2
+ subject(:cop) { described_class.new }
3
+
4
+ it 'registers offense for unaligned braces' do
5
+ expect_offense(<<-RUBY)
6
+ let(:foo) { a }
7
+ ^ Align right let brace
8
+ let(:hi) { ab }
9
+ ^ Align right let brace
10
+ let(:blahblah) { abcd }
11
+
12
+ let(:thing) { ignore_this }
13
+ let(:other) {
14
+ ignore_this_too
15
+ }
16
+
17
+ describe 'blah' do
18
+ let(:blahblah) { a }
19
+ ^ Align right let brace
20
+ let(:blah) { bc }
21
+ ^ Align right let brace
22
+ let(:a) { abc }
23
+ end
24
+ RUBY
25
+ end
26
+
27
+ offensive_source = <<-RUBY
28
+ let(:foo) { a }
29
+ let(:hi) { ab }
30
+ let(:blahblah) { abcd }
31
+
32
+ let(:thing) { ignore_this }
33
+ let(:other) {
34
+ ignore_this_too
35
+ }
36
+
37
+ describe 'blah' do
38
+ let(:blahblah) { a }
39
+ let(:blah) { bc }
40
+ let(:a) { abc }
41
+ end
42
+ RUBY
43
+
44
+ corrected_source = <<-RUBY
45
+ let(:foo) { a }
46
+ let(:hi) { ab }
47
+ let(:blahblah) { abcd }
48
+
49
+ let(:thing) { ignore_this }
50
+ let(:other) {
51
+ ignore_this_too
52
+ }
53
+
54
+ describe 'blah' do
55
+ let(:blahblah) { a }
56
+ let(:blah) { bc }
57
+ let(:a) { abc }
58
+ end
59
+ RUBY
60
+
61
+ include_examples 'autocorrect', offensive_source, corrected_source
62
+ end
@@ -2,7 +2,7 @@ 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
- expect_violation(<<-RUBY)
5
+ expect_offense(<<-RUBY)
6
6
  before do
7
7
  allow_any_instance_of(Object).to receive(:foo)
8
8
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid stubbing using `allow_any_instance_of`.
@@ -11,7 +11,7 @@ RSpec.describe RuboCop::Cop::RSpec::AnyInstance do
11
11
  end
12
12
 
13
13
  it 'finds `expect_any_instance_of` instead of an instance double' do
14
- expect_violation(<<-RUBY)
14
+ expect_offense(<<-RUBY)
15
15
  before do
16
16
  expect_any_instance_of(Object).to receive(:foo)
17
17
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid stubbing using `expect_any_instance_of`.
@@ -20,7 +20,7 @@ RSpec.describe RuboCop::Cop::RSpec::AnyInstance do
20
20
  end
21
21
 
22
22
  it 'finds old `any_instance` syntax instead of an instance double' do
23
- expect_violation(<<-RUBY)
23
+ expect_offense(<<-RUBY)
24
24
  before do
25
25
  Object.any_instance.should_receive(:foo)
26
26
  ^^^^^^^^^^^^^^^^^^^ Avoid stubbing using `any_instance`.