rubocop-rspec 2.21.0 → 3.0.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 (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