rubocop-minitest 0.4.0 → 0.6.1

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 (40) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +3 -0
  3. data/.github/FUNDING.yml +2 -1
  4. data/.rubocop_todo.yml +5 -5
  5. data/CHANGELOG.md +32 -0
  6. data/Gemfile +1 -1
  7. data/LICENSE.txt +1 -1
  8. data/README.md +2 -2
  9. data/config/default.yml +17 -0
  10. data/lib/rubocop/cop/minitest/assert_empty.rb +5 -5
  11. data/lib/rubocop/cop/minitest/assert_empty_literal.rb +36 -0
  12. data/lib/rubocop/cop/minitest/assert_equal.rb +8 -13
  13. data/lib/rubocop/cop/minitest/assert_includes.rb +2 -37
  14. data/lib/rubocop/cop/minitest/assert_instance_of.rb +7 -8
  15. data/lib/rubocop/cop/minitest/assert_match.rb +60 -0
  16. data/lib/rubocop/cop/minitest/assert_nil.rb +8 -3
  17. data/lib/rubocop/cop/minitest/assert_respond_to.rb +20 -9
  18. data/lib/rubocop/cop/minitest/assert_truthy.rb +8 -3
  19. data/lib/rubocop/cop/minitest/refute_empty.rb +5 -5
  20. data/lib/rubocop/cop/minitest/refute_equal.rb +7 -8
  21. data/lib/rubocop/cop/minitest/refute_false.rb +38 -9
  22. data/lib/rubocop/cop/minitest/refute_includes.rb +2 -37
  23. data/lib/rubocop/cop/minitest/refute_instance_of.rb +7 -8
  24. data/lib/rubocop/cop/minitest/refute_match.rb +60 -0
  25. data/lib/rubocop/cop/minitest/refute_nil.rb +8 -3
  26. data/lib/rubocop/cop/minitest/refute_respond_to.rb +20 -9
  27. data/lib/rubocop/cop/minitest_cops.rb +5 -0
  28. data/lib/rubocop/cop/mixin/argument_range_helper.rb +31 -0
  29. data/lib/rubocop/cop/mixin/includes_cop_rule.rb +78 -0
  30. data/lib/rubocop/minitest/inject.rb +1 -1
  31. data/lib/rubocop/minitest/version.rb +1 -1
  32. data/manual/cops.md +3 -0
  33. data/manual/cops_minitest.md +77 -0
  34. data/relnotes/v0.4.1.md +5 -0
  35. data/relnotes/v0.5.0.md +5 -0
  36. data/relnotes/v0.5.1.md +5 -0
  37. data/relnotes/v0.6.0.md +5 -0
  38. data/relnotes/v0.6.1.md +6 -0
  39. data/rubocop-minitest.gemspec +2 -2
  40. metadata +16 -5
@@ -16,6 +16,8 @@ module RuboCop
16
16
  # assert(actual, 'the message')
17
17
  #
18
18
  class AssertTruthy < Cop
19
+ include ArgumentRangeHelper
20
+
19
21
  MSG = 'Prefer using `assert(%<arguments>s)` over ' \
20
22
  '`assert_equal(true, %<arguments>s)`.'
21
23
 
@@ -35,9 +37,12 @@ module RuboCop
35
37
 
36
38
  def autocorrect(node)
37
39
  lambda do |corrector|
38
- arguments = node.arguments.reject(&:true_type?)
39
- replacement = arguments.map(&:source).join(', ')
40
- corrector.replace(node.loc.expression, "assert(#{replacement})")
40
+ assert_equal_with_truthy(node) do |actual|
41
+ corrector.replace(node.loc.selector, 'assert')
42
+ corrector.replace(
43
+ first_and_second_arguments_range(node), actual.source
44
+ )
45
+ end
41
46
  end
42
47
  end
43
48
  end
@@ -16,6 +16,8 @@ module RuboCop
16
16
  # refute_empty(object, 'the message')
17
17
  #
18
18
  class RefuteEmpty < Cop
19
+ include ArgumentRangeHelper
20
+
19
21
  MSG = 'Prefer using `refute_empty(%<arguments>s)` over ' \
20
22
  '`refute(%<receiver>s)`.'
21
23
 
@@ -37,11 +39,9 @@ module RuboCop
37
39
 
38
40
  def autocorrect(node)
39
41
  lambda do |corrector|
40
- refute_with_empty(node) do |_first_receiver_arg, object, rest_receiver_arg|
41
- message = rest_receiver_arg.first
42
-
43
- replacement = [object.source, message&.source].compact.join(', ')
44
- corrector.replace(node.loc.expression, "refute_empty(#{replacement})")
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
45
  end
46
46
  end
47
47
  end
@@ -15,6 +15,8 @@ module RuboCop
15
15
  # refute_equal("rubocop-minitest", actual)
16
16
  #
17
17
  class RefuteEqual < Cop
18
+ include ArgumentRangeHelper
19
+
18
20
  MSG = 'Prefer using `refute_equal(%<preferred>s)` over ' \
19
21
  '`assert(%<over>s)`.'
20
22
 
@@ -32,20 +34,17 @@ module RuboCop
32
34
 
33
35
  def autocorrect(node)
34
36
  lambda do |corrector|
35
- assert_not_equal(node) do |_, first_arg, second_arg, rest_args|
36
- autocorrect_node(node, corrector, first_arg, second_arg, rest_args)
37
+ assert_not_equal(node) do |_, expected, actual|
38
+ corrector.replace(node.loc.selector, 'refute_equal')
39
+
40
+ replacement = [expected, actual].map(&:source).join(', ')
41
+ corrector.replace(first_argument_range(node), replacement)
37
42
  end
38
43
  end
39
44
  end
40
45
 
41
46
  private
42
47
 
43
- def autocorrect_node(node, corrector, first_arg, second_arg, rest_args)
44
- custom_message = rest_args.first
45
- replacement = preferred_usage(first_arg, second_arg, custom_message)
46
- corrector.replace(node.loc.expression, "refute_equal(#{replacement})")
47
- end
48
-
49
48
  def preferred_usage(first_arg, second_arg, custom_message = nil)
50
49
  [first_arg, second_arg, custom_message]
51
50
  .compact.map(&:source).join(', ')
@@ -11,33 +11,62 @@ module RuboCop
11
11
  # assert_equal(false, actual)
12
12
  # assert_equal(false, actual, 'the message')
13
13
  #
14
+ # assert(!test)
15
+ # assert(!test, 'the message')
16
+ #
14
17
  # # good
15
18
  # refute(actual)
16
19
  # refute(actual, 'the message')
17
20
  #
18
21
  class RefuteFalse < Cop
19
- MSG = 'Prefer using `refute(%<arguments>s)` over ' \
22
+ include ArgumentRangeHelper
23
+
24
+ MSG_FOR_ASSERT_EQUAL = 'Prefer using `refute(%<arguments>s)` over ' \
20
25
  '`assert_equal(false, %<arguments>s)`.'
26
+ MSG_FOR_ASSERT = 'Prefer using `refute(%<arguments>s)` over ' \
27
+ '`assert(!%<arguments>s)`.'
21
28
 
22
29
  def_node_matcher :assert_equal_with_false, <<~PATTERN
23
30
  (send nil? :assert_equal false $_ $...)
24
31
  PATTERN
25
32
 
33
+ def_node_matcher :assert_with_bang_argument, <<~PATTERN
34
+ (send nil? :assert (send $_ :!) $...)
35
+ PATTERN
36
+
26
37
  def on_send(node)
27
- assert_equal_with_false(node) do |actual, rest_receiver_arg|
28
- message = rest_receiver_arg.first
38
+ actual, rest_receiver_arg = assert_equal_with_false(node) ||
39
+ assert_with_bang_argument(node)
40
+ return unless actual
29
41
 
30
- arguments = [actual.source, message&.source].compact.join(', ')
42
+ message_argument = rest_receiver_arg.first
31
43
 
32
- add_offense(node, message: format(MSG, arguments: arguments))
33
- end
44
+ arguments = [actual.source, message_argument&.source].compact.join(', ')
45
+
46
+ message = if node.method?(:assert_equal)
47
+ MSG_FOR_ASSERT_EQUAL
48
+ else
49
+ MSG_FOR_ASSERT
50
+ end
51
+
52
+ add_offense(node, message: format(message, arguments: arguments))
34
53
  end
35
54
 
36
55
  def autocorrect(node)
37
56
  lambda do |corrector|
38
- arguments = node.arguments.reject(&:false_type?)
39
- replacement = arguments.map(&:source).join(', ')
40
- corrector.replace(node.loc.expression, "refute(#{replacement})")
57
+ corrector.replace(node.loc.selector, 'refute')
58
+
59
+ assert_equal_with_false(node) do |actual|
60
+ corrector.replace(
61
+ first_and_second_arguments_range(node), actual.source
62
+ )
63
+ end
64
+
65
+ assert_with_bang_argument(node) do |actual|
66
+ corrector.replace(
67
+ first_argument_range(node), actual.source
68
+ )
69
+ end
41
70
  end
42
71
  end
43
72
  end
@@ -16,44 +16,9 @@ module RuboCop
16
16
  # refute_includes(collection, object, 'the message')
17
17
  #
18
18
  class RefuteIncludes < Cop
19
- MSG = 'Prefer using `refute_includes(%<arguments>s)` over ' \
20
- '`refute(%<receiver>s)`.'
19
+ extend IncludesCopRule
21
20
 
22
- def_node_matcher :refute_with_includes, <<~PATTERN
23
- (send nil? :refute $(send $_ :include? $_) $...)
24
- PATTERN
25
-
26
- def on_send(node)
27
- refute_with_includes(node) do
28
- |first_receiver_arg, collection, object, rest_receiver_arg|
29
-
30
- message = rest_receiver_arg.first
31
- arguments = node_arguments(collection, object, 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_includes(node) do
43
- |_receiver, collection, object, rest_receiver_arg|
44
-
45
- message = rest_receiver_arg.first
46
- replacement = node_arguments(collection, object, message)
47
- corrector.replace(node.loc.expression, "refute_includes(#{replacement})")
48
- end
49
- end
50
- end
51
-
52
- private
53
-
54
- def node_arguments(collection, object, message)
55
- [collection.source, object.source, message&.source].compact.join(', ')
56
- end
21
+ rule target_method: :refute, prefer_method: :refute_includes
57
22
  end
58
23
  end
59
24
  end
@@ -16,6 +16,8 @@ module RuboCop
16
16
  # refute_instance_of(Class, object, 'the message')
17
17
  #
18
18
  class RefuteInstanceOf < Cop
19
+ include ArgumentRangeHelper
20
+
19
21
  MSG = 'Prefer using `refute_instance_of(%<arguments>s)` over ' \
20
22
  '`refute(%<receiver>s)`.'
21
23
 
@@ -24,9 +26,7 @@ module RuboCop
24
26
  PATTERN
25
27
 
26
28
  def on_send(node)
27
- refute_with_instance_of(node) do
28
- |first_receiver_arg, object, method, rest_args|
29
-
29
+ refute_with_instance_of(node) do |first_receiver_arg, object, method, rest_args|
30
30
  message = rest_args.first
31
31
  arguments = node_arguments(object, method, message)
32
32
  receiver = [first_receiver_arg.source, message&.source].compact.join(', ')
@@ -39,12 +39,11 @@ module RuboCop
39
39
 
40
40
  def autocorrect(node)
41
41
  lambda do |corrector|
42
- refute_with_instance_of(node) do |_, object, method, rest_args|
43
- message = rest_args.first
44
- arguments = node_arguments(object, method, message)
42
+ refute_with_instance_of(node) do |_, object, method|
43
+ corrector.replace(node.loc.selector, 'refute_instance_of')
45
44
 
46
- replacement = "refute_instance_of(#{arguments})"
47
- corrector.replace(node.loc.expression, replacement)
45
+ replacement = [method, object].map(&:source).join(', ')
46
+ corrector.replace(first_argument_range(node), replacement)
48
47
  end
49
48
  end
50
49
  end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Minitest
6
+ # This cop enforces the test to use `refute_match`
7
+ # instead of using `refute(matcher.match(string))`.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # refute(matcher.match(string))
12
+ # refute(matcher.match(string), 'the message')
13
+ #
14
+ # # good
15
+ # refute_match(matcher, string)
16
+ # refute_match(matcher, string, 'the message')
17
+ #
18
+ class RefuteMatch < Cop
19
+ include ArgumentRangeHelper
20
+
21
+ MSG = 'Prefer using `refute_match(%<arguments>s)` over ' \
22
+ '`refute(%<receiver>s)`.'
23
+
24
+ def_node_matcher :refute_with_match, <<~PATTERN
25
+ (send nil? :refute $(send $_ :match $_) $...)
26
+ PATTERN
27
+
28
+ def on_send(node)
29
+ refute_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
+ refute_with_match(node) do |_, matcher, actual|
44
+ corrector.replace(node.loc.selector, 'refute_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
57
+ end
58
+ end
59
+ end
60
+ end
@@ -16,6 +16,8 @@ module RuboCop
16
16
  # refute_nil(actual, 'the message')
17
17
  #
18
18
  class RefuteNil < Cop
19
+ include ArgumentRangeHelper
20
+
19
21
  MSG = 'Prefer using `refute_nil(%<arguments>s)` over ' \
20
22
  '`refute_equal(nil, %<arguments>s)`.'
21
23
 
@@ -35,9 +37,12 @@ module RuboCop
35
37
 
36
38
  def autocorrect(node)
37
39
  lambda do |corrector|
38
- arguments = node.arguments.reject(&:nil_type?)
39
- replacement = arguments.map(&:source).join(', ')
40
- corrector.replace(node.loc.expression, "refute_nil(#{replacement})")
40
+ refute_equal_with_nil(node) do |actual|
41
+ corrector.replace(node.loc.selector, 'refute_nil')
42
+ corrector.replace(
43
+ first_and_second_arguments_range(node), actual.source
44
+ )
45
+ end
41
46
  end
42
47
  end
43
48
  end
@@ -10,12 +10,16 @@ module RuboCop
10
10
  # # bad
11
11
  # refute(object.respond_to?(:some_method))
12
12
  # refute(object.respond_to?(:some_method), 'the message')
13
+ # refute(respond_to?(:some_method))
13
14
  #
14
15
  # # good
15
16
  # refute_respond_to(object, :some_method)
16
17
  # refute_respond_to(object, :some_method, 'the message')
18
+ # refute_respond_to(self, :some_method)
17
19
  #
18
20
  class RefuteRespondTo < Cop
21
+ include ArgumentRangeHelper
22
+
19
23
  MSG = 'Prefer using `refute_respond_to(%<preferred>s)` over ' \
20
24
  '`refute(%<over>s)`.'
21
25
 
@@ -26,9 +30,8 @@ module RuboCop
26
30
  def on_send(node)
27
31
  refute_with_respond_to(node) do |over, object, method, rest_args|
28
32
  custom_message = rest_args.first
29
- preferred = [object, method, custom_message]
30
- .compact.map(&:source).join(', ')
31
- over = [over, custom_message].compact.map(&:source).join(', ')
33
+ preferred = build_preferred_arguments(object, method, custom_message)
34
+ over = [over, custom_message].compact.map(&:source).join(', ')
32
35
  message = format(MSG, preferred: preferred, over: over)
33
36
  add_offense(node, message: message)
34
37
  end
@@ -36,15 +39,23 @@ module RuboCop
36
39
 
37
40
  def autocorrect(node)
38
41
  lambda do |corrector|
39
- refute_with_respond_to(node) do |_, object, method, rest_args|
40
- custom_message = rest_args.first
41
- preferred = [object, method, custom_message]
42
- .compact.map(&:source).join(', ')
43
- replacement = "refute_respond_to(#{preferred})"
44
- corrector.replace(node.loc.expression, replacement)
42
+ refute_with_respond_to(node) do |_, object, method|
43
+ corrector.replace(node.loc.selector, 'refute_respond_to')
44
+
45
+ object = object ? object.source : 'self'
46
+ replacement = [object, method.source].join(', ')
47
+ corrector.replace(first_argument_range(node), replacement)
45
48
  end
46
49
  end
47
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
48
59
  end
49
60
  end
50
61
  end
@@ -1,10 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'mixin/argument_range_helper'
4
+ require_relative 'mixin/includes_cop_rule'
3
5
  require_relative 'minitest/assert_empty'
6
+ require_relative 'minitest/assert_empty_literal'
4
7
  require_relative 'minitest/assert_equal'
5
8
  require_relative 'minitest/assert_nil'
6
9
  require_relative 'minitest/assert_includes'
7
10
  require_relative 'minitest/assert_instance_of'
11
+ require_relative 'minitest/assert_match'
8
12
  require_relative 'minitest/assert_respond_to'
9
13
  require_relative 'minitest/assert_truthy'
10
14
  require_relative 'minitest/refute_empty'
@@ -12,5 +16,6 @@ require_relative 'minitest/refute_false'
12
16
  require_relative 'minitest/refute_equal'
13
17
  require_relative 'minitest/refute_nil'
14
18
  require_relative 'minitest/refute_includes'
19
+ require_relative 'minitest/refute_match'
15
20
  require_relative 'minitest/refute_instance_of'
16
21
  require_relative 'minitest/refute_respond_to'
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # Methods that calculate and return `Parser::Source::Ranges`.
6
+ module ArgumentRangeHelper
7
+ include RangeHelp
8
+
9
+ private
10
+
11
+ def first_argument_range(node)
12
+ first_argument = node.first_argument
13
+
14
+ range_between(
15
+ first_argument.source_range.begin_pos,
16
+ first_argument.source_range.end_pos
17
+ )
18
+ end
19
+
20
+ def first_and_second_arguments_range(node)
21
+ first_argument = node.first_argument
22
+ second_argument = node.arguments[1]
23
+
24
+ range_between(
25
+ first_argument.source_range.begin_pos,
26
+ second_argument.source_range.end_pos
27
+ )
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # Define the rule for `Minitest/AssertIncludes` and `Minitest/RefuteIncludes` cops.
6
+ module IncludesCopRule
7
+ def rule(target_method:, prefer_method:)
8
+ class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
9
+ include ArgumentRangeHelper
10
+
11
+ MSG = 'Prefer using `#{prefer_method}(%<new_arguments>s)` over ' \
12
+ '`#{target_method}(%<original_arguments>s)`.'
13
+
14
+ def on_send(node)
15
+ return unless node.method?(:#{target_method})
16
+ return unless (arguments = peel_redundant_parentheses_from(node.arguments))
17
+ return unless arguments.first.method?(:include?)
18
+
19
+ add_offense(node, message: offense_message(arguments))
20
+ end
21
+
22
+ def autocorrect(node)
23
+ lambda do |corrector|
24
+ corrector.replace(node.loc.selector, '#{prefer_method}')
25
+
26
+ arguments = peel_redundant_parentheses_from(node.arguments)
27
+
28
+ new_arguments = [
29
+ arguments.first.receiver.source,
30
+ arguments.first.arguments.map(&:source)
31
+ ].join(', ')
32
+
33
+ if enclosed_in_redundant_parentheses?(node)
34
+ new_arguments = '(' + new_arguments + ')'
35
+ end
36
+
37
+ corrector.replace(first_argument_range(node), new_arguments)
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def peel_redundant_parentheses_from(arguments)
44
+ return arguments unless arguments.first.begin_type?
45
+
46
+ peel_redundant_parentheses_from(arguments.first.children)
47
+ end
48
+
49
+ def offense_message(arguments)
50
+ new_arguments = new_arguments(arguments)
51
+
52
+ original_arguments = arguments.map(&:source).join(', ')
53
+
54
+ format(
55
+ MSG,
56
+ new_arguments: new_arguments,
57
+ original_arguments: original_arguments
58
+ )
59
+ end
60
+
61
+ def new_arguments(arguments)
62
+ message_argument = arguments.last if arguments.first != arguments.last
63
+
64
+ [
65
+ arguments.first.receiver,
66
+ arguments.first.arguments.first,
67
+ message_argument
68
+ ].compact.map(&:source).join(', ')
69
+ end
70
+
71
+ def enclosed_in_redundant_parentheses?(node)
72
+ node.arguments.first.begin_type?
73
+ end
74
+ RUBY
75
+ end
76
+ end
77
+ end
78
+ end