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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/Gemfile +0 -2
- data/README.md +0 -8
- data/Rakefile +1 -3
- data/lib/rubocop-rspec.rb +2 -2
- data/lib/rubocop/cop/rspec/any_instance.rb +1 -10
- data/lib/rubocop/cop/rspec/describe_class.rb +23 -15
- data/lib/rubocop/cop/rspec/describe_method.rb +4 -6
- data/lib/rubocop/cop/rspec/described_class.rb +5 -8
- data/lib/rubocop/cop/rspec/example_length.rb +4 -9
- data/lib/rubocop/cop/rspec/example_wording.rb +13 -37
- data/lib/rubocop/cop/rspec/file_path.rb +10 -13
- data/lib/rubocop/cop/rspec/focus.rb +48 -30
- data/lib/rubocop/cop/rspec/instance_variable.rb +0 -1
- data/lib/rubocop/cop/rspec/multiple_describes.rb +2 -3
- data/lib/rubocop/cop/rspec/not_to_not.rb +3 -5
- data/lib/rubocop/cop/rspec/verified_doubles.rb +7 -15
- data/lib/rubocop/rspec/inject.rb +0 -1
- data/lib/rubocop/rspec/top_level_describe.rb +0 -2
- data/lib/rubocop/rspec/util.rb +19 -0
- data/lib/rubocop/rspec/version.rb +1 -2
- data/lib/rubocop/rspec/wording.rb +47 -0
- data/rubocop-rspec.gemspec +2 -2
- data/spec/project_spec.rb +0 -2
- data/spec/rubocop/cop/rspec/any_instance_spec.rb +0 -2
- data/spec/rubocop/cop/rspec/describe_class_spec.rb +36 -2
- data/spec/rubocop/cop/rspec/describe_method_spec.rb +10 -3
- data/spec/rubocop/cop/rspec/described_class_spec.rb +32 -2
- data/spec/rubocop/cop/rspec/example_length_spec.rb +17 -3
- data/spec/rubocop/cop/rspec/example_wording_spec.rb +61 -62
- data/spec/rubocop/cop/rspec/file_path_spec.rb +61 -21
- data/spec/rubocop/cop/rspec/focus_spec.rb +11 -3
- data/spec/rubocop/cop/rspec/instance_variable_spec.rb +13 -2
- data/spec/rubocop/cop/rspec/multiple_describes_spec.rb +0 -2
- data/spec/rubocop/cop/rspec/not_to_not_spec.rb +0 -2
- data/spec/rubocop/cop/rspec/verified_doubles_spec.rb +41 -19
- data/spec/rubocop/rspec/util/one_spec.rb +21 -0
- data/spec/rubocop/rspec/wording_spec.rb +44 -0
- data/spec/spec_helper.rb +1 -9
- metadata +11 -5
@@ -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
|
31
|
+
return unless top_level_nodes.first.equal?(node)
|
33
32
|
|
34
|
-
add_offense(node, :expression
|
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
|
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
|
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
|
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
|
-
|
25
|
-
|
26
|
-
|
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
|
-
|
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
|
-
|
38
|
-
name.children.first.is_a? Symbol
|
30
|
+
add_offense(node, :expression)
|
39
31
|
end
|
40
32
|
end
|
41
33
|
end
|
data/lib/rubocop/rspec/inject.rb
CHANGED
@@ -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
|
@@ -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
|
data/rubocop-rspec.gemspec
CHANGED
@@ -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.
|
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.
|
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::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(
|
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 '
|
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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
40
|
-
|
41
|
-
cop
|
42
|
-
[
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
-
|
53
|
-
|
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
|
-
|
68
|
-
|
69
|
-
cop,
|
70
|
-
'it "
|
71
|
-
|
72
|
-
|
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
|