rubocop-rspec 1.4.1 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -3
- data/README.md +1 -1
- data/config/default.yml +14 -2
- data/lib/rubocop-rspec.rb +2 -0
- data/lib/rubocop/cop/rspec/any_instance.rb +8 -5
- data/lib/rubocop/cop/rspec/describe_class.rb +2 -1
- data/lib/rubocop/cop/rspec/example_length.rb +60 -0
- data/lib/rubocop/cop/rspec/file_path.rb +13 -3
- data/lib/rubocop/cop/rspec/focus.rb +67 -0
- data/lib/rubocop/cop/rspec/not_to_not.rb +21 -20
- data/lib/rubocop/cop/rspec/verified_doubles.rb +12 -2
- data/lib/rubocop/rspec/version.rb +1 -1
- data/rubocop-rspec.gemspec +1 -1
- data/spec/rubocop/cop/rspec/any_instance_spec.rb +24 -9
- data/spec/rubocop/cop/rspec/describe_class_spec.rb +28 -8
- data/spec/rubocop/cop/rspec/described_class_spec.rb +107 -53
- data/spec/rubocop/cop/rspec/example_length_spec.rb +83 -0
- data/spec/rubocop/cop/rspec/example_wording_spec.rb +12 -5
- data/spec/rubocop/cop/rspec/file_path_spec.rb +121 -61
- data/spec/rubocop/cop/rspec/focus_spec.rb +70 -0
- data/spec/rubocop/cop/rspec/instance_variable_spec.rb +18 -9
- data/spec/rubocop/cop/rspec/multiple_describes_spec.rb +22 -7
- data/spec/rubocop/cop/rspec/not_to_not_spec.rb +15 -5
- data/spec/rubocop/cop/rspec/verified_doubles_spec.rb +41 -3
- metadata +12 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f7a58ee16af46402f371a3a3be9ae83752a7555
|
4
|
+
data.tar.gz: 15ecddf6c683fe294fb914faeadd45eabbbabba6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca7b87e0e9210d37795f29ebba6b5398c5e5583b9b68e3a1519c4f9208d18228d99378fba6114a6381c8bf579bf21cf755a3b9ef438765065965b381d9a1e3ca
|
7
|
+
data.tar.gz: f515ccc02aace366c6ec987aaf258450d8d7f0d2e740382d303a4480633b031de8150ca198369b2059c5856cb94d121afe7161bb10dfe1e70f7bdc1a60ed6f5d
|
data/CHANGELOG.md
CHANGED
@@ -2,13 +2,26 @@
|
|
2
2
|
|
3
3
|
## master (unreleased)
|
4
4
|
|
5
|
-
## 1.
|
5
|
+
## 1.5.0 (2016-05-17)
|
6
|
+
|
7
|
+
* Expand `VerifiedDoubles` cop to check for `spy` as well as `double`. ([@andyw8][])
|
8
|
+
* Enable `VerifiedDoubles` cop by default. ([@andyw8][])
|
9
|
+
* Add `IgnoreSymbolicNames` option for `VerifiedDoubles` cop. ([@andyw8][])
|
10
|
+
* Add `RSpec::ExampleLength` cop. ([@andyw8][])
|
11
|
+
* Handle alphanumeric class names in `FilePath` cop. ([@andyw8][])
|
12
|
+
* Skip `DescribeClass` cop for view specs. ([@andyw8][])
|
13
|
+
* Skip `FilePath` cop for Rails routing specs. ([@andyw8][])
|
14
|
+
* Add cop to check for focused specs. ([@renanborgescampos][], [@jaredmoody][])
|
15
|
+
* Clean-up `RSpec::NotToNot` to use same configuration semantics as other Rubocop cops, add autocorrect support for `RSpec::NotToNot`. ([@baberthal][])
|
16
|
+
* Update to rubocop 0.40.0. ([@nijikon][])
|
17
|
+
|
18
|
+
## 1.4.1 (2016-04-03)
|
6
19
|
|
7
20
|
* Ignore routing specs for DescribeClass cop. ([@nijikon][])
|
8
21
|
* Move rubocop dependency to runtime. ([@nijikon][])
|
9
22
|
* Update to rubocop 0.39.0. ([@nijikon][])
|
10
23
|
|
11
|
-
## 1.4.0 (15
|
24
|
+
## 1.4.0 (2016-02-15)
|
12
25
|
|
13
26
|
* Update to rubocop 0.37.2. ([@nijikon][])
|
14
27
|
* Update ruby versions we test against. ([@nijikon][])
|
@@ -73,7 +86,7 @@
|
|
73
86
|
|
74
87
|
<!-- Contributors -->
|
75
88
|
|
76
|
-
[@andyw8]: https://github.com/
|
89
|
+
[@andyw8]: https://github.com/andyw8
|
77
90
|
[@bquorning]: https://github.com/bquorning
|
78
91
|
[@deivid-rodriguez]: https://github.com/deivid-rodriguez
|
79
92
|
[@geniou]: https://github.com/geniou
|
@@ -83,3 +96,6 @@
|
|
83
96
|
[@pstengel]: https://github.com/pstengel
|
84
97
|
[@miguelfteixeira]: https://github.com/miguelfteixeira
|
85
98
|
[@mlarraz]: https://github.com/mlarraz
|
99
|
+
[@renanborgescampos]: https://github.com/renanborgescampos
|
100
|
+
[@jaredmoody]: https://github.com/jaredmoody
|
101
|
+
[@baberthal]: https://github.com/baberthal
|
data/README.md
CHANGED
data/config/default.yml
CHANGED
@@ -41,9 +41,21 @@ RSpec/FilePath:
|
|
41
41
|
|
42
42
|
RSpec/VerifiedDoubles:
|
43
43
|
Description: 'Prefer using verifying doubles over normal doubles.'
|
44
|
-
Enabled:
|
44
|
+
Enabled: true
|
45
45
|
|
46
46
|
RSpec/NotToNot:
|
47
47
|
Description: 'Enforces the usage of the same method on all negative message expectations.'
|
48
|
+
EnforcedStyle: not_to
|
49
|
+
SupportedStyles:
|
50
|
+
- not_to
|
51
|
+
- to_not
|
52
|
+
Enabled: true
|
53
|
+
|
54
|
+
RSpec/Focus:
|
55
|
+
Description: 'Checks if there are focused specs.'
|
56
|
+
Enabled: true
|
57
|
+
|
58
|
+
RSpec/ExampleLength:
|
59
|
+
Description: 'Checks for long example'
|
48
60
|
Enabled: true
|
49
|
-
|
61
|
+
Max: 5
|
data/lib/rubocop-rspec.rb
CHANGED
@@ -15,7 +15,9 @@ require 'rubocop/cop/rspec/describe_method'
|
|
15
15
|
require 'rubocop/cop/rspec/described_class'
|
16
16
|
require 'rubocop/cop/rspec/example_wording'
|
17
17
|
require 'rubocop/cop/rspec/file_path'
|
18
|
+
require 'rubocop/cop/rspec/focus'
|
18
19
|
require 'rubocop/cop/rspec/instance_variable'
|
20
|
+
require 'rubocop/cop/rspec/example_length'
|
19
21
|
require 'rubocop/cop/rspec/multiple_describes'
|
20
22
|
require 'rubocop/cop/rspec/not_to_not'
|
21
23
|
require 'rubocop/cop/rspec/verified_doubles'
|
@@ -33,11 +33,14 @@ module RuboCop
|
|
33
33
|
_receiver, method_name, *_args = *node
|
34
34
|
return unless ANY_INSTANCE_METHODS.include?(method_name)
|
35
35
|
|
36
|
-
add_offense(
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
36
|
+
add_offense(
|
37
|
+
node,
|
38
|
+
:expression,
|
39
|
+
format(
|
40
|
+
MESSAGE % { method: method_name },
|
41
|
+
node.loc.expression.source
|
42
|
+
)
|
43
|
+
)
|
41
44
|
end
|
42
45
|
end
|
43
46
|
end
|
@@ -24,6 +24,7 @@ module RuboCop
|
|
24
24
|
REQUEST_PAIR = s(:pair, s(:sym, :type), s(:sym, :request))
|
25
25
|
FEATURE_PAIR = s(:pair, s(:sym, :type), s(:sym, :feature))
|
26
26
|
ROUTING_PAIR = s(:pair, s(:sym, :type), s(:sym, :routing))
|
27
|
+
VIEW_PAIR = s(:pair, s(:sym, :type), s(:sym, :view))
|
27
28
|
|
28
29
|
MESSAGE = 'The first argument to describe should be the class or ' \
|
29
30
|
'module being tested.'.freeze
|
@@ -34,7 +35,7 @@ module RuboCop
|
|
34
35
|
return if args[1..-1].any? do |arg|
|
35
36
|
next unless arg.hash_type?
|
36
37
|
arg.children.any? do |n|
|
37
|
-
[REQUEST_PAIR, FEATURE_PAIR, ROUTING_PAIR].include?(n)
|
38
|
+
[REQUEST_PAIR, FEATURE_PAIR, ROUTING_PAIR, VIEW_PAIR].include?(n)
|
38
39
|
end
|
39
40
|
end
|
40
41
|
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RuboCop
|
5
|
+
module Cop
|
6
|
+
module RSpec
|
7
|
+
# A long example is usually more difficult to understand. Consider
|
8
|
+
# extracting out some behaviour, e.g. with a `let` block, or a helper
|
9
|
+
# method.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# # bad
|
13
|
+
# it do
|
14
|
+
# service = described_class.new
|
15
|
+
# more_setup
|
16
|
+
# more_setup
|
17
|
+
# result = service.call
|
18
|
+
# expect(result).to be(true)
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# # good
|
22
|
+
# it do
|
23
|
+
# service = described_class.new
|
24
|
+
# result = service.call
|
25
|
+
# expect(result).to be(true)
|
26
|
+
# end
|
27
|
+
class ExampleLength < Cop
|
28
|
+
include CodeLength
|
29
|
+
EXAMPLE_BLOCKS = [:it, :specify].freeze
|
30
|
+
|
31
|
+
def on_block(node)
|
32
|
+
method, _args, _body = *node
|
33
|
+
_receiver, method_name, _object = *method
|
34
|
+
return unless EXAMPLE_BLOCKS.include?(method_name)
|
35
|
+
|
36
|
+
length = code_length(node)
|
37
|
+
|
38
|
+
return unless length > max
|
39
|
+
add_offense(node, :expression, message(length, max))
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def max
|
45
|
+
cop_config['Max']
|
46
|
+
end
|
47
|
+
|
48
|
+
def code_length(node)
|
49
|
+
lines = node.source.lines.to_a[1..-2] || []
|
50
|
+
|
51
|
+
lines.count { |line| !irrelevant_line(line) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def message(length, max_length)
|
55
|
+
format('Example has too many lines. [%d/%d]', length, max_length)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -7,8 +7,8 @@ module RuboCop
|
|
7
7
|
# Checks the path of the spec file and enforces that it reflects the
|
8
8
|
# described class/module and its optionally called out method.
|
9
9
|
#
|
10
|
-
# With the configuration option `CustomTransform` modules or
|
11
|
-
# specified that should not as usual be transformed from CamelCase to
|
10
|
+
# With the configuration option `CustomTransform` modules or classes can
|
11
|
+
# be specified that should not as usual be transformed from CamelCase to
|
12
12
|
# snake_case (e.g. 'RuboCop' => 'rubocop' ).
|
13
13
|
#
|
14
14
|
# @example
|
@@ -20,8 +20,11 @@ module RuboCop
|
|
20
20
|
|
21
21
|
MESSAGE = 'Spec path should end with `%s`'.freeze
|
22
22
|
METHOD_STRING_MATCHER = /^[\#\.].+/
|
23
|
+
ROUTING_PAIR = s(:pair, s(:sym, :type), s(:sym, :routing))
|
23
24
|
|
24
25
|
def on_top_level_describe(node, args)
|
26
|
+
return if routing_spec?(args)
|
27
|
+
|
25
28
|
return unless single_top_level_describe?
|
26
29
|
object = args.first.const_name
|
27
30
|
return unless object
|
@@ -34,6 +37,13 @@ module RuboCop
|
|
34
37
|
|
35
38
|
private
|
36
39
|
|
40
|
+
def routing_spec?(args)
|
41
|
+
args[1..-1].any? do |arg|
|
42
|
+
next unless arg.hash_type?
|
43
|
+
arg.children.include?(ROUTING_PAIR)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
37
47
|
def matcher(object, method)
|
38
48
|
path = File.join(parts(object))
|
39
49
|
if method && method.type == :str
|
@@ -56,7 +66,7 @@ module RuboCop
|
|
56
66
|
def camel_to_underscore(string)
|
57
67
|
string.dup.tap do |result|
|
58
68
|
result.gsub!(/([^A-Z])([A-Z]+)/, '\\1_\\2')
|
59
|
-
result.gsub!(/([A-Z])([A-Z][^A-Z]+)/, '\\1_\\2')
|
69
|
+
result.gsub!(/([A-Z])([A-Z\d][^A-Z\d]+)/, '\\1_\\2')
|
60
70
|
result.downcase!
|
61
71
|
end
|
62
72
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RuboCop
|
5
|
+
module Cop
|
6
|
+
module RSpec
|
7
|
+
# Checks if test is focused.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# describe MyClass, focus: true do
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# describe MyClass, :focus do
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# fdescribe MyClass do
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# describe MyClass do
|
22
|
+
# end
|
23
|
+
class Focus < Cop
|
24
|
+
MESSAGE = 'Focused spec found.'.freeze
|
25
|
+
|
26
|
+
FOCUSABLE_BLOCKS = [
|
27
|
+
:example_group, :describe, :context, :xdescribe, :xcontext,
|
28
|
+
:it, :example, :specify, :xit, :xexample, :xspecify,
|
29
|
+
:feature, :scenario, :xfeature, :xscenario
|
30
|
+
].freeze
|
31
|
+
|
32
|
+
FOCUSED_BLOCKS = [
|
33
|
+
:fdescribe, :fcontext,
|
34
|
+
:focus, :fexample, :fit, :fspecify,
|
35
|
+
:ffeature, :fscenario
|
36
|
+
].freeze
|
37
|
+
|
38
|
+
FOCUS_KEY = s(:sym, :focus)
|
39
|
+
|
40
|
+
FOCUS_TRUE_PAIR = s(:pair, FOCUS_KEY, s(:true))
|
41
|
+
|
42
|
+
def on_send(node)
|
43
|
+
_receiver, method_name, *_args = *node
|
44
|
+
@focusable_block = FOCUSABLE_BLOCKS.include?(method_name)
|
45
|
+
if FOCUSED_BLOCKS.include?(method_name)
|
46
|
+
add_offense(node, :expression, MESSAGE)
|
47
|
+
end
|
48
|
+
|
49
|
+
# check for :focus
|
50
|
+
return unless @focusable_block
|
51
|
+
node.children.any? do |n|
|
52
|
+
add_offense(n, :expression, MESSAGE) if n == FOCUS_KEY
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def on_hash(node)
|
57
|
+
return unless @focusable_block
|
58
|
+
return if node.children.any? do |n|
|
59
|
+
if [FOCUS_TRUE_PAIR].include?(n)
|
60
|
+
add_offense(n, :expression, MESSAGE)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -17,36 +17,37 @@ module RuboCop
|
|
17
17
|
# expect(false).not_to be_true
|
18
18
|
# end
|
19
19
|
class NotToNot < Cop
|
20
|
-
|
20
|
+
include RuboCop::Cop::ConfigurableEnforcedStyle
|
21
|
+
|
22
|
+
MSG = 'Prefer `%s` over `%s`'.freeze
|
23
|
+
|
24
|
+
METHOD_NAMES = [:not_to, :to_not].freeze
|
21
25
|
|
22
26
|
def on_send(node)
|
23
27
|
_receiver, method_name, *_args = *node
|
24
28
|
|
25
|
-
|
26
|
-
add_offense(node, :expression, offense_message)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
29
|
+
return unless METHOD_NAMES.include?(method_name)
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
return if style == method_name
|
32
|
+
add_offense(node, :expression)
|
33
|
+
end
|
35
34
|
|
36
|
-
|
37
|
-
|
38
|
-
end
|
35
|
+
def message(node)
|
36
|
+
_receiver, method_name, *_args = *node
|
39
37
|
|
40
|
-
|
38
|
+
if method_name == :not_to
|
39
|
+
format(MSG, 'to_not', 'not_to')
|
40
|
+
else
|
41
|
+
format(MSG, 'not_to', 'to_not')
|
41
42
|
end
|
42
43
|
end
|
43
44
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
45
|
+
def autocorrect(node)
|
46
|
+
_receiver, method_name, *_args = *node
|
47
|
+
lambda do |corrector|
|
48
|
+
corrector.replace(node.loc.selector,
|
49
|
+
method_name == :not_to ? 'to_not' : 'not_to')
|
50
|
+
end
|
50
51
|
end
|
51
52
|
end
|
52
53
|
end
|
@@ -19,14 +19,24 @@ module RuboCop
|
|
19
19
|
# end
|
20
20
|
class VerifiedDoubles < Cop
|
21
21
|
MSG = 'Prefer using verifying doubles over normal doubles.'.freeze
|
22
|
+
DOUBLE_TYPES = [:double, :spy].freeze
|
22
23
|
|
23
24
|
def on_send(node)
|
24
|
-
_receiver, method_name, *
|
25
|
-
|
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']
|
26
30
|
add_offense(node,
|
27
31
|
:expression,
|
28
32
|
format(MSG, node.loc.expression.source))
|
29
33
|
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def name_is_symbol?(name)
|
38
|
+
name.children.first.is_a? Symbol
|
39
|
+
end
|
30
40
|
end
|
31
41
|
end
|
32
42
|
end
|
data/rubocop-rspec.gemspec
CHANGED
@@ -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.40.0'
|
34
34
|
|
35
35
|
spec.add_development_dependency 'rake'
|
36
36
|
spec.add_development_dependency 'rspec', '>= 3.4'
|
@@ -4,9 +4,14 @@ describe RuboCop::Cop::RSpec::AnyInstance do
|
|
4
4
|
subject(:cop) { described_class.new }
|
5
5
|
|
6
6
|
it 'finds `allow_any_instance_of` instead of an instance double' do
|
7
|
-
inspect_source(
|
8
|
-
|
9
|
-
|
7
|
+
inspect_source(
|
8
|
+
cop,
|
9
|
+
[
|
10
|
+
'before do',
|
11
|
+
' allow_any_instance_of(Object).to receive(:foo)',
|
12
|
+
'end'
|
13
|
+
]
|
14
|
+
)
|
10
15
|
expect(cop.messages)
|
11
16
|
.to eq(['Avoid stubbing using `allow_any_instance_of`'])
|
12
17
|
expect(cop.highlights).to eq(['allow_any_instance_of(Object)'])
|
@@ -14,9 +19,14 @@ describe RuboCop::Cop::RSpec::AnyInstance do
|
|
14
19
|
end
|
15
20
|
|
16
21
|
it 'finds `expect_any_instance_of` instead of an instance double' do
|
17
|
-
inspect_source(
|
18
|
-
|
19
|
-
|
22
|
+
inspect_source(
|
23
|
+
cop,
|
24
|
+
[
|
25
|
+
'before do',
|
26
|
+
' expect_any_instance_of(Object).to receive(:foo)',
|
27
|
+
'end'
|
28
|
+
]
|
29
|
+
)
|
20
30
|
expect(cop.messages)
|
21
31
|
.to eq(['Avoid stubbing using `expect_any_instance_of`'])
|
22
32
|
expect(cop.highlights).to eq(['expect_any_instance_of(Object)'])
|
@@ -24,9 +34,14 @@ describe RuboCop::Cop::RSpec::AnyInstance do
|
|
24
34
|
end
|
25
35
|
|
26
36
|
it 'finds old `any_instance` syntax instead of an instance double' do
|
27
|
-
inspect_source(
|
28
|
-
|
29
|
-
|
37
|
+
inspect_source(
|
38
|
+
cop,
|
39
|
+
[
|
40
|
+
'before do',
|
41
|
+
' Object.any_instance.should_receive(:foo)',
|
42
|
+
'end'
|
43
|
+
]
|
44
|
+
)
|
30
45
|
expect(cop.messages)
|
31
46
|
.to eq(['Avoid stubbing using `any_instance`'])
|
32
47
|
expect(cop.highlights).to eq(['Object.any_instance'])
|