rubocop-rspec 1.5.1 → 1.5.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/Gemfile +0 -2
  4. data/README.md +0 -8
  5. data/Rakefile +1 -3
  6. data/lib/rubocop-rspec.rb +2 -2
  7. data/lib/rubocop/cop/rspec/any_instance.rb +1 -10
  8. data/lib/rubocop/cop/rspec/describe_class.rb +23 -15
  9. data/lib/rubocop/cop/rspec/describe_method.rb +4 -6
  10. data/lib/rubocop/cop/rspec/described_class.rb +5 -8
  11. data/lib/rubocop/cop/rspec/example_length.rb +4 -9
  12. data/lib/rubocop/cop/rspec/example_wording.rb +13 -37
  13. data/lib/rubocop/cop/rspec/file_path.rb +10 -13
  14. data/lib/rubocop/cop/rspec/focus.rb +48 -30
  15. data/lib/rubocop/cop/rspec/instance_variable.rb +0 -1
  16. data/lib/rubocop/cop/rspec/multiple_describes.rb +2 -3
  17. data/lib/rubocop/cop/rspec/not_to_not.rb +3 -5
  18. data/lib/rubocop/cop/rspec/verified_doubles.rb +7 -15
  19. data/lib/rubocop/rspec/inject.rb +0 -1
  20. data/lib/rubocop/rspec/top_level_describe.rb +0 -2
  21. data/lib/rubocop/rspec/util.rb +19 -0
  22. data/lib/rubocop/rspec/version.rb +1 -2
  23. data/lib/rubocop/rspec/wording.rb +47 -0
  24. data/rubocop-rspec.gemspec +2 -2
  25. data/spec/project_spec.rb +0 -2
  26. data/spec/rubocop/cop/rspec/any_instance_spec.rb +0 -2
  27. data/spec/rubocop/cop/rspec/describe_class_spec.rb +36 -2
  28. data/spec/rubocop/cop/rspec/describe_method_spec.rb +10 -3
  29. data/spec/rubocop/cop/rspec/described_class_spec.rb +32 -2
  30. data/spec/rubocop/cop/rspec/example_length_spec.rb +17 -3
  31. data/spec/rubocop/cop/rspec/example_wording_spec.rb +61 -62
  32. data/spec/rubocop/cop/rspec/file_path_spec.rb +61 -21
  33. data/spec/rubocop/cop/rspec/focus_spec.rb +11 -3
  34. data/spec/rubocop/cop/rspec/instance_variable_spec.rb +13 -2
  35. data/spec/rubocop/cop/rspec/multiple_describes_spec.rb +0 -2
  36. data/spec/rubocop/cop/rspec/not_to_not_spec.rb +0 -2
  37. data/spec/rubocop/cop/rspec/verified_doubles_spec.rb +41 -19
  38. data/spec/rubocop/rspec/util/one_spec.rb +21 -0
  39. data/spec/rubocop/rspec/wording_spec.rb +44 -0
  40. data/spec/spec_helper.rb +1 -9
  41. metadata +11 -5
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module RuboCop
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module RuboCop
@@ -29,9 +28,9 @@ module RuboCop
29
28
 
30
29
  def on_top_level_describe(node, _args)
31
30
  return if single_top_level_describe?
32
- return unless top_level_nodes.first == node
31
+ return unless top_level_nodes.first.equal?(node)
33
32
 
34
- add_offense(node, :expression, MSG)
33
+ add_offense(node, :expression)
35
34
  end
36
35
  end
37
36
  end
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module RuboCop
4
2
  module Cop
5
3
  module RSpec
@@ -28,14 +26,14 @@ module RuboCop
28
26
 
29
27
  return unless METHOD_NAMES.include?(method_name)
30
28
 
31
- return if style == method_name
29
+ return if style.equal?(method_name)
32
30
  add_offense(node, :expression)
33
31
  end
34
32
 
35
33
  def message(node)
36
34
  _receiver, method_name, *_args = *node
37
35
 
38
- if method_name == :not_to
36
+ if method_name.equal?(:not_to)
39
37
  format(MSG, 'to_not', 'not_to')
40
38
  else
41
39
  format(MSG, 'not_to', 'to_not')
@@ -46,7 +44,7 @@ module RuboCop
46
44
  _receiver, method_name, *_args = *node
47
45
  lambda do |corrector|
48
46
  corrector.replace(node.loc.selector,
49
- method_name == :not_to ? 'to_not' : 'not_to')
47
+ method_name.equal?(:not_to) ? 'to_not' : 'not_to')
50
48
  end
51
49
  end
52
50
  end
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module RuboCop
@@ -19,23 +18,16 @@ module RuboCop
19
18
  # end
20
19
  class VerifiedDoubles < Cop
21
20
  MSG = 'Prefer using verifying doubles over normal doubles.'.freeze
22
- DOUBLE_TYPES = [:double, :spy].freeze
23
21
 
24
- def on_send(node)
25
- _receiver, method_name, *args = *node
26
- name, *_stubs = *args
27
- return unless DOUBLE_TYPES.include?(method_name)
28
- return if name.nil?
29
- return if name_is_symbol?(name) && cop_config['IgnoreSymbolicNames']
30
- add_offense(node,
31
- :expression,
32
- format(MSG, node.loc.expression.source))
33
- end
22
+ def_node_matcher :unverified_double, <<-PATTERN
23
+ {(send nil {:double :spy} $_ ...) }
24
+ PATTERN
34
25
 
35
- private
26
+ def on_send(node)
27
+ return unless (name = unverified_double(node))
28
+ return if name.type.equal?(:sym) && cop_config['IgnoreSymbolicNames']
36
29
 
37
- def name_is_symbol?(name)
38
- name.children.first.is_a? Symbol
30
+ add_offense(node, :expression)
39
31
  end
40
32
  end
41
33
  end
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  module RuboCop
3
2
  module RSpec
4
3
  # Because RuboCop doesn't yet support plugins, we have to monkey patch in a
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module RuboCop
4
2
  module RSpec
5
3
  # Helper methods for top level describe cops
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module RSpec
5
+ # Utility methods
6
+ module Util
7
+ # Error raised by `Util.one` if size is less than zero or greater than one
8
+ SizeError = Class.new(IndexError)
9
+
10
+ # Return only element in array if it contains exactly one member
11
+ def one(array)
12
+ return array.first if array.one?
13
+
14
+ raise SizeError,
15
+ "expected size to be exactly 1 but size was #{array.size}"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,11 +1,10 @@
1
- # encoding: utf-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module RuboCop
5
4
  module RSpec
6
5
  # Version information for the RSpec RuboCop plugin.
7
6
  module Version
8
- STRING = '1.5.1'.freeze
7
+ STRING = '1.5.2'.freeze
9
8
  end
10
9
  end
11
10
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module RSpec
5
+ # RSpec example wording rewriter
6
+ class Wording
7
+ def initialize(text, ignore:, replace:)
8
+ @text = text
9
+ @ignores = ignore
10
+ @replacements = replace
11
+ end
12
+
13
+ def rewrite
14
+ text.split.tap do |words|
15
+ first_word = words.shift
16
+ words.unshift('not') if first_word.eql?("shouldn't")
17
+
18
+ words.each_with_index do |value, key|
19
+ next if ignores.include?(value)
20
+ words[key] = simple_present(words.fetch(key))
21
+ break
22
+ end
23
+ end.join(' ')
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :text, :ignores, :replacements
29
+
30
+ def simple_present(word)
31
+ return replacements.fetch(word) if replacements.key?(word)
32
+
33
+ # ends with o s x ch sh or ss
34
+ if %w(o s x ch sh).any?(&word.public_method(:end_with?))
35
+ return "#{word}es"
36
+ end
37
+
38
+ # ends with y
39
+ if word.end_with?('y') && !%w(a u o e).include?(word[-2])
40
+ return "#{word[0..-2]}ies"
41
+ end
42
+
43
+ "#{word}s"
44
+ end
45
+ end
46
+ end
47
+ end
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
17
17
 
18
18
  spec.version = RuboCop::RSpec::Version::STRING
19
19
  spec.platform = Gem::Platform::RUBY
20
- spec.required_ruby_version = '>= 2.0.0'
20
+ spec.required_ruby_version = '>= 2.2.0'
21
21
 
22
22
  spec.require_paths = ['lib']
23
23
  spec.files = Dir[
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.test_files = spec.files.grep(%r{^spec/})
31
31
  spec.extra_rdoc_files = ['MIT-LICENSE.md', 'README.md']
32
32
 
33
- spec.add_runtime_dependency 'rubocop', '>= 0.41.2'
33
+ spec.add_runtime_dependency 'rubocop', '>= 0.42.0'
34
34
 
35
35
  spec.add_development_dependency 'rake'
36
36
  spec.add_development_dependency 'rspec', '>= 3.4'
data/spec/project_spec.rb CHANGED
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  describe 'RuboCop Project' do # rubocop:disable RSpec/DescribeClass
4
2
  describe 'default configuration file' do
5
3
  let(:cop_names) do
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  describe RuboCop::Cop::RSpec::AnyInstance do
4
2
  subject(:cop) { described_class.new }
5
3
 
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  describe RuboCop::Cop::RSpec::DescribeClass do
4
2
  subject(:cop) { described_class.new }
5
3
 
@@ -11,6 +9,11 @@ describe RuboCop::Cop::RSpec::DescribeClass do
11
9
  'the class or module being tested.'])
12
10
  end
13
11
 
12
+ it 'supports RSpec.describe' do
13
+ inspect_source(cop, 'RSpec.describe Foo do; end')
14
+ expect(cop.offenses).to be_empty
15
+ end
16
+
14
17
  it 'checks describe statements after a require' do
15
18
  inspect_source(
16
19
  cop,
@@ -25,6 +28,11 @@ describe RuboCop::Cop::RSpec::DescribeClass do
25
28
  'the class or module being tested.'])
26
29
  end
27
30
 
31
+ it 'checks highlights the first argument of a describe' do
32
+ inspect_source(cop, 'describe "bad describe", "blah blah" do; end')
33
+ expect(cop.offenses.first.location.column_range).to eq(9...23)
34
+ end
35
+
28
36
  it 'ignores nested describe statements' do
29
37
  inspect_source(
30
38
  cop,
@@ -47,6 +55,27 @@ describe RuboCop::Cop::RSpec::DescribeClass do
47
55
  expect(cop.offenses).to be_empty
48
56
  end
49
57
 
58
+ it 'ignores feature specs when RSpec.describe is used' do
59
+ inspect_source(
60
+ cop,
61
+ "RSpec.describe 'my new feature', type: :feature do; end"
62
+ )
63
+
64
+ expect(cop.offenses).to be_empty
65
+ end
66
+
67
+ it 'flags specs with non :type metadata' do
68
+ inspect_source(cop, "describe 'my new feature', foo: :feature do; end")
69
+ expect(cop.messages).to eq(['The first argument to describe should be ' \
70
+ 'the class or module being tested.'])
71
+ end
72
+
73
+ it 'flags normal metadata in describe' do
74
+ inspect_source(cop, "describe 'my new feature', blah, type: :wow do; end")
75
+ expect(cop.messages).to eq(['The first argument to describe should be ' \
76
+ 'the class or module being tested.'])
77
+ end
78
+
50
79
  it 'ignores feature specs - also with complex options' do
51
80
  inspect_source(
52
81
  cop,
@@ -59,6 +88,11 @@ describe RuboCop::Cop::RSpec::DescribeClass do
59
88
  expect(cop.offenses).to be_empty
60
89
  end
61
90
 
91
+ it 'ignores an empty describe' do
92
+ inspect_source(cop, 'describe do; end')
93
+ expect(cop.offenses).to be_empty
94
+ end
95
+
62
96
  it 'ignores routing specs' do
63
97
  inspect_source(cop, "describe 'my new route', type: :routing do; end")
64
98
  expect(cop.offenses).to be_empty
@@ -1,10 +1,17 @@
1
- # encoding: utf-8
2
-
3
1
  describe RuboCop::Cop::RSpec::DescribeMethod do
4
2
  subject(:cop) { described_class.new }
5
3
 
4
+ it 'ignores describes with only a class' do
5
+ inspect_source(cop, 'describe Some::Class do; end')
6
+ expect(cop.offenses.empty?).to be(true)
7
+ end
8
+
6
9
  it 'enforces non-method names' do
7
- inspect_source(cop, "describe Some::Class, 'nope' do; end")
10
+ inspect_source(
11
+ cop,
12
+ "describe Some::Class, 'nope', '.incorrect_usage' do; end"
13
+ )
14
+
8
15
  expect(cop.offenses.size).to eq(1)
9
16
  expect(cop.offenses.map(&:line).sort).to eq([1])
10
17
  expect(cop.messages)
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  describe RuboCop::Cop::RSpec::DescribedClass do
4
2
  subject(:cop) { described_class.new }
5
3
 
@@ -125,6 +123,38 @@ describe RuboCop::Cop::RSpec::DescribedClass do
125
123
  expect(cop.highlights).to eq(['MyNamespace::MyClass'])
126
124
  end
127
125
 
126
+ it 'does not flag violations within a scope change' do
127
+ inspect_source(
128
+ cop,
129
+ [
130
+ 'describe MyNamespace::MyClass do',
131
+ ' before do',
132
+ ' class Foo',
133
+ ' thing = MyNamespace::MyClass.new',
134
+ ' end',
135
+ ' end',
136
+ 'end'
137
+ ]
138
+ )
139
+
140
+ expect(cop.offenses).to be_empty
141
+ end
142
+
143
+ it 'does not flag violations within a scope change' do
144
+ inspect_source(
145
+ cop,
146
+ [
147
+ 'describe do',
148
+ ' before do',
149
+ ' MyNamespace::MyClass.new',
150
+ ' end',
151
+ 'end'
152
+ ]
153
+ )
154
+
155
+ expect(cop.offenses).to be_empty
156
+ end
157
+
128
158
  it 'checks for the use of described class with module' do
129
159
  skip
130
160
  inspect_source(
@@ -1,9 +1,23 @@
1
- # encoding: utf-8
2
-
3
1
  describe RuboCop::Cop::RSpec::ExampleLength, :config do
4
2
  subject(:cop) { described_class.new(config) }
5
3
  let(:cop_config) { { 'Max' => 3 } }
6
4
 
5
+ it 'ignores non-spec blocks' do
6
+ inspect_source(
7
+ cop,
8
+ [
9
+ 'foo do',
10
+ ' line 1',
11
+ ' line 2',
12
+ ' line 3',
13
+ ' line 4',
14
+ 'end'
15
+ ]
16
+ )
17
+
18
+ expect(cop.offenses).to be_empty
19
+ end
20
+
7
21
  it 'allows an empty example' do
8
22
  inspect_source(
9
23
  cop,
@@ -29,7 +43,7 @@ describe RuboCop::Cop::RSpec::ExampleLength, :config do
29
43
  expect(cop.offenses).to be_empty
30
44
  end
31
45
 
32
- it 'doesn\t allow a long example' do
46
+ it "doesn't allow a long example" do
33
47
  inspect_source(
34
48
  cop,
35
49
  [
@@ -1,74 +1,73 @@
1
- # encoding: utf-8
2
-
3
1
  describe RuboCop::Cop::RSpec::ExampleWording, :config do
4
2
  subject(:cop) { described_class.new(config) }
5
- let(:cop_config) do
6
- {
7
- 'CustomTransform' => { 'have' => 'has', 'not' => 'does not' },
8
- 'IgnoredWords' => %w(only really)
9
- }
10
- end
11
3
 
12
- it 'finds description with `should` at the beginning' do
13
- inspect_source(cop, ["it 'should do something' do", 'end'])
14
- expect(cop.offenses.size).to eq(1)
15
- expect(cop.offenses.map(&:line).sort).to eq([1])
16
- expect(cop.messages)
17
- .to eq(['Do not use should when describing your tests.'])
18
- expect(cop.highlights).to eq(['should do something'])
19
- end
4
+ context 'with configuration' do
5
+ let(:cop_config) do
6
+ {
7
+ 'CustomTransform' => { 'have' => 'has', 'not' => 'does not' },
8
+ 'IgnoredWords' => %w(only really)
9
+ }
10
+ end
20
11
 
21
- it 'finds description with `Should` at the beginning' do
22
- inspect_source(cop, ["it 'Should do something' do", 'end'])
23
- expect(cop.offenses.size).to eq(1)
24
- expect(cop.offenses.map(&:line).sort).to eq([1])
25
- expect(cop.messages)
26
- .to eq(['Do not use should when describing your tests.'])
27
- expect(cop.highlights).to eq(['Should do something'])
28
- end
12
+ it 'ignores non-example blocks' do
13
+ inspect_source(cop, 'foo "should do something" do; end')
14
+ expect(cop.offenses).to be_empty
15
+ end
29
16
 
30
- it 'finds description with `shouldn\'t` at the beginning' do
31
- inspect_source(cop, ['it "shouldn\'t do something" do', 'end'])
32
- expect(cop.offenses.size).to eq(1)
33
- expect(cop.offenses.map(&:line).sort).to eq([1])
34
- expect(cop.messages)
35
- .to eq(['Do not use should when describing your tests.'])
36
- expect(cop.highlights).to eq(['shouldn\'t do something'])
37
- end
17
+ it 'finds description with `should` at the beginning' do
18
+ inspect_source(cop, ["it 'should do something' do", 'end'])
19
+ expect(cop.offenses.size).to eq(1)
20
+ expect(cop.offenses.map(&:line).sort).to eq([1])
21
+ expect(cop.messages)
22
+ .to eq(['Do not use should when describing your tests.'])
23
+ expect(cop.highlights).to eq(['should do something'])
24
+ end
38
25
 
39
- it 'skips descriptions without `should` at the beginning' do
40
- inspect_source(
41
- cop,
42
- [
43
- "it 'finds no should ' \\",
44
- " 'here' do",
45
- 'end'
46
- ]
47
- )
48
- expect(cop.offenses).to be_empty
49
- end
26
+ it 'finds description with `Should` at the beginning' do
27
+ inspect_source(cop, ["it 'Should do something' do", 'end'])
28
+ expect(cop.offenses.size).to eq(1)
29
+ expect(cop.offenses.map(&:line).sort).to eq([1])
30
+ expect(cop.messages)
31
+ .to eq(['Do not use should when describing your tests.'])
32
+ expect(cop.highlights).to eq(['Should do something'])
33
+ end
34
+
35
+ it 'finds description with `shouldn\'t` at the beginning' do
36
+ inspect_source(cop, ['it "shouldn\'t do something" do', 'end'])
37
+ expect(cop.offenses.size).to eq(1)
38
+ expect(cop.offenses.map(&:line).sort).to eq([1])
39
+ expect(cop.messages)
40
+ .to eq(['Do not use should when describing your tests.'])
41
+ expect(cop.highlights).to eq(['shouldn\'t do something'])
42
+ end
43
+
44
+ it 'skips descriptions without `should` at the beginning' do
45
+ inspect_source(
46
+ cop,
47
+ [
48
+ "it 'finds no should ' \\",
49
+ " 'here' do",
50
+ 'end'
51
+ ]
52
+ )
53
+ expect(cop.offenses).to be_empty
54
+ end
50
55
 
51
- {
52
- 'should return something' => 'returns something',
53
- 'should not return something' => 'does not return something',
54
- 'should do nothing' => 'does nothing',
55
- 'should have sweets' => 'has sweets',
56
- 'should worry about the future' => 'worries about the future',
57
- 'should pay for pizza' => 'pays for pizza',
58
- 'should miss me' => 'misses me',
59
- 'should really only return one item' => 'really only returns one item'
60
- }.each do |old, new|
61
- it 'autocorrects an offenses' do
62
- new_source = autocorrect_source(cop, ["it '#{old}' do", 'end'])
63
- expect(new_source).to eq("it '#{new}' do\nend")
56
+ it 'corrects `it "should only have"` to it "only has"' do
57
+ corrected = autocorrect_source(cop, 'it "should only have trait" do end')
58
+ expect(corrected).to eql('it "only has trait" do end')
64
59
  end
65
60
  end
66
61
 
67
- it "autocorrects shouldn't" do
68
- new_source = autocorrect_source(
69
- cop,
70
- 'it "shouldn\'t return something" do; end'
71
- )
72
- expect(new_source).to eq('it "does not return something" do; end')
62
+ context 'when configuration is empty' do
63
+ it 'only does not correct "have"' do
64
+ corrected = autocorrect_source(cop, 'it "should have trait" do end')
65
+ expect(corrected).to eql('it "haves trait" do end')
66
+ end
67
+
68
+ it 'only does not make an exception for the word "only"' do
69
+ corrected = autocorrect_source(cop, 'it "should only fail" do end')
70
+ expect(corrected).to eql('it "onlies fail" do end')
71
+ end
73
72
  end
74
73
  end