rubocop-minitest 0.4.0 → 0.6.1

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