rubocop-rspec 1.4.1 → 1.5.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.
- 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'])
|