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
@@ -14,38 +14,9 @@ module RuboCop
14
14
  # assert_equal("rubocop-minitest", actual)
15
15
  #
16
16
  class AssertEqual < Cop
17
- include ArgumentRangeHelper
17
+ extend MinitestCopRule
18
18
 
19
- MSG = 'Prefer using `assert_equal(%<preferred>s)` over ' \
20
- '`assert(%<over>s)`.'
21
-
22
- def_node_matcher :assert_equal, <<~PATTERN
23
- (send nil? :assert $(send $_ :== $_) $...)
24
- PATTERN
25
-
26
- def on_send(node)
27
- assert_equal(node) do |first_receiver_arg, expected, actual, rest_receiver_arg|
28
- message = rest_receiver_arg.first
29
- preferred = [expected.source, actual.source, message&.source]
30
- .compact.join(', ')
31
- over = [first_receiver_arg.source, message&.source].compact.join(', ')
32
-
33
- offense_message = format(MSG, preferred: preferred, over: over)
34
-
35
- add_offense(node, message: offense_message)
36
- end
37
- end
38
-
39
- def autocorrect(node)
40
- lambda do |corrector|
41
- assert_equal(node) do |_, expected, actual|
42
- corrector.replace(node.loc.selector, 'assert_equal')
43
-
44
- replacement = [expected, actual].map(&:source).join(', ')
45
- corrector.replace(first_argument_range(node), replacement)
46
- end
47
- end
48
- end
19
+ define_rule :assert, target_method: :==, preferred_method: :assert_equal
49
20
  end
50
21
  end
51
22
  end
@@ -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 `assert_in_delta`
7
+ # instead of using `assert_equal` to compare floats.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # assert_equal(0.2, actual)
12
+ # assert_equal(0.2, actual, 'message')
13
+ #
14
+ # # good
15
+ # assert_in_delta(0.2, actual)
16
+ # assert_in_delta(0.2, actual, 0.001, 'message')
17
+ #
18
+ class AssertInDelta < Cop
19
+ include InDeltaMixin
20
+
21
+ def_node_matcher :equal_floats_call, <<~PATTERN
22
+ (send nil? :assert_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
  # assert(collection.include?(object))
12
- # assert(collection.include?(object), 'the message')
12
+ # assert(collection.include?(object), 'message')
13
13
  #
14
14
  # # good
15
15
  # assert_includes(collection, object)
16
- # assert_includes(collection, object, 'the message')
16
+ # assert_includes(collection, object, 'message')
17
17
  #
18
18
  class AssertIncludes < Cop
19
- extend IncludesCopRule
19
+ extend MinitestCopRule
20
20
 
21
- rule target_method: :assert, prefer_method: :assert_includes
21
+ define_rule :assert, target_method: :include?, preferred_method: :assert_includes
22
22
  end
23
23
  end
24
24
  end
@@ -9,50 +9,16 @@ module RuboCop
9
9
  # @example
10
10
  # # bad
11
11
  # assert(object.instance_of?(Class))
12
- # assert(object.instance_of?(Class), 'the message')
12
+ # assert(object.instance_of?(Class), 'message')
13
13
  #
14
14
  # # good
15
15
  # assert_instance_of(Class, object)
16
- # assert_instance_of(Class, object, 'the message')
16
+ # assert_instance_of(Class, object, 'message')
17
17
  #
18
18
  class AssertInstanceOf < Cop
19
- include ArgumentRangeHelper
19
+ extend MinitestCopRule
20
20
 
21
- MSG = 'Prefer using `assert_instance_of(%<arguments>s)` over ' \
22
- '`assert(%<receiver>s)`.'
23
-
24
- def_node_matcher :assert_with_instance_of, <<~PATTERN
25
- (send nil? :assert $(send $_ :instance_of? $_) $...)
26
- PATTERN
27
-
28
- def on_send(node)
29
- assert_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
- assert_with_instance_of(node) do |_, object, method|
43
- corrector.replace(node.loc.selector, 'assert_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 :assert, 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 test to use `assert_kind_of(Class, object)`
7
+ # over `assert(object.kind_of?(Class))`.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # assert(object.kind_of?(Class))
12
+ # assert(object.kind_of?(Class), 'message')
13
+ #
14
+ # # good
15
+ # assert_kind_of(Class, object)
16
+ # assert_kind_of(Class, object, 'message')
17
+ #
18
+ class AssertKindOf < Cop
19
+ extend MinitestCopRule
20
+
21
+ define_rule :assert, target_method: :kind_of?, inverse: true
22
+ end
23
+ end
24
+ end
25
+ end
@@ -9,51 +9,16 @@ module RuboCop
9
9
  # @example
10
10
  # # bad
11
11
  # assert(matcher.match(string))
12
- # assert(matcher.match(string), 'the message')
12
+ # assert(matcher.match(string), 'message')
13
13
  #
14
14
  # # good
15
15
  # assert_match(regex, string)
16
- # assert_match(matcher, string, 'the message')
16
+ # assert_match(matcher, string, 'message')
17
17
  #
18
18
  class AssertMatch < Cop
19
- include ArgumentRangeHelper
19
+ extend MinitestCopRule
20
20
 
21
- MSG = 'Prefer using `assert_match(%<arguments>s)` over ' \
22
- '`assert(%<receiver>s)`.'
23
-
24
- def_node_matcher :assert_with_match, <<~PATTERN
25
- (send nil? :assert $(send $_ :match $_) $...)
26
- PATTERN
27
-
28
- def on_send(node)
29
- assert_with_match(node) do
30
- |first_receiver_arg, matcher, actual, rest_receiver_arg|
31
- message = rest_receiver_arg.first
32
- arguments = node_arguments(matcher, actual, message)
33
- receiver = [first_receiver_arg.source, message&.source].compact.join(', ')
34
-
35
- offense_message = format(MSG, arguments: arguments, receiver: receiver)
36
-
37
- add_offense(node, message: offense_message)
38
- end
39
- end
40
-
41
- def autocorrect(node)
42
- lambda do |corrector|
43
- assert_with_match(node) do |_, matcher, actual|
44
- corrector.replace(node.loc.selector, 'assert_match')
45
-
46
- replacement = [matcher, actual].map(&:source).join(', ')
47
- corrector.replace(first_argument_range(node), replacement)
48
- end
49
- end
50
- end
51
-
52
- private
53
-
54
- def node_arguments(matcher, actual, message)
55
- [matcher.source, actual.source, message&.source].compact.join(', ')
56
- end
21
+ define_rule :assert, target_method: :match
57
22
  end
58
23
  end
59
24
  end
@@ -9,11 +9,11 @@ module RuboCop
9
9
  # @example
10
10
  # # bad
11
11
  # assert_equal(nil, actual)
12
- # assert_equal(nil, actual, 'the message')
12
+ # assert_equal(nil, actual, 'message')
13
13
  #
14
14
  # # good
15
15
  # assert_nil(actual)
16
- # assert_nil(actual, 'the message')
16
+ # assert_nil(actual, 'message')
17
17
  #
18
18
  class AssertNil < Cop
19
19
  include ArgumentRangeHelper
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Minitest
6
+ # This cop checks for opportunities to use `assert_output`.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # $stdout = StringIO.new
11
+ # puts object.method
12
+ # $stdout.rewind
13
+ # assert_match expected, $stdout.read
14
+ #
15
+ # # good
16
+ # assert_output(expected) { puts object.method }
17
+ #
18
+ class AssertOutput < Cop
19
+ include MinitestExplorationHelpers
20
+
21
+ MSG = 'Use `assert_output` instead of mutating %<name>s.'
22
+ OUTPUT_GLOBAL_VARIABLES = %i[$stdout $stderr].freeze
23
+
24
+ def on_gvasgn(node)
25
+ test_case_node = find_test_case(node)
26
+ return unless test_case_node
27
+
28
+ gvar_name = node.children.first
29
+ return unless OUTPUT_GLOBAL_VARIABLES.include?(gvar_name)
30
+
31
+ assertions(test_case_node).each do |assertion|
32
+ add_offense(assertion, message: format(MSG, name: gvar_name)) if references_gvar?(assertion, gvar_name)
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def find_test_case(node)
39
+ def_ancestor = node.each_ancestor(:def).first
40
+ def_ancestor if test_case?(def_ancestor)
41
+ end
42
+
43
+ def references_gvar?(assertion, gvar_name)
44
+ assertion.each_descendant(:gvar).any? { |d| d.children.first == gvar_name }
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Minitest
6
+ # This cop enforces the test to use `assert_path_exists`
7
+ # instead of using `assert(File.exist?(path))`.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # assert(File.exist?(path))
12
+ # assert(File.exist?(path), 'message')
13
+ #
14
+ # # good
15
+ # assert_path_exists(path)
16
+ # assert_path_exists(path, 'message')
17
+ #
18
+ class AssertPathExists < Cop
19
+ MSG = 'Prefer using `%<good_method>s` over `%<bad_method>s`.'
20
+
21
+ def_node_matcher :assert_file_exists, <<~PATTERN
22
+ (send nil? :assert
23
+ (send
24
+ (const _ :File) {:exist? :exists?} $_)
25
+ $...)
26
+ PATTERN
27
+
28
+ def on_send(node)
29
+ assert_file_exists(node) do |path, failure_message|
30
+ failure_message = failure_message.first
31
+ good_method = build_good_method(path, failure_message)
32
+ message = format(MSG, good_method: good_method, bad_method: node.source)
33
+
34
+ add_offense(node, message: message)
35
+ end
36
+ end
37
+
38
+ def autocorrect(node)
39
+ assert_file_exists(node) do |path, failure_message|
40
+ failure_message = failure_message.first
41
+
42
+ lambda do |corrector|
43
+ replacement = build_good_method(path, failure_message)
44
+ corrector.replace(node, replacement)
45
+ end
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def build_good_method(path, message)
52
+ args = [path.source, message&.source].compact.join(', ')
53
+ "assert_path_exists(#{args})"
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -3,59 +3,24 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Minitest
6
- # This cop enforces the use of `assert_respond_to(object, :some_method)`
7
- # over `assert(object.respond_to?(:some_method))`.
6
+ # This cop enforces the use of `assert_respond_to(object, :do_something)`
7
+ # over `assert(object.respond_to?(:do_something))`.
8
8
  #
9
9
  # @example
10
10
  # # bad
11
- # assert(object.respond_to?(:some_method))
12
- # assert(object.respond_to?(:some_method), 'the message')
13
- # assert(respond_to?(:some_method))
11
+ # assert(object.respond_to?(:do_something))
12
+ # assert(object.respond_to?(:do_something), 'message')
13
+ # assert(respond_to?(:do_something))
14
14
  #
15
15
  # # good
16
- # assert_respond_to(object, :some_method)
17
- # assert_respond_to(object, :some_method, 'the message')
18
- # assert_respond_to(self, some_method)
16
+ # assert_respond_to(object, :do_something)
17
+ # assert_respond_to(object, :do_something, 'message')
18
+ # assert_respond_to(self, :do_something)
19
19
  #
20
20
  class AssertRespondTo < Cop
21
- include ArgumentRangeHelper
21
+ extend MinitestCopRule
22
22
 
23
- MSG = 'Prefer using `assert_respond_to(%<preferred>s)` over ' \
24
- '`assert(%<over>s)`.'
25
-
26
- def_node_matcher :assert_with_respond_to, <<~PATTERN
27
- (send nil? :assert $(send $_ :respond_to? $_) $...)
28
- PATTERN
29
-
30
- def on_send(node)
31
- assert_with_respond_to(node) do |over, object, method, rest_args|
32
- custom_message = rest_args.first
33
- preferred = build_preferred_arguments(object, method, custom_message)
34
- over = [over, custom_message].compact.map(&:source).join(', ')
35
- message = format(MSG, preferred: preferred, over: over)
36
- add_offense(node, message: message)
37
- end
38
- end
39
-
40
- def autocorrect(node)
41
- lambda do |corrector|
42
- assert_with_respond_to(node) do |_, object, method|
43
- corrector.replace(node.loc.selector, 'assert_respond_to')
44
-
45
- object = object ? object.source : 'self'
46
- replacement = [object, method.source].join(', ')
47
- corrector.replace(first_argument_range(node), replacement)
48
- end
49
- end
50
- end
51
-
52
- private
53
-
54
- def build_preferred_arguments(receiver, method, message)
55
- receiver = receiver ? receiver.source : 'self'
56
-
57
- [receiver, method.source, message&.source].compact.join(', ')
58
- end
23
+ define_rule :assert, target_method: :respond_to?
59
24
  end
60
25
  end
61
26
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Minitest
6
+ # This cop enforces the test to use `assert_silent { ... }`
7
+ # instead of using `assert_output('', '') { ... }`.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # assert_output('', '') { puts object.do_something }
12
+ #
13
+ # # good
14
+ # assert_silent { puts object.do_something }
15
+ #
16
+ class AssertSilent < Cop
17
+ MSG = 'Prefer using `assert_silent` over `assert_output("", "")`.'
18
+
19
+ def_node_matcher :assert_silent_candidate?, <<~PATTERN
20
+ (block
21
+ (send nil? :assert_output
22
+ #empty_string?
23
+ #empty_string?)
24
+ ...)
25
+ PATTERN
26
+
27
+ def on_block(node)
28
+ add_offense(node.send_node) if assert_silent_candidate?(node)
29
+ end
30
+
31
+ def autocorrect(node)
32
+ lambda do |corrector|
33
+ corrector.replace(node, 'assert_silent')
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def empty_string?(node)
40
+ node.str_type? && node.value.empty?
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end