summaryrefslogtreecommitdiff
path: root/rubocop
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-01-15 18:08:34 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-01-15 18:08:34 +0000
commit571d993b49313dd806bd3f6af16d36c26d9d28ca (patch)
tree06bd12c4b56b97881aef8a00d4d46698de1eb63f /rubocop
parent9044365a91112d426fbbfba07eca595652bbe2df (diff)
downloadgitlab-ce-571d993b49313dd806bd3f6af16d36c26d9d28ca.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'rubocop')
-rw-r--r--rubocop/cop/rspec/have_gitlab_http_status.rb119
-rw-r--r--rubocop/rubocop.rb1
2 files changed, 120 insertions, 0 deletions
diff --git a/rubocop/cop/rspec/have_gitlab_http_status.rb b/rubocop/cop/rspec/have_gitlab_http_status.rb
new file mode 100644
index 00000000000..6b179720060
--- /dev/null
+++ b/rubocop/cop/rspec/have_gitlab_http_status.rb
@@ -0,0 +1,119 @@
+# frozen_string_literal: true
+
+require 'rack/utils'
+
+module RuboCop
+ module Cop
+ module RSpec
+ # This cops checks for `have_http_status` usages in specs.
+ # It also discourages the usage of numeric HTTP status codes in
+ # `have_gitlab_http_status`.
+ #
+ # @example
+ #
+ # # bad
+ # expect(response).to have_http_status(200)
+ # expect(response).to have_http_status(:ok)
+ # expect(response).to have_gitlab_http_status(200)
+ #
+ # # good
+ # expect(response).to have_gitlab_http_status(:ok)
+ #
+ class HaveGitlabHttpStatus < RuboCop::Cop::Cop
+ CODE_TO_SYMBOL = Rack::Utils::SYMBOL_TO_STATUS_CODE.invert
+
+ MSG_MATCHER_NAME =
+ 'Use `have_gitlab_http_status` instead of `have_http_status`.'
+
+ MSG_STATUS =
+ 'Prefer named HTTP status `%{name}` over ' \
+ 'its numeric representation `%{code}`.'
+
+ MSG_UNKNOWN = 'HTTP status `%{code}` is unknown. ' \
+ 'Please provide a valid one or disable this cop.'
+
+ MSG_DOCS_LINK = 'https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#have_gitlab_http_status'
+
+ REPLACEMENT = 'have_gitlab_http_status(%{arg})'
+
+ def_node_matcher :have_http_status?, <<~PATTERN
+ (
+ send nil?
+ {
+ :have_http_status
+ :have_gitlab_http_status
+ }
+ _
+ )
+ PATTERN
+
+ def on_send(node)
+ return unless have_http_status?(node)
+
+ offenses = [
+ offense_for_name(node),
+ offense_for_status(node)
+ ].compact
+
+ return if offenses.empty?
+
+ add_offense(node, message: message_for(offenses))
+ end
+
+ def autocorrect(node)
+ lambda do |corrector|
+ corrector.replace(node.source_range, replacement(node))
+ end
+ end
+
+ private
+
+ def offense_for_name(node)
+ return if method_name(node) == :have_gitlab_http_status
+
+ MSG_MATCHER_NAME
+ end
+
+ def offense_for_status(node)
+ code = extract_numeric_code(node)
+ return unless code
+
+ symbol = code_to_symbol(code)
+ return format(MSG_UNKNOWN, code: code) unless symbol
+
+ format(MSG_STATUS, name: symbol, code: code)
+ end
+
+ def message_for(offenses)
+ (offenses + [MSG_DOCS_LINK]).join(' ')
+ end
+
+ def replacement(node)
+ code = extract_numeric_code(node)
+ arg = code_to_symbol(code) || argument(node).source
+
+ format(REPLACEMENT, arg: arg)
+ end
+
+ def code_to_symbol(code)
+ CODE_TO_SYMBOL[code]&.inspect
+ end
+
+ def extract_numeric_code(node)
+ arg_node = argument(node)
+ return unless arg_node&.type == :int
+
+ arg_node.children[0]
+ end
+
+ def method_name(node)
+ node.children[1]
+ end
+
+ def argument(node)
+ node.children[2]
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb
index 5f95703df01..1479dc3384a 100644
--- a/rubocop/rubocop.rb
+++ b/rubocop/rubocop.rb
@@ -40,6 +40,7 @@ require_relative 'cop/rspec/be_success_matcher'
require_relative 'cop/rspec/env_assignment'
require_relative 'cop/rspec/factories_in_migration_specs'
require_relative 'cop/rspec/top_level_describe_path'
+require_relative 'cop/rspec/have_gitlab_http_status'
require_relative 'cop/qa/element_with_pattern'
require_relative 'cop/qa/ambiguous_page_object_name'
require_relative 'cop/sidekiq_options_queue'