rubocop-rspec 0.18.1 → 1.0.rc1

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.
@@ -0,0 +1,59 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module RSpec
5
+ # Helper methods for top level describe cops
6
+ module TopLevelDescribe
7
+ def on_send(node)
8
+ return unless respond_to?(:on_top_level_describe)
9
+ return unless top_level_describe?(node)
10
+
11
+ _receiver, _method_name, *args = *node
12
+ # Ignore non-string args (RSpec metadata)
13
+ args = [args.first] + args[1..-1].select { |a| a.type == :str }
14
+
15
+ on_top_level_describe(node, args)
16
+ end
17
+
18
+ private
19
+
20
+ def top_level_describe?(node)
21
+ _receiver, method_name, *_args = *node
22
+ return false unless method_name == :describe
23
+
24
+ top_level_nodes.include?(node)
25
+ end
26
+
27
+ def top_level_nodes
28
+ nodes = describe_statement_children(root_node)
29
+ # If we have no top level describe statements, we need to check any
30
+ # blocks on the top level (e.g. after a require).
31
+ if nodes.size == 0
32
+ nodes = node_children(root_node).map do |child|
33
+ describe_statement_children(child) if child.type == :block
34
+ end.flatten.compact
35
+ end
36
+
37
+ nodes
38
+ end
39
+
40
+ def root_node
41
+ processed_source.ast
42
+ end
43
+
44
+ def single_top_level_describe?
45
+ top_level_nodes.count == 1
46
+ end
47
+
48
+ def describe_statement_children(node)
49
+ node_children(node).select do |element|
50
+ element.type == :send && element.children[1] == :describe
51
+ end
52
+ end
53
+
54
+ def node_children(node)
55
+ node.children.select { |e| e.is_a? Parser::AST::Node }
56
+ end
57
+ end
58
+ end
59
+ end
@@ -4,7 +4,7 @@ module Rubocop
4
4
  module RSpec
5
5
  # Version information for the RSpec RuboCop plugin.
6
6
  module Version
7
- STRING = '0.18.1'
7
+ STRING = '1.0.rc1'
8
8
  end
9
9
  end
10
10
  end
Binary file
Binary file
@@ -11,8 +11,8 @@ Gem::Specification.new do |spec|
11
11
  A plugin for the RuboCop code style enforcing & linting tool.
12
12
  end_description
13
13
  spec.homepage = 'http://github.com/nevir/rubocop-rspec'
14
- spec.authors = ['Ian MacLeod']
15
- spec.email = ['ian@nevir.net']
14
+ spec.authors = ['Ian MacLeod', 'Nils Gemeinhardt']
15
+ spec.email = ['ian@nevir.net', 'git@nilsgemeinhardt.de']
16
16
  spec.licenses = ['MIT']
17
17
 
18
18
  spec.version = Rubocop::RSpec::Version::STRING
@@ -24,5 +24,5 @@ Gem::Specification.new do |spec|
24
24
  spec.test_files = spec.files.grep(/^spec\//)
25
25
  spec.extra_rdoc_files = ['MIT-LICENSE.md', 'README.md']
26
26
 
27
- spec.add_runtime_dependency('rubocop', '~> 0.18')
27
+ spec.add_runtime_dependency('rubocop', '~> 0.19', '>= 0.19')
28
28
  end
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Rubocop::Cop::RSpecDescribeClass do
6
+ subject(:cop) { described_class.new }
7
+
8
+ it 'checks first-line describe statements' do
9
+ inspect_source(cop, ['describe "bad describe" do; end'])
10
+ expect(cop.offenses.size).to eq(1)
11
+ expect(cop.offenses.map(&:line).sort).to eq([1])
12
+ expect(cop.messages).to eq(['The first argument to describe should be ' \
13
+ 'the class or module being tested.'])
14
+ end
15
+
16
+ it 'checks describe statements after a require' do
17
+ inspect_source(cop, ["require 'spec_helper'",
18
+ 'describe "bad describe" do; end'])
19
+ expect(cop.offenses.size).to eq(1)
20
+ expect(cop.offenses.map(&:line).sort).to eq([2])
21
+ expect(cop.messages).to eq(['The first argument to describe should be ' \
22
+ 'the class or module being tested.'])
23
+ end
24
+
25
+ it 'ignores nested describe statements' do
26
+ inspect_source(cop, ['describe Some::Class do',
27
+ ' describe "bad describe" do; end',
28
+ 'end'])
29
+ expect(cop.offenses).to be_empty
30
+ end
31
+
32
+ it "doesn't blow up on single-line describes" do
33
+ inspect_source(cop, ['describe Some::Class'])
34
+ expect(cop.offenses).to be_empty
35
+ end
36
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Rubocop::Cop::RSpecDescribeMethod do
6
+ subject(:cop) { described_class.new }
7
+
8
+ it 'enforces non-method names' do
9
+ inspect_source(cop, ["describe Some::Class, 'nope' do; end"])
10
+ expect(cop.offenses.size).to eq(1)
11
+ expect(cop.offenses.map(&:line).sort).to eq([1])
12
+ expect(cop.messages)
13
+ .to eq(['The second argument to describe should be the method being ' \
14
+ "tested. '#instance' or '.class'"])
15
+ end
16
+
17
+ it 'skips methods starting with a . or #' do
18
+ inspect_source(cop, ["describe Some::Class, '.asdf' do; end",
19
+ "describe Some::Class, '#fdsa' do; end"])
20
+ expect(cop.offenses).to be_empty
21
+ end
22
+ end
@@ -0,0 +1,113 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Rubocop::Cop::RSpecDescribedClass do
6
+ subject(:cop) { described_class.new }
7
+
8
+ it 'checks for the use of the described class' do
9
+ inspect_source(cop, ['describe MyClass do',
10
+ ' subject { MyClass.do_something }',
11
+ ' before { MyClass.do_something }',
12
+ 'end'])
13
+ expect(cop.offenses.size).to eq(2)
14
+ expect(cop.offenses.map(&:line).sort).to eq([2, 3])
15
+ expect(cop.messages)
16
+ .to eq(['Use `described_class` instead of `MyClass`'] * 2)
17
+ expect(cop.highlights).to eq(['MyClass'] * 2)
18
+ end
19
+
20
+ it 'ignores described class as string' do
21
+ inspect_source(cop, ['describe MyClass do',
22
+ ' subject { "MyClass" }',
23
+ 'end'])
24
+ expect(cop.offenses).to be_empty
25
+ end
26
+
27
+ it 'ignores describes that do not referece to a class' do
28
+ inspect_source(cop, ['describe "MyClass" do',
29
+ ' subject { "MyClass" }',
30
+ 'end'])
31
+ expect(cop.offenses).to be_empty
32
+ end
33
+
34
+ it 'ignores if the scope is changing' do
35
+ inspect_source(cop, ['describe MyClass do',
36
+ ' include MyClass',
37
+ 'end'])
38
+ expect(cop.offenses.size).to eq(1)
39
+ expect(cop.offenses.map(&:line).sort).to eq([2])
40
+ expect(cop.messages)
41
+ .to eq(['Use `described_class` instead of `MyClass`'])
42
+ expect(cop.highlights).to eq(['MyClass'])
43
+ end
44
+
45
+ it 'ignores class if the scope is changing' do
46
+ inspect_source(cop, ['describe MyClass do',
47
+ ' def method',
48
+ ' include MyClass',
49
+ ' end',
50
+ ' class OtherClass',
51
+ ' include MyClass',
52
+ ' end',
53
+ ' module MyModle',
54
+ ' include MyClass',
55
+ ' end',
56
+ 'end'])
57
+ expect(cop.offenses).to be_empty
58
+ end
59
+
60
+ it 'only takes class from top level describes' do
61
+ inspect_source(cop, ['describe MyClass do',
62
+ ' describe MyClass::Foo do',
63
+ ' subject { MyClass::Foo }',
64
+ ' let(:foo) { MyClass }',
65
+ ' end',
66
+ 'end'])
67
+ expect(cop.offenses.size).to eq(1)
68
+ expect(cop.offenses.map(&:line).sort).to eq([4])
69
+ expect(cop.messages)
70
+ .to eq(['Use `described_class` instead of `MyClass`'])
71
+ expect(cop.highlights).to eq(['MyClass'])
72
+ end
73
+
74
+ it 'ignores subclasses' do
75
+ inspect_source(cop, ['describe MyClass do',
76
+ ' subject { MyClass::SubClass }',
77
+ 'end'])
78
+ expect(cop.offenses).to be_empty
79
+ end
80
+
81
+ it 'ignores if namespace is not matching' do
82
+ inspect_source(cop, ['describe MyNamespace::MyClass do',
83
+ ' subject { ::MyClass }',
84
+ ' let(:foo) { MyClass }',
85
+ 'end'])
86
+ expect(cop.offenses).to be_empty
87
+ end
88
+
89
+ it 'checks for the use of described class with namespace' do
90
+ inspect_source(cop, ['describe MyNamespace::MyClass do',
91
+ ' subject { MyNamespace::MyClass }',
92
+ 'end'])
93
+ expect(cop.offenses.size).to eq(1)
94
+ expect(cop.offenses.map(&:line).sort).to eq([2])
95
+ expect(cop.messages)
96
+ .to eq(['Use `described_class` instead of `MyNamespace::MyClass`'])
97
+ expect(cop.highlights).to eq(['MyNamespace::MyClass'])
98
+ end
99
+
100
+ it 'checks for the use of described class with module' do
101
+ pending 'TODO'
102
+ inspect_source(cop, ['module MyNamespace',
103
+ ' describe MyClass do',
104
+ ' subject { MyNamespace::MyClass }',
105
+ ' end',
106
+ 'end'])
107
+ expect(cop.offenses.size).to eq(1)
108
+ expect(cop.offenses.map(&:line).sort).to eq([2])
109
+ expect(cop.messages)
110
+ .to eq(['Use `described_class` instead of `MyNamespace::MyClass`'])
111
+ expect(cop.highlights).to eq(['MyNamespace::MyClass'])
112
+ end
113
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Rubocop::Cop::RSpecExampleWording do
6
+ subject(:cop) { described_class.new }
7
+
8
+ it 'finds description with `should` at the beginning' do
9
+ inspect_source(cop, ["it 'should do something' do", 'end'])
10
+ expect(cop.offenses.size).to eq(1)
11
+ expect(cop.offenses.map(&:line).sort).to eq([1])
12
+ expect(cop.messages)
13
+ .to eq(['Do not use should when describing your tests.'])
14
+ expect(cop.highlights).to eq(['it'])
15
+ end
16
+
17
+ it 'skips descriptions without `should` at the beginning' do
18
+ inspect_source(cop, ["it 'finds no should ' \\",
19
+ " 'here' do",
20
+ 'end'])
21
+ expect(cop.offenses).to be_empty
22
+ end
23
+ end
@@ -0,0 +1,122 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Rubocop::Cop::RSpecFileName do
6
+ subject(:cop) { described_class.new }
7
+
8
+ it 'checks the path' do
9
+ inspect_source(cop,
10
+ ["describe MyClass, 'foo' do; end"],
11
+ 'wrong_path_foo_spec.rb')
12
+ expect(cop.offenses.size).to eq(1)
13
+ expect(cop.offenses.map(&:line).sort).to eq([1])
14
+ expect(cop.messages)
15
+ .to eq(['Spec path should end with `my_class_foo*_spec.rb`'])
16
+ end
17
+
18
+ it 'checks the path' do
19
+ inspect_source(cop,
20
+ ["describe MyClass, '#foo' do; end"],
21
+ 'wrong_class_foo_spec.rb')
22
+ expect(cop.offenses.size).to eq(1)
23
+ expect(cop.offenses.map(&:line).sort).to eq([1])
24
+ expect(cop.messages)
25
+ .to eq(['Spec path should end with `my_class_foo*_spec.rb`'])
26
+ end
27
+
28
+ it 'checks class spec paths' do
29
+ inspect_source(cop,
30
+ ['describe MyClass do; end'],
31
+ 'wrong_class_spec.rb')
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(['Spec path should end with `my_class*_spec.rb`'])
36
+ end
37
+
38
+ it 'skips specs that do not describe a class / method' do
39
+ inspect_source(cop,
40
+ ["describe 'Test something' do; end"],
41
+ 'some/class_spec.rb')
42
+ expect(cop.offenses).to be_empty
43
+ end
44
+
45
+ it 'skips specs that do have multiple top level describes' do
46
+ inspect_source(cop,
47
+ ["describe MyClass, 'do_this' do; end",
48
+ "describe MyClass, 'do_that' do; end"],
49
+ 'some/class_spec.rb')
50
+ expect(cop.offenses).to be_empty
51
+ end
52
+
53
+ it 'checks class specs' do
54
+ inspect_source(cop,
55
+ ['describe Some::Class do; end'],
56
+ 'some/class_spec.rb')
57
+ expect(cop.offenses).to be_empty
58
+ end
59
+
60
+ it 'handles CamelCaps class names' do
61
+ inspect_source(cop,
62
+ ['describe MyClass do; end'],
63
+ 'my_class_spec.rb')
64
+ expect(cop.offenses).to be_empty
65
+ end
66
+
67
+ it 'handles ACRONYMClassNames' do
68
+ inspect_source(cop,
69
+ ['describe ABCOne::Two do; end'],
70
+ 'abc_one/two_spec.rb')
71
+ expect(cop.offenses).to be_empty
72
+ end
73
+
74
+ it 'handles ALLCAPS class names' do
75
+ inspect_source(cop,
76
+ ['describe ALLCAPS do; end'],
77
+ 'allcaps_spec.rb')
78
+ expect(cop.offenses).to be_empty
79
+ end
80
+
81
+ it 'checks instance methods' do
82
+ inspect_source(cop,
83
+ ["describe Some::Class, '#inst' do; end"],
84
+ 'some/class_inst_spec.rb')
85
+ expect(cop.offenses).to be_empty
86
+ end
87
+
88
+ it 'checks methods' do
89
+ inspect_source(cop,
90
+ ["describe Some::Class, 'inst' do; end"],
91
+ 'some/class_inst_spec.rb')
92
+ expect(cop.offenses).to be_empty
93
+ end
94
+
95
+ it 'checks class methods' do
96
+ inspect_source(cop,
97
+ ["describe Some::Class, '.inst' do; end"],
98
+ 'some/class_inst_spec.rb')
99
+ expect(cop.offenses).to be_empty
100
+ end
101
+
102
+ it 'ignores non-alphanumeric characters' do
103
+ inspect_source(cop,
104
+ ["describe Some::Class, '#pred?' do; end"],
105
+ 'some/class_pred_spec.rb')
106
+ expect(cop.offenses).to be_empty
107
+ end
108
+
109
+ it 'allows flexibility with predicates' do
110
+ inspect_source(cop,
111
+ ["describe Some::Class, '#thing?' do; end"],
112
+ 'some/class_thing_predicate_spec.rb')
113
+ expect(cop.offenses).to be_empty
114
+ end
115
+
116
+ it 'allows flexibility with operators' do
117
+ inspect_source(cop,
118
+ ["describe MyClass, '#<=>' do; end"],
119
+ 'my_class_spaceship_operator_spec.rb')
120
+ expect(cop.offenses).to be_empty
121
+ end
122
+ end
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Rubocop::Cop::RSpecInstanceVariable do
6
+ subject(:cop) { described_class.new }
7
+
8
+ it 'finds an instance variable inside a describe' do
9
+ inspect_source(cop, ['describe MyClass do',
10
+ ' before { @foo = [] }',
11
+ ' it { expect(@foo).to be_emtpy }',
12
+ 'end'])
13
+ expect(cop.offenses.size).to eq(1)
14
+ expect(cop.offenses.map(&:line).sort).to eq([3])
15
+ expect(cop.messages).to eq(['Use `let` instead of an instance variable'])
16
+ end
17
+
18
+ it 'finds an instance variable inside a shared example' do
19
+ inspect_source(cop, ["shared_examples 'shared example' do",
20
+ ' it { expect(@foo).to be_emtpy }',
21
+ 'end'])
22
+ expect(cop.offenses.size).to eq(1)
23
+ expect(cop.offenses.map(&:line).sort).to eq([2])
24
+ expect(cop.messages).to eq(['Use `let` instead of an instance variable'])
25
+ end
26
+
27
+ it 'ignores an instance variable without describe' do
28
+ inspect_source(cop, ['@foo = []',
29
+ '@foo.empty?'])
30
+ expect(cop.offenses).to be_empty
31
+ end
32
+ end