From 9a9027990fb73be6a5d555e452295158ded696ef Mon Sep 17 00:00:00 2001 From: Dave Corson-Knowles Date: Tue, 17 Sep 2024 16:28:08 -0700 Subject: [PATCH 001/105] Sort RuboCop config file --- .rubocop.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 4795eec03..e5b68d25d 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -101,34 +101,34 @@ 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/MultipleExpectations: Max: 2 +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/RequireOrder: - Enabled: true - -RSpec/SpecFilePathFormat: - Exclude: - - spec/rubocop/cop/rspec/mixin/**/*.rb - Style/NumberedParameters: Enabled: true EnforcedStyle: disallow +Style/RequireOrder: + Enabled: true + # Enable RuboCop's pending cops up to v1.63 Gemspec/DeprecatedAttributeAssignment: {Enabled: true} From f4f698c1055263a40b7fae5a4f98a331a8bd4ca2 Mon Sep 17 00:00:00 2001 From: Benjamin Quorning Date: Wed, 18 Sep 2024 10:49:03 +0200 Subject: [PATCH 002/105] Fix InternalAffairs/RedundantSourceRange offenses --- lib/rubocop/cop/rspec/change_by_zero.rb | 4 ++-- lib/rubocop/cop/rspec/expect_actual.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/rubocop/cop/rspec/change_by_zero.rb b/lib/rubocop/cop/rspec/change_by_zero.rb index d37ddd4dd..1ee9a40b7 100644 --- a/lib/rubocop/cop/rspec/change_by_zero.rb +++ b/lib/rubocop/cop/rspec/change_by_zero.rb @@ -104,12 +104,12 @@ def on_send(node) # rubocop:disable Metrics/MethodLength def register_offense(node, change_node) if compound_expectations?(node) - add_offense(node.source_range, + add_offense(node, message: message_compound(change_node)) do |corrector| autocorrect_compound(corrector, node) end else - add_offense(node.source_range, + add_offense(node, message: message(change_node)) do |corrector| autocorrect(corrector, node, change_node) end diff --git a/lib/rubocop/cop/rspec/expect_actual.rb b/lib/rubocop/cop/rspec/expect_actual.rb index 7a15aa25d..7aeb0fa81 100644 --- a/lib/rubocop/cop/rspec/expect_actual.rb +++ b/lib/rubocop/cop/rspec/expect_actual.rb @@ -69,7 +69,7 @@ def on_send(node) # rubocop:disable Metrics/MethodLength expect_literal(node) do |actual, send_node, matcher, expected| next if SKIPPED_MATCHERS.include?(matcher) - add_offense(actual.source_range) do |corrector| + add_offense(actual) do |corrector| next unless CORRECTABLE_MATCHERS.include?(matcher) next if literal?(expected) From a59315fb180454a4fdbf245eebac843a11952c98 Mon Sep 17 00:00:00 2001 From: Peter Aarestad Date: Tue, 13 Aug 2024 14:17:52 -0500 Subject: [PATCH 003/105] fix false positive on UnspecifiedException cop when function is named raise_exception --- CHANGELOG.md | 3 ++ .../cop/rspec/unspecified_exception.rb | 5 +- .../cop/rspec/unspecified_exception_spec.rb | 48 +++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fb31d825..f0797ef0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +- Fix false-positive for `RSpec/UnspecifiedException` when a method is literally named `raise_exception`. ([@aarestad]) + ## 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]) @@ -899,6 +901,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features. +[@aarestad]: https://github.com/aarestad [@abrom]: https://github.com/abrom [@ahukkanen]: https://github.com/ahukkanen [@akiomik]: https://github.com/akiomik diff --git a/lib/rubocop/cop/rspec/unspecified_exception.rb b/lib/rubocop/cop/rspec/unspecified_exception.rb index ed49701a8..30d4c49af 100644 --- a/lib/rubocop/cop/rspec/unspecified_exception.rb +++ b/lib/rubocop/cop/rspec/unspecified_exception.rb @@ -62,7 +62,10 @@ def empty_exception_matcher?(node) end def find_expect_to(node) - node.each_ancestor(:send).find do |ancestor| + node.each_ancestor.find do |ancestor| + break if ancestor.block_type? + next unless ancestor.send_type? + expect_to?(ancestor) end end diff --git a/spec/rubocop/cop/rspec/unspecified_exception_spec.rb b/spec/rubocop/cop/rspec/unspecified_exception_spec.rb index bb5db00bd..2181b24bb 100644 --- a/spec/rubocop/cop/rspec/unspecified_exception_spec.rb +++ b/spec/rubocop/cop/rspec/unspecified_exception_spec.rb @@ -85,6 +85,30 @@ }.to raise_error(my_exception) RUBY end + + it 'allows a subject function to be named raise_error' do + expect_no_offenses(<<~RUBY) + def raise_exception + raise StandardError + end + + expect { + raise_error + }.to raise_error(StandardError) + RUBY + end + + it 'allows a subject function to be named raise_exception' do + expect_no_offenses(<<~RUBY) + def raise_exception + raise StandardError + end + + expect { + raise_exception + }.to raise_error(StandardError) + RUBY + end end context 'with raise_exception matcher' do @@ -198,5 +222,29 @@ ^^^^^^^^^^^^^^^ Specify the exception being captured RUBY end + + it 'allows a subject function to be named raise_exception' do + expect_no_offenses(<<~RUBY) + def raise_error + raise StandardError + end + + expect { + raise_exception + }.to raise_exception(StandardError) + RUBY + end + + it 'allows a subject function to be named raise_error' do + expect_no_offenses(<<~RUBY) + def raise_error + raise StandardError + end + + expect { + raise_error + }.to raise_exception(StandardError) + RUBY + end end end From 1f48c7b3f4362b2f01e8ad2ae51805c9b831a689 Mon Sep 17 00:00:00 2001 From: Gareth Jones Date: Fri, 27 Sep 2024 08:45:16 +1200 Subject: [PATCH 004/105] test: showcase `RSpec/UnspecifiedException` block/chain confusion is fixed --- CHANGELOG.md | 1 + spec/rubocop/cop/rspec/unspecified_exception_spec.rb | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0797ef0a..d1027dc93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Master (Unreleased) - Fix false-positive for `RSpec/UnspecifiedException` when a method is literally named `raise_exception`. ([@aarestad]) +- Fix false-positive for `RSpec/UnspecifiedException` when `not_to raise_error` is used within a block. ([@aarestad], [@G-Rath]) ## 3.0.5 (2024-09-07) diff --git a/spec/rubocop/cop/rspec/unspecified_exception_spec.rb b/spec/rubocop/cop/rspec/unspecified_exception_spec.rb index 2181b24bb..8c41e6b30 100644 --- a/spec/rubocop/cop/rspec/unspecified_exception_spec.rb +++ b/spec/rubocop/cop/rspec/unspecified_exception_spec.rb @@ -223,6 +223,14 @@ def raise_exception RUBY end + it 'does not confuse blocks with chains' do + expect_no_offenses(<<~RUBY) + expect do + expect { foo }.not_to raise_error + end.to change(Foo, :count).by(3) + RUBY + end + it 'allows a subject function to be named raise_exception' do expect_no_offenses(<<~RUBY) def raise_error From 324552cc8ff780b43a5eab2e697e0f4541213086 Mon Sep 17 00:00:00 2001 From: Dave Corson-Knowles Date: Wed, 18 Sep 2024 06:49:10 -0700 Subject: [PATCH 005/105] Add RSpec/StringAsInstanceDoubleConstant Addresses #1136 Adds a cop which can autocorrect from String declarations for instance_double to Class declarations. Symbol declarations are not affected. --- .rubocop.yml | 3 +- CHANGELOG.md | 2 + config/default.yml | 7 +++ docs/modules/ROOT/pages/cops.adoc | 1 + docs/modules/ROOT/pages/cops_rspec.adoc | 35 +++++++++++++++ .../string_as_instance_double_constant.rb | 45 +++++++++++++++++++ lib/rubocop/cop/rspec_cops.rb | 1 + ...string_as_instance_double_constant_spec.rb | 33 ++++++++++++++ 8 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 lib/rubocop/cop/rspec/string_as_instance_double_constant.rb create mode 100644 spec/rubocop/cop/rspec/string_as_instance_double_constant_spec.rb diff --git a/.rubocop.yml b/.rubocop.yml index e5b68d25d..6fb427aef 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -253,4 +253,5 @@ Style/YAMLFileRead: {Enabled: true} # Enable our own pending cops. # -# No pending cops yet. +RSpec/StringAsInstanceDoubleConstant: + Enabled: true diff --git a/CHANGELOG.md b/CHANGELOG.md index d1027dc93..bf2338aee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Master (Unreleased) +- Add `RSpec/StringAsInstanceDoubleConstant` to check for and correct strings used as instance_doubles. ([@corsonknowles]) - Fix false-positive for `RSpec/UnspecifiedException` when a method is literally named `raise_exception`. ([@aarestad]) - Fix false-positive for `RSpec/UnspecifiedException` when `not_to raise_error` is used within a block. ([@aarestad], [@G-Rath]) @@ -924,6 +925,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..7e6e742b4 100644 --- a/config/default.yml +++ b/config/default.yml @@ -929,6 +929,13 @@ RSpec/SpecFilePathSuffix: - "**/spec/**/*" Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SpecFilePathSuffix +RSpec/StringAsInstanceDoubleConstant: + Description: Do not use a string as `instance_double` constant. + Enabled: pending + Safe: false + VersionAdded: "<>" + Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/StringAsInstanceDoubleConstant + RSpec/StubbedMock: Description: Checks that message expectations do not have a configured response. Enabled: true diff --git a/docs/modules/ROOT/pages/cops.adoc b/docs/modules/ROOT/pages/cops.adoc index 16ddf0fd6..116d2a714 100644 --- a/docs/modules/ROOT/pages/cops.adoc +++ b/docs/modules/ROOT/pages/cops.adoc @@ -101,6 +101,7 @@ * xref:cops_rspec.adoc#rspecsortmetadata[RSpec/SortMetadata] * xref:cops_rspec.adoc#rspecspecfilepathformat[RSpec/SpecFilePathFormat] * xref:cops_rspec.adoc#rspecspecfilepathsuffix[RSpec/SpecFilePathSuffix] +* xref:cops_rspec.adoc#rspecstringasinstancedoubleconstant[RSpec/StringAsInstanceDoubleConstant] * xref:cops_rspec.adoc#rspecstubbedmock[RSpec/StubbedMock] * xref:cops_rspec.adoc#rspecsubjectdeclaration[RSpec/SubjectDeclaration] * xref:cops_rspec.adoc#rspecsubjectstub[RSpec/SubjectStub] diff --git a/docs/modules/ROOT/pages/cops_rspec.adoc b/docs/modules/ROOT/pages/cops_rspec.adoc index 143791aa5..01240298c 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -5493,6 +5493,41 @@ spec/models/user.rb # shared_examples_for 'foo' * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SpecFilePathSuffix +== RSpec/StringAsInstanceDoubleConstant + +|=== +| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed + +| Pending +| No +| Always (Unsafe) +| <> +| - +|=== + +Do not use a string as `instance_double` constant. + +=== Safety + +This cop is unsafe because the correction requires loading the class. +Loading before stubbing causes RSpec to only allow instance methods +to be stubbed. + +=== Examples + +[source,ruby] +---- +# bad +instance_double('User', name: 'John') + +# good +instance_double(User, name: 'John') +---- + +=== References + +* https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/StringAsInstanceDoubleConstant + == RSpec/StubbedMock |=== diff --git a/lib/rubocop/cop/rspec/string_as_instance_double_constant.rb b/lib/rubocop/cop/rspec/string_as_instance_double_constant.rb new file mode 100644 index 000000000..c7a346821 --- /dev/null +++ b/lib/rubocop/cop/rspec/string_as_instance_double_constant.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Do not use a string as `instance_double` constant. + # + # @safety + # This cop is unsafe because the correction requires loading the class. + # Loading before stubbing causes RSpec to only allow instance methods + # to be stubbed. + # + # @example + # # bad + # instance_double('User', name: 'John') + # + # # good + # instance_double(User, name: 'John') + # + class StringAsInstanceDoubleConstant < 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 $str ...) + PATTERN + + def on_send(node) + stringified_instance_double_const?(node) do |args_node| + add_offense(args_node) do |corrector| + autocorrect(corrector, args_node) + 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..85c177e8e 100644 --- a/lib/rubocop/cop/rspec_cops.rb +++ b/lib/rubocop/cop/rspec_cops.rb @@ -99,6 +99,7 @@ require_relative 'rspec/sort_metadata' require_relative 'rspec/spec_file_path_format' require_relative 'rspec/spec_file_path_suffix' +require_relative 'rspec/string_as_instance_double_constant' require_relative 'rspec/stubbed_mock' require_relative 'rspec/subject_declaration' require_relative 'rspec/subject_stub' diff --git a/spec/rubocop/cop/rspec/string_as_instance_double_constant_spec.rb b/spec/rubocop/cop/rspec/string_as_instance_double_constant_spec.rb new file mode 100644 index 000000000..8f19ada94 --- /dev/null +++ b/spec/rubocop/cop/rspec/string_as_instance_double_constant_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::Cop::RSpec::StringAsInstanceDoubleConstant, + :config do + context 'when using a class for instance_double' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + instance_double(Shape, area: 12) + RUBY + end + end + + context 'when passing a variable to initialize instance_double' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + instance_double(type_undetectable_in_static_analysis) + RUBY + end + end + + context 'when using a string for instance_double' do + it 'replaces the string with the class' do + expect_offense <<~RUBY + instance_double('Shape', area: 12) + ^^^^^^^ Do not use a string as `instance_double` constant. + RUBY + + expect_correction <<~RUBY + instance_double(Shape, area: 12) + RUBY + end + end +end From 34c042e40092a8f92990bbc0a338e01f15057f28 Mon Sep 17 00:00:00 2001 From: Benjamin Quorning Date: Tue, 1 Oct 2024 12:13:00 +0200 Subject: [PATCH 006/105] Bump version to v3.1.0 --- CHANGELOG.md | 2 ++ config/default.yml | 2 +- docs/antora.yml | 2 +- docs/modules/ROOT/pages/cops_rspec.adoc | 2 +- lib/rubocop/rspec/version.rb | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf2338aee..93499ceaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +## 3.1.0 (2024-10-01) + - Add `RSpec/StringAsInstanceDoubleConstant` to check for and correct strings used as instance_doubles. ([@corsonknowles]) - Fix false-positive for `RSpec/UnspecifiedException` when a method is literally named `raise_exception`. ([@aarestad]) - Fix false-positive for `RSpec/UnspecifiedException` when `not_to raise_error` is used within a block. ([@aarestad], [@G-Rath]) diff --git a/config/default.yml b/config/default.yml index 7e6e742b4..c62b2f138 100644 --- a/config/default.yml +++ b/config/default.yml @@ -933,7 +933,7 @@ RSpec/StringAsInstanceDoubleConstant: Description: Do not use a string as `instance_double` constant. Enabled: pending Safe: false - VersionAdded: "<>" + VersionAdded: '3.1' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/StringAsInstanceDoubleConstant RSpec/StubbedMock: diff --git a/docs/antora.yml b/docs/antora.yml index 51a533a15..bac2f797a 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -1,5 +1,5 @@ name: rubocop-rspec title: RuboCop RSpec -version: ~ +version: '3.1' nav: - modules/ROOT/nav.adoc diff --git a/docs/modules/ROOT/pages/cops_rspec.adoc b/docs/modules/ROOT/pages/cops_rspec.adoc index 01240298c..2aff167af 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -5501,7 +5501,7 @@ spec/models/user.rb # shared_examples_for 'foo' | Pending | No | Always (Unsafe) -| <> +| 3.1 | - |=== diff --git a/lib/rubocop/rspec/version.rb b/lib/rubocop/rspec/version.rb index 554e79ce9..334b1761a 100644 --- a/lib/rubocop/rspec/version.rb +++ b/lib/rubocop/rspec/version.rb @@ -4,7 +4,7 @@ module RuboCop module RSpec # Version information for the RSpec RuboCop plugin. module Version - STRING = '3.0.5' + STRING = '3.1.0' end end end From f1bd410d926252853f5bcdd418fb0e5599894ac3 Mon Sep 17 00:00:00 2001 From: bquorning Date: Tue, 1 Oct 2024 13:43:33 +0000 Subject: [PATCH 007/105] Switch docs version back --- docs/antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/antora.yml b/docs/antora.yml index bac2f797a..51a533a15 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -1,5 +1,5 @@ name: rubocop-rspec title: RuboCop RSpec -version: '3.1' +version: ~ nav: - modules/ROOT/nav.adoc From a4e43cb9c338251f8b6b1d5767ce6f9de3cc1c6e Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Tue, 8 Oct 2024 14:10:05 +0200 Subject: [PATCH 008/105] Link related style guide for RSpec/ExampleWithoutDescription --- config/default.yml | 1 + docs/modules/ROOT/pages/cops_rspec.adoc | 1 + 2 files changed, 2 insertions(+) diff --git a/config/default.yml b/config/default.yml index c62b2f138..6c09b7d72 100644 --- a/config/default.yml +++ b/config/default.yml @@ -403,6 +403,7 @@ RSpec/ExampleWithoutDescription: - single_line_only - disallow VersionAdded: '1.22' + StyleGuide: https://rspec.rubystyle.guide/#it-and-specify Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleWithoutDescription RSpec/ExampleWording: diff --git a/docs/modules/ROOT/pages/cops_rspec.adoc b/docs/modules/ROOT/pages/cops_rspec.adoc index 2aff167af..cf421a9a1 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -1775,6 +1775,7 @@ end === References +* https://rspec.rubystyle.guide/#it-and-specify * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleWithoutDescription == RSpec/ExampleWording From c52269be7e13daee673feb250a66089388eee9e7 Mon Sep 17 00:00:00 2001 From: ydah Date: Mon, 14 Oct 2024 11:09:01 +0900 Subject: [PATCH 009/105] Fix a failed test in hook_spec.rb use ruby-head see: https://github.com/rubocop/rubocop-rspec/actions/runs/11319581327/job/31475851856 --- spec/rubocop/rspec/hook_spec.rb | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/spec/rubocop/rspec/hook_spec.rb b/spec/rubocop/rspec/hook_spec.rb index dffb7d63d..ad9493527 100644 --- a/spec/rubocop/rspec/hook_spec.rb +++ b/spec/rubocop/rspec/hook_spec.rb @@ -74,24 +74,32 @@ def metadata(source) hook(source).metadata.to_s end + if RUBY_VERSION >= '3.4' + let(:expected_special) { 's(:sym, :special) => true' } + let(:expected_symbol) { 's(:sym, :symbol) => true' } + else + let(:expected_special) { 's(:sym, :special)=>true' } + let(:expected_symbol) { 's(:sym, :symbol)=>true' } + end + it 'extracts symbol metadata' do expect(metadata('before(:example, :special) { foo }')) - .to eq('{s(:sym, :special)=>true}') + .to eq("{#{expected_special}}") end it 'extracts hash metadata' do expect(metadata('before(:example, special: true) { foo }')) - .to eq('{s(:sym, :special)=>true}') + .to eq("{#{expected_special}}") end it 'combines symbol and hash metadata' do expect(metadata('before(:example, :symbol, special: true) { foo }')) - .to eq('{s(:sym, :symbol)=>true, s(:sym, :special)=>true}') + .to eq("{#{expected_symbol}, #{expected_special}}") end it 'extracts hash metadata with no scope given' do expect(metadata('before(special: true) { foo }')) - .to eq('{s(:sym, :special)=>true}') + .to eq("{#{expected_special}}") end it 'withstands no arguments' do From d3e4268136201f60deba051939b5b92e6f2c3168 Mon Sep 17 00:00:00 2001 From: Dave Corson-Knowles Date: Sun, 13 Oct 2024 05:22:40 -0700 Subject: [PATCH 010/105] Complete branch coverage for VoidExpect and ContextWording --- spec/rubocop/cop/rspec/context_wording_spec.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/spec/rubocop/cop/rspec/context_wording_spec.rb b/spec/rubocop/cop/rspec/context_wording_spec.rb index 5896110af..340d10181 100644 --- a/spec/rubocop/cop/rspec/context_wording_spec.rb +++ b/spec/rubocop/cop/rspec/context_wording_spec.rb @@ -214,4 +214,17 @@ end end end + + context 'when `AllowedPatterns:` and `Prefixes:` are both empty' do + let(:cop_config) do + { 'Prefixes' => [], 'AllowedPatterns' => [] } + end + + it 'skips any description' do + expect_no_offenses(<<~RUBY) + context 'arbitrary text' do + end + RUBY + end + end end From 5c8fef3b136e1866642b84b6690b0538b31ae341 Mon Sep 17 00:00:00 2001 From: Dave Corson-Knowles Date: Sun, 13 Oct 2024 03:46:04 -0700 Subject: [PATCH 011/105] Complete 100 line coverage for Metadata mixin This adds a final spec to cover an intentionally unimplemented method. --- spec/rubocop/cop/rspec/mixin/metadata_spec.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 spec/rubocop/cop/rspec/mixin/metadata_spec.rb diff --git a/spec/rubocop/cop/rspec/mixin/metadata_spec.rb b/spec/rubocop/cop/rspec/mixin/metadata_spec.rb new file mode 100644 index 000000000..df51b1c80 --- /dev/null +++ b/spec/rubocop/cop/rspec/mixin/metadata_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::Cop::RSpec::Metadata do + describe '#on_metadata' do + subject(:on_metadata) do + stub_class.new.on_metadata(:symbol, {}) + end + + let(:stub_class) do + Class.new do + include RuboCop::Cop::RSpec::Metadata + end + end + + it { expect { on_metadata }.to raise_error(NotImplementedError) } + end +end From 1278b73d183696e27419b203efd8872ca33da33c Mon Sep 17 00:00:00 2001 From: ydah Date: Wed, 16 Oct 2024 22:50:02 +0900 Subject: [PATCH 012/105] Fix problem with `Open3.popen3` where `confirm_documentation` task never finishes waiting for child processes see: https://github.com/rubocop/rubocop-rspec/actions/runs/11360936578/job/31599655573 --- Rakefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Rakefile b/Rakefile index a91382b68..59d02a4b6 100644 --- a/Rakefile +++ b/Rakefile @@ -72,10 +72,10 @@ end desc 'Confirm documentation is up to date' task confirm_documentation: :generate_cops_documentation do - _, _, _, process = - Open3.popen3('git diff --exit-code docs/') + _, _, status = + Open3.capture3('git diff --exit-code docs/') - unless process.value.success? + unless status.success? raise 'Please run `rake generate_cops_documentation` ' \ 'and add docs/ to the commit.' end From 5a99401f4a4490c49d9446345b82efa8ce2b1f4b Mon Sep 17 00:00:00 2001 From: ydah Date: Wed, 16 Oct 2024 22:50:45 +0900 Subject: [PATCH 013/105] Improve `confirm_documentation` task to display out-of-sync documentation --- Rakefile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Rakefile b/Rakefile index 59d02a4b6..23d584ed0 100644 --- a/Rakefile +++ b/Rakefile @@ -72,12 +72,15 @@ end desc 'Confirm documentation is up to date' task confirm_documentation: :generate_cops_documentation do - _, _, status = + stdout, _stderr, status = Open3.capture3('git diff --exit-code docs/') unless status.success? - raise 'Please run `rake generate_cops_documentation` ' \ - 'and add docs/ to the commit.' + warn 'Documentation is out of sync:' + warn stdout + warn 'Please run `rake generate_cops_documentation` ' \ + 'and add docs/ to the commit.' + exit 1 end end From 9e4855ff9c0f05d711529dd3c7270b27244ebc21 Mon Sep 17 00:00:00 2001 From: ydah Date: Wed, 16 Oct 2024 22:50:52 +0900 Subject: [PATCH 014/105] bundle exec rake generate_cops_documentation --- docs/modules/ROOT/pages/cops_rspec.adoc | 459 ++++++++++++++++++++++++ 1 file changed, 459 insertions(+) diff --git a/docs/modules/ROOT/pages/cops_rspec.adoc b/docs/modules/ROOT/pages/cops_rspec.adoc index cf421a9a1..5556dd086 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -6,6 +6,7 @@ = RSpec +[#rspecalignleftletbrace] == RSpec/AlignLeftLetBrace |=== @@ -20,6 +21,7 @@ Checks that left braces for adjacent single line lets are aligned. +[#examples-rspecalignleftletbrace] === Examples [source,ruby] @@ -35,10 +37,12 @@ let(:baz) { bar } let(:a) { b } ---- +[#references-rspecalignleftletbrace] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AlignLeftLetBrace +[#rspecalignrightletbrace] == RSpec/AlignRightLetBrace |=== @@ -53,6 +57,7 @@ let(:a) { b } Checks that right braces for adjacent single line lets are aligned. +[#examples-rspecalignrightletbrace] === Examples [source,ruby] @@ -68,10 +73,12 @@ let(:baz) { bar } let(:a) { b } ---- +[#references-rspecalignrightletbrace] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AlignRightLetBrace +[#rspecanyinstance] == RSpec/AnyInstance |=== @@ -88,6 +95,7 @@ Check that instances are not being stubbed globally. Prefer instance doubles over stubbing any instance of a class +[#examples-rspecanyinstance] === Examples [source,ruby] @@ -108,11 +116,13 @@ describe MyClass do end ---- +[#references-rspecanyinstance] === References * https://rspec.rubystyle.guide/#any_instance_of * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AnyInstance +[#rspecaroundblock] == RSpec/AroundBlock |=== @@ -127,6 +137,7 @@ end Checks that around blocks actually run the test. +[#examples-rspecaroundblock] === Examples [source,ruby] @@ -152,10 +163,12 @@ around do |test| end ---- +[#references-rspecaroundblock] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AroundBlock +[#rspecbe] == RSpec/Be |=== @@ -174,6 +187,7 @@ The `be` matcher is too generic, as it pass on everything that is not nil or false. If that is the exact intend, use `be_truthy`. In all other cases it's better to specify what exactly is the expected value. +[#examples-rspecbe] === Examples [source,ruby] @@ -187,11 +201,13 @@ expect(foo).to be 1.0 expect(foo).to be(true) ---- +[#references-rspecbe] === References * https://rspec.rubystyle.guide/#be-matcher * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Be +[#rspecbeempty] == RSpec/BeEmpty |=== @@ -206,6 +222,7 @@ expect(foo).to be(true) Prefer using `be_empty` when checking for an empty array. +[#examples-rspecbeempty] === Examples [source,ruby] @@ -218,10 +235,12 @@ expect(array).to match_array([]) expect(array).to be_empty ---- +[#references-rspecbeempty] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeEmpty +[#rspecbeeq] == RSpec/BeEq |=== @@ -240,10 +259,12 @@ The `be` matcher compares by identity while the `eq` matcher compares using `==`. Booleans and nil can be compared by identity and therefore the `be` matcher is preferable as it is a more strict test. +[#safety-rspecbeeq] === Safety This cop is unsafe because it changes how values are compared. +[#examples-rspecbeeq] === Examples [source,ruby] @@ -259,10 +280,12 @@ expect(foo).to be(false) expect(foo).to be(nil) ---- +[#references-rspecbeeq] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeEq +[#rspecbeeql] == RSpec/BeEql |=== @@ -289,10 +312,12 @@ than `!equal?`. We also do not try to flag `eq` because if necessarily the same type as `b` since the `#==` operator can coerce objects for comparison. +[#safety-rspecbeeql] === Safety This cop is unsafe because it changes how values are compared. +[#examples-rspecbeeql] === Examples [source,ruby] @@ -314,10 +339,12 @@ expect(foo).to be(:bar) expect(foo).to be(nil) ---- +[#references-rspecbeeql] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeEql +[#rspecbenil] == RSpec/BeNil |=== @@ -337,8 +364,10 @@ generic `be` matcher with a `nil` argument. This cop can be configured using the `EnforcedStyle` option +[#examples-rspecbenil] === Examples +[#_enforcedstyle_-be_nil_-_default_-rspecbenil] ==== `EnforcedStyle: be_nil` (default) [source,ruby] @@ -350,6 +379,7 @@ expect(foo).to be(nil) expect(foo).to be_nil ---- +[#_enforcedstyle_-be_-rspecbenil] ==== `EnforcedStyle: be` [source,ruby] @@ -361,6 +391,7 @@ expect(foo).to be_nil expect(foo).to be(nil) ---- +[#configurable-attributes-rspecbenil] === Configurable attributes |=== @@ -371,10 +402,12 @@ expect(foo).to be(nil) | `be`, `be_nil` |=== +[#references-rspecbenil] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeNil +[#rspecbeforeafterall] == RSpec/BeforeAfterAll |=== @@ -389,6 +422,7 @@ expect(foo).to be(nil) Check that before/after(:all/:context) isn't being used. +[#examples-rspecbeforeafterall] === Examples [source,ruby] @@ -406,6 +440,7 @@ describe MyClass do end ---- +[#configurable-attributes-rspecbeforeafterall] === Configurable attributes |=== @@ -416,11 +451,13 @@ end | Array |=== +[#references-rspecbeforeafterall] === References * https://rspec.rubystyle.guide/#avoid-hooks-with-context-scope * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeforeAfterAll +[#rspecchangebyzero] == RSpec/ChangeByZero |=== @@ -443,8 +480,10 @@ compound expectations, but if you set the negated matcher for `change`, e.g. `not_change` with the `NegatedMatcher` option, the cop will perform the autocorrection. +[#examples-rspecchangebyzero] === Examples +[#negatedmatcher_-_-_default_-rspecchangebyzero] ==== NegatedMatcher: ~ (default) [source,ruby] @@ -475,6 +514,7 @@ expect { run } .and not_change { Foo.baz } ---- +[#negatedmatcher_-not_change-rspecchangebyzero] ==== NegatedMatcher: not_change [source,ruby] @@ -497,6 +537,7 @@ expect { run } .and not_change { Foo.baz } ---- +[#configurable-attributes-rspecchangebyzero] === Configurable attributes |=== @@ -507,10 +548,12 @@ expect { run } | |=== +[#references-rspecchangebyzero] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ChangeByZero +[#rspecclasscheck] == RSpec/ClassCheck |=== @@ -525,8 +568,10 @@ expect { run } Enforces consistent use of `be_a` or `be_kind_of`. +[#examples-rspecclasscheck] === Examples +[#enforcedstyle_-be_a-_default_-rspecclasscheck] ==== EnforcedStyle: be_a (default) [source,ruby] @@ -540,6 +585,7 @@ expect(object).to be_a(String) expect(object).to be_an(String) ---- +[#enforcedstyle_-be_kind_of-rspecclasscheck] ==== EnforcedStyle: be_kind_of [source,ruby] @@ -553,6 +599,7 @@ expect(object).to be_kind_of(String) expect(object).to be_a_kind_of(String) ---- +[#configurable-attributes-rspecclasscheck] === Configurable attributes |=== @@ -563,11 +610,13 @@ expect(object).to be_a_kind_of(String) | `be_a`, `be_kind_of` |=== +[#references-rspecclasscheck] === References * https://rubystyle.guide#is-a-vs-kind-of * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ClassCheck +[#rspeccontainexactly] == RSpec/ContainExactly |=== @@ -586,6 +635,7 @@ This cop checks for the following: - Prefer `match_array` when matching array values. - Prefer `be_empty` when using `contain_exactly` with no arguments. +[#examples-rspeccontainexactly] === Examples [source,ruby] @@ -600,10 +650,12 @@ it { is_expected.to match_array(array1 + array2) } it { is_expected.to contain_exactly(content, *array) } ---- +[#references-rspeccontainexactly] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContainExactly +[#rspeccontextmethod] == RSpec/ContextMethod |=== @@ -618,6 +670,7 @@ it { is_expected.to contain_exactly(content, *array) } `context` should not be used for specifying methods. +[#examples-rspeccontextmethod] === Examples [source,ruby] @@ -641,11 +694,13 @@ describe '.foo_bar' do end ---- +[#references-rspeccontextmethod] === References * https://rspec.rubystyle.guide/#example-group-naming * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextMethod +[#rspeccontextwording] == RSpec/ContextWording |=== @@ -668,8 +723,10 @@ They may consist of multiple words if desired. This cop can be customized allowed context description pattern with `AllowedPatterns`. By default, there are no checking by pattern. +[#examples-rspeccontextwording] === Examples +[#_prefixes_-configuration-rspeccontextwording] ==== `Prefixes` configuration [source,ruby] @@ -698,6 +755,7 @@ context 'when the display name is not present' do end ---- +[#_allowedpatterns_-configuration-rspeccontextwording] ==== `AllowedPatterns` configuration [source,ruby] @@ -721,6 +779,7 @@ context '条件を満たすとき' do end ---- +[#configurable-attributes-rspeccontextwording] === Configurable attributes |=== @@ -735,12 +794,14 @@ end | Array |=== +[#references-rspeccontextwording] === References * https://rspec.rubystyle.guide/#context-descriptions * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextWording * http://www.betterspecs.org/#contexts +[#rspecdescribeclass] == RSpec/DescribeClass |=== @@ -759,8 +820,10 @@ It can be configured to ignore strings when certain metadata is passed. Ignores Rails and Aruba `type` metadata by default. +[#examples-rspecdescribeclass] === Examples +[#_ignoredmetadata_-configuration-rspecdescribeclass] ==== `IgnoredMetadata` configuration [source,ruby] @@ -792,6 +855,7 @@ describe "A feature example", type: :feature do end ---- +[#configurable-attributes-rspecdescribeclass] === Configurable attributes |=== @@ -806,10 +870,12 @@ end | |=== +[#references-rspecdescribeclass] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeClass +[#rspecdescribemethod] == RSpec/DescribeMethod |=== @@ -824,6 +890,7 @@ end Checks that the second argument to `describe` specifies a method. +[#examples-rspecdescribemethod] === Examples [source,ruby] @@ -840,10 +907,12 @@ describe MyClass, '.my_class_method' do end ---- +[#references-rspecdescribemethod] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeMethod +[#rspecdescribesymbol] == RSpec/DescribeSymbol |=== @@ -858,6 +927,7 @@ end Avoid describing symbols. +[#examples-rspecdescribesymbol] === Examples [source,ruby] @@ -873,11 +943,13 @@ describe '#my_method' do end ---- +[#references-rspecdescribesymbol] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeSymbol * https://github.com/rspec/rspec-core/issues/1610 +[#rspecdescribedclass] == RSpec/DescribedClass |=== @@ -909,8 +981,10 @@ To narrow down this setting to only a specific directory, it is possible to use an overriding configuration file local to that directory. +[#examples-rspecdescribedclass] === Examples +[#_enforcedstyle_-described_class_-_default_-rspecdescribedclass] ==== `EnforcedStyle: described_class` (default) [source,ruby] @@ -926,6 +1000,7 @@ describe MyClass do end ---- +[#_onlystaticconstants_-true_-_default_-rspecdescribedclass] ==== `OnlyStaticConstants: true` (default) [source,ruby] @@ -936,6 +1011,7 @@ describe MyClass do end ---- +[#_onlystaticconstants_-false_-rspecdescribedclass] ==== `OnlyStaticConstants: false` [source,ruby] @@ -946,6 +1022,7 @@ describe MyClass do end ---- +[#_enforcedstyle_-explicit_-rspecdescribedclass] ==== `EnforcedStyle: explicit` [source,ruby] @@ -961,6 +1038,7 @@ describe MyClass do end ---- +[#_skipblocks_-true_-rspecdescribedclass] ==== `SkipBlocks: true` [source,ruby] @@ -977,6 +1055,7 @@ describe MyConcern do end ---- +[#configurable-attributes-rspecdescribedclass] === Configurable attributes |=== @@ -995,10 +1074,12 @@ end | Boolean |=== +[#references-rspecdescribedclass] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribedClass +[#rspecdescribedclassmodulewrapping] == RSpec/DescribedClassModuleWrapping |=== @@ -1013,6 +1094,7 @@ end Avoid opening modules and defining specs within them. +[#examples-rspecdescribedclassmodulewrapping] === Examples [source,ruby] @@ -1030,11 +1112,13 @@ RSpec.describe MyModule::MyClass do end ---- +[#references-rspecdescribedclassmodulewrapping] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribedClassModuleWrapping * https://github.com/rubocop/rubocop-rspec/issues/735 +[#rspecdialect] == RSpec/Dialect |=== @@ -1088,6 +1172,7 @@ native RSpec method (e.g. are just aliases), use the following config: You can expect the following behavior: +[#examples-rspecdialect] === Examples [source,ruby] @@ -1103,6 +1188,7 @@ describe 'display name presence' do end ---- +[#configurable-attributes-rspecdialect] === Configurable attributes |=== @@ -1113,10 +1199,12 @@ end | |=== +[#references-rspecdialect] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Dialect +[#rspecduplicatedmetadata] == RSpec/DuplicatedMetadata |=== @@ -1131,6 +1219,7 @@ end Avoid duplicated metadata. +[#examples-rspecduplicatedmetadata] === Examples [source,ruby] @@ -1142,10 +1231,12 @@ describe 'Something', :a, :a describe 'Something', :a ---- +[#references-rspecduplicatedmetadata] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DuplicatedMetadata +[#rspecemptyexamplegroup] == RSpec/EmptyExampleGroup |=== @@ -1160,8 +1251,10 @@ describe 'Something', :a Checks if an example group does not include any tests. +[#examples-rspecemptyexamplegroup] === Examples +[#usage-rspecemptyexamplegroup] ==== usage [source,ruby] @@ -1196,10 +1289,12 @@ describe Bacon do end ---- +[#references-rspecemptyexamplegroup] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyExampleGroup +[#rspecemptyhook] == RSpec/EmptyHook |=== @@ -1214,6 +1309,7 @@ end Checks for empty before and after hooks. +[#examples-rspecemptyhook] === Examples [source,ruby] @@ -1236,10 +1332,12 @@ end after(:all) { cleanup_feed } ---- +[#references-rspecemptyhook] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyHook +[#rspecemptylineafterexample] == RSpec/EmptyLineAfterExample |=== @@ -1254,6 +1352,7 @@ after(:all) { cleanup_feed } Checks if there is an empty line after example blocks. +[#examples-rspecemptylineafterexample] === Examples [source,ruby] @@ -1282,6 +1381,7 @@ RSpec.describe Foo do end ---- +[#with-allowconsecutiveoneliners-configuration-rspecemptylineafterexample] ==== with AllowConsecutiveOneLiners configuration [source,ruby] @@ -1297,6 +1397,7 @@ RSpec.describe Foo do end ---- +[#configurable-attributes-rspecemptylineafterexample] === Configurable attributes |=== @@ -1307,11 +1408,13 @@ end | Boolean |=== +[#references-rspecemptylineafterexample] === References * https://rspec.rubystyle.guide/#empty-lines-around-examples * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterExample +[#rspecemptylineafterexamplegroup] == RSpec/EmptyLineAfterExampleGroup |=== @@ -1326,6 +1429,7 @@ end Checks if there is an empty line after example group blocks. +[#examples-rspecemptylineafterexamplegroup] === Examples [source,ruby] @@ -1348,11 +1452,13 @@ RSpec.describe Foo do end ---- +[#references-rspecemptylineafterexamplegroup] === References * https://rspec.rubystyle.guide/#empty-lines-between-describes * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterExampleGroup +[#rspecemptylineafterfinallet] == RSpec/EmptyLineAfterFinalLet |=== @@ -1367,6 +1473,7 @@ end Checks if there is an empty line after the last let block. +[#examples-rspecemptylineafterfinallet] === Examples [source,ruby] @@ -1383,11 +1490,13 @@ let(:something) { other } it { does_something } ---- +[#references-rspecemptylineafterfinallet] === References * https://rspec.rubystyle.guide/#empty-line-after-let * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterFinalLet +[#rspecemptylineafterhook] == RSpec/EmptyLineAfterHook |=== @@ -1405,6 +1514,7 @@ Checks if there is an empty line after hook blocks. `AllowConsecutiveOneLiners` configures whether adjacent one-line definitions are considered an offense. +[#examples-rspecemptylineafterhook] === Examples [source,ruby] @@ -1433,6 +1543,7 @@ after { do_something } it { does_something } ---- +[#with-allowconsecutiveoneliners-configuration-rspecemptylineafterhook] ==== with AllowConsecutiveOneLiners configuration [source,ruby] @@ -1455,6 +1566,7 @@ after { do_something } it { does_something } ---- +[#configurable-attributes-rspecemptylineafterhook] === Configurable attributes |=== @@ -1465,11 +1577,13 @@ it { does_something } | Boolean |=== +[#references-rspecemptylineafterhook] === References * https://rspec.rubystyle.guide/#empty-line-after-let * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterHook +[#rspecemptylineaftersubject] == RSpec/EmptyLineAfterSubject |=== @@ -1484,6 +1598,7 @@ it { does_something } Checks if there is an empty line after subject block. +[#examples-rspecemptylineaftersubject] === Examples [source,ruby] @@ -1498,11 +1613,13 @@ subject(:obj) { described_class } let(:foo) { bar } ---- +[#references-rspecemptylineaftersubject] === References * https://rspec.rubystyle.guide/#empty-line-after-let * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterSubject +[#rspecemptymetadata] == RSpec/EmptyMetadata |=== @@ -1517,8 +1634,10 @@ let(:foo) { bar } Avoid empty metadata hash. +[#examples-rspecemptymetadata] === Examples +[#enforcedstyle_-symbol-_default_-rspecemptymetadata] ==== EnforcedStyle: symbol (default) [source,ruby] @@ -1530,10 +1649,12 @@ describe 'Something', {} describe 'Something' ---- +[#references-rspecemptymetadata] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyMetadata +[#rspecemptyoutput] == RSpec/EmptyOutput |=== @@ -1548,6 +1669,7 @@ describe 'Something' Check that the `output` matcher is not called with an empty string. +[#examples-rspecemptyoutput] === Examples [source,ruby] @@ -1561,10 +1683,12 @@ expect { foo }.not_to output.to_stdout expect { bar }.to output.to_stderr ---- +[#references-rspecemptyoutput] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyOutput +[#rspeceq] == RSpec/Eq |=== @@ -1579,6 +1703,7 @@ expect { bar }.to output.to_stderr Use `eq` instead of `be ==` to compare objects. +[#examples-rspeceq] === Examples [source,ruby] @@ -1590,10 +1715,12 @@ expect(foo).to be == 42 expect(foo).to eq 42 ---- +[#references-rspeceq] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Eq +[#rspecexamplelength] == RSpec/ExampleLength |=== @@ -1617,6 +1744,7 @@ Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct will be counted as one line regardless of its actual size. +[#examples-rspecexamplelength] === Examples [source,ruby] @@ -1638,6 +1766,7 @@ it do end ---- +[#countasone_-__array__-_heredoc__-_method_call__-rspecexamplelength] ==== CountAsOne: ['array', 'heredoc', 'method_call'] [source,ruby] @@ -1664,6 +1793,7 @@ it do end # 6 points ---- +[#configurable-attributes-rspecexamplelength] === Configurable attributes |=== @@ -1678,10 +1808,12 @@ end # 6 points | Array |=== +[#references-rspecexamplelength] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleLength +[#rspecexamplewithoutdescription] == RSpec/ExampleWithoutDescription |=== @@ -1706,6 +1838,7 @@ on the configured style. This cop can be configured using the `EnforcedStyle` option +[#examples-rspecexamplewithoutdescription] === Examples [source,ruby] @@ -1717,6 +1850,7 @@ specify do end ---- +[#_enforcedstyle_-always_allow_-_default_-rspecexamplewithoutdescription] ==== `EnforcedStyle: always_allow` (default) [source,ruby] @@ -1736,6 +1870,7 @@ specify do end ---- +[#_enforcedstyle_-single_line_only_-rspecexamplewithoutdescription] ==== `EnforcedStyle: single_line_only` [source,ruby] @@ -1751,6 +1886,7 @@ end it { is_expected.to be_good } ---- +[#_enforcedstyle_-disallow_-rspecexamplewithoutdescription] ==== `EnforcedStyle: disallow` [source,ruby] @@ -1763,6 +1899,7 @@ it do end ---- +[#configurable-attributes-rspecexamplewithoutdescription] === Configurable attributes |=== @@ -1773,11 +1910,13 @@ end | `always_allow`, `single_line_only`, `disallow` |=== +[#references-rspecexamplewithoutdescription] === References * https://rspec.rubystyle.guide/#it-and-specify * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleWithoutDescription +[#rspecexamplewording] == RSpec/ExampleWording |=== @@ -1802,6 +1941,7 @@ Use the DisallowedExamples setting to prevent unclear or insufficient descriptions. Please note that this config will not be treated as case sensitive. +[#examples-rspecexamplewording] === Examples [source,ruby] @@ -1829,6 +1969,7 @@ it 'does things' do end ---- +[#_disallowedexamples_-__works___-_default_-rspecexamplewording] ==== `DisallowedExamples: ['works']` (default) [source,ruby] @@ -1842,6 +1983,7 @@ it 'marks the task as done' do end ---- +[#configurable-attributes-rspecexamplewording] === Configurable attributes |=== @@ -1860,12 +2002,14 @@ end | Array |=== +[#references-rspecexamplewording] === References * https://rspec.rubystyle.guide/#should-in-example-docstrings * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleWording * http://betterspecs.org/#should +[#rspecexcessivedocstringspacing] == RSpec/ExcessiveDocstringSpacing |=== @@ -1880,6 +2024,7 @@ end Checks for excessive whitespace in example descriptions. +[#examples-rspecexcessivedocstringspacing] === Examples [source,ruby] @@ -1904,10 +2049,12 @@ context 'when a condition is met' do end ---- +[#references-rspecexcessivedocstringspacing] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExcessiveDocstringSpacing +[#rspecexpectactual] == RSpec/ExpectActual |=== @@ -1924,6 +2071,7 @@ Checks for `expect(...)` calls containing literal values. Autocorrection is performed when the expected is not a literal. +[#examples-rspecexpectactual] === Examples [source,ruby] @@ -1942,6 +2090,7 @@ expect(name).to eq("John") expect(false).to eq(true) ---- +[#configurable-attributes-rspecexpectactual] === Configurable attributes |=== @@ -1952,10 +2101,12 @@ expect(false).to eq(true) | Array |=== +[#references-rspecexpectactual] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectActual +[#rspecexpectchange] == RSpec/ExpectChange |=== @@ -1975,8 +2126,10 @@ or passing a block that reads the attribute value. This cop can be configured using the `EnforcedStyle` option. +[#examples-rspecexpectchange] === Examples +[#_enforcedstyle_-method_call_-_default_-rspecexpectchange] ==== `EnforcedStyle: method_call` (default) [source,ruby] @@ -1993,6 +2146,7 @@ expect { run }.to change { Foo.bar(:count) } expect { run }.to change { user.reload.name } ---- +[#_enforcedstyle_-block_-rspecexpectchange] ==== `EnforcedStyle: block` [source,ruby] @@ -2004,6 +2158,7 @@ expect { run }.to change(Foo, :bar) expect { run }.to change { Foo.bar } ---- +[#configurable-attributes-rspecexpectchange] === Configurable attributes |=== @@ -2014,10 +2169,12 @@ expect { run }.to change { Foo.bar } | `method_call`, `block` |=== +[#references-rspecexpectchange] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectChange +[#rspecexpectinhook] == RSpec/ExpectInHook |=== @@ -2032,6 +2189,7 @@ expect { run }.to change { Foo.bar } Do not use `expect` in hooks such as `before`. +[#examples-rspecexpectinhook] === Examples [source,ruby] @@ -2052,10 +2210,12 @@ it do end ---- +[#references-rspecexpectinhook] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectInHook +[#rspecexpectinlet] == RSpec/ExpectInLet |=== @@ -2070,6 +2230,7 @@ end Do not use `expect` in let. +[#examples-rspecexpectinlet] === Examples [source,ruby] @@ -2085,10 +2246,12 @@ it do end ---- +[#references-rspecexpectinlet] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectInLet +[#rspecexpectoutput] == RSpec/ExpectOutput |=== @@ -2103,6 +2266,7 @@ end Checks for opportunities to use `expect { ... }.to output`. +[#examples-rspecexpectoutput] === Examples [source,ruby] @@ -2117,10 +2281,12 @@ expect($stdout.string).to eq('Hello World') expect { my_app.print_report }.to output('Hello World').to_stdout ---- +[#references-rspecexpectoutput] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectOutput +[#rspecfocus] == RSpec/Focus |=== @@ -2137,6 +2303,7 @@ Checks if examples are focused. This cop does not support autocorrection in some cases. +[#examples-rspecfocus] === Examples [source,ruby] @@ -2183,10 +2350,12 @@ shared_context 'test' do; end focus 'test' do; end ---- +[#references-rspecfocus] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Focus +[#rspechookargument] == RSpec/HookArgument |=== @@ -2206,8 +2375,10 @@ hooks which run for each example. There are three supported styles: "implicit", "each", and "example." All styles have the same behavior. +[#examples-rspechookargument] === Examples +[#_enforcedstyle_-implicit_-_default_-rspechookargument] ==== `EnforcedStyle: implicit` (default) [source,ruby] @@ -2228,6 +2399,7 @@ before do end ---- +[#_enforcedstyle_-each_-rspechookargument] ==== `EnforcedStyle: each` [source,ruby] @@ -2248,6 +2420,7 @@ before(:each) do end ---- +[#_enforcedstyle_-example_-rspechookargument] ==== `EnforcedStyle: example` [source,ruby] @@ -2268,6 +2441,7 @@ before(:example) do end ---- +[#configurable-attributes-rspechookargument] === Configurable attributes |=== @@ -2278,11 +2452,13 @@ end | `implicit`, `each`, `example` |=== +[#references-rspechookargument] === References * https://rspec.rubystyle.guide/#redundant-beforeeach * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/HookArgument +[#rspechooksbeforeexamples] == RSpec/HooksBeforeExamples |=== @@ -2297,6 +2473,7 @@ end Checks for before/around/after hooks that come after an example. +[#examples-rspechooksbeforeexamples] === Examples [source,ruby] @@ -2318,10 +2495,12 @@ it 'checks what foo does' do end ---- +[#references-rspechooksbeforeexamples] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/HooksBeforeExamples +[#rspecidenticalequalityassertion] == RSpec/IdenticalEqualityAssertion |=== @@ -2336,6 +2515,7 @@ end Checks for equality assertions with identical expressions on both sides. +[#examples-rspecidenticalequalityassertion] === Examples [source,ruby] @@ -2349,10 +2529,12 @@ expect(foo.bar).to eq(2) expect(foo.bar).to eql(2) ---- +[#references-rspecidenticalequalityassertion] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IdenticalEqualityAssertion +[#rspecimplicitblockexpectation] == RSpec/ImplicitBlockExpectation |=== @@ -2369,6 +2551,7 @@ Check that implicit block expectation syntax is not used. Prefer using explicit block expectations. +[#examples-rspecimplicitblockexpectation] === Examples [source,ruby] @@ -2383,11 +2566,13 @@ it 'changes something to a new value' do end ---- +[#references-rspecimplicitblockexpectation] === References * https://rspec.rubystyle.guide/#implicit-block-expectations * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitBlockExpectation +[#rspecimplicitexpect] == RSpec/ImplicitExpect |=== @@ -2405,8 +2590,10 @@ Check that a consistent implicit expectation style is used. This cop can be configured using the `EnforcedStyle` option and supports the `--auto-gen-config` flag. +[#examples-rspecimplicitexpect] === Examples +[#_enforcedstyle_-is_expected_-_default_-rspecimplicitexpect] ==== `EnforcedStyle: is_expected` (default) [source,ruby] @@ -2418,6 +2605,7 @@ it { should be_truthy } it { is_expected.to be_truthy } ---- +[#_enforcedstyle_-should_-rspecimplicitexpect] ==== `EnforcedStyle: should` [source,ruby] @@ -2429,6 +2617,7 @@ it { is_expected.to be_truthy } it { should be_truthy } ---- +[#configurable-attributes-rspecimplicitexpect] === Configurable attributes |=== @@ -2439,11 +2628,13 @@ it { should be_truthy } | `is_expected`, `should` |=== +[#references-rspecimplicitexpect] === References * https://rspec.rubystyle.guide/#use-expect * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitExpect +[#rspecimplicitsubject] == RSpec/ImplicitSubject |=== @@ -2460,8 +2651,10 @@ Checks for usage of implicit subject (`is_expected` / `should`). This cop can be configured using the `EnforcedStyle` option +[#examples-rspecimplicitsubject] === Examples +[#_enforcedstyle_-single_line_only_-_default_-rspecimplicitsubject] ==== `EnforcedStyle: single_line_only` (default) [source,ruby] @@ -2478,6 +2671,7 @@ it do end ---- +[#_enforcedstyle_-single_statement_only_-rspecimplicitsubject] ==== `EnforcedStyle: single_statement_only` [source,ruby] @@ -2498,6 +2692,7 @@ it do end ---- +[#_enforcedstyle_-disallow_-rspecimplicitsubject] ==== `EnforcedStyle: disallow` [source,ruby] @@ -2509,6 +2704,7 @@ it { is_expected.to be_truthy } it { expect(subject).to be_truthy } ---- +[#_enforcedstyle_-require_implicit_-rspecimplicitsubject] ==== `EnforcedStyle: require_implicit` [source,ruby] @@ -2533,6 +2729,7 @@ end it { expect(named_subject).to be_truthy } ---- +[#configurable-attributes-rspecimplicitsubject] === Configurable attributes |=== @@ -2543,10 +2740,12 @@ it { expect(named_subject).to be_truthy } | `single_line_only`, `single_statement_only`, `disallow`, `require_implicit` |=== +[#references-rspecimplicitsubject] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitSubject +[#rspecindexedlet] == RSpec/IndexedLet |=== @@ -2567,8 +2766,10 @@ is tested by this particular example. The configurable options `AllowedIdentifiers` and `AllowedPatterns` will also read those set in `Naming/VariableNumber`. +[#examples-rspecindexedlet] === Examples +[#_max_-1-_default__-rspecindexedlet] ==== `Max: 1 (default)` [source,ruby] @@ -2586,6 +2787,7 @@ let(:visible_item) { create(:item, visible: true) } let(:invisible_item) { create(:item, visible: false) } ---- +[#_max_-2_-rspecindexedlet] ==== `Max: 2` [source,ruby] @@ -2600,6 +2802,7 @@ let(:item_1) { create(:item) } let(:item_2) { create(:item) } ---- +[#_allowedidentifiers_-__item_1__-_item_2___-rspecindexedlet] ==== `AllowedIdentifiers: ['item_1', 'item_2']` [source,ruby] @@ -2609,6 +2812,7 @@ let(:item_1) { create(:item) } let(:item_2) { create(:item) } ---- +[#_allowedpatterns_-__item___-rspecindexedlet] ==== `AllowedPatterns: ['item']` [source,ruby] @@ -2618,6 +2822,7 @@ let(:item_1) { create(:item) } let(:item_2) { create(:item) } ---- +[#configurable-attributes-rspecindexedlet] === Configurable attributes |=== @@ -2636,10 +2841,12 @@ let(:item_2) { create(:item) } | Array |=== +[#references-rspecindexedlet] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IndexedLet +[#rspecinstancespy] == RSpec/InstanceSpy |=== @@ -2654,6 +2861,7 @@ let(:item_2) { create(:item) } Checks for `instance_double` used with `have_received`. +[#examples-rspecinstancespy] === Examples [source,ruby] @@ -2671,10 +2879,12 @@ it do end ---- +[#references-rspecinstancespy] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/InstanceSpy +[#rspecinstancevariable] == RSpec/InstanceVariable |=== @@ -2694,6 +2904,7 @@ will configure the cop to only register offenses on instance variable usage if the instance variable is also assigned within the spec +[#examples-rspecinstancevariable] === Examples [source,ruby] @@ -2711,6 +2922,7 @@ describe MyClass do end ---- +[#with-assignmentonly-configuration-rspecinstancevariable] ==== with AssignmentOnly configuration [source,ruby] @@ -2737,6 +2949,7 @@ describe MyClass do end ---- +[#configurable-attributes-rspecinstancevariable] === Configurable attributes |=== @@ -2747,11 +2960,13 @@ end | Boolean |=== +[#references-rspecinstancevariable] === References * https://rspec.rubystyle.guide/#instance-variables * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/InstanceVariable +[#rspecisexpectedspecify] == RSpec/IsExpectedSpecify |=== @@ -2766,6 +2981,7 @@ end Check for `specify` with `is_expected` and one-liner expectations. +[#examples-rspecisexpectedspecify] === Examples [source,ruby] @@ -2783,11 +2999,13 @@ end specify { expect(sqrt(4)).to eq(2) } ---- +[#references-rspecisexpectedspecify] === References * https://rspec.rubystyle.guide/#it-and-specify * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IsExpectedSpecify +[#rspecitbehaveslike] == RSpec/ItBehavesLike |=== @@ -2802,8 +3020,10 @@ specify { expect(sqrt(4)).to eq(2) } Checks that only one `it_behaves_like` style is used. +[#examples-rspecitbehaveslike] === Examples +[#_enforcedstyle_-it_behaves_like_-_default_-rspecitbehaveslike] ==== `EnforcedStyle: it_behaves_like` (default) [source,ruby] @@ -2815,6 +3035,7 @@ it_should_behave_like 'a foo' it_behaves_like 'a foo' ---- +[#_enforcedstyle_-it_should_behave_like_-rspecitbehaveslike] ==== `EnforcedStyle: it_should_behave_like` [source,ruby] @@ -2826,6 +3047,7 @@ it_behaves_like 'a foo' it_should_behave_like 'a foo' ---- +[#configurable-attributes-rspecitbehaveslike] === Configurable attributes |=== @@ -2836,10 +3058,12 @@ it_should_behave_like 'a foo' | `it_behaves_like`, `it_should_behave_like` |=== +[#references-rspecitbehaveslike] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ItBehavesLike +[#rspeciteratedexpectation] == RSpec/IteratedExpectation |=== @@ -2854,6 +3078,7 @@ it_should_behave_like 'a foo' Check that `all` matcher is used instead of iterating over an array. +[#examples-rspeciteratedexpectation] === Examples [source,ruby] @@ -2869,10 +3094,12 @@ it 'validates users' do end ---- +[#references-rspeciteratedexpectation] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IteratedExpectation +[#rspecleadingsubject] == RSpec/LeadingSubject |=== @@ -2887,6 +3114,7 @@ end Enforce that subject is the first definition in the test. +[#examples-rspecleadingsubject] === Examples [source,ruby] @@ -2916,11 +3144,13 @@ it { expect_something } it { expect_something_else } ---- +[#references-rspecleadingsubject] === References * https://rspec.rubystyle.guide/#leading-subject * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LeadingSubject +[#rspecleakyconstantdeclaration] == RSpec/LeakyConstantDeclaration |=== @@ -2947,8 +3177,10 @@ Even worse when a class that exists in the codebase is reopened. Anonymous classes are fine, since they don't result in global namespace name clashes. +[#examples-rspecleakyconstantdeclaration] === Examples +[#constants-leak-between-examples-rspecleakyconstantdeclaration] ==== Constants leak between examples [source,ruby] @@ -3032,12 +3264,14 @@ describe SomeClass do end ---- +[#references-rspecleakyconstantdeclaration] === References * https://rspec.rubystyle.guide/#declare-constants * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LeakyConstantDeclaration * https://rspec.info/features/3-12/rspec-mocks/mutating-constants +[#rspecletbeforeexamples] == RSpec/LetBeforeExamples |=== @@ -3052,6 +3286,7 @@ end Checks for `let` definitions that come after an example. +[#examples-rspecletbeforeexamples] === Examples [source,ruby] @@ -3082,10 +3317,12 @@ it 'checks what some does' do end ---- +[#references-rspecletbeforeexamples] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LetBeforeExamples +[#rspecletsetup] == RSpec/LetSetup |=== @@ -3100,6 +3337,7 @@ end Checks unreferenced `let!` calls being used for test setup. +[#examples-rspecletsetup] === Examples [source,ruby] @@ -3125,10 +3363,12 @@ it 'counts widgets' do end ---- +[#references-rspecletsetup] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LetSetup +[#rspecmatcharray] == RSpec/MatchArray |=== @@ -3147,6 +3387,7 @@ This cop checks for the following: - Prefer `contain_exactly` when matching an array with values. - Prefer `eq` when using `match_array` with an empty array literal. +[#examples-rspecmatcharray] === Examples [source,ruby] @@ -3164,10 +3405,12 @@ it { is_expected.to match_array([content] + array) } it { is_expected.to match_array(%w(tremble in fear foolish mortals)) } ---- +[#references-rspecmatcharray] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MatchArray +[#rspecmessagechain] == RSpec/MessageChain |=== @@ -3182,6 +3425,7 @@ it { is_expected.to match_array(%w(tremble in fear foolish mortals)) } Check that chains of messages are not being stubbed. +[#examples-rspecmessagechain] === Examples [source,ruby] @@ -3194,10 +3438,12 @@ thing = Thing.new(baz: 42) allow(foo).to receive(:bar).and_return(thing) ---- +[#references-rspecmessagechain] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageChain +[#rspecmessageexpectation] == RSpec/MessageExpectation |=== @@ -3215,8 +3461,10 @@ Checks for consistent message expectation style. This cop can be configured in your configuration using the `EnforcedStyle` option and supports `--auto-gen-config`. +[#examples-rspecmessageexpectation] === Examples +[#_enforcedstyle_-allow_-_default_-rspecmessageexpectation] ==== `EnforcedStyle: allow` (default) [source,ruby] @@ -3228,6 +3476,7 @@ expect(foo).to receive(:bar) allow(foo).to receive(:bar) ---- +[#_enforcedstyle_-expect_-rspecmessageexpectation] ==== `EnforcedStyle: expect` [source,ruby] @@ -3239,6 +3488,7 @@ allow(foo).to receive(:bar) expect(foo).to receive(:bar) ---- +[#configurable-attributes-rspecmessageexpectation] === Configurable attributes |=== @@ -3249,10 +3499,12 @@ expect(foo).to receive(:bar) | `allow`, `expect` |=== +[#references-rspecmessageexpectation] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageExpectation +[#rspecmessagespies] == RSpec/MessageSpies |=== @@ -3270,8 +3522,10 @@ Checks that message expectations are set using spies. This cop can be configured in your configuration using the `EnforcedStyle` option and supports `--auto-gen-config`. +[#examples-rspecmessagespies] === Examples +[#_enforcedstyle_-have_received_-_default_-rspecmessagespies] ==== `EnforcedStyle: have_received` (default) [source,ruby] @@ -3286,6 +3540,7 @@ do_something expect(foo).to have_received(:bar) ---- +[#_enforcedstyle_-receive_-rspecmessagespies] ==== `EnforcedStyle: receive` [source,ruby] @@ -3300,6 +3555,7 @@ expect(foo).to receive(:bar) do_something ---- +[#configurable-attributes-rspecmessagespies] === Configurable attributes |=== @@ -3310,10 +3566,12 @@ do_something | `have_received`, `receive` |=== +[#references-rspecmessagespies] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageSpies +[#rspecmetadatastyle] == RSpec/MetadataStyle |=== @@ -3332,8 +3590,10 @@ This cop does not support autocorrection in the case of `EnforcedStyle: hash` where the trailing metadata type is ambiguous. (e.g. `describe 'Something', :a, b`) +[#examples-rspecmetadatastyle] === Examples +[#enforcedstyle_-symbol-_default_-rspecmetadatastyle] ==== EnforcedStyle: symbol (default) [source,ruby] @@ -3345,6 +3605,7 @@ describe 'Something', a: true describe 'Something', :a ---- +[#enforcedstyle_-hash-rspecmetadatastyle] ==== EnforcedStyle: hash [source,ruby] @@ -3356,6 +3617,7 @@ describe 'Something', :a describe 'Something', a: true ---- +[#configurable-attributes-rspecmetadatastyle] === Configurable attributes |=== @@ -3366,10 +3628,12 @@ describe 'Something', a: true | `hash`, `symbol` |=== +[#references-rspecmetadatastyle] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MetadataStyle +[#rspecmissingexamplegroupargument] == RSpec/MissingExampleGroupArgument |=== @@ -3384,6 +3648,7 @@ describe 'Something', a: true Checks that the first argument to an example group is not empty. +[#examples-rspecmissingexamplegroupargument] === Examples [source,ruby] @@ -3403,10 +3668,12 @@ describe "A feature example" do end ---- +[#references-rspecmissingexamplegroupargument] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MissingExampleGroupArgument +[#rspecmissingexpectationtargetmethod] == RSpec/MissingExpectationTargetMethod |=== @@ -3424,6 +3691,7 @@ Checks if `.to`, `not_to` or `to_not` are used. The RSpec::Expectations::ExpectationTarget must use `to`, `not_to` or `to_not` to run. Therefore, this cop checks if other methods are used. +[#examples-rspecmissingexpectationtargetmethod] === Examples [source,ruby] @@ -3439,10 +3707,12 @@ is_expected.to eq 42 expect{something}.to raise_error BarError ---- +[#references-rspecmissingexpectationtargetmethod] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MissingExpectationTargetMethod +[#rspecmultipledescribes] == RSpec/MultipleDescribes |=== @@ -3460,6 +3730,7 @@ Checks for multiple top-level example groups. Multiple descriptions for the same class or module should either be nested or separated into different test files. +[#examples-rspecmultipledescribes] === Examples [source,ruby] @@ -3479,10 +3750,12 @@ describe MyClass do end ---- +[#references-rspecmultipledescribes] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleDescribes +[#rspecmultipleexpectations] == RSpec/MultipleExpectations |=== @@ -3500,6 +3773,7 @@ Checks if examples contain too many `expect` calls. This cop is configurable using the `Max` option and works with `--auto-gen-config`. +[#examples-rspecmultipleexpectations] === Examples [source,ruby] @@ -3524,6 +3798,7 @@ describe UserCreator do end ---- +[#_aggregate_failures_-true_-_default_-rspecmultipleexpectations] ==== `aggregate_failures: true` (default) [source,ruby] @@ -3537,6 +3812,7 @@ describe UserCreator do end ---- +[#_aggregate_failures_-false_-rspecmultipleexpectations] ==== `aggregate_failures: false` [source,ruby] @@ -3550,6 +3826,7 @@ describe UserCreator do end ---- +[#_max_-1_-_default_-rspecmultipleexpectations] ==== `Max: 1` (default) [source,ruby] @@ -3563,6 +3840,7 @@ describe UserCreator do end ---- +[#_max_-2_-rspecmultipleexpectations] ==== `Max: 2` [source,ruby] @@ -3576,6 +3854,7 @@ describe UserCreator do end ---- +[#configurable-attributes-rspecmultipleexpectations] === Configurable attributes |=== @@ -3586,12 +3865,14 @@ end | Integer |=== +[#references-rspecmultipleexpectations] === References * https://rspec.rubystyle.guide/#expectation-per-example * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleExpectations * http://betterspecs.org/#single +[#rspecmultiplememoizedhelpers] == RSpec/MultipleMemoizedHelpers |=== @@ -3610,6 +3891,7 @@ This cop is configurable using the `Max` option and the `AllowSubject` which will configure the cop to only register offenses on calls to `let` and not calls to `subject`. +[#examples-rspecmultiplememoizedhelpers] === Examples [source,ruby] @@ -3660,6 +3942,7 @@ describe MyClass do end ---- +[#when-disabling-allowsubject-configuration-rspecmultiplememoizedhelpers] ==== when disabling AllowSubject configuration [source,ruby] @@ -3679,6 +3962,7 @@ describe MyClass do end ---- +[#with-max-configuration-rspecmultiplememoizedhelpers] ==== with Max configuration [source,ruby] @@ -3694,6 +3978,7 @@ describe MyClass do end ---- +[#configurable-attributes-rspecmultiplememoizedhelpers] === Configurable attributes |=== @@ -3708,11 +3993,13 @@ end | Integer |=== +[#references-rspecmultiplememoizedhelpers] === References * https://rspec.rubystyle.guide/#let-blocks * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleMemoizedHelpers +[#rspecmultiplesubjects] == RSpec/MultipleSubjects |=== @@ -3743,6 +4030,7 @@ duplication: This is enough of an edge case that people can just move this to a `before` hook on their own +[#examples-rspecmultiplesubjects] === Examples [source,ruby] @@ -3774,10 +4062,12 @@ describe Foo do end ---- +[#references-rspecmultiplesubjects] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleSubjects +[#rspecnamedsubject] == RSpec/NamedSubject |=== @@ -3803,8 +4093,10 @@ This cop can be configured in your configuration using `EnforcedStyle`, and `IgnoreSharedExamples` which will not report offenses for implicit subjects in shared example groups. +[#examples-rspecnamedsubject] === Examples +[#_enforcedstyle_-always_-_default_-rspecnamedsubject] ==== `EnforcedStyle: always` (default) [source,ruby] @@ -3835,6 +4127,7 @@ RSpec.describe User do end ---- +[#_enforcedstyle_-named_only_-rspecnamedsubject] ==== `EnforcedStyle: named_only` [source,ruby] @@ -3874,6 +4167,7 @@ RSpec.describe User do end ---- +[#configurable-attributes-rspecnamedsubject] === Configurable attributes |=== @@ -3888,11 +4182,13 @@ end | Boolean |=== +[#references-rspecnamedsubject] === References * https://rspec.rubystyle.guide/#use-subject * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NamedSubject +[#rspecnestedgroups] == RSpec/NestedGroups |=== @@ -3910,6 +4206,7 @@ Checks for nested example groups. This cop is configurable using the `Max` option and supports `--auto-gen-config`. +[#examples-rspecnestedgroups] === Examples [source,ruby] @@ -3959,6 +4256,7 @@ context 'using some feature as an admin' do end ---- +[#_max_-3_-_default_-rspecnestedgroups] ==== `Max: 3` (default) [source,ruby] @@ -3974,6 +4272,7 @@ describe Foo do end ---- +[#_max_-2_-rspecnestedgroups] ==== `Max: 2` [source,ruby] @@ -3989,6 +4288,7 @@ describe Foo do end ---- +[#_allowedgroups_-__-_default__-rspecnestedgroups] ==== `AllowedGroups: [] (default)` [source,ruby] @@ -4001,6 +4301,7 @@ describe Foo do # <-- nested groups 1 end ---- +[#_allowedgroups_-_path__-rspecnestedgroups] ==== `AllowedGroups: [path]` [source,ruby] @@ -4013,6 +4314,7 @@ describe Foo do # <-- nested groups 1 end ---- +[#configurable-attributes-rspecnestedgroups] === Configurable attributes |=== @@ -4027,10 +4329,12 @@ end | Array |=== +[#references-rspecnestedgroups] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NestedGroups +[#rspecnoexpectationexample] == RSpec/NoExpectationExample |=== @@ -4061,6 +4365,7 @@ This cop can be customized with an allowed expectation methods pattern with an `AllowedPatterns` option. ^expect_ and ^assert_ are allowed by default. +[#examples-rspecnoexpectationexample] === Examples [source,ruby] @@ -4076,6 +4381,7 @@ it do end ---- +[#_allowedpatterns_-configuration-rspecnoexpectationexample] ==== `AllowedPatterns` configuration [source,ruby] @@ -4104,6 +4410,7 @@ it do end ---- +[#configurable-attributes-rspecnoexpectationexample] === Configurable attributes |=== @@ -4114,10 +4421,12 @@ end | Array |=== +[#references-rspecnoexpectationexample] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NoExpectationExample +[#rspecnottonot] == RSpec/NotToNot |=== @@ -4132,8 +4441,10 @@ end Checks for consistent method usage for negating expectations. +[#examples-rspecnottonot] === Examples +[#_enforcedstyle_-not_to_-_default_-rspecnottonot] ==== `EnforcedStyle: not_to` (default) [source,ruby] @@ -4149,6 +4460,7 @@ it '...' do end ---- +[#_enforcedstyle_-to_not_-rspecnottonot] ==== `EnforcedStyle: to_not` [source,ruby] @@ -4164,6 +4476,7 @@ it '...' do end ---- +[#configurable-attributes-rspecnottonot] === Configurable attributes |=== @@ -4174,10 +4487,12 @@ end | `not_to`, `to_not` |=== +[#references-rspecnottonot] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NotToNot +[#rspecoverwritingsetup] == RSpec/OverwritingSetup |=== @@ -4192,6 +4507,7 @@ end Checks if there is a let/subject that overwrites an existing one. +[#examples-rspecoverwritingsetup] === Examples [source,ruby] @@ -4213,10 +4529,12 @@ let(:baz) { baz } let!(:other) { other } ---- +[#references-rspecoverwritingsetup] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/OverwritingSetup +[#rspecpending] == RSpec/Pending |=== @@ -4231,6 +4549,7 @@ let!(:other) { other } Checks for any pending or skipped examples. +[#examples-rspecpending] === Examples [source,ruby] @@ -4262,10 +4581,12 @@ describe MyClass do end ---- +[#references-rspecpending] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Pending +[#rspecpendingwithoutreason] == RSpec/PendingWithoutReason |=== @@ -4280,6 +4601,7 @@ end Checks for pending or skipped examples without reason. +[#examples-rspecpendingwithoutreason] === Examples [source,ruby] @@ -4336,10 +4658,12 @@ it 'does something', skip: 'reason' do end ---- +[#references-rspecpendingwithoutreason] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/PendingWithoutReason +[#rspecpredicatematcher] == RSpec/PredicateMatcher |=== @@ -4358,8 +4682,10 @@ RSpec defines magic matchers for predicate methods. This cop recommends to use the predicate matcher instead of using predicate method directly. +[#examples-rspecpredicatematcher] === Examples +[#strict_-true_-enforcedstyle_-inflected-_default_-rspecpredicatematcher] ==== Strict: true, EnforcedStyle: inflected (default) [source,ruby] @@ -4374,6 +4700,7 @@ expect(foo).to be_something expect(foo.something?).to be(true) ---- +[#strict_-false_-enforcedstyle_-inflected-rspecpredicatematcher] ==== Strict: false, EnforcedStyle: inflected [source,ruby] @@ -4386,6 +4713,7 @@ expect(foo.something?).to be(true) expect(foo).to be_something ---- +[#strict_-true_-enforcedstyle_-explicit-rspecpredicatematcher] ==== Strict: true, EnforcedStyle: explicit [source,ruby] @@ -4408,6 +4736,7 @@ expect(foo.something?(<<~TEXT)).to be(true) TEXT ---- +[#strict_-false_-enforcedstyle_-explicit-rspecpredicatematcher] ==== Strict: false, EnforcedStyle: explicit [source,ruby] @@ -4419,6 +4748,7 @@ expect(foo).to be_something expect(foo.something?).to be_truthy ---- +[#configurable-attributes-rspecpredicatematcher] === Configurable attributes |=== @@ -4437,11 +4767,13 @@ expect(foo.something?).to be_truthy | Array |=== +[#references-rspecpredicatematcher] === References * https://rspec.rubystyle.guide/#predicate-matchers * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/PredicateMatcher +[#rspecreceivecounts] == RSpec/ReceiveCounts |=== @@ -4456,6 +4788,7 @@ expect(foo.something?).to be_truthy Check for `once` and `twice` receive counts matchers usage. +[#examples-rspecreceivecounts] === Examples [source,ruby] @@ -4477,10 +4810,12 @@ expect(foo).to receive(:bar).at_most(:once) expect(foo).to receive(:bar).at_most(:twice).times ---- +[#references-rspecreceivecounts] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReceiveCounts +[#rspecreceivemessages] == RSpec/ReceiveMessages |=== @@ -4495,12 +4830,14 @@ expect(foo).to receive(:bar).at_most(:twice).times Checks for multiple messages stubbed on the same object. +[#safety-rspecreceivemessages] === Safety The autocorrection is marked as unsafe, because it may change the order of stubs. This in turn may cause e.g. variables to be called before they are defined. +[#examples-rspecreceivemessages] === Examples [source,ruby] @@ -4523,10 +4860,12 @@ before do end ---- +[#references-rspecreceivemessages] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReceiveMessages +[#rspecreceivenever] == RSpec/ReceiveNever |=== @@ -4541,6 +4880,7 @@ end Prefer `not_to receive(...)` over `receive(...).never`. +[#examples-rspecreceivenever] === Examples [source,ruby] @@ -4552,10 +4892,12 @@ expect(foo).to receive(:bar).never expect(foo).not_to receive(:bar) ---- +[#references-rspecreceivenever] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReceiveNever +[#rspecredundantaround] == RSpec/RedundantAround |=== @@ -4570,6 +4912,7 @@ expect(foo).not_to receive(:bar) Remove redundant `around` hook. +[#examples-rspecredundantaround] === Examples [source,ruby] @@ -4582,10 +4925,12 @@ end # good ---- +[#references-rspecredundantaround] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RedundantAround +[#rspecredundantpredicatematcher] == RSpec/RedundantPredicateMatcher |=== @@ -4600,6 +4945,7 @@ end Checks for redundant predicate matcher. +[#examples-rspecredundantpredicatematcher] === Examples [source,ruby] @@ -4615,10 +4961,12 @@ expect(foo).not_to include(bar) expect(foo).to all be(bar) ---- +[#references-rspecredundantpredicatematcher] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RedundantPredicateMatcher +[#rspecremoveconst] == RSpec/RemoveConst |=== @@ -4633,6 +4981,7 @@ expect(foo).to all be(bar) Checks that `remove_const` is not used in specs. +[#examples-rspecremoveconst] === Examples [source,ruby] @@ -4647,10 +4996,12 @@ before do end ---- +[#references-rspecremoveconst] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RemoveConst +[#rspecrepeateddescription] == RSpec/RepeatedDescription |=== @@ -4665,6 +5016,7 @@ end Check for repeated description strings in example groups. +[#examples-rspecrepeateddescription] === Examples [source,ruby] @@ -4703,10 +5055,12 @@ RSpec.describe User do end ---- +[#references-rspecrepeateddescription] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedDescription +[#rspecrepeatedexample] == RSpec/RepeatedExample |=== @@ -4721,6 +5075,7 @@ end Check for repeated examples within example groups. +[#examples-rspecrepeatedexample] === Examples [source,ruby] @@ -4734,10 +5089,12 @@ it 'validates the user' do end ---- +[#references-rspecrepeatedexample] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedExample +[#rspecrepeatedexamplegroupbody] == RSpec/RepeatedExampleGroupBody |=== @@ -4752,6 +5109,7 @@ end Check for repeated describe and context block body. +[#examples-rspecrepeatedexamplegroupbody] === Examples [source,ruby] @@ -4793,10 +5151,12 @@ context Hash do end ---- +[#references-rspecrepeatedexamplegroupbody] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedExampleGroupBody +[#rspecrepeatedexamplegroupdescription] == RSpec/RepeatedExampleGroupDescription |=== @@ -4811,6 +5171,7 @@ end Check for repeated example group descriptions. +[#examples-rspecrepeatedexamplegroupdescription] === Examples [source,ruby] @@ -4852,10 +5213,12 @@ context 'when another case' do end ---- +[#references-rspecrepeatedexamplegroupdescription] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedExampleGroupDescription +[#rspecrepeatedincludeexample] == RSpec/RepeatedIncludeExample |=== @@ -4870,6 +5233,7 @@ end Check for repeated include of shared examples. +[#examples-rspecrepeatedincludeexample] === Examples [source,ruby] @@ -4914,10 +5278,12 @@ context 'foo' do end ---- +[#references-rspecrepeatedincludeexample] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedIncludeExample +[#rspecrepeatedsubjectcall] == RSpec/RepeatedSubjectCall |=== @@ -4932,6 +5298,7 @@ end Checks for repeated calls to subject missing that it is memoized. +[#examples-rspecrepeatedsubjectcall] === Examples [source,ruby] @@ -4960,10 +5327,12 @@ it do end ---- +[#references-rspecrepeatedsubjectcall] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedSubjectCall +[#rspecreturnfromstub] == RSpec/ReturnFromStub |=== @@ -4984,8 +5353,10 @@ are the result would be different This cop can be configured using the `EnforcedStyle` option +[#examples-rspecreturnfromstub] === Examples +[#_enforcedstyle_-and_return_-_default_-rspecreturnfromstub] ==== `EnforcedStyle: and_return` (default) [source,ruby] @@ -5001,6 +5372,7 @@ expect(Foo).to receive(:bar).and_return("baz") allow(Foo).to receive(:bar) { bar.baz } ---- +[#_enforcedstyle_-block_-rspecreturnfromstub] ==== `EnforcedStyle: block` [source,ruby] @@ -5016,6 +5388,7 @@ expect(Foo).to receive(:bar) { "baz" } allow(Foo).to receive(:bar).and_return(bar.baz) ---- +[#configurable-attributes-rspecreturnfromstub] === Configurable attributes |=== @@ -5026,10 +5399,12 @@ allow(Foo).to receive(:bar).and_return(bar.baz) | `and_return`, `block` |=== +[#references-rspecreturnfromstub] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReturnFromStub +[#rspecscatteredlet] == RSpec/ScatteredLet |=== @@ -5046,6 +5421,7 @@ Checks for let scattered across the example group. Group lets together +[#examples-rspecscatteredlet] === Examples [source,ruby] @@ -5069,10 +5445,12 @@ describe Foo do end ---- +[#references-rspecscatteredlet] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ScatteredLet +[#rspecscatteredsetup] == RSpec/ScatteredSetup |=== @@ -5089,6 +5467,7 @@ Checks for setup scattered across multiple hooks in an example group. Unify `before`, `after`, and `around` hooks when possible. +[#examples-rspecscatteredsetup] === Examples [source,ruby] @@ -5108,10 +5487,12 @@ describe Foo do end ---- +[#references-rspecscatteredsetup] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ScatteredSetup +[#rspecsharedcontext] == RSpec/SharedContext |=== @@ -5129,6 +5510,7 @@ Checks for proper shared_context and shared_examples usage. If there are no examples defined, use shared_context. If there is no setup defined, use shared_examples. +[#examples-rspecsharedcontext] === Examples [source,ruby] @@ -5177,10 +5559,12 @@ RSpec.shared_context 'only setup here' do end ---- +[#references-rspecsharedcontext] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SharedContext +[#rspecsharedexamples] == RSpec/SharedExamples |=== @@ -5199,8 +5583,10 @@ Enforces either `string` or `symbol` for shared example names. This cop can be configured using the `EnforcedStyle` option +[#examples-rspecsharedexamples] === Examples +[#_enforcedstyle_-string_-_default_-rspecsharedexamples] ==== `EnforcedStyle: string` (default) [source,ruby] @@ -5220,6 +5606,7 @@ shared_examples_for 'foo bar baz' include_examples 'foo bar baz' ---- +[#_enforcedstyle_-symbol_-rspecsharedexamples] ==== `EnforcedStyle: symbol` [source,ruby] @@ -5239,6 +5626,7 @@ shared_examples_for :foo_bar_baz include_examples :foo_bar_baz ---- +[#configurable-attributes-rspecsharedexamples] === Configurable attributes |=== @@ -5249,10 +5637,12 @@ include_examples :foo_bar_baz | `string`, `symbol` |=== +[#references-rspecsharedexamples] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SharedExamples +[#rspecsingleargumentmessagechain] == RSpec/SingleArgumentMessageChain |=== @@ -5267,6 +5657,7 @@ include_examples :foo_bar_baz Checks that chains of messages contain more than one element. +[#examples-rspecsingleargumentmessagechain] === Examples [source,ruby] @@ -5282,10 +5673,12 @@ allow(foo).to receive(:bar, :baz) allow(foo).to receive("bar.baz") ---- +[#references-rspecsingleargumentmessagechain] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SingleArgumentMessageChain +[#rspecskipblockinsideexample] == RSpec/SkipBlockInsideExample |=== @@ -5300,6 +5693,7 @@ allow(foo).to receive("bar.baz") Checks for passing a block to `skip` within examples. +[#examples-rspecskipblockinsideexample] === Examples [source,ruby] @@ -5322,10 +5716,12 @@ skip 'not yet implemented' do end ---- +[#references-rspecskipblockinsideexample] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SkipBlockInsideExample +[#rspecsortmetadata] == RSpec/SortMetadata |=== @@ -5340,6 +5736,7 @@ end Sort RSpec metadata alphabetically. +[#examples-rspecsortmetadata] === Examples [source,ruby] @@ -5355,10 +5752,12 @@ context 'Something', baz: true, foo: 'bar' it 'works', :a, :b, baz: true, foo: 'bar' ---- +[#references-rspecsortmetadata] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SortMetadata +[#rspecspecfilepathformat] == RSpec/SpecFilePathFormat |=== @@ -5373,6 +5772,7 @@ it 'works', :a, :b, baz: true, foo: 'bar' Checks that spec file paths are consistent and well-formed. +[#examples-rspecspecfilepathformat] === Examples [source,ruby] @@ -5387,6 +5787,7 @@ my_class_method_spec.rb # describe MyClass, '#method' my_class/method_spec.rb # describe MyClass, '#method' ---- +[#_customtransform_-_rubocop__rubocop_-rspec__rspec__-_default_-rspecspecfilepathformat] ==== `CustomTransform: {RuboCop=>rubocop, RSpec=>rspec}` (default) [source,ruby] @@ -5396,6 +5797,7 @@ rubocop_spec.rb # describe RuboCop rspec_spec.rb # describe RSpec ---- +[#_ignoremethods_-false_-_default_-rspecspecfilepathformat] ==== `IgnoreMethods: false` (default) [source,ruby] @@ -5404,6 +5806,7 @@ rspec_spec.rb # describe RSpec my_class_spec.rb # describe MyClass, '#method' ---- +[#_ignoremethods_-true_-rspecspecfilepathformat] ==== `IgnoreMethods: true` [source,ruby] @@ -5412,6 +5815,7 @@ my_class_spec.rb # describe MyClass, '#method' my_class_spec.rb # describe MyClass, '#method' ---- +[#_ignoremetadata_-_type__routing__-_default_-rspecspecfilepathformat] ==== `IgnoreMetadata: {type=>routing}` (default) [source,ruby] @@ -5420,6 +5824,7 @@ my_class_spec.rb # describe MyClass, '#method' whatever_spec.rb # describe MyClass, type: :routing do; end ---- +[#configurable-attributes-rspecspecfilepathformat] === Configurable attributes |=== @@ -5446,10 +5851,12 @@ whatever_spec.rb # describe MyClass, type: :routing do; end | |=== +[#references-rspecspecfilepathformat] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SpecFilePathFormat +[#rspecspecfilepathsuffix] == RSpec/SpecFilePathSuffix |=== @@ -5464,6 +5871,7 @@ whatever_spec.rb # describe MyClass, type: :routing do; end Checks that spec file paths suffix are consistent and well-formed. +[#examples-rspecspecfilepathsuffix] === Examples [source,ruby] @@ -5480,6 +5888,7 @@ my_class_spec.rb # describe MyClass spec/models/user.rb # shared_examples_for 'foo' ---- +[#configurable-attributes-rspecspecfilepathsuffix] === Configurable attributes |=== @@ -5490,10 +5899,12 @@ spec/models/user.rb # shared_examples_for 'foo' | Array |=== +[#references-rspecspecfilepathsuffix] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SpecFilePathSuffix +[#rspecstringasinstancedoubleconstant] == RSpec/StringAsInstanceDoubleConstant |=== @@ -5508,12 +5919,14 @@ spec/models/user.rb # shared_examples_for 'foo' Do not use a string as `instance_double` constant. +[#safety-rspecstringasinstancedoubleconstant] === Safety This cop is unsafe because the correction requires loading the class. Loading before stubbing causes RSpec to only allow instance methods to be stubbed. +[#examples-rspecstringasinstancedoubleconstant] === Examples [source,ruby] @@ -5525,10 +5938,12 @@ instance_double('User', name: 'John') instance_double(User, name: 'John') ---- +[#references-rspecstringasinstancedoubleconstant] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/StringAsInstanceDoubleConstant +[#rspecstubbedmock] == RSpec/StubbedMock |=== @@ -5543,6 +5958,7 @@ instance_double(User, name: 'John') Checks that message expectations do not have a configured response. +[#examples-rspecstubbedmock] === Examples [source,ruby] @@ -5555,10 +5971,12 @@ allow(foo).to receive(:bar).with(42).and_return("hello world") expect(foo).to receive(:bar).with(42) ---- +[#references-rspecstubbedmock] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/StubbedMock +[#rspecsubjectdeclaration] == RSpec/SubjectDeclaration |=== @@ -5573,6 +5991,7 @@ expect(foo).to receive(:bar).with(42) Ensure that subject is defined using subject helper. +[#examples-rspecsubjectdeclaration] === Examples [source,ruby] @@ -5591,10 +6010,12 @@ let(:subject, &block) subject(:test_subject) { foo } ---- +[#references-rspecsubjectdeclaration] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SubjectDeclaration +[#rspecsubjectstub] == RSpec/SubjectStub |=== @@ -5612,6 +6033,7 @@ Checks for stubbed test subjects. Checks nested subject stubs for innermost subject definition when subject is also defined in parent example groups. +[#examples-rspecsubjectstub] === Examples [source,ruby] @@ -5650,6 +6072,7 @@ describe Article do end ---- +[#references-rspecsubjectstub] === References * https://rspec.rubystyle.guide/#dont-stub-subject @@ -5657,6 +6080,7 @@ end * https://robots.thoughtbot.com/don-t-stub-the-system-under-test * https://penelope.zone/2015/12/27/introducing-rspec-smells-and-where-to-find-them.html#smell-1-stubjec +[#rspecundescriptiveliteralsdescription] == RSpec/UndescriptiveLiteralsDescription |=== @@ -5674,6 +6098,7 @@ Description should be descriptive. If example group or example contains only `execute string`, numbers and regular expressions, the description is not clear. +[#examples-rspecundescriptiveliteralsdescription] === Examples [source,ruby] @@ -5714,10 +6139,12 @@ it 'does something' do end ---- +[#references-rspecundescriptiveliteralsdescription] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/UndescriptiveLiteralsDescription +[#rspecunspecifiedexception] == RSpec/UnspecifiedException |=== @@ -5736,6 +6163,7 @@ Enforces one of an Exception type, a string, or a regular expression to match against the exception message as a parameter to `raise_error` +[#examples-rspecunspecifiedexception] === Examples [source,ruby] @@ -5761,10 +6189,12 @@ expect { expect { do_something }.not_to raise_error ---- +[#references-rspecunspecifiedexception] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/UnspecifiedException +[#rspecvariabledefinition] == RSpec/VariableDefinition |=== @@ -5779,8 +6209,10 @@ expect { do_something }.not_to raise_error Checks that memoized helpers names are symbols or strings. +[#examples-rspecvariabledefinition] === Examples +[#enforcedstyle_-symbols-_default_-rspecvariabledefinition] ==== EnforcedStyle: symbols (default) [source,ruby] @@ -5794,6 +6226,7 @@ subject(:user) { create_user } let(:user_name) { 'Adam' } ---- +[#enforcedstyle_-strings-rspecvariabledefinition] ==== EnforcedStyle: strings [source,ruby] @@ -5807,6 +6240,7 @@ subject('user') { create_user } let('user_name') { 'Adam' } ---- +[#configurable-attributes-rspecvariabledefinition] === Configurable attributes |=== @@ -5817,10 +6251,12 @@ let('user_name') { 'Adam' } | `symbols`, `strings` |=== +[#references-rspecvariabledefinition] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VariableDefinition +[#rspecvariablename] == RSpec/VariableName |=== @@ -5838,8 +6274,10 @@ Checks that memoized helper names use the configured style. Variables can be excluded from checking using the `AllowedPatterns` option. +[#examples-rspecvariablename] === Examples +[#enforcedstyle_-snake_case-_default_-rspecvariablename] ==== EnforcedStyle: snake_case (default) [source,ruby] @@ -5853,6 +6291,7 @@ subject(:user_name_1) { 'Adam' } let(:user_name_2) { 'Adam' } ---- +[#enforcedstyle_-camelcase-rspecvariablename] ==== EnforcedStyle: camelCase [source,ruby] @@ -5866,6 +6305,7 @@ subject(:userName1) { 'Adam' } let(:userName2) { 'Adam' } ---- +[#allowedpatterns-configuration-rspecvariablename] ==== AllowedPatterns configuration [source,ruby] @@ -5884,6 +6324,7 @@ subject(:userFood_1) { 'spaghetti' } let(:userFood_2) { 'fettuccine' } ---- +[#configurable-attributes-rspecvariablename] === Configurable attributes |=== @@ -5898,10 +6339,12 @@ let(:userFood_2) { 'fettuccine' } | Array |=== +[#references-rspecvariablename] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VariableName +[#rspecverifieddoublereference] == RSpec/VerifiedDoubleReference |=== @@ -5921,8 +6364,10 @@ Only investigates references that are one of the supported styles. This cop can be configured in your configuration using the `EnforcedStyle` option and supports `--auto-gen-config`. +[#examples-rspecverifieddoublereference] === Examples +[#_enforcedstyle_-constant_-_default_-rspecverifieddoublereference] ==== `EnforcedStyle: constant` (default) [source,ruby] @@ -5938,6 +6383,7 @@ let(:foo) do end ---- +[#_enforcedstyle_-string_-rspecverifieddoublereference] ==== `EnforcedStyle: string` [source,ruby] @@ -5953,6 +6399,7 @@ let(:foo) do end ---- +[#reference-is-not-in-the-supported-style-list_-no-enforcement-rspecverifieddoublereference] ==== Reference is not in the supported style list. No enforcement [source,ruby] @@ -5963,6 +6410,7 @@ let(:foo) do end ---- +[#configurable-attributes-rspecverifieddoublereference] === Configurable attributes |=== @@ -5973,11 +6421,13 @@ end | `constant`, `string` |=== +[#references-rspecverifieddoublereference] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VerifiedDoubleReference * https://rspec.info/features/3-12/rspec-mocks/verifying-doubles +[#rspecverifieddoubles] == RSpec/VerifiedDoubles |=== @@ -5992,6 +6442,7 @@ end Prefer using verifying doubles over normal doubles. +[#examples-rspecverifieddoubles] === Examples [source,ruby] @@ -6012,6 +6463,7 @@ let(:foo) do end ---- +[#configurable-attributes-rspecverifieddoubles] === Configurable attributes |=== @@ -6026,12 +6478,14 @@ end | Boolean |=== +[#references-rspecverifieddoubles] === References * https://rspec.rubystyle.guide/#doubles * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VerifiedDoubles * https://rspec.info/features/3-12/rspec-mocks/verifying-doubles +[#rspecvoidexpect] == RSpec/VoidExpect |=== @@ -6046,6 +6500,7 @@ end Checks void `expect()`. +[#examples-rspecvoidexpect] === Examples [source,ruby] @@ -6057,10 +6512,12 @@ expect(something) expect(something).to be(1) ---- +[#references-rspecvoidexpect] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VoidExpect +[#rspecyield] == RSpec/Yield |=== @@ -6075,6 +6532,7 @@ expect(something).to be(1) Checks for calling a block within a stub. +[#examples-rspecyield] === Examples [source,ruby] @@ -6086,6 +6544,7 @@ allow(foo).to receive(:bar) { |&block| block.call(1) } expect(foo).to receive(:bar).and_yield(1) ---- +[#references-rspecyield] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Yield From e8fa4586e1cfdc4d14eccc50e1a73546c3d84c16 Mon Sep 17 00:00:00 2001 From: ydah Date: Wed, 16 Oct 2024 15:56:14 +0900 Subject: [PATCH 015/105] Fix typo in example_without_description_spec.rb --- spec/rubocop/cop/rspec/example_without_description_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/rubocop/cop/rspec/example_without_description_spec.rb b/spec/rubocop/cop/rspec/example_without_description_spec.rb index c3dad2ac1..1759505a6 100644 --- a/spec/rubocop/cop/rspec/example_without_description_spec.rb +++ b/spec/rubocop/cop/rspec/example_without_description_spec.rb @@ -84,7 +84,7 @@ RUBY end - it 'ignores `specify` missing decripton in multi-line examples' do + it 'ignores `specify` missing description in multi-line examples' do expect_no_offenses(<<~RUBY) specify do expect(subject).to be_good From c91e9d6a273d31d7e665a4f620c2d010a4613988 Mon Sep 17 00:00:00 2001 From: ydah Date: Wed, 16 Oct 2024 16:20:59 +0900 Subject: [PATCH 016/105] Add issue templates for bug reports and feature requests I think this will minimize the questions. --- .github/ISSUE_TEMPLATE/bug_report.md | 48 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 ++++++++++ 2 files changed, 68 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..e356c939e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,48 @@ +--- +name: Bug Report +about: Report an issue with RuboCop RSpec you've discovered. +--- + +*Be clear, concise and precise in your description of the problem. +Open an issue with a descriptive title and a summary in grammatically correct, +complete sentences.* + +*Use the template below when reporting bugs. Please, make sure that +you're running the latest stable RuboCop RSpec and that the problem you're reporting +hasn't been reported (and potentially fixed) already.* + +*Before filing the ticket you should replace all text above the horizontal +rule with your own words.* + +*In the case of false positive or false negative, please add the +corresponding cop name.* + +______________________________________________________________________ + +## Expected behavior + +Describe here how you expected RuboCop RSpec to behave in this particular situation. + +## Actual behavior + +Describe here what actually happened. +Please use `rubocop --debug` when pasting rubocop output as it contains additional information. + +## Steps to reproduce the problem + +This is extremely important! Providing us with a reliable way to reproduce +a problem will expedite its solution. + +## RuboCop RSpec version + +Include the output of `rubocop -V` or `bundle exec rubocop -V` if using Bundler. +If you see extension cop versions (e.g. `rubocop-performance`, `rubocop-rake`, and others) +output by `rubocop -V`, include them as well. Here's an example: + +```shell +$ [bundle exec] rubocop -V +1.67.0 (using Parser 3.3.5.0, rubocop-ast 1.32.3, analyzing as Ruby 2.7, running on ruby 3.4.0) [arm64-darwin23] + - rubocop-performance 1.22.1 + - rubocop-rake 0.6.0 + - rubocop-rspec 3.1.0 +``` diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..5c8eefd93 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature Request +about: Suggest new RuboCop RSpec features or improvements to existing features. +--- + +## Is your feature request related to a problem? Please describe. + +A clear and concise description of what the problem is. Ex. I'm always frustrated when \[...\] + +## Describe the solution you'd like + +A clear and concise description of what you want to happen. + +## Describe alternatives you've considered + +A clear and concise description of any alternative solutions or features you've considered. + +## Additional context + +Add any other context or screenshots about the feature request here. From 7e3149d7bf8e37f57970e4484d7798b4485b205e Mon Sep 17 00:00:00 2001 From: Dave Corson-Knowles Date: Mon, 14 Oct 2024 12:49:41 -0700 Subject: [PATCH 017/105] Require VoidExpect operate inside an example block --- CHANGELOG.md | 2 ++ lib/rubocop/cop/rspec/void_expect.rb | 7 ++++++- spec/rubocop/cop/rspec/void_expect_spec.rb | 22 ++++++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93499ceaf..a93ca6537 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +- Fix `RSpec/VoidExpect` to only operate inside an example block. ([@corsonknowles]) + ## 3.1.0 (2024-10-01) - Add `RSpec/StringAsInstanceDoubleConstant` to check for and correct strings used as instance_doubles. ([@corsonknowles]) diff --git a/lib/rubocop/cop/rspec/void_expect.rb b/lib/rubocop/cop/rspec/void_expect.rb index 8db6a496c..52f32147c 100644 --- a/lib/rubocop/cop/rspec/void_expect.rb +++ b/lib/rubocop/cop/rspec/void_expect.rb @@ -29,12 +29,14 @@ class VoidExpect < Base def on_send(node) return unless expect?(node) + return unless inside_example?(node) check_expect(node) end def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless expect_block?(node) + return unless inside_example?(node) check_expect(node) end @@ -49,11 +51,14 @@ def check_expect(node) def void?(expect) parent = expect.parent - return true unless parent return true if parent.begin_type? parent.block_type? && parent.body == expect end + + def inside_example?(node) + node.each_ancestor(:block).any? { |ancestor| example?(ancestor) } + end end end end diff --git a/spec/rubocop/cop/rspec/void_expect_spec.rb b/spec/rubocop/cop/rspec/void_expect_spec.rb index 5791d7161..1ccf3ae74 100644 --- a/spec/rubocop/cop/rspec/void_expect_spec.rb +++ b/spec/rubocop/cop/rspec/void_expect_spec.rb @@ -44,4 +44,26 @@ end RUBY end + + it 'ignores unrelated method named expect in an example block' do + expect_no_offenses(<<~RUBY) + it 'something' do + MyObject.expect(:foo) + end + RUBY + end + + context 'when expect has no parent node' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + expect(something) + RUBY + end + + it 'does not register an offense for unrelated expect with block' do + expect_no_offenses(<<~RUBY) + expect { block_contents } + RUBY + end + end end From 5a75070cf80910788fb6523094cfa007cb27f600 Mon Sep 17 00:00:00 2001 From: ydah Date: Tue, 22 Oct 2024 13:56:33 +0900 Subject: [PATCH 018/105] Change `RSpec/ContextWording` cop to always report an offense when both `Prefixes` and `AllowedPatterns` are empty see: https://github.com/rubocop/rubocop-rspec/pull/1972#discussion_r1808522184 --- CHANGELOG.md | 2 ++ docs/modules/ROOT/pages/cops_rspec.adoc | 3 +++ lib/rubocop/cop/rspec/context_wording.rb | 24 ++++++++++++------- .../rubocop/cop/rspec/context_wording_spec.rb | 7 +++--- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93499ceaf..cd89a961c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +- Change `RSpec/ContextWording` cop to always report an offense when both `Prefixes` and `AllowedPatterns` are empty. ([@ydah]) + ## 3.1.0 (2024-10-01) - Add `RSpec/StringAsInstanceDoubleConstant` to check for and correct strings used as instance_doubles. ([@corsonknowles]) diff --git a/docs/modules/ROOT/pages/cops_rspec.adoc b/docs/modules/ROOT/pages/cops_rspec.adoc index 5556dd086..20015bc0a 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -720,6 +720,9 @@ the configuration to meet project needs. Other acceptable prefixes may include `if`, `unless`, `for`, `before`, `after`, or `during`. They may consist of multiple words if desired. +If both `Prefixes` and `AllowedPatterns` are empty, this cop will always +report an offense. So you need to set at least one of them. + This cop can be customized allowed context description pattern with `AllowedPatterns`. By default, there are no checking by pattern. diff --git a/lib/rubocop/cop/rspec/context_wording.rb b/lib/rubocop/cop/rspec/context_wording.rb index 693c5c185..3fdba92f6 100644 --- a/lib/rubocop/cop/rspec/context_wording.rb +++ b/lib/rubocop/cop/rspec/context_wording.rb @@ -12,6 +12,9 @@ module RSpec # # @see http://www.betterspecs.org/#contexts # + # If both `Prefixes` and `AllowedPatterns` are empty, this cop will always + # report an offense. So you need to set at least one of them. + # # @example `Prefixes` configuration # # .rubocop.yml # # RSpec/ContextWording: @@ -58,7 +61,9 @@ module RSpec class ContextWording < Base include AllowedPattern - MSG = 'Context description should match %s.' + MSG_MATCH = 'Context description should match %s.' + MSG_ALWAYS = 'Current settings will always report an offense. Please ' \ + 'add allowed words to `Prefixes` or `AllowedPatterns`.' # @!method context_wording(node) def_node_matcher :context_wording, <<~PATTERN @@ -67,8 +72,7 @@ class ContextWording < Base def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler context_wording(node) do |context| - if bad_pattern?(context) - message = format(MSG, patterns: expect_patterns) + unless matches_allowed_pattern?(description(context)) add_offense(context, message: message) end end @@ -84,12 +88,6 @@ def prefix_regexes @prefix_regexes ||= prefixes.map { |pre| /^#{Regexp.escape(pre)}\b/ } end - def bad_pattern?(node) - return false if allowed_patterns.empty? - - !matches_allowed_pattern?(description(node)) - end - def description(context) if context.xstr_type? context.value.value @@ -98,6 +96,14 @@ def description(context) end end + def message + if allowed_patterns.empty? + MSG_ALWAYS + else + format(MSG_MATCH, patterns: expect_patterns) + end + end + def expect_patterns inspected = allowed_patterns.map do |pattern| pattern.inspect.gsub(/\A"|"\z/, '/') diff --git a/spec/rubocop/cop/rspec/context_wording_spec.rb b/spec/rubocop/cop/rspec/context_wording_spec.rb index 340d10181..de3394b53 100644 --- a/spec/rubocop/cop/rspec/context_wording_spec.rb +++ b/spec/rubocop/cop/rspec/context_wording_spec.rb @@ -220,9 +220,10 @@ { 'Prefixes' => [], 'AllowedPatterns' => [] } end - it 'skips any description' do - expect_no_offenses(<<~RUBY) - context 'arbitrary text' do + it 'always registers an offense' do + expect_offense(<<~RUBY) + context 'this is an incorrect context' do + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Current settings will always report an offense. Please add allowed words to `Prefixes` or `AllowedPatterns`. end RUBY end From 130c5641f1a1afff88513d0a8278656d157ab88f Mon Sep 17 00:00:00 2001 From: ydah Date: Wed, 23 Oct 2024 21:28:04 +0900 Subject: [PATCH 019/105] Fix an error for `RSpec/ChangeByZero` when `change (...) .by (0)` and `change (...)`, concatenated with `and` and `or` fix: https://github.com/rubocop/rubocop-rspec/issues/1983 --- CHANGELOG.md | 1 + lib/rubocop/cop/rspec/change_by_zero.rb | 6 +++- spec/rubocop/cop/rspec/change_by_zero_spec.rb | 30 +++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd89a961c..e7dd725c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Master (Unreleased) - Change `RSpec/ContextWording` cop to always report an offense when both `Prefixes` and `AllowedPatterns` are empty. ([@ydah]) +- Fix an error for `RSpec/ChangeByZero` when `change (...) .by (0)` and `change (...)`, concatenated with `and` and `or`. ([@ydah]) ## 3.1.0 (2024-10-01) diff --git a/lib/rubocop/cop/rspec/change_by_zero.rb b/lib/rubocop/cop/rspec/change_by_zero.rb index 1ee9a40b7..75d442c75 100644 --- a/lib/rubocop/cop/rspec/change_by_zero.rb +++ b/lib/rubocop/cop/rspec/change_by_zero.rb @@ -118,7 +118,11 @@ def register_offense(node, change_node) # rubocop:enable Metrics/MethodLength def compound_expectations?(node) - %i[and or & |].include?(node.parent.method_name) + if node.parent.send_type? + %i[and or & |].include?(node.parent.method_name) + else + node.parent.and_type? || node.parent.or_type? + end end def message(change_node) diff --git a/spec/rubocop/cop/rspec/change_by_zero_spec.rb b/spec/rubocop/cop/rspec/change_by_zero_spec.rb index 5f313895b..4e9604768 100644 --- a/spec/rubocop/cop/rspec/change_by_zero_spec.rb +++ b/spec/rubocop/cop/rspec/change_by_zero_spec.rb @@ -68,6 +68,10 @@ expect { foo }.to change { Foo.bar }.by(0).and change { Foo.baz }.by(0) ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. + expect { foo }.to change(Foo, :bar).by(0).and change(Foo, :baz) + ^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. + expect { foo }.to change { Foo.bar }.and change { Foo.baz }.by(0) + ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. end RUBY @@ -84,6 +88,10 @@ expect { foo }.to change { Foo.bar }.by(0) & change { Foo.baz }.by(0) ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. + expect { foo }.to change(Foo, :bar).by(0) & change(Foo, :baz) + ^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. + expect { foo }.to change { Foo.bar } & change { Foo.baz }.by(0) + ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. end RUBY @@ -100,6 +108,10 @@ expect { foo }.to change { Foo.bar }.by(0).or change { Foo.baz }.by(0) ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. + expect { foo }.to change(Foo, :bar).by(0).or change(Foo, :baz) + ^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. + expect { foo }.to change { Foo.bar }.or change { Foo.baz }.by(0) + ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. end RUBY @@ -116,6 +128,10 @@ expect { foo }.to change { Foo.bar }.by(0) | change { Foo.baz }.by(0) ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. + expect { foo }.to change(Foo, :bar) | change(Foo, :baz).by(0) + ^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. + expect { foo }.to change { Foo.bar }.by(0) | change { Foo.baz } + ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. end RUBY @@ -244,6 +260,14 @@ ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `not_change` with compound expectations over `change.by(0)`. .and change { Foo.baz }.by(0) ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `not_change` with compound expectations over `change.by(0)`. + expect { foo } + .to change(Foo, :bar) + .and change(Foo, :baz).by(0) + ^^^^^^^^^^^^^^^^^^^^^^^ Prefer `not_change` with compound expectations over `change.by(0)`. + expect { foo } + .to change { Foo.bar } + .and change { Foo.baz }.by(0) + ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `not_change` with compound expectations over `change.by(0)`. end RUBY @@ -255,6 +279,12 @@ expect { foo } .to not_change { Foo.bar } .and not_change { Foo.baz } + expect { foo } + .to change(Foo, :bar) + .and not_change(Foo, :baz) + expect { foo } + .to change { Foo.bar } + .and not_change { Foo.baz } end RUBY end From eb617486819a01ad76a08f50b0aa04cae3337dca Mon Sep 17 00:00:00 2001 From: Phil Pirozhkov Date: Fri, 25 Oct 2024 17:24:09 +0300 Subject: [PATCH 020/105] Revert an change that would conceal unintentional RSpec syntax Specifically: expect { ... }.to change { ... }.by(...) and change { ... }.by(...) Here the usage of `and` is incorrect, as RSpec does not (and can't reasonably) support it. Compound should use the `and` method, not the operator, or the `&`. Same for `.or` and `|`. --- CHANGELOG.md | 1 + lib/rubocop/cop/rspec/change_by_zero.rb | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7dd725c9..f1de7a001 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Change `RSpec/ContextWording` cop to always report an offense when both `Prefixes` and `AllowedPatterns` are empty. ([@ydah]) - Fix an error for `RSpec/ChangeByZero` when `change (...) .by (0)` and `change (...)`, concatenated with `and` and `or`. ([@ydah]) +- Revert an change that would conceal unintentional RSpec syntax. ([@pirj]) ## 3.1.0 (2024-10-01) diff --git a/lib/rubocop/cop/rspec/change_by_zero.rb b/lib/rubocop/cop/rspec/change_by_zero.rb index 75d442c75..82da74193 100644 --- a/lib/rubocop/cop/rspec/change_by_zero.rb +++ b/lib/rubocop/cop/rspec/change_by_zero.rb @@ -118,11 +118,8 @@ def register_offense(node, change_node) # rubocop:enable Metrics/MethodLength def compound_expectations?(node) - if node.parent.send_type? + node.parent.send_type? && %i[and or & |].include?(node.parent.method_name) - else - node.parent.and_type? || node.parent.or_type? - end end def message(change_node) From 6cbe4238dd5a4881758b9504670fb6893bae1be8 Mon Sep 17 00:00:00 2001 From: Phil Pirozhkov Date: Fri, 25 Oct 2024 18:20:12 +0300 Subject: [PATCH 021/105] Update CHANGELOG.md --- CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1de7a001..14afa61bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,7 @@ ## Master (Unreleased) - Change `RSpec/ContextWording` cop to always report an offense when both `Prefixes` and `AllowedPatterns` are empty. ([@ydah]) -- Fix an error for `RSpec/ChangeByZero` when `change (...) .by (0)` and `change (...)`, concatenated with `and` and `or`. ([@ydah]) -- Revert an change that would conceal unintentional RSpec syntax. ([@pirj]) +- Add support for `and` and `or` compound matchers to `RSpec/ChangeByZero` cop. ([@ydah]) ## 3.1.0 (2024-10-01) From b7d0877332c64a987df6ad9076f41e95cf0ae3a4 Mon Sep 17 00:00:00 2001 From: Dave Corson-Knowles Date: Mon, 14 Oct 2024 15:46:15 -0700 Subject: [PATCH 022/105] Deprecate top_level_group? and test it in a Cop class In this PR, we add a deprecation message for top_level_group?, which has no callers in current Rubocop/RSpec. The specs for this change complete line coverage for this repo. --- CHANGELOG.md | 1 + .../cop/rspec/mixin/top_level_group.rb | 6 +++++ .../cop/rspec/mixin/top_level_group_spec.rb | 24 +++++++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 spec/rubocop/cop/rspec/mixin/top_level_group_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index b911f161d..783874b7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Fix `RSpec/VoidExpect` to only operate inside an example block. ([@corsonknowles]) - Change `RSpec/ContextWording` cop to always report an offense when both `Prefixes` and `AllowedPatterns` are empty. ([@ydah]) - Fix an error for `RSpec/ChangeByZero` when `change (...) .by (0)` and `change (...)`, concatenated with `and` and `or`. ([@ydah]) +- Deprecate `top_level_group?` method from `TopLevelGroup` mixin as all of its callers were intentionally removed from `Rubocop/RSpec`. ([@corsonknowles]) ## 3.1.0 (2024-10-01) diff --git a/lib/rubocop/cop/rspec/mixin/top_level_group.rb b/lib/rubocop/cop/rspec/mixin/top_level_group.rb index c3b48fb1d..1d4d8c6a2 100644 --- a/lib/rubocop/cop/rspec/mixin/top_level_group.rb +++ b/lib/rubocop/cop/rspec/mixin/top_level_group.rb @@ -7,6 +7,9 @@ module RSpec module TopLevelGroup extend RuboCop::NodePattern::Macros + DEPRECATED_MODULE_METHOD_WARNING = + 'top_level_group? is deprecated and will be ' \ + 'removed in the next major version of rubocop_rspec.' def on_new_investigation super @@ -28,7 +31,10 @@ def on_top_level_example_group(_node); end def on_top_level_group(_node); end + # @private + # @deprecated All callers of this method have been removed. def top_level_group?(node) + warn DEPRECATED_MODULE_METHOD_WARNING, uplevel: 1 top_level_groups.include?(node) end diff --git a/spec/rubocop/cop/rspec/mixin/top_level_group_spec.rb b/spec/rubocop/cop/rspec/mixin/top_level_group_spec.rb new file mode 100644 index 000000000..251e3d711 --- /dev/null +++ b/spec/rubocop/cop/rspec/mixin/top_level_group_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::Cop::RSpec::TopLevelGroup do + describe '#top_level_group?' do + let(:stub_class) do + Class.new do + include RuboCop::Cop::RSpec::TopLevelGroup + + def initialize + @top_level_groups = [] + end + + def test_top_level_group + top_level_group?(nil) + end + end + end + + it 'warns because it is deprecated' do + expect { stub_class.new.test_top_level_group }.to \ + output(/warning: top_level_group\? is deprecated/).to_stderr + end + end +end From 39b0d3f8c1d6dd720cce3dd37782ee5b0d26d448 Mon Sep 17 00:00:00 2001 From: ydah Date: Sat, 26 Oct 2024 15:50:20 +0900 Subject: [PATCH 023/105] Release v3.2.0 --- CHANGELOG.md | 2 ++ docs/antora.yml | 2 +- lib/rubocop/rspec/version.rb | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2146a165d..73cb05892 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +## 3.2.0 (2024-10-26) + - Fix `RSpec/VoidExpect` to only operate inside an example block. ([@corsonknowles]) - Change `RSpec/ContextWording` cop to always report an offense when both `Prefixes` and `AllowedPatterns` are empty. ([@ydah]) - Add support for `and` and `or` compound matchers to `RSpec/ChangeByZero` cop. ([@ydah]) diff --git a/docs/antora.yml b/docs/antora.yml index 51a533a15..7cca04801 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -1,5 +1,5 @@ name: rubocop-rspec title: RuboCop RSpec -version: ~ +version: '3.2' nav: - modules/ROOT/nav.adoc diff --git a/lib/rubocop/rspec/version.rb b/lib/rubocop/rspec/version.rb index 334b1761a..e511c3f04 100644 --- a/lib/rubocop/rspec/version.rb +++ b/lib/rubocop/rspec/version.rb @@ -4,7 +4,7 @@ module RuboCop module RSpec # Version information for the RSpec RuboCop plugin. module Version - STRING = '3.1.0' + STRING = '3.2.0' end end end From 62e61b781f7e3de8c59d840425b232f84133fd0f Mon Sep 17 00:00:00 2001 From: ydah Date: Sat, 26 Oct 2024 08:04:15 +0000 Subject: [PATCH 024/105] Switch docs version back --- docs/antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/antora.yml b/docs/antora.yml index 7cca04801..51a533a15 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -1,5 +1,5 @@ name: rubocop-rspec title: RuboCop RSpec -version: '3.2' +version: ~ nav: - modules/ROOT/nav.adoc From feda95b026d3820e824180e3dbe022a79b5a4ded Mon Sep 17 00:00:00 2001 From: Dave Corson-Knowles Date: Sun, 13 Oct 2024 04:11:02 -0700 Subject: [PATCH 025/105] Update .simplecov Require full line coverage --- .simplecov | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.simplecov b/.simplecov index c09a9b47f..f039d5d74 100644 --- a/.simplecov +++ b/.simplecov @@ -2,7 +2,7 @@ SimpleCov.start do enable_coverage :branch - minimum_coverage line: 99.60, branch: 94.77 + minimum_coverage line: 100, branch: 96.39 add_filter '/spec/' add_filter '/vendor/bundle/' end From 94a509d7bc651668d5a505322df88887540effe2 Mon Sep 17 00:00:00 2001 From: Benjamin Quorning Date: Sat, 26 Oct 2024 10:54:41 +0200 Subject: [PATCH 026/105] Increase branch coverage value --- .simplecov | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.simplecov b/.simplecov index f039d5d74..91dedc280 100644 --- a/.simplecov +++ b/.simplecov @@ -2,7 +2,7 @@ SimpleCov.start do enable_coverage :branch - minimum_coverage line: 100, branch: 96.39 + minimum_coverage line: 100, branch: 96.79 add_filter '/spec/' add_filter '/vendor/bundle/' end From e5898c1562492f62abc88b5ee36fdffc46729c4b Mon Sep 17 00:00:00 2001 From: Benjamin Quorning Date: Sat, 26 Oct 2024 12:01:03 +0200 Subject: [PATCH 027/105] Improve branch coverage --- .simplecov | 2 +- .../rspec/empty_line_after_subject_spec.rb | 7 ++++ .../rspec/leaky_constant_declaration_spec.rb | 14 ++++++++ .../cop/rspec/return_from_stub_spec.rb | 34 +++++++++++++++++++ 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/.simplecov b/.simplecov index 91dedc280..37e9f727f 100644 --- a/.simplecov +++ b/.simplecov @@ -2,7 +2,7 @@ SimpleCov.start do enable_coverage :branch - minimum_coverage line: 100, branch: 96.79 + minimum_coverage line: 100, branch: 97.43 add_filter '/spec/' add_filter '/vendor/bundle/' end diff --git a/spec/rubocop/cop/rspec/empty_line_after_subject_spec.rb b/spec/rubocop/cop/rspec/empty_line_after_subject_spec.rb index e3bbccc13..a19239248 100644 --- a/spec/rubocop/cop/rspec/empty_line_after_subject_spec.rb +++ b/spec/rubocop/cop/rspec/empty_line_after_subject_spec.rb @@ -19,6 +19,13 @@ RUBY end + it 'does not register an offense outside of an example group' do + expect_no_offenses(<<~RUBY) + subject { foo } + bar + RUBY + end + it 'registers an offense for empty line after subject!' do expect_offense(<<~RUBY) RSpec.describe User do diff --git a/spec/rubocop/cop/rspec/leaky_constant_declaration_spec.rb b/spec/rubocop/cop/rspec/leaky_constant_declaration_spec.rb index 07d1e26e1..c3a6beb82 100644 --- a/spec/rubocop/cop/rspec/leaky_constant_declaration_spec.rb +++ b/spec/rubocop/cop/rspec/leaky_constant_declaration_spec.rb @@ -73,6 +73,13 @@ class SomeModule::AnotherModule::DummyClass end RUBY end + + it 'ignores outside of example/shared group' do + expect_no_offenses(<<~RUBY) + class DummyClass + end + RUBY + end end describe 'module defined' do @@ -85,5 +92,12 @@ module DummyModule end RUBY end + + it 'ignores outside of example/shared group' do + expect_no_offenses(<<~RUBY) + module Dummymodule + end + RUBY + end end end diff --git a/spec/rubocop/cop/rspec/return_from_stub_spec.rb b/spec/rubocop/cop/rspec/return_from_stub_spec.rb index 5c4371a6f..2b5451ffe 100644 --- a/spec/rubocop/cop/rspec/return_from_stub_spec.rb +++ b/spec/rubocop/cop/rspec/return_from_stub_spec.rb @@ -176,6 +176,21 @@ RUBY end + it 'registers, but does not try to autocorrect, heredocs' do + expect_offense(<<~RUBY) + it do + allow(Foo).to receive(:bar) do + ^^ Use `and_return` for static values. + <<-TXT + You called me + TXT + end + end + RUBY + + expect_no_corrections + end + it 'does not register an offense for a stub without return value' do expect_no_offenses(<<~RUBY) it do @@ -214,6 +229,19 @@ def stub_foo RUBY end + it 'registers, but does not try to autocorrect, heredocs' do + expect_offense(<<~RUBY) + it do + allow(Foo).to receive(:bar).and_return(<<-TXT) + ^^^^^^^^^^ Use block for static values. + You called me + TXT + end + RUBY + + expect_no_corrections + end + it 'does not register an offense for dynamic values returned from method' do expect_no_offenses(<<~RUBY) it do @@ -283,5 +311,11 @@ def stub_foo 'me' } RUBY end + + it 'ignores irrelevant #and_return methods' do + expect_no_offenses(<<~RUBY) + library.visit.and_return(book) + RUBY + end end end From d5c48e602bad4d8ac3570780243dd449dab79147 Mon Sep 17 00:00:00 2001 From: Benjamin Quorning Date: Thu, 17 Oct 2024 13:26:39 +0200 Subject: [PATCH 028/105] Add job for CI using Prism parser Copied from https://github.com/rubocop/rubocop-capybara/pull/112 Co-authored-by: ydah --- .github/workflows/main.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 785a677df..ce87855bd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -119,3 +119,24 @@ jobs: ruby-version: "3.3" bundler-cache: true - run: NO_COVERAGE=true bundle exec rake spec + + prism: + runs-on: ubuntu-latest + name: Prism + steps: + - uses: actions/checkout@v4 + - name: Use prism parser + run: | + cat << EOF > Gemfile.local + gem 'prism' + EOF + - name: set up Ruby + uses: ruby/setup-ruby@v1 + with: + # Specify the minimum Ruby version 2.7 required for Prism to run. + ruby-version: "2.7" + bundler-cache: true + - env: + NO_COVERAGE: true + PARSER_ENGINE: parser_prism + run: bundle exec rake spec From e0509b96030c8dff2ba4c12d6b76677822c17ae5 Mon Sep 17 00:00:00 2001 From: Dave Corson-Knowles Date: Wed, 30 Oct 2024 06:38:23 -0700 Subject: [PATCH 029/105] Experiment with trailing empty lines --- .../rspec/excessive_docstring_spacing_spec.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/spec/rubocop/cop/rspec/excessive_docstring_spacing_spec.rb b/spec/rubocop/cop/rspec/excessive_docstring_spacing_spec.rb index ec0ee7d94..00c071bb6 100644 --- a/spec/rubocop/cop/rspec/excessive_docstring_spacing_spec.rb +++ b/spec/rubocop/cop/rspec/excessive_docstring_spacing_spec.rb @@ -755,4 +755,21 @@ end RUBY end + + it 'flags \-separated multiline interpolated strings with ' \ + 'leading whitespace and corrects trailing empty lines' do + expect_offense(<<~'RUBY') + describe " ##{object} " \ + ^^^^^^^^^^^^^^^^ Excessive whitespace. + "(is cool)" \ + ' ' \ + " " do + end + RUBY + + expect_correction(<<~'RUBY') + describe "##{object} (is cool)" do + end + RUBY + end end From 5d0fbfb2dce5e8a8c37654743aa8458b7384ef01 Mon Sep 17 00:00:00 2001 From: Dave Corson-Knowles Date: Wed, 30 Oct 2024 05:37:31 -0700 Subject: [PATCH 030/105] Cover and then remove `ancestor.send_type?` branch in `UnspecifiedException` Wraps a non-send type conditional branch around `raise_error` spec --- lib/rubocop/cop/rspec/unspecified_exception.rb | 1 - spec/rubocop/cop/rspec/unspecified_exception_spec.rb | 7 +++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rspec/unspecified_exception.rb b/lib/rubocop/cop/rspec/unspecified_exception.rb index 30d4c49af..e7d90fec1 100644 --- a/lib/rubocop/cop/rspec/unspecified_exception.rb +++ b/lib/rubocop/cop/rspec/unspecified_exception.rb @@ -64,7 +64,6 @@ def empty_exception_matcher?(node) def find_expect_to(node) node.each_ancestor.find do |ancestor| break if ancestor.block_type? - next unless ancestor.send_type? expect_to?(ancestor) end diff --git a/spec/rubocop/cop/rspec/unspecified_exception_spec.rb b/spec/rubocop/cop/rspec/unspecified_exception_spec.rb index 8c41e6b30..8269209f8 100644 --- a/spec/rubocop/cop/rspec/unspecified_exception_spec.rb +++ b/spec/rubocop/cop/rspec/unspecified_exception_spec.rb @@ -254,5 +254,12 @@ def raise_error }.to raise_exception(StandardError) RUBY end + + it 'detects even when a non-send node is an ancestor' do + expect_offense(<<~RUBY) + expect { raise 'error' }.to (branch_conditional ? raise_error : handle_exception) + ^^^^^^^^^^^ Specify the exception being captured + RUBY + end end end From 9ca0da8b9bbff1dfc542ca56ddbc30cc19c76add Mon Sep 17 00:00:00 2001 From: Dave Corson-Knowles Date: Sat, 26 Oct 2024 11:24:12 -0700 Subject: [PATCH 031/105] Complete branch coverage for more files --- .rubocop_todo.yml | 6 +--- .simplecov | 2 +- lib/rubocop/rspec/hook.rb | 2 +- spec/rubocop/cop/rspec/instance_spy_spec.rb | 10 ++++++ spec/rubocop/rspec/hook_spec.rb | 34 ++++++++++++++++-- spec/rubocop/rspec/inject_spec.rb | 40 +++++++++++++++++++++ 6 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 spec/rubocop/rspec/inject_spec.rb diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index eef920c77..99d9bf300 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,15 +1,11 @@ # This configuration was generated by # `rubocop --auto-gen-config --no-offense-counts --no-auto-gen-timestamp` -# using RuboCop version 1.63.4. +# using RuboCop version 1.68.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -Lint/ToEnumArguments: - Exclude: - - 'lib/rubocop/cop/rspec/multiple_expectations.rb' - Rake/MethodDefinitionInTask: Exclude: - 'tasks/cut_release.rake' diff --git a/.simplecov b/.simplecov index 37e9f727f..81ecd5fae 100644 --- a/.simplecov +++ b/.simplecov @@ -2,7 +2,7 @@ SimpleCov.start do enable_coverage :branch - minimum_coverage line: 100, branch: 97.43 + minimum_coverage line: 100, branch: 97.94 add_filter '/spec/' add_filter '/vendor/bundle/' end diff --git a/lib/rubocop/rspec/hook.rb b/lib/rubocop/rspec/hook.rb index d0272c156..90116a75e 100644 --- a/lib/rubocop/rspec/hook.rb +++ b/lib/rubocop/rspec/hook.rb @@ -45,7 +45,7 @@ def metadata private def valid_scope?(node) - node&.sym_type? && Language::HookScopes.all(node.value) + node.sym_type? && Language::HookScopes.all(node.value) end def transform_metadata(meta) diff --git a/spec/rubocop/cop/rspec/instance_spy_spec.rb b/spec/rubocop/cop/rspec/instance_spy_spec.rb index 9807003b2..94f0d360f 100644 --- a/spec/rubocop/cop/rspec/instance_spy_spec.rb +++ b/spec/rubocop/cop/rspec/instance_spy_spec.rb @@ -44,6 +44,16 @@ end RUBY end + + it 'ignores instance_double when expect is called on another variable' do + expect_no_offenses(<<~RUBY) + it do + foo = instance_double(Foo).as_null_object + bar = instance_spy(Bar).as_null_object + expect(bar).to have_received(:baz) + end + RUBY + end end context 'when not used with `have_received`' do diff --git a/spec/rubocop/rspec/hook_spec.rb b/spec/rubocop/rspec/hook_spec.rb index ad9493527..9cf2e59b4 100644 --- a/spec/rubocop/rspec/hook_spec.rb +++ b/spec/rubocop/rspec/hook_spec.rb @@ -45,6 +45,11 @@ def hook(source) .to be(:each) end + it 'ignores invalid hooks' do + expect(hook('before(:invalid) { example_setup }').scope) + .to be_nil + end + it 'classifies :each as an example hook' do expect(hook('before(:each) { }').example?).to be(true) end @@ -75,9 +80,13 @@ def metadata(source) end if RUBY_VERSION >= '3.4' + let(:expected_focus) { 's(:sym, :focus) => true' } + let(:expected_invalid) { '{s(:sym, :invalid) => true}' } let(:expected_special) { 's(:sym, :special) => true' } let(:expected_symbol) { 's(:sym, :symbol) => true' } else + let(:expected_focus) { 's(:sym, :focus)=>true' } + let(:expected_invalid) { '{s(:sym, :invalid)=>true}' } let(:expected_special) { 's(:sym, :special)=>true' } let(:expected_symbol) { 's(:sym, :symbol)=>true' } end @@ -103,8 +112,29 @@ def metadata(source) end it 'withstands no arguments' do - expect(metadata('before { foo }')) - .to be_empty + expect(metadata('before { foo }')).to be_empty + end + + it 'returns the symbol even when an invalid symbol scope is provided' do + expect(metadata('before(:invalid) { foo }')).to eq(expected_invalid) + end + + it 'extracts multiple symbol metadata' do + expect(metadata('before(:example, :special, :focus) { foo }')) + .to eq("{#{expected_special}, #{expected_focus}}") + end + + it 'extracts multiple hash metadata' do + expect(metadata('before(:example, special: true, focus: true) { foo }')) + .to eq("{#{expected_special}, #{expected_focus}}") + end + + it 'combines multiple symbol and hash metadata' do + expect( + metadata( + 'before(:example, :symbol, special: true, focus: true) { foo }' + ) + ).to eq("{#{expected_symbol}, #{expected_special}, #{expected_focus}}") end end end diff --git a/spec/rubocop/rspec/inject_spec.rb b/spec/rubocop/rspec/inject_spec.rb new file mode 100644 index 000000000..44f98070f --- /dev/null +++ b/spec/rubocop/rspec/inject_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::RSpec::Inject do + describe '.defaults!' do + let(:config_loader) { class_double(RuboCop::ConfigLoader).as_stubbed_const } + + before do + rubocop_config = instance_double(RuboCop::Config) + allow(config_loader).to receive(:send) + .with(:load_yaml_configuration, any_args) + .and_return({}) + allow(RuboCop::Config).to receive(:new).and_return(rubocop_config) + allow(config_loader).to receive(:merge_with_default) + .and_return(rubocop_config) + allow(config_loader).to receive(:instance_variable_set) + end + + context 'when ConfigLoader.debug? is true' do + before do + allow(config_loader).to receive(:debug?).and_return(true) + end + + it 'puts the configuration path' do + expect { described_class.defaults! }.to output( + %r{configuration from .*rubocop-rspec/config/default.yml} + ).to_stdout + end + end + + context 'when ConfigLoader.debug? is false' do + before do + allow(config_loader).to receive(:debug?).and_return(false) + end + + it 'does not put the configuration path' do + expect { described_class.defaults! }.not_to output.to_stdout + end + end + end +end From 2f4763e81be1e5a0f84612ac76cfa97c0136784a Mon Sep 17 00:00:00 2001 From: Dave Corson-Knowles Date: Sat, 2 Nov 2024 14:52:03 -0700 Subject: [PATCH 032/105] Add an else condition to correct `StubbedMock` behavior --- lib/rubocop/cop/rspec/stubbed_mock.rb | 21 ++++++++++++--------- spec/rubocop/cop/rspec/stubbed_mock_spec.rb | 9 ++++++++- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/lib/rubocop/cop/rspec/stubbed_mock.rb b/lib/rubocop/cop/rspec/stubbed_mock.rb index 0b7d0a0a7..1787246c5 100644 --- a/lib/rubocop/cop/rspec/stubbed_mock.rb +++ b/lib/rubocop/cop/rspec/stubbed_mock.rb @@ -14,8 +14,9 @@ module RSpec # expect(foo).to receive(:bar).with(42) # class StubbedMock < Base - MSG = 'Prefer `%s` over `%s` when ' \ + MSG = 'Prefer %s over `%s` when ' \ 'configuring a response.' + RESTRICT_ON_SEND = %i[to].freeze # @!method message_expectation?(node) # Match message expectation matcher @@ -133,8 +134,6 @@ class StubbedMock < Base } PATTERN - RESTRICT_ON_SEND = %i[to].freeze - def on_send(node) expectation(node) do |expectation, method_name, matcher| on_expectation(expectation, method_name, matcher) @@ -155,19 +154,23 @@ def on_expectation(expectation, method_name, matcher) end def msg(method_name) - format(MSG, - method_name: method_name, - replacement: replacement(method_name)) + format( + MSG, + method_name: method_name, + replacement: replacement(method_name) + ) end def replacement(method_name) case method_name when :expect - :allow + '`allow`' when :is_expected - 'allow(subject)' + '`allow(subject)`' when :expect_any_instance_of - :allow_any_instance_of + '`allow_any_instance_of`' + else + 'an allow statement' end end end diff --git a/spec/rubocop/cop/rspec/stubbed_mock_spec.rb b/spec/rubocop/cop/rspec/stubbed_mock_spec.rb index 37ee2e686..1c920b638 100644 --- a/spec/rubocop/cop/rspec/stubbed_mock_spec.rb +++ b/spec/rubocop/cop/rspec/stubbed_mock_spec.rb @@ -126,7 +126,7 @@ RUBY end - it 'tolerates passed arguments without parentheses' do + it 'flags even when passed arguments without parentheses' do expect_offense(<<~RUBY) expect(Foo) ^^^^^^^^^^^ Prefer `allow` over `expect` when configuring a response. @@ -134,4 +134,11 @@ .with(bar).and_return baz RUBY end + + it 'flags `are_expected`' do + expect_offense(<<~RUBY) + are_expected.to receive(:bar).and_return(:baz) + ^^^^^^^^^^^^ Prefer an allow statement over `are_expected` when configuring a response. + RUBY + end end From c270e66e786bcf6b985df8f33dd7d52e72f6abb2 Mon Sep 17 00:00:00 2001 From: ydah Date: Fri, 6 Dec 2024 15:58:37 +0900 Subject: [PATCH 033/105] Fix formatting in some markdown files --- .github/ISSUE_TEMPLATE/feature_request.md | 2 +- CHANGELOG.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 5c8eefd93..0cffb2019 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -5,7 +5,7 @@ about: Suggest new RuboCop RSpec features or improvements to existing features. ## Is your feature request related to a problem? Please describe. -A clear and concise description of what the problem is. Ex. I'm always frustrated when \[...\] +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] ## Describe the solution you'd like diff --git a/CHANGELOG.md b/CHANGELOG.md index 41551a09d..4b640f048 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -742,7 +742,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features. ## 1.13.0 (2017-03-07) - Add repeated 'it' detection to `RSpec/ExampleWording` cop. ([@dgollahon]) -- Add \[observed_nesting/max_nesting\] info to `RSpec/NestedGroups` messages. ([@dgollahon]) +- Add [observed_nesting/max_nesting] info to `RSpec/NestedGroups` messages. ([@dgollahon]) - Add `RSpec/ItBehavesLike` cop. ([@dgollahon]) - Add `RSpec/SharedContext` cop. ([@Darhazer]) - `RSpec/MultipleExpectations`: Count aggregate_failures block as single expectation. ([@Darhazer]) From a115a93dff3441d7b965f8bee0a72bff57d26c36 Mon Sep 17 00:00:00 2001 From: Benjamin Quorning Date: Wed, 20 Nov 2024 11:29:04 +0100 Subject: [PATCH 034/105] Use Node extensions instead of *splat --- lib/rubocop/cop/rspec/around_block.rb | 6 ++---- lib/rubocop/cop/rspec/single_argument_message_chain.rb | 7 +++---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/rubocop/cop/rspec/around_block.rb b/lib/rubocop/cop/rspec/around_block.rb index 0c992b009..c10d8f183 100644 --- a/lib/rubocop/cop/rspec/around_block.rb +++ b/lib/rubocop/cop/rspec/around_block.rb @@ -69,15 +69,13 @@ def add_no_arg_offense(node) end def check_for_unused_proxy(block, proxy) - name, = *proxy - find_arg_usage(block) do |usage| - return if usage.include?(s(:lvar, name)) + return if usage.include?(s(:lvar, proxy.name)) end add_offense( proxy, - message: format(MSG_UNUSED_ARG, arg: name) + message: format(MSG_UNUSED_ARG, arg: proxy.name) ) end diff --git a/lib/rubocop/cop/rspec/single_argument_message_chain.rb b/lib/rubocop/cop/rspec/single_argument_message_chain.rb index dbc772301..66e6afdd6 100644 --- a/lib/rubocop/cop/rspec/single_argument_message_chain.rb +++ b/lib/rubocop/cop/rspec/single_argument_message_chain.rb @@ -67,11 +67,10 @@ def single_element_array?(node) end def autocorrect_hash_arg(corrector, arg) - key, value = *arg.children.first - - corrector.replace(arg, key_to_arg(key)) + pair = arg.pairs.first + corrector.replace(arg, key_to_arg(pair.key)) corrector.insert_after(arg.parent.loc.end, - ".and_return(#{value.source})") + ".and_return(#{pair.value.source})") end def autocorrect_array_arg(corrector, arg) From 48326255c146350ad1757dea4525f2aba6415757 Mon Sep 17 00:00:00 2001 From: Phil Pirozhkov Date: Wed, 11 Dec 2024 23:59:31 +0300 Subject: [PATCH 035/105] Fix EmptyMetadata for splat kwargs --- CHANGELOG.md | 1 + lib/rubocop/cop/rspec/empty_metadata.rb | 1 + spec/rubocop/cop/rspec/empty_metadata_spec.rb | 7 +++++++ 3 files changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b640f048..fb2a0d385 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Master (Unreleased) - Deprecate `top_level_group?` method from `TopLevelGroup` mixin as all of its callers were intentionally removed from `Rubocop/RSpec`. ([@corsonknowles]) +- Fix false positive for RSpec/EmptyMetadata for splat kwargs. ([@pirj]) ## 3.2.0 (2024-10-26) diff --git a/lib/rubocop/cop/rspec/empty_metadata.rb b/lib/rubocop/cop/rspec/empty_metadata.rb index 7cb3e9483..390059c31 100644 --- a/lib/rubocop/cop/rspec/empty_metadata.rb +++ b/lib/rubocop/cop/rspec/empty_metadata.rb @@ -21,6 +21,7 @@ class EmptyMetadata < Base def on_metadata(_symbols, hash) return unless hash&.pairs&.empty? + return if hash.children.any?(&:kwsplat_type?) add_offense(hash) do |corrector| remove_empty_metadata(corrector, hash) diff --git a/spec/rubocop/cop/rspec/empty_metadata_spec.rb b/spec/rubocop/cop/rspec/empty_metadata_spec.rb index 25ee913fc..8a36b6f85 100644 --- a/spec/rubocop/cop/rspec/empty_metadata_spec.rb +++ b/spec/rubocop/cop/rspec/empty_metadata_spec.rb @@ -33,4 +33,11 @@ RUBY end end + + it 'registers no offense for splat kwargs metadata' do + expect_no_offenses(<<~RUBY) + describe 'Something', **{ a: b } do + end + RUBY + end end From 3c4c64ed8ea2a9d02d30c6566716addacc80ac66 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Thu, 12 Dec 2024 13:01:40 +0100 Subject: [PATCH 036/105] Update RSpec 4 CI to the monorepo Also see https://github.com/rubocop/rubocop/pull/13576 --- .github/workflows/main.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ce87855bd..69b9dfb6d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -108,11 +108,11 @@ jobs: run: | sed -e '/rspec/d' -i Gemfile cat << EOF > Gemfile.local - gem 'rspec', github: 'rspec/rspec-metagem', branch: '4-0-dev' - gem 'rspec-core', github: 'rspec/rspec-core', branch: '4-0-dev' - gem 'rspec-expectations', github: 'rspec/rspec-expectations', branch: '4-0-dev' - gem 'rspec-mocks', github: 'rspec/rspec-mocks', branch: '4-0-dev' - gem 'rspec-support', github: 'rspec/rspec-support', branch: '4-0-dev' + gem 'rspec', github: 'rspec/rspec', branch: '4-0-dev' + gem 'rspec-core', github: 'rspec/rspec', branch: '4-0-dev' + gem 'rspec-expectations', github: 'rspec/rspec', branch: '4-0-dev' + gem 'rspec-mocks', github: 'rspec/rspec', branch: '4-0-dev' + gem 'rspec-support', github: 'rspec/rspec', branch: '4-0-dev' EOF - uses: ruby/setup-ruby@v1 with: From 737f2d02aed0bf4d435da4f1ee6af9e4b73e8fc1 Mon Sep 17 00:00:00 2001 From: Benjamin Quorning Date: Thu, 12 Dec 2024 13:14:25 +0100 Subject: [PATCH 037/105] CI: Add actions:write to gem-publish workflow The last step in this workflow's publish run opens a PR, but the actions are not running on the PR, requiring a manual triggering or force-push. It will save us time if this way, we can merge the created PR sooner. --- .github/workflows/publish.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index de3c2d7ae..d998a5008 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -8,6 +8,7 @@ jobs: name: Publish to RubyGems runs-on: ubuntu-latest permissions: + actions: write contents: write id-token: write pull-requests: write From 47365dc93b07dea5822c65be06df25d6395245a7 Mon Sep 17 00:00:00 2001 From: Benjamin Quorning Date: Thu, 12 Dec 2024 13:00:36 +0100 Subject: [PATCH 038/105] Release v3.3.0 --- CHANGELOG.md | 2 ++ docs/antora.yml | 2 +- lib/rubocop/rspec/version.rb | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb2a0d385..aa199ab0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +## 3.3.0 (2024-12-12) + - Deprecate `top_level_group?` method from `TopLevelGroup` mixin as all of its callers were intentionally removed from `Rubocop/RSpec`. ([@corsonknowles]) - Fix false positive for RSpec/EmptyMetadata for splat kwargs. ([@pirj]) diff --git a/docs/antora.yml b/docs/antora.yml index 51a533a15..e1117437d 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -1,5 +1,5 @@ name: rubocop-rspec title: RuboCop RSpec -version: ~ +version: '3.3' nav: - modules/ROOT/nav.adoc diff --git a/lib/rubocop/rspec/version.rb b/lib/rubocop/rspec/version.rb index e511c3f04..45e946f97 100644 --- a/lib/rubocop/rspec/version.rb +++ b/lib/rubocop/rspec/version.rb @@ -4,7 +4,7 @@ module RuboCop module RSpec # Version information for the RSpec RuboCop plugin. module Version - STRING = '3.2.0' + STRING = '3.3.0' end end end From 6759438b5bc4591fd658ce38a9378ba2cf14eb13 Mon Sep 17 00:00:00 2001 From: bquorning Date: Thu, 12 Dec 2024 12:50:03 +0000 Subject: [PATCH 039/105] Switch docs version back --- docs/antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/antora.yml b/docs/antora.yml index e1117437d..51a533a15 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -1,5 +1,5 @@ name: rubocop-rspec title: RuboCop RSpec -version: '3.3' +version: ~ nav: - modules/ROOT/nav.adoc From 9a00e8b15b9ba402b104029613d7b911e58754ab Mon Sep 17 00:00:00 2001 From: Kouhei Yanagita Date: Mon, 23 Dec 2024 16:48:20 +0900 Subject: [PATCH 040/105] [DOC] Remove duplicated examples --- docs/modules/ROOT/pages/cops_rspec.adoc | 6 ------ lib/rubocop/cop/rspec/focus.rb | 6 ------ 2 files changed, 12 deletions(-) diff --git a/docs/modules/ROOT/pages/cops_rspec.adoc b/docs/modules/ROOT/pages/cops_rspec.adoc index 20015bc0a..3e81d5240 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -2331,12 +2331,6 @@ fdescribe 'test' do; end # good describe 'test' do; end -# bad -fdescribe 'test' do; end - -# good -describe 'test' do; end - # bad shared_examples 'test', focus: true do; end diff --git a/lib/rubocop/cop/rspec/focus.rb b/lib/rubocop/cop/rspec/focus.rb index 116277280..246352ad5 100644 --- a/lib/rubocop/cop/rspec/focus.rb +++ b/lib/rubocop/cop/rspec/focus.rb @@ -29,12 +29,6 @@ module RSpec # describe 'test' do; end # # # bad - # fdescribe 'test' do; end - # - # # good - # describe 'test' do; end - # - # # bad # shared_examples 'test', focus: true do; end # # # good From f636e7f33b421105021af3aa79c36e738fba96a1 Mon Sep 17 00:00:00 2001 From: Kouhei Yanagita Date: Tue, 24 Dec 2024 20:30:44 +0900 Subject: [PATCH 041/105] [DOC] Fix markup for lists --- docs/modules/ROOT/pages/cops_rspec.adoc | 2 ++ lib/rubocop/cop/rspec/contain_exactly.rb | 1 + lib/rubocop/cop/rspec/match_array.rb | 1 + 3 files changed, 4 insertions(+) diff --git a/docs/modules/ROOT/pages/cops_rspec.adoc b/docs/modules/ROOT/pages/cops_rspec.adoc index 3e81d5240..85a6c21ef 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -632,6 +632,7 @@ expect(object).to be_a_kind_of(String) Checks where `contain_exactly` is used. This cop checks for the following: + - Prefer `match_array` when matching array values. - Prefer `be_empty` when using `contain_exactly` with no arguments. @@ -3381,6 +3382,7 @@ end Checks where `match_array` is used. This cop checks for the following: + - Prefer `contain_exactly` when matching an array with values. - Prefer `eq` when using `match_array` with an empty array literal. diff --git a/lib/rubocop/cop/rspec/contain_exactly.rb b/lib/rubocop/cop/rspec/contain_exactly.rb index 65eb8742f..bdb44ed8d 100644 --- a/lib/rubocop/cop/rspec/contain_exactly.rb +++ b/lib/rubocop/cop/rspec/contain_exactly.rb @@ -6,6 +6,7 @@ module RSpec # Checks where `contain_exactly` is used. # # This cop checks for the following: + # # - Prefer `match_array` when matching array values. # - Prefer `be_empty` when using `contain_exactly` with no arguments. # diff --git a/lib/rubocop/cop/rspec/match_array.rb b/lib/rubocop/cop/rspec/match_array.rb index b92e5f227..17e32a907 100644 --- a/lib/rubocop/cop/rspec/match_array.rb +++ b/lib/rubocop/cop/rspec/match_array.rb @@ -6,6 +6,7 @@ module RSpec # Checks where `match_array` is used. # # This cop checks for the following: + # # - Prefer `contain_exactly` when matching an array with values. # - Prefer `eq` when using `match_array` with an empty array literal. # From 1971c32f6c3b41553cf55f92a66d4dce0fb9bbcd Mon Sep 17 00:00:00 2001 From: ydah Date: Tue, 24 Dec 2024 23:52:13 +0900 Subject: [PATCH 042/105] Remove unused method matcher for pending steps without reason --- lib/rubocop/cop/rspec/pending_without_reason.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/rubocop/cop/rspec/pending_without_reason.rb b/lib/rubocop/cop/rspec/pending_without_reason.rb index c710703a9..5f72bcd1f 100644 --- a/lib/rubocop/cop/rspec/pending_without_reason.rb +++ b/lib/rubocop/cop/rspec/pending_without_reason.rb @@ -94,11 +94,6 @@ class PendingWithoutReason < Base (send #rspec? ${#ExampleGroups.skipped} ...) PATTERN - # @!method pending_step_without_reason?(node) - def_node_matcher :pending_step_without_reason?, <<~PATTERN - (send nil? {:skip :pending}) - PATTERN - def on_send(node) on_pending_by_metadata(node) return unless (parent = parent_node(node)) From 207434c75bca343e7efcfe47362c2affc27a6e7a Mon Sep 17 00:00:00 2001 From: ydah Date: Wed, 25 Dec 2024 20:32:42 +0900 Subject: [PATCH 043/105] Update Ruby version in GitHub Actions workflow to 3.4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ruby 3.4 has been released🎉 https://www.ruby-lang.org/en/news/2024/12/25/ruby-3-4-0-released/ --- .github/workflows/main.yml | 11 ++++++----- docs/modules/ROOT/pages/cops_rspec.adoc | 8 ++++---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 69b9dfb6d..2552c68b2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 with: - ruby-version: "3.3" + ruby-version: "3.4" bundler-cache: true - run: bundle exec rake confirm_config documentation_syntax_check confirm_documentation @@ -32,6 +32,7 @@ jobs: - "3.1" - "3.2" - "3.3" + - "3.4" - ruby-head - jruby-9.4 task: @@ -53,7 +54,7 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 with: - ruby-version: "3.3" + ruby-version: "3.4" bundler-cache: true - run: bundle exec rake spec @@ -73,7 +74,7 @@ jobs: cat Gemfile.local - uses: ruby/setup-ruby@v1 with: - ruby-version: "3.3" + ruby-version: "3.4" bundler-cache: true - run: bundle exec rubocop -V - run: NO_COVERAGE=true bundle exec rake ${{ matrix.task }} @@ -94,7 +95,7 @@ jobs: cat Gemfile.local - uses: ruby/setup-ruby@v1 with: - ruby-version: "3.3" + ruby-version: "3.4" bundler-cache: true - run: bundle exec rubocop -V - run: NO_COVERAGE=true bundle exec rake ${{ matrix.task }} @@ -116,7 +117,7 @@ jobs: EOF - uses: ruby/setup-ruby@v1 with: - ruby-version: "3.3" + ruby-version: "3.4" bundler-cache: true - run: NO_COVERAGE=true bundle exec rake spec diff --git a/docs/modules/ROOT/pages/cops_rspec.adoc b/docs/modules/ROOT/pages/cops_rspec.adoc index 85a6c21ef..0d235a7c4 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -870,7 +870,7 @@ end | Array | IgnoredMetadata -| `{"type"=>["channel", "controller", "helper", "job", "mailer", "model", "request", "routing", "view", "feature", "system", "mailbox", "aruba", "task"]}` +| `{"type" => ["channel", "controller", "helper", "job", "mailer", "model", "request", "routing", "view", "feature", "system", "mailbox", "aruba", "task"]}` | |=== @@ -1994,7 +1994,7 @@ end | Name | Default value | Configurable values | CustomTransform -| `{"be"=>"is", "BE"=>"IS", "have"=>"has", "HAVE"=>"HAS"}` +| `{"be" => "is", "BE" => "IS", "have" => "has", "HAVE" => "HAS"}` | | IgnoredWords @@ -5838,7 +5838,7 @@ whatever_spec.rb # describe MyClass, type: :routing do; end | Array | CustomTransform -| `{"RuboCop"=>"rubocop", "RSpec"=>"rspec"}` +| `{"RuboCop" => "rubocop", "RSpec" => "rspec"}` | | IgnoreMethods @@ -5846,7 +5846,7 @@ whatever_spec.rb # describe MyClass, type: :routing do; end | Boolean | IgnoreMetadata -| `{"type"=>"routing"}` +| `{"type" => "routing"}` | |=== From 8cfe4c57d4e9f4ccc6b225e781dd35bf2fd520cf Mon Sep 17 00:00:00 2001 From: ydah Date: Wed, 25 Dec 2024 23:05:21 +0900 Subject: [PATCH 044/105] Remove an example which is a syntax error in Ruby's parser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This code generates a syntax error as follows: ```ruby ❯ ruby -e '[1].each { put _1; [1].each { put _1 } }' -e: -e:1: syntax error found (SyntaxError) > 1 | ... _1 } } | ^~ numbered parameter is already used in outer block ``` When numbered parameters are used in nested blocks, it is not possible to use numbered parameters in multiple different hierarchies. While it was considered to split these up, we discussed below. https://github.com/rubocop/rubocop-rspec/pull/2014#discussion_r1897371078 --- .../cop/rspec/pending_without_reason_spec.rb | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/spec/rubocop/cop/rspec/pending_without_reason_spec.rb b/spec/rubocop/cop/rspec/pending_without_reason_spec.rb index 9e678e859..4c6a70f91 100644 --- a/spec/rubocop/cop/rspec/pending_without_reason_spec.rb +++ b/spec/rubocop/cop/rspec/pending_without_reason_spec.rb @@ -300,35 +300,6 @@ end RUBY end - - context 'with a numblock' do - it 'registers offense' do - expect_offense(<<~RUBY) - RSpec.describe Foo do - pending - ^^^^^^^ Give the reason for pending. - skip - ^^^^ Give the reason for skip. - _1 - context 'when something' do - _1 - pending - ^^^^^^^ Give the reason for pending. - skip - ^^^^ Give the reason for skip. - it 'does something' do - _1 - skip - ^^^^ Give the reason for skip. - pending - ^^^^^^^ Give the reason for pending. - _1 - end - end - end - RUBY - end - end end context 'when pending/skip inside conditional' do From c2e861f26dc89f90308f4290cfd6dd2c77ff34b2 Mon Sep 17 00:00:00 2001 From: Christophe Bliard Date: Mon, 12 Aug 2024 08:17:21 +0200 Subject: [PATCH 045/105] Fix `RSpec/SortMetadata` cop to limit sorting to trailing metadata Metadata processed by RSpec is: - the last argument when it's a hash - the trailing arguments when they are symbols Only this metadata is sorted by this cop. If the second argument to a `context`/`describe` block is used as an additional description, it is not sorted anymore. This fixes #1946. Co-authored-by: Phil Pirozhkov --- CHANGELOG.md | 2 + docs/modules/ROOT/pages/cops_rspec.adoc | 6 ++ lib/rubocop/cop/rspec/mixin/metadata.rb | 13 ++- lib/rubocop/cop/rspec/sort_metadata.rb | 30 +++++-- lib/rubocop/rspec/description_extractor.rb | 4 +- spec/rubocop/cop/rspec/sort_metadata_spec.rb | 83 +++++++++++++++++--- 6 files changed, 108 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa199ab0c..b0ce06ab2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +- Fix `RSpec/SortMetadata` cop to limit sorting to trailing metadata arguments. ([@cbliard]) + ## 3.3.0 (2024-12-12) - Deprecate `top_level_group?` method from `TopLevelGroup` mixin as all of its callers were intentionally removed from `Rubocop/RSpec`. ([@corsonknowles]) diff --git a/docs/modules/ROOT/pages/cops_rspec.adoc b/docs/modules/ROOT/pages/cops_rspec.adoc index 0d235a7c4..287ed80b1 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -5735,6 +5735,8 @@ end Sort RSpec metadata alphabetically. +Only the trailing metadata is sorted. + [#examples-rspecsortmetadata] === Examples @@ -5749,6 +5751,10 @@ it 'works', :b, :a, foo: 'bar', baz: true describe 'Something', :a, :b context 'Something', baz: true, foo: 'bar' it 'works', :a, :b, baz: true, foo: 'bar' + +# good, trailing metadata is sorted +describe 'Something', 'description', :a, :b, :z +context 'Something', :z, variable, :a, :b ---- [#references-rspecsortmetadata] diff --git a/lib/rubocop/cop/rspec/mixin/metadata.rb b/lib/rubocop/cop/rspec/mixin/metadata.rb index b5dd448c1..325747433 100644 --- a/lib/rubocop/cop/rspec/mixin/metadata.rb +++ b/lib/rubocop/cop/rspec/mixin/metadata.rb @@ -47,15 +47,12 @@ def on_metadata(_symbols, _hash) private def on_metadata_arguments(metadata_arguments) - *symbols, last = metadata_arguments - hash = nil - case last&.type - when :hash - hash = last - when :sym - symbols << last + if metadata_arguments.last&.hash_type? + *metadata_arguments, hash = metadata_arguments + on_metadata(metadata_arguments, hash) + else + on_metadata(metadata_arguments, nil) end - on_metadata(symbols, hash) end end end diff --git a/lib/rubocop/cop/rspec/sort_metadata.rb b/lib/rubocop/cop/rspec/sort_metadata.rb index f34f0ade1..2e9411a44 100644 --- a/lib/rubocop/cop/rspec/sort_metadata.rb +++ b/lib/rubocop/cop/rspec/sort_metadata.rb @@ -5,6 +5,8 @@ module Cop module RSpec # Sort RSpec metadata alphabetically. # + # Only the trailing metadata is sorted. + # # @example # # bad # describe 'Something', :b, :a @@ -16,6 +18,9 @@ module RSpec # context 'Something', baz: true, foo: 'bar' # it 'works', :a, :b, baz: true, foo: 'bar' # + # # good, trailing metadata is sorted + # describe 'Something', 'description', :a, :b, :z + # context 'Something', :z, variable, :a, :b class SortMetadata < Base extend AutoCorrector include Metadata @@ -23,8 +28,14 @@ class SortMetadata < Base MSG = 'Sort metadata alphabetically.' - def on_metadata(symbols, hash) + # @!method match_ambiguous_trailing_metadata?(node) + def_node_matcher :match_ambiguous_trailing_metadata?, <<~PATTERN + (send _ _ _ ... !{hash sym str dstr xstr}) + PATTERN + + def on_metadata(args, hash) pairs = hash&.pairs || [] + symbols = trailing_symbols(args) return if sorted?(symbols, pairs) crime_scene = crime_scene(symbols, pairs) @@ -35,6 +46,15 @@ def on_metadata(symbols, hash) private + def trailing_symbols(args) + args = args[...-1] if last_arg_could_be_a_hash?(args) + args.reverse.take_while(&:sym_type?).reverse + end + + def last_arg_could_be_a_hash?(args) + args.last && match_ambiguous_trailing_metadata?(args.last.parent) + end + def crime_scene(symbols, pairs) metadata = symbols + pairs @@ -57,13 +77,7 @@ def sort_pairs(pairs) end def sort_symbols(symbols) - symbols.sort_by do |symbol| - if symbol.str_type? || symbol.sym_type? - symbol.value.to_s.downcase - else - symbol.source.downcase - end - end + symbols.sort_by { |symbol| symbol.value.to_s.downcase } end end end diff --git a/lib/rubocop/rspec/description_extractor.rb b/lib/rubocop/rspec/description_extractor.rb index f63cbc3a8..20facb399 100644 --- a/lib/rubocop/rspec/description_extractor.rb +++ b/lib/rubocop/rspec/description_extractor.rb @@ -62,8 +62,8 @@ def documented_constant end def cop_subclass? - yardoc.superclass.path == RSPEC_COP_CLASS_NAME || - yardoc.superclass.path == RUBOCOP_COP_CLASS_NAME + [RSPEC_COP_CLASS_NAME, + RUBOCOP_COP_CLASS_NAME].include?(yardoc.superclass.path) end def abstract? diff --git a/spec/rubocop/cop/rspec/sort_metadata_spec.rb b/spec/rubocop/cop/rspec/sort_metadata_spec.rb index c6129a366..d2f9e631f 100644 --- a/spec/rubocop/cop/rspec/sort_metadata_spec.rb +++ b/spec/rubocop/cop/rspec/sort_metadata_spec.rb @@ -4,7 +4,7 @@ it 'does not register an offense when using only symbol metadata ' \ 'in alphabetical order' do expect_no_offenses(<<~RUBY) - RSpec.describe 'Something', :a, :b do + describe 'Something', :a, :b do end RUBY end @@ -12,13 +12,72 @@ it 'registers an offense when using only symbol metadata, ' \ 'but not in alphabetical order' do expect_offense(<<~RUBY) - RSpec.describe 'Something', :b, :a do - ^^^^^^ Sort metadata alphabetically. + describe 'Something', :b, :a do + ^^^^^^ Sort metadata alphabetically. end RUBY expect_correction(<<~RUBY) - RSpec.describe 'Something', :a, :b do + describe 'Something', :a, :b do + end + RUBY + end + + it 'does not register an offense for a symbol metadata before a non-symbol ' \ + 'argument' do + expect_no_offenses(<<~RUBY) + describe 'Something', :z, :a, variable, foo: :bar do + end + RUBY + end + + it 'registers an offense only for trailing symbol metadata not in ' \ + 'alphabetical order' do + expect_offense(<<~RUBY) + describe 'Something', :z, :a, variable, :c, :b do + ^^^^^^ Sort metadata alphabetically. + end + RUBY + + expect_correction(<<~RUBY) + describe 'Something', :z, :a, variable, :b, :c do + end + RUBY + end + + it 'registers an offense when a symbol metadata not in alphabetical order ' \ + 'is before a variable argument being the last argument ' \ + 'as it could be a hash' do + expect_offense(<<~RUBY) + describe 'Something', :z, :a, some_hash do + ^^^^^^ Sort metadata alphabetically. + end + RUBY + + expect_correction(<<~RUBY) + describe 'Something', :a, :z, some_hash do + end + RUBY + end + + it 'does not register an offense when using a second level description ' \ + 'not in alphabetical order with symbol metadata' do + expect_no_offenses(<<~RUBY) + describe 'Something', 'second docstring', :a, :b do + end + RUBY + end + + it 'registers an offense when using a second level description ' \ + 'and metadata not in alphabetical order' do + expect_offense(<<~RUBY) + describe 'Something', 'second docstring', :b, :a do + ^^^^^^ Sort metadata alphabetically. + end + RUBY + + expect_correction(<<~RUBY) + describe 'Something', 'second docstring', :a, :b do end RUBY end @@ -100,27 +159,27 @@ 'and the hash values are complex objects' do expect_offense(<<~RUBY) it 'Something', variable, 'B', :a, key => {}, foo: ->(x) { bar(x) }, Identifier.sample => true, baz: Snafu.new do - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Sort metadata alphabetically. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Sort metadata alphabetically. end RUBY expect_correction(<<~RUBY) - it 'Something', :a, 'B', variable, baz: Snafu.new, foo: ->(x) { bar(x) }, Identifier.sample => true, key => {} do + it 'Something', variable, 'B', :a, baz: Snafu.new, foo: ->(x) { bar(x) }, Identifier.sample => true, key => {} do end RUBY end it 'registers an offense only when example or group has a block' do expect_offense(<<~RUBY) - shared_examples 'a difficult situation', 'B', :a do |x, y| - ^^^^^^^ Sort metadata alphabetically. + shared_examples 'a difficult situation', 'B', :z, :a do |x, y| + ^^^^^^ Sort metadata alphabetically. end include_examples 'a difficult situation', 'value', 'another value' RUBY expect_correction(<<~RUBY) - shared_examples 'a difficult situation', :a, 'B' do |x, y| + shared_examples 'a difficult situation', 'B', :a, :z do |x, y| end include_examples 'a difficult situation', 'value', 'another value' @@ -129,14 +188,14 @@ it 'registers an offense also when the metadata is not on one single line' do expect_offense(<<~RUBY) - RSpec.describe 'Something', :foo, :bar, - ^^^^^^^^^^^ Sort metadata alphabetically. + describe 'Something', :foo, :bar, + ^^^^^^^^^^^ Sort metadata alphabetically. baz: 'goo' do end RUBY expect_correction(<<~RUBY) - RSpec.describe 'Something', :bar, :foo, baz: 'goo' do + describe 'Something', :bar, :foo, baz: 'goo' do end RUBY end From 1aa987fa709c77e9ba068498e624c08ab2e5c9e8 Mon Sep 17 00:00:00 2001 From: Dave Corson-Knowles Date: Sun, 13 Oct 2024 03:07:16 -0700 Subject: [PATCH 046/105] Obsolete StringAsInstanceDoubleConstant in favor of VerifiedDoubleReference for constants only --- .rubocop.yml | 5 -- CHANGELOG.md | 1 + config/default.yml | 13 +-- config/obsoletion.yml | 5 ++ docs/modules/ROOT/pages/cops.adoc | 1 - docs/modules/ROOT/pages/cops_rspec.adoc | 83 ++----------------- .../string_as_instance_double_constant.rb | 45 ---------- .../cop/rspec/verified_double_reference.rb | 67 ++++----------- lib/rubocop/cop/rspec_cops.rb | 1 - ...string_as_instance_double_constant_spec.rb | 33 -------- .../rspec/verified_double_reference_spec.rb | 47 +---------- 11 files changed, 33 insertions(+), 268 deletions(-) delete mode 100644 lib/rubocop/cop/rspec/string_as_instance_double_constant.rb delete mode 100644 spec/rubocop/cop/rspec/string_as_instance_double_constant_spec.rb diff --git a/.rubocop.yml b/.rubocop.yml index 6fb427aef..6f7695352 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -250,8 +250,3 @@ Style/StringChars: {Enabled: true} Style/SuperWithArgsParentheses: {Enabled: true} Style/SwapValues: {Enabled: true} Style/YAMLFileRead: {Enabled: true} - -# Enable our own pending cops. -# -RSpec/StringAsInstanceDoubleConstant: - Enabled: true diff --git a/CHANGELOG.md b/CHANGELOG.md index b0ce06ab2..d0c771eca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - Fix `RSpec/VoidExpect` to only operate inside an example block. ([@corsonknowles]) - Change `RSpec/ContextWording` cop to always report an offense when both `Prefixes` and `AllowedPatterns` are empty. ([@ydah]) - Add support for `and` and `or` compound matchers to `RSpec/ChangeByZero` cop. ([@ydah]) +- Replace `RSpec/StringAsInstanceDoubleConstant` with `RSpecVerifiedDoubleReference` configured to only support constant class references. ([@corsonknowles]) ## 3.1.0 (2024-10-01) diff --git a/config/default.yml b/config/default.yml index 6c09b7d72..a3bb9f216 100644 --- a/config/default.yml +++ b/config/default.yml @@ -930,13 +930,6 @@ RSpec/SpecFilePathSuffix: - "**/spec/**/*" Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SpecFilePathSuffix -RSpec/StringAsInstanceDoubleConstant: - Description: Do not use a string as `instance_double` constant. - Enabled: pending - Safe: false - VersionAdded: '3.1' - Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/StringAsInstanceDoubleConstant - RSpec/StubbedMock: Description: Checks that message expectations do not have a configured response. Enabled: true @@ -995,12 +988,8 @@ RSpec/VerifiedDoubleReference: Description: Checks for consistent verified double reference style. Enabled: true SafeAutoCorrect: false - EnforcedStyle: constant - SupportedStyles: - - constant - - string VersionAdded: 2.10.0 - VersionChanged: '2.12' + VersionChanged: "<>" Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VerifiedDoubleReference RSpec/VerifiedDoubles: diff --git a/config/obsoletion.yml b/config/obsoletion.yml index 530bd0ed4..2c2442805 100644 --- a/config/obsoletion.yml +++ b/config/obsoletion.yml @@ -12,6 +12,9 @@ changed_parameters: parameters: IgnoredPatterns alternative: AllowedPatterns severity: warning + - cops: RSpec/VerifiedDoubleReference + parameters: EnforcedStyle + reason: String references are not verifying unless the class is loaded. split: RSpec/FilePath: @@ -23,6 +26,8 @@ removed: RSpec/Capybara/FeatureMethods: reason: > this cop has migrated to `RSpec/Dialect`. Please use `RSpec/Dialect` instead + RSpec/StringAsInstanceDoubleConstant: + reason: Please use `RSpec/VerifiedDoubleReference` instead extracted: RSpec/Rails/*: rubocop-rspec_rails diff --git a/docs/modules/ROOT/pages/cops.adoc b/docs/modules/ROOT/pages/cops.adoc index 116d2a714..16ddf0fd6 100644 --- a/docs/modules/ROOT/pages/cops.adoc +++ b/docs/modules/ROOT/pages/cops.adoc @@ -101,7 +101,6 @@ * xref:cops_rspec.adoc#rspecsortmetadata[RSpec/SortMetadata] * xref:cops_rspec.adoc#rspecspecfilepathformat[RSpec/SpecFilePathFormat] * xref:cops_rspec.adoc#rspecspecfilepathsuffix[RSpec/SpecFilePathSuffix] -* xref:cops_rspec.adoc#rspecstringasinstancedoubleconstant[RSpec/StringAsInstanceDoubleConstant] * xref:cops_rspec.adoc#rspecstubbedmock[RSpec/StubbedMock] * xref:cops_rspec.adoc#rspecsubjectdeclaration[RSpec/SubjectDeclaration] * xref:cops_rspec.adoc#rspecsubjectstub[RSpec/SubjectStub] diff --git a/docs/modules/ROOT/pages/cops_rspec.adoc b/docs/modules/ROOT/pages/cops_rspec.adoc index 287ed80b1..6e980a34c 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -5909,45 +5909,6 @@ spec/models/user.rb # shared_examples_for 'foo' * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SpecFilePathSuffix -[#rspecstringasinstancedoubleconstant] -== RSpec/StringAsInstanceDoubleConstant - -|=== -| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed - -| Pending -| No -| Always (Unsafe) -| 3.1 -| - -|=== - -Do not use a string as `instance_double` constant. - -[#safety-rspecstringasinstancedoubleconstant] -=== Safety - -This cop is unsafe because the correction requires loading the class. -Loading before stubbing causes RSpec to only allow instance methods -to be stubbed. - -[#examples-rspecstringasinstancedoubleconstant] -=== Examples - -[source,ruby] ----- -# bad -instance_double('User', name: 'John') - -# good -instance_double(User, name: 'John') ----- - -[#references-rspecstringasinstancedoubleconstant] -=== References - -* https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/StringAsInstanceDoubleConstant - [#rspecstubbedmock] == RSpec/StubbedMock @@ -6359,22 +6320,21 @@ let(:userFood_2) { 'fettuccine' } | Yes | Always (Unsafe) | 2.10.0 -| 2.12 +| <> |=== Checks for consistent verified double reference style. -Only investigates references that are one of the supported styles. +[#safety-rspecverifieddoublereference] +=== Safety -This cop can be configured in your configuration using the -`EnforcedStyle` option and supports `--auto-gen-config`. +This cop is unsafe because the correction requires loading the class. +Loading before stubbing causes RSpec to only allow instance methods +to be stubbed. [#examples-rspecverifieddoublereference] === Examples -[#_enforcedstyle_-constant_-_default_-rspecverifieddoublereference] -==== `EnforcedStyle: constant` (default) - [source,ruby] ---- # bad @@ -6388,24 +6348,8 @@ let(:foo) do end ---- -[#_enforcedstyle_-string_-rspecverifieddoublereference] -==== `EnforcedStyle: string` - -[source,ruby] ----- -# bad -let(:foo) do - instance_double(ClassName, method_name: 'returned_value') -end - -# good -let(:foo) do - instance_double('ClassName', method_name: 'returned_value') -end ----- - -[#reference-is-not-in-the-supported-style-list_-no-enforcement-rspecverifieddoublereference] -==== Reference is not in the supported style list. No enforcement +[#reference-is-any-dynamic-variable_-no-enforcement-rspecverifieddoublereference] +==== Reference is any dynamic variable. No enforcement [source,ruby] ---- @@ -6415,17 +6359,6 @@ let(:foo) do end ---- -[#configurable-attributes-rspecverifieddoublereference] -=== Configurable attributes - -|=== -| Name | Default value | Configurable values - -| EnforcedStyle -| `constant` -| `constant`, `string` -|=== - [#references-rspecverifieddoublereference] === References diff --git a/lib/rubocop/cop/rspec/string_as_instance_double_constant.rb b/lib/rubocop/cop/rspec/string_as_instance_double_constant.rb deleted file mode 100644 index c7a346821..000000000 --- a/lib/rubocop/cop/rspec/string_as_instance_double_constant.rb +++ /dev/null @@ -1,45 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module Cop - module RSpec - # Do not use a string as `instance_double` constant. - # - # @safety - # This cop is unsafe because the correction requires loading the class. - # Loading before stubbing causes RSpec to only allow instance methods - # to be stubbed. - # - # @example - # # bad - # instance_double('User', name: 'John') - # - # # good - # instance_double(User, name: 'John') - # - class StringAsInstanceDoubleConstant < 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 $str ...) - PATTERN - - def on_send(node) - stringified_instance_double_const?(node) do |args_node| - add_offense(args_node) do |corrector| - autocorrect(corrector, args_node) - end - end - end - - def autocorrect(corrector, node) - corrector.replace(node, node.value) - end - end - end - end -end diff --git a/lib/rubocop/cop/rspec/verified_double_reference.rb b/lib/rubocop/cop/rspec/verified_double_reference.rb index b4f6e8d38..1a3621a26 100644 --- a/lib/rubocop/cop/rspec/verified_double_reference.rb +++ b/lib/rubocop/cop/rspec/verified_double_reference.rb @@ -5,14 +5,14 @@ module Cop module RSpec # Checks for consistent verified double reference style. # - # Only investigates references that are one of the supported styles. - # # @see https://rspec.info/features/3-12/rspec-mocks/verifying-doubles # - # This cop can be configured in your configuration using the - # `EnforcedStyle` option and supports `--auto-gen-config`. + # @safety + # This cop is unsafe because the correction requires loading the class. + # Loading before stubbing causes RSpec to only allow instance methods + # to be stubbed. # - # @example `EnforcedStyle: constant` (default) + # @example # # bad # let(:foo) do # instance_double('ClassName', method_name: 'returned_value') @@ -23,18 +23,7 @@ module RSpec # instance_double(ClassName, method_name: 'returned_value') # end # - # @example `EnforcedStyle: string` - # # bad - # let(:foo) do - # instance_double(ClassName, method_name: 'returned_value') - # end - # - # # good - # let(:foo) do - # instance_double('ClassName', method_name: 'returned_value') - # end - # - # @example Reference is not in the supported style list. No enforcement + # @example Reference is any dynamic variable. No enforcement # # # good # let(:foo) do @@ -42,9 +31,9 @@ module RSpec # end class VerifiedDoubleReference < Base extend AutoCorrector - include ConfigurableEnforcedStyle - MSG = 'Use a %