rubocop-rspec 1.11.0 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fda044631502561746af13188e9d7217ef83f8fb
4
- data.tar.gz: d021f893b44704291ff69433019a9798b50fe82e
3
+ metadata.gz: 48bfb61579b01b4044eeca76aa125c026ac18630
4
+ data.tar.gz: 240d2ce3b483174eae7c4049fcc65f8301bf48a1
5
5
  SHA512:
6
- metadata.gz: 8d804e069e562fa9af39669b2f39b6d8fa81e1ce4778bba2dfbf999dd1afc583475e1bd3d296e1ce79cf40bf04ad42d09468d9b4b0eb6dd10fced565e7e970b3
7
- data.tar.gz: 8d14f57b6eb8437b68a7f92acea42a687a7515e1793da6d11485e3c97140571b6741697fad84e6763be1f31fad1d897b88e8dd5131d0286e92fe05cd4c77717a
6
+ metadata.gz: 09f351caba55c9c7ad8710e286fec4b9f087028a64a886c4edf25d69b3147ecedebd5e7eeacec52a81285e14c3cd46cf615fbfef3c15a542fe6cd6c6a9d28a0c
7
+ data.tar.gz: 120152a6271b3eb853a9e8c4b19716667b401f732a712c045ebada5df7371c3a843e49d5a8a83cb5197fd7a9bbf4a12e6ef245fdf9df9cd26155a849cdcdeffc
@@ -1,6 +1,11 @@
1
1
  # Change log
2
2
 
3
- ## Master (unreleased)
3
+ ## Master (Unreleased)
4
+
5
+ ## 1.12.0 (2017-02-21)
6
+
7
+ * Add `RSpec/InstanceSpy` cop. ([@Darhazer][])
8
+ * Add `RSpec/BeforeAfterAll` for avoiding leaky global test setup. ([@cfabianski][])
4
9
 
5
10
  ## 1.11.0 (2017-02-16)
6
11
 
@@ -180,3 +185,4 @@
180
185
  [@onk]: https://github.com/onk
181
186
  [@Darhazer]: https://github.com/Darhazer
182
187
  [@redross]: https://github.com/redross
188
+ [@cfabianski]: https://github.com/cfabianski
@@ -17,6 +17,14 @@ RSpec/BeEql:
17
17
  Description: Check for expectations where `be(...)` can replace `eql(...)`.
18
18
  Enabled: true
19
19
 
20
+ RSpec/BeforeAfterAll:
21
+ Description: Check that before/after(:all) isn't being used.
22
+ Enabled: true
23
+ Exclude:
24
+ - spec/spec_helper.rb
25
+ - spec/rails_helper.rb
26
+ - spec/support/**/*.rb
27
+
20
28
  RSpec/DescribeClass:
21
29
  Description: Check that the first argument to the top level describe is a constant.
22
30
  Enabled: true
@@ -90,6 +98,10 @@ RSpec/ImplicitExpect:
90
98
  - is_expected
91
99
  - should
92
100
 
101
+ RSpec/InstanceSpy:
102
+ Description: Checks for `instance_double` used with `have_received`.
103
+ Enabled: true
104
+
93
105
  RSpec/InstanceVariable:
94
106
  Description: Checks for instance variable usage in specs.
95
107
  AssignmentOnly: false
@@ -23,6 +23,7 @@ RuboCop::RSpec::Inject.defaults!
23
23
  require 'rubocop/cop/rspec/any_instance'
24
24
  require 'rubocop/cop/rspec/around_block'
25
25
  require 'rubocop/cop/rspec/be_eql'
26
+ require 'rubocop/cop/rspec/before_after_all'
26
27
  require 'rubocop/cop/rspec/describe_class'
27
28
  require 'rubocop/cop/rspec/describe_method'
28
29
  require 'rubocop/cop/rspec/described_class'
@@ -35,6 +36,7 @@ require 'rubocop/cop/rspec/file_path'
35
36
  require 'rubocop/cop/rspec/focus'
36
37
  require 'rubocop/cop/rspec/hook_argument'
37
38
  require 'rubocop/cop/rspec/implicit_expect'
39
+ require 'rubocop/cop/rspec/instance_spy'
38
40
  require 'rubocop/cop/rspec/instance_variable'
39
41
  require 'rubocop/cop/rspec/leading_subject'
40
42
  require 'rubocop/cop/rspec/let_setup'
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Check that before/after(:all) isn't being used.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # #
11
+ # # Faster but risk of state leaking between examples
12
+ # #
13
+ # describe MyClass do
14
+ # before(:all) { Widget.create }
15
+ # after(:all) { Widget.delete_all }
16
+ # end
17
+ #
18
+ # # good
19
+ # #
20
+ # # Slower but examples are properly isolated
21
+ # #
22
+ # describe MyClass do
23
+ # before(:each) { Widget.create }
24
+ # after(:each) { Widget.delete_all }
25
+ # end
26
+ class BeforeAfterAll < Cop
27
+ MESSAGE = 'Beware of using `before/after(:all)` as it may cause state '\
28
+ 'to leak between tests. If you are using rspec-rails, and '\
29
+ '`use_transactional_fixtures` is enabled, then records created in '\
30
+ '`before(:all)` are not rolled back.'.freeze
31
+
32
+ BEFORE_AFTER_METHODS = [
33
+ :before,
34
+ :after
35
+ ].freeze
36
+
37
+ ALL_PAIR = s(:sym, :all)
38
+ CONTEXT_PAIR = s(:sym, :context)
39
+
40
+ def on_send(node)
41
+ _receiver, method_name, *args = *node
42
+ return unless BEFORE_AFTER_METHODS.include?(method_name)
43
+ return unless args.include?(ALL_PAIR) || args.include?(CONTEXT_PAIR)
44
+
45
+ add_offense(node, :expression, MESSAGE)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks for `instance_double` used with `have_received`.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # it do
11
+ # foo = instance_double(Foo).as_null_object
12
+ # expect(foo).to have_received(:bar)
13
+ # end
14
+ #
15
+ # # good
16
+ # it do
17
+ # foo = instance_spy(Foo)
18
+ # expect(foo).to have_received(:bar)
19
+ # end
20
+ #
21
+ class InstanceSpy < Cop
22
+ MSG = 'Use `instance_spy` when you check your double ' \
23
+ 'with `have_received`'.freeze
24
+
25
+ EXAMPLES = Examples::ALL.node_pattern_union.freeze
26
+
27
+ def_node_matcher :example?, "(block $(send nil #{EXAMPLES}) ...)"
28
+
29
+ def_node_search :null_double, <<-PATTERN
30
+ (lvasgn $_
31
+ (send
32
+ $(send nil :instance_double
33
+ ...) :as_null_object))
34
+ PATTERN
35
+
36
+ def_node_search :have_received_usage, <<-PATTERN
37
+ (send
38
+ (send nil :expect
39
+ (lvar $_)) :to
40
+ (send nil :have_received
41
+ ...)
42
+ ...)
43
+ PATTERN
44
+
45
+ def on_block(node)
46
+ return unless example?(node)
47
+
48
+ null_double(node) do |var, receiver|
49
+ have_received_usage(node) do |expected|
50
+ add_offense(receiver, :expression, MSG) if expected == var
51
+ end
52
+ end
53
+ end
54
+
55
+ def autocorrect(node)
56
+ lambda do |corrector|
57
+ replacement = 'instance_spy'
58
+ corrector.replace(node.loc.selector, replacement)
59
+
60
+ double_source_map = node.parent.loc
61
+ as_null_object_range = double_source_map
62
+ .dot
63
+ .join(double_source_map.selector)
64
+ corrector.remove(as_null_object_range)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ 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 = '1.11.0'.freeze
7
+ STRING = '1.12.0'.freeze
8
8
  end
9
9
  end
10
10
  end
@@ -0,0 +1,92 @@
1
+ describe RuboCop::Cop::RSpec::BeforeAfterAll, :config do
2
+ subject(:cop) { described_class.new(config) }
3
+
4
+ context 'when offenses detected' do
5
+ let(:code) do
6
+ [
7
+ 'describe MyClass do',
8
+ ' before(:all) { do_something}',
9
+ ' after(:all) { do_something_else }',
10
+ 'end'
11
+ ]
12
+ end
13
+
14
+ let(:expected_error) do
15
+ 'Beware of using `before/after(:all)` as it may cause state to leak '\
16
+ 'between tests. If you are using rspec-rails, and '\
17
+ '`use_transactional_fixtures` is enabled, then records created in '\
18
+ '`before(:all)` are not rolled back.'
19
+ end
20
+
21
+ it 'reports 2 offenses' do
22
+ inspect_source(cop, code, 'foo_spec.rb')
23
+ expect(cop.offenses.size).to eq(2)
24
+ end
25
+
26
+ it 'reports the lines for these offenses' do
27
+ inspect_source(cop, code, 'foo_spec.rb')
28
+ expect(cop.offenses.map(&:line).sort).to eq([2, 3])
29
+ end
30
+
31
+ it 'describes the offenses' do
32
+ inspect_source(cop, code, 'foo_spec.rb')
33
+ expect(cop.messages).to eq([expected_error, expected_error])
34
+ end
35
+ end
36
+
37
+ it 'complains for :context' do
38
+ inspect_source(
39
+ cop,
40
+ [
41
+ 'describe MyClass do',
42
+ ' before(:context) { do_something }',
43
+ ' after(:context) { do_something_else }',
44
+ 'end'
45
+ ],
46
+ 'foo_spec.rb'
47
+ )
48
+ expect(cop.offenses.size).to eq(2)
49
+ end
50
+
51
+ it 'does not complain for before/after :each' do
52
+ inspect_source(
53
+ cop,
54
+ [
55
+ 'describe MyClass do',
56
+ ' before(:each) { do_something }',
57
+ ' after(:each) { do_something_else }',
58
+ 'end'
59
+ ],
60
+ 'foo_spec.rb'
61
+ )
62
+ expect(cop.offenses).to be_empty
63
+ end
64
+
65
+ it 'does not complain for before/after :example' do
66
+ inspect_source(
67
+ cop,
68
+ [
69
+ 'describe MyClass do',
70
+ ' before(:example) { do_something }',
71
+ ' after(:example) { do_something_else }',
72
+ 'end'
73
+ ],
74
+ 'foo_spec.rb'
75
+ )
76
+ expect(cop.offenses).to be_empty
77
+ end
78
+
79
+ it 'does not complain for before/after' do
80
+ inspect_source(
81
+ cop,
82
+ [
83
+ 'describe MyClass do',
84
+ ' before { do_something }',
85
+ ' after { do_something_else }',
86
+ 'end'
87
+ ],
88
+ 'foo_spec.rb'
89
+ )
90
+ expect(cop.offenses).to be_empty
91
+ end
92
+ end
@@ -0,0 +1,60 @@
1
+ describe RuboCop::Cop::RSpec::InstanceSpy do
2
+ subject(:cop) { described_class.new }
3
+
4
+ context 'when used with `have_received`' do
5
+ it 'adds an offense for an instance_double with single argument' do
6
+ expect_violation(<<-RUBY)
7
+ it do
8
+ foo = instance_double(Foo).as_null_object
9
+ ^^^^^^^^^^^^^^^^^^^^ Use `instance_spy` when you check your double with `have_received`
10
+ expect(foo).to have_received(:bar)
11
+ end
12
+ RUBY
13
+ end
14
+
15
+ it 'adds an offense for an instance_double with multiple arguments' do
16
+ expect_violation(<<-RUBY)
17
+ it do
18
+ foo = instance_double(Foo, :name).as_null_object
19
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `instance_spy` when you check your double with `have_received`
20
+ expect(foo).to have_received(:bar)
21
+ end
22
+ RUBY
23
+ end
24
+
25
+ it 'ignores instance_double when it is not used with as_null_object' do
26
+ expect_no_violations(<<-RUBY)
27
+ it do
28
+ foo = instance_double(Foo)
29
+ expect(bar).to have_received(:bar)
30
+ end
31
+ RUBY
32
+ end
33
+ end
34
+
35
+ context 'when not used with `have_received`' do
36
+ it 'does not add an offence' do
37
+ expect_no_violations(<<-RUBY)
38
+ it do
39
+ foo = instance_double(Foo).as_null_object
40
+ expect(bar).to have_received(:bar)
41
+ end
42
+ RUBY
43
+ end
44
+ end
45
+
46
+ original = <<-RUBY
47
+ it do
48
+ foo = instance_double(Foo, :name).as_null_object
49
+ expect(foo).to have_received(:bar)
50
+ end
51
+ RUBY
52
+ corrected = <<-RUBY
53
+ it do
54
+ foo = instance_spy(Foo, :name)
55
+ expect(foo).to have_received(:bar)
56
+ end
57
+ RUBY
58
+
59
+ include_examples 'autocorrect', original, corrected
60
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-rspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.11.0
4
+ version: 1.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Backus
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2017-02-16 00:00:00.000000000 Z
13
+ date: 2017-02-22 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rubocop
@@ -147,6 +147,7 @@ files:
147
147
  - lib/rubocop/cop/rspec/any_instance.rb
148
148
  - lib/rubocop/cop/rspec/around_block.rb
149
149
  - lib/rubocop/cop/rspec/be_eql.rb
150
+ - lib/rubocop/cop/rspec/before_after_all.rb
150
151
  - lib/rubocop/cop/rspec/cop.rb
151
152
  - lib/rubocop/cop/rspec/describe_class.rb
152
153
  - lib/rubocop/cop/rspec/describe_method.rb
@@ -160,6 +161,7 @@ files:
160
161
  - lib/rubocop/cop/rspec/focus.rb
161
162
  - lib/rubocop/cop/rspec/hook_argument.rb
162
163
  - lib/rubocop/cop/rspec/implicit_expect.rb
164
+ - lib/rubocop/cop/rspec/instance_spy.rb
163
165
  - lib/rubocop/cop/rspec/instance_variable.rb
164
166
  - lib/rubocop/cop/rspec/leading_subject.rb
165
167
  - lib/rubocop/cop/rspec/let_setup.rb
@@ -199,6 +201,7 @@ files:
199
201
  - spec/rubocop/cop/rspec/any_instance_spec.rb
200
202
  - spec/rubocop/cop/rspec/around_block_spec.rb
201
203
  - spec/rubocop/cop/rspec/be_eql_spec.rb
204
+ - spec/rubocop/cop/rspec/before_after_all_spec.rb
202
205
  - spec/rubocop/cop/rspec/cop_spec.rb
203
206
  - spec/rubocop/cop/rspec/describe_class_spec.rb
204
207
  - spec/rubocop/cop/rspec/describe_method_spec.rb
@@ -212,6 +215,7 @@ files:
212
215
  - spec/rubocop/cop/rspec/focus_spec.rb
213
216
  - spec/rubocop/cop/rspec/hook_argument_spec.rb
214
217
  - spec/rubocop/cop/rspec/implicit_expect_spec.rb
218
+ - spec/rubocop/cop/rspec/instance_spy_spec.rb
215
219
  - spec/rubocop/cop/rspec/instance_variable_spec.rb
216
220
  - spec/rubocop/cop/rspec/leading_subject_spec.rb
217
221
  - spec/rubocop/cop/rspec/let_setup_spec.rb
@@ -273,6 +277,7 @@ test_files:
273
277
  - spec/rubocop/cop/rspec/any_instance_spec.rb
274
278
  - spec/rubocop/cop/rspec/around_block_spec.rb
275
279
  - spec/rubocop/cop/rspec/be_eql_spec.rb
280
+ - spec/rubocop/cop/rspec/before_after_all_spec.rb
276
281
  - spec/rubocop/cop/rspec/cop_spec.rb
277
282
  - spec/rubocop/cop/rspec/describe_class_spec.rb
278
283
  - spec/rubocop/cop/rspec/describe_method_spec.rb
@@ -286,6 +291,7 @@ test_files:
286
291
  - spec/rubocop/cop/rspec/focus_spec.rb
287
292
  - spec/rubocop/cop/rspec/hook_argument_spec.rb
288
293
  - spec/rubocop/cop/rspec/implicit_expect_spec.rb
294
+ - spec/rubocop/cop/rspec/instance_spy_spec.rb
289
295
  - spec/rubocop/cop/rspec/instance_variable_spec.rb
290
296
  - spec/rubocop/cop/rspec/leading_subject_spec.rb
291
297
  - spec/rubocop/cop/rspec/let_setup_spec.rb