rubocop-minitest 0.6.2 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
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