rubocop-rspec_rails 2.28.0
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 +7 -0
- data/CHANGELOG.md +58 -0
- data/CODE_OF_CONDUCT.md +17 -0
- data/MIT-LICENSE.md +21 -0
- data/README.md +88 -0
- data/config/default.yml +83 -0
- data/lib/rubocop/cop/rspec_rails/avoid_setup_hook.rb +41 -0
- data/lib/rubocop/cop/rspec_rails/have_http_status.rb +77 -0
- data/lib/rubocop/cop/rspec_rails/http_status.rb +212 -0
- data/lib/rubocop/cop/rspec_rails/inferred_spec_type.rb +143 -0
- data/lib/rubocop/cop/rspec_rails/minitest_assertions.rb +350 -0
- data/lib/rubocop/cop/rspec_rails/negation_be_valid.rb +98 -0
- data/lib/rubocop/cop/rspec_rails/travel_around.rb +90 -0
- data/lib/rubocop/cop/rspec_rails_cops.rb +13 -0
- data/lib/rubocop/rspec_rails/config_formatter.rb +55 -0
- data/lib/rubocop/rspec_rails/description_extractor.rb +72 -0
- data/lib/rubocop/rspec_rails/version.rb +10 -0
- data/lib/rubocop-rspec_rails.rb +14 -0
- metadata +97 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 53524a3483350f80d17572e3e221a777dabb1421999fbbcb37ad30cb182358b1
|
|
4
|
+
data.tar.gz: af8ff0697f66b78c197fc34e8dbd207e75a64473075ccb1b65d00650582d80d5
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 6b42314769301898bd8723c2c8d5e29eee29cb1952b70e3e4abb892f75e8a13c2129933a3a99de8247510030f208925ab70c5a0a1f1ebaf950595a5c7d540152
|
|
7
|
+
data.tar.gz: 9ad058ef82208bb685249e7ed847da8fc4b06b6718033d9153adc6544d28845e91454524531a72f67f25497325876ed140d543e7173b839f72d12044ef37c429
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Master (Unreleased)
|
|
4
|
+
|
|
5
|
+
## 2.28.0 (2024-03-28)
|
|
6
|
+
|
|
7
|
+
- Extracted from `rubocop-rspec` into a separate repository. ([@ydah])
|
|
8
|
+
|
|
9
|
+
## Previously (see [rubocop-rspec's changelist](https://github.com/rubocop/rubocop-rspec/blob/v2.27.1/CHANGELOG.md) for details)
|
|
10
|
+
|
|
11
|
+
- Add support for `assert_true`, `assert_false`, `assert_not_equal`, `assert_not_nil`, `*_empty`, `*_predicate`, `*_kind_of`, `*_in_delta`, `*_match`, `*_instance_of` and `*_includes` assertions in `RSpec/Rails/MinitestAssertions`. ([@ydah], [@G-Rath])
|
|
12
|
+
- Add configuration option `ResponseMethods` to `RSpec/Rails/HaveHttpStatus`. ([@ydah])
|
|
13
|
+
- Add support single quoted string and percent string and heredoc for `RSpec/Rails/HttpStatus`. ([@ydah])
|
|
14
|
+
- Add support `RSpec/Rails/HttpStatus` when `have_http_status` with string argument. ([@ydah])
|
|
15
|
+
- Mark to `Safe: false` for `RSpec/Rails/NegationBeValid` cop. ([@ydah])
|
|
16
|
+
- Add new `RSpec/Rails/NegationBeValid` cop. ([@ydah])
|
|
17
|
+
- Fix a false negative for `RSpec/ExcessiveDocstringSpacing` when finds description with em space. ([@ydah])
|
|
18
|
+
- Fix a false positive for `RSpec/EmptyExampleGroup` when example group with examples defined in `if` branch inside iterator. ([@ydah])
|
|
19
|
+
- Update the message output of `RSpec/ExpectActual` to include the word 'value'. ([@corydiamand])
|
|
20
|
+
- Fix a false negative for `RSpec/Pending` when `it` without body. ([@ydah])
|
|
21
|
+
- Add new `RSpec/ReceiveMessages` cop. ([@ydah])
|
|
22
|
+
- Change default.yml path to use `**/spec/*` instead of `spec/*`. ([@ydah])
|
|
23
|
+
- Add `AllowedIdentifiers` and `AllowedPatterns` configuration option to `RSpec/IndexedLet`. ([@ydah])
|
|
24
|
+
- Fix `RSpec/NamedSubject` when block has no body. ([@splattael])
|
|
25
|
+
- Fix `RSpec/LetBeforeExamples` autocorrect incompatible with `RSpec/ScatteredLet` autocorrect. ([@ydah])
|
|
26
|
+
- Update `RSpec/Focus` to support `shared_context` and `shared_examples`. ([@tmaier])
|
|
27
|
+
- Fix an error for `RSpec/Rails/HaveHttpStatus` with comparison with strings containing non-numeric characters. ([@ydah])
|
|
28
|
+
- Add support `be_status` style for `RSpec/Rails/HttpStatus`. ([@ydah])
|
|
29
|
+
- Fix order of expected and actual in correction for `RSpec/Rails/MinitestAssertions`. ([@mvz])
|
|
30
|
+
- Add `RSpec/Rails/TravelAround` cop. ([@r7kamura])
|
|
31
|
+
- Add new `RSpec/Rails/MinitestAssertions` cop. ([@ydah])
|
|
32
|
+
- Improved processing speed for `RSpec/Be`, `RSpec/ExpectActual`, `RSpec/ImplicitExpect`, `RSpec/MessageSpies`, `RSpec/PredicateMatcher` and `RSpec/Rails/HaveHttpStatus`. ([@ydah])
|
|
33
|
+
- Fix an error for `RSpec/Rails/InferredSpecType` with redundant type before other Hash metadata. ([@ydah])
|
|
34
|
+
- Add `RSpec/Rails/InferredSpecType` cop. ([@r7kamura])
|
|
35
|
+
- Add new `RSpec/Rails/HaveHttpStatus` cop. ([@akiomik])
|
|
36
|
+
- Exclude unrelated Rails directories from `RSpec/DescribeClass`. ([@MothOnMars])
|
|
37
|
+
- Add `RSpec/Rails/AvoidSetupHook` cop. ([@paydaylight])
|
|
38
|
+
- Change namespace of several cops (`Capybara/*` -> `RSpec/Capybara/*`, `FactoryBot/*` -> `RSpec/FactoryBot/*`, `Rails/*` -> `RSpec/Rails/*`). ([@pirj], [@bquorning])
|
|
39
|
+
- The `Rails/HttpStatus` cop is unavailable if the `rack` gem cannot be loaded. ([@bquorning])
|
|
40
|
+
- Fix `Rails/HttpStatus` not working with custom HTTP status codes. ([@bquorning])
|
|
41
|
+
- Add `RSpec/Rails/HttpStatus` cop to enforce consistent usage of the status format (numeric or symbolic). ([@anthony-robin], [@jojos003])
|
|
42
|
+
|
|
43
|
+
<!-- Contributors (alphabetically) -->
|
|
44
|
+
|
|
45
|
+
[@akiomik]: https://github.com/akiomik
|
|
46
|
+
[@anthony-robin]: https://github.com/anthony-robin
|
|
47
|
+
[@bquorning]: https://github.com/bquorning
|
|
48
|
+
[@corydiamand]: https://github.com/corydiamand
|
|
49
|
+
[@g-rath]: https://github.com/G-Rath
|
|
50
|
+
[@jojos003]: https://github.com/jojos003
|
|
51
|
+
[@mothonmars]: https://github.com/MothOnMars
|
|
52
|
+
[@mvz]: https://github.com/mvz
|
|
53
|
+
[@paydaylight]: https://github.com/paydaylight
|
|
54
|
+
[@pirj]: https://github.com/pirj
|
|
55
|
+
[@r7kamura]: https://github.com/r7kamura
|
|
56
|
+
[@splattael]: https://github.com/splattael
|
|
57
|
+
[@tmaier]: https://github.com/tmaier
|
|
58
|
+
[@ydah]: https://github.com/ydah
|
data/CODE_OF_CONDUCT.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# The RuboCop Community Code of Conduct
|
|
2
|
+
|
|
3
|
+
**Note:** We have picked the following code of conduct based on [Ruby's own
|
|
4
|
+
code of conduct](https://www.ruby-lang.org/en/conduct/).
|
|
5
|
+
|
|
6
|
+
This document provides a few simple community guidelines for a safe, respectful,
|
|
7
|
+
productive, and collaborative place for any person who is willing to contribute
|
|
8
|
+
to the RuboCop community. It applies to all "collaborative spaces", which are
|
|
9
|
+
defined as community communications channels (such as mailing lists, submitted
|
|
10
|
+
patches, commit comments, etc.).
|
|
11
|
+
|
|
12
|
+
- Participants will be tolerant of opposing views.
|
|
13
|
+
- Participants must ensure that their language and actions are free of personal
|
|
14
|
+
attacks and disparaging personal remarks.
|
|
15
|
+
- When interpreting the words and actions of others, participants should always
|
|
16
|
+
assume good intentions.
|
|
17
|
+
- Behaviour which can be reasonably considered harassment will not be tolerated.
|
data/MIT-LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2014 Ian MacLeod <ian@nevir.net>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
7
|
+
the Software without restriction, including without limitation the rights to
|
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
9
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
|
10
|
+
so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# RuboCop RSpec Rails
|
|
2
|
+
|
|
3
|
+
[](https://gitter.im/rubocop-rspec/Lobby)
|
|
4
|
+
[](https://rubygems.org/gems/rubocop-rspec_rails)
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
[RSpec Rails](https://rspec.info/)-specific analysis for your projects, as an extension to
|
|
8
|
+
[RuboCop](https://github.com/rubocop/rubocop).
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
Just install the `rubocop-rspec_rails` gem
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
gem install rubocop-rspec_rails
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
or if you use bundler put this in your `Gemfile`
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
gem 'rubocop-rspec_rails', require: false
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
You need to tell RuboCop to load the RSpec Rails extension. There are three
|
|
27
|
+
ways to do this:
|
|
28
|
+
|
|
29
|
+
### RuboCop configuration file
|
|
30
|
+
|
|
31
|
+
Put this into your `.rubocop.yml`.
|
|
32
|
+
|
|
33
|
+
```yaml
|
|
34
|
+
require: rubocop-rspec_rails
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Alternatively, use the following array notation when specifying multiple extensions.
|
|
38
|
+
|
|
39
|
+
```yaml
|
|
40
|
+
require:
|
|
41
|
+
- rubocop-rspec
|
|
42
|
+
- rubocop-rspec_rails
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Now you can run `rubocop` and it will automatically load the RuboCop RSpec Rails
|
|
46
|
+
cops together with the standard cops.
|
|
47
|
+
|
|
48
|
+
### Command line
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
rubocop --require rubocop-rspec_rails
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Rake task
|
|
55
|
+
|
|
56
|
+
```ruby
|
|
57
|
+
RuboCop::RakeTask.new do |task|
|
|
58
|
+
task.requires << 'rubocop-rspec_rails'
|
|
59
|
+
end
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Documentation
|
|
63
|
+
|
|
64
|
+
You can read more about RuboCop RSpec Rails in its [official manual](https://docs.rubocop.org/rubocop-rspec_rails).
|
|
65
|
+
|
|
66
|
+
## The Cops
|
|
67
|
+
|
|
68
|
+
All cops are located under
|
|
69
|
+
[`lib/rubocop/cop/rspec_rails`](lib/rubocop/cop/rspec_rails), and contain
|
|
70
|
+
examples/documentation.
|
|
71
|
+
|
|
72
|
+
In your `.rubocop.yml`, you may treat the RSpec Rails cops just like any other
|
|
73
|
+
cop. For example:
|
|
74
|
+
|
|
75
|
+
```yaml
|
|
76
|
+
RSpecRails/AvoidSetupHook:
|
|
77
|
+
Exclude:
|
|
78
|
+
- spec/my_poorly_named_spec_file.rb
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Contributing
|
|
82
|
+
|
|
83
|
+
Checkout the [contribution guidelines](.github/CONTRIBUTING.md).
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
`rubocop-rspec_rails` is MIT licensed. [See the accompanying file](MIT-LICENSE.md) for
|
|
88
|
+
the full text.
|
data/config/default.yml
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
RSpecRails:
|
|
3
|
+
Enabled: true
|
|
4
|
+
DocumentationBaseURL: https://docs.rubocop.org/rubocop-rspec_rails
|
|
5
|
+
Include:
|
|
6
|
+
- "**/*_spec.rb"
|
|
7
|
+
- "**/spec/**/*"
|
|
8
|
+
|
|
9
|
+
RSpecRails/AvoidSetupHook:
|
|
10
|
+
Description: Checks that tests use RSpec `before` hook over Rails `setup` method.
|
|
11
|
+
Enabled: pending
|
|
12
|
+
VersionAdded: '2.4'
|
|
13
|
+
Reference: https://www.rubydoc.info/gems/rubocop-rspec_rails/RuboCop/Cop/RSpecRails/AvoidSetupHook
|
|
14
|
+
|
|
15
|
+
RSpecRails/HaveHttpStatus:
|
|
16
|
+
Description: Checks that tests use `have_http_status` instead of equality matchers.
|
|
17
|
+
Enabled: pending
|
|
18
|
+
ResponseMethods:
|
|
19
|
+
- response
|
|
20
|
+
- last_response
|
|
21
|
+
SafeAutoCorrect: false
|
|
22
|
+
VersionAdded: '2.12'
|
|
23
|
+
VersionChanged: '2.27'
|
|
24
|
+
Reference: https://www.rubydoc.info/gems/rubocop-rspec_rails/RuboCop/Cop/RSpecRails/HaveHttpStatus
|
|
25
|
+
|
|
26
|
+
RSpecRails/HttpStatus:
|
|
27
|
+
Description: Enforces use of symbolic or numeric value to describe HTTP status.
|
|
28
|
+
Enabled: true
|
|
29
|
+
EnforcedStyle: symbolic
|
|
30
|
+
SupportedStyles:
|
|
31
|
+
- numeric
|
|
32
|
+
- symbolic
|
|
33
|
+
- be_status
|
|
34
|
+
VersionAdded: '1.23'
|
|
35
|
+
VersionChanged: '2.20'
|
|
36
|
+
Reference: https://www.rubydoc.info/gems/rubocop-rspec_rails/RuboCop/Cop/RSpecRails/HttpStatus
|
|
37
|
+
|
|
38
|
+
RSpecRails/InferredSpecType:
|
|
39
|
+
Description: Identifies redundant spec type.
|
|
40
|
+
Enabled: pending
|
|
41
|
+
Safe: false
|
|
42
|
+
VersionAdded: '2.14'
|
|
43
|
+
Reference: https://www.rubydoc.info/gems/rubocop-rspec_rails/RuboCop/Cop/RSpecRails/InferredSpecType
|
|
44
|
+
Inferences:
|
|
45
|
+
channels: channel
|
|
46
|
+
controllers: controller
|
|
47
|
+
features: feature
|
|
48
|
+
generator: generator
|
|
49
|
+
helpers: helper
|
|
50
|
+
jobs: job
|
|
51
|
+
mailboxes: mailbox
|
|
52
|
+
mailers: mailer
|
|
53
|
+
models: model
|
|
54
|
+
requests: request
|
|
55
|
+
integration: request
|
|
56
|
+
api: request
|
|
57
|
+
routing: routing
|
|
58
|
+
system: system
|
|
59
|
+
views: view
|
|
60
|
+
|
|
61
|
+
RSpecRails/MinitestAssertions:
|
|
62
|
+
Description: Check if using Minitest-like matchers.
|
|
63
|
+
Enabled: pending
|
|
64
|
+
VersionAdded: '2.17'
|
|
65
|
+
Reference: https://www.rubydoc.info/gems/rubocop-rspec_rails/RuboCop/Cop/RSpecRails/MinitestAssertions
|
|
66
|
+
|
|
67
|
+
RSpecRails/NegationBeValid:
|
|
68
|
+
Description: Enforces use of `be_invalid` or `not_to` for negated be_valid.
|
|
69
|
+
Safe: false
|
|
70
|
+
EnforcedStyle: not_to
|
|
71
|
+
SupportedStyles:
|
|
72
|
+
- not_to
|
|
73
|
+
- be_invalid
|
|
74
|
+
Enabled: pending
|
|
75
|
+
VersionAdded: '2.23'
|
|
76
|
+
Reference: https://www.rubydoc.info/gems/rubocop-rspec_rails/RuboCop/Cop/RSpecRails/NegationBeValid
|
|
77
|
+
|
|
78
|
+
RSpecRails/TravelAround:
|
|
79
|
+
Description: Prefer to travel in `before` rather than `around`.
|
|
80
|
+
Enabled: pending
|
|
81
|
+
Safe: false
|
|
82
|
+
VersionAdded: '2.19'
|
|
83
|
+
Reference: https://www.rubydoc.info/gems/rubocop-rspec_rails/RuboCop/Cop/RSpecRails/TravelAround
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module RSpecRails
|
|
6
|
+
# Checks that tests use RSpec `before` hook over Rails `setup` method.
|
|
7
|
+
#
|
|
8
|
+
# @example
|
|
9
|
+
# # bad
|
|
10
|
+
# setup do
|
|
11
|
+
# allow(foo).to receive(:bar)
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
# # good
|
|
15
|
+
# before do
|
|
16
|
+
# allow(foo).to receive(:bar)
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
class AvoidSetupHook < ::RuboCop::Cop::RSpec::Base
|
|
20
|
+
extend AutoCorrector
|
|
21
|
+
|
|
22
|
+
MSG = 'Use `before` instead of `setup`.'
|
|
23
|
+
|
|
24
|
+
# @!method setup_call(node)
|
|
25
|
+
def_node_matcher :setup_call, <<~PATTERN
|
|
26
|
+
(block
|
|
27
|
+
$(send nil? :setup)
|
|
28
|
+
(args) _)
|
|
29
|
+
PATTERN
|
|
30
|
+
|
|
31
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
|
32
|
+
setup_call(node) do |setup|
|
|
33
|
+
add_offense(node) do |corrector|
|
|
34
|
+
corrector.replace setup, 'before'
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module RSpecRails
|
|
6
|
+
# Checks that tests use `have_http_status` instead of equality matchers.
|
|
7
|
+
#
|
|
8
|
+
# @example ResponseMethods: ['response', 'last_response'] (default)
|
|
9
|
+
# # bad
|
|
10
|
+
# expect(response.status).to be(200)
|
|
11
|
+
# expect(last_response.code).to eq("200")
|
|
12
|
+
#
|
|
13
|
+
# # good
|
|
14
|
+
# expect(response).to have_http_status(200)
|
|
15
|
+
# expect(last_response).to have_http_status(200)
|
|
16
|
+
#
|
|
17
|
+
# @example ResponseMethods: ['foo_response']
|
|
18
|
+
# # bad
|
|
19
|
+
# expect(foo_response.status).to be(200)
|
|
20
|
+
#
|
|
21
|
+
# # good
|
|
22
|
+
# expect(foo_response).to have_http_status(200)
|
|
23
|
+
#
|
|
24
|
+
# # also good
|
|
25
|
+
# expect(response).to have_http_status(200)
|
|
26
|
+
# expect(last_response).to have_http_status(200)
|
|
27
|
+
#
|
|
28
|
+
class HaveHttpStatus < ::RuboCop::Cop::Base
|
|
29
|
+
extend AutoCorrector
|
|
30
|
+
|
|
31
|
+
MSG =
|
|
32
|
+
'Prefer `expect(%<response>s).%<to>s ' \
|
|
33
|
+
'have_http_status(%<status>s)` over `%<bad_code>s`.'
|
|
34
|
+
|
|
35
|
+
RUNNERS = %i[to to_not not_to].to_set
|
|
36
|
+
RESTRICT_ON_SEND = RUNNERS
|
|
37
|
+
|
|
38
|
+
# @!method match_status(node)
|
|
39
|
+
def_node_matcher :match_status, <<~PATTERN
|
|
40
|
+
(send
|
|
41
|
+
(send nil? :expect
|
|
42
|
+
$(send $(send nil? #response_methods?) {:status :code})
|
|
43
|
+
)
|
|
44
|
+
$RUNNERS
|
|
45
|
+
$(send nil? {:be :eq :eql :equal} ({int str} $_))
|
|
46
|
+
)
|
|
47
|
+
PATTERN
|
|
48
|
+
|
|
49
|
+
def on_send(node) # rubocop:disable Metrics/MethodLength
|
|
50
|
+
match_status(node) do
|
|
51
|
+
|response_status, response_method, to, match, status|
|
|
52
|
+
return unless status.to_s.match?(/\A\d+\z/)
|
|
53
|
+
|
|
54
|
+
message = format(MSG, response: response_method.method_name,
|
|
55
|
+
to: to, status: status,
|
|
56
|
+
bad_code: node.source)
|
|
57
|
+
add_offense(node, message: message) do |corrector|
|
|
58
|
+
corrector.replace(response_status, response_method.method_name)
|
|
59
|
+
corrector.replace(match.loc.selector, 'have_http_status')
|
|
60
|
+
corrector.replace(match.first_argument, status.to_s)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def response_methods?(name)
|
|
68
|
+
response_methods.include?(name.to_s)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def response_methods
|
|
72
|
+
cop_config.fetch('ResponseMethods', [])
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rack/utils'
|
|
4
|
+
|
|
5
|
+
module RuboCop
|
|
6
|
+
module Cop
|
|
7
|
+
module RSpecRails
|
|
8
|
+
# Enforces use of symbolic or numeric value to describe HTTP status.
|
|
9
|
+
#
|
|
10
|
+
# This cop inspects only `have_http_status` calls.
|
|
11
|
+
# So, this cop does not check if a method starting with `be_*` is used
|
|
12
|
+
# when setting for `EnforcedStyle: symbolic` or
|
|
13
|
+
# `EnforcedStyle: numeric`.
|
|
14
|
+
#
|
|
15
|
+
# @example `EnforcedStyle: symbolic` (default)
|
|
16
|
+
# # bad
|
|
17
|
+
# it { is_expected.to have_http_status 200 }
|
|
18
|
+
# it { is_expected.to have_http_status 404 }
|
|
19
|
+
# it { is_expected.to have_http_status "403" }
|
|
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 :forbidden }
|
|
25
|
+
# it { is_expected.to have_http_status :success }
|
|
26
|
+
# it { is_expected.to have_http_status :error }
|
|
27
|
+
#
|
|
28
|
+
# @example `EnforcedStyle: numeric`
|
|
29
|
+
# # bad
|
|
30
|
+
# it { is_expected.to have_http_status :ok }
|
|
31
|
+
# it { is_expected.to have_http_status :not_found }
|
|
32
|
+
# it { is_expected.to have_http_status "forbidden" }
|
|
33
|
+
#
|
|
34
|
+
# # good
|
|
35
|
+
# it { is_expected.to have_http_status 200 }
|
|
36
|
+
# it { is_expected.to have_http_status 404 }
|
|
37
|
+
# it { is_expected.to have_http_status 403 }
|
|
38
|
+
# it { is_expected.to have_http_status :success }
|
|
39
|
+
# it { is_expected.to have_http_status :error }
|
|
40
|
+
#
|
|
41
|
+
# @example `EnforcedStyle: be_status`
|
|
42
|
+
# # bad
|
|
43
|
+
# it { is_expected.to have_http_status :ok }
|
|
44
|
+
# it { is_expected.to have_http_status :not_found }
|
|
45
|
+
# it { is_expected.to have_http_status "forbidden" }
|
|
46
|
+
# it { is_expected.to have_http_status 200 }
|
|
47
|
+
# it { is_expected.to have_http_status 404 }
|
|
48
|
+
# it { is_expected.to have_http_status "403" }
|
|
49
|
+
#
|
|
50
|
+
# # good
|
|
51
|
+
# it { is_expected.to be_ok }
|
|
52
|
+
# it { is_expected.to be_not_found }
|
|
53
|
+
# it { is_expected.to have_http_status :success }
|
|
54
|
+
# it { is_expected.to have_http_status :error }
|
|
55
|
+
#
|
|
56
|
+
class HttpStatus < ::RuboCop::Cop::RSpec::Base
|
|
57
|
+
extend AutoCorrector
|
|
58
|
+
include ConfigurableEnforcedStyle
|
|
59
|
+
RESTRICT_ON_SEND = %i[have_http_status].freeze
|
|
60
|
+
|
|
61
|
+
# @!method http_status(node)
|
|
62
|
+
def_node_matcher :http_status, <<~PATTERN
|
|
63
|
+
(send nil? :have_http_status ${int sym str})
|
|
64
|
+
PATTERN
|
|
65
|
+
|
|
66
|
+
def on_send(node)
|
|
67
|
+
http_status(node) do |arg|
|
|
68
|
+
return if arg.str_type? && arg.heredoc?
|
|
69
|
+
|
|
70
|
+
checker = checker_class.new(arg)
|
|
71
|
+
return unless checker.offensive?
|
|
72
|
+
|
|
73
|
+
add_offense(checker.offense_range,
|
|
74
|
+
message: checker.message) do |corrector|
|
|
75
|
+
corrector.replace(checker.offense_range, checker.prefer)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
def checker_class
|
|
83
|
+
case style
|
|
84
|
+
when :symbolic
|
|
85
|
+
SymbolicStyleChecker
|
|
86
|
+
when :numeric
|
|
87
|
+
NumericStyleChecker
|
|
88
|
+
when :be_status
|
|
89
|
+
BeStatusStyleChecker
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# :nodoc:
|
|
94
|
+
class StyleCheckerBase
|
|
95
|
+
MSG = 'Prefer `%<prefer>s` over `%<current>s` ' \
|
|
96
|
+
'to describe HTTP status code.'
|
|
97
|
+
ALLOWED_STATUSES = %i[error success missing redirect].freeze
|
|
98
|
+
|
|
99
|
+
attr_reader :node
|
|
100
|
+
|
|
101
|
+
def initialize(node)
|
|
102
|
+
@node = node
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def message
|
|
106
|
+
format(MSG, prefer: prefer, current: current)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def current
|
|
110
|
+
offense_range.source
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def offense_range
|
|
114
|
+
node
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def allowed_symbol?
|
|
118
|
+
node.sym_type? && ALLOWED_STATUSES.include?(node.value)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def custom_http_status_code?
|
|
122
|
+
node.int_type? &&
|
|
123
|
+
!::Rack::Utils::SYMBOL_TO_STATUS_CODE.value?(node.source.to_i)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# :nodoc:
|
|
128
|
+
class SymbolicStyleChecker < StyleCheckerBase
|
|
129
|
+
def offensive?
|
|
130
|
+
!node.sym_type? && !custom_http_status_code?
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def prefer
|
|
134
|
+
symbol.inspect
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
private
|
|
138
|
+
|
|
139
|
+
def symbol
|
|
140
|
+
::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(number)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def number
|
|
144
|
+
node.value.to_i
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# :nodoc:
|
|
149
|
+
class NumericStyleChecker < StyleCheckerBase
|
|
150
|
+
def offensive?
|
|
151
|
+
!node.int_type? && !allowed_symbol?
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def prefer
|
|
155
|
+
number.to_s
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
private
|
|
159
|
+
|
|
160
|
+
def symbol
|
|
161
|
+
node.value
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def number
|
|
165
|
+
::Rack::Utils::SYMBOL_TO_STATUS_CODE[symbol.to_sym]
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# :nodoc:
|
|
170
|
+
class BeStatusStyleChecker < StyleCheckerBase
|
|
171
|
+
def offensive?
|
|
172
|
+
(!node.sym_type? && !custom_http_status_code?) ||
|
|
173
|
+
(!node.int_type? && !allowed_symbol?)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def offense_range
|
|
177
|
+
node.parent
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def prefer
|
|
181
|
+
if node.sym_type?
|
|
182
|
+
"be_#{node.value}"
|
|
183
|
+
elsif node.int_type?
|
|
184
|
+
"be_#{symbol}"
|
|
185
|
+
elsif node.str_type?
|
|
186
|
+
"be_#{normalize_str}"
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
private
|
|
191
|
+
|
|
192
|
+
def symbol
|
|
193
|
+
::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(number)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def number
|
|
197
|
+
node.value.to_i
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def normalize_str
|
|
201
|
+
str = node.value.to_s
|
|
202
|
+
if str.match?(/\A\d+\z/)
|
|
203
|
+
::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(str.to_i)
|
|
204
|
+
else
|
|
205
|
+
str
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|