rubocop-minitest 0.2.1 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +7 -0
  3. data/.rubocop_todo.yml +5 -5
  4. data/CHANGELOG.md +44 -0
  5. data/Gemfile +6 -2
  6. data/README.md +2 -1
  7. data/config/default.yml +70 -10
  8. data/lib/rubocop-minitest.rb +0 -3
  9. data/lib/rubocop/cop/minitest/assert_empty.rb +11 -10
  10. data/lib/rubocop/cop/minitest/assert_empty_literal.rb +36 -0
  11. data/lib/rubocop/cop/minitest/assert_equal.rb +52 -0
  12. data/lib/rubocop/cop/minitest/assert_includes.rb +13 -12
  13. data/lib/rubocop/cop/minitest/assert_instance_of.rb +59 -0
  14. data/lib/rubocop/cop/minitest/assert_nil.rb +10 -4
  15. data/lib/rubocop/cop/minitest/assert_respond_to.rb +62 -0
  16. data/lib/rubocop/cop/minitest/assert_truthy.rb +10 -5
  17. data/lib/rubocop/cop/minitest/refute_empty.rb +51 -0
  18. data/lib/rubocop/cop/minitest/refute_equal.rb +68 -0
  19. data/lib/rubocop/cop/minitest/refute_false.rb +51 -0
  20. data/lib/rubocop/cop/minitest/refute_includes.rb +61 -0
  21. data/lib/rubocop/cop/minitest/refute_instance_of.rb +59 -0
  22. data/lib/rubocop/cop/minitest/refute_nil.rb +10 -4
  23. data/lib/rubocop/cop/minitest/refute_respond_to.rb +62 -0
  24. data/lib/rubocop/cop/minitest_cops.rb +11 -0
  25. data/lib/rubocop/cop/mixin/argument_range_helper.rb +31 -0
  26. data/lib/rubocop/minitest/version.rb +1 -1
  27. data/manual/cops.md +10 -0
  28. data/manual/cops_minitest.md +264 -15
  29. data/relnotes/v0.1.0.md +7 -0
  30. data/relnotes/v0.2.0.md +9 -0
  31. data/relnotes/v0.2.1.md +5 -0
  32. data/relnotes/v0.3.0.md +16 -0
  33. data/relnotes/v0.4.0.md +14 -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 +3 -0
  37. data/tasks/cut_release.rake +60 -0
  38. metadata +24 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dc2eabe582388a8716653ef64d84833b48547f2c0e84fd666c36ab59b773abdc
4
- data.tar.gz: 726cd0a1cc2f11eee03f49278408b9eda29308d74641cdc8a562f84c063e4e8c
3
+ metadata.gz: c3c643f7623a14a4a99f813daf392e31a491b7177504cad25760093d80e0b32e
4
+ data.tar.gz: b2e5de6e39a741828ae69ca48311b366747bb19aebbc85b23c96ff346f180b39
5
5
  SHA512:
6
- metadata.gz: 60bec75d6fab0181c7f1ee5e664ca0a9dda0d8ba7d9a54d184a7f4573633e10fccef93719da3dead41c5919862f67aa0b66eb92f1dc933759c240e093ee93bd0
7
- data.tar.gz: 28d6e3f708ce291589ff8e2b74a12792777dbc39e244309951ba21e1ffdd59ac982fed3f52af148acca2b8a96bc8f0158711c3e99f893f09d26ef74beb743d2e
6
+ metadata.gz: eada0f53e4b625d321342f22aa80942512fcefa2131443a7d7d1d7a6f9fafabc1f1e8659f7b7fd2cc002bf83dcec037e760def29db035ac2f1e29bb6ace5fba3
7
+ data.tar.gz: ca010bc26330c8c32a9a28fe12f27870affa6e554c6832b6eedede0daf4c89fd5e28ffd93bca1e152a5e3785240023db9e4d35226f3e1bcfc02f49a7cffc5c68
@@ -0,0 +1,7 @@
1
+ # These are supported funding model platforms
2
+
3
+ github: [bbatsov, koic]
4
+ patreon: bbatsov
5
+ open_collective: rubocop
6
+ tidelift: "rubygems/rubocop"
7
+ custom: https://www.paypal.me/bbatsov
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2019-08-07 15:41:02 +0900 using RuboCop version 0.74.0.
3
+ # on 2019-12-21 01:15:41 +0900 using RuboCop version 0.78.0.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -10,14 +10,14 @@
10
10
  Metrics/AbcSize:
11
11
  Max: 17
12
12
 
13
- # Offense count: 5
13
+ # Offense count: 19
14
14
  # Configuration parameters: CountComments, ExcludedMethods.
15
15
  Metrics/MethodLength:
16
16
  Max: 14
17
17
 
18
- # Offense count: 2
18
+ # Offense count: 40
19
19
  # Cop supports --auto-correct.
20
20
  # Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
21
21
  # URISchemes: http, https
22
- Metrics/LineLength:
23
- Max: 87
22
+ Layout/LineLength:
23
+ Max: 90
@@ -2,6 +2,49 @@
2
2
 
3
3
  ## master (unreleased)
4
4
 
5
+ ## 0.5.1 (2019-12-25)
6
+
7
+ * [#42](https://github.com/rubocop-hq/rubocop-minitest/issues/42): Fix an incorrect autocorrect for some cops of `Minitest` department when using heredoc message. ([@koic][])
8
+
9
+ ## 0.5.0 (2019-11-24)
10
+
11
+ ### New features
12
+
13
+ * [#32](https://github.com/rubocop-hq/rubocop-minitest/issues/32): Add new `Minitest/AssertEmptyLiteral` cop. ([@tejasbubane][])
14
+
15
+ ## 0.4.1 (2019-11-10)
16
+
17
+ ### Bug fixes
18
+
19
+ * [#39](https://github.com/rubocop-hq/rubocop-minitest/issues/39): Fix an incorrect autocorrect for `Minitest/AssertRespondTo` and `Minitest/RefuteRespondTo` when using assertion method calling `respond_to` with receiver omitted. ([@koic][])
20
+
21
+ ## 0.4.0 (2019-11-07)
22
+
23
+ ### New features
24
+
25
+ * [#29](https://github.com/rubocop-hq/rubocop-minitest/pull/29): Add new `Minitest/RefuteRespondTo` cop. ([@herwinw][])
26
+ * [#31](https://github.com/rubocop-hq/rubocop-minitest/pull/31): Add new `Minitest/AssertEqual` cop. ([@herwinw][])
27
+ * [#34](https://github.com/rubocop-hq/rubocop-minitest/pull/34): Add new `Minitest/AssertInstanceOf` cop. ([@abhaynikam][])
28
+ * [#35](https://github.com/rubocop-hq/rubocop-minitest/pull/35): Add new `Minitest/RefuteInstanceOf` cop. ([@abhaynikam][])
29
+
30
+ ### Bug fixes
31
+
32
+ * [#25](https://github.com/rubocop-hq/rubocop-minitest/issues/25): Add `Enabled: true` to `Minitest` department config to suppress `Warning: Minitest does not support Enabled parameter`. ([@koic][])
33
+
34
+ ## 0.3.0 (2019-10-13)
35
+
36
+ ### New features
37
+
38
+ * [#15](https://github.com/rubocop-hq/rubocop-minitest/pull/15): Add new `Minitest/RefuteIncludes` cop. ([@abhaynikam][])
39
+ * [#18](https://github.com/rubocop-hq/rubocop-minitest/pull/18): Add new `Minitest/RefuteFalse` cop. ([@duduribeiro][])
40
+ * [#20](https://github.com/rubocop-hq/rubocop-minitest/pull/20): Add new `Minitest/RefuteEmpty` cop. ([@abhaynikam][])
41
+ * [#21](https://github.com/rubocop-hq/rubocop-minitest/pull/21): Add new `Minitest/RefuteEqual` cop. ([@duduribeiro][])
42
+ * [#27](https://github.com/rubocop-hq/rubocop-minitest/pull/27): Add new `Minitest/AssertRespondTo` cop. ([@duduribeiro][])
43
+
44
+ ### Bug fixes
45
+
46
+ * [#19](https://github.com/rubocop-hq/rubocop-minitest/pull/19): Fix a false negative for `Minitest/AssertIncludes` when using `include` method in arguments of `assert` method. ([@abhaynikam][])
47
+
5
48
  ## 0.2.1 (2019-09-24)
6
49
 
7
50
  ### Bug fixes
@@ -28,3 +71,4 @@
28
71
  [@duduribeiro]: https://github.com/duduribeiro
29
72
  [@tejasbubane]: https://github.com/tejasbubane
30
73
  [@abhaynikam]: https://github.com/abhaynikam
74
+ [@herwinw]: https://github.com/herwinw
data/Gemfile CHANGED
@@ -6,7 +6,11 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
6
6
 
7
7
  gemspec
8
8
 
9
+ gem 'bump', require: false
9
10
  gem 'rake'
10
11
  gem 'rubocop', github: 'rubocop-hq/rubocop'
11
- gem 'rubocop-performance', '~> 1.4.0'
12
- gem 'yard', '~> 0.9'
12
+ gem 'rubocop-performance', '~> 1.5.0'
13
+ # Workaround for YARD 0.9.20 or lower.
14
+ # It specifies `github` until the release that includes the following changes:
15
+ # https://github.com/lsegal/yard/pull/1290
16
+ gem 'yard', github: 'lsegal/yard', ref: '10a2e5b'
data/README.md CHANGED
@@ -4,6 +4,7 @@
4
4
  [![CircleCI](https://circleci.com/gh/rubocop-hq/rubocop-minitest.svg?style=svg)](https://circleci.com/gh/rubocop-hq/rubocop-minitest)
5
5
 
6
6
  A [RuboCop](https://github.com/rubocop-hq/rubocop) extension focused on enforcing Minitest best practices and coding conventions.
7
+ The library is based on the guidelines outlined in the community [Minitest Style Guide](https://minitest.rubystyle.guide).
7
8
 
8
9
  ## Installation
9
10
 
@@ -61,7 +62,7 @@ end
61
62
 
62
63
  All cops are located under
63
64
  [`lib/rubocop/cop/minitest`](lib/rubocop/cop/minitest), and contain
64
- examples/documentation.
65
+ examples/documentation. The documentation is published [here](https://docs.rubocop.org/projects/minitest).
65
66
 
66
67
  In your `.rubocop.yml`, you may treat the Minitest cops just like any other
67
68
  cop. For example:
@@ -1,33 +1,93 @@
1
1
  Minitest:
2
+ Enabled: true
2
3
  Include:
3
4
  - '**/test/**/*'
4
5
 
5
- Minitest/AssertNil:
6
- Description: 'Check if your test uses `assert_nil` instead of `assert_equal(nil, something)`.'
7
- StyleGuide: 'https://github.com/rubocop-hq/minitest-style-guide#assert-nil'
8
- Enabled: true
9
- VersionAdded: '0.1'
10
-
11
6
  Minitest/AssertEmpty:
12
- Description: 'Check if your test uses `assert_empty` instead of `assert(actual.empty?)`.'
7
+ Description: 'This cop enforces the test to use `assert_empty` instead of using `assert(object.empty?)`.'
13
8
  StyleGuide: 'https://github.com/rubocop-hq/minitest-style-guide#assert-empty'
14
9
  Enabled: true
15
10
  VersionAdded: '0.2'
16
11
 
12
+ Minitest/AssertEmptyLiteral:
13
+ Description: 'This cop enforces the test to use `assert_empty` instead of using `assert([], object)` or `assert({}, object)`.'
14
+ Enabled: true
15
+ VersionAdded: '0.5'
16
+
17
+ Minitest/AssertEqual:
18
+ Description: 'This cop enforces the test to use `assert_equal` instead of using `assert(expected == actual)`.'
19
+ StyleGuide: 'https://github.com/rubocop-hq/minitest-style-guide#assert-equal-arguments-order'
20
+ Enabled: true
21
+ VersionAdded: '0.4'
22
+
17
23
  Minitest/AssertIncludes:
18
- Description: 'Check if your test uses `assert_includes` instead of `assert(collection.includes?(actual))`.'
24
+ Description: 'This cop enforces the test to use `assert_includes` instead of using `assert(collection.include?(object))`.'
19
25
  StyleGuide: 'https://github.com/rubocop-hq/minitest-style-guide#assert-includes'
20
26
  Enabled: true
21
27
  VersionAdded: '0.2'
22
28
 
29
+ Minitest/AssertInstanceOf:
30
+ Description: 'This cop enforces the test to use `assert_instance_of(Class, object)` over `assert(object.instance_of?(Class))`'
31
+ StyleGuide: 'https://github.com/rubocop-hq/minitest-style-guide#assert-instance-of'
32
+ Enabled: true
33
+ VersionAdded: '0.4'
34
+
35
+ Minitest/AssertNil:
36
+ Description: 'This cop enforces the test to use `assert_nil` instead of using `assert_equal(nil, something)`.'
37
+ StyleGuide: 'https://github.com/rubocop-hq/minitest-style-guide#assert-nil'
38
+ Enabled: true
39
+ VersionAdded: '0.1'
40
+
41
+ Minitest/AssertRespondTo:
42
+ Description: 'This cop enforces the test to use `assert_respond_to(object, :some_method)` over `assert(object.respond_to?(:some_method))`.'
43
+ StyleGuide: 'https://github.com/rubocop-hq/minitest-style-guide#assert-responds-to-method'
44
+ Enabled: true
45
+ VersionAdded: '0.3'
46
+
23
47
  Minitest/AssertTruthy:
24
- Description: 'Check if your test uses `assert(actual)` instead of `assert_equal(true, actual)`.'
48
+ Description: 'This cop enforces the test to use `assert(actual)` instead of using `assert_equal(true, actual)`.'
25
49
  StyleGuide: 'https://github.com/rubocop-hq/minitest-style-guide#assert-truthy'
26
50
  Enabled: true
27
51
  VersionAdded: '0.2'
28
52
 
53
+ Minitest/RefuteEmpty:
54
+ Description: 'This cop enforces to use `refute_empty` instead of using `refute(object.empty?)`.'
55
+ StyleGuide: 'https://github.com/rubocop-hq/minitest-style-guide#refute-empty'
56
+ Enabled: true
57
+ VersionAdded: '0.3'
58
+
59
+ Minitest/RefuteEqual:
60
+ Description: 'Check if your test uses `refute_equal` instead of `assert(expected != object)` or `assert(! expected == object))`.'
61
+ StyleGuide: 'https://github.com/rubocop-hq/minitest-style-guide#refute-equal'
62
+ Enabled: true
63
+ VersionAdded: '0.3'
64
+
65
+ Minitest/RefuteFalse:
66
+ Description: 'Check if your test uses `refute(actual)` instead of `assert_equal(false, actual)`.'
67
+ StyleGuide: 'https://github.com/rubocop-hq/minitest-style-guide#refute-false'
68
+ Enabled: true
69
+ VersionAdded: '0.3'
70
+
71
+ Minitest/RefuteIncludes:
72
+ Description: 'This cop enforces the test to use `refute_includes` instead of using `refute(collection.include?(object))`.'
73
+ StyleGuide: 'https://github.com/rubocop-hq/minitest-style-guide#refute-includes'
74
+ Enabled: true
75
+ VersionAdded: '0.3'
76
+
77
+ Minitest/RefuteInstanceOf:
78
+ Description: 'This cop enforces the test to use `refute_instance_of(Class, object)` over `refute(object.instance_of?(Class))`.'
79
+ StyleGuide: 'https://github.com/rubocop-hq/minitest-style-guide#refute-instance-of'
80
+ Enabled: true
81
+ VersionAdded: '0.4'
82
+
29
83
  Minitest/RefuteNil:
30
- Description: 'Check if your test uses `refute_nil` instead of `refute_equal(nil, something)`.'
84
+ Description: 'This cop enforces the test to use `refute_nil` instead of using `refute_equal(nil, something)`.'
31
85
  StyleGuide: 'https://github.com/rubocop-hq/minitest-style-guide#refute-nil'
32
86
  Enabled: true
33
87
  VersionAdded: '0.2'
88
+
89
+ Minitest/RefuteRespondTo:
90
+ Description: 'This cop enforces the test to use `refute_respond_to(object, :some_method)` over `refute(object.respond_to?(:some_method))`.'
91
+ StyleGuide: 'https://github.com/rubocop-hq/minitest-style-guide#refute-respond-to'
92
+ Enabled: true
93
+ VersionAdded: '0.4'
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pathname'
4
- require 'yaml'
5
-
6
3
  require 'rubocop'
7
4
 
8
5
  require_relative 'rubocop/minitest'
@@ -3,18 +3,21 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Minitest
6
- # Check if your test uses `assert_empty` instead of `assert(actual.empty?)`.
6
+ # This cop enforces the test to use `assert_empty`
7
+ # instead of using `assert(object.empty?)`.
7
8
  #
8
9
  # @example
9
10
  # # bad
10
- # assert(actual.empty?)
11
- # assert(actual.empty?, 'the message')
11
+ # assert(object.empty?)
12
+ # assert(object.empty?, 'the message')
12
13
  #
13
14
  # # good
14
- # assert_empty(actual)
15
- # assert_empty(actual, 'the message')
15
+ # assert_empty(object)
16
+ # assert_empty(object, 'the message')
16
17
  #
17
18
  class AssertEmpty < Cop
19
+ include ArgumentRangeHelper
20
+
18
21
  MSG = 'Prefer using `assert_empty(%<arguments>s)` over ' \
19
22
  '`assert(%<receiver>s)`.'
20
23
 
@@ -36,11 +39,9 @@ module RuboCop
36
39
 
37
40
  def autocorrect(node)
38
41
  lambda do |corrector|
39
- assert_with_empty(node) do |_first_receiver_arg, actual, rest_receiver_arg|
40
- message = rest_receiver_arg.first
41
-
42
- replacement = [actual.source, message&.source].compact.join(', ')
43
- corrector.replace(node.loc.expression, "assert_empty(#{replacement})")
42
+ assert_with_empty(node) do |_, actual_arg|
43
+ corrector.replace(node.loc.selector, 'assert_empty')
44
+ corrector.replace(first_argument_range(node), actual_arg.source)
44
45
  end
45
46
  end
46
47
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Minitest
6
+ # This cop enforces the test to use `assert_empty`
7
+ # instead of using `assert([], object)`.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # assert([], object)
12
+ # assert({}, object)
13
+ #
14
+ # # good
15
+ # assert_empty(object)
16
+ #
17
+ class AssertEmptyLiteral < Cop
18
+ MSG = 'Prefer using `assert_empty(%<arguments>s)` over ' \
19
+ '`assert(%<literal>s, %<arguments>s)`.'
20
+
21
+ def_node_matcher :assert_with_empty_literal, <<~PATTERN
22
+ (send nil? :assert ${hash array} $...)
23
+ PATTERN
24
+
25
+ def on_send(node)
26
+ assert_with_empty_literal(node) do |literal, matchers|
27
+ args = matchers.map(&:source).join(', ')
28
+
29
+ message = format(MSG, literal: literal.source, arguments: args)
30
+ add_offense(node, message: message)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Minitest
6
+ # This cop enforces the use of `assert_equal(expected, actual)`
7
+ # over `assert(expected == actual)`.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # assert("rubocop-minitest" == actual)
12
+ #
13
+ # # good
14
+ # assert_equal("rubocop-minitest", actual)
15
+ #
16
+ class AssertEqual < Cop
17
+ include ArgumentRangeHelper
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
49
+ end
50
+ end
51
+ end
52
+ end
@@ -3,24 +3,26 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Minitest
6
- # Check if your test uses `assert_includes`
7
- # instead of `assert(collection.includes?(actual))`.
6
+ # This cop enforces the test to use `assert_includes`
7
+ # instead of using `assert(collection.include?(object))`.
8
8
  #
9
9
  # @example
10
10
  # # bad
11
- # assert(collection.includes?(actual))
12
- # assert(collection.includes?(actual), 'the message')
11
+ # assert(collection.include?(object))
12
+ # assert(collection.include?(object), 'the message')
13
13
  #
14
14
  # # good
15
- # assert_includes(collection, actual)
16
- # assert_includes(collection, actual, 'the message')
15
+ # assert_includes(collection, object)
16
+ # assert_includes(collection, object, 'the message')
17
17
  #
18
18
  class AssertIncludes < Cop
19
+ include ArgumentRangeHelper
20
+
19
21
  MSG = 'Prefer using `assert_includes(%<arguments>s)` over ' \
20
22
  '`assert(%<receiver>s)`.'
21
23
 
22
24
  def_node_matcher :assert_with_includes, <<~PATTERN
23
- (send nil? :assert $(send $_ :includes? $_) $...)
25
+ (send nil? :assert $(send $_ :include? $_) $...)
24
26
  PATTERN
25
27
 
26
28
  def on_send(node)
@@ -39,12 +41,11 @@ module RuboCop
39
41
 
40
42
  def autocorrect(node)
41
43
  lambda do |corrector|
42
- assert_with_includes(node) do
43
- |_receiver, collection, actual, rest_receiver_arg|
44
+ assert_with_includes(node) do |_, collection, actual|
45
+ corrector.replace(node.loc.selector, 'assert_includes')
44
46
 
45
- message = rest_receiver_arg.first
46
- replacement = node_arguments(collection, actual, message)
47
- corrector.replace(node.loc.expression, "assert_includes(#{replacement})")
47
+ replacement = [collection, actual].map(&:source).join(', ')
48
+ corrector.replace(first_argument_range(node), replacement)
48
49
  end
49
50
  end
50
51
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Minitest
6
+ # This cop enforces the test to use `assert_instance_of(Class, object)`
7
+ # over `assert(object.instance_of?(Class))`.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # assert(object.instance_of?(Class))
12
+ # assert(object.instance_of?(Class), 'the message')
13
+ #
14
+ # # good
15
+ # assert_instance_of(Class, object)
16
+ # assert_instance_of(Class, object, 'the message')
17
+ #
18
+ class AssertInstanceOf < Cop
19
+ include ArgumentRangeHelper
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
56
+ end
57
+ end
58
+ end
59
+ end