diff options
Diffstat (limited to 'spec/rubocop')
16 files changed, 485 insertions, 84 deletions
diff --git a/spec/rubocop/batched_background_migrations_spec.rb b/spec/rubocop/batched_background_migrations_spec.rb new file mode 100644 index 00000000000..a9b99bb466b --- /dev/null +++ b/spec/rubocop/batched_background_migrations_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'rubocop_spec_helper' + +require_relative '../../rubocop/batched_background_migrations' + +RSpec.describe RuboCop::BatchedBackgroundMigrations, feature_category: :database do + let(:bbm_dictionary_file_name) { "#{described_class::DICTIONARY_BASE_DIR}/test_migration.yml" } + let(:migration_version) { 20230307160250 } + let(:finalized_by_version) { 20230307160255 } + let(:bbm_dictionary_data) do + { + migration_job_name: 'TestMigration', + feature_category: :database, + introduced_by_url: 'https://test_url', + milestone: 16.5, + queued_migration_version: migration_version, + finalized_by: finalized_by_version + } + end + + before do + File.open(bbm_dictionary_file_name, 'w') do |file| + file.write(bbm_dictionary_data.stringify_keys.to_yaml) + end + end + + after do + FileUtils.rm(bbm_dictionary_file_name) + end + + subject(:batched_background_migration) { described_class.new(migration_version) } + + describe '#finalized_by' do + it 'returns the finalized_by version of the bbm with given version' do + expect(batched_background_migration.finalized_by).to eq(finalized_by_version.to_s) + end + + it 'returns nothing for non-existing bbm dictionary' do + expect(described_class.new('random').finalized_by).to be_nil + end + end +end diff --git a/spec/rubocop/check_graceful_task_spec.rb b/spec/rubocop/check_graceful_task_spec.rb index 38c2d68a593..aa66643dd8e 100644 --- a/spec/rubocop/check_graceful_task_spec.rb +++ b/spec/rubocop/check_graceful_task_spec.rb @@ -1,14 +1,9 @@ # frozen_string_literal: true -require 'fast_spec_helper' -require 'stringio' - -require_relative '../support/helpers/next_instance_of' +require 'rubocop_spec_helper' require_relative '../../rubocop/check_graceful_task' RSpec.describe RuboCop::CheckGracefulTask do - include NextInstanceOf - let(:output) { StringIO.new } subject(:task) { described_class.new(output) } @@ -119,9 +114,9 @@ RSpec.describe RuboCop::CheckGracefulTask do end context 'with args' do - let(:args) { %w[a.rb Lint/EmptyFile b.rb Lint/Syntax] } + let(:args) { %w[Lint/EmptyFile Lint/Syntax] } - it_behaves_like 'rubocop scan', rubocop_args: %w[--only Lint/EmptyFile,Lint/Syntax a.rb b.rb] + it_behaves_like 'rubocop scan', rubocop_args: %w[--only Lint/EmptyFile,Lint/Syntax] it 'does not notify slack' do expect(Gitlab::Popen).not_to receive(:popen) diff --git a/spec/rubocop/cop/background_migration/feature_category_spec.rb b/spec/rubocop/cop/background_migration/feature_category_spec.rb index 1d1b6cfad5a..12794de4f38 100644 --- a/spec/rubocop/cop/background_migration/feature_category_spec.rb +++ b/spec/rubocop/cop/background_migration/feature_category_spec.rb @@ -66,4 +66,10 @@ RSpec.describe RuboCop::Cop::BackgroundMigration::FeatureCategory, feature_categ RUBY end end + + describe '#external_dependency_checksum' do + it 'returns a SHA256 digest used by RuboCop to invalid cache' do + expect(cop.external_dependency_checksum).to match(/^\h{64}$/) + end + end end diff --git a/spec/rubocop/cop/experiments_test_coverage_spec.rb b/spec/rubocop/cop/experiments_test_coverage_spec.rb index eb1e672ef40..8221d0d6720 100644 --- a/spec/rubocop/cop/experiments_test_coverage_spec.rb +++ b/spec/rubocop/cop/experiments_test_coverage_spec.rb @@ -4,7 +4,7 @@ require 'rubocop_spec_helper' require_relative '../../../rubocop/cop/experiments_test_coverage' -RSpec.describe RuboCop::Cop::ExperimentsTestCoverage, feature_category: :experimentation_conversion do +RSpec.describe RuboCop::Cop::ExperimentsTestCoverage, feature_category: :acquisition do let(:class_offense) { described_class::CLASS_OFFENSE } let(:block_offense) { described_class::BLOCK_OFFENSE } diff --git a/spec/rubocop/cop/gemfile/missing_feature_category_spec.rb b/spec/rubocop/cop/gemfile/missing_feature_category_spec.rb new file mode 100644 index 00000000000..5f8e32f0c03 --- /dev/null +++ b/spec/rubocop/cop/gemfile/missing_feature_category_spec.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require 'rubocop_spec_helper' + +require_relative '../../../../rubocop/cop/gemfile/missing_feature_category' + +RSpec.describe RuboCop::Cop::Gemfile::MissingFeatureCategory, feature_category: :tooling do + let(:valid_category) { RuboCop::FeatureCategories.available.first } + let(:invalid_category) { :invalid_category } + + it 'flags missing feature category in gem method without keyword argument' do + expect_offense(<<~RUBY) + gem 'foo', '~> 1.0' + ^^^^^^^^^^^^^^^^^^^ Please use a valid feature category. See https://docs.gitlab.com/ee/development/feature_categorization/#gemfile + RUBY + end + + it 'flags missing feature category in gem method with keyword argument' do + expect_offense(<<~RUBY) + gem 'foo', '~> 1.0', require: false + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Please use a valid feature category. See https://docs.gitlab.com/ee/development/feature_categorization/#gemfile + RUBY + end + + it 'flags invalid feature category in gem method as the only keyword argument' do + expect_offense(<<~RUBY, invalid: invalid_category) + gem 'foo', '~> 1.0', feature_category: :%{invalid} + ^^{invalid} Please use a valid feature category. See https://docs.gitlab.com/ee/development/feature_categorization/#gemfile + RUBY + end + + it 'flags invalid feature category in gem method as the last keyword argument' do + expect_offense(<<~RUBY, invalid: invalid_category) + gem 'foo', '~> 1.0', require: false, feature_category: :%{invalid} + ^^{invalid} Please use a valid feature category. See https://docs.gitlab.com/ee/development/feature_categorization/#gemfile + RUBY + end + + it 'flags invalid feature category in gem method as the first keyword argument' do + expect_offense(<<~RUBY, invalid: invalid_category) + gem 'foo', '~> 1.0', feature_category: :%{invalid}, require: false + ^^{invalid} Please use a valid feature category. See https://docs.gitlab.com/ee/development/feature_categorization/#gemfile + RUBY + end + + it 'does not flag in gem method if feature category is valid as the only keyword argument' do + expect_no_offenses(<<~RUBY) + gem 'foo', '~> 1.0', feature_category: :#{valid_category} + RUBY + end + + it 'does not flag in gem method if feature category is valid as the last keyword argument' do + expect_no_offenses(<<~RUBY) + gem 'foo', '~> 1.0', require: false, feature_category: :#{valid_category} + RUBY + end + + describe '#external_dependency_checksum' do + it 'returns a SHA256 digest used by RuboCop to invalid cache' do + expect(cop.external_dependency_checksum).to match(/^\h{64}$/) + end + end +end diff --git a/spec/rubocop/cop/gitlab/avoid_gitlab_instance_checks_spec.rb b/spec/rubocop/cop/gitlab/avoid_gitlab_instance_checks_spec.rb new file mode 100644 index 00000000000..2dba6194d44 --- /dev/null +++ b/spec/rubocop/cop/gitlab/avoid_gitlab_instance_checks_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'rubocop_spec_helper' +require 'rspec-parameterized' +require_relative '../../../../rubocop/cop/gitlab/avoid_gitlab_instance_checks' + +RSpec.describe RuboCop::Cop::Gitlab::AvoidGitlabInstanceChecks, feature_category: :shared do + let(:msg) { described_class::MSG } + + describe 'bad examples' do + where(:code) do + %w[ + Gitlab.com? + Gitlab.com_except_jh? + Gitlab.com_and_canary? + Gitlab.com_but_not_canary? + Gitlab.org_or_com? + ::Gitlab.com? + Gitlab::CurrentSettings.should_check_namespace_plan? + ::Gitlab::CurrentSettings.should_check_namespace_plan? + ] + end + + with_them do + it 'registers an offense' do + expect_offense(<<~CODE, node: code) + return if %{node} + ^{node} Avoid the use of [...] + CODE + end + end + end + + describe 'good examples' do + where(:code) do + %w[com? com Gitlab.com Gitlab::CurrentSettings.check_namespace_plan?] + end + + with_them do + it 'does not register an offense' do + expect_no_offenses(code) + end + end + end +end diff --git a/spec/rubocop/cop/gitlab/feature_available_usage_spec.rb b/spec/rubocop/cop/gitlab/feature_available_usage_spec.rb index b15c298099d..184f2c3ee92 100644 --- a/spec/rubocop/cop/gitlab/feature_available_usage_spec.rb +++ b/spec/rubocop/cop/gitlab/feature_available_usage_spec.rb @@ -16,6 +16,10 @@ RSpec.describe RuboCop::Cop::Gitlab::FeatureAvailableUsage do expect_no_offenses('License.feature_available?(:push_rules)') end + it 'does not flag the use of Gitlab::Saas.feature_available?' do + expect_no_offenses('Gitlab::Saas.feature_available?("some/feature")') + end + it 'flags the use with a dynamic feature as nil' do expect_offense(<<~SOURCE) feature_available?(nil) diff --git a/spec/rubocop/cop/migration/prevent_index_creation_spec.rb b/spec/rubocop/cop/migration/prevent_index_creation_spec.rb index 9d886467a48..088edfedfc9 100644 --- a/spec/rubocop/cop/migration/prevent_index_creation_spec.rb +++ b/spec/rubocop/cop/migration/prevent_index_creation_spec.rb @@ -4,7 +4,7 @@ require 'rubocop_spec_helper' require_relative '../../../../rubocop/cop/migration/prevent_index_creation' RSpec.describe RuboCop::Cop::Migration::PreventIndexCreation do - let(:forbidden_tables) { %w(ci_builds) } + let(:forbidden_tables) { %w(ci_builds namespaces) } let(:forbidden_tables_list) { forbidden_tables.join(', ') } context 'when in migration' do @@ -12,14 +12,26 @@ RSpec.describe RuboCop::Cop::Migration::PreventIndexCreation do allow(cop).to receive(:in_migration?).and_return(true) end + let(:offense) { "Adding new index to #{forbidden_tables_list} is forbidden. [...]" } + context 'when adding an index to a forbidden table' do + it 'does not register an offense when direction is down' do + forbidden_tables.each do |table_name| + expect_no_offenses(<<~RUBY) + def down + add_concurrent_index :#{table_name}, :runners_token, unique: true, name: INDEX_NAME + end + RUBY + end + end + context 'when table_name is a symbol' do it "registers an offense when add_index is used", :aggregate_failures do forbidden_tables.each do |table_name| expect_offense(<<~RUBY) def change add_index :#{table_name}, :protected - ^^^^^^^^^ Adding new index to #{forbidden_tables_list} is forbidden, see https://gitlab.com/gitlab-org/gitlab/-/issues/332886 + ^^^^^^^^^ #{offense} end RUBY end @@ -30,7 +42,7 @@ RSpec.describe RuboCop::Cop::Migration::PreventIndexCreation do expect_offense(<<~RUBY) def change add_concurrent_index :#{table_name}, :protected - ^^^^^^^^^^^^^^^^^^^^ Adding new index to #{forbidden_tables_list} is forbidden, see https://gitlab.com/gitlab-org/gitlab/-/issues/332886 + ^^^^^^^^^^^^^^^^^^^^ #{offense} end RUBY end @@ -43,7 +55,7 @@ RSpec.describe RuboCop::Cop::Migration::PreventIndexCreation do expect_offense(<<~RUBY) def change add_index "#{table_name}", :protected - ^^^^^^^^^ Adding new index to #{forbidden_tables_list} is forbidden, see https://gitlab.com/gitlab-org/gitlab/-/issues/332886 + ^^^^^^^^^ #{offense} end RUBY end @@ -54,7 +66,7 @@ RSpec.describe RuboCop::Cop::Migration::PreventIndexCreation do expect_offense(<<~RUBY) def change add_concurrent_index "#{table_name}", :protected - ^^^^^^^^^^^^^^^^^^^^ Adding new index to #{forbidden_tables_list} is forbidden, see https://gitlab.com/gitlab-org/gitlab/-/issues/332886 + ^^^^^^^^^^^^^^^^^^^^ #{offense} end RUBY end @@ -70,7 +82,7 @@ RSpec.describe RuboCop::Cop::Migration::PreventIndexCreation do def change add_concurrent_index TABLE_NAME, :protected - ^^^^^^^^^^^^^^^^^^^^ Adding new index to #{forbidden_tables_list} is forbidden, see https://gitlab.com/gitlab-org/gitlab/-/issues/332886 + ^^^^^^^^^^^^^^^^^^^^ #{offense} end RUBY end diff --git a/spec/rubocop/cop/migration/unfinished_dependencies_spec.rb b/spec/rubocop/cop/migration/unfinished_dependencies_spec.rb new file mode 100644 index 00000000000..cac48871856 --- /dev/null +++ b/spec/rubocop/cop/migration/unfinished_dependencies_spec.rb @@ -0,0 +1,118 @@ +# frozen_string_literal: true + +require 'rubocop_spec_helper' +require_relative '../../../../rubocop/cop/migration/unfinished_dependencies' + +RSpec.describe RuboCop::Cop::Migration::UnfinishedDependencies, feature_category: :database do + let(:version) { 20230307160250 } + + let(:migration) do + <<~RUBY + class TestMigration < Gitlab::Database::Migration[2.1] + def perform; end + end + RUBY + end + + before do + allow(cop).to receive(:in_migration?).and_return(true) + + allow(cop).to receive(:version).and_return(version) + end + + shared_examples 'migration with rubocop offense' do + it 'registers an offense' do + expect_offense(migration) + end + end + + shared_examples 'migration without any rubocop offense' do + it 'does not register any offense' do + expect_no_offenses(migration) + end + end + + context 'without any dependent batched background migrations' do + it_behaves_like 'migration without any rubocop offense' + end + + context 'with dependent batched background migrations' do + let(:dependent_migration_versions) { [20230307160240] } + + let(:migration) do + <<~RUBY + class TestMigration < Gitlab::Database::Migration[2.1] + DEPENDENT_BATCHED_BACKGROUND_MIGRATIONS = #{dependent_migration_versions} + + def perform; end + end + RUBY + end + + context 'with unfinished dependent migration' do + before do + allow(cop).to receive(:fetch_finalized_by) + .with(dependent_migration_versions.first) + .and_return(nil) + end + + it_behaves_like 'migration with rubocop offense' do + let(:migration) do + <<~RUBY + class TestMigration < Gitlab::Database::Migration[2.1] + DEPENDENT_BATCHED_BACKGROUND_MIGRATIONS = #{dependent_migration_versions} + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{format(described_class::NOT_FINALIZED_MSG, version: dependent_migration_versions.first)} + + def perform; end + end + RUBY + end + end + end + + context 'with incorrectly finalized dependent migration' do + let(:dependent_migration_versions) { [20230307160240, 20230307160230] } + + before do + allow(cop).to receive(:fetch_finalized_by) + .with(dependent_migration_versions.first) + .and_return(version - 10) + + allow(cop).to receive(:fetch_finalized_by) + .with(dependent_migration_versions.last) + .and_return(version + 10) + end + + it_behaves_like 'migration with rubocop offense' do + let(:migration) do + <<~RUBY + class TestMigration < Gitlab::Database::Migration[2.1] + DEPENDENT_BATCHED_BACKGROUND_MIGRATIONS = #{dependent_migration_versions} + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{format(described_class::FINALIZED_BY_LATER_MIGRATION_MSG, version: dependent_migration_versions.last)} + + def perform; end + end + RUBY + end + end + end + + context 'with properly finalized dependent background migrations' do + before do + allow_next_instance_of(RuboCop::BatchedBackgroundMigrations) do |bbms| + allow(bbms).to receive(:finalized_by).and_return(version - 5) + end + end + + it_behaves_like 'migration without any rubocop offense' + end + end + + context 'for non migrations' do + before do + allow(cop).to receive(:in_migration?).and_return(false) + end + + it_behaves_like 'migration without any rubocop offense' + end +end diff --git a/spec/rubocop/cop/qa/fabricate_usage_spec.rb b/spec/rubocop/cop/qa/fabricate_usage_spec.rb new file mode 100644 index 00000000000..7c4b42b91e0 --- /dev/null +++ b/spec/rubocop/cop/qa/fabricate_usage_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'rubocop_spec_helper' + +require_relative '../../../../rubocop/cop/qa/fabricate_usage' + +RSpec.describe RuboCop::Cop::QA::FabricateUsage, feature_category: :quality_management do + let(:source_file) { 'qa/qa/specs/spec.rb' } + + it 'registers an offense when using fabricate_via_api! for a valid resource' do + expect_offense(<<~RUBY) + Resource::Project.fabricate_via_api! do |project| + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create(:project[, ...]) here. + project.name = 'test' + end + RUBY + end + + it 'registers an offense for groups' do + expect_offense(<<~RUBY) + Resource::Group.fabricate_via_api! do |group| + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create(:group[, ...]) here. + group.path = 'test' + end + RUBY + end + + it 'does not register an offense when using fabricate_via_api! for an unenforced resource' do + expect_no_offenses(<<~RUBY) + Resource::Invalid.fabricate_via_api! do |project| + project.name = 'test' + end + RUBY + end +end diff --git a/spec/rubocop/cop/rspec/env_mocking_spec.rb b/spec/rubocop/cop/rspec/env_mocking_spec.rb index 189fccf483a..fec2000c88b 100644 --- a/spec/rubocop/cop/rspec/env_mocking_spec.rb +++ b/spec/rubocop/cop/rspec/env_mocking_spec.rb @@ -34,23 +34,23 @@ RSpec.describe RuboCop::Cop::RSpec::EnvMocking, feature_category: :tooling do context 'with mocking bracket calls ' do it_behaves_like 'cop offense mocking the ENV constant correctable with stub_env', - offense_call_brackets_string_quotes, %(stub_env('FOO', 'bar')) + offense_call_brackets_string_quotes, %(stub_env('FOO', 'bar')) it_behaves_like 'cop offense mocking the ENV constant correctable with stub_env', - offense_call_brackets_variables, %(stub_env(key, value)) + offense_call_brackets_variables, %(stub_env(key, value)) end context 'with mocking fetch calls' do it_behaves_like 'cop offense mocking the ENV constant correctable with stub_env', - offense_call_fetch_string_quotes, %(stub_env('FOO', 'bar')) + offense_call_fetch_string_quotes, %(stub_env('FOO', 'bar')) it_behaves_like 'cop offense mocking the ENV constant correctable with stub_env', - offense_call_fetch_variables, %(stub_env(key, value)) + offense_call_fetch_variables, %(stub_env(key, value)) end context 'with other special cases and variations' do it_behaves_like 'cop offense mocking the ENV constant correctable with stub_env', - offense_call_root_env_variables, %(stub_env(key, value)) + offense_call_root_env_variables, %(stub_env(key, value)) it_behaves_like 'cop offense mocking the ENV constant correctable with stub_env', - offense_call_key_value_method_calls, %(stub_env(fetch_key(object), fetch_value(object))) + offense_call_key_value_method_calls, %(stub_env(fetch_key(object), fetch_value(object))) end context 'with acceptable cases' do diff --git a/spec/rubocop/cop/rspec/invalid_feature_category_spec.rb b/spec/rubocop/cop/rspec/feature_category_spec.rb index e5287f7105e..05e3cae012e 100644 --- a/spec/rubocop/cop/rspec/invalid_feature_category_spec.rb +++ b/spec/rubocop/cop/rspec/feature_category_spec.rb @@ -3,14 +3,15 @@ require 'rubocop_spec_helper' require 'rspec-parameterized' -require_relative '../../../../rubocop/cop/rspec/invalid_feature_category' +require_relative '../../../../rubocop/feature_categories' +require_relative '../../../../rubocop/cop/rspec/feature_category' -RSpec.describe RuboCop::Cop::RSpec::InvalidFeatureCategory, feature_category: :tooling do +RSpec.describe RuboCop::Cop::RSpec::FeatureCategory, feature_category: :tooling do shared_examples 'feature category validation' do |valid_category| it 'flags invalid feature category in top level example group' do expect_offense(<<~RUBY, invalid: invalid_category) RSpec.describe 'foo', feature_category: :%{invalid}, foo: :bar do - ^^{invalid} Please use a valid feature category. See https://docs.gitlab.com/ee/development/feature_categorization/#rspec-examples. + ^^{invalid} Please use a valid feature category. See https://docs.gitlab.com/ee/development/feature_categorization/#rspec-examples end RUBY end @@ -19,7 +20,7 @@ RSpec.describe RuboCop::Cop::RSpec::InvalidFeatureCategory, feature_category: :t expect_offense(<<~RUBY, valid: valid_category, invalid: invalid_category) RSpec.describe 'foo', feature_category: :"%{valid}" do context 'bar', foo: :bar, feature_category: :%{invalid} do - ^^{invalid} Please use a valid feature category. See https://docs.gitlab.com/ee/development/feature_categorization/#rspec-examples. + ^^{invalid} Please use a valid feature category. See https://docs.gitlab.com/ee/development/feature_categorization/#rspec-examples end end RUBY @@ -29,7 +30,7 @@ RSpec.describe RuboCop::Cop::RSpec::InvalidFeatureCategory, feature_category: :t expect_offense(<<~RUBY, valid: valid_category, invalid: invalid_category) RSpec.describe 'foo', feature_category: :"%{valid}" do it 'bar', feature_category: :%{invalid} do - ^^{invalid} Please use a valid feature category. See https://docs.gitlab.com/ee/development/feature_categorization/#rspec-examples. + ^^{invalid} Please use a valid feature category. See https://docs.gitlab.com/ee/development/feature_categorization/#rspec-examples end end RUBY @@ -63,21 +64,14 @@ RSpec.describe RuboCop::Cop::RSpec::InvalidFeatureCategory, feature_category: :t let(:invalid_category) { :invalid_category } - context 'with categories defined in config/feature_categories.yml' do - where(:valid_category) do - YAML.load_file(rails_root_join('config/feature_categories.yml')) - end + context 'with defined in config/feature_categories.yml and custom categories' do + where(:valid_category) { RuboCop::FeatureCategories.available_with_custom.to_a } with_them do it_behaves_like 'feature category validation', params[:valid_category] end end - context 'with custom categories' do - it_behaves_like 'feature category validation', 'tooling' - it_behaves_like 'feature category validation', 'shared' - end - it 'flags invalid feature category for non-symbols' do expect_offense(<<~RUBY, invalid: invalid_category) RSpec.describe 'foo', feature_category: "%{invalid}" do @@ -91,9 +85,11 @@ RSpec.describe RuboCop::Cop::RSpec::InvalidFeatureCategory, feature_category: :t end it 'does not flag use of invalid categories in non-example code' do + valid_category = RuboCop::FeatureCategories.available.first + # See https://gitlab.com/gitlab-org/gitlab/-/issues/381882#note_1265865125 expect_no_offenses(<<~RUBY) - RSpec.describe 'A spec' do + RSpec.describe 'A spec', feature_category: :#{valid_category} do let(:api_handler) do Class.new(described_class) do namespace '/test' do @@ -112,6 +108,18 @@ RSpec.describe RuboCop::Cop::RSpec::InvalidFeatureCategory, feature_category: :t RUBY end + it 'flags missing feature category in top level example group' do + expect_offense(<<~RUBY) + RSpec.describe 'foo' do + ^^^^^^^^^^^^^^^^^^^^^^^ Please use a valid feature category. See https://docs.gitlab.com/ee/development/feature_categorization/#rspec-examples + end + + RSpec.describe 'foo', some: :tag do + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Please use a valid feature category. See https://docs.gitlab.com/ee/development/feature_categorization/#rspec-examples + end + RUBY + end + describe '#external_dependency_checksum' do it 'returns a SHA256 digest used by RuboCop to invalid cache' do expect(cop.external_dependency_checksum).to match(/^\h{64}$/) diff --git a/spec/rubocop/cop/rspec/missing_feature_category_spec.rb b/spec/rubocop/cop/rspec/missing_feature_category_spec.rb deleted file mode 100644 index 41b1d2b8580..00000000000 --- a/spec/rubocop/cop/rspec/missing_feature_category_spec.rb +++ /dev/null @@ -1,31 +0,0 @@ -# frozen_string_literal: true - -require 'rubocop_spec_helper' -require_relative '../../../../rubocop/cop/rspec/missing_feature_category' - -RSpec.describe RuboCop::Cop::RSpec::MissingFeatureCategory, feature_category: :tooling do - it 'flags missing feature category in top level example group' do - expect_offense(<<~RUBY) - RSpec.describe 'foo' do - ^^^^^^^^^^^^^^^^^^^^ Please add missing feature category. See https://docs.gitlab.com/ee/development/feature_categorization/#rspec-examples. - end - - RSpec.describe 'foo', some: :tag do - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Please add missing feature category. See https://docs.gitlab.com/ee/development/feature_categorization/#rspec-examples. - end - RUBY - end - - it 'does not flag if feature category is defined' do - expect_no_offenses(<<~RUBY) - RSpec.describe 'foo', feature_category: :foo do - end - - RSpec.describe 'foo', some: :tag, feature_category: :foo do - end - - RSpec.describe 'foo', feature_category: :foo, some: :tag do - end - RUBY - end -end diff --git a/spec/rubocop/cop/style/regexp_literal_mixed_preserve_spec.rb b/spec/rubocop/cop/style/regexp_literal_mixed_preserve_spec.rb index 1d1c0852db2..d2ccd504fcd 100644 --- a/spec/rubocop/cop/style/regexp_literal_mixed_preserve_spec.rb +++ b/spec/rubocop/cop/style/regexp_literal_mixed_preserve_spec.rb @@ -10,10 +10,10 @@ require_relative '../../../../rubocop/cop/style/regexp_literal_mixed_preserve' RSpec.describe RuboCop::Cop::Style::RegexpLiteralMixedPreserve, :config do let(:config) do supported_styles = { 'SupportedStyles' => %w[slashes percent_r mixed mixed_preserve] } - RuboCop::Config.new('Style/PercentLiteralDelimiters' => - percent_literal_delimiters_config, - 'Style/RegexpLiteralMixedPreserve' => - cop_config.merge(supported_styles)) + RuboCop::Config.new( + 'Style/PercentLiteralDelimiters' => percent_literal_delimiters_config, + 'Style/RegexpLiteralMixedPreserve' => cop_config.merge(supported_styles) + ) end let(:percent_literal_delimiters_config) { { 'PreferredDelimiters' => { '%r' => '{}' } } } diff --git a/spec/rubocop/feature_categories_spec.rb b/spec/rubocop/feature_categories_spec.rb new file mode 100644 index 00000000000..ffe7ade82e2 --- /dev/null +++ b/spec/rubocop/feature_categories_spec.rb @@ -0,0 +1,102 @@ +# frozen_string_literal: true + +require 'rubocop_spec_helper' + +require_relative '../../rubocop/feature_categories' + +RSpec.describe RuboCop::FeatureCategories, feature_category: :tooling do + subject(:feature_categories) { described_class.new(categories) } + + let(:categories) { ['valid_category'] } + + describe '.available' do + it 'returns a list of available feature categories in a set of strings' do + expect(described_class.available).to be_a(Set) + expect(described_class.available).to all(be_a(String)) + end + end + + describe '.available_with_custom' do + it 'returns a list of available feature categories' do + expect(described_class.available_with_custom).to include(described_class.available) + end + + it 'returns a list containing the custom feature categories' do + expect(described_class.available_with_custom).to include(described_class::CUSTOM_CATEGORIES) + end + end + + describe '.config_checksum' do + it 'returns a SHA256 digest used by RuboCop to invalid cache' do + expect(described_class.config_checksum).to match(/^\h{64}$/) + end + end + + describe '#check' do + let(:value_node) { instance_double(RuboCop::AST::SymbolNode, sym_type?: true) } + let(:document_link) { 'https://example.com' } + + def check + expect do |block| + feature_categories.check( + value_node: value_node, + document_link: document_link, + &block) + end + end + + context 'when value_node is nil' do + let(:value_node) { nil } + + it 'yields a message asking for a feature category with document link only' do + check.to yield_with_args(<<~MARKDOWN.chomp) + Please use a valid feature category. See https://example.com + MARKDOWN + end + end + + context 'when value_node is not a symbol node' do + before do + allow(value_node).to receive(:sym_type?).and_return(false) + end + + it 'yields a message asking for a symbol value' do + check.to yield_with_args(described_class::MSG_SYMBOL) + end + end + + context 'when category is found' do + before do + allow(value_node).to receive(:value).and_return(categories.first) + end + + it 'returns nil without yielding anything' do + check.not_to yield_with_args + end + end + + context 'when a similar category is found' do + before do + allow(value_node).to receive(:value).and_return('invalid_category') + end + + it 'yields a message asking for a feature category with suggestion and document link' do + check.to yield_with_args(<<~MARKDOWN.chomp) + Please use a valid feature category. Did you mean `:valid_category`? See https://example.com + MARKDOWN + end + end + + context 'when no similar category is found' do + before do + allow(value_node).to receive(:value).and_return('something_completely_different') + end + + it 'yields a message asking for a feature category with document link only' do + check.to yield_with_args(<<~MARKDOWN.chomp) + Please use a valid feature category. See https://example.com + MARKDOWN + end + end + end +end diff --git a/spec/rubocop/formatter/graceful_formatter_spec.rb b/spec/rubocop/formatter/graceful_formatter_spec.rb index d76e566e2b4..b9a56bec115 100644 --- a/spec/rubocop/formatter/graceful_formatter_spec.rb +++ b/spec/rubocop/formatter/graceful_formatter_spec.rb @@ -220,19 +220,20 @@ RSpec.describe RuboCop::Formatter::GracefulFormatter, :isolated_environment do def fake_offense(cop_name) # rubocop:disable RSpec/VerifiedDoubles - double(:offense, - cop_name: cop_name, - corrected?: false, - correctable?: false, - severity: double(:severity, name: :convention, code: :C), - line: 5, - column: 23, - real_column: 23, - corrected_with_todo?: false, - message: "#{cop_name} message", - location: double(:location, source_line: 'line', first_line: 1, last_line: 1, single_line?: true), - highlighted_area: double(:highlighted_area, begin_pos: 1, size: 2, source_buffer: 'line', source: 'i') - ) + double( + :offense, + cop_name: cop_name, + corrected?: false, + correctable?: false, + severity: double(:severity, name: :convention, code: :C), + line: 5, + column: 23, + real_column: 23, + corrected_with_todo?: false, + message: "#{cop_name} message", + location: double(:location, source_line: 'line', first_line: 1, last_line: 1, single_line?: true), + highlighted_area: double(:highlighted_area, begin_pos: 1, size: 2, source_buffer: 'line', source: 'i') + ) # rubocop:enable RSpec/VerifiedDoubles end end |