rubocop-betterment 1.17.0 → 1.19.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8239d7858cb48ea9f9d93ee9f84ad1619b85eba879b9d426ee6170013b8fa822
4
- data.tar.gz: b3543e852dd249fa2be8ee46d12a8742a2c9de750a1a77847a7a22cb4c47a98b
3
+ metadata.gz: e45880e05081ae8b62a4b1e1fb9778a5580b9b17fe839973f1046242222881e1
4
+ data.tar.gz: 4212f8e0f60a70d61db53a2f9af447248efc686d593af0145c715a5a831db683
5
5
  SHA512:
6
- metadata.gz: f2195af7a4f7c629cfee631d365854d507791fa5aa96fbdcbcbab0dadb6e0d70f13c6908fd5949ba3be565527098a37112cdc55dc8dd1b1b13664c3f489d9298
7
- data.tar.gz: 5cda689379c9b1ba9d5508120b0a6479a73f06f158273ef67b0039e64f7c56a2199f23658204b3c873f2623b99f2d54580cf930e51002a84addc8767805134d6
6
+ metadata.gz: be0a7163ee430bcc93333c227cdbe56180864dbac0f128e0e70fc526a2a82b202d36f8e54fad30d8bdf33c66fc668c9ad207ddc29d1f6eaeea97b35f4a676070
7
+ data.tar.gz: a4aefcc523eb8c4c63ce31d851e4a47461288a6ee152e9a53572258135778098e55e7b470d1058f2dbd283d4d9c45abcd714717327db5ee1d6114d4f0bfd8d91
@@ -87,4 +87,25 @@ user1 = User.first
87
87
  user2 = User.second
88
88
  ```
89
89
 
90
- The snake case style is more readable.
90
+ The snake case style is more readable.
91
+
92
+ ## Betterment/ServerErrorAssertion
93
+
94
+ In RSpec tests, we prevent HTTP response status assertions against server error codes (e.g., 500). While it’s acceptable to
95
+ “under-build” APIs under assumption of controlled and well-behaving clients, these exceptions should be treated as undefined behavior and
96
+ thus do not need request spec coverage. In cases where the server must communicate an expected failure to the client, an appropriate
97
+ semantic status code must be used (e.g., 403, 422, etc.).
98
+
99
+ ### GOOD:
100
+
101
+ ```ruby
102
+ expect(response).to have_http_status :forbidden
103
+ expect(response).to have_http_status 422
104
+ ```
105
+
106
+ ### BAD:
107
+
108
+ ```ruby
109
+ expect(response).to have_http_status :internal_server_error
110
+ expect(response).to have_http_status 500
111
+ ```
@@ -17,6 +17,11 @@ AllCops:
17
17
  DisplayStyleGuide: true
18
18
  DisplayCopNames: true
19
19
 
20
+ Betterment/ServerErrorAssertion:
21
+ Description: 'Detects assertions on 5XX HTTP statuses.'
22
+ Include:
23
+ - 'spec/requests/**/*_spec.rb'
24
+
20
25
  Betterment/AuthorizationInController:
21
26
  Description: 'Detects unsafe handling of id-like parameters in controllers.'
22
27
  Enabled: false
@@ -10,3 +10,4 @@ require 'rubocop/cop/betterment/spec_helper_required_outside_spec_dir'
10
10
  require 'rubocop/cop/betterment/implicit_redirect_type'
11
11
  require 'rubocop/cop/betterment/active_job_performable'
12
12
  require 'rubocop/cop/betterment/allowlist_blocklist'
13
+ require 'rubocop/cop/betterment/server_error_assertion'
@@ -21,7 +21,7 @@ module RuboCop
21
21
  def evaluate_node(node)
22
22
  return unless should_use_allowlist?(node) || should_use_blocklist?(node)
23
23
 
24
- add_offense(node, message: MSG)
24
+ add_offense(node)
25
25
  end
26
26
 
27
27
  def should_use_allowlist?(node)
@@ -51,12 +51,12 @@ module RuboCop
51
51
  return if !model_new?(node) && !model_update?(node)
52
52
 
53
53
  arg_nodes.each do |argument|
54
- if argument.type == :send
54
+ if argument.send_type?
55
55
  tag_unsafe_param_hash(argument)
56
56
  tag_unsafe_param_permit_wrapper(argument)
57
57
  elsif argument.variable?
58
58
  tag_unsafe_param_permit_wrapper(argument)
59
- elsif argument.type == :hash
59
+ elsif argument.hash_type?
60
60
  argument.children.each do |pair|
61
61
  next if pair.type != :pair
62
62
 
@@ -130,7 +130,7 @@ module RuboCop
130
130
  end
131
131
 
132
132
  def get_all_assignments(node)
133
- return [] unless node.children && node.type == :class
133
+ return [] unless node.children && node.class_type?
134
134
 
135
135
  node.descendants.select do |descendant|
136
136
  _lhs, rhs = *descendant
@@ -143,10 +143,10 @@ module RuboCop
143
143
  end
144
144
 
145
145
  def get_all_methods(node)
146
- return [] unless node.children && node.type == :class
146
+ return [] unless node.children && node.class_type?
147
147
 
148
148
  node.descendants.select do |descendant|
149
- descendant.type == :def
149
+ descendant.def_type?
150
150
  end
151
151
  end
152
152
 
@@ -158,10 +158,10 @@ module RuboCop
158
158
  wrappers = []
159
159
 
160
160
  methods.each do |method|
161
- return [] unless method.type == :def || method.type == :send
161
+ return [] unless method.def_type? || method.send_type?
162
162
 
163
- method.descendants.each do |child|
164
- next unless child.type == :send
163
+ method.descendants.each do |child|
164
+ next unless child.send_type?
165
165
  next unless param_symbol?(child.method_name)
166
166
 
167
167
  child.ancestors.each do |ancestor|
@@ -27,7 +27,7 @@ module RuboCop
27
27
  return unless arg_nodes
28
28
 
29
29
  arg_nodes.find do |arg|
30
- arg.type == :array && find_dynamic_param(arg.values) || !arg.literal? && !arg.const_type?
30
+ arg.array_type? && find_dynamic_param(arg.values) || !arg.literal? && !arg.const_type?
31
31
  end
32
32
  end
33
33
  end
@@ -47,7 +47,7 @@ module RuboCop
47
47
  return unless routes_file?
48
48
 
49
49
  if block_form_with_options(node) { |options| options.none?(&method(:valid_status_option?)) } || block_form_without_options?(node)
50
- add_offense(node, message: MSG)
50
+ add_offense(node)
51
51
  end
52
52
  end
53
53
 
@@ -55,7 +55,7 @@ module RuboCop
55
55
  return unless routes_file?
56
56
 
57
57
  if arg_form_with_options(node) { |options| options.none?(&method(:valid_status_option?)) } || arg_form_without_options?(node)
58
- add_offense(node, message: MSG)
58
+ add_offense(node)
59
59
  end
60
60
  end
61
61
 
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Betterment
6
+ # Checks the status passed to have_http_status
7
+ #
8
+ # If a number, enforces that it doesn't start with 5. If a symbol or a string, enforces that it's not one of:
9
+ #
10
+ # * internal_server_error
11
+ # * not_implemented
12
+ # * bad_gateway
13
+ # * service_unavailable
14
+ # * gateway_timeout
15
+ # * http_version_not_supported
16
+ # * insufficient_storage
17
+ # * not_extended
18
+ #
19
+ # @example
20
+ #
21
+ # # bad
22
+ # expect(response).to have_http_status :internal_server_error
23
+ #
24
+ # # bad
25
+ # expect(response).to have_http_status 500
26
+ #
27
+ # # good
28
+ # expect(response).to have_http_status :forbidden
29
+ #
30
+ # # good
31
+ # expect(response).to have_http_status 422
32
+ class ServerErrorAssertion < Cop
33
+ MSG = 'Do not assert on 5XX statuses. Use a semantic status (e.g., 403, 422, etc.) or treat them as bugs (omit tests).'
34
+ BAD_STATUSES = %i(
35
+ internal_server_error
36
+ not_implemented
37
+ bad_gateway
38
+ service_unavailable
39
+ gateway_timeout
40
+ http_version_not_supported
41
+ insufficient_storage
42
+ not_extended
43
+ ).freeze
44
+
45
+ def_node_matcher :offensive_node?, <<-PATTERN
46
+ (send nil? :have_http_status
47
+ {
48
+ (int {#{(500..599).map(&:to_s).join(' ')}})
49
+ (str {#{BAD_STATUSES.map(&:to_s).map(&:inspect).join(' ')}})
50
+ (sym {#{BAD_STATUSES.map(&:inspect).join(' ')}})
51
+ }
52
+ )
53
+ PATTERN
54
+
55
+ def on_send(node)
56
+ return unless offensive_node?(node)
57
+
58
+ add_offense(node)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -21,7 +21,7 @@ module RuboCop
21
21
  PATTERN
22
22
 
23
23
  def on_send(node)
24
- add_offense(node, message: MSG) if requires_spec_helper?(node) && !spec_directory?
24
+ add_offense(node) if requires_spec_helper?(node) && !spec_directory?
25
25
  end
26
26
 
27
27
  private
@@ -43,7 +43,7 @@ module RuboCop
43
43
  static_method_name(node.method_name)
44
44
  ) && !@unauthenticated_models.include?(Utils::Parser.get_root_token(node))
45
45
 
46
- add_offense(node, message: MSG) if find_param_arg(arg_nodes)
46
+ add_offense(node) if find_param_arg(arg_nodes)
47
47
  end
48
48
 
49
49
  private
@@ -52,7 +52,7 @@ module RuboCop
52
52
  return unless arg_nodes
53
53
 
54
54
  arg_nodes.find do |arg|
55
- if arg.type == :hash
55
+ if arg.hash_type?
56
56
  arg.children.each do |pair|
57
57
  _key, value = *pair.children
58
58
  return arg if Utils::Parser.get_root_token(value) == :params
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-betterment
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.17.0
4
+ version: 1.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Development
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-13 00:00:00.000000000 Z
11
+ date: 2020-12-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -97,16 +97,17 @@ files:
97
97
  - lib/rubocop/cop/betterment/dynamic_params.rb
98
98
  - lib/rubocop/cop/betterment/implicit_redirect_type.rb
99
99
  - lib/rubocop/cop/betterment/memoization_with_arguments.rb
100
+ - lib/rubocop/cop/betterment/server_error_assertion.rb
100
101
  - lib/rubocop/cop/betterment/site_prism_loaded.rb
101
102
  - lib/rubocop/cop/betterment/spec_helper_required_outside_spec_dir.rb
102
103
  - lib/rubocop/cop/betterment/timeout.rb
103
104
  - lib/rubocop/cop/betterment/unscoped_find.rb
104
105
  - lib/rubocop/cop/betterment/utils/parser.rb
105
- homepage:
106
+ homepage:
106
107
  licenses:
107
108
  - MIT
108
109
  metadata: {}
109
- post_install_message:
110
+ post_install_message:
110
111
  rdoc_options: []
111
112
  require_paths:
112
113
  - lib
@@ -122,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
123
  version: '0'
123
124
  requirements: []
124
125
  rubygems_version: 3.1.4
125
- signing_key:
126
+ signing_key:
126
127
  specification_version: 4
127
128
  summary: Betterment rubocop configuration
128
129
  test_files: []