From 978a7eab108518d642ff3ec12d4b67aada7999b2 Mon Sep 17 00:00:00 2001 From: Tejas Bubane Date: Fri, 30 Dec 2022 23:54:38 +0530 Subject: [PATCH] [Fix #213] Add new cop `Minitest/FileName` Closes #213 --- changelog/new_file_name_cop.md | 1 + config/default.yml | 6 +++ lib/rubocop/cop/minitest/file_name.rb | 42 +++++++++++++++++++++ lib/rubocop/cop/minitest_cops.rb | 1 + test/rubocop/cop/minitest/file_name_test.rb | 34 +++++++++++++++++ 5 files changed, 84 insertions(+) create mode 100644 changelog/new_file_name_cop.md create mode 100644 lib/rubocop/cop/minitest/file_name.rb create mode 100644 test/rubocop/cop/minitest/file_name_test.rb diff --git a/changelog/new_file_name_cop.md b/changelog/new_file_name_cop.md new file mode 100644 index 00000000..c776ca79 --- /dev/null +++ b/changelog/new_file_name_cop.md @@ -0,0 +1 @@ +* [#213](https://github.com/rubocop/rubocop-minitest/issues/213): Add new `Minitest/FileName` cop. ([@tejasbubane][]) diff --git a/config/default.yml b/config/default.yml index 9fc12f67..5299eac5 100644 --- a/config/default.yml +++ b/config/default.yml @@ -129,6 +129,12 @@ Minitest/EmptyLineBeforeAssertionMethods: Enabled: pending VersionAdded: '0.23' +Minitest/FileName: + Description: 'Checks if test file names start with `test_` or end with `_test.rb`.' + StyleGuide: 'https://minitest.rubystyle.guide/#file-naming' + Enabled: pending + VersionAdded: '<>' + Minitest/GlobalExpectations: Description: 'This cop checks for deprecated global expectations.' StyleGuide: 'https://minitest.rubystyle.guide#global-expectations' diff --git a/lib/rubocop/cop/minitest/file_name.rb b/lib/rubocop/cop/minitest/file_name.rb new file mode 100644 index 00000000..2d17a2d7 --- /dev/null +++ b/lib/rubocop/cop/minitest/file_name.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Minitest + # Checks if test file names start with `test_` or end with `_test.rb`. + # + # @example + # # bad + # my_class.rb + # + # # good + # my_class_test.rb + # test_my_class.rb + # + class FileName < Base + include MinitestExplorationHelpers + + MSG = 'Test file path should start with `test_` or end with `_test.rb`.' + + def on_new_investigation + return if processed_source.blank? + return unless test_file?(processed_source.ast) + + add_global_offense(MSG) unless valid_file_name? + end + + private + + def test_file?(node) + test_class?(node) || + node.each_child_node.any? { |child_node| child_node&.class_type? && test_class?(child_node) } + end + + def valid_file_name? + file_name = File.basename(processed_source.buffer.name) + file_name.start_with?('test_') || file_name.end_with?('_test.rb') + end + end + end + end +end diff --git a/lib/rubocop/cop/minitest_cops.rb b/lib/rubocop/cop/minitest_cops.rb index 4ad7087f..808e0c3d 100644 --- a/lib/rubocop/cop/minitest_cops.rb +++ b/lib/rubocop/cop/minitest_cops.rb @@ -27,6 +27,7 @@ require_relative 'minitest/assert_truthy' require_relative 'minitest/duplicate_test_run' require_relative 'minitest/empty_line_before_assertion_methods' +require_relative 'minitest/file_name' require_relative 'minitest/global_expectations' require_relative 'minitest/literal_as_actual_argument' require_relative 'minitest/multiple_assertions' diff --git a/test/rubocop/cop/minitest/file_name_test.rb b/test/rubocop/cop/minitest/file_name_test.rb new file mode 100644 index 00000000..458fc1d3 --- /dev/null +++ b/test/rubocop/cop/minitest/file_name_test.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'test_helper' + +class FileNameTest < Minitest::Test + def test_registers_offense_for_invalid_path + offenses = inspect_source(<<~RUBY, @cop, 'foo.rb') + class FooTest < Minitest::Test + end + RUBY + message = 'Test file path should start with `test_` or end with `_test.rb`.' + + assert_equal(offenses.size, 1) + assert_equal(offenses.first.message, message) + end + + def test_does_not_register_offense_for_files_starting_with_test + assert_no_offenses(<<~RUBY, 'test_foo.rb') + class FooTest < Minitest::Test; end + RUBY + end + + def test_does_not_register_offense_for_files_ending_with_test + assert_no_offenses(<<~RUBY, 'foo_test.rb') + class FooTest < Minitest::Test; end + RUBY + end + + def test_does_not_register_offense_for_non_test_classes + assert_no_offenses(<<~RUBY, 'foo.rb') + class Foo; end + RUBY + end +end