rubocop-rspec 1.11.0 → 1.12.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 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