rubocop-rspec 2.21.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +147 -9
  3. data/README.md +2 -2
  4. data/config/default.yml +159 -244
  5. data/config/obsoletion.yml +24 -0
  6. data/lib/rubocop/cop/rspec/around_block.rb +3 -3
  7. data/lib/rubocop/cop/rspec/base.rb +0 -1
  8. data/lib/rubocop/cop/rspec/be.rb +1 -1
  9. data/lib/rubocop/cop/rspec/be_empty.rb +1 -0
  10. data/lib/rubocop/cop/rspec/be_eq.rb +1 -1
  11. data/lib/rubocop/cop/rspec/be_eql.rb +1 -1
  12. data/lib/rubocop/cop/rspec/be_nil.rb +2 -2
  13. data/lib/rubocop/cop/rspec/before_after_all.rb +7 -13
  14. data/lib/rubocop/cop/rspec/change_by_zero.rb +30 -4
  15. data/lib/rubocop/cop/rspec/context_method.rb +2 -2
  16. data/lib/rubocop/cop/rspec/context_wording.rb +1 -1
  17. data/lib/rubocop/cop/rspec/describe_symbol.rb +1 -1
  18. data/lib/rubocop/cop/rspec/described_class.rb +33 -11
  19. data/lib/rubocop/cop/rspec/dialect.rb +13 -0
  20. data/lib/rubocop/cop/rspec/duplicated_metadata.rb +1 -1
  21. data/lib/rubocop/cop/rspec/empty_example_group.rb +4 -1
  22. data/lib/rubocop/cop/rspec/empty_hook.rb +1 -1
  23. data/lib/rubocop/cop/rspec/empty_line_after_example.rb +2 -2
  24. data/lib/rubocop/cop/rspec/empty_metadata.rb +46 -0
  25. data/lib/rubocop/cop/rspec/empty_output.rb +47 -0
  26. data/lib/rubocop/cop/rspec/eq.rb +47 -0
  27. data/lib/rubocop/cop/rspec/example_length.rb +11 -5
  28. data/lib/rubocop/cop/rspec/example_without_description.rb +11 -2
  29. data/lib/rubocop/cop/rspec/example_wording.rb +11 -2
  30. data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +14 -5
  31. data/lib/rubocop/cop/rspec/expect_actual.rb +17 -14
  32. data/lib/rubocop/cop/rspec/expect_change.rb +2 -2
  33. data/lib/rubocop/cop/rspec/expect_in_hook.rb +1 -1
  34. data/lib/rubocop/cop/rspec/expect_in_let.rb +42 -0
  35. data/lib/rubocop/cop/rspec/expect_output.rb +1 -4
  36. data/lib/rubocop/cop/rspec/focus.rb +17 -2
  37. data/lib/rubocop/cop/rspec/hook_argument.rb +2 -2
  38. data/lib/rubocop/cop/rspec/hooks_before_examples.rb +1 -1
  39. data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +2 -2
  40. data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -1
  41. data/lib/rubocop/cop/rspec/implicit_subject.rb +2 -2
  42. data/lib/rubocop/cop/rspec/indexed_let.rb +32 -1
  43. data/lib/rubocop/cop/rspec/instance_spy.rb +2 -2
  44. data/lib/rubocop/cop/rspec/instance_variable.rb +4 -4
  45. data/lib/rubocop/cop/rspec/is_expected_specify.rb +45 -0
  46. data/lib/rubocop/cop/rspec/iterated_expectation.rb +3 -3
  47. data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +2 -2
  48. data/lib/rubocop/cop/rspec/let_before_examples.rb +5 -1
  49. data/lib/rubocop/cop/rspec/let_setup.rb +1 -1
  50. data/lib/rubocop/cop/rspec/message_expectation.rb +1 -2
  51. data/lib/rubocop/cop/rspec/message_spies.rb +0 -2
  52. data/lib/rubocop/cop/rspec/metadata_style.rb +202 -0
  53. data/lib/rubocop/cop/rspec/missing_expectation_target_method.rb +54 -0
  54. data/lib/rubocop/cop/rspec/mixin/file_help.rb +14 -0
  55. data/lib/rubocop/cop/rspec/mixin/metadata.rb +21 -7
  56. data/lib/rubocop/cop/rspec/mixin/skip_or_pending.rb +2 -2
  57. data/lib/rubocop/cop/rspec/multiple_describes.rb +1 -1
  58. data/lib/rubocop/cop/rspec/multiple_expectations.rb +16 -11
  59. data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +2 -4
  60. data/lib/rubocop/cop/rspec/named_subject.rb +6 -3
  61. data/lib/rubocop/cop/rspec/pending.rb +12 -2
  62. data/lib/rubocop/cop/rspec/pending_without_reason.rb +1 -1
  63. data/lib/rubocop/cop/rspec/predicate_matcher.rb +10 -10
  64. data/lib/rubocop/cop/rspec/receive_counts.rb +1 -1
  65. data/lib/rubocop/cop/rspec/receive_messages.rb +161 -0
  66. data/lib/rubocop/cop/rspec/redundant_predicate_matcher.rb +67 -0
  67. data/lib/rubocop/cop/rspec/remove_const.rb +39 -0
  68. data/lib/rubocop/cop/rspec/repeated_example.rb +6 -6
  69. data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +1 -1
  70. data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +2 -2
  71. data/lib/rubocop/cop/rspec/repeated_include_example.rb +1 -1
  72. data/lib/rubocop/cop/rspec/repeated_subject_call.rb +125 -0
  73. data/lib/rubocop/cop/rspec/return_from_stub.rb +1 -1
  74. data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
  75. data/lib/rubocop/cop/rspec/shared_context.rb +1 -1
  76. data/lib/rubocop/cop/rspec/shared_examples.rb +66 -20
  77. data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +2 -3
  78. data/lib/rubocop/cop/rspec/sort_metadata.rb +3 -2
  79. data/lib/rubocop/cop/rspec/spec_file_path_format.rb +133 -0
  80. data/lib/rubocop/cop/rspec/spec_file_path_suffix.rb +40 -0
  81. data/lib/rubocop/cop/rspec/stubbed_mock.rb +4 -2
  82. data/lib/rubocop/cop/rspec/subject_stub.rb +6 -6
  83. data/lib/rubocop/cop/rspec/undescriptive_literals_description.rb +69 -0
  84. data/lib/rubocop/cop/rspec/unspecified_exception.rb +2 -2
  85. data/lib/rubocop/cop/rspec/variable_definition.rb +4 -4
  86. data/lib/rubocop/cop/rspec/verified_double_reference.rb +6 -6
  87. data/lib/rubocop/cop/rspec/verified_doubles.rb +2 -2
  88. data/lib/rubocop/cop/rspec/void_expect.rb +4 -3
  89. data/lib/rubocop/cop/rspec_cops.rb +14 -28
  90. data/lib/rubocop/rspec/concept.rb +0 -1
  91. data/lib/rubocop/rspec/config_formatter.rb +1 -11
  92. data/lib/rubocop/rspec/cop/generator.rb +25 -0
  93. data/lib/rubocop/rspec/language.rb +8 -9
  94. data/lib/rubocop/rspec/node.rb +1 -1
  95. data/lib/rubocop/rspec/shared_contexts/default_rspec_language_config_context.rb +1 -1
  96. data/lib/rubocop/rspec/version.rb +1 -1
  97. data/lib/rubocop/rspec/wording.rb +8 -0
  98. data/lib/rubocop-rspec.rb +2 -16
  99. metadata +27 -49
  100. data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +0 -39
  101. data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +0 -104
  102. data/lib/rubocop/cop/rspec/capybara/match_style.rb +0 -38
  103. data/lib/rubocop/cop/rspec/capybara/negation_matcher.rb +0 -33
  104. data/lib/rubocop/cop/rspec/capybara/specific_actions.rb +0 -29
  105. data/lib/rubocop/cop/rspec/capybara/specific_finders.rb +0 -24
  106. data/lib/rubocop/cop/rspec/capybara/specific_matcher.rb +0 -35
  107. data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +0 -36
  108. data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +0 -128
  109. data/lib/rubocop/cop/rspec/factory_bot/consistent_parentheses_style.rb +0 -117
  110. data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +0 -260
  111. data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +0 -56
  112. data/lib/rubocop/cop/rspec/factory_bot/factory_name_style.rb +0 -74
  113. data/lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb +0 -89
  114. data/lib/rubocop/cop/rspec/file_path.rb +0 -173
  115. data/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb +0 -43
  116. data/lib/rubocop/cop/rspec/rails/have_http_status.rb +0 -55
  117. data/lib/rubocop/cop/rspec/rails/http_status.rb +0 -203
  118. data/lib/rubocop/cop/rspec/rails/inferred_spec_type.rb +0 -145
  119. data/lib/rubocop/cop/rspec/rails/minitest_assertions.rb +0 -60
  120. data/lib/rubocop/cop/rspec/rails/travel_around.rb +0 -92
  121. data/lib/rubocop/rspec/factory_bot/language.rb +0 -37
  122. data/lib/rubocop/rspec/factory_bot.rb +0 -64
  123. data/lib/rubocop/rspec/language/node_pattern.rb +0 -48
@@ -1,89 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module RSpec
6
- module FactoryBot
7
- # Use shorthands from `FactoryBot::Syntax::Methods` in your specs.
8
- #
9
- # @safety
10
- # The autocorrection is marked as unsafe because the cop
11
- # cannot verify whether you already include
12
- # `FactoryBot::Syntax::Methods` in your test suite.
13
- #
14
- # If you're using Rails, add the following configuration to
15
- # `spec/support/factory_bot.rb` and be sure to require that file in
16
- # `rails_helper.rb`:
17
- #
18
- # [source,ruby]
19
- # ----
20
- # RSpec.configure do |config|
21
- # config.include FactoryBot::Syntax::Methods
22
- # end
23
- # ----
24
- #
25
- # If you're not using Rails:
26
- #
27
- # [source,ruby]
28
- # ----
29
- # RSpec.configure do |config|
30
- # config.include FactoryBot::Syntax::Methods
31
- #
32
- # config.before(:suite) do
33
- # FactoryBot.find_definitions
34
- # end
35
- # end
36
- # ----
37
- #
38
- # @example
39
- # # bad
40
- # FactoryBot.create(:bar)
41
- # FactoryBot.build(:bar)
42
- # FactoryBot.attributes_for(:bar)
43
- #
44
- # # good
45
- # create(:bar)
46
- # build(:bar)
47
- # attributes_for(:bar)
48
- #
49
- class SyntaxMethods < Base
50
- extend AutoCorrector
51
- include InsideExampleGroup
52
- include RangeHelp
53
- include RuboCop::RSpec::FactoryBot::Language
54
-
55
- MSG = 'Use `%<method>s` from `FactoryBot::Syntax::Methods`.'
56
-
57
- RESTRICT_ON_SEND = RuboCop::RSpec::FactoryBot::Language::METHODS
58
-
59
- def on_send(node)
60
- return unless factory_bot?(node.receiver)
61
- return unless inside_example_group?(node)
62
-
63
- message = format(MSG, method: node.method_name)
64
-
65
- add_offense(crime_scene(node), message: message) do |corrector|
66
- corrector.remove(offense(node))
67
- end
68
- end
69
-
70
- private
71
-
72
- def crime_scene(node)
73
- range_between(
74
- node.source_range.begin_pos,
75
- node.loc.selector.end_pos
76
- )
77
- end
78
-
79
- def offense(node)
80
- range_between(
81
- node.source_range.begin_pos,
82
- node.loc.selector.begin_pos
83
- )
84
- end
85
- end
86
- end
87
- end
88
- end
89
- end
@@ -1,173 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module RSpec
6
- # Checks that spec file paths are consistent and well-formed.
7
- #
8
- # By default, this checks that spec file paths are consistent with the
9
- # test subject and enforces that it reflects the described
10
- # class/module and its optionally called out method.
11
- #
12
- # With the configuration option `IgnoreMethods` the called out method will
13
- # be ignored when determining the enforced path.
14
- #
15
- # With the configuration option `CustomTransform` modules or classes can
16
- # be specified that should not as usual be transformed from CamelCase to
17
- # snake_case (e.g. 'RuboCop' => 'rubocop' ).
18
- #
19
- # With the configuration option `SpecSuffixOnly` test files will only
20
- # be checked to ensure they end in '_spec.rb'. This option disables
21
- # checking for consistency in the test subject or test methods.
22
- #
23
- # @example
24
- # # bad
25
- # whatever_spec.rb # describe MyClass
26
- #
27
- # # bad
28
- # my_class_spec.rb # describe MyClass, '#method'
29
- #
30
- # # good
31
- # my_class_spec.rb # describe MyClass
32
- #
33
- # # good
34
- # my_class_method_spec.rb # describe MyClass, '#method'
35
- #
36
- # # good
37
- # my_class/method_spec.rb # describe MyClass, '#method'
38
- #
39
- # @example when configuration is `IgnoreMethods: true`
40
- # # bad
41
- # whatever_spec.rb # describe MyClass
42
- #
43
- # # good
44
- # my_class_spec.rb # describe MyClass
45
- #
46
- # # good
47
- # my_class_spec.rb # describe MyClass, '#method'
48
- #
49
- # @example when configuration is `SpecSuffixOnly: true`
50
- # # good
51
- # whatever_spec.rb # describe MyClass
52
- #
53
- # # good
54
- # my_class_spec.rb # describe MyClass
55
- #
56
- # # good
57
- # my_class_spec.rb # describe MyClass, '#method'
58
- #
59
- class FilePath < Base
60
- include TopLevelGroup
61
- include Namespace
62
-
63
- MSG = 'Spec path should end with `%<suffix>s`.'
64
-
65
- # @!method example_group(node)
66
- def_node_matcher :example_group, <<~PATTERN
67
- (block
68
- $(send #rspec? _example_group $_ $...) ...
69
- )
70
- PATTERN
71
-
72
- # @!method routing_metadata?(node)
73
- def_node_search :routing_metadata?, '(pair (sym :type) (sym :routing))'
74
-
75
- def on_top_level_example_group(node)
76
- return unless top_level_groups.one?
77
-
78
- example_group(node) do |send_node, example_group, arguments|
79
- ensure_correct_file_path(send_node, example_group, arguments)
80
- end
81
- end
82
-
83
- private
84
-
85
- def ensure_correct_file_path(send_node, example_group, arguments)
86
- pattern = pattern_for(example_group, arguments)
87
- return if filename_ends_with?(pattern)
88
-
89
- # For the suffix shown in the offense message, modify the regular
90
- # expression pattern to resemble a glob pattern for clearer error
91
- # messages.
92
- offense_suffix = pattern.gsub('.*', '*').sub('[^/]', '')
93
- .sub('\.', '.')
94
- add_offense(send_node, message: format(MSG, suffix: offense_suffix))
95
- end
96
-
97
- def routing_spec?(args)
98
- args.any?(&method(:routing_metadata?)) || routing_spec_path?
99
- end
100
-
101
- def pattern_for(example_group, arguments)
102
- method_name = arguments.first
103
- if spec_suffix_only? || !example_group.const_type? ||
104
- routing_spec?(arguments)
105
- return pattern_for_spec_suffix_only
106
- end
107
-
108
- [
109
- expected_path(example_group),
110
- name_pattern(method_name),
111
- '[^/]*_spec\.rb'
112
- ].join
113
- end
114
-
115
- def pattern_for_spec_suffix_only
116
- '.*_spec\.rb'
117
- end
118
-
119
- def name_pattern(method_name)
120
- return unless method_name&.str_type?
121
- return if ignore_methods?
122
-
123
- ".*#{method_name.str_content.gsub(/\s/, '_').gsub(/\W/, '')}"
124
- end
125
-
126
- def expected_path(constant)
127
- constants = namespace(constant) + constant.const_name.split('::')
128
-
129
- File.join(
130
- constants.map do |name|
131
- custom_transform.fetch(name) { camel_to_snake_case(name) }
132
- end
133
- )
134
- end
135
-
136
- def camel_to_snake_case(string)
137
- string
138
- .gsub(/([^A-Z])([A-Z]+)/, '\1_\2')
139
- .gsub(/([A-Z])([A-Z][^A-Z\d]+)/, '\1_\2')
140
- .downcase
141
- end
142
-
143
- def custom_transform
144
- cop_config.fetch('CustomTransform', {})
145
- end
146
-
147
- def ignore_methods?
148
- cop_config['IgnoreMethods']
149
- end
150
-
151
- def filename_ends_with?(pattern)
152
- expanded_file_path.match?("#{pattern}$")
153
- end
154
-
155
- def relevant_rubocop_rspec_file?(_file)
156
- true
157
- end
158
-
159
- def spec_suffix_only?
160
- cop_config['SpecSuffixOnly']
161
- end
162
-
163
- def routing_spec_path?
164
- expanded_file_path.include?('spec/routing/')
165
- end
166
-
167
- def expanded_file_path
168
- File.expand_path(processed_source.file_path)
169
- end
170
- end
171
- end
172
- end
173
- end
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module RSpec
6
- module Rails
7
- # Checks that tests use RSpec `before` hook over Rails `setup` method.
8
- #
9
- # @example
10
- # # bad
11
- # setup do
12
- # allow(foo).to receive(:bar)
13
- # end
14
- #
15
- # # good
16
- # before do
17
- # allow(foo).to receive(:bar)
18
- # end
19
- #
20
- class AvoidSetupHook < Base
21
- extend AutoCorrector
22
-
23
- MSG = 'Use `before` instead of `setup`.'
24
-
25
- # @!method setup_call(node)
26
- def_node_matcher :setup_call, <<-PATTERN
27
- (block
28
- $(send nil? :setup)
29
- (args) _)
30
- PATTERN
31
-
32
- def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
33
- setup_call(node) do |setup|
34
- add_offense(node) do |corrector|
35
- corrector.replace setup, 'before'
36
- end
37
- end
38
- end
39
- end
40
- end
41
- end
42
- end
43
- end
@@ -1,55 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module RSpec
6
- module Rails
7
- # Checks that tests use `have_http_status` instead of equality matchers.
8
- #
9
- # @example
10
- # # bad
11
- # expect(response.status).to be(200)
12
- # expect(response.code).to eq("200")
13
- #
14
- # # good
15
- # expect(response).to have_http_status(200)
16
- #
17
- class HaveHttpStatus < ::RuboCop::Cop::Base
18
- extend AutoCorrector
19
-
20
- MSG =
21
- 'Prefer `expect(response).%<to>s have_http_status(%<status>s)` ' \
22
- 'over `%<bad_code>s`.'
23
-
24
- RUNNERS = %i[to to_not not_to].to_set
25
- RESTRICT_ON_SEND = RUNNERS
26
-
27
- # @!method match_status(node)
28
- def_node_matcher :match_status, <<-PATTERN
29
- (send
30
- (send nil? :expect
31
- $(send (send nil? :response) {:status :code})
32
- )
33
- $RUNNERS
34
- $(send nil? {:be :eq :eql :equal} ({int str} $_))
35
- )
36
- PATTERN
37
-
38
- def on_send(node)
39
- match_status(node) do |response_status, to, match, status|
40
- return unless status.to_s.match?(/\A\d+\z/)
41
-
42
- message = format(MSG, to: to, status: status,
43
- bad_code: node.source)
44
- add_offense(node, message: message) do |corrector|
45
- corrector.replace(response_status, 'response')
46
- corrector.replace(match.loc.selector, 'have_http_status')
47
- corrector.replace(match.first_argument, status.to_s)
48
- end
49
- end
50
- end
51
- end
52
- end
53
- end
54
- end
55
- end
@@ -1,203 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rack/utils'
4
-
5
- module RuboCop
6
- module Cop
7
- module RSpec
8
- module Rails
9
- # Enforces use of symbolic or numeric value to describe HTTP status.
10
- #
11
- # This cop inspects only `have_http_status` calls.
12
- # So, this cop does not check if a method starting with `be_*` is used
13
- # when setting for `EnforcedStyle: symbolic` or
14
- # `EnforcedStyle: numeric`.
15
- #
16
- # @example `EnforcedStyle: symbolic` (default)
17
- # # bad
18
- # it { is_expected.to have_http_status 200 }
19
- # it { is_expected.to have_http_status 404 }
20
- #
21
- # # good
22
- # it { is_expected.to have_http_status :ok }
23
- # it { is_expected.to have_http_status :not_found }
24
- # it { is_expected.to have_http_status :success }
25
- # it { is_expected.to have_http_status :error }
26
- #
27
- # @example `EnforcedStyle: numeric`
28
- # # bad
29
- # it { is_expected.to have_http_status :ok }
30
- # it { is_expected.to have_http_status :not_found }
31
- #
32
- # # good
33
- # it { is_expected.to have_http_status 200 }
34
- # it { is_expected.to have_http_status 404 }
35
- # it { is_expected.to have_http_status :success }
36
- # it { is_expected.to have_http_status :error }
37
- #
38
- # @example `EnforcedStyle: be_status`
39
- # # bad
40
- # it { is_expected.to have_http_status :ok }
41
- # it { is_expected.to have_http_status :not_found }
42
- # it { is_expected.to have_http_status 200 }
43
- # it { is_expected.to have_http_status 404 }
44
- #
45
- # # good
46
- # it { is_expected.to be_ok }
47
- # it { is_expected.to be_not_found }
48
- # it { is_expected.to have_http_status :success }
49
- # it { is_expected.to have_http_status :error }
50
- #
51
- class HttpStatus < Base
52
- extend AutoCorrector
53
- include ConfigurableEnforcedStyle
54
- RESTRICT_ON_SEND = %i[have_http_status].freeze
55
-
56
- # @!method http_status(node)
57
- def_node_matcher :http_status, <<-PATTERN
58
- (send nil? :have_http_status ${int sym})
59
- PATTERN
60
-
61
- def on_send(node)
62
- http_status(node) do |arg|
63
- checker = checker_class.new(arg)
64
- return unless checker.offensive?
65
-
66
- add_offense(checker.offense_range,
67
- message: checker.message) do |corrector|
68
- corrector.replace(checker.offense_range, checker.prefer)
69
- end
70
- end
71
- end
72
-
73
- private
74
-
75
- def checker_class
76
- case style
77
- when :symbolic
78
- SymbolicStyleChecker
79
- when :numeric
80
- NumericStyleChecker
81
- when :be_status
82
- BeStatusStyleChecker
83
- end
84
- end
85
-
86
- # :nodoc:
87
- class StyleCheckerBase
88
- MSG = 'Prefer `%<prefer>s` over `%<current>s` ' \
89
- 'to describe HTTP status code.'
90
- ALLOWED_STATUSES = %i[error success missing redirect].freeze
91
-
92
- attr_reader :node
93
-
94
- def initialize(node)
95
- @node = node
96
- end
97
-
98
- def message
99
- format(MSG, prefer: prefer, current: current)
100
- end
101
-
102
- def offense_range
103
- node
104
- end
105
-
106
- def allowed_symbol?
107
- node.sym_type? && ALLOWED_STATUSES.include?(node.value)
108
- end
109
-
110
- def custom_http_status_code?
111
- node.int_type? &&
112
- !::Rack::Utils::SYMBOL_TO_STATUS_CODE.value?(node.source.to_i)
113
- end
114
- end
115
-
116
- # :nodoc:
117
- class SymbolicStyleChecker < StyleCheckerBase
118
- def offensive?
119
- !node.sym_type? && !custom_http_status_code?
120
- end
121
-
122
- def prefer
123
- symbol.inspect
124
- end
125
-
126
- def current
127
- number.inspect
128
- end
129
-
130
- private
131
-
132
- def symbol
133
- ::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(number)
134
- end
135
-
136
- def number
137
- node.source.to_i
138
- end
139
- end
140
-
141
- # :nodoc:
142
- class NumericStyleChecker < StyleCheckerBase
143
- def offensive?
144
- !node.int_type? && !allowed_symbol?
145
- end
146
-
147
- def prefer
148
- number.to_s
149
- end
150
-
151
- def current
152
- symbol.inspect
153
- end
154
-
155
- private
156
-
157
- def symbol
158
- node.value
159
- end
160
-
161
- def number
162
- ::Rack::Utils::SYMBOL_TO_STATUS_CODE[symbol]
163
- end
164
- end
165
-
166
- # :nodoc:
167
- class BeStatusStyleChecker < StyleCheckerBase
168
- def offensive?
169
- (!node.sym_type? && !custom_http_status_code?) ||
170
- (!node.int_type? && !allowed_symbol?)
171
- end
172
-
173
- def offense_range
174
- node.parent
175
- end
176
-
177
- def prefer
178
- if node.sym_type?
179
- "be_#{node.value}"
180
- else
181
- "be_#{symbol}"
182
- end
183
- end
184
-
185
- def current
186
- offense_range.source
187
- end
188
-
189
- private
190
-
191
- def symbol
192
- ::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(number)
193
- end
194
-
195
- def number
196
- node.source.to_i
197
- end
198
- end
199
- end
200
- end
201
- end
202
- end
203
- end
@@ -1,145 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module RSpec
6
- module Rails
7
- # Identifies redundant spec type.
8
- #
9
- # After setting up rspec-rails, you will have enabled
10
- # `config.infer_spec_type_from_file_location!` by default in
11
- # spec/rails_helper.rb. This cop works in conjunction with this config.
12
- # If you disable this config, disable this cop as well.
13
- #
14
- # @safety
15
- # This cop is marked as unsafe because
16
- # `config.infer_spec_type_from_file_location!` may not be enabled.
17
- #
18
- # @example
19
- # # bad
20
- # # spec/models/user_spec.rb
21
- # RSpec.describe User, type: :model do
22
- # end
23
- #
24
- # # good
25
- # # spec/models/user_spec.rb
26
- # RSpec.describe User do
27
- # end
28
- #
29
- # # good
30
- # # spec/models/user_spec.rb
31
- # RSpec.describe User, type: :common do
32
- # end
33
- #
34
- # @example `Inferences` configuration
35
- # # .rubocop.yml
36
- # # RSpec/Rails/InferredSpecType:
37
- # # Inferences:
38
- # # services: service
39
- #
40
- # # bad
41
- # # spec/services/user_spec.rb
42
- # RSpec.describe User, type: :service do
43
- # end
44
- #
45
- # # good
46
- # # spec/services/user_spec.rb
47
- # RSpec.describe User do
48
- # end
49
- #
50
- # # good
51
- # # spec/services/user_spec.rb
52
- # RSpec.describe User, type: :common do
53
- # end
54
- class InferredSpecType < Base
55
- extend AutoCorrector
56
-
57
- MSG = 'Remove redundant spec type.'
58
-
59
- # @param [RuboCop::AST::BlockNode] node
60
- def on_block(node)
61
- return unless example_group?(node)
62
-
63
- pair_node = describe_with_type(node)
64
- return unless pair_node
65
- return unless inferred_type?(pair_node)
66
-
67
- removable_node = detect_removable_node(pair_node)
68
- add_offense(removable_node) do |corrector|
69
- autocorrect(corrector, removable_node)
70
- end
71
- end
72
- alias on_numblock on_block
73
-
74
- private
75
-
76
- # @!method describe_with_type(node)
77
- # @param [RuboCop::AST::BlockNode] node
78
- # @return [RuboCop::AST::PairNode, nil]
79
- def_node_matcher :describe_with_type, <<~PATTERN
80
- (block
81
- (send #rspec? #ExampleGroups.all
82
- ...
83
- (hash <$(pair (sym :type) sym) ...>)
84
- )
85
- ...
86
- )
87
- PATTERN
88
-
89
- # @param [RuboCop::AST::Corrector] corrector
90
- # @param [RuboCop::AST::Node] node
91
- def autocorrect(corrector, node)
92
- corrector.remove(remove_range(node))
93
- end
94
-
95
- # @param [RuboCop::AST::Node] node
96
- # @return [Parser::Source::Range]
97
- def remove_range(node)
98
- if node.left_sibling
99
- node.source_range.with(
100
- begin_pos: node.left_sibling.source_range.end_pos
101
- )
102
- elsif node.right_sibling
103
- node.source_range.with(
104
- end_pos: node.right_sibling.source_range.begin_pos
105
- )
106
- end
107
- end
108
-
109
- # @param [RuboCop::AST::PairNode] node
110
- # @return [RuboCop::AST::Node]
111
- def detect_removable_node(node)
112
- if node.parent.pairs.size == 1
113
- node.parent
114
- else
115
- node
116
- end
117
- end
118
-
119
- # @return [String]
120
- def file_path
121
- processed_source.file_path
122
- end
123
-
124
- # @param [RuboCop::AST::PairNode] node
125
- # @return [Boolean]
126
- def inferred_type?(node)
127
- inferred_type_from_file_path.inspect == node.value.source
128
- end
129
-
130
- # @return [Symbol, nil]
131
- def inferred_type_from_file_path
132
- inferences.find do |prefix, type|
133
- break type.to_sym if file_path.include?("spec/#{prefix}/")
134
- end
135
- end
136
-
137
- # @return [Hash]
138
- def inferences
139
- cop_config['Inferences'] || {}
140
- end
141
- end
142
- end
143
- end
144
- end
145
- end