rubocop-minitest 0.6.2 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +0 -3
  3. data/.gitattributes +1 -0
  4. data/.rubocop.yml +2 -1
  5. data/.rubocop_todo.yml +0 -7
  6. data/CHANGELOG.md +65 -0
  7. data/Gemfile +1 -1
  8. data/README.md +5 -1
  9. data/Rakefile +29 -0
  10. data/config/default.yml +103 -18
  11. data/docs/antora.yml +7 -0
  12. data/docs/modules/ROOT/nav.adoc +6 -0
  13. data/docs/modules/ROOT/pages/cops.adoc +37 -0
  14. data/docs/modules/ROOT/pages/cops_minitest.adoc +1014 -0
  15. data/docs/modules/ROOT/pages/index.adoc +5 -0
  16. data/docs/modules/ROOT/pages/installation.adoc +15 -0
  17. data/docs/modules/ROOT/pages/usage.adoc +32 -0
  18. data/{manual → legacy-docs}/cops.md +1 -0
  19. data/{manual → legacy-docs}/cops_minitest.md +64 -41
  20. data/{manual → legacy-docs}/index.md +0 -0
  21. data/{manual → legacy-docs}/installation.md +0 -0
  22. data/{manual → legacy-docs}/usage.md +0 -0
  23. data/lib/rubocop/cop/generator.rb +56 -0
  24. data/lib/rubocop/cop/minitest/assert_empty.rb +4 -30
  25. data/lib/rubocop/cop/minitest/assert_empty_literal.rb +15 -0
  26. data/lib/rubocop/cop/minitest/assert_equal.rb +2 -31
  27. data/lib/rubocop/cop/minitest/assert_in_delta.rb +27 -0
  28. data/lib/rubocop/cop/minitest/assert_includes.rb +4 -4
  29. data/lib/rubocop/cop/minitest/assert_instance_of.rb +4 -38
  30. data/lib/rubocop/cop/minitest/assert_kind_of.rb +25 -0
  31. data/lib/rubocop/cop/minitest/assert_match.rb +4 -39
  32. data/lib/rubocop/cop/minitest/assert_nil.rb +2 -2
  33. data/lib/rubocop/cop/minitest/assert_output.rb +49 -0
  34. data/lib/rubocop/cop/minitest/assert_path_exists.rb +58 -0
  35. data/lib/rubocop/cop/minitest/assert_respond_to.rb +10 -45
  36. data/lib/rubocop/cop/minitest/assert_silent.rb +45 -0
  37. data/lib/rubocop/cop/minitest/assert_truthy.rb +2 -2
  38. data/lib/rubocop/cop/minitest/assertion_in_lifecycle_hook.rb +43 -0
  39. data/lib/rubocop/cop/minitest/global_expectations.rb +95 -0
  40. data/lib/rubocop/cop/minitest/literal_as_actual_argument.rb +52 -0
  41. data/lib/rubocop/cop/minitest/multiple_assertions.rb +63 -0
  42. data/lib/rubocop/cop/minitest/refute_empty.rb +4 -30
  43. data/lib/rubocop/cop/minitest/refute_false.rb +3 -3
  44. data/lib/rubocop/cop/minitest/refute_in_delta.rb +27 -0
  45. data/lib/rubocop/cop/minitest/refute_includes.rb +4 -4
  46. data/lib/rubocop/cop/minitest/refute_instance_of.rb +4 -38
  47. data/lib/rubocop/cop/minitest/refute_kind_of.rb +25 -0
  48. data/lib/rubocop/cop/minitest/refute_match.rb +4 -39
  49. data/lib/rubocop/cop/minitest/refute_nil.rb +2 -2
  50. data/lib/rubocop/cop/minitest/refute_path_exists.rb +58 -0
  51. data/lib/rubocop/cop/minitest/refute_respond_to.rb +10 -45
  52. data/lib/rubocop/cop/minitest/test_method_name.rb +70 -0
  53. data/lib/rubocop/cop/minitest/unspecified_exception.rb +36 -0
  54. data/lib/rubocop/cop/minitest_cops.rb +17 -1
  55. data/lib/rubocop/cop/mixin/argument_range_helper.rb +10 -0
  56. data/lib/rubocop/cop/mixin/in_delta_mixin.rb +50 -0
  57. data/lib/rubocop/cop/mixin/minitest_cop_rule.rb +102 -0
  58. data/lib/rubocop/cop/mixin/minitest_exploration_helpers.rb +84 -0
  59. data/lib/rubocop/minitest/version.rb +1 -1
  60. data/mkdocs.yml +2 -2
  61. data/relnotes/v0.10.0.md +21 -0
  62. data/relnotes/v0.6.2.md +5 -0
  63. data/relnotes/v0.7.0.md +13 -0
  64. data/relnotes/v0.8.0.md +12 -0
  65. data/relnotes/v0.8.1.md +5 -0
  66. data/relnotes/v0.9.0.md +10 -0
  67. data/rubocop-minitest.gemspec +4 -4
  68. data/tasks/cops_documentation.rake +83 -52
  69. data/tasks/cut_release.rake +16 -0
  70. metadata +45 -15
  71. data/lib/rubocop/cop/mixin/includes_cop_rule.rb +0 -78
@@ -9,11 +9,11 @@ module RuboCop
9
9
  # @example
10
10
  # # bad
11
11
  # assert_equal(true, actual)
12
- # assert_equal(true, actual, 'the message')
12
+ # assert_equal(true, actual, 'message')
13
13
  #
14
14
  # # good
15
15
  # assert(actual)
16
- # assert(actual, 'the message')
16
+ # assert(actual, 'message')
17
17
  #
18
18
  class AssertTruthy < Cop
19
19
  include ArgumentRangeHelper
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Minitest
6
+ # This cop checks for usage of assertions in lifecycle hooks.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # class FooTest < Minitest::Test
11
+ # def setup
12
+ # assert_equal(foo, bar)
13
+ # end
14
+ # end
15
+ #
16
+ # # good
17
+ # class FooTest < Minitest::Test
18
+ # def test_something
19
+ # assert_equal(foo, bar)
20
+ # end
21
+ # end
22
+ #
23
+ class AssertionInLifecycleHook < Cop
24
+ include MinitestExplorationHelpers
25
+
26
+ MSG = 'Do not use `%<assertion>s` in `%<hook>s` hook.'
27
+
28
+ def on_class(class_node)
29
+ return unless test_class?(class_node)
30
+
31
+ lifecycle_hooks(class_node).each do |hook_node|
32
+ hook_node.each_descendant(:send) do |node|
33
+ if assertion?(node)
34
+ message = format(MSG, assertion: node.method_name, hook: hook_node.method_name)
35
+ add_offense(node, message: message)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Minitest
6
+ # This cop checks for deprecated global expectations
7
+ # and autocorrects them to use expect format.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # musts.must_equal expected_musts
12
+ # wonts.wont_match expected_wonts
13
+ # musts.must_raise TypeError
14
+ #
15
+ # # good
16
+ # _(musts).must_equal expected_musts
17
+ # _(wonts).wont_match expected_wonts
18
+ # _ { musts }.must_raise TypeError
19
+ class GlobalExpectations < Cop
20
+ MSG = 'Use `%<preferred>s` instead.'
21
+
22
+ VALUE_MATCHERS = %i[
23
+ must_be_empty must_equal must_be_close_to must_be_within_delta
24
+ must_be_within_epsilon must_include must_be_instance_of must_be_kind_of
25
+ must_match must_be_nil must_be must_respond_to must_be_same_as
26
+ path_must_exist path_wont_exist wont_be_empty wont_equal wont_be_close_to
27
+ wont_be_within_delta wont_be_within_epsilon wont_include wont_be_instance_of
28
+ wont_be_kind_of wont_match wont_be_nil wont_be wont_respond_to wont_be_same_as
29
+ ].freeze
30
+
31
+ BLOCK_MATCHERS = %i[must_output must_raise must_be_silent must_throw].freeze
32
+
33
+ VALUE_MATCHERS_STR = VALUE_MATCHERS.map do |m|
34
+ ":#{m}"
35
+ end.join(' ').freeze
36
+
37
+ BLOCK_MATCHERS_STR = BLOCK_MATCHERS.map do |m|
38
+ ":#{m}"
39
+ end.join(' ').freeze
40
+
41
+ # There are aliases for the `_` method - `expect` and `value`
42
+ DSL_METHODS_LIST = %w[_ value expect].map do |n|
43
+ ":#{n}"
44
+ end.join(' ').freeze
45
+
46
+ def_node_matcher :value_global_expectation?, <<~PATTERN
47
+ (send !(send nil? {#{DSL_METHODS_LIST}} _) {#{VALUE_MATCHERS_STR}} ...)
48
+ PATTERN
49
+
50
+ def_node_matcher :block_global_expectation?, <<~PATTERN
51
+ (send
52
+ [
53
+ !(send nil? {#{DSL_METHODS_LIST}} _)
54
+ !(block (send nil? {#{DSL_METHODS_LIST}}) _ _)
55
+ ]
56
+ {#{BLOCK_MATCHERS_STR}}
57
+ _
58
+ )
59
+ PATTERN
60
+
61
+ def on_send(node)
62
+ return unless value_global_expectation?(node) || block_global_expectation?(node)
63
+
64
+ message = format(MSG, preferred: preferred_receiver(node))
65
+ add_offense(node, location: node.receiver.source_range, message: message)
66
+ end
67
+
68
+ def autocorrect(node)
69
+ return unless value_global_expectation?(node) || block_global_expectation?(node)
70
+
71
+ lambda do |corrector|
72
+ receiver = node.receiver.source_range
73
+
74
+ if BLOCK_MATCHERS.include?(node.method_name)
75
+ corrector.wrap(receiver, '_ { ', ' }')
76
+ else
77
+ corrector.wrap(receiver, '_(', ')')
78
+ end
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ def preferred_receiver(node)
85
+ source = node.receiver.source
86
+ if BLOCK_MATCHERS.include?(node.method_name)
87
+ "_ { #{source} }"
88
+ else
89
+ "_(#{source})"
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Minitest
6
+ # This cop enforces correct order of expected and
7
+ # actual arguments for `assert_equal`.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # assert_equal foo, 2
12
+ # assert_equal foo, [1, 2]
13
+ # assert_equal foo, [1, 2], 'message'
14
+ #
15
+ # # good
16
+ # assert_equal 2, foo
17
+ # assert_equal [1, 2], foo
18
+ # assert_equal [1, 2], foo, 'message'
19
+ #
20
+ class LiteralAsActualArgument < Cop
21
+ include ArgumentRangeHelper
22
+
23
+ MSG = 'Replace the literal with the first argument.'
24
+
25
+ def on_send(node)
26
+ return unless node.method?(:assert_equal)
27
+
28
+ actual = node.arguments[1]
29
+ return unless actual
30
+
31
+ add_offense(node, location: all_arguments_range(node)) if actual.recursive_basic_literal?
32
+ end
33
+
34
+ def autocorrect(node)
35
+ expected, actual, message = *node.arguments
36
+
37
+ lambda do |corrector|
38
+ new_actual_source =
39
+ if actual.hash_type? && !actual.braces?
40
+ "{#{actual.source}}"
41
+ else
42
+ actual.source
43
+ end
44
+ arguments = [new_actual_source, expected.source, message&.source].compact.join(', ')
45
+
46
+ corrector.replace(node, "assert_equal(#{arguments})")
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Minitest
6
+ # This cop checks if test cases contain too many assertion calls.
7
+ # The maximum allowed assertion calls is configurable.
8
+ #
9
+ # @example Max: 1
10
+ # # bad
11
+ # class FooTest < Minitest::Test
12
+ # def test_asserts_twice
13
+ # assert_equal(42, do_something)
14
+ # assert_empty(array)
15
+ # end
16
+ # end
17
+ #
18
+ # # good
19
+ # class FooTest < Minitest::Test
20
+ # def test_asserts_once
21
+ # assert_equal(42, do_something)
22
+ # end
23
+ #
24
+ # def test_another_asserts_once
25
+ # assert_empty(array)
26
+ # end
27
+ # end
28
+ #
29
+ class MultipleAssertions < Cop
30
+ include ConfigurableMax
31
+ include MinitestExplorationHelpers
32
+
33
+ MSG = 'Test case has too many assertions [%<total>d/%<max>d].'
34
+
35
+ def on_class(class_node)
36
+ return unless test_class?(class_node)
37
+
38
+ test_cases(class_node).each do |node|
39
+ assertions_count = assertions_count(node)
40
+
41
+ next unless assertions_count > max_assertions
42
+
43
+ self.max = assertions_count
44
+
45
+ message = format(MSG, total: assertions_count, max: max_assertions)
46
+ add_offense(node, location: :name, message: message)
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def assertions_count(node)
53
+ base = assertion?(node) ? 1 : 0
54
+ base + node.each_child_node.sum { |c| assertions_count(c) }
55
+ end
56
+
57
+ def max_assertions
58
+ Integer(cop_config.fetch('Max', 3))
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -9,42 +9,16 @@ module RuboCop
9
9
  # @example
10
10
  # # bad
11
11
  # refute(object.empty?)
12
- # refute(object.empty?, 'the message')
12
+ # refute(object.empty?, 'message')
13
13
  #
14
14
  # # good
15
15
  # refute_empty(object)
16
- # refute_empty(object, 'the message')
16
+ # refute_empty(object, 'message')
17
17
  #
18
18
  class RefuteEmpty < Cop
19
- include ArgumentRangeHelper
19
+ extend MinitestCopRule
20
20
 
21
- MSG = 'Prefer using `refute_empty(%<arguments>s)` over ' \
22
- '`refute(%<receiver>s)`.'
23
-
24
- def_node_matcher :refute_with_empty, <<~PATTERN
25
- (send nil? :refute $(send $_ :empty?) $...)
26
- PATTERN
27
-
28
- def on_send(node)
29
- refute_with_empty(node) do |first_receiver_arg, object, rest_receiver_arg|
30
- message = rest_receiver_arg.first
31
-
32
- arguments = [object.source, message&.source].compact.join(', ')
33
- receiver = [first_receiver_arg.source, message&.source].compact.join(', ')
34
-
35
- offense_message = format(MSG, arguments: arguments, receiver: receiver)
36
- add_offense(node, message: offense_message)
37
- end
38
- end
39
-
40
- def autocorrect(node)
41
- lambda do |corrector|
42
- refute_with_empty(node) do |_, actual_arg|
43
- corrector.replace(node.loc.selector, 'refute_empty')
44
- corrector.replace(first_argument_range(node), actual_arg.source)
45
- end
46
- end
47
- end
21
+ define_rule :refute, target_method: :empty?
48
22
  end
49
23
  end
50
24
  end
@@ -9,14 +9,14 @@ module RuboCop
9
9
  # @example
10
10
  # # bad
11
11
  # assert_equal(false, actual)
12
- # assert_equal(false, actual, 'the message')
12
+ # assert_equal(false, actual, 'message')
13
13
  #
14
14
  # assert(!test)
15
- # assert(!test, 'the message')
15
+ # assert(!test, 'message')
16
16
  #
17
17
  # # good
18
18
  # refute(actual)
19
- # refute(actual, 'the message')
19
+ # refute(actual, 'message')
20
20
  #
21
21
  class RefuteFalse < Cop
22
22
  include ArgumentRangeHelper
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Minitest
6
+ # This cop enforces the test to use `refute_in_delta`
7
+ # instead of using `refute_equal` to compare floats.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # refute_equal(0.2, actual)
12
+ # refute_equal(0.2, actual, 'message')
13
+ #
14
+ # # good
15
+ # refute_in_delta(0.2, actual)
16
+ # refute_in_delta(0.2, actual, 0.001, 'message')
17
+ #
18
+ class RefuteInDelta < Cop
19
+ include InDeltaMixin
20
+
21
+ def_node_matcher :equal_floats_call, <<~PATTERN
22
+ (send nil? :refute_equal $_ $_ $...)
23
+ PATTERN
24
+ end
25
+ end
26
+ end
27
+ end
@@ -9,16 +9,16 @@ module RuboCop
9
9
  # @example
10
10
  # # bad
11
11
  # refute(collection.include?(object))
12
- # refute(collection.include?(object), 'the message')
12
+ # refute(collection.include?(object), 'message')
13
13
  #
14
14
  # # good
15
15
  # refute_includes(collection, object)
16
- # refute_includes(collection, object, 'the message')
16
+ # refute_includes(collection, object, 'message')
17
17
  #
18
18
  class RefuteIncludes < Cop
19
- extend IncludesCopRule
19
+ extend MinitestCopRule
20
20
 
21
- rule target_method: :refute, prefer_method: :refute_includes
21
+ define_rule :refute, target_method: :include?, preferred_method: :refute_includes
22
22
  end
23
23
  end
24
24
  end
@@ -9,50 +9,16 @@ module RuboCop
9
9
  # @example
10
10
  # # bad
11
11
  # refute(object.instance_of?(Class))
12
- # refute(object.instance_of?(Class), 'the message')
12
+ # refute(object.instance_of?(Class), 'message')
13
13
  #
14
14
  # # good
15
15
  # refute_instance_of(Class, object)
16
- # refute_instance_of(Class, object, 'the message')
16
+ # refute_instance_of(Class, object, 'message')
17
17
  #
18
18
  class RefuteInstanceOf < Cop
19
- include ArgumentRangeHelper
19
+ extend MinitestCopRule
20
20
 
21
- MSG = 'Prefer using `refute_instance_of(%<arguments>s)` over ' \
22
- '`refute(%<receiver>s)`.'
23
-
24
- def_node_matcher :refute_with_instance_of, <<~PATTERN
25
- (send nil? :refute $(send $_ :instance_of? $_) $...)
26
- PATTERN
27
-
28
- def on_send(node)
29
- refute_with_instance_of(node) do |first_receiver_arg, object, method, rest_args|
30
- message = rest_args.first
31
- arguments = node_arguments(object, method, message)
32
- receiver = [first_receiver_arg.source, message&.source].compact.join(', ')
33
-
34
- offense_message = format(MSG, arguments: arguments, receiver: receiver)
35
-
36
- add_offense(node, message: offense_message)
37
- end
38
- end
39
-
40
- def autocorrect(node)
41
- lambda do |corrector|
42
- refute_with_instance_of(node) do |_, object, method|
43
- corrector.replace(node.loc.selector, 'refute_instance_of')
44
-
45
- replacement = [method, object].map(&:source).join(', ')
46
- corrector.replace(first_argument_range(node), replacement)
47
- end
48
- end
49
- end
50
-
51
- private
52
-
53
- def node_arguments(object, method, message)
54
- [method, object, message].compact.map(&:source).join(', ')
55
- end
21
+ define_rule :refute, target_method: :instance_of?, inverse: true
56
22
  end
57
23
  end
58
24
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Minitest
6
+ # This cop enforces the use of `refute_kind_of(Class, object)`
7
+ # over `refute(object.kind_of?(Class))`.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # refute(object.kind_of?(Class))
12
+ # refute(object.kind_of?(Class), 'message')
13
+ #
14
+ # # good
15
+ # refute_kind_of(Class, object)
16
+ # refute_kind_of(Class, object, 'message')
17
+ #
18
+ class RefuteKindOf < Cop
19
+ extend MinitestCopRule
20
+
21
+ define_rule :refute, target_method: :kind_of?, inverse: true
22
+ end
23
+ end
24
+ end
25
+ end