diff options
Diffstat (limited to 'spec/rubocop/cop')
11 files changed, 449 insertions, 30 deletions
diff --git a/spec/rubocop/cop/gitlab/duplicate_spec_location_spec.rb b/spec/rubocop/cop/gitlab/duplicate_spec_location_spec.rb index 9a1639806c8..0a121a495c9 100644 --- a/spec/rubocop/cop/gitlab/duplicate_spec_location_spec.rb +++ b/spec/rubocop/cop/gitlab/duplicate_spec_location_spec.rb @@ -4,7 +4,7 @@ require 'rubocop_spec_helper' require_relative '../../../../rubocop/cop/gitlab/duplicate_spec_location' -RSpec.describe RuboCop::Cop::Gitlab::DuplicateSpecLocation do +RSpec.describe RuboCop::Cop::Gitlab::DuplicateSpecLocation, type: :rubocop_rspec do let(:rails_root) { '../../../../' } def full_path(path) 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 ac7e41dda44..a3c9ae8916e 100644 --- a/spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb +++ b/spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb @@ -7,7 +7,7 @@ require_relative '../../../../rubocop/cop/gitlab/mark_used_feature_flags' RSpec.describe RuboCop::Cop::Gitlab::MarkUsedFeatureFlags do let(:defined_feature_flags) do - %w[a_feature_flag foo_hello foo_world baz_experiment_percentage bar_baz] + %w[a_feature_flag foo_hello foo_world bar_baz baz] end before do @@ -118,40 +118,33 @@ RSpec.describe RuboCop::Cop::Gitlab::MarkUsedFeatureFlags do end end - %w[ - experiment - experiment_enabled? - push_frontend_experiment - Gitlab::Experimentation.active? - ].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}("baz")|, %w[baz baz_experiment_percentage] - end + context 'with the experiment method' do + context 'a string feature flag' do + include_examples 'sets flag as used', %q|experiment("baz")|, %w[baz] + end - context 'a symbol feature flag' do - include_examples 'sets flag as used', %Q|#{feature_flag_method}(:baz)|, %w[baz baz_experiment_percentage] - end + context 'a symbol feature flag' do + include_examples 'sets flag as used', %q|experiment(:baz)|, %w[baz] + 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] - 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] + 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] - 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] + 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")| - 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")| + 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)| - end + context 'a dynamic string feature flag as a variable' do + include_examples 'does not set any flags as used', %q|experiment(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)| - end + context 'an integer feature flag' do + include_examples 'does not set any flags as used', %q|experiment(123)| end end diff --git a/spec/rubocop/cop/gitlab/no_code_coverage_comment_spec.rb b/spec/rubocop/cop/gitlab/no_code_coverage_comment_spec.rb new file mode 100644 index 00000000000..f0c0297d266 --- /dev/null +++ b/spec/rubocop/cop/gitlab/no_code_coverage_comment_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'rubocop_spec_helper' +require_relative '../../../../rubocop/cop/gitlab/no_code_coverage_comment' + +RSpec.describe RuboCop::Cop::Gitlab::NoCodeCoverageComment do + let(:msg) { format(described_class::MSG, nocov_comment: nocov_comment) } + let(:nocov_comment) { ":#{comment_token}:" } + + shared_examples 'nocov check' do + it 'flags related code comments' do + expect_offense(<<~RUBY, nocov_token: comment_token, msg: msg) + # :%{nocov_token}: + ^^^{nocov_token} %{msg} + def method + end + #:%{nocov_token}: + ^^^{nocov_token} %{msg} + + def other_method + if expr + # :%{nocov_token}: With some additional comments + ^^^{nocov_token} %{msg} + value << line.strip + # :%{nocov_token}: + ^^^{nocov_token} %{msg} + end + end + RUBY + end + + it 'ignores unrelated comments' do + expect_no_offenses(<<~RUBY) + # Other comments are ignored :#{comment_token}: + # + # # :#{comment_token}: + RUBY + end + end + + context 'with nocov as default comment token' do + it_behaves_like 'nocov check' do + let(:comment_token) { described_class::DEFAULT_COMMENT_TOKEN } + end + end + + context 'with configured comment token' do + it_behaves_like 'nocov check' do + let(:comment_token) { 'skipit' } + + let(:config) do + RuboCop::Config.new( + 'Gitlab/NoCodeCoverageComment' => { + 'CommentToken' => comment_token + } + ) + end + end + end +end diff --git a/spec/rubocop/cop/gitlab/service_response_spec.rb b/spec/rubocop/cop/gitlab/service_response_spec.rb new file mode 100644 index 00000000000..84cf0dbff52 --- /dev/null +++ b/spec/rubocop/cop/gitlab/service_response_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require 'rubocop_spec_helper' +require_relative '../../../../rubocop/cop/gitlab/service_response' + +RSpec.describe RuboCop::Cop::Gitlab::ServiceResponse do + subject(:cop) { described_class.new } + + it 'does not flag the `http_status:` param on a homonym method' do + expect_no_offenses("MyClass.error(http_status: :ok)") + end + + it 'does not flag calls without params' do + expect_no_offenses('ServiceResponse.error') + end + + it 'does not flag the offense when `http_status` is not used' do + expect_no_offenses('ServiceResponse.error(message: "some error", reason: :bad_time)') + end + + it 'flags the use of `http_status:` parameter in ServiceResponse in error' do + expect_offense(<<~CODE, msg: described_class::MSG) + ServiceResponse.error(message: "some error", http_status: :bad_request) + ^^^^^^^^^^^^^^^^^^^^^^^^^ %{msg} + CODE + end + + it 'flags the use of `http_status:` parameter in ServiceResponse in success' do + expect_offense(<<~CODE, msg: described_class::MSG) + ServiceResponse.success(message: "some error", http_status: :bad_request) + ^^^^^^^^^^^^^^^^^^^^^^^^^ %{msg} + CODE + end + + it 'flags the use of `http_status:` parameter in ServiceResponse in initializer' do + expect_offense(<<~CODE, msg: described_class::MSG) + ServiceResponse.new(message: "some error", http_status: :bad_request) + ^^^^^^^^^^^^^^^^^^^^^^^^^ %{msg} + CODE + end +end diff --git a/spec/rubocop/cop/migration/background_migration_missing_active_concern_spec.rb b/spec/rubocop/cop/migration/background_migration_missing_active_concern_spec.rb new file mode 100644 index 00000000000..c74a7d29056 --- /dev/null +++ b/spec/rubocop/cop/migration/background_migration_missing_active_concern_spec.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +require 'rubocop_spec_helper' +require_relative '../../../../rubocop/cop/migration/background_migration_missing_active_concern' + +RSpec.describe RuboCop::Cop::Migration::BackgroundMigrationMissingActiveConcern do + shared_examples 'offense is not registered' do + it 'does not register any offenses' do + expect_no_offenses(<<~RUBY) + module Gitlab + module BackgroundMigration + prepended do + scope_to -> (relation) { relation } + end + end + end + RUBY + end + end + + context 'when outside of a migration' do + it_behaves_like 'offense is not registered' + end + + context 'in non-ee background migration' do + before do + allow(cop).to receive(:in_ee_background_migration?).and_return(false) + end + + it_behaves_like 'offense is not registered' + end + + context 'in ee background migration' do + before do + allow(cop).to receive(:in_ee_background_migration?).and_return(true) + end + + context 'when scope_to is not used inside prepended block' do + it 'does not register any offenses' do + expect_no_offenses(<<~RUBY) + module Gitlab + module BackgroundMigration + prepended do + some_method_to -> (relation) { relation } + end + + def foo + scope_to -> (relation) { relation } + end + end + end + RUBY + end + end + + context 'when scope_to is used inside prepended block' do + it 'does not register any offenses if the module does extend ActiveSupport::Concern' do + expect_no_offenses(<<~RUBY) + module Gitlab + module BackgroundMigration + extend ::Gitlab::Utils::Override + extend ActiveSupport::Concern + + prepended do + scope_to -> (relation) { relation } + end + end + end + RUBY + end + + it 'registers an offense if the module does not extend ActiveSupport::Concern' do + expect_offense(<<~RUBY) + module Gitlab + module BackgroundMigration + prepended do + scope_to -> (relation) { relation } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Extend `ActiveSupport::Concern` [...] + end + end + end + RUBY + end + end + end +end diff --git a/spec/rubocop/cop/redis_queue_usage_spec.rb b/spec/rubocop/cop/redis_queue_usage_spec.rb new file mode 100644 index 00000000000..9861a6a79d9 --- /dev/null +++ b/spec/rubocop/cop/redis_queue_usage_spec.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +require 'rubocop_spec_helper' + +require_relative '../../../rubocop/cop/redis_queue_usage' + +RSpec.describe RuboCop::Cop::RedisQueueUsage do + let(:msg) { described_class::MSG } + + context 'when assigning Gitlab::Redis::Queues as a variable' do + it 'registers offence for any variable assignment' do + expect_offense(<<~PATTERN) + x = Gitlab::Redis::Queues + ^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} + PATTERN + end + + it 'registers offence for constant assignment' do + expect_offense(<<~PATTERN) + X = Gitlab::Redis::Queues + ^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} + PATTERN + end + end + + context 'when assigning Gitlab::Redis::Queues as a part of an array' do + it 'registers offence for variable assignments' do + expect_offense(<<~PATTERN) + x = [ Gitlab::Redis::Cache, Gitlab::Redis::Queues, Gitlab::Redis::SharedState ] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} + PATTERN + end + + it 'registers offence for constant assignments' do + expect_offense(<<~PATTERN) + ALL = [ Gitlab::Redis::Cache, Gitlab::Redis::Queues, Gitlab::Redis::SharedState ] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} + PATTERN + end + + it 'registers offence for constant assignments while invoking function' do + expect_offense(<<~PATTERN) + ALL = [ Gitlab::Redis::Cache, Gitlab::Redis::Queues, Gitlab::Redis::SharedState ].freeze + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} + PATTERN + end + + it 'registers offence for constant assignments while invoking multiple functions' do + expect_offense(<<~PATTERN) + ALL = [ Gitlab::Redis::Cache, Gitlab::Redis::Queues, Gitlab::Redis::SharedState ].foo.freeze + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} + PATTERN + end + end + + context 'when assigning Gitlab::Redis::Queues as a part of a hash' do + it 'registers offence for variable assignments' do + expect_offense(<<~PATTERN) + x = { "test": Gitlab::Redis::Queues, "test2": Gitlab::Redis::SharedState } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} + PATTERN + end + + it 'registers offence for constant assignments' do + expect_offense(<<~PATTERN) + ALL = { "test": Gitlab::Redis::Queues, "test2": Gitlab::Redis::SharedState } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} + PATTERN + end + + it 'registers offence for constant assignments while invoking function' do + expect_offense(<<~PATTERN) + ALL = { "test": Gitlab::Redis::Queues, "test2": Gitlab::Redis::SharedState }.freeze + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} + PATTERN + end + + it 'registers offence for constant assignments while invoking multiple functions' do + expect_offense(<<~PATTERN) + ALL = { "test": Gitlab::Redis::Queues, "test2": Gitlab::Redis::SharedState }.foo.freeze + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} + PATTERN + end + end + + it 'registers offence for any invocation of Gitlab::Redis::Queues methods' do + expect_offense(<<~PATTERN) + Gitlab::Redis::Queues.params + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} + PATTERN + end + + it 'registers offence for using Gitlab::Redis::Queues as parameter in method calls' do + expect_offense(<<~PATTERN) + use_redis(Gitlab::Redis::Queues) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} + PATTERN + end +end diff --git a/spec/rubocop/cop/rspec/factory_bot/avoid_create_spec.rb b/spec/rubocop/cop/rspec/factory_bot/avoid_create_spec.rb new file mode 100644 index 00000000000..7f45661c13d --- /dev/null +++ b/spec/rubocop/cop/rspec/factory_bot/avoid_create_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'rubocop_spec_helper' + +require_relative '../../../../../rubocop/cop/rspec/factory_bot/avoid_create' + +RSpec.describe RuboCop::Cop::RSpec::FactoryBot::AvoidCreate do + shared_examples 'an offensive factory call' do |namespace| + %i[create create_list].each do |forbidden_method| + namespaced_forbidden_method = "#{namespace}#{forbidden_method}(:user)" + + it "registers an offense for #{namespaced_forbidden_method}" do + expect_offense(<<-RUBY) + describe 'foo' do + let(:user) { #{namespaced_forbidden_method} } + #{'^' * namespaced_forbidden_method.size} Prefer using `build_stubbed` or similar over `#{forbidden_method}`. See https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#optimize-factory-usage + end + RUBY + end + end + end + + it_behaves_like 'an offensive factory call', '' + it_behaves_like 'an offensive factory call', 'FactoryBot.' +end diff --git a/spec/rubocop/cop/rspec/top_level_describe_path_spec.rb b/spec/rubocop/cop/rspec/top_level_describe_path_spec.rb index 90101e09023..6c596210f4e 100644 --- a/spec/rubocop/cop/rspec/top_level_describe_path_spec.rb +++ b/spec/rubocop/cop/rspec/top_level_describe_path_spec.rb @@ -22,6 +22,19 @@ RSpec.describe RuboCop::Cop::RSpec::TopLevelDescribePath do end end + context 'when the describe is in a shared context' do + context 'with shared_context' do + it 'registers no offenses' do + expect_no_offenses(<<~SOURCE, 'spec/foo.rb') + shared_context 'Foo' do + describe '#bar' do + end + end + SOURCE + end + end + end + context 'when the describe is in a shared example' do context 'with shared_examples' do it 'registers no offenses' do diff --git a/spec/rubocop/cop/sidekiq_api_usage_spec.rb b/spec/rubocop/cop/sidekiq_api_usage_spec.rb new file mode 100644 index 00000000000..79a0774e625 --- /dev/null +++ b/spec/rubocop/cop/sidekiq_api_usage_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'rubocop_spec_helper' + +require_relative '../../../rubocop/cop/sidekiq_api_usage' + +RSpec.describe RuboCop::Cop::SidekiqApiUsage do + let(:msg) { described_class::MSG } + + context 'when calling Sidekiq::Worker' do + it 'registers no offences for calling skipping_transaction_check' do + expect_no_offenses(<<~PATTERN) + Sidekiq::Worker.skipping_transaction_check do + end + PATTERN + end + + it 'registers no offences for calling raise_inside_transaction_exception' do + expect_no_offenses(<<~PATTERN) + Sidekiq::Worker.raise_inside_transaction_exception(cause: "testing") + PATTERN + end + + it 'registers no offences for calling raise_exception_for_being_inside_a_transaction?' do + expect_no_offenses(<<~PATTERN) + return if Sidekiq::Worker.raise_exception_for_being_inside_a_transaction? + PATTERN + end + + it 'registers offence for calling other Sidekiq::Worker methods' do + expect_offense(<<~PATTERN) + Sidekiq::Worker.drain_all + ^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} + PATTERN + end + end + + it 'does not registers offence when calling Sidekiq::Testing' do + expect_no_offenses(<<~PATTERN) + Sidekiq::Testing.inline! do + create_real_projects! + create_large_projects! + end + PATTERN + end + + it 'registers offence when calling Sidekiq API' do + expect_offense(<<~PATTERN) + Sidekiq::Queue.new('testing').all + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg} + PATTERN + end + + it 'registers offence when assigning Sidekiq API classes' do + expect_offense(<<~PATTERN) + retry_set = Sidekiq::RetrySet.new + ^^^^^^^^^^^^^^^^^^^^^ #{msg} + PATTERN + end +end diff --git a/spec/rubocop/cop/sidekiq_redis_call_spec.rb b/spec/rubocop/cop/sidekiq_redis_call_spec.rb new file mode 100644 index 00000000000..7d1c68bfabe --- /dev/null +++ b/spec/rubocop/cop/sidekiq_redis_call_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'rubocop_spec_helper' + +require_relative '../../../rubocop/cop/sidekiq_redis_call' + +RSpec.describe RuboCop::Cop::SidekiqRedisCall do + it 'flags any use of Sidekiq.redis even without blocks' do + expect_offense(<<~PATTERN) + Sidekiq.redis + ^^^^^^^^^^^^^ Refrain from directly using Sidekiq.redis unless for migration. For admin operations, use Sidekiq APIs. + PATTERN + end + + it 'flags the use of Sidekiq.redis in single-line blocks' do + expect_offense(<<~PATTERN) + Sidekiq.redis { |redis| yield redis } + ^^^^^^^^^^^^^ Refrain from directly using Sidekiq.redis unless for migration. For admin operations, use Sidekiq APIs. + PATTERN + end + + it 'flags the use of Sidekiq.redis in multi-line blocks' do + expect_offense(<<~PATTERN) + Sidekiq.redis do |conn| + ^^^^^^^^^^^^^ Refrain from directly using Sidekiq.redis unless for migration. For admin operations, use Sidekiq APIs. + conn.sadd('queues', queues) + end + PATTERN + end +end diff --git a/spec/rubocop/cop/static_translation_definition_spec.rb b/spec/rubocop/cop/static_translation_definition_spec.rb index 10b4f162504..9f45f6f8c5b 100644 --- a/spec/rubocop/cop/static_translation_definition_spec.rb +++ b/spec/rubocop/cop/static_translation_definition_spec.rb @@ -38,6 +38,15 @@ RSpec.describe RuboCop::Cop::StaticTranslationDefinition do C = n_("c") ^^^^^^^ #{msg} CODE + <<~'CODE', + A = _('a' \ + ^^^^^^^ [...] + 'b') + CODE + <<~'CODE', + A = _("a#{s}") + ^^^^^^^^^^ [...] + CODE <<~CODE, class MyClass def self.translations @@ -100,6 +109,9 @@ RSpec.describe RuboCop::Cop::StaticTranslationDefinition do 'CONSTANT_1 = __("a")', 'CONSTANT_2 = s__("a")', 'CONSTANT_3 = n__("a")', + 'CONSTANT_var = _(code)', + 'CONSTANT_int = _(1)', + 'CONSTANT_none = _()', <<~CODE, class MyClass def self.method |