diff options
Diffstat (limited to 'spec/rubocop')
18 files changed, 752 insertions, 215 deletions
diff --git a/spec/rubocop/cop/avoid_return_from_blocks_spec.rb b/spec/rubocop/cop/avoid_return_from_blocks_spec.rb index e35705ae791..1b41e140454 100644 --- a/spec/rubocop/cop/avoid_return_from_blocks_spec.rb +++ b/spec/rubocop/cop/avoid_return_from_blocks_spec.rb @@ -41,10 +41,10 @@ RSpec.describe RuboCop::Cop::AvoidReturnFromBlocks do RUBY end - shared_examples 'examples with whitelisted method' do |whitelisted_method| - it "doesn't flag violation for return inside #{whitelisted_method}" do + shared_examples 'examples with allowlisted method' do |allowlisted_method| + it "doesn't flag violation for return inside #{allowlisted_method}" do expect_no_offenses(<<~RUBY) - items.#{whitelisted_method} do |item| + items.#{allowlisted_method} do |item| do_something return if something_else end @@ -52,8 +52,8 @@ RSpec.describe RuboCop::Cop::AvoidReturnFromBlocks do end end - %i[each each_filename times loop].each do |whitelisted_method| - it_behaves_like 'examples with whitelisted method', whitelisted_method + %i[each each_filename times loop].each do |allowlisted_method| + it_behaves_like 'examples with allowlisted method', allowlisted_method end shared_examples 'examples with def methods' do |def_method| diff --git a/spec/rubocop/cop/background_migration/avoid_silent_rescue_exceptions_spec.rb b/spec/rubocop/cop/background_migration/avoid_silent_rescue_exceptions_spec.rb new file mode 100644 index 00000000000..ea4f7d5fca8 --- /dev/null +++ b/spec/rubocop/cop/background_migration/avoid_silent_rescue_exceptions_spec.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +require 'rubocop_spec_helper' +require_relative '../../../../rubocop/cop/background_migration/avoid_silent_rescue_exceptions' + +RSpec.describe RuboCop::Cop::BackgroundMigration::AvoidSilentRescueExceptions, feature_category: :database do + shared_examples 'expecting offense when' do |node| + it 'throws offense when rescuing exceptions without re-raising them' do + %w[Gitlab::BackgroundMigration::BatchedMigrationJob BatchedMigrationJob].each do |base_class| + expect_offense(<<~RUBY) + module Gitlab + module BackgroundMigration + class MyJob < #{base_class} + #{node} + end + end + end + RUBY + end + end + end + + shared_examples 'not expecting offense when' do |node| + it 'does not throw any offense if exception is re-raised' do + %w[Gitlab::BackgroundMigration::BatchedMigrationJob BatchedMigrationJob].each do |base_class| + expect_no_offenses(<<~RUBY) + module Gitlab + module BackgroundMigration + class MyJob < #{base_class} + #{node} + end + end + end + RUBY + end + end + end + + context "when the migration class doesn't inherits from BatchedMigrationJob" do + it 'does not throw any offense' do + expect_no_offenses(<<~RUBY) + module Gitlab + module BackgroundMigration + class MyClass < ::Gitlab::BackgroundMigration::Logger + def my_method + execute + rescue StandardError => error + puts error.message + end + end + end + end + RUBY + end + end + + context 'when the migration class inherits from BatchedMigrationJob' do + context 'when specifying an error class' do + it_behaves_like 'expecting offense when', <<~RUBY + def perform + connection.execute('SELECT 1;') + rescue JSON::ParserError + ^^^^^^^^^^^^^^^^^^^^^^^^ #{described_class::MSG} + logger.error(message: error.message, class: self.class.name) + end + RUBY + + it_behaves_like 'expecting offense when', <<~RUBY + def perform + connection.execute('SELECT 1;') + rescue StandardError, ActiveRecord::StatementTimeout => error + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{described_class::MSG} + logger.error(message: error.message, class: self.class.name) + end + RUBY + + it_behaves_like 'not expecting offense when', <<~RUBY + def perform + connection.execute('SELECT 1;') + rescue StandardError, ActiveRecord::StatementTimeout => error + logger.error(message: error.message, class: self.class.name) + raise error + end + RUBY + end + + context 'without specifying an error class' do + it_behaves_like 'expecting offense when', <<~RUBY + def perform + connection.execute('SELECT 1;') + rescue => error + ^^^^^^ #{described_class::MSG} + logger.error(message: error.message, class: self.class.name) + end + RUBY + + it_behaves_like 'not expecting offense when', <<~RUBY + def perform + connection.execute('SELECT 1;') + rescue => error + logger.error(message: error.message, class: self.class.name) + raise error + end + RUBY + end + end +end diff --git a/spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb b/spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb index 96ff01108c3..4b7ea6b72e5 100644 --- a/spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb +++ b/spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb @@ -48,35 +48,35 @@ RSpec.describe RuboCop::Cop::Gitlab::MarkUsedFeatureFlags do ].each do |feature_flag_method| context "#{feature_flag_method} method" do context 'a string feature flag' do - include_examples 'sets flag as used', %Q|#{feature_flag_method}("foo")|, 'foo' + include_examples 'sets flag as used', %|#{feature_flag_method}("foo")|, 'foo' end context 'a symbol feature flag' do - include_examples 'sets flag as used', %Q|#{feature_flag_method}(:foo)|, 'foo' + include_examples 'sets flag as used', %|#{feature_flag_method}(:foo)|, 'foo' end context 'an interpolated string feature flag with a string prefix' do - include_examples 'sets flag as used', %Q|#{feature_flag_method}("foo_\#{bar}")|, %w[foo_hello foo_world] + include_examples 'sets flag as used', %|#{feature_flag_method}("foo_\#{bar}")|, %w[foo_hello foo_world] end context 'an interpolated symbol feature flag with a string prefix' do - include_examples 'sets flag as used', %Q|#{feature_flag_method}(:"foo_\#{bar}")|, %w[foo_hello foo_world] + include_examples 'sets flag as used', %|#{feature_flag_method}(:"foo_\#{bar}")|, %w[foo_hello foo_world] end context 'a string with a "/" in it' do - include_examples 'sets flag as used', %Q|#{feature_flag_method}("bar/baz")|, 'bar_baz' + include_examples 'sets flag as used', %|#{feature_flag_method}("bar/baz")|, 'bar_baz' end context 'an interpolated string feature flag with a string prefix and suffix' do - include_examples 'does not set any flags as used', %Q|#{feature_flag_method}(:"foo_\#{bar}_baz")| + include_examples 'does not set any flags as used', %|#{feature_flag_method}(:"foo_\#{bar}_baz")| end context 'a dynamic string feature flag as a variable' do - include_examples 'does not set any flags as used', %Q|#{feature_flag_method}(a_variable, an_arg)| + include_examples 'does not set any flags as used', %|#{feature_flag_method}(a_variable, an_arg)| end context 'an integer feature flag' do - include_examples 'does not set any flags as used', %Q|#{feature_flag_method}(123)| + include_examples 'does not set any flags as used', %|#{feature_flag_method}(123)| end end end @@ -87,31 +87,31 @@ RSpec.describe RuboCop::Cop::Gitlab::MarkUsedFeatureFlags do ].each do |feature_flag_method| context "#{feature_flag_method} method" do context 'a string feature flag' do - include_examples 'sets flag as used', %Q|#{feature_flag_method}("foo")|, 'gitaly_foo' + include_examples 'sets flag as used', %|#{feature_flag_method}("foo")|, 'gitaly_foo' end context 'a symbol feature flag' do - include_examples 'sets flag as used', %Q|#{feature_flag_method}(:foo)|, 'gitaly_foo' + include_examples 'sets flag as used', %|#{feature_flag_method}(:foo)|, 'gitaly_foo' end context 'an interpolated string feature flag with a string prefix' do - include_examples 'sets flag as used', %Q|#{feature_flag_method}("foo_\#{bar}")|, %w[foo_hello foo_world] + include_examples 'sets flag as used', %|#{feature_flag_method}("foo_\#{bar}")|, %w[foo_hello foo_world] end context 'an interpolated symbol feature flag with a string prefix' do - include_examples 'sets flag as used', %Q|#{feature_flag_method}(:"foo_\#{bar}")|, %w[foo_hello foo_world] + include_examples 'sets flag as used', %|#{feature_flag_method}(:"foo_\#{bar}")|, %w[foo_hello foo_world] end context 'an interpolated string feature flag with a string prefix and suffix' do - include_examples 'does not set any flags as used', %Q|#{feature_flag_method}(:"foo_\#{bar}_baz")| + include_examples 'does not set any flags as used', %|#{feature_flag_method}(:"foo_\#{bar}_baz")| end context 'a dynamic string feature flag as a variable' do - include_examples 'does not set any flags as used', %Q|#{feature_flag_method}(a_variable, an_arg)| + include_examples 'does not set any flags as used', %|#{feature_flag_method}(a_variable, an_arg)| end context 'an integer feature flag' do - include_examples 'does not set any flags as used', %Q|#{feature_flag_method}(123)| + include_examples 'does not set any flags as used', %|#{feature_flag_method}(123)| end end end @@ -126,15 +126,15 @@ RSpec.describe RuboCop::Cop::Gitlab::MarkUsedFeatureFlags do end context 'an interpolated string feature flag with a string prefix' do - include_examples 'sets flag as used', %Q|experiment("foo_\#{bar}")|, %w[foo_hello foo_world] + include_examples 'sets flag as used', %|experiment("foo_\#{bar}")|, %w[foo_hello foo_world] end context 'an interpolated symbol feature flag with a string prefix' do - include_examples 'sets flag as used', %Q|experiment(:"foo_\#{bar}")|, %w[foo_hello foo_world] + include_examples 'sets flag as used', %|experiment(:"foo_\#{bar}")|, %w[foo_hello foo_world] end context 'an interpolated string feature flag with a string prefix and suffix' do - include_examples 'does not set any flags as used', %Q|experiment(:"foo_\#{bar}_baz")| + include_examples 'does not set any flags as used', %|experiment(:"foo_\#{bar}_baz")| end context 'a dynamic string feature flag as a variable' do @@ -151,31 +151,31 @@ RSpec.describe RuboCop::Cop::Gitlab::MarkUsedFeatureFlags do ].each do |feature_flag_method| context "#{feature_flag_method} method" do context 'a string feature flag' do - include_examples 'sets flag as used', %Q|#{feature_flag_method}(arg, "baz")|, 'baz' + include_examples 'sets flag as used', %|#{feature_flag_method}(arg, "baz")|, 'baz' end context 'a symbol feature flag' do - include_examples 'sets flag as used', %Q|#{feature_flag_method}(arg, :baz)|, 'baz' + include_examples 'sets flag as used', %|#{feature_flag_method}(arg, :baz)|, 'baz' end context 'an interpolated string feature flag with a string prefix' do - include_examples 'sets flag as used', %Q|#{feature_flag_method}(arg, "foo_\#{bar}")|, %w[foo_hello foo_world] + include_examples 'sets flag as used', %|#{feature_flag_method}(arg, "foo_\#{bar}")|, %w[foo_hello foo_world] end context 'an interpolated symbol feature flag with a string prefix' do - include_examples 'sets flag as used', %Q|#{feature_flag_method}(arg, :"foo_\#{bar}")|, %w[foo_hello foo_world] + include_examples 'sets flag as used', %|#{feature_flag_method}(arg, :"foo_\#{bar}")|, %w[foo_hello foo_world] end context 'an interpolated string feature flag with a string prefix and suffix' do - include_examples 'does not set any flags as used', %Q|#{feature_flag_method}(arg, :"foo_\#{bar}_baz")| + include_examples 'does not set any flags as used', %|#{feature_flag_method}(arg, :"foo_\#{bar}_baz")| end context 'a dynamic string feature flag as a variable' do - include_examples 'does not set any flags as used', %Q|#{feature_flag_method}(a_variable, an_arg)| + include_examples 'does not set any flags as used', %|#{feature_flag_method}(a_variable, an_arg)| end context 'an integer feature flag' do - include_examples 'does not set any flags as used', %Q|#{feature_flag_method}(arg, 123)| + include_examples 'does not set any flags as used', %|#{feature_flag_method}(arg, 123)| end end end diff --git a/spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb b/spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb index fde53f8f98c..75455a390f4 100644 --- a/spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb +++ b/spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb @@ -100,4 +100,42 @@ RSpec.describe RuboCop::Cop::Gitlab::StrongMemoizeAttr do RUBY end end + + context 'when strong_memoize_with() is called without parameters' do + it 'registers an offense and autocorrects' do + expect_offense(<<~RUBY) + class Foo + def memoized_method + strong_memoize_with(:memoized_method) do + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `strong_memoize_attr`, instead of using `strong_memoize_with` without parameters. + 'This is a memoized method' + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo + def memoized_method + 'This is a memoized method' + end + strong_memoize_attr :memoized_method + end + RUBY + end + end + + context 'when strong_memoize_with() is called with parameters' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + class Foo + def memoized_method(param) + strong_memoize_with(:memoized_method, param) do + param.to_s + end + end + end + RUBY + end + end end diff --git a/spec/rubocop/cop/graphql/gid_expected_type_spec.rb b/spec/rubocop/cop/graphql/gid_expected_type_spec.rb deleted file mode 100644 index 563c16a99df..00000000000 --- a/spec/rubocop/cop/graphql/gid_expected_type_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -require 'rubocop_spec_helper' - -require_relative '../../../../rubocop/cop/graphql/gid_expected_type' - -RSpec.describe RuboCop::Cop::Graphql::GIDExpectedType do - it 'adds an offense when there is no expected_type parameter' do - expect_offense(<<~TYPE) - GitlabSchema.object_from_id(received_id) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Add an expected_type parameter to #object_from_id calls if possible. - TYPE - end - - it 'does not add an offense for calls that have an expected_type parameter' do - expect_no_offenses(<<~TYPE.strip) - GitlabSchema.object_from_id("some_id", expected_type: SomeClass) - TYPE - end -end diff --git a/spec/rubocop/cop/graphql/id_type_spec.rb b/spec/rubocop/cop/graphql/id_type_spec.rb index 3a56753d39e..6eb4890c064 100644 --- a/spec/rubocop/cop/graphql/id_type_spec.rb +++ b/spec/rubocop/cop/graphql/id_type_spec.rb @@ -12,8 +12,8 @@ RSpec.describe RuboCop::Cop::Graphql::IDType do TYPE end - context 'whitelisted arguments' do - RuboCop::Cop::Graphql::IDType::WHITELISTED_ARGUMENTS.each do |arg| + context 'allowlisted arguments' do + RuboCop::Cop::Graphql::IDType::ALLOWLISTED_ARGUMENTS.each do |arg| it "does not add an offense for calls to #argument with #{arg} as argument name" do expect_no_offenses(<<~TYPE.strip) argument #{arg}, GraphQL::Types::ID, some: other, params: do_not_matter diff --git a/spec/rubocop/cop/ignored_columns_spec.rb b/spec/rubocop/cop/ignored_columns_spec.rb index 8d2c6b92c70..c8f47f8aee9 100644 --- a/spec/rubocop/cop/ignored_columns_spec.rb +++ b/spec/rubocop/cop/ignored_columns_spec.rb @@ -4,20 +4,20 @@ require 'rubocop_spec_helper' require_relative '../../../rubocop/cop/ignored_columns' RSpec.describe RuboCop::Cop::IgnoredColumns, feature_category: :database do - it 'flags use of `self.ignored_columns +=` instead of the IgnoredColumns concern' do + it 'flags use of `self.ignored_columns +=` instead of the IgnorableColumns concern' do expect_offense(<<~RUBY) class Foo < ApplicationRecord self.ignored_columns += %i[id] - ^^^^^^^^^^^^^^^ Use `IgnoredColumns` concern instead of adding to `self.ignored_columns`. + ^^^^^^^^^^^^^^^ Use `IgnorableColumns` concern instead of adding to `self.ignored_columns`. end RUBY end - it 'flags use of `self.ignored_columns =` instead of the IgnoredColumns concern' do + it 'flags use of `self.ignored_columns =` instead of the IgnorableColumns concern' do expect_offense(<<~RUBY) class Foo < ApplicationRecord self.ignored_columns = %i[id] - ^^^^^^^^^^^^^^^ Use `IgnoredColumns` concern instead of setting `self.ignored_columns`. + ^^^^^^^^^^^^^^^ Use `IgnorableColumns` concern instead of setting `self.ignored_columns`. end RUBY end diff --git a/spec/rubocop/cop/migration/avoid_finalize_background_migration_spec.rb b/spec/rubocop/cop/migration/avoid_finalize_background_migration_spec.rb new file mode 100644 index 00000000000..e4eec39e3ff --- /dev/null +++ b/spec/rubocop/cop/migration/avoid_finalize_background_migration_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'rubocop_spec_helper' +require_relative '../../../../rubocop/cop/migration/avoid_finalize_background_migration' + +RSpec.describe RuboCop::Cop::Migration::AvoidFinalizeBackgroundMigration, feature_category: :database do + context 'when file is under db/post_migration' do + it "flags the use of 'finalize_background_migration' method" do + expect_offense(<<~RUBY) + class FinalizeMyMigration < Gitlab::Database::Migration[2.1] + MIGRATION = 'MyMigration' + + def up + finalize_background_migration(MIGRATION) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{described_class::MSG} + end + end + RUBY + end + end +end diff --git a/spec/rubocop/cop/qa/element_with_pattern_spec.rb b/spec/rubocop/cop/qa/element_with_pattern_spec.rb index 1febdaf9c3b..ccc03d7f5ae 100644 --- a/spec/rubocop/cop/qa/element_with_pattern_spec.rb +++ b/spec/rubocop/cop/qa/element_with_pattern_spec.rb @@ -40,7 +40,7 @@ RSpec.describe RuboCop::Cop::QA::ElementWithPattern do end end - context 'outside of a migration spec file' do + context 'when outside of a QA spec file' do it "does not register an offense" do expect_no_offenses(<<-RUBY) describe 'foo' do diff --git a/spec/rubocop/cop/rake/require_spec.rb b/spec/rubocop/cop/rake/require_spec.rb index bb8c6a1f063..de484643d6e 100644 --- a/spec/rubocop/cop/rake/require_spec.rb +++ b/spec/rubocop/cop/rake/require_spec.rb @@ -7,54 +7,84 @@ require_relative '../../../../rubocop/cop/rake/require' RSpec.describe RuboCop::Cop::Rake::Require do let(:msg) { described_class::MSG } - it 'registers an offenses for require methods' do - expect_offense(<<~RUBY) - require 'json' - ^^^^^^^^^^^^^^ #{msg} - require_relative 'gitlab/json' - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} - RUBY + describe '#in_rake_file?' do + context 'in a Rake file' do + let(:node) { double(location: double(expression: double(source_buffer: double(name: 'foo/bar.rake')))) } # rubocop:disable RSpec/VerifiedDoubles + + it { expect(subject.__send__(:in_rake_file?, node)).to be(true) } + end + + context 'when outside of a Rake file' do + let(:node) { double(location: double(expression: double(source_buffer: double(name: 'foo/bar.rb')))) } # rubocop:disable RSpec/VerifiedDoubles + + it { expect(subject.__send__(:in_rake_file?, node)).to be(false) } + end end - it 'does not register offense inside `task` definition' do - expect_no_offenses(<<~RUBY) - task :parse do + context 'in a Rake file' do + before do + allow(cop).to receive(:in_rake_file?).and_return(true) + end + + it 'registers an offenses for require methods' do + expect_offense(<<~RUBY) require 'json' - end + ^^^^^^^^^^^^^^ #{msg} + require_relative 'gitlab/json' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} + RUBY + end - namespace :some do - task parse: :env do - require_relative 'gitlab/json' + it 'does not register offense inside `task` definition' do + expect_no_offenses(<<~RUBY) + task :parse do + require 'json' end - end - RUBY - end - it 'does not register offense inside a block definition' do - expect_no_offenses(<<~RUBY) - RSpec::Core::RakeTask.new(:parse_json) do |t, args| - require 'json' - end - RUBY - end + namespace :some do + task parse: :env do + require_relative 'gitlab/json' + end + end + RUBY + end - it 'does not register offense inside a method definition' do - expect_no_offenses(<<~RUBY) - def load_deps - require 'json' - end + it 'does not register offense inside a block definition' do + expect_no_offenses(<<~RUBY) + RSpec::Core::RakeTask.new(:parse_json) do |t, args| + require 'json' + end + RUBY + end + + it 'does not register offense inside a method definition' do + expect_no_offenses(<<~RUBY) + def load_deps + require 'json' + end - task :parse do - load_deps - end - RUBY + task :parse do + load_deps + end + RUBY + end + + it 'does not register offense when require task related files' do + expect_no_offenses(<<~RUBY) + require 'rubocop/rake_tasks' + require 'gettext_i18n_rails/tasks' + require_relative '../../rubocop/check_graceful_task' + RUBY + end end - it 'does not register offense when require task related files' do - expect_no_offenses(<<~RUBY) - require 'rubocop/rake_tasks' - require 'gettext_i18n_rails/tasks' - require_relative '../../rubocop/check_graceful_task' - RUBY + context 'when outside of a Rake file' do + before do + allow(cop).to receive(:in_rake_file?).and_return(false) + end + + it 'registers an offenses for require methods' do + expect_no_offenses("require 'json'") + end end end diff --git a/spec/rubocop/cop/rspec/before_all_role_assignment_spec.rb b/spec/rubocop/cop/rspec/before_all_role_assignment_spec.rb new file mode 100644 index 00000000000..f8a9a6e22c4 --- /dev/null +++ b/spec/rubocop/cop/rspec/before_all_role_assignment_spec.rb @@ -0,0 +1,234 @@ +# frozen_string_literal: true + +require 'rubocop_spec_helper' +require 'rspec-parameterized' +require_relative '../../../../rubocop/cop/rspec/before_all_role_assignment' + +RSpec.describe Rubocop::Cop::RSpec::BeforeAllRoleAssignment, :rubocop_rspec, feature_category: :tooling do + context 'with `let`' do + context 'and `before_all`' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + context 'with something' do + let(:project) { create(:project) } + let(:guest) { create(:user) } + + before_all do + project.add_guest(guest) + end + end + RUBY + end + end + + context 'and `before`' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + context 'with something' do + let(:project) { create(:project) } + let(:guest) { create(:user) } + + before do + project.add_guest(guest) + end + end + RUBY + end + end + end + + shared_examples '`let_it_be` definitions' do |let_it_be| + context 'and `before_all`' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + context 'with something' do + #{let_it_be}(:project) { create(:project) } + #{let_it_be}(:guest) { create(:user) } + + before_all do + project.add_guest(guest) + end + end + RUBY + end + end + + context 'and `before`' do + context 'and without role methods' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + context 'with something' do + #{let_it_be}(:project) { create(:project) } + #{let_it_be}(:guest) { create(:user) } + + before do + project.add_details(guest) + end + end + RUBY + end + end + + context 'and role methods' do + where(:role_method) { described_class::ROLE_METHODS.to_a } + + with_them do + it 'registers an offense' do + expect_offense(<<~RUBY, role_method: role_method) + context 'with something' do + #{let_it_be}(:project) { create(:project) } + #{let_it_be}(:guest) { create(:user) } + + before do + project.%{role_method}(guest) + ^^^^^^^^^{role_method}^^^^^^^ Use `before_all` when used with `#{let_it_be}`. + end + end + RUBY + end + end + end + + context 'without nested contexts' do + it 'registers an offense' do + expect_offense(<<~RUBY) + context 'with something' do + #{let_it_be}(:project) { create(:project) } + #{let_it_be}(:guest) { create(:user) } + + before do + project.add_guest(guest) + ^^^^^^^^^^^^^^^^^^^^^^^^ Use `before_all` when used with `#{let_it_be}`. + end + end + RUBY + end + end + + context 'with nested contexts' do + it 'registers an offense' do + expect_offense(<<~RUBY) + context 'when first context' do + #{let_it_be}(:guest) { create(:user) } + + context 'when second context' do + #{let_it_be}(:project) { create(:project) } + + context 'when third context' do + before do + project.add_guest(guest) + ^^^^^^^^^^^^^^^^^^^^^^^^ Use `before_all` when used with `#{let_it_be}`. + end + end + end + end + RUBY + end + end + + describe 'edge cases' do + context 'with unrelated `let_it_be` definition' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + context 'with something' do + let(:project) { create(:project) } + #{let_it_be}(:user) { create(:user) } + + before do + project.add_guest(guest) + end + end + RUBY + end + end + + context 'with many role method calls' do + it 'registers an offense' do + expect_offense(<<~RUBY) + context 'with something' do + let(:project) { create(:project) } + #{let_it_be}(:other_project) { create(:user) } + + before do + project.add_guest(guest) + other_project.add_guest(guest) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `before_all` when used with `#{let_it_be}`. + end + end + RUBY + end + end + + context 'with alternative example groups' do + it 'registers an offense' do + expect_offense(<<~RUBY) + describe 'with something' do + #{let_it_be}(:project) { create(:user) } + + before do + project.add_guest(guest) + ^^^^^^^^^^^^^^^^^^^^^^^^ Use `before_all` when used with `#{let_it_be}`. + end + end + + it_behaves_like 'with something' do + #{let_it_be}(:project) { create(:user) } + + before do + project.add_guest(guest) + ^^^^^^^^^^^^^^^^^^^^^^^^ Use `before_all` when used with `#{let_it_be}`. + end + end + + include_examples 'with something' do + #{let_it_be}(:project) { create(:user) } + + before do + project.add_guest(guest) + ^^^^^^^^^^^^^^^^^^^^^^^^ Use `before_all` when used with `#{let_it_be}`. + end + end + RUBY + end + end + + context 'with `let_it_be` outside of the ancestors chain' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + context 'when in main context' do + let(:project) { create(:user) } + + before do + project.add_guest(guest) + end + + context 'when in a separate context' do + #{let_it_be}(:project) { create(:user) } + + before do + project + end + end + end + RUBY + end + end + end + end + end + + context 'with `let_it_be` variants' do + before do + other_cops.tap do |config| + config.dig('RSpec', 'Language', 'Helpers') + .push('let_it_be', 'let_it_be_with_reload', 'let_it_be_with_refind') + end + end + + where(:let_it_be) { %i[let_it_be let_it_be_with_reload let_it_be_with_refind] } + + with_them do + include_examples '`let_it_be` definitions', params[:let_it_be] + end + end +end diff --git a/spec/rubocop/cop/search/avoid_checking_finished_on_deprecated_migrations_spec.rb b/spec/rubocop/cop/search/avoid_checking_finished_on_deprecated_migrations_spec.rb new file mode 100644 index 00000000000..9853423e758 --- /dev/null +++ b/spec/rubocop/cop/search/avoid_checking_finished_on_deprecated_migrations_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'rubocop_spec_helper' +require_relative '../../../../rubocop/cop/search/avoid_checking_finished_on_deprecated_migrations' + +RSpec.describe RuboCop::Cop::Search::AvoidCheckingFinishedOnDeprecatedMigrations, feature_category: :global_search do + context 'when a deprecated class is used with migration_has_finished?' do + it 'flags it as an offense' do + expect_offense <<~SOURCE + return if Elastic::DataMigrationService.migration_has_finished?(:backfill_project_permissions_in_blobs_using_permutations) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Migration is deprecated and can not be used with `migration_has_finished?`. + SOURCE + end + end + + context 'when a non deprecated class is used with migration_has_finished?' do + it 'does not flag it as an offense' do + expect_no_offenses <<~SOURCE + return if Elastic::DataMigrationService.migration_has_finished?(:backfill_project_permissions_in_blobs) + SOURCE + end + end + + context 'when migration_has_finished? method is called on another class' do + it 'does not flag it as an offense' do + expect_no_offenses <<~SOURCE + return if Klass.migration_has_finished?(:backfill_project_permissions_in_blobs_using_permutations) + SOURCE + end + end +end diff --git a/spec/rubocop/cop/usage_data/distinct_count_by_large_foreign_key_spec.rb b/spec/rubocop/cop/usage_data/distinct_count_by_large_foreign_key_spec.rb index b4d113a9bcc..53bf5de6243 100644 --- a/spec/rubocop/cop/usage_data/distinct_count_by_large_foreign_key_spec.rb +++ b/spec/rubocop/cop/usage_data/distinct_count_by_large_foreign_key_spec.rb @@ -13,33 +13,45 @@ RSpec.describe RuboCop::Cop::UsageData::DistinctCountByLargeForeignKey do }) end - context 'when counting by disallowed key' do - it 'registers an offense' do - expect_offense(<<~CODE) - distinct_count(Issue, :creator_id) - ^^^^^^^^^^^^^^ #{msg} - CODE + context 'in an usage data file' do + before do + allow(cop).to receive(:in_usage_data_file?).and_return(true) end - it 'does not register an offense when batch is false' do - expect_no_offenses('distinct_count(Issue, :creator_id, batch: false)') + context 'when counting by disallowed key' do + it 'registers an offense' do + expect_offense(<<~CODE) + distinct_count(Issue, :creator_id) + ^^^^^^^^^^^^^^ #{msg} + CODE + end + + it 'does not register an offense when batch is false' do + expect_no_offenses('distinct_count(Issue, :creator_id, batch: false)') + end + + it 'registers an offense when batch is true' do + expect_offense(<<~CODE) + distinct_count(Issue, :creator_id, batch: true) + ^^^^^^^^^^^^^^ #{msg} + CODE + end end - it 'registers an offense when batch is true' do - expect_offense(<<~CODE) - distinct_count(Issue, :creator_id, batch: true) - ^^^^^^^^^^^^^^ #{msg} - CODE - end - end + context 'when calling by allowed key' do + it 'does not register an offense with symbol' do + expect_no_offenses('distinct_count(Issue, :author_id)') + end - context 'when calling by allowed key' do - it 'does not register an offense with symbol' do - expect_no_offenses('distinct_count(Issue, :author_id)') + it 'does not register an offense with string' do + expect_no_offenses("distinct_count(Issue, 'merge_requests.target_project_id')") + end end + end - it 'does not register an offense with string' do - expect_no_offenses("distinct_count(Issue, 'merge_requests.target_project_id')") + context 'when outside of an usage data file' do + it 'does not register an offense' do + expect_no_offenses('distinct_count(Issue, :creator_id)') end end end diff --git a/spec/rubocop/cop/usage_data/histogram_with_large_table_spec.rb b/spec/rubocop/cop/usage_data/histogram_with_large_table_spec.rb index efa4e27dc9c..0de14310e13 100644 --- a/spec/rubocop/cop/usage_data/histogram_with_large_table_spec.rb +++ b/spec/rubocop/cop/usage_data/histogram_with_large_table_spec.rb @@ -14,93 +14,105 @@ RSpec.describe RuboCop::Cop::UsageData::HistogramWithLargeTable do }) end - context 'with large tables' do - context 'with one-level constants' do - context 'when calling histogram(Issue)' do - it 'registers an offense' do - expect_offense(<<~CODE) - histogram(Issue, :project_id, buckets: 1..100) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} Issue - CODE + context 'in an usage data file' do + before do + allow(cop).to receive(:in_usage_data_file?).and_return(true) + end + + context 'with large tables' do + context 'with one-level constants' do + context 'when calling histogram(Issue)' do + it 'registers an offense' do + expect_offense(<<~CODE) + histogram(Issue, :project_id, buckets: 1..100) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} Issue + CODE + end end - end - context 'when calling histogram(::Issue)' do - it 'registers an offense' do - expect_offense(<<~CODE) - histogram(::Issue, :project_id, buckets: 1..100) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} Issue - CODE + context 'when calling histogram(::Issue)' do + it 'registers an offense' do + expect_offense(<<~CODE) + histogram(::Issue, :project_id, buckets: 1..100) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} Issue + CODE + end end - end - context 'when calling histogram(Issue.closed)' do - it 'registers an offense' do - expect_offense(<<~CODE) - histogram(Issue.closed, :project_id, buckets: 1..100) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} Issue - CODE + context 'when calling histogram(Issue.closed)' do + it 'registers an offense' do + expect_offense(<<~CODE) + histogram(Issue.closed, :project_id, buckets: 1..100) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} Issue + CODE + end end - end - context 'when calling histogram(::Issue.closed)' do - it 'registers an offense' do - expect_offense(<<~CODE) - histogram(::Issue.closed, :project_id, buckets: 1..100) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} Issue - CODE + context 'when calling histogram(::Issue.closed)' do + it 'registers an offense' do + expect_offense(<<~CODE) + histogram(::Issue.closed, :project_id, buckets: 1..100) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} Issue + CODE + end end end - end - context 'with two-level constants' do - context 'when calling histogram(::Ci::Build)' do - it 'registers an offense' do - expect_offense(<<~CODE) - histogram(::Ci::Build, buckets: 1..100) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} Ci::Build - CODE + context 'with two-level constants' do + context 'when calling histogram(::Ci::Build)' do + it 'registers an offense' do + expect_offense(<<~CODE) + histogram(::Ci::Build, buckets: 1..100) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} Ci::Build + CODE + end end - end - context 'when calling histogram(::Ci::Build.active)' do - it 'registers an offense' do - expect_offense(<<~CODE) - histogram(::Ci::Build.active, buckets: 1..100) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} Ci::Build - CODE + context 'when calling histogram(::Ci::Build.active)' do + it 'registers an offense' do + expect_offense(<<~CODE) + histogram(::Ci::Build.active, buckets: 1..100) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} Ci::Build + CODE + end end - end - context 'when calling histogram(Ci::Build)' do - it 'registers an offense' do - expect_offense(<<~CODE) - histogram(Ci::Build, buckets: 1..100) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} Ci::Build - CODE + context 'when calling histogram(Ci::Build)' do + it 'registers an offense' do + expect_offense(<<~CODE) + histogram(Ci::Build, buckets: 1..100) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} Ci::Build + CODE + end end - end - context 'when calling histogram(Ci::Build.active)' do - it 'registers an offense' do - expect_offense(<<~CODE) - histogram(Ci::Build.active, buckets: 1..100) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} Ci::Build - CODE + context 'when calling histogram(Ci::Build.active)' do + it 'registers an offense' do + expect_offense(<<~CODE) + histogram(Ci::Build.active, buckets: 1..100) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} Ci::Build + CODE + end end end end - end - context 'with non related class' do - it 'does not register an offense' do - expect_no_offenses('histogram(MergeRequest, buckets: 1..100)') + context 'with non related class' do + it 'does not register an offense' do + expect_no_offenses('histogram(MergeRequest, buckets: 1..100)') + end + end + + context 'with non related method' do + it 'does not register an offense' do + expect_no_offenses('count(Issue, buckets: 1..100)') + end end end - context 'with non related method' do + context 'when outside of an usage data file' do it 'does not register an offense' do - expect_no_offenses('count(Issue, buckets: 1..100)') + expect_no_offenses('histogram(Issue, :project_id, buckets: 1..100)') end end end diff --git a/spec/rubocop/cop/usage_data/instrumentation_superclass_spec.rb b/spec/rubocop/cop/usage_data/instrumentation_superclass_spec.rb index a55f0852f35..f208a5451cb 100644 --- a/spec/rubocop/cop/usage_data/instrumentation_superclass_spec.rb +++ b/spec/rubocop/cop/usage_data/instrumentation_superclass_spec.rb @@ -14,49 +14,63 @@ RSpec.describe RuboCop::Cop::UsageData::InstrumentationSuperclass do }) end - context 'with class definition' do - context 'when inheriting from allowed superclass' do - it 'does not register an offense' do - expect_no_offenses('class NewMetric < GenericMetric; end') - end + context 'when in an instrumentation file' do + before do + allow(cop).to receive(:in_instrumentation_file?).and_return(true) end - context 'when inheriting from some other superclass' do - it 'registers an offense' do - expect_offense(<<~CODE) - class NewMetric < BaseMetric; end - ^^^^^^^^^^ #{msg} - CODE + context 'with class definition' do + context 'when inheriting from allowed superclass' do + it 'does not register an offense' do + expect_no_offenses('class NewMetric < GenericMetric; end') + end end - end - context 'when not inheriting' do - it 'does not register an offense' do - expect_no_offenses('class NewMetric; end') + context 'when inheriting from some other superclass' do + it 'registers an offense' do + expect_offense(<<~CODE) + class NewMetric < BaseMetric; end + ^^^^^^^^^^ #{msg} + CODE + end end - end - end - context 'with dynamic class definition' do - context 'when inheriting from allowed superclass' do - it 'does not register an offense' do - expect_no_offenses('NewMetric = Class.new(GenericMetric)') + context 'when not inheriting' do + it 'does not register an offense' do + expect_no_offenses('class NewMetric; end') + end end end - context 'when inheriting from some other superclass' do - it 'registers an offense' do - expect_offense(<<~CODE) - NewMetric = Class.new(BaseMetric) - ^^^^^^^^^^ #{msg} - CODE + context 'with dynamic class definition' do + context 'when inheriting from allowed superclass' do + it 'does not register an offense' do + expect_no_offenses('NewMetric = Class.new(GenericMetric)') + end end - end - context 'when not inheriting' do - it 'does not register an offense' do - expect_no_offenses('NewMetric = Class.new') + context 'when inheriting from some other superclass' do + it 'registers an offense' do + expect_offense(<<~CODE) + NewMetric = Class.new(BaseMetric) + ^^^^^^^^^^ #{msg} + CODE + end end + + context 'when not inheriting' do + it 'does not register an offense' do + expect_no_offenses('NewMetric = Class.new') + end + end + end + end + + context 'when outside of an instrumentation file' do + it "does not register an offense" do + expect_no_offenses(<<-RUBY) + class NewMetric < BaseMetric; end + RUBY end end end diff --git a/spec/rubocop/cop/usage_data/large_table_spec.rb b/spec/rubocop/cop/usage_data/large_table_spec.rb index fa94f878cea..ceeb1143690 100644 --- a/spec/rubocop/cop/usage_data/large_table_spec.rb +++ b/spec/rubocop/cop/usage_data/large_table_spec.rb @@ -18,9 +18,9 @@ RSpec.describe RuboCop::Cop::UsageData::LargeTable do }) end - context 'when in usage_data files' do + context 'in an usage data file' do before do - allow(cop).to receive(:usage_data_files?).and_return(true) + allow(cop).to receive(:in_usage_data_file?).and_return(true) end context 'with large tables' do @@ -76,4 +76,10 @@ RSpec.describe RuboCop::Cop::UsageData::LargeTable do end end end + + context 'when outside of an usage data file' do + it 'does not register an offense' do + expect_no_offenses('Issue.active.count') + end + end end diff --git a/spec/rubocop/cop_todo_spec.rb b/spec/rubocop/cop_todo_spec.rb index c641001789f..49206d76d5a 100644 --- a/spec/rubocop/cop_todo_spec.rb +++ b/spec/rubocop/cop_todo_spec.rb @@ -3,7 +3,7 @@ require 'rubocop_spec_helper' require_relative '../../rubocop/cop_todo' -RSpec.describe RuboCop::CopTodo do +RSpec.describe RuboCop::CopTodo, feature_category: :tooling do let(:cop_name) { 'Cop/Rule' } subject(:cop_todo) { described_class.new(cop_name) } @@ -32,6 +32,19 @@ RSpec.describe RuboCop::CopTodo do end end + describe '#add_files' do + it 'adds files' do + cop_todo.add_files(%w[a.rb b.rb]) + cop_todo.add_files(%w[a.rb]) + cop_todo.add_files(%w[]) + + expect(cop_todo).to have_attributes( + files: contain_exactly('a.rb', 'b.rb'), + offense_count: 0 + ) + end + end + describe '#autocorrectable?' do subject { cop_todo.autocorrectable? } diff --git a/spec/rubocop/formatter/todo_formatter_spec.rb b/spec/rubocop/formatter/todo_formatter_spec.rb index 5494d518605..55a64198289 100644 --- a/spec/rubocop/formatter/todo_formatter_spec.rb +++ b/spec/rubocop/formatter/todo_formatter_spec.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # rubocop:disable RSpec/VerifiedDoubles require 'fast_spec_helper' @@ -10,7 +11,7 @@ require 'tmpdir' require_relative '../../../rubocop/formatter/todo_formatter' require_relative '../../../rubocop/todo_dir' -RSpec.describe RuboCop::Formatter::TodoFormatter do +RSpec.describe RuboCop::Formatter::TodoFormatter, feature_category: :tooling do let(:stdout) { StringIO.new } let(:tmp_dir) { Dir.mktmpdir } let(:real_tmp_dir) { File.join(tmp_dir, 'real') } @@ -97,6 +98,40 @@ RSpec.describe RuboCop::Formatter::TodoFormatter do YAML end + context 'with existing HAML exclusions' do + before do + todo_dir.write('B/TooManyOffenses', <<~YAML) + --- + B/TooManyOffenses: + Exclude: + - 'd.rb' + - 'app/views/project.html.haml.rb' + - 'app/views/project.haml.rb' + - 'app/views/project.text.haml.rb' + - 'app/views/unrelated.html.haml.rb.ext' + - 'app/views/unrelated.html.haml.ext' + - 'app/views/unrelated.html.haml' + YAML + + todo_dir.inspect_all + end + + it 'does not remove them' do + run_formatter + + expect(todo_yml('B/TooManyOffenses')).to eq(<<~YAML) + --- + B/TooManyOffenses: + Exclude: + - 'a.rb' + - 'app/views/project.haml.rb' + - 'app/views/project.html.haml.rb' + - 'app/views/project.text.haml.rb' + - 'c.rb' + YAML + end + end + context 'when cop previously not explicitly disabled' do before do todo_dir.write('B/TooManyOffenses', <<~YAML) @@ -105,6 +140,8 @@ RSpec.describe RuboCop::Formatter::TodoFormatter do Exclude: - 'x.rb' YAML + + todo_dir.inspect_all end it 'does not disable cop' do @@ -158,6 +195,8 @@ RSpec.describe RuboCop::Formatter::TodoFormatter do Exclude: - 'x.rb' YAML + + todo_dir.inspect_all end it 'keeps cop disabled' do |