Skip to content

Commit dea7de9

Browse files
authored
Merge pull request #1957 from corsonknowles/master
Add RSpec/StringAsInstanceDoubleConstant
2 parents 5959ad6 + 324552c commit dea7de9

File tree

8 files changed

+126
-1
lines changed

8 files changed

+126
-1
lines changed

.rubocop.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,4 +253,5 @@ Style/YAMLFileRead: {Enabled: true}
253253

254254
# Enable our own pending cops.
255255
#
256-
# No pending cops yet.
256+
RSpec/StringAsInstanceDoubleConstant:
257+
Enabled: true

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Master (Unreleased)
44

5+
- Add `RSpec/StringAsInstanceDoubleConstant` to check for and correct strings used as instance_doubles. ([@corsonknowles])
56
- Fix false-positive for `RSpec/UnspecifiedException` when a method is literally named `raise_exception`. ([@aarestad])
67
- Fix false-positive for `RSpec/UnspecifiedException` when `not_to raise_error` is used within a block. ([@aarestad], [@G-Rath])
78

@@ -924,6 +925,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
924925
[@cfabianski]: https://github.com/cfabianski
925926
[@clupprich]: https://github.com/clupprich
926927
[@composerinteralia]: https://github.com/composerinteralia
928+
[@corsonknowles]: https://github.com/corsonknowles
927929
[@corydiamand]: https://github.com/corydiamand
928930
[@darhazer]: https://github.com/Darhazer
929931
[@daveworth]: https://github.com/daveworth

config/default.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,13 @@ RSpec/SpecFilePathSuffix:
929929
- "**/spec/**/*"
930930
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SpecFilePathSuffix
931931

932+
RSpec/StringAsInstanceDoubleConstant:
933+
Description: Do not use a string as `instance_double` constant.
934+
Enabled: pending
935+
Safe: false
936+
VersionAdded: "<<next>>"
937+
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/StringAsInstanceDoubleConstant
938+
932939
RSpec/StubbedMock:
933940
Description: Checks that message expectations do not have a configured response.
934941
Enabled: true

docs/modules/ROOT/pages/cops.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
* xref:cops_rspec.adoc#rspecsortmetadata[RSpec/SortMetadata]
102102
* xref:cops_rspec.adoc#rspecspecfilepathformat[RSpec/SpecFilePathFormat]
103103
* xref:cops_rspec.adoc#rspecspecfilepathsuffix[RSpec/SpecFilePathSuffix]
104+
* xref:cops_rspec.adoc#rspecstringasinstancedoubleconstant[RSpec/StringAsInstanceDoubleConstant]
104105
* xref:cops_rspec.adoc#rspecstubbedmock[RSpec/StubbedMock]
105106
* xref:cops_rspec.adoc#rspecsubjectdeclaration[RSpec/SubjectDeclaration]
106107
* xref:cops_rspec.adoc#rspecsubjectstub[RSpec/SubjectStub]

docs/modules/ROOT/pages/cops_rspec.adoc

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5493,6 +5493,41 @@ spec/models/user.rb # shared_examples_for 'foo'
54935493
54945494
* https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SpecFilePathSuffix
54955495
5496+
== RSpec/StringAsInstanceDoubleConstant
5497+
5498+
|===
5499+
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed
5500+
5501+
| Pending
5502+
| No
5503+
| Always (Unsafe)
5504+
| <<next>>
5505+
| -
5506+
|===
5507+
5508+
Do not use a string as `instance_double` constant.
5509+
5510+
=== Safety
5511+
5512+
This cop is unsafe because the correction requires loading the class.
5513+
Loading before stubbing causes RSpec to only allow instance methods
5514+
to be stubbed.
5515+
5516+
=== Examples
5517+
5518+
[source,ruby]
5519+
----
5520+
# bad
5521+
instance_double('User', name: 'John')
5522+
5523+
# good
5524+
instance_double(User, name: 'John')
5525+
----
5526+
5527+
=== References
5528+
5529+
* https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/StringAsInstanceDoubleConstant
5530+
54965531
== RSpec/StubbedMock
54975532
54985533
|===
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# frozen_string_literal: true
2+
3+
module RuboCop
4+
module Cop
5+
module RSpec
6+
# Do not use a string as `instance_double` constant.
7+
#
8+
# @safety
9+
# This cop is unsafe because the correction requires loading the class.
10+
# Loading before stubbing causes RSpec to only allow instance methods
11+
# to be stubbed.
12+
#
13+
# @example
14+
# # bad
15+
# instance_double('User', name: 'John')
16+
#
17+
# # good
18+
# instance_double(User, name: 'John')
19+
#
20+
class StringAsInstanceDoubleConstant < Base
21+
extend AutoCorrector
22+
23+
MSG = 'Do not use a string as `instance_double` constant.'
24+
RESTRICT_ON_SEND = %i[instance_double].freeze
25+
26+
# @!method stringified_instance_double_const?(node)
27+
def_node_matcher :stringified_instance_double_const?, <<~PATTERN
28+
(send nil? :instance_double $str ...)
29+
PATTERN
30+
31+
def on_send(node)
32+
stringified_instance_double_const?(node) do |args_node|
33+
add_offense(args_node) do |corrector|
34+
autocorrect(corrector, args_node)
35+
end
36+
end
37+
end
38+
39+
def autocorrect(corrector, node)
40+
corrector.replace(node, node.value)
41+
end
42+
end
43+
end
44+
end
45+
end

lib/rubocop/cop/rspec_cops.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
require_relative 'rspec/sort_metadata'
100100
require_relative 'rspec/spec_file_path_format'
101101
require_relative 'rspec/spec_file_path_suffix'
102+
require_relative 'rspec/string_as_instance_double_constant'
102103
require_relative 'rspec/stubbed_mock'
103104
require_relative 'rspec/subject_declaration'
104105
require_relative 'rspec/subject_stub'
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe RuboCop::Cop::RSpec::StringAsInstanceDoubleConstant,
4+
:config do
5+
context 'when using a class for instance_double' do
6+
it 'does not register an offense' do
7+
expect_no_offenses(<<~RUBY)
8+
instance_double(Shape, area: 12)
9+
RUBY
10+
end
11+
end
12+
13+
context 'when passing a variable to initialize instance_double' do
14+
it 'does not register an offense' do
15+
expect_no_offenses(<<~RUBY)
16+
instance_double(type_undetectable_in_static_analysis)
17+
RUBY
18+
end
19+
end
20+
21+
context 'when using a string for instance_double' do
22+
it 'replaces the string with the class' do
23+
expect_offense <<~RUBY
24+
instance_double('Shape', area: 12)
25+
^^^^^^^ Do not use a string as `instance_double` constant.
26+
RUBY
27+
28+
expect_correction <<~RUBY
29+
instance_double(Shape, area: 12)
30+
RUBY
31+
end
32+
end
33+
end

0 commit comments

Comments
 (0)