1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
|
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
# Check that the first argument to the top-level describe is a constant.
#
# It can be configured to ignore strings when certain metadata is passed.
#
# Ignores Rails and Aruba `type` metadata by default.
#
# @example `IgnoredMetadata` configuration
# # .rubocop.yml
# # RSpec/DescribeClass:
# # IgnoredMetadata:
# # type:
# # - request
# # - controller
#
# @example
# # bad
# describe 'Do something' do
# end
#
# # good
# describe TestedClass do
# subject { described_class }
# end
#
# describe 'TestedClass::VERSION' do
# subject { Object.const_get(self.class.description) }
# end
#
# describe "A feature example", type: :feature do
# end
#
class DescribeClass < Base
include TopLevelGroup
MSG = 'The first argument to describe should be ' \
'the class or module being tested.'
# @!method example_group_with_ignored_metadata?(node)
def_node_matcher :example_group_with_ignored_metadata?, <<~PATTERN
(send #rspec? :describe ... (hash <#ignored_metadata? ...>))
PATTERN
# @!method not_a_const_described(node)
def_node_matcher :not_a_const_described, <<~PATTERN
(send #rspec? :describe $[!const !#string_constant?] ...)
PATTERN
# @!method sym_pair(node)
def_node_matcher :sym_pair, <<~PATTERN
(pair $sym $sym)
PATTERN
def on_top_level_group(node)
return if example_group_with_ignored_metadata?(node.send_node)
not_a_const_described(node.send_node) do |described|
add_offense(described)
end
end
private
def ignored_metadata?(node)
sym_pair(node) do |key, value|
ignored_metadata[key.value.to_s].to_a.include?(value.value.to_s)
end
end
def string_constant?(described)
described.str_type? &&
described.value.match?(/^(?:(?:::)?[A-Z]\w*)+$/)
end
def ignored_metadata
cop_config['IgnoredMetadata'] || {}
end
end
end
end
end
|