From 4d08365be08d06b02bb2c11415a4e8060331a0bb Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Thu, 11 Jul 2024 03:52:39 +0900 Subject: [PATCH 1/7] Switch back docs version to master --- docs/antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/antora.yml b/docs/antora.yml index 6a7af675..02c36842 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -2,6 +2,6 @@ name: rubocop-minitest title: RuboCop Minitest # We always provide version without patch here (e.g. 1.1), # as patch versions should not appear in the docs. -version: '0.35' +version: ~ nav: - modules/ROOT/nav.adoc From 2c2add05fecf39f3e7e1ad59eb2b7558e2d266b7 Mon Sep 17 00:00:00 2001 From: Brandon Conway Date: Mon, 12 Aug 2024 12:38:57 -0700 Subject: [PATCH 2/7] Accessing an unregistered cop raises useful error Currently, when a test class includes `AssertOffense`, `AssertOffense#setup` attempts to dynamically identify the Cop under test. If the Cop class cannot be found, `#setup` exits early. In these cases, the test cases continue to execute with a nil `@cop` since it wasn't set in `#setup` as expected. When helpers such as `#assert_offense` are used, they access `@cop` and the tests can fail with cryptic messages such as: ``` NoMethodError: undefined method `[]=' for nil ``` Initialization of the Cop was refactored to a lazily-called accessor method which has the same caching functionality via `@cop`, but raises an error if the expected Cop class isn't defined. --- ...offense_setup_fails_with_useful_message.md | 1 + lib/rubocop/minitest/assert_offense.rb | 23 +++++++++++-------- .../cop/minitest/assert_offense_test.rb | 22 ++++++++++++++++++ .../cop/minitest/test_file_name_test.rb | 4 ++-- 4 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 changelog/change_assert_offense_setup_fails_with_useful_message.md create mode 100644 test/rubocop/cop/minitest/assert_offense_test.rb diff --git a/changelog/change_assert_offense_setup_fails_with_useful_message.md b/changelog/change_assert_offense_setup_fails_with_useful_message.md new file mode 100644 index 00000000..21a76c7f --- /dev/null +++ b/changelog/change_assert_offense_setup_fails_with_useful_message.md @@ -0,0 +1 @@ +* [#314](https://github.com/rubocop/rubocop-minitest/pull/314): **(Breaking)** Raise a useful error when using a Cop in `AssertOffense` if the Cop's class is not defined. ([@brandoncc][]) diff --git a/lib/rubocop/minitest/assert_offense.rb b/lib/rubocop/minitest/assert_offense.rb index 447e9644..937f99c2 100644 --- a/lib/rubocop/minitest/assert_offense.rb +++ b/lib/rubocop/minitest/assert_offense.rb @@ -75,11 +75,13 @@ module Minitest module AssertOffense private - def setup - cop_name = self.class.to_s.delete_suffix('Test') - return unless RuboCop::Cop::Minitest.const_defined?(cop_name) + def cop + @cop ||= begin + cop_name = self.class.to_s.delete_suffix('Test') + raise "Cop not defined: #{cop_name}" unless RuboCop::Cop::Minitest.const_defined?(cop_name) - @cop = RuboCop::Cop::Minitest.const_get(cop_name).new(configuration) + RuboCop::Cop::Minitest.const_get(cop_name).new(configuration) + end end def format_offense(source, **replacements) @@ -95,7 +97,7 @@ def format_offense(source, **replacements) def assert_no_offenses(source, file = nil) setup_assertion - offenses = inspect_source(source, @cop, file) + offenses = inspect_source(source, cop, file) expected_annotations = RuboCop::RSpec::ExpectOffense::AnnotatedSource.parse(source) actual_annotations = expected_annotations.with_offense_annotations(offenses) @@ -105,8 +107,7 @@ def assert_no_offenses(source, file = nil) def assert_offense(source, file = nil, **replacements) setup_assertion - - @cop.instance_variable_get(:@options)[:autocorrect] = true + enable_autocorrect source = format_offense(source, **replacements) expected_annotations = RuboCop::RSpec::ExpectOffense::AnnotatedSource.parse(source) @@ -116,7 +117,7 @@ def assert_offense(source, file = nil, **replacements) @processed_source = parse_source!(expected_annotations.plain_source, file) - @offenses = _investigate(@cop, @processed_source) + @offenses = _investigate(cop, @processed_source) actual_annotations = expected_annotations.with_offense_annotations(@offenses) @@ -130,6 +131,10 @@ def _investigate(cop, processed_source) report.offenses end + def enable_autocorrect + cop.instance_variable_get(:@options)[:autocorrect] = true + end + def assert_correction(correction, loop: true) raise '`assert_correction` must follow `assert_offense`' unless @processed_source @@ -149,7 +154,7 @@ def assert_correction(correction, loop: true) # Prepare for next loop @processed_source = parse_source!(corrected_source, @processed_source.path) - _investigate(@cop, @processed_source) + _investigate(cop, @processed_source) end assert_equal(correction, new_source) diff --git a/test/rubocop/cop/minitest/assert_offense_test.rb b/test/rubocop/cop/minitest/assert_offense_test.rb new file mode 100644 index 00000000..ecd9951f --- /dev/null +++ b/test/rubocop/cop/minitest/assert_offense_test.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require_relative '../../../test_helper' + +class AssertOffenseTest + class CopNotDefinedTest < Minitest::Test + def test_correct_failure_is_raised_when_cop_is_not_defined + error = assert_raises RuntimeError do + assert_offense(<<~RUBY) + class FooTest < Minitest::Test + def test_do_something + assert_equal(nil, somestuff) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `assert_nil(somestuff)`. + end + end + RUBY + end + + assert_includes error.message, 'Cop not defined' + end + end +end diff --git a/test/rubocop/cop/minitest/test_file_name_test.rb b/test/rubocop/cop/minitest/test_file_name_test.rb index b38d1b04..03d2ae81 100644 --- a/test/rubocop/cop/minitest/test_file_name_test.rb +++ b/test/rubocop/cop/minitest/test_file_name_test.rb @@ -4,7 +4,7 @@ class TestFileNameTest < Minitest::Test def test_registers_offense_for_invalid_path - offenses = inspect_source(<<~RUBY, @cop, 'lib/foo.rb') + offenses = inspect_source(<<~RUBY, cop, 'lib/foo.rb') class FooTest < Minitest::Test end RUBY @@ -15,7 +15,7 @@ class FooTest < Minitest::Test end def test_registers_offense_for_namespaced_invalid_path - offenses = inspect_source(<<~RUBY, @cop, 'lib/foo/bar.rb') + offenses = inspect_source(<<~RUBY, cop, 'lib/foo/bar.rb') module Foo class BarTest < Minitest::Test end From e901adf35423c4450a911988deaf900730c905ba Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Fri, 23 Aug 2024 17:38:02 +0200 Subject: [PATCH 3/7] Fix an error for `Minitest/SkipEnsure` when only `ensure` has a body --- changelog/fix_error_skip_ensure.md | 1 + lib/rubocop/cop/minitest/skip_ensure.rb | 4 +++- test/rubocop/cop/minitest/skip_ensure_test.rb | 9 +++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 changelog/fix_error_skip_ensure.md diff --git a/changelog/fix_error_skip_ensure.md b/changelog/fix_error_skip_ensure.md new file mode 100644 index 00000000..6ee410fd --- /dev/null +++ b/changelog/fix_error_skip_ensure.md @@ -0,0 +1 @@ +* [#314](https://github.com/rubocop/rubocop-minitest/pull/314): Fix an error for `Minitest/SkipEnsure` when only `ensure` has a body. ([@earlopain][]) diff --git a/lib/rubocop/cop/minitest/skip_ensure.rb b/lib/rubocop/cop/minitest/skip_ensure.rb index 8a52c11a..9ff6bd21 100644 --- a/lib/rubocop/cop/minitest/skip_ensure.rb +++ b/lib/rubocop/cop/minitest/skip_ensure.rb @@ -75,7 +75,9 @@ def on_ensure(node) private def find_skip(node) - node.node_parts.first.descendants.detect { |n| n.send_type? && n.receiver.nil? && n.method?(:skip) } + return unless (body = node.node_parts.first) + + body.descendants.detect { |n| n.send_type? && n.receiver.nil? && n.method?(:skip) } end def use_skip_in_rescue?(skip_method) diff --git a/test/rubocop/cop/minitest/skip_ensure_test.rb b/test/rubocop/cop/minitest/skip_ensure_test.rb index e80be68d..dc2ccd9c 100644 --- a/test/rubocop/cop/minitest/skip_ensure_test.rb +++ b/test/rubocop/cop/minitest/skip_ensure_test.rb @@ -119,4 +119,13 @@ def test_skip_with_receiver end RUBY end + + def test_registers_no_offese_when_ensure_only + assert_no_offenses(<<~RUBY) + def test_ensure_only + ensure + do_something + end + RUBY + end end From 53d197d31de4796f5783a929cfcee3b76f6b89bd Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Fri, 23 Aug 2024 18:01:39 +0200 Subject: [PATCH 4/7] Fix an error for `Minitest/MultipleAssertions` when using for-style loops They produce an assign node, but the value is part of the parent for node --- changelog/fix_error_multiple_assertions.md | 1 + lib/rubocop/cop/minitest/multiple_assertions.rb | 6 +++++- .../cop/minitest/multiple_assertions_test.rb | 14 ++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 changelog/fix_error_multiple_assertions.md diff --git a/changelog/fix_error_multiple_assertions.md b/changelog/fix_error_multiple_assertions.md new file mode 100644 index 00000000..8f3c6bbd --- /dev/null +++ b/changelog/fix_error_multiple_assertions.md @@ -0,0 +1 @@ +* [#317](https://github.com/rubocop/rubocop-minitest/pull/317): Fix an error for `Minitest/MultipleAssertions` when using for-style loops. ([@earlopain][]) diff --git a/lib/rubocop/cop/minitest/multiple_assertions.rb b/lib/rubocop/cop/minitest/multiple_assertions.rb index 388ad601..0696eafa 100644 --- a/lib/rubocop/cop/minitest/multiple_assertions.rb +++ b/lib/rubocop/cop/minitest/multiple_assertions.rb @@ -75,7 +75,11 @@ def assertions_count_based_on_type(node) end def assertions_count_in_assignment(node) - return assertions_count_based_on_type(node.expression) unless node.masgn_type? + unless node.masgn_type? + return 0 unless node.expression # for-style loop + + return assertions_count_based_on_type(node.expression) + end rhs = node.children.last diff --git a/test/rubocop/cop/minitest/multiple_assertions_test.rb b/test/rubocop/cop/minitest/multiple_assertions_test.rb index b47d6662..0509c12f 100644 --- a/test/rubocop/cop/minitest/multiple_assertions_test.rb +++ b/test/rubocop/cop/minitest/multiple_assertions_test.rb @@ -616,6 +616,20 @@ class FooTest < ActiveSupport::TestCase RUBY end + def test_registers_offense_when_for_style_loop + assert_offense(<<~RUBY) + class FooTest < Minitest::Test + def test_asserts_twice + ^^^^^^^^^^^^^^^^^^^^^^ Test case has too many assertions [2/1]. + assert_equal(foo, bar) + for baz in [1, 2] + assert_equal(baz, 1) + end + end + end + RUBY + end + def test_registers_offense_when_complex_multiple_assignment_structure_and_multiple_assertions skip 'FIXME: The shared `@cop` instance variable causes flaky tests due to state changes.' From bec9cbbbd77c7792863b5c3d7b7583e85298fddb Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Sat, 24 Aug 2024 11:48:41 +0200 Subject: [PATCH 5/7] Enable `InternalAffairs/UndefinedConfig` The described problem doesn't occur anymore --- .rubocop.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 7fc88a4d..2eda3d2a 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -15,10 +15,6 @@ AllCops: InternalAffairs/NodeMatcherDirective: Enabled: false -# FIXME: Workaround for a false positive caused by this cop when using `bundle exec rake`. -InternalAffairs/UndefinedConfig: - Enabled: false - Naming/PredicateName: # Method define macros for dynamically generated method. MethodDefinitionMacros: From a7452b720b05145a3e2080888be58de579c9c020 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 31 Aug 2024 17:58:43 +0900 Subject: [PATCH 6/7] Update Changelog --- CHANGELOG.md | 10 ++++++++++ ...e_assert_offense_setup_fails_with_useful_message.md | 1 - changelog/fix_error_multiple_assertions.md | 1 - changelog/fix_error_skip_ensure.md | 1 - 4 files changed, 10 insertions(+), 3 deletions(-) delete mode 100644 changelog/change_assert_offense_setup_fails_with_useful_message.md delete mode 100644 changelog/fix_error_multiple_assertions.md delete mode 100644 changelog/fix_error_skip_ensure.md diff --git a/CHANGELOG.md b/CHANGELOG.md index c468335b..136eb28d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,15 @@ ## master (unreleased) +### Bug fixes + +* [#317](https://github.com/rubocop/rubocop-minitest/pull/317): Fix an error for `Minitest/MultipleAssertions` when using for-style loops. ([@earlopain][]) +* [#314](https://github.com/rubocop/rubocop-minitest/pull/314): Fix an error for `Minitest/SkipEnsure` when only `ensure` has a body. ([@earlopain][]) + +### Changes + +* [#314](https://github.com/rubocop/rubocop-minitest/pull/314): **(Breaking)** Raise a useful error when using a Cop in `AssertOffense` if the Cop's class is not defined. ([@brandoncc][]) + ## 0.35.1 (2024-07-11) ### New features @@ -615,3 +624,4 @@ [@amomchilov]: https://github.com/amomchilov [@earlopain]: https://github.com/earlopain [@jaredmoody]: https://github.com/jaredmoody +[@brandoncc]: https://github.com/brandoncc diff --git a/changelog/change_assert_offense_setup_fails_with_useful_message.md b/changelog/change_assert_offense_setup_fails_with_useful_message.md deleted file mode 100644 index 21a76c7f..00000000 --- a/changelog/change_assert_offense_setup_fails_with_useful_message.md +++ /dev/null @@ -1 +0,0 @@ -* [#314](https://github.com/rubocop/rubocop-minitest/pull/314): **(Breaking)** Raise a useful error when using a Cop in `AssertOffense` if the Cop's class is not defined. ([@brandoncc][]) diff --git a/changelog/fix_error_multiple_assertions.md b/changelog/fix_error_multiple_assertions.md deleted file mode 100644 index 8f3c6bbd..00000000 --- a/changelog/fix_error_multiple_assertions.md +++ /dev/null @@ -1 +0,0 @@ -* [#317](https://github.com/rubocop/rubocop-minitest/pull/317): Fix an error for `Minitest/MultipleAssertions` when using for-style loops. ([@earlopain][]) diff --git a/changelog/fix_error_skip_ensure.md b/changelog/fix_error_skip_ensure.md deleted file mode 100644 index 6ee410fd..00000000 --- a/changelog/fix_error_skip_ensure.md +++ /dev/null @@ -1 +0,0 @@ -* [#314](https://github.com/rubocop/rubocop-minitest/pull/314): Fix an error for `Minitest/SkipEnsure` when only `ensure` has a body. ([@earlopain][]) From 68aed47e52f6d9848cbcac91be7a043a1b93d003 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 31 Aug 2024 17:58:55 +0900 Subject: [PATCH 7/7] Cut 0.36.0 --- CHANGELOG.md | 2 ++ docs/antora.yml | 2 +- lib/rubocop/minitest/version.rb | 2 +- relnotes/v0.36.0.md | 11 +++++++++++ 4 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 relnotes/v0.36.0.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 136eb28d..b29c3a5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ ## master (unreleased) +## 0.36.0 (2024-08-31) + ### Bug fixes * [#317](https://github.com/rubocop/rubocop-minitest/pull/317): Fix an error for `Minitest/MultipleAssertions` when using for-style loops. ([@earlopain][]) diff --git a/docs/antora.yml b/docs/antora.yml index 02c36842..1234f9d7 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -2,6 +2,6 @@ name: rubocop-minitest title: RuboCop Minitest # We always provide version without patch here (e.g. 1.1), # as patch versions should not appear in the docs. -version: ~ +version: '0.36' nav: - modules/ROOT/nav.adoc diff --git a/lib/rubocop/minitest/version.rb b/lib/rubocop/minitest/version.rb index 6dbe51cf..00bdd1fb 100644 --- a/lib/rubocop/minitest/version.rb +++ b/lib/rubocop/minitest/version.rb @@ -4,7 +4,7 @@ module RuboCop module Minitest # This module holds the RuboCop Minitest version information. module Version - STRING = '0.35.1' + STRING = '0.36.0' def self.document_version STRING.match('\d+\.\d+').to_s diff --git a/relnotes/v0.36.0.md b/relnotes/v0.36.0.md new file mode 100644 index 00000000..3d5b8c6a --- /dev/null +++ b/relnotes/v0.36.0.md @@ -0,0 +1,11 @@ +### Bug fixes + +* [#317](https://github.com/rubocop/rubocop-minitest/pull/317): Fix an error for `Minitest/MultipleAssertions` when using for-style loops. ([@earlopain][]) +* [#314](https://github.com/rubocop/rubocop-minitest/pull/314): Fix an error for `Minitest/SkipEnsure` when only `ensure` has a body. ([@earlopain][]) + +### Changes + +* [#314](https://github.com/rubocop/rubocop-minitest/pull/314): **(Breaking)** Raise a useful error when using a Cop in `AssertOffense` if the Cop's class is not defined. ([@brandoncc][]) + +[@earlopain]: https://github.com/earlopain +[@brandoncc]: https://github.com/brandoncc