diff --git a/.rubocop.yml b/.rubocop.yml index 4795eec03..78847b5c4 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -101,34 +101,40 @@ RSpec: - expect_no_offenses - expect_offense +RSpec/DescribeClass: + Exclude: + - spec/project/**/*.rb + RSpec/ExampleLength: CountAsOne: - heredoc Max: 11 -RSpec/DescribeClass: - Exclude: - - spec/project/**/*.rb +RSpec/ExpectInLet: + Enabled: true RSpec/MultipleExpectations: Max: 2 -# `expect_offense` does not use Kernel#format or String#% -Style/FormatStringToken: - Exclude: - - spec/rubocop/**/*.rb - -Style/RequireOrder: +RSpec/NoStringifiedInstanceDoubleConstant: Enabled: true RSpec/SpecFilePathFormat: Exclude: - spec/rubocop/cop/rspec/mixin/**/*.rb +# `expect_offense` does not use Kernel#format or String#% +Style/FormatStringToken: + Exclude: + - spec/rubocop/**/*.rb + Style/NumberedParameters: Enabled: true EnforcedStyle: disallow +Style/RequireOrder: + Enabled: true + # Enable RuboCop's pending cops up to v1.63 Gemspec/DeprecatedAttributeAssignment: {Enabled: true} diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fb31d825..914180c55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Master (Unreleased) +## 3.0.6 (2024-09-17) + +- Add `RSpec/NoStringifiedInstanceDoubleConstant` to check for and correct strings used as instance_doubles. ([@corsonknowles]) + ## 3.0.5 (2024-09-07) - Fix false-negative and error for `RSpec/MetadataStyle` when non-literal args are used in metadata in `EnforceStyle: hash`. ([@cbliard]) @@ -920,6 +924,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features. [@cfabianski]: https://github.com/cfabianski [@clupprich]: https://github.com/clupprich [@composerinteralia]: https://github.com/composerinteralia +[@corsonknowles]: https://github.com/corsonknowles [@corydiamand]: https://github.com/corydiamand [@darhazer]: https://github.com/Darhazer [@daveworth]: https://github.com/daveworth diff --git a/config/default.yml b/config/default.yml index 62135b81d..74fd9568a 100644 --- a/config/default.yml +++ b/config/default.yml @@ -726,6 +726,13 @@ RSpec/NoExpectationExample: - "^expect_" - "^assert_" +RSpec/NoStringifiedInstanceDoubleConstant: + Description: Do not use a string as `instance_double` constant. + Enabled: pending + Safe: true + VersionAdded: "<>" + Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NoStringifiedInstanceDoubleConstant + RSpec/NotToNot: Description: Checks for consistent method usage for negating expectations. Enabled: true diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 000000000..f6e5dfe59 --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,35 @@ +# EXAMPLE USAGE: +# +# Refer for explanation to following link: +# https://github.com/evilmartians/lefthook/blob/master/docs/configuration.md +# +# pre-push: +# commands: +# packages-audit: +# tags: frontend security +# run: yarn audit +# gems-audit: +# tags: backend security +# run: bundle audit +# +# pre-commit: +# parallel: true +# commands: +# eslint: +# glob: "*.{js,ts,jsx,tsx}" +# run: yarn eslint {staged_files} +# rubocop: +# tags: backend style +# glob: "*.rb" +# exclude: '(^|/)(application|routes)\.rb$' +# run: bundle exec rubocop --force-exclusion {all_files} +# govet: +# tags: backend style +# files: git ls-files -m +# glob: "*.go" +# run: go vet {files} +# scripts: +# "hello.js": +# runner: node +# "any.go": +# runner: go run diff --git a/lib/rubocop/cop/rspec/no_stringified_instance_double_constant.rb b/lib/rubocop/cop/rspec/no_stringified_instance_double_constant.rb new file mode 100644 index 000000000..2b074956a --- /dev/null +++ b/lib/rubocop/cop/rspec/no_stringified_instance_double_constant.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Do not use a string as `instance_double` constant. + # + # @example + # # bad + # instance_double('Foo', ...) + # + # # good + # instance_double(Foo, ...) + # + class NoStringifiedInstanceDoubleConstant < Base + extend AutoCorrector + + MSG = 'Do not use a string as `instance_double` constant.' + RESTRICT_ON_SEND = %i[instance_double].freeze + + # @!method stringified_instance_double_const?(node) + def_node_matcher :stringified_instance_double_const?, <<~PATTERN + (send nil? :instance_double $...) + PATTERN + + def on_send(node) + stringified_instance_double_const?(node) do |args_node| + if args_node.first.str_type? + add_offense(args_node.first) do |corrector| + autocorrect(corrector, args_node.first) + end + end + end + end + + def autocorrect(corrector, node) + corrector.replace(node, node.value) + end + end + end + end +end diff --git a/lib/rubocop/cop/rspec_cops.rb b/lib/rubocop/cop/rspec_cops.rb index 5eed7e860..0ddc55a3c 100644 --- a/lib/rubocop/cop/rspec_cops.rb +++ b/lib/rubocop/cop/rspec_cops.rb @@ -72,6 +72,7 @@ require_relative 'rspec/named_subject' require_relative 'rspec/nested_groups' require_relative 'rspec/no_expectation_example' +require_relative 'rspec/no_stringified_instance_double_constant' require_relative 'rspec/not_to_not' require_relative 'rspec/overwriting_setup' require_relative 'rspec/pending' diff --git a/spec/rubocop/cop/rspec/no_stringified_instance_double_constant_spec.rb b/spec/rubocop/cop/rspec/no_stringified_instance_double_constant_spec.rb new file mode 100644 index 000000000..107e5515d --- /dev/null +++ b/spec/rubocop/cop/rspec/no_stringified_instance_double_constant_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::Cop::RSpec::NoStringifiedInstanceDoubleConstant, + :config do + context 'when using a class for instance_double' do + let(:source) do + <<~RUBY + instance_double(Foo, failure_message, stubs) + RUBY + end + + it { expect_no_offenses source } + end + + context 'when using a symbol for instance_double' do + let(:source) do + <<~RUBY + instance_double(:Foo, failure_message, stubs) + RUBY + end + + it { expect_no_offenses source } + end + + context 'when using a string for instance_double' do + it 'replaces the string with the class' do + expect_offense <<~RUBY + instance_double('Foo', failure_message, stubs) + ^^^^^ Do not use a string as `instance_double` constant. + RUBY + + expect_correction <<~RUBY + instance_double(Foo, failure_message, stubs) + RUBY + end + end +end