rubocop-rspec 1.5.1 → 1.5.2

Sign up to get free protection for your applications and to get access to all the features.
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