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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +147 -9
- data/README.md +2 -2
- data/config/default.yml +159 -244
- data/config/obsoletion.yml +24 -0
- data/lib/rubocop/cop/rspec/around_block.rb +3 -3
- data/lib/rubocop/cop/rspec/base.rb +0 -1
- data/lib/rubocop/cop/rspec/be.rb +1 -1
- data/lib/rubocop/cop/rspec/be_empty.rb +1 -0
- data/lib/rubocop/cop/rspec/be_eq.rb +1 -1
- data/lib/rubocop/cop/rspec/be_eql.rb +1 -1
- data/lib/rubocop/cop/rspec/be_nil.rb +2 -2
- data/lib/rubocop/cop/rspec/before_after_all.rb +7 -13
- data/lib/rubocop/cop/rspec/change_by_zero.rb +30 -4
- data/lib/rubocop/cop/rspec/context_method.rb +2 -2
- data/lib/rubocop/cop/rspec/context_wording.rb +1 -1
- data/lib/rubocop/cop/rspec/describe_symbol.rb +1 -1
- data/lib/rubocop/cop/rspec/described_class.rb +33 -11
- data/lib/rubocop/cop/rspec/dialect.rb +13 -0
- data/lib/rubocop/cop/rspec/duplicated_metadata.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_example_group.rb +4 -1
- data/lib/rubocop/cop/rspec/empty_hook.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_line_after_example.rb +2 -2
- data/lib/rubocop/cop/rspec/empty_metadata.rb +46 -0
- data/lib/rubocop/cop/rspec/empty_output.rb +47 -0
- data/lib/rubocop/cop/rspec/eq.rb +47 -0
- data/lib/rubocop/cop/rspec/example_length.rb +11 -5
- data/lib/rubocop/cop/rspec/example_without_description.rb +11 -2
- data/lib/rubocop/cop/rspec/example_wording.rb +11 -2
- data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +14 -5
- data/lib/rubocop/cop/rspec/expect_actual.rb +17 -14
- data/lib/rubocop/cop/rspec/expect_change.rb +2 -2
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +1 -1
- data/lib/rubocop/cop/rspec/expect_in_let.rb +42 -0
- data/lib/rubocop/cop/rspec/expect_output.rb +1 -4
- data/lib/rubocop/cop/rspec/focus.rb +17 -2
- data/lib/rubocop/cop/rspec/hook_argument.rb +2 -2
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +1 -1
- data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +2 -2
- data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -1
- data/lib/rubocop/cop/rspec/implicit_subject.rb +2 -2
- data/lib/rubocop/cop/rspec/indexed_let.rb +32 -1
- data/lib/rubocop/cop/rspec/instance_spy.rb +2 -2
- data/lib/rubocop/cop/rspec/instance_variable.rb +4 -4
- data/lib/rubocop/cop/rspec/is_expected_specify.rb +45 -0
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +3 -3
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +2 -2
- data/lib/rubocop/cop/rspec/let_before_examples.rb +5 -1
- data/lib/rubocop/cop/rspec/let_setup.rb +1 -1
- data/lib/rubocop/cop/rspec/message_expectation.rb +1 -2
- data/lib/rubocop/cop/rspec/message_spies.rb +0 -2
- data/lib/rubocop/cop/rspec/metadata_style.rb +202 -0
- data/lib/rubocop/cop/rspec/missing_expectation_target_method.rb +54 -0
- data/lib/rubocop/cop/rspec/mixin/file_help.rb +14 -0
- data/lib/rubocop/cop/rspec/mixin/metadata.rb +21 -7
- data/lib/rubocop/cop/rspec/mixin/skip_or_pending.rb +2 -2
- data/lib/rubocop/cop/rspec/multiple_describes.rb +1 -1
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +16 -11
- data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +2 -4
- data/lib/rubocop/cop/rspec/named_subject.rb +6 -3
- data/lib/rubocop/cop/rspec/pending.rb +12 -2
- data/lib/rubocop/cop/rspec/pending_without_reason.rb +1 -1
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +10 -10
- data/lib/rubocop/cop/rspec/receive_counts.rb +1 -1
- data/lib/rubocop/cop/rspec/receive_messages.rb +161 -0
- data/lib/rubocop/cop/rspec/redundant_predicate_matcher.rb +67 -0
- data/lib/rubocop/cop/rspec/remove_const.rb +39 -0
- data/lib/rubocop/cop/rspec/repeated_example.rb +6 -6
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +1 -1
- data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +2 -2
- data/lib/rubocop/cop/rspec/repeated_include_example.rb +1 -1
- data/lib/rubocop/cop/rspec/repeated_subject_call.rb +125 -0
- data/lib/rubocop/cop/rspec/return_from_stub.rb +1 -1
- data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
- data/lib/rubocop/cop/rspec/shared_context.rb +1 -1
- data/lib/rubocop/cop/rspec/shared_examples.rb +66 -20
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +2 -3
- data/lib/rubocop/cop/rspec/sort_metadata.rb +3 -2
- data/lib/rubocop/cop/rspec/spec_file_path_format.rb +133 -0
- data/lib/rubocop/cop/rspec/spec_file_path_suffix.rb +40 -0
- data/lib/rubocop/cop/rspec/stubbed_mock.rb +4 -2
- data/lib/rubocop/cop/rspec/subject_stub.rb +6 -6
- data/lib/rubocop/cop/rspec/undescriptive_literals_description.rb +69 -0
- data/lib/rubocop/cop/rspec/unspecified_exception.rb +2 -2
- data/lib/rubocop/cop/rspec/variable_definition.rb +4 -4
- data/lib/rubocop/cop/rspec/verified_double_reference.rb +6 -6
- data/lib/rubocop/cop/rspec/verified_doubles.rb +2 -2
- data/lib/rubocop/cop/rspec/void_expect.rb +4 -3
- data/lib/rubocop/cop/rspec_cops.rb +14 -28
- data/lib/rubocop/rspec/concept.rb +0 -1
- data/lib/rubocop/rspec/config_formatter.rb +1 -11
- data/lib/rubocop/rspec/cop/generator.rb +25 -0
- data/lib/rubocop/rspec/language.rb +8 -9
- data/lib/rubocop/rspec/node.rb +1 -1
- data/lib/rubocop/rspec/shared_contexts/default_rspec_language_config_context.rb +1 -1
- data/lib/rubocop/rspec/version.rb +1 -1
- data/lib/rubocop/rspec/wording.rb +8 -0
- data/lib/rubocop-rspec.rb +2 -16
- metadata +27 -49
- data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +0 -39
- data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +0 -104
- data/lib/rubocop/cop/rspec/capybara/match_style.rb +0 -38
- data/lib/rubocop/cop/rspec/capybara/negation_matcher.rb +0 -33
- data/lib/rubocop/cop/rspec/capybara/specific_actions.rb +0 -29
- data/lib/rubocop/cop/rspec/capybara/specific_finders.rb +0 -24
- data/lib/rubocop/cop/rspec/capybara/specific_matcher.rb +0 -35
- data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +0 -36
- data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +0 -128
- data/lib/rubocop/cop/rspec/factory_bot/consistent_parentheses_style.rb +0 -117
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +0 -260
- data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +0 -56
- data/lib/rubocop/cop/rspec/factory_bot/factory_name_style.rb +0 -74
- data/lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb +0 -89
- data/lib/rubocop/cop/rspec/file_path.rb +0 -173
- data/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb +0 -43
- data/lib/rubocop/cop/rspec/rails/have_http_status.rb +0 -55
- data/lib/rubocop/cop/rspec/rails/http_status.rb +0 -203
- data/lib/rubocop/cop/rspec/rails/inferred_spec_type.rb +0 -145
- data/lib/rubocop/cop/rspec/rails/minitest_assertions.rb +0 -60
- data/lib/rubocop/cop/rspec/rails/travel_around.rb +0 -92
- data/lib/rubocop/rspec/factory_bot/language.rb +0 -37
- data/lib/rubocop/rspec/factory_bot.rb +0 -64
- 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
|