Skip to content

Commit

Permalink
Handle unknown HTTP status codes for RSpecRails::HttpStatus cop
Browse files Browse the repository at this point in the history
  • Loading branch information
viralpraxis committed Oct 8, 2024
1 parent 41a3bd4 commit e741eab
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 9 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Master (Unreleased)

- Handle unknown HTTP status codes for `RSpecRails/HttpStatus` cop. ([@viralpraxis])

## 2.30.0 (2024-06-12)

- Fix an runtime error for rubocop-rspec +3.0. ([@bquorning])
Expand Down Expand Up @@ -81,4 +83,5 @@
[@r7kamura]: https://github.com/r7kamura
[@splattael]: https://github.com/splattael
[@tmaier]: https://github.com/tmaier
[@viralpraxis]: https://github.com/viralpraxis
[@ydah]: https://github.com/ydah
10 changes: 10 additions & 0 deletions docs/modules/ROOT/pages/cops_rspecrails.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ This cop inspects only `have_http_status` calls.
So, this cop does not check if a method starting with `be_*` is used
when setting for `EnforcedStyle: symbolic` or
`EnforcedStyle: numeric`.
This cop is also capable of detecting unknown HTTP status codes.
=== Examples
Expand Down Expand Up @@ -171,6 +172,15 @@ it { is_expected.to have_http_status :success }
it { is_expected.to have_http_status :error }
----
[source,ruby]
----
# bad
it { is_expected.to have_http_status :oki_doki }
# good
it { is_expected.to have_http_status :ok }
----
=== Configurable attributes
|===
Expand Down
52 changes: 43 additions & 9 deletions lib/rubocop/cop/rspec_rails/http_status.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module RSpecRails
# So, this cop does not check if a method starting with `be_*` is used
# when setting for `EnforcedStyle: symbolic` or
# `EnforcedStyle: numeric`.
# This cop is also capable of detecting unknown HTTP status codes.
#
# @example `EnforcedStyle: symbolic` (default)
# # bad
Expand Down Expand Up @@ -57,6 +58,12 @@ module RSpecRails
# it { is_expected.to have_http_status :success }
# it { is_expected.to have_http_status :error }
#
# @example
# # bad
# it { is_expected.to have_http_status :oki_doki }
#
# # good
# it { is_expected.to have_http_status :ok }
class HttpStatus < ::RuboCop::Cop::Base
extend AutoCorrector
include ConfigurableEnforcedStyle
Expand All @@ -67,7 +74,7 @@ class HttpStatus < ::RuboCop::Cop::Base
(send nil? :have_http_status ${int sym str})
PATTERN

def on_send(node)
def on_send(node) # rubocop:disable Metrics/MethodLength
return unless defined?(::Rack::Utils::SYMBOL_TO_STATUS_CODE)

http_status(node) do |arg|
Expand All @@ -78,6 +85,8 @@ def on_send(node)

add_offense(checker.offense_range,
message: checker.message) do |corrector|
next unless checker.autocorrectable?

corrector.replace(checker.offense_range, checker.prefer)
end
end
Expand All @@ -100,6 +109,7 @@ def checker_class
class StyleCheckerBase
MSG = 'Prefer `%<prefer>s` over `%<current>s` ' \
'to describe HTTP status code.'
MSG_UNKNOWN_STATUS_CODE = 'Unknown status code.'
ALLOWED_STATUSES = %i[error success missing redirect].freeze

attr_reader :node
Expand All @@ -109,7 +119,15 @@ def initialize(node)
end

def message
format(MSG, prefer: prefer, current: current)
if autocorrectable?
format(MSG, prefer: prefer, current: current)
else
MSG_UNKNOWN_STATUS_CODE
end
end

def autocorrectable?
true
end

def current
Expand All @@ -136,6 +154,10 @@ def offensive?
!node.sym_type? && !custom_http_status_code?
end

def autocorrectable?
!!symbol
end

def prefer
symbol.inspect
end
Expand All @@ -157,6 +179,10 @@ def offensive?
!node.int_type? && !allowed_symbol?
end

def autocorrectable?
!!number
end

def prefer
number.to_s
end
Expand All @@ -179,22 +205,30 @@ def offensive?
(!node.int_type? && !allowed_symbol?)
end

def autocorrectable?
!!status_code
end

def offense_range
node.parent
end

def prefer
"be_#{status_code}"
end

private

def status_code
if node.sym_type?
"be_#{node.value}"
node.value
elsif node.int_type?
"be_#{symbol}"
elsif node.str_type?
"be_#{normalize_str}"
symbol
else
normalize_str
end
end

private

def symbol
::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(number)
end
Expand All @@ -207,7 +241,7 @@ def normalize_str
str = node.value.to_s
if str.match?(/\A\d+\z/)
::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(str.to_i)
else
elsif ::Rack::Utils::SYMBOL_TO_STATUS_CODE.key?(str.to_sym)
str
end
end
Expand Down
27 changes: 27 additions & 0 deletions spec/rubocop/cop/rspec_rails/http_status_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,15 @@
RUBY
end
end

it 'registers an offense for unknown status code' do
expect_offense(<<~RUBY)
it { is_expected.to have_http_status("some-custom-string") }
^^^^^^^^^^^^^^^^^^^^ Unknown status code.
RUBY

expect_no_corrections
end
end

context 'when EnforcedStyle is `numeric`' do
Expand Down Expand Up @@ -133,6 +142,15 @@
RUBY
end

it 'registers an offense for unknown status code' do
expect_offense(<<~RUBY)
it { is_expected.to have_http_status("some-custom-string") }
^^^^^^^^^^^^^^^^^^^^ Unknown status code.
RUBY

expect_no_corrections
end

context 'with parenthesis' do
it 'registers an offense when using symbolic value' do
expect_offense(<<~RUBY)
Expand Down Expand Up @@ -237,6 +255,15 @@
RUBY
end

it 'registers an offense for unknown status code' do
expect_offense(<<~RUBY)
it { is_expected.to have_http_status("some-custom-string") }
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Unknown status code.
RUBY

expect_no_corrections
end

context 'with parenthesis' do
it 'registers an offense when using numeric value' do
expect_offense(<<~RUBY)
Expand Down

0 comments on commit e741eab

Please sign in to comment.