Merge pull request #8373 from Homebrew/dependabot/bundler/Library/Homebrew/rubocop-rspec-1.43.1
build(deps): bump rubocop-rspec from 1.42.0 to 1.43.1 in /Library/Homebrew
This commit is contained in:
commit
97b57393cc
@ -43,3 +43,5 @@ RSpec/MultipleExpectations:
|
||||
Max: 26
|
||||
RSpec/NestedGroups:
|
||||
Max: 5
|
||||
RSpec/MultipleMemoizedHelpers:
|
||||
Max: 12
|
||||
|
||||
@ -112,8 +112,8 @@ GEM
|
||||
parser (>= 2.7.1.4)
|
||||
rubocop-performance (1.7.1)
|
||||
rubocop (>= 0.82.0)
|
||||
rubocop-rspec (1.42.0)
|
||||
rubocop (>= 0.87.0)
|
||||
rubocop-rspec (1.43.1)
|
||||
rubocop (~> 0.87)
|
||||
ruby-macho (2.2.0)
|
||||
ruby-progressbar (1.10.1)
|
||||
simplecov (0.19.0)
|
||||
|
||||
@ -51,7 +51,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel-1.19.2/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel_tests-3.1.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parser-2.7.1.4/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rainbow-3.0.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-runtime-0.5.5866/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-runtime-0.5.5869/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parlour-4.0.1/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/patchelf-1.2.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/plist-3.5.0/lib"
|
||||
@ -74,9 +74,9 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-progressbar-1.10
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width-1.7.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-0.88.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1.7.1/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-1.42.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-1.43.1/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-macho-2.2.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-0.5.5866-universal-darwin-19/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-0.5.5866/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-0.5.5869-universal-darwin-19/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-0.5.5869/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/thor-1.0.1/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/tapioca-0.4.1/lib"
|
||||
|
||||
@ -1,72 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# Check that the first argument to the top level describe is a constant.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# describe 'Do something' do
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# describe TestedClass do
|
||||
# subject { described_class }
|
||||
# end
|
||||
#
|
||||
# describe 'TestedClass::VERSION' do
|
||||
# subject { Object.const_get(self.class.description) }
|
||||
# end
|
||||
#
|
||||
# describe "A feature example", type: :feature do
|
||||
# end
|
||||
class DescribeClass < Cop
|
||||
include RuboCop::RSpec::TopLevelDescribe
|
||||
|
||||
MSG = 'The first argument to describe should be '\
|
||||
'the class or module being tested.'
|
||||
|
||||
def_node_matcher :valid_describe?, <<-PATTERN
|
||||
{
|
||||
(send #{RSPEC} :describe const ...)
|
||||
(send #{RSPEC} :describe)
|
||||
}
|
||||
PATTERN
|
||||
|
||||
def_node_matcher :describe_with_rails_metadata?, <<-PATTERN
|
||||
(send #{RSPEC} :describe !const ...
|
||||
(hash <#rails_metadata? ...>)
|
||||
)
|
||||
PATTERN
|
||||
|
||||
def_node_matcher :rails_metadata?, <<-PATTERN
|
||||
(pair
|
||||
(sym :type)
|
||||
(sym {
|
||||
:channel :controller :helper :job :mailer :model :request
|
||||
:routing :view :feature :system :mailbox
|
||||
}
|
||||
)
|
||||
)
|
||||
PATTERN
|
||||
|
||||
def on_top_level_describe(node, (described_value, _))
|
||||
return if shared_group?(root_node)
|
||||
return if valid_describe?(node)
|
||||
return if describe_with_rails_metadata?(node)
|
||||
return if string_constant_describe?(described_value)
|
||||
|
||||
add_offense(described_value)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def string_constant_describe?(described_value)
|
||||
described_value.str_type? &&
|
||||
described_value.value =~ /^((::)?[A-Z]\w*)+$/
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,90 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# Checks if an example group does not include any tests.
|
||||
#
|
||||
# This cop is configurable using the `CustomIncludeMethods` option
|
||||
#
|
||||
# @example usage
|
||||
#
|
||||
# # bad
|
||||
# describe Bacon do
|
||||
# let(:bacon) { Bacon.new(chunkiness) }
|
||||
# let(:chunkiness) { false }
|
||||
#
|
||||
# context 'extra chunky' do # flagged by rubocop
|
||||
# let(:chunkiness) { true }
|
||||
# end
|
||||
#
|
||||
# it 'is chunky' do
|
||||
# expect(bacon.chunky?).to be_truthy
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# describe Bacon do
|
||||
# let(:bacon) { Bacon.new(chunkiness) }
|
||||
# let(:chunkiness) { false }
|
||||
#
|
||||
# it 'is chunky' do
|
||||
# expect(bacon.chunky?).to be_truthy
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# @example configuration
|
||||
#
|
||||
# # .rubocop.yml
|
||||
# # RSpec/EmptyExampleGroup:
|
||||
# # CustomIncludeMethods:
|
||||
# # - include_tests
|
||||
#
|
||||
# # spec_helper.rb
|
||||
# RSpec.configure do |config|
|
||||
# config.alias_it_behaves_like_to(:include_tests)
|
||||
# end
|
||||
#
|
||||
# # bacon_spec.rb
|
||||
# describe Bacon do
|
||||
# let(:bacon) { Bacon.new(chunkiness) }
|
||||
# let(:chunkiness) { false }
|
||||
#
|
||||
# context 'extra chunky' do # not flagged by rubocop
|
||||
# let(:chunkiness) { true }
|
||||
#
|
||||
# include_tests 'shared tests'
|
||||
# end
|
||||
# end
|
||||
#
|
||||
class EmptyExampleGroup < Cop
|
||||
MSG = 'Empty example group detected.'
|
||||
|
||||
def_node_search :contains_example?, <<-PATTERN
|
||||
{
|
||||
#{(Examples::ALL + Includes::ALL).send_pattern}
|
||||
(send _ #custom_include? ...)
|
||||
}
|
||||
PATTERN
|
||||
|
||||
def on_block(node)
|
||||
return unless example_group?(node) && !contains_example?(node)
|
||||
|
||||
add_offense(node.send_node)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def custom_include?(method_name)
|
||||
custom_include_methods.include?(method_name)
|
||||
end
|
||||
|
||||
def custom_include_methods
|
||||
cop_config
|
||||
.fetch('CustomIncludeMethods', [])
|
||||
.map(&:to_sym)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,47 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# Checks that memoized helper names use the configured style.
|
||||
#
|
||||
# @example EnforcedStyle: snake_case (default)
|
||||
# # bad
|
||||
# let(:userName) { 'Adam' }
|
||||
# subject(:userName) { 'Adam' }
|
||||
#
|
||||
# # good
|
||||
# let(:user_name) { 'Adam' }
|
||||
# subject(:user_name) { 'Adam' }
|
||||
#
|
||||
# @example EnforcedStyle: camelCase
|
||||
# # bad
|
||||
# let(:user_name) { 'Adam' }
|
||||
# subject(:user_name) { 'Adam' }
|
||||
#
|
||||
# # good
|
||||
# let(:userName) { 'Adam' }
|
||||
# subject(:userName) { 'Adam' }
|
||||
class VariableName < Cop
|
||||
include ConfigurableNaming
|
||||
include RuboCop::RSpec::Variable
|
||||
|
||||
MSG = 'Use %<style>s for variable names.'
|
||||
|
||||
def on_send(node)
|
||||
variable_definition?(node) do |variable|
|
||||
return if variable.dstr_type? || variable.dsym_type?
|
||||
|
||||
check_name(node, variable.value, variable.loc.expression)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def message(style)
|
||||
format(MSG, style: style)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,44 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module RSpec
|
||||
# Helper methods for top level example group cops
|
||||
module TopLevelGroup
|
||||
extend RuboCop::NodePattern::Macros
|
||||
include RuboCop::RSpec::Language
|
||||
|
||||
def_node_matcher :example_or_shared_group?,
|
||||
(ExampleGroups::ALL + SharedGroups::ALL).block_pattern
|
||||
|
||||
def on_block(node)
|
||||
return unless respond_to?(:on_top_level_group)
|
||||
return unless top_level_group?(node)
|
||||
|
||||
on_top_level_group(node)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def top_level_group?(node)
|
||||
top_level_groups.include?(node)
|
||||
end
|
||||
|
||||
def top_level_groups
|
||||
@top_level_groups ||=
|
||||
top_level_nodes.select { |n| example_or_shared_group?(n) }
|
||||
end
|
||||
|
||||
def top_level_nodes
|
||||
if root_node.begin_type?
|
||||
root_node.children
|
||||
else
|
||||
[root_node]
|
||||
end
|
||||
end
|
||||
|
||||
def root_node
|
||||
processed_source.ast
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -74,7 +74,7 @@ RSpec/ContextWording:
|
||||
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextWording
|
||||
|
||||
RSpec/DescribeClass:
|
||||
Description: Check that the first argument to the top level describe is a constant.
|
||||
Description: Check that the first argument to the top-level describe is a constant.
|
||||
Enabled: true
|
||||
VersionAdded: '1.0'
|
||||
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeClass
|
||||
@ -381,7 +381,7 @@ RSpec/MissingExampleGroupArgument:
|
||||
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MissingExampleGroupArgument
|
||||
|
||||
RSpec/MultipleDescribes:
|
||||
Description: Checks for multiple top level describes.
|
||||
Description: Checks for multiple top-level example groups.
|
||||
Enabled: true
|
||||
VersionAdded: '1.0'
|
||||
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleDescribes
|
||||
@ -394,6 +394,14 @@ RSpec/MultipleExpectations:
|
||||
VersionChanged: '1.21'
|
||||
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleExpectations
|
||||
|
||||
RSpec/MultipleMemoizedHelpers:
|
||||
Description: Checks if example groups contain too many `let` and `subject` calls.
|
||||
Enabled: true
|
||||
AllowSubject: true
|
||||
Max: 5
|
||||
VersionAdded: '1.43'
|
||||
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleMemoizedHelpers
|
||||
|
||||
RSpec/MultipleSubjects:
|
||||
Description: Checks if an example group defines `subject` multiple times.
|
||||
Enabled: true
|
||||
@ -558,7 +566,9 @@ RSpec/VariableName:
|
||||
SupportedStyles:
|
||||
- snake_case
|
||||
- camelCase
|
||||
IgnoredPatterns: []
|
||||
VersionAdded: '1.40'
|
||||
VersionChanged: '1.43'
|
||||
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VariableName
|
||||
|
||||
RSpec/VerifiedDoubles:
|
||||
@ -19,11 +19,12 @@ require_relative 'rubocop/rspec/example_group'
|
||||
require_relative 'rubocop/rspec/example'
|
||||
require_relative 'rubocop/rspec/hook'
|
||||
require_relative 'rubocop/rspec/variable'
|
||||
require_relative 'rubocop/cop/rspec/base'
|
||||
require_relative 'rubocop/cop/rspec/cop'
|
||||
require_relative 'rubocop/rspec/align_let_brace'
|
||||
require_relative 'rubocop/rspec/factory_bot'
|
||||
require_relative 'rubocop/rspec/final_end_location'
|
||||
require_relative 'rubocop/rspec/blank_line_separation'
|
||||
require_relative 'rubocop/rspec/empty_line_separation'
|
||||
require_relative 'rubocop/rspec/corrector/move_node'
|
||||
|
||||
RuboCop::RSpec::Inject.defaults!
|
||||
@ -17,7 +17,7 @@ module RuboCop
|
||||
# let(:baz) { bar }
|
||||
# let(:a) { b }
|
||||
#
|
||||
class AlignLeftLetBrace < Cop
|
||||
class AlignLeftLetBrace < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Align left let brace'
|
||||
@ -17,7 +17,7 @@ module RuboCop
|
||||
# let(:baz) { bar }
|
||||
# let(:a) { b }
|
||||
#
|
||||
class AlignRightLetBrace < Cop
|
||||
class AlignRightLetBrace < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Align right let brace'
|
||||
@ -22,7 +22,7 @@ module RuboCop
|
||||
# allow(my_instance).to receive(:foo)
|
||||
# end
|
||||
# end
|
||||
class AnyInstance < Cop
|
||||
class AnyInstance < Base
|
||||
MSG = 'Avoid stubbing using `%<method>s`.'
|
||||
|
||||
def_node_matcher :disallowed_stub, <<-PATTERN
|
||||
@ -25,7 +25,7 @@ module RuboCop
|
||||
# some_method
|
||||
# test.run
|
||||
# end
|
||||
class AroundBlock < Cop
|
||||
class AroundBlock < Base
|
||||
MSG_NO_ARG = 'Test object should be passed to around block.'
|
||||
MSG_UNUSED_ARG = 'You should call `%<arg>s.call` '\
|
||||
'or `%<arg>s.run`.'
|
||||
@ -17,7 +17,7 @@ module RuboCop
|
||||
# # Patterns:
|
||||
# # - '_test.rb$'
|
||||
# # - '(?:^|/)test/'
|
||||
class Cop < ::RuboCop::Cop::Base
|
||||
class Base < ::RuboCop::Cop::Base
|
||||
include RuboCop::RSpec::Language
|
||||
include RuboCop::RSpec::Language::NodePattern
|
||||
|
||||
@ -30,8 +30,8 @@ module RuboCop
|
||||
)
|
||||
|
||||
# Invoke the original inherited hook so our cops are recognized
|
||||
def self.inherited(subclass)
|
||||
RuboCop::Cop::Cop.inherited(subclass)
|
||||
def self.inherited(subclass) # rubocop:disable Lint/MissingSuper
|
||||
RuboCop::Cop::Base.inherited(subclass)
|
||||
end
|
||||
|
||||
def relevant_file?(file)
|
||||
@ -41,7 +41,7 @@ module RuboCop
|
||||
private
|
||||
|
||||
def relevant_rubocop_rspec_file?(file)
|
||||
rspec_pattern =~ file
|
||||
rspec_pattern.match?(file)
|
||||
end
|
||||
|
||||
def rspec_pattern
|
||||
@ -19,7 +19,7 @@ module RuboCop
|
||||
# expect(foo).to be 1.0
|
||||
# expect(foo).to be(true)
|
||||
#
|
||||
class Be < Cop
|
||||
class Be < Base
|
||||
MSG = 'Don\'t use `be` without an argument.'
|
||||
|
||||
def_node_matcher :be_without_args, <<-PATTERN
|
||||
@ -35,7 +35,7 @@ module RuboCop
|
||||
# necessarily the same type as `b` since the `#==` operator can
|
||||
# coerce objects for comparison.
|
||||
#
|
||||
class BeEql < Cop
|
||||
class BeEql < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Prefer `be` over `eql`.'
|
||||
@ -23,7 +23,7 @@ module RuboCop
|
||||
# before(:each) { Widget.create }
|
||||
# after(:each) { Widget.delete_all }
|
||||
# end
|
||||
class BeforeAfterAll < Cop
|
||||
class BeforeAfterAll < Base
|
||||
MSG = 'Beware of using `%<hook>s` as it may cause state to leak '\
|
||||
'between tests. If you are using `rspec-rails`, and '\
|
||||
'`use_transactional_fixtures` is enabled, then records created '\
|
||||
@ -23,7 +23,7 @@ module RuboCop
|
||||
# expect(page).to have_current_path("/callback")
|
||||
# expect(page).to have_current_path(/widgets/)
|
||||
#
|
||||
class CurrentPathExpectation < Cop
|
||||
class CurrentPathExpectation < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Do not set an RSpec expectation on `current_path` in ' \
|
||||
@ -40,7 +40,7 @@ module RuboCop
|
||||
# # ...
|
||||
# end
|
||||
# end
|
||||
class FeatureMethods < Cop
|
||||
class FeatureMethods < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `%<replacement>s` instead of `%<method>s`.'
|
||||
@ -55,15 +55,18 @@ module RuboCop
|
||||
feature: :describe
|
||||
}.freeze
|
||||
|
||||
def_node_matcher :capybara_speak,
|
||||
SelectorSet.new(MAP.keys).node_pattern_union
|
||||
|
||||
def_node_matcher :spec?, <<-PATTERN
|
||||
(block
|
||||
(send #{RSPEC} {:describe :feature} ...)
|
||||
(send #rspec? {:describe :feature} ...)
|
||||
...)
|
||||
PATTERN
|
||||
|
||||
def_node_matcher :feature_method, <<-PATTERN
|
||||
(block
|
||||
$(send #{RSPEC} ${#{MAP.keys.map(&:inspect).join(' ')}} ...)
|
||||
$(send #rspec? $#capybara_speak ...)
|
||||
...)
|
||||
PATTERN
|
||||
|
||||
@ -26,7 +26,7 @@ module RuboCop
|
||||
# expect(page).to have_css('.foo', visible: :all)
|
||||
# expect(page).to have_link('my link', visible: :hidden)
|
||||
#
|
||||
class VisibilityMatcher < Cop
|
||||
class VisibilityMatcher < Base
|
||||
MSG_FALSE = 'Use `:all` or `:hidden` instead of `false`.'
|
||||
MSG_TRUE = 'Use `:visible` instead of `true`.'
|
||||
CAPYBARA_MATCHER_METHODS = %i[
|
||||
@ -23,13 +23,13 @@ module RuboCop
|
||||
# describe '.foo_bar' do
|
||||
# # ...
|
||||
# end
|
||||
class ContextMethod < Cop
|
||||
class ContextMethod < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `describe` for testing methods.'
|
||||
|
||||
def_node_matcher :context_method, <<-PATTERN
|
||||
(block (send #{RSPEC} :context $(str #method_name?) ...) ...)
|
||||
(block (send #rspec? :context $(str #method_name?) ...) ...)
|
||||
PATTERN
|
||||
|
||||
def on_block(node)
|
||||
@ -34,11 +34,11 @@ module RuboCop
|
||||
# context 'when the display name is not present' do
|
||||
# # ...
|
||||
# end
|
||||
class ContextWording < Cop
|
||||
class ContextWording < Base
|
||||
MSG = 'Start context description with %<prefixes>s.'
|
||||
|
||||
def_node_matcher :context_wording, <<-PATTERN
|
||||
(block (send #{RSPEC} { :context :shared_context } $(str #bad_prefix?) ...) ...)
|
||||
(block (send #rspec? { :context :shared_context } $(str #bad_prefix?) ...) ...)
|
||||
PATTERN
|
||||
|
||||
def on_block(node)
|
||||
@ -51,7 +51,7 @@ module RuboCop
|
||||
private
|
||||
|
||||
def bad_prefix?(description)
|
||||
!prefixes.include?(description.split.first)
|
||||
!prefixes.include?(description.split(/\b/).first)
|
||||
end
|
||||
|
||||
def joined_prefixes
|
||||
10
Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rspec-1.43.1/lib/rubocop/cop/rspec/cop.rb
vendored
Normal file
10
Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rspec-1.43.1/lib/rubocop/cop/rspec/cop.rb
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# @deprecated Use ::RuboCop::Cop::RSpec::Base instead
|
||||
Cop = Base
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,63 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# Check that the first argument to the top-level describe is a constant.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# describe 'Do something' do
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# describe TestedClass do
|
||||
# subject { described_class }
|
||||
# end
|
||||
#
|
||||
# describe 'TestedClass::VERSION' do
|
||||
# subject { Object.const_get(self.class.description) }
|
||||
# end
|
||||
#
|
||||
# describe "A feature example", type: :feature do
|
||||
# end
|
||||
class DescribeClass < Base
|
||||
include RuboCop::RSpec::TopLevelGroup
|
||||
|
||||
MSG = 'The first argument to describe should be '\
|
||||
'the class or module being tested.'
|
||||
|
||||
def_node_matcher :rails_metadata?, <<-PATTERN
|
||||
(pair
|
||||
(sym :type)
|
||||
(sym { :channel :controller :helper :job :mailer :model :request
|
||||
:routing :view :feature :system :mailbox })
|
||||
)
|
||||
PATTERN
|
||||
|
||||
def_node_matcher :example_group_with_rails_metadata?, <<~PATTERN
|
||||
(send #rspec? :describe ... (hash <#rails_metadata? ...>))
|
||||
PATTERN
|
||||
|
||||
def_node_matcher :not_a_const_described, <<~PATTERN
|
||||
(send #rspec? :describe $[!const !#string_constant?] ...)
|
||||
PATTERN
|
||||
|
||||
def on_top_level_group(top_level_node)
|
||||
return if example_group_with_rails_metadata?(top_level_node.send_node)
|
||||
|
||||
not_a_const_described(top_level_node.send_node) do |described|
|
||||
add_offense(described)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def string_constant?(described)
|
||||
described.str_type? &&
|
||||
described.value.match?(/^(?:(?:::)?[A-Z]\w*)+$/)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -16,17 +16,25 @@ module RuboCop
|
||||
#
|
||||
# describe MyClass, '.my_class_method' do
|
||||
# end
|
||||
class DescribeMethod < Cop
|
||||
include RuboCop::RSpec::TopLevelDescribe
|
||||
class DescribeMethod < Base
|
||||
include RuboCop::RSpec::TopLevelGroup
|
||||
|
||||
MSG = 'The second argument to describe should be the method '\
|
||||
"being tested. '#instance' or '.class'."
|
||||
|
||||
def on_top_level_describe(_node, (_, second_arg))
|
||||
return unless second_arg&.str_type?
|
||||
return if second_arg.str_content.start_with?('#', '.')
|
||||
def_node_matcher :second_argument, <<~PATTERN
|
||||
(block
|
||||
(send #rspec? :describe _first_argument $(str _) ...) ...
|
||||
)
|
||||
PATTERN
|
||||
|
||||
add_offense(second_arg)
|
||||
def on_top_level_group(node)
|
||||
second_argument = second_argument(node)
|
||||
|
||||
return unless second_argument
|
||||
return if second_argument.str_content.start_with?('#', '.')
|
||||
|
||||
add_offense(second_argument)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -17,11 +17,11 @@ module RuboCop
|
||||
# end
|
||||
#
|
||||
# @see https://github.com/rspec/rspec-core/issues/1610
|
||||
class DescribeSymbol < Cop
|
||||
class DescribeSymbol < Base
|
||||
MSG = 'Avoid describing symbols.'
|
||||
|
||||
def_node_matcher :describe_symbol?, <<-PATTERN
|
||||
(send #{RSPEC} :describe $sym ...)
|
||||
(send #rspec? :describe $sym ...)
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
@ -54,7 +54,7 @@ module RuboCop
|
||||
# end
|
||||
# end
|
||||
#
|
||||
class DescribedClass < Cop
|
||||
class DescribedClass < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
@ -142,7 +142,7 @@ module RuboCop
|
||||
if style == :described_class
|
||||
offensive_described_class?(node)
|
||||
else
|
||||
node.send_type? && node.method_name == :described_class
|
||||
node.send_type? && node.method?(:described_class)
|
||||
end
|
||||
end
|
||||
|
||||
@ -19,7 +19,7 @@ module RuboCop
|
||||
# end
|
||||
#
|
||||
# @see https://github.com/rubocop-hq/rubocop-rspec/issues/735
|
||||
class DescribedClassModuleWrapping < Cop
|
||||
class DescribedClassModuleWrapping < Base
|
||||
MSG = 'Avoid opening modules and defining specs within them.'
|
||||
|
||||
def_node_search :find_rspec_blocks,
|
||||
@ -41,7 +41,7 @@ module RuboCop
|
||||
# describe 'display name presence' do
|
||||
# # ...
|
||||
# end
|
||||
class Dialect < Cop
|
||||
class Dialect < Base
|
||||
extend AutoCorrector
|
||||
include MethodPreference
|
||||
|
||||
@ -0,0 +1,174 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# Checks if an example group does not include any tests.
|
||||
#
|
||||
# This cop is configurable using the `CustomIncludeMethods` option
|
||||
#
|
||||
# @example usage
|
||||
#
|
||||
# # bad
|
||||
# describe Bacon do
|
||||
# let(:bacon) { Bacon.new(chunkiness) }
|
||||
# let(:chunkiness) { false }
|
||||
#
|
||||
# context 'extra chunky' do # flagged by rubocop
|
||||
# let(:chunkiness) { true }
|
||||
# end
|
||||
#
|
||||
# it 'is chunky' do
|
||||
# expect(bacon.chunky?).to be_truthy
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# describe Bacon do
|
||||
# let(:bacon) { Bacon.new(chunkiness) }
|
||||
# let(:chunkiness) { false }
|
||||
#
|
||||
# it 'is chunky' do
|
||||
# expect(bacon.chunky?).to be_truthy
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# @example configuration
|
||||
#
|
||||
# # .rubocop.yml
|
||||
# # RSpec/EmptyExampleGroup:
|
||||
# # CustomIncludeMethods:
|
||||
# # - include_tests
|
||||
#
|
||||
# # spec_helper.rb
|
||||
# RSpec.configure do |config|
|
||||
# config.alias_it_behaves_like_to(:include_tests)
|
||||
# end
|
||||
#
|
||||
# # bacon_spec.rb
|
||||
# describe Bacon do
|
||||
# let(:bacon) { Bacon.new(chunkiness) }
|
||||
# let(:chunkiness) { false }
|
||||
#
|
||||
# context 'extra chunky' do # not flagged by rubocop
|
||||
# let(:chunkiness) { true }
|
||||
#
|
||||
# include_tests 'shared tests'
|
||||
# end
|
||||
# end
|
||||
#
|
||||
class EmptyExampleGroup < Base
|
||||
MSG = 'Empty example group detected.'
|
||||
|
||||
# @!method example_group_body(node)
|
||||
# Match example group blocks and yield their body
|
||||
#
|
||||
# @example source that matches
|
||||
# describe 'example group' do
|
||||
# it { is_expected.to be }
|
||||
# end
|
||||
#
|
||||
# @param node [RuboCop::AST::Node]
|
||||
# @yield [RuboCop::AST::Node] example group body
|
||||
def_node_matcher :example_group_body, <<~PATTERN
|
||||
(block #{ExampleGroups::ALL.send_pattern} args $_)
|
||||
PATTERN
|
||||
|
||||
# @!method example_or_group_or_include?(node)
|
||||
# Match examples, example groups and includes
|
||||
#
|
||||
# @example source that matches
|
||||
# it { is_expected.to fly }
|
||||
# describe('non-empty example groups too') { }
|
||||
# it_behaves_like 'an animal'
|
||||
# it_behaves_like('a cat') { let(:food) { 'milk' } }
|
||||
# it_has_root_access
|
||||
#
|
||||
# @param node [RuboCop::AST::Node]
|
||||
# @return [Array<RuboCop::AST::Node>] matching nodes
|
||||
def_node_matcher :example_or_group_or_include?, <<~PATTERN
|
||||
{
|
||||
#{Examples::ALL.block_pattern}
|
||||
#{ExampleGroups::ALL.block_pattern}
|
||||
#{Includes::ALL.send_pattern}
|
||||
#{Includes::ALL.block_pattern}
|
||||
(send nil? #custom_include? ...)
|
||||
}
|
||||
PATTERN
|
||||
|
||||
# @!method examples_inside_block?(node)
|
||||
# Match examples defined inside a block which is not a hook
|
||||
#
|
||||
# @example source that matches
|
||||
# %w(r g b).each do |color|
|
||||
# it { is_expected.to have_color(color) }
|
||||
# end
|
||||
#
|
||||
# @example source that does not match
|
||||
# before do
|
||||
# it { is_expected.to fall_into_oblivion }
|
||||
# end
|
||||
#
|
||||
# @param node [RuboCop::AST::Node]
|
||||
# @return [Array<RuboCop::AST::Node>] matching nodes
|
||||
def_node_matcher :examples_inside_block?, <<~PATTERN
|
||||
(block !#{Hooks::ALL.send_pattern} _ #examples?)
|
||||
PATTERN
|
||||
|
||||
# @!method examples_directly_or_in_block?(node)
|
||||
# Match examples or examples inside blocks
|
||||
#
|
||||
# @example source that matches
|
||||
# it { expect(drink).to be_cold }
|
||||
# context('when winter') { it { expect(drink).to be_hot } }
|
||||
# (1..5).each { |divisor| it { is_expected.to divide_by(divisor) } }
|
||||
#
|
||||
# @param node [RuboCop::AST::Node]
|
||||
# @return [Array<RuboCop::AST::Node>] matching nodes
|
||||
def_node_matcher :examples_directly_or_in_block?, <<~PATTERN
|
||||
{
|
||||
#example_or_group_or_include?
|
||||
#examples_inside_block?
|
||||
}
|
||||
PATTERN
|
||||
|
||||
# @!method examples?(node)
|
||||
# Matches examples defined in scopes where they could run
|
||||
#
|
||||
# @example source that matches
|
||||
# it { expect(myself).to be_run }
|
||||
# describe { it { i_run_as_well } }
|
||||
#
|
||||
# @example source that does not match
|
||||
# before { it { whatever here wont run anyway } }
|
||||
#
|
||||
# @param node [RuboCop::AST::Node]
|
||||
# @return [Array<RuboCop::AST::Node>] matching nodes
|
||||
def_node_matcher :examples?, <<~PATTERN
|
||||
{
|
||||
#examples_directly_or_in_block?
|
||||
(begin <#examples_directly_or_in_block? ...>)
|
||||
}
|
||||
PATTERN
|
||||
|
||||
def on_block(node)
|
||||
example_group_body(node) do |body|
|
||||
add_offense(node.send_node) unless examples?(body)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def custom_include?(method_name)
|
||||
custom_include_methods.include?(method_name)
|
||||
end
|
||||
|
||||
def custom_include_methods
|
||||
cop_config
|
||||
.fetch('CustomIncludeMethods', [])
|
||||
.map(&:to_sym)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -22,7 +22,7 @@ module RuboCop
|
||||
# create_feed
|
||||
# end
|
||||
# after(:all) { cleanup_feed }
|
||||
class EmptyHook < Cop
|
||||
class EmptyHook < Base
|
||||
extend AutoCorrector
|
||||
include RuboCop::Cop::RangeHelp
|
||||
|
||||
@ -41,22 +41,18 @@ module RuboCop
|
||||
# it { two }
|
||||
# end
|
||||
#
|
||||
class EmptyLineAfterExample < Cop
|
||||
class EmptyLineAfterExample < Base
|
||||
extend AutoCorrector
|
||||
include RuboCop::RSpec::BlankLineSeparation
|
||||
include RuboCop::RSpec::EmptyLineSeparation
|
||||
|
||||
MSG = 'Add an empty line after `%<example>s`.'
|
||||
|
||||
def on_block(node)
|
||||
return unless example?(node)
|
||||
return if last_child?(node)
|
||||
return if allowed_one_liner?(node)
|
||||
|
||||
missing_separating_line(node) do |location|
|
||||
msg = format(MSG, example: node.method_name)
|
||||
add_offense(location, message: msg) do |corrector|
|
||||
corrector.insert_after(location.end, "\n")
|
||||
end
|
||||
missing_separating_line_offense(node) do |method|
|
||||
format(MSG, example: method)
|
||||
end
|
||||
end
|
||||
|
||||
@ -23,21 +23,17 @@ module RuboCop
|
||||
# end
|
||||
# end
|
||||
#
|
||||
class EmptyLineAfterExampleGroup < Cop
|
||||
class EmptyLineAfterExampleGroup < Base
|
||||
extend AutoCorrector
|
||||
include RuboCop::RSpec::BlankLineSeparation
|
||||
include RuboCop::RSpec::EmptyLineSeparation
|
||||
|
||||
MSG = 'Add an empty line after `%<example_group>s`.'
|
||||
|
||||
def on_block(node)
|
||||
return unless example_group?(node)
|
||||
return if last_child?(node)
|
||||
|
||||
missing_separating_line(node) do |location|
|
||||
msg = format(MSG, example_group: node.method_name)
|
||||
add_offense(location, message: msg) do |corrector|
|
||||
corrector.insert_after(location.end, "\n")
|
||||
end
|
||||
missing_separating_line_offense(node) do |method|
|
||||
format(MSG, example_group: method)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -16,24 +16,21 @@ module RuboCop
|
||||
# let(:something) { other }
|
||||
#
|
||||
# it { does_something }
|
||||
class EmptyLineAfterFinalLet < Cop
|
||||
class EmptyLineAfterFinalLet < Base
|
||||
extend AutoCorrector
|
||||
include RuboCop::RSpec::BlankLineSeparation
|
||||
include RuboCop::RSpec::EmptyLineSeparation
|
||||
|
||||
MSG = 'Add an empty line after the last `let` block.'
|
||||
MSG = 'Add an empty line after the last `%<let>s`.'
|
||||
|
||||
def on_block(node)
|
||||
return unless example_group_with_body?(node)
|
||||
|
||||
latest_let = node.body.child_nodes.select { |child| let?(child) }.last
|
||||
final_let = node.body.child_nodes.reverse.find { |child| let?(child) }
|
||||
|
||||
return if latest_let.nil?
|
||||
return if last_child?(latest_let)
|
||||
return if final_let.nil?
|
||||
|
||||
missing_separating_line(latest_let) do |location|
|
||||
add_offense(location) do |corrector|
|
||||
corrector.insert_after(location.end, "\n")
|
||||
end
|
||||
missing_separating_line_offense(final_let) do |method|
|
||||
format(MSG, let: method)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -33,21 +33,17 @@ module RuboCop
|
||||
#
|
||||
# it { does_something }
|
||||
#
|
||||
class EmptyLineAfterHook < Cop
|
||||
class EmptyLineAfterHook < Base
|
||||
extend AutoCorrector
|
||||
include RuboCop::RSpec::BlankLineSeparation
|
||||
include RuboCop::RSpec::EmptyLineSeparation
|
||||
|
||||
MSG = 'Add an empty line after `%<hook>s`.'
|
||||
|
||||
def on_block(node)
|
||||
return unless hook?(node)
|
||||
return if last_child?(node)
|
||||
|
||||
missing_separating_line(node) do |location|
|
||||
msg = format(MSG, hook: node.method_name)
|
||||
add_offense(location, message: msg) do |corrector|
|
||||
corrector.insert_after(location.end, "\n")
|
||||
end
|
||||
missing_separating_line_offense(node) do |method|
|
||||
format(MSG, hook: method)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -14,20 +14,17 @@ module RuboCop
|
||||
# subject(:obj) { described_class }
|
||||
#
|
||||
# let(:foo) { bar }
|
||||
class EmptyLineAfterSubject < Cop
|
||||
class EmptyLineAfterSubject < Base
|
||||
extend AutoCorrector
|
||||
include RuboCop::RSpec::BlankLineSeparation
|
||||
include RuboCop::RSpec::EmptyLineSeparation
|
||||
|
||||
MSG = 'Add empty line after `subject`.'
|
||||
MSG = 'Add an empty line after `%<subject>s`.'
|
||||
|
||||
def on_block(node)
|
||||
return unless subject?(node) && !in_spec_block?(node)
|
||||
return if last_child?(node)
|
||||
|
||||
missing_separating_line(node) do |location|
|
||||
add_offense(location) do |corrector|
|
||||
corrector.insert_after(location.end, "\n")
|
||||
end
|
||||
missing_separating_line_offense(node) do |method|
|
||||
format(MSG, subject: method)
|
||||
end
|
||||
end
|
||||
|
||||
@ -25,7 +25,7 @@ module RuboCop
|
||||
# result = service.call
|
||||
# expect(result).to be(true)
|
||||
# end
|
||||
class ExampleLength < Cop
|
||||
class ExampleLength < Base
|
||||
include CodeLength
|
||||
|
||||
MSG = 'Example has too many lines [%<total>d/%<max>d].'
|
||||
@ -47,7 +47,7 @@ module RuboCop
|
||||
# result = service.call
|
||||
# expect(result).to be(true)
|
||||
# end
|
||||
class ExampleWithoutDescription < Cop
|
||||
class ExampleWithoutDescription < Base
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
MSG_DEFAULT_ARGUMENT = 'Omit the argument when you want to ' \
|
||||
@ -29,7 +29,7 @@ module RuboCop
|
||||
# # good
|
||||
# it 'does things' do
|
||||
# end
|
||||
class ExampleWording < Cop
|
||||
class ExampleWording < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG_SHOULD = 'Do not use should when describing your tests.'
|
||||
@ -47,9 +47,9 @@ module RuboCop
|
||||
|
||||
def on_block(node)
|
||||
it_description(node) do |description_node, message|
|
||||
if message =~ SHOULD_PREFIX
|
||||
if message.match?(SHOULD_PREFIX)
|
||||
add_wording_offense(description_node, MSG_SHOULD)
|
||||
elsif message =~ IT_PREFIX
|
||||
elsif message.match?(IT_PREFIX)
|
||||
add_wording_offense(description_node, MSG_IT)
|
||||
end
|
||||
end
|
||||
@ -77,7 +77,7 @@ module RuboCop
|
||||
def replacement_text(node)
|
||||
text = text(node)
|
||||
|
||||
if text =~ SHOULD_PREFIX
|
||||
if text.match?(SHOULD_PREFIX)
|
||||
RuboCop::RSpec::Wording.new(
|
||||
text,
|
||||
ignore: ignored_words,
|
||||
@ -16,7 +16,7 @@ module RuboCop
|
||||
# expect(pattern).to eq(/foo/)
|
||||
# expect(name).to eq("John")
|
||||
#
|
||||
class ExpectActual < Cop
|
||||
class ExpectActual < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Provide the actual you are testing to `expect(...)`.'
|
||||
@ -29,7 +29,7 @@ module RuboCop
|
||||
# expect { run }.to change { Foo.bar(:count) }
|
||||
# expect { run }.to change { user.reload.name }
|
||||
#
|
||||
class ExpectChange < Cop
|
||||
class ExpectChange < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
@ -20,7 +20,7 @@ module RuboCop
|
||||
# it do
|
||||
# expect(something).to eq 'foo'
|
||||
# end
|
||||
class ExpectInHook < Cop
|
||||
class ExpectInHook < Base
|
||||
MSG = 'Do not use `%<expect>s` in `%<hook>s` hook'
|
||||
|
||||
def_node_search :expectation, Expectations::ALL.send_pattern
|
||||
@ -14,7 +14,7 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# expect { my_app.print_report }.to output('Hello World').to_stdout
|
||||
class ExpectOutput < Cop
|
||||
class ExpectOutput < Base
|
||||
MSG = 'Use `expect { ... }.to output(...).to_%<name>s` '\
|
||||
'instead of mutating $%<name>s.'
|
||||
|
||||
@ -24,7 +24,7 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# count { 1 }
|
||||
class AttributeDefinedStatically < Cop
|
||||
class AttributeDefinedStatically < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use a block to declare attribute values.'
|
||||
@ -39,7 +39,7 @@ module RuboCop
|
||||
|
||||
def on_block(node)
|
||||
attributes = factory_attributes(node) || []
|
||||
attributes = [attributes] unless attributes.is_a?(Array)
|
||||
attributes = [attributes] unless attributes.is_a?(Array) # rubocop:disable Style/ArrayCoercion, Lint/RedundantCopDisableDirective
|
||||
|
||||
attributes.each do |attribute|
|
||||
next unless offensive_receiver?(attribute.receiver, node)
|
||||
@ -84,7 +84,7 @@ module RuboCop
|
||||
def autocorrect_replacing_parens(corrector, node)
|
||||
left_braces, right_braces = braces(node)
|
||||
|
||||
corrector.replace(node.location.begin, ' ' + left_braces)
|
||||
corrector.replace(node.location.begin, " #{left_braces}")
|
||||
corrector.replace(node.location.end, right_braces)
|
||||
end
|
||||
|
||||
@ -24,7 +24,7 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# 3.times { create :user }
|
||||
class CreateList < Cop
|
||||
class CreateList < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
@ -44,7 +44,7 @@ module RuboCop
|
||||
PATTERN
|
||||
|
||||
def_node_matcher :factory_list_call, <<-PATTERN
|
||||
(send ${(const nil? {:FactoryGirl :FactoryBot}) nil?} :create_list (sym $_) (int $_) $...)
|
||||
(send {(const nil? {:FactoryGirl :FactoryBot}) nil?} :create_list (sym _) (int $_) ...)
|
||||
PATTERN
|
||||
|
||||
def on_block(node)
|
||||
@ -60,7 +60,7 @@ module RuboCop
|
||||
def on_send(node)
|
||||
return unless style == :n_times
|
||||
|
||||
factory_list_call(node) do |_receiver, _factory, count, _|
|
||||
factory_list_call(node) do |count|
|
||||
message = format(MSG_N_TIMES, number: count)
|
||||
add_offense(node.loc.selector, message: message) do |corrector|
|
||||
TimesCorrector.new(node).call(corrector)
|
||||
@ -79,7 +79,7 @@ module RuboCop
|
||||
end
|
||||
|
||||
# :nodoc
|
||||
class Corrector
|
||||
module Corrector
|
||||
private
|
||||
|
||||
def build_options_string(options)
|
||||
@ -102,7 +102,9 @@ module RuboCop
|
||||
end
|
||||
|
||||
# :nodoc
|
||||
class TimesCorrector < Corrector
|
||||
class TimesCorrector
|
||||
include Corrector
|
||||
|
||||
def initialize(node)
|
||||
@node = node
|
||||
end
|
||||
@ -130,7 +132,9 @@ module RuboCop
|
||||
end
|
||||
|
||||
# :nodoc:
|
||||
class CreateListCorrector < Corrector
|
||||
class CreateListCorrector
|
||||
include Corrector
|
||||
|
||||
def initialize(node)
|
||||
@node = node.parent
|
||||
end
|
||||
@ -19,7 +19,7 @@ module RuboCop
|
||||
# # good
|
||||
# factory :foo, class: 'Foo' do
|
||||
# end
|
||||
class FactoryClassName < Cop
|
||||
class FactoryClassName < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = "Pass '%<class_name>s' string instead of `%<class_name>s` " \
|
||||
@ -56,35 +56,43 @@ module RuboCop
|
||||
# # good
|
||||
# my_class_spec.rb # describe MyClass, '#method'
|
||||
#
|
||||
class FilePath < Cop
|
||||
include RuboCop::RSpec::TopLevelDescribe
|
||||
class FilePath < Base
|
||||
include RuboCop::RSpec::TopLevelGroup
|
||||
|
||||
MSG = 'Spec path should end with `%<suffix>s`.'
|
||||
|
||||
def_node_search :const_described?, '(send _ :describe (const ...) ...)'
|
||||
def_node_matcher :const_described, <<~PATTERN
|
||||
(block
|
||||
$(send #rspec? _example_group $(const ...) $...) ...
|
||||
)
|
||||
PATTERN
|
||||
|
||||
def_node_search :routing_metadata?, '(pair (sym :type) (sym :routing))'
|
||||
|
||||
def on_top_level_describe(node, args)
|
||||
return unless const_described?(node) && single_top_level_describe?
|
||||
return if routing_spec?(args)
|
||||
def on_top_level_group(node)
|
||||
return unless top_level_groups.one?
|
||||
|
||||
glob = glob_for(args)
|
||||
const_described(node) do |send_node, described_class, arguments|
|
||||
next if routing_spec?(arguments)
|
||||
|
||||
return if filename_ends_with?(glob)
|
||||
|
||||
add_offense(
|
||||
node,
|
||||
message: format(MSG, suffix: glob)
|
||||
)
|
||||
ensure_correct_file_path(send_node, described_class, arguments)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ensure_correct_file_path(send_node, described_class, arguments)
|
||||
glob = glob_for(described_class, arguments.first)
|
||||
return if filename_ends_with?(glob)
|
||||
|
||||
add_offense(send_node, message: format(MSG, suffix: glob))
|
||||
end
|
||||
|
||||
def routing_spec?(args)
|
||||
args.any?(&method(:routing_metadata?))
|
||||
end
|
||||
|
||||
def glob_for((described_class, method_name))
|
||||
def glob_for(described_class, method_name)
|
||||
return glob_for_spec_suffix_only? if spec_suffix_only?
|
||||
|
||||
"#{expected_path(described_class)}#{name_glob(method_name)}*_spec.rb"
|
||||
@ -94,10 +102,10 @@ module RuboCop
|
||||
'*_spec.rb'
|
||||
end
|
||||
|
||||
def name_glob(name)
|
||||
return unless name&.str_type?
|
||||
def name_glob(method_name)
|
||||
return unless method_name&.str_type?
|
||||
|
||||
"*#{name.str_content.gsub(/\W/, '')}" unless ignore_methods?
|
||||
"*#{method_name.str_content.gsub(/\W/, '')}" unless ignore_methods?
|
||||
end
|
||||
|
||||
def expected_path(constant)
|
||||
@ -19,23 +19,19 @@ module RuboCop
|
||||
# # good
|
||||
# describe MyClass do
|
||||
# end
|
||||
class Focus < Cop
|
||||
class Focus < Base
|
||||
MSG = 'Focused spec found.'
|
||||
|
||||
focusable =
|
||||
ExampleGroups::GROUPS +
|
||||
ExampleGroups::SKIPPED +
|
||||
Examples::EXAMPLES +
|
||||
Examples::SKIPPED +
|
||||
Examples::PENDING
|
||||
|
||||
focused = ExampleGroups::FOCUSED + Examples::FOCUSED
|
||||
|
||||
FOCUSABLE_SELECTORS = focusable.node_pattern_union
|
||||
def_node_matcher :focusable_selector?,
|
||||
(ExampleGroups::GROUPS + ExampleGroups::SKIPPED +
|
||||
Examples::EXAMPLES + Examples::SKIPPED +
|
||||
Examples::PENDING).node_pattern_union
|
||||
|
||||
def_node_matcher :metadata, <<-PATTERN
|
||||
{(send #{RSPEC} #{FOCUSABLE_SELECTORS} <$(sym :focus) ...>)
|
||||
(send #{RSPEC} #{FOCUSABLE_SELECTORS} ... (hash <$(pair (sym :focus) true) ...>))}
|
||||
{(send #rspec? #focusable_selector? <$(sym :focus) ...>)
|
||||
(send #rspec? #focusable_selector? ... (hash <$(pair (sym :focus) true) ...>))}
|
||||
PATTERN
|
||||
|
||||
def_node_matcher :focused_block?, focused.send_pattern
|
||||
@ -57,21 +57,20 @@ module RuboCop
|
||||
# before(:example) do
|
||||
# # ...
|
||||
# end
|
||||
class HookArgument < Cop
|
||||
class HookArgument < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
IMPLICIT_MSG = 'Omit the default `%<scope>p` ' \
|
||||
'argument for RSpec hooks.'
|
||||
IMPLICIT_MSG = 'Omit the default `%<scope>p` argument for RSpec hooks.'
|
||||
EXPLICIT_MSG = 'Use `%<scope>p` for RSpec hooks.'
|
||||
|
||||
HOOKS = Hooks::ALL.node_pattern_union.freeze
|
||||
def_node_matcher :hook?, Hooks::ALL.node_pattern_union
|
||||
|
||||
def_node_matcher :scoped_hook, <<-PATTERN
|
||||
(block $(send _ #{HOOKS} (sym ${:each :example})) ...)
|
||||
(block $(send _ #hook? (sym ${:each :example})) ...)
|
||||
PATTERN
|
||||
|
||||
def_node_matcher :unscoped_hook, "(block $(send _ #{HOOKS}) ...)"
|
||||
def_node_matcher :unscoped_hook, '(block $(send _ #hook?) ...)'
|
||||
|
||||
def on_block(node)
|
||||
hook(node) do |method_send, scope_name|
|
||||
@ -23,7 +23,7 @@ module RuboCop
|
||||
# expect(foo).to be
|
||||
# end
|
||||
#
|
||||
class HooksBeforeExamples < Cop
|
||||
class HooksBeforeExamples < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Move `%<hook>s` above the examples in the group.'
|
||||
@ -16,7 +16,7 @@ module RuboCop
|
||||
# it 'changes something to a new value' do
|
||||
# expect { do_something }.to change(something).to(new_value)
|
||||
# end
|
||||
class ImplicitBlockExpectation < Cop
|
||||
class ImplicitBlockExpectation < Base
|
||||
MSG = 'Avoid implicit block expectations.'
|
||||
|
||||
def_node_matcher :lambda?, <<-PATTERN
|
||||
@ -24,7 +24,7 @@ module RuboCop
|
||||
# # good
|
||||
# it { should be_truthy }
|
||||
#
|
||||
class ImplicitExpect < Cop
|
||||
class ImplicitExpect < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
@ -26,7 +26,7 @@ module RuboCop
|
||||
# # good
|
||||
# it { expect(subject).to be_truthy }
|
||||
#
|
||||
class ImplicitSubject < Cop
|
||||
class ImplicitSubject < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
@ -49,9 +49,10 @@ module RuboCop
|
||||
|
||||
def autocorrect(corrector, node)
|
||||
replacement = 'expect(subject)'
|
||||
if node.method_name == :should
|
||||
case node.method_name
|
||||
when :should
|
||||
replacement += '.to'
|
||||
elsif node.method_name == :should_not
|
||||
when :should_not
|
||||
replacement += '.not_to'
|
||||
end
|
||||
|
||||
@ -62,13 +63,14 @@ module RuboCop
|
||||
example = node.ancestors.find { |parent| example?(parent) }
|
||||
return false if example.nil?
|
||||
|
||||
example.method_name == :its || allowed_by_style?(example)
|
||||
example.method?(:its) || allowed_by_style?(example)
|
||||
end
|
||||
|
||||
def allowed_by_style?(example)
|
||||
if style == :single_line_only
|
||||
case style
|
||||
when :single_line_only
|
||||
example.single_line?
|
||||
elsif style == :single_statement_only
|
||||
when :single_statement_only
|
||||
!example.body.begin_type?
|
||||
else
|
||||
false
|
||||
@ -18,7 +18,7 @@ module RuboCop
|
||||
# expect(foo).to have_received(:bar)
|
||||
# end
|
||||
#
|
||||
class InstanceSpy < Cop
|
||||
class InstanceSpy < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `instance_spy` when you check your double '\
|
||||
@ -46,7 +46,7 @@ module RuboCop
|
||||
# it { expect(foo).to be_empty }
|
||||
# end
|
||||
#
|
||||
class InstanceVariable < Cop
|
||||
class InstanceVariable < Base
|
||||
include RuboCop::RSpec::TopLevelGroup
|
||||
|
||||
MSG = 'Avoid instance variables – use let, ' \
|
||||
@ -15,7 +15,7 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# expect(foo).to be_something
|
||||
class InvalidPredicateMatcher < Cop
|
||||
class InvalidPredicateMatcher < Base
|
||||
MSG = 'Omit `?` from `%<matcher>s`.'
|
||||
|
||||
def_node_matcher :invalid_predicate_matcher?, <<-PATTERN
|
||||
@ -18,7 +18,7 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# it_should_behave_like 'a foo'
|
||||
class ItBehavesLike < Cop
|
||||
class ItBehavesLike < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
@ -15,7 +15,7 @@ module RuboCop
|
||||
# it 'validates users' do
|
||||
# expect([user1, user2, user3]).to all(be_valid)
|
||||
# end
|
||||
class IteratedExpectation < Cop
|
||||
class IteratedExpectation < Base
|
||||
MSG = 'Prefer using the `all` matcher instead ' \
|
||||
'of iterating over an array.'
|
||||
|
||||
@ -31,7 +31,7 @@ module RuboCop
|
||||
# it { expect_something }
|
||||
# it { expect_something_else }
|
||||
#
|
||||
class LeadingSubject < Cop
|
||||
class LeadingSubject < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Declare `subject` above any other `%<offending>s` declarations.'
|
||||
@ -43,33 +43,36 @@ module RuboCop
|
||||
end
|
||||
|
||||
def check_previous_nodes(node)
|
||||
node.parent.each_child_node do |sibling|
|
||||
if offending?(sibling)
|
||||
msg = format(MSG, offending: sibling.method_name)
|
||||
add_offense(node, message: msg) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
offending_node(node) do |offender|
|
||||
msg = format(MSG, offending: offender.method_name)
|
||||
add_offense(node, message: msg) do |corrector|
|
||||
autocorrect(corrector, node, offender)
|
||||
end
|
||||
|
||||
break if offending?(sibling) || sibling.equal?(node)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def autocorrect(corrector, node)
|
||||
first_node = find_first_offending_node(node)
|
||||
def offending_node(node)
|
||||
node.parent.each_child_node.find do |sibling|
|
||||
break if sibling.equal?(node)
|
||||
|
||||
yield sibling if offending?(sibling)
|
||||
end
|
||||
end
|
||||
|
||||
def autocorrect(corrector, node, sibling)
|
||||
RuboCop::RSpec::Corrector::MoveNode.new(
|
||||
node, corrector, processed_source
|
||||
).move_before(first_node)
|
||||
).move_before(sibling)
|
||||
end
|
||||
|
||||
def offending?(node)
|
||||
let?(node) || hook?(node) || example?(node)
|
||||
end
|
||||
|
||||
def find_first_offending_node(node)
|
||||
node.parent.children.find { |sibling| offending?(sibling) }
|
||||
let?(node) ||
|
||||
hook?(node) ||
|
||||
example?(node) ||
|
||||
spec_group?(node) ||
|
||||
include?(node)
|
||||
end
|
||||
|
||||
def in_spec_block?(node)
|
||||
@ -93,7 +93,7 @@ module RuboCop
|
||||
# stub_const('SomeModule::SomeClass', foo_class)
|
||||
# end
|
||||
# end
|
||||
class LeakyConstantDeclaration < Cop
|
||||
class LeakyConstantDeclaration < Base
|
||||
MSG_CONST = 'Stub constant instead of declaring explicitly.'
|
||||
MSG_CLASS = 'Stub class constant instead of declaring explicitly.'
|
||||
MSG_MODULE = 'Stub module constant instead of declaring explicitly.'
|
||||
@ -30,7 +30,7 @@ module RuboCop
|
||||
# it 'checks what some does' do
|
||||
# expect(some).to be
|
||||
# end
|
||||
class LetBeforeExamples < Cop
|
||||
class LetBeforeExamples < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Move `let` before the examples in the group.'
|
||||
@ -25,7 +25,7 @@ module RuboCop
|
||||
# it 'counts widgets' do
|
||||
# expect(Widget.count).to eq(1)
|
||||
# end
|
||||
class LetSetup < Cop
|
||||
class LetSetup < Base
|
||||
MSG = 'Do not use `let!` to setup objects not referenced in tests.'
|
||||
|
||||
def_node_matcher :example_or_shared_group_or_including?,
|
||||
@ -35,7 +35,10 @@ module RuboCop
|
||||
).block_pattern
|
||||
|
||||
def_node_matcher :let_bang, <<-PATTERN
|
||||
(block $(send nil? :let! (sym $_)) args ...)
|
||||
{
|
||||
(block $(send nil? :let! {(sym $_) (str $_)}) ...)
|
||||
$(send nil? :let! {(sym $_) (str $_)} block_pass)
|
||||
}
|
||||
PATTERN
|
||||
|
||||
def_node_search :method_called?, '(send nil? %)'
|
||||
@ -52,7 +55,7 @@ module RuboCop
|
||||
|
||||
def unused_let_bang(node)
|
||||
child_let_bang(node) do |method_send, method_name|
|
||||
yield(method_send) unless method_called?(node, method_name)
|
||||
yield(method_send) unless method_called?(node, method_name.to_sym)
|
||||
end
|
||||
end
|
||||
|
||||
@ -13,7 +13,7 @@ module RuboCop
|
||||
# thing = Thing.new(baz: 42)
|
||||
# allow(foo).to receive(:bar).and_return(thing)
|
||||
#
|
||||
class MessageChain < Cop
|
||||
class MessageChain < Base
|
||||
MSG = 'Avoid stubbing using `%<method>s`.'
|
||||
|
||||
def_node_matcher :message_chain, <<-PATTERN
|
||||
@ -24,7 +24,7 @@ module RuboCop
|
||||
# # good
|
||||
# expect(foo).to receive(:bar)
|
||||
#
|
||||
class MessageExpectation < Cop
|
||||
class MessageExpectation < Base
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
MSG = 'Prefer `%<style>s` for setting message expectations.'
|
||||
@ -24,7 +24,7 @@ module RuboCop
|
||||
# # good
|
||||
# expect(foo).to receive(:bar)
|
||||
#
|
||||
class MessageSpies < Cop
|
||||
class MessageSpies < Base
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
MSG_RECEIVE = 'Prefer `receive` for setting message expectations.'
|
||||
@ -19,7 +19,7 @@ module RuboCop
|
||||
#
|
||||
# describe "A feature example" do
|
||||
# end
|
||||
class MissingExampleGroupArgument < Cop
|
||||
class MissingExampleGroupArgument < Base
|
||||
MSG = 'The first argument to `%<method>s` should not be empty.'
|
||||
|
||||
def on_block(node)
|
||||
@ -3,7 +3,7 @@
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# Checks for multiple top level describes.
|
||||
# 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.
|
||||
@ -22,17 +22,20 @@ module RuboCop
|
||||
# describe '.do_something_else' do
|
||||
# end
|
||||
# end
|
||||
class MultipleDescribes < Cop
|
||||
include RuboCop::RSpec::TopLevelDescribe
|
||||
class MultipleDescribes < Base
|
||||
include RuboCop::RSpec::TopLevelGroup
|
||||
|
||||
MSG = 'Do not use multiple top level describes - '\
|
||||
MSG = 'Do not use multiple top-level example groups - '\
|
||||
'try to nest them.'
|
||||
|
||||
def on_top_level_describe(node, _args)
|
||||
return if single_top_level_describe?
|
||||
return unless top_level_nodes.first.equal?(node)
|
||||
def on_top_level_group(node)
|
||||
top_level_example_groups =
|
||||
top_level_groups.select(&method(:example_group?))
|
||||
|
||||
add_offense(node)
|
||||
return if top_level_example_groups.one?
|
||||
return unless top_level_example_groups.first.equal?(node)
|
||||
|
||||
add_offense(node.send_node)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -45,22 +45,18 @@ module RuboCop
|
||||
# end
|
||||
# end
|
||||
#
|
||||
class MultipleExpectations < Cop
|
||||
class MultipleExpectations < Base
|
||||
include ConfigurableMax
|
||||
|
||||
MSG = 'Example has too many expectations [%<total>d/%<max>d].'
|
||||
|
||||
ANYTHING = ->(_node) { true }
|
||||
TRUE = ->(node) { node.true_type? }
|
||||
|
||||
def_node_matcher :aggregate_failures?, <<-PATTERN
|
||||
(block {
|
||||
(send _ _ <(sym :aggregate_failures) ...>)
|
||||
(send _ _ ... (hash <(pair (sym :aggregate_failures) true) ...>))
|
||||
} ...)
|
||||
PATTERN
|
||||
|
||||
def_node_matcher :aggregate_failures_present?, <<-PATTERN
|
||||
(block {
|
||||
(send _ _ <(sym :aggregate_failures) ...>)
|
||||
(send _ _ ... (hash <(pair (sym :aggregate_failures) _) ...>))
|
||||
(send _ _ ... (hash <(pair (sym :aggregate_failures) %1) ...>))
|
||||
} ...)
|
||||
PATTERN
|
||||
|
||||
@ -89,12 +85,12 @@ module RuboCop
|
||||
node_with_aggregate_failures = find_aggregate_failures(example_node)
|
||||
return false unless node_with_aggregate_failures
|
||||
|
||||
aggregate_failures?(node_with_aggregate_failures)
|
||||
aggregate_failures?(node_with_aggregate_failures, TRUE)
|
||||
end
|
||||
|
||||
def find_aggregate_failures(example_node)
|
||||
example_node.send_node.each_ancestor(:block)
|
||||
.find { |block_node| aggregate_failures_present?(block_node) }
|
||||
.find { |block_node| aggregate_failures?(block_node, ANYTHING) }
|
||||
end
|
||||
|
||||
def find_expectation(node, &block)
|
||||
@ -0,0 +1,148 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# Checks if example groups contain too many `let` and `subject` calls.
|
||||
#
|
||||
# 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`.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# describe MyClass do
|
||||
# let(:foo) { [] }
|
||||
# let(:bar) { [] }
|
||||
# let!(:baz) { [] }
|
||||
# let(:qux) { [] }
|
||||
# let(:quux) { [] }
|
||||
# let(:quuz) { {} }
|
||||
# end
|
||||
#
|
||||
# describe MyClass do
|
||||
# let(:foo) { [] }
|
||||
# let(:bar) { [] }
|
||||
# let!(:baz) { [] }
|
||||
#
|
||||
# context 'when stuff' do
|
||||
# let(:qux) { [] }
|
||||
# let(:quux) { [] }
|
||||
# let(:quuz) { {} }
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# describe MyClass do
|
||||
# let(:bar) { [] }
|
||||
# let!(:baz) { [] }
|
||||
# let(:qux) { [] }
|
||||
# let(:quux) { [] }
|
||||
# let(:quuz) { {} }
|
||||
# end
|
||||
#
|
||||
# describe MyClass do
|
||||
# context 'when stuff' do
|
||||
# let(:foo) { [] }
|
||||
# let(:bar) { [] }
|
||||
# let!(:booger) { [] }
|
||||
# end
|
||||
#
|
||||
# context 'when other stuff' do
|
||||
# let(:qux) { [] }
|
||||
# let(:quux) { [] }
|
||||
# let(:quuz) { {} }
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# @example when disabling AllowSubject configuration
|
||||
#
|
||||
# # rubocop.yml
|
||||
# # RSpec/MultipleMemoizedHelpers:
|
||||
# # AllowSubject: false
|
||||
#
|
||||
# # bad - `subject` counts towards memoized helpers
|
||||
# describe MyClass do
|
||||
# subject { {} }
|
||||
# let(:foo) { [] }
|
||||
# let(:bar) { [] }
|
||||
# let!(:baz) { [] }
|
||||
# let(:qux) { [] }
|
||||
# let(:quux) { [] }
|
||||
# end
|
||||
#
|
||||
# @example with Max configuration
|
||||
#
|
||||
# # rubocop.yml
|
||||
# # RSpec/MultipleMemoizedHelpers:
|
||||
# # Max: 1
|
||||
#
|
||||
# # bad
|
||||
# describe MyClass do
|
||||
# let(:foo) { [] }
|
||||
# let(:bar) { [] }
|
||||
# end
|
||||
#
|
||||
class MultipleMemoizedHelpers < Base
|
||||
include ConfigurableMax
|
||||
include RuboCop::RSpec::Variable
|
||||
|
||||
MSG = 'Example group has too many memoized helpers [%<count>d/%<max>d]'
|
||||
|
||||
def on_block(node)
|
||||
return unless spec_group?(node)
|
||||
|
||||
count = all_helpers(node).uniq.count
|
||||
|
||||
return if count <= max
|
||||
|
||||
self.max = count
|
||||
add_offense(node, message: format(MSG, count: count, max: max))
|
||||
end
|
||||
|
||||
def on_new_investigation
|
||||
@example_group_memoized_helpers = {}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :example_group_memoized_helpers
|
||||
|
||||
def all_helpers(node)
|
||||
[
|
||||
*helpers(node),
|
||||
*node.each_ancestor(:block).flat_map(&method(:helpers))
|
||||
]
|
||||
end
|
||||
|
||||
def helpers(node)
|
||||
@example_group_memoized_helpers[node] ||=
|
||||
variable_nodes(node).map do |variable_node|
|
||||
if variable_node.block_type?
|
||||
variable_definition?(variable_node.send_node)
|
||||
else # block-pass (`let(:foo, &bar)`)
|
||||
variable_definition?(variable_node)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def variable_nodes(node)
|
||||
example_group = RuboCop::RSpec::ExampleGroup.new(node)
|
||||
if allow_subject?
|
||||
example_group.lets
|
||||
else
|
||||
example_group.lets + example_group.subjects
|
||||
end
|
||||
end
|
||||
|
||||
def max
|
||||
cop_config['Max']
|
||||
end
|
||||
|
||||
def allow_subject?
|
||||
cop_config['AllowSubject']
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -33,7 +33,7 @@ module RuboCop
|
||||
# - If subjects are defined with `subject!` then we don't autocorrect.
|
||||
# This is enough of an edge case that people can just move this to
|
||||
# a `before` hook on their own
|
||||
class MultipleSubjects < Cop
|
||||
class MultipleSubjects < Base
|
||||
extend AutoCorrector
|
||||
include RangeHelp
|
||||
|
||||
@ -41,7 +41,7 @@ module RuboCop
|
||||
#
|
||||
# it { is_expected.to be_valid }
|
||||
# end
|
||||
class NamedSubject < Cop
|
||||
class NamedSubject < Base
|
||||
MSG = 'Name your test subject if you need '\
|
||||
'to reference it explicitly.'
|
||||
|
||||
@ -85,9 +85,9 @@ module RuboCop
|
||||
# end
|
||||
# end
|
||||
#
|
||||
class NestedGroups < Cop
|
||||
class NestedGroups < Base
|
||||
include ConfigurableMax
|
||||
include RuboCop::RSpec::TopLevelDescribe
|
||||
include RuboCop::RSpec::TopLevelGroup
|
||||
|
||||
MSG = 'Maximum example group nesting exceeded [%<total>d/%<max>d].'
|
||||
|
||||
@ -97,8 +97,8 @@ module RuboCop
|
||||
"Configuration key `#{DEPRECATED_MAX_KEY}` for #{cop_name} is " \
|
||||
'deprecated in favor of `Max`. Please use that instead.'
|
||||
|
||||
def on_top_level_describe(node, _args)
|
||||
find_nested_example_groups(node.parent) do |example_group, nesting|
|
||||
def on_top_level_group(node)
|
||||
find_nested_example_groups(node) do |example_group, nesting|
|
||||
self.max = nesting
|
||||
add_offense(
|
||||
example_group.send_node,
|
||||
@ -15,7 +15,7 @@ module RuboCop
|
||||
# it '...' do
|
||||
# expect(false).not_to be_true
|
||||
# end
|
||||
class NotToNot < Cop
|
||||
class NotToNot < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
@ -21,7 +21,7 @@ module RuboCop
|
||||
# let(:foo) { bar }
|
||||
# let(:baz) { baz }
|
||||
# let!(:other) { other }
|
||||
class OverwritingSetup < Cop
|
||||
class OverwritingSetup < Base
|
||||
MSG = '`%<name>s` is already defined.'
|
||||
|
||||
def_node_matcher :setup?, (Helpers::ALL + Subject::ALL).block_pattern
|
||||
@ -31,7 +31,7 @@ module RuboCop
|
||||
# # good
|
||||
# describe MyClass do
|
||||
# end
|
||||
class Pending < Cop
|
||||
class Pending < Base
|
||||
MSG = 'Pending spec found.'
|
||||
|
||||
PENDING = Examples::PENDING + Examples::SKIPPED + ExampleGroups::SKIPPED
|
||||
@ -208,18 +208,20 @@ module RuboCop
|
||||
'is_a?'
|
||||
when 'be_an_instance_of', 'be_instance_of', 'an_instance_of'
|
||||
'instance_of?'
|
||||
when 'include', 'respond_to'
|
||||
matcher + '?'
|
||||
when 'include'
|
||||
'include?'
|
||||
when 'respond_to'
|
||||
'respond_to?'
|
||||
when /^have_(.+)/
|
||||
"has_#{Regexp.last_match(1)}?"
|
||||
else
|
||||
matcher[/^be_(.+)/, 1] + '?'
|
||||
"#{matcher[/^be_(.+)/, 1]}?"
|
||||
end
|
||||
end
|
||||
# rubocop:enable Metrics/MethodLength
|
||||
|
||||
def replacement_matcher(node)
|
||||
case [cop_config['Strict'], node.method_name == :to]
|
||||
case [cop_config['Strict'], node.method?(:to)]
|
||||
when [true, true]
|
||||
'be(true)'
|
||||
when [true, false]
|
||||
@ -269,7 +271,7 @@ module RuboCop
|
||||
#
|
||||
# # good - the above code is rewritten to it by this cop
|
||||
# expect(foo.something?).to be_truthy
|
||||
class PredicateMatcher < Cop
|
||||
class PredicateMatcher < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
include InflectedHelper
|
||||
@ -288,15 +290,6 @@ module RuboCop
|
||||
check_explicit(node) if style == :explicit
|
||||
end
|
||||
|
||||
def autocorrect(node)
|
||||
case style
|
||||
when :inflected
|
||||
autocorrect_inflected(node)
|
||||
when :explicit
|
||||
autocorrect_explicit(node)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# returns args location with whitespace
|
||||
@ -30,7 +30,7 @@ module RuboCop
|
||||
# it { is_expected.to have_http_status :success }
|
||||
# it { is_expected.to have_http_status :error }
|
||||
#
|
||||
class HttpStatus < Cop
|
||||
class HttpStatus < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
@ -23,7 +23,7 @@ module RuboCop
|
||||
# expect(foo).to receive(:bar).at_most(:once)
|
||||
# expect(foo).to receive(:bar).at_most(:twice).times
|
||||
#
|
||||
class ReceiveCounts < Cop
|
||||
class ReceiveCounts < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `%<alternative>s` instead of `%<original>s`.'
|
||||
@ -13,14 +13,14 @@ module RuboCop
|
||||
# # good
|
||||
# expect(foo).not_to receive(:bar)
|
||||
#
|
||||
class ReceiveNever < Cop
|
||||
class ReceiveNever < Base
|
||||
extend AutoCorrector
|
||||
MSG = 'Use `not_to receive` instead of `never`.'
|
||||
|
||||
def_node_search :method_on_stub?, '(send nil? :receive ...)'
|
||||
|
||||
def on_send(node)
|
||||
return unless node.method_name == :never && method_on_stub?(node)
|
||||
return unless node.method?(:never) && method_on_stub?(node)
|
||||
|
||||
add_offense(node.loc.selector) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
@ -40,7 +40,7 @@ module RuboCop
|
||||
# end
|
||||
# end
|
||||
#
|
||||
class RepeatedDescription < Cop
|
||||
class RepeatedDescription < Base
|
||||
MSG = "Don't repeat descriptions within an example group."
|
||||
|
||||
def on_block(node)
|
||||
@ -15,7 +15,7 @@ module RuboCop
|
||||
# expect(user).to be_valid
|
||||
# end
|
||||
#
|
||||
class RepeatedExample < Cop
|
||||
class RepeatedExample < Base
|
||||
MSG = "Don't repeat examples within an example group."
|
||||
|
||||
def on_block(node)
|
||||
@ -41,7 +41,7 @@ module RuboCop
|
||||
def example_signature(example)
|
||||
key_parts = [example.metadata, example.implementation]
|
||||
|
||||
if example.definition.method_name == :its
|
||||
if example.definition.method?(:its)
|
||||
key_parts << example.definition.arguments
|
||||
end
|
||||
|
||||
@ -43,7 +43,7 @@ module RuboCop
|
||||
# it { is_expected.to respond_to :each }
|
||||
# end
|
||||
#
|
||||
class RepeatedExampleGroupBody < Cop
|
||||
class RepeatedExampleGroupBody < Base
|
||||
MSG = 'Repeated %<group>s block body on line(s) %<loc>s'
|
||||
|
||||
def_node_matcher :several_example_groups?, <<-PATTERN
|
||||
@ -43,7 +43,7 @@ module RuboCop
|
||||
# # example group
|
||||
# end
|
||||
#
|
||||
class RepeatedExampleGroupDescription < Cop
|
||||
class RepeatedExampleGroupDescription < Base
|
||||
MSG = 'Repeated %<group>s block description on line(s) %<loc>s'
|
||||
|
||||
def_node_matcher :several_example_groups?, <<-PATTERN
|
||||
@ -33,7 +33,7 @@ module RuboCop
|
||||
# # also good as the returned value is dynamic
|
||||
# allow(Foo).to receive(:bar) { bar.baz }
|
||||
#
|
||||
class ReturnFromStub < Cop
|
||||
class ReturnFromStub < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
@ -26,7 +26,7 @@ module RuboCop
|
||||
# let!(:baz) { 3 }
|
||||
# end
|
||||
#
|
||||
class ScatteredLet < Cop
|
||||
class ScatteredLet < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Group all let/let! blocks in the example group together.'
|
||||
@ -22,7 +22,7 @@ module RuboCop
|
||||
# end
|
||||
# end
|
||||
#
|
||||
class ScatteredSetup < Cop
|
||||
class ScatteredSetup < Base
|
||||
MSG = 'Do not define multiple `%<hook_name>s` hooks in the same '\
|
||||
'example group (also defined on %<lines>s).'
|
||||
|
||||
@ -50,7 +50,7 @@ module RuboCop
|
||||
# end
|
||||
# end
|
||||
#
|
||||
class SharedContext < Cop
|
||||
class SharedContext < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG_EXAMPLES = "Use `shared_examples` when you don't "\
|
||||
@ -20,7 +20,7 @@ module RuboCop
|
||||
# shared_examples_for 'foo bar baz'
|
||||
# include_examples 'foo bar baz'
|
||||
#
|
||||
class SharedExamples < Cop
|
||||
class SharedExamples < Base
|
||||
extend AutoCorrector
|
||||
|
||||
def_node_matcher :shared_examples,
|
||||
@ -16,7 +16,7 @@ module RuboCop
|
||||
# allow(foo).to receive(:bar, :baz)
|
||||
# allow(foo).to receive("bar.baz")
|
||||
#
|
||||
class SingleArgumentMessageChain < Cop
|
||||
class SingleArgumentMessageChain < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = 'Use `%<recommended>s` instead of calling '\
|
||||
@ -21,7 +21,7 @@ module RuboCop
|
||||
# end
|
||||
# end
|
||||
#
|
||||
class SubjectStub < Cop
|
||||
class SubjectStub < Base
|
||||
include RuboCop::RSpec::TopLevelGroup
|
||||
|
||||
MSG = 'Do not stub methods of the object under test.'
|
||||
@ -39,7 +39,7 @@ module RuboCop
|
||||
# name # => :thing
|
||||
# end
|
||||
#
|
||||
# @param node [RuboCop::Node]
|
||||
# @param node [RuboCop::AST::Node]
|
||||
#
|
||||
# @yield [Symbol] subject name
|
||||
def_node_matcher :subject, <<-PATTERN
|
||||
@ -30,7 +30,7 @@ module RuboCop
|
||||
# }.to raise_error(/err/)
|
||||
#
|
||||
# expect { do_something }.not_to raise_error
|
||||
class UnspecifiedException < Cop
|
||||
class UnspecifiedException < Base
|
||||
MSG = 'Specify the exception being captured'
|
||||
|
||||
def_node_matcher :empty_raise_error_or_exception, <<-PATTERN
|
||||
@ -7,22 +7,22 @@ module RuboCop
|
||||
#
|
||||
# @example EnforcedStyle: symbols (default)
|
||||
# # bad
|
||||
# let('user_name') { 'Adam' }
|
||||
# subject('user') { create_user }
|
||||
# let('user_name') { 'Adam' }
|
||||
#
|
||||
# # good
|
||||
# let(:user_name) { 'Adam' }
|
||||
# subject(:user) { create_user }
|
||||
# let(:user_name) { 'Adam' }
|
||||
#
|
||||
# @example EnforcedStyle: strings
|
||||
# # bad
|
||||
# let(:user_name) { 'Adam' }
|
||||
# subject(:user) { create_user }
|
||||
# let(:user_name) { 'Adam' }
|
||||
#
|
||||
# # good
|
||||
# let('user_name') { 'Adam' }
|
||||
# subject('user') { create_user }
|
||||
class VariableDefinition < Cop
|
||||
# let('user_name') { 'Adam' }
|
||||
class VariableDefinition < Base
|
||||
include ConfigurableEnforcedStyle
|
||||
include RuboCop::RSpec::Variable
|
||||
|
||||
@ -44,7 +44,7 @@ module RuboCop
|
||||
end
|
||||
|
||||
def string?(node)
|
||||
node.str_type? || node.dstr_type?
|
||||
node.str_type?
|
||||
end
|
||||
|
||||
def symbol?(node)
|
||||
@ -0,0 +1,66 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# Checks that memoized helper names use the configured style.
|
||||
#
|
||||
# Variables can be excluded from checking using the `IgnoredPatterns`
|
||||
# option.
|
||||
#
|
||||
# @example EnforcedStyle: snake_case (default)
|
||||
# # bad
|
||||
# subject(:userName1) { 'Adam' }
|
||||
# let(:userName2) { 'Adam' }
|
||||
#
|
||||
# # good
|
||||
# subject(:user_name_1) { 'Adam' }
|
||||
# let(:user_name_2) { 'Adam' }
|
||||
#
|
||||
# @example EnforcedStyle: camelCase
|
||||
# # bad
|
||||
# subject(:user_name_1) { 'Adam' }
|
||||
# let(:user_name_2) { 'Adam' }
|
||||
#
|
||||
# # good
|
||||
# subject(:userName1) { 'Adam' }
|
||||
# let(:userName2) { 'Adam' }
|
||||
#
|
||||
# @example IgnoredPatterns configuration
|
||||
#
|
||||
# # rubocop.yml
|
||||
# # RSpec/VariableName:
|
||||
# # EnforcedStyle: snake_case
|
||||
# # IgnoredPatterns:
|
||||
# # - ^userFood
|
||||
#
|
||||
# @example
|
||||
# # okay because it matches the `^userFood` regex in `IgnoredPatterns`
|
||||
# subject(:userFood_1) { 'spaghetti' }
|
||||
# let(:userFood_2) { 'fettuccine' }
|
||||
#
|
||||
class VariableName < Base
|
||||
include ConfigurableNaming
|
||||
include IgnoredPattern
|
||||
include RuboCop::RSpec::Variable
|
||||
|
||||
MSG = 'Use %<style>s for variable names.'
|
||||
|
||||
def on_send(node)
|
||||
variable_definition?(node) do |variable|
|
||||
return if variable.dstr_type? || variable.dsym_type?
|
||||
return if matches_ignored_pattern?(variable.value)
|
||||
|
||||
check_name(node, variable.value, variable.loc.expression)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def message(style)
|
||||
format(MSG, style: style)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -22,7 +22,7 @@ module RuboCop
|
||||
# let(:foo) do
|
||||
# instance_double("ClassName", method_name: 'returned value')
|
||||
# end
|
||||
class VerifiedDoubles < Cop
|
||||
class VerifiedDoubles < Base
|
||||
MSG = 'Prefer using verifying doubles over normal doubles.'
|
||||
|
||||
def_node_matcher :unverified_double, <<-PATTERN
|
||||
@ -11,7 +11,7 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# expect(something).to be(1)
|
||||
class VoidExpect < Cop
|
||||
class VoidExpect < Base
|
||||
MSG = 'Do not use `expect()` without `.to` or `.not_to`. ' \
|
||||
'Chain the methods or remove it.'
|
||||
|
||||
@ -11,7 +11,7 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# expect(foo).to be(:bar).and_yield(1)
|
||||
class Yield < Cop
|
||||
class Yield < Base
|
||||
extend AutoCorrector
|
||||
include RangeHelp
|
||||
|
||||
@ -65,6 +65,7 @@ require_relative 'rspec/message_spies'
|
||||
require_relative 'rspec/missing_example_group_argument'
|
||||
require_relative 'rspec/multiple_describes'
|
||||
require_relative 'rspec/multiple_expectations'
|
||||
require_relative 'rspec/multiple_memoized_helpers'
|
||||
require_relative 'rspec/multiple_subjects'
|
||||
require_relative 'rspec/named_subject'
|
||||
require_relative 'rspec/nested_groups'
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user