Skip to content

Commit 0610b73

Browse files
authored
Merge pull request #1527 from ydah/feature/1148
Add support `be_status` style for `RSpec/Rails/HttpStatus`
2 parents cfa122e + af64ecd commit 0610b73

File tree

5 files changed

+181
-36
lines changed

5 files changed

+181
-36
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Master (Unreleased)
44

5+
- Add support `be_status` style for `RSpec/Rails/HttpStatus`. ([@ydah])
56
- Add new `RSpec/IndexedLet` cop. ([@dmitrytsepelev])
67
- Fix order of expected and actual in correction for `RSpec/Rails/MinitestAssertions` ([@mvz])
78
- Fix a false positive for `RSpec/FactoryBot/ConsistentParenthesesStyle` inside `&&`, `||` and `:?` when `omit_parentheses` is on ([@dmitrytsepelev])

config/default.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1061,8 +1061,9 @@ RSpec/Rails/HttpStatus:
10611061
SupportedStyles:
10621062
- numeric
10631063
- symbolic
1064+
- be_status
10641065
VersionAdded: '1.23'
1065-
VersionChanged: '2.0'
1066+
VersionChanged: "<<next>>"
10661067
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/HttpStatus
10671068

10681069
RSpec/Rails/InferredSpecType:

docs/modules/ROOT/pages/cops_rspec_rails.adoc

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,16 @@ expect(response).to have_http_status(200)
7272
| Yes
7373
| Yes
7474
| 1.23
75-
| 2.0
75+
| <<next>>
7676
|===
7777

7878
Enforces use of symbolic or numeric value to describe HTTP status.
7979

80+
This cop inspects only `have_http_status` calls.
81+
So, this cop does not check if a method starting with `be_*` is used
82+
when setting for `EnforcedStyle: symbolic` or
83+
`EnforcedStyle: numeric`.
84+
8085
=== Examples
8186

8287
==== `EnforcedStyle: symbolic` (default)
@@ -109,14 +114,31 @@ it { is_expected.to have_http_status :success }
109114
it { is_expected.to have_http_status :error }
110115
----
111116

117+
==== `EnforcedStyle: be_status`
118+
119+
[source,ruby]
120+
----
121+
# bad
122+
it { is_expected.to have_http_status :ok }
123+
it { is_expected.to have_http_status :not_found }
124+
it { is_expected.to have_http_status 200 }
125+
it { is_expected.to have_http_status 404 }
126+
127+
# good
128+
it { is_expected.to be_ok }
129+
it { is_expected.to be_not_found }
130+
it { is_expected.to have_http_status :success }
131+
it { is_expected.to have_http_status :error }
132+
----
133+
112134
=== Configurable attributes
113135

114136
|===
115137
| Name | Default value | Configurable values
116138

117139
| EnforcedStyle
118140
| `symbolic`
119-
| `numeric`, `symbolic`
141+
| `numeric`, `symbolic`, `be_status`
120142
|===
121143

122144
=== References

lib/rubocop/cop/rspec/rails/http_status.rb

Lines changed: 89 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ module RSpec
88
module Rails
99
# Enforces use of symbolic or numeric value to describe HTTP status.
1010
#
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+
#
1116
# @example `EnforcedStyle: symbolic` (default)
1217
# # bad
1318
# it { is_expected.to have_http_status 200 }
@@ -30,6 +35,19 @@ module Rails
3035
# it { is_expected.to have_http_status :success }
3136
# it { is_expected.to have_http_status :error }
3237
#
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+
#
3351
class HttpStatus < Base
3452
extend AutoCorrector
3553
include ConfigurableEnforcedStyle
@@ -41,12 +59,13 @@ class HttpStatus < Base
4159
PATTERN
4260

4361
def on_send(node)
44-
http_status(node) do |ast_node|
45-
checker = checker_class.new(ast_node)
62+
http_status(node) do |arg|
63+
checker = checker_class.new(arg)
4664
return unless checker.offensive?
4765

48-
add_offense(checker.node, message: checker.message) do |corrector|
49-
corrector.replace(checker.node, checker.preferred_style)
66+
add_offense(checker.offense_range,
67+
message: checker.message) do |corrector|
68+
corrector.replace(checker.offense_range, checker.prefer)
5069
end
5170
end
5271
end
@@ -59,30 +78,53 @@ def checker_class
5978
SymbolicStyleChecker
6079
when :numeric
6180
NumericStyleChecker
81+
when :be_status
82+
BeStatusStyleChecker
6283
end
6384
end
6485

6586
# :nodoc:
66-
class SymbolicStyleChecker
87+
class StyleCheckerBase
6788
MSG = 'Prefer `%<prefer>s` over `%<current>s` ' \
6889
'to describe HTTP status code.'
90+
ALLOWED_STATUSES = %i[error success missing redirect].freeze
6991

7092
attr_reader :node
7193

7294
def initialize(node)
7395
@node = node
7496
end
7597

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
76118
def offensive?
77119
!node.sym_type? && !custom_http_status_code?
78120
end
79121

80-
def message
81-
format(MSG, prefer: preferred_style, current: number.to_s)
122+
def prefer
123+
symbol.inspect
82124
end
83125

84-
def preferred_style
85-
symbol.inspect
126+
def current
127+
number.inspect
86128
end
87129

88130
private
@@ -94,50 +136,64 @@ def symbol
94136
def number
95137
node.source.to_i
96138
end
97-
98-
def custom_http_status_code?
99-
node.int_type? &&
100-
!::Rack::Utils::SYMBOL_TO_STATUS_CODE.value?(node.source.to_i)
101-
end
102139
end
103140

104141
# :nodoc:
105-
class NumericStyleChecker
106-
MSG = 'Prefer `%<prefer>s` over `%<current>s` ' \
107-
'to describe HTTP status code.'
108-
109-
ALLOWED_STATUSES = %i[error success missing redirect].freeze
110-
111-
attr_reader :node
112-
113-
def initialize(node)
114-
@node = node
115-
end
116-
142+
class NumericStyleChecker < StyleCheckerBase
117143
def offensive?
118144
!node.int_type? && !allowed_symbol?
119145
end
120146

121-
def message
122-
format(MSG, prefer: preferred_style, current: symbol.inspect)
147+
def prefer
148+
number.to_s
123149
end
124150

125-
def preferred_style
126-
number.to_s
151+
def current
152+
symbol.inspect
127153
end
128154

129155
private
130156

157+
def symbol
158+
node.value
159+
end
160+
131161
def number
132162
::Rack::Utils::SYMBOL_TO_STATUS_CODE[symbol]
133163
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
134190

135191
def symbol
136-
node.value
192+
::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(number)
137193
end
138194

139-
def allowed_symbol?
140-
node.sym_type? && ALLOWED_STATUSES.include?(node.value)
195+
def number
196+
node.source.to_i
141197
end
142198
end
143199
end

spec/rubocop/cop/rspec/rails/http_status_spec.rb

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,69 @@
8383
end
8484
end
8585
end
86+
87+
context 'when EnforcedStyle is `be_status`' do
88+
let(:cop_config) { { 'EnforcedStyle' => 'be_status' } }
89+
90+
it 'registers an offense when using numeric value' do
91+
expect_offense(<<-RUBY)
92+
it { is_expected.to have_http_status 200 }
93+
^^^^^^^^^^^^^^^^^^^^ Prefer `be_ok` over `have_http_status 200` to describe HTTP status code.
94+
RUBY
95+
96+
expect_correction(<<-RUBY)
97+
it { is_expected.to be_ok }
98+
RUBY
99+
end
100+
101+
it 'registers an offense when using symbolic value' do
102+
expect_offense(<<-RUBY)
103+
it { is_expected.to have_http_status :ok }
104+
^^^^^^^^^^^^^^^^^^^^ Prefer `be_ok` over `have_http_status :ok` to describe HTTP status code.
105+
RUBY
106+
107+
expect_correction(<<-RUBY)
108+
it { is_expected.to be_ok }
109+
RUBY
110+
end
111+
112+
it 'does not register an offense when using numeric value' do
113+
expect_no_offenses(<<-RUBY)
114+
it { is_expected.to be_ok }
115+
RUBY
116+
end
117+
118+
it 'does not register an offense when using allowed symbols' do
119+
expect_no_offenses(<<-RUBY)
120+
it { is_expected.to have_http_status :error }
121+
it { is_expected.to have_http_status :success }
122+
it { is_expected.to have_http_status :missing }
123+
it { is_expected.to have_http_status :redirect }
124+
RUBY
125+
end
126+
127+
context 'with parenthesis' do
128+
it 'registers an offense when using numeric value' do
129+
expect_offense(<<-RUBY)
130+
it { is_expected.to have_http_status(404) }
131+
^^^^^^^^^^^^^^^^^^^^^ Prefer `be_not_found` over `have_http_status(404)` to describe HTTP status code.
132+
RUBY
133+
134+
expect_correction(<<-RUBY)
135+
it { is_expected.to be_not_found }
136+
RUBY
137+
end
138+
139+
it 'registers an offense when using symbolic value' do
140+
expect_offense(<<-RUBY)
141+
it { is_expected.to have_http_status(:not_found) }
142+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `be_not_found` over `have_http_status(:not_found)` to describe HTTP status code.
143+
RUBY
144+
145+
expect_correction(<<-RUBY)
146+
it { is_expected.to be_not_found }
147+
RUBY
148+
end
149+
end
150+
end
86151
end

0 commit comments

Comments
 (0)