diff --git a/Library/.rubocop_cask.yml b/Library/.rubocop_cask.yml index fe874e591c..cc6ccf9a5f 100644 --- a/Library/.rubocop_cask.yml +++ b/Library/.rubocop_cask.yml @@ -1,5 +1,9 @@ inherit_from: ./Homebrew/.rubocop.yml +Cask/Desc: + Description: 'Ensure that the desc stanza conforms to various content and style checks.' + Enabled: true + Cask/HomepageMatchesUrl: Description: 'Ensure that the homepage and url match, otherwise add a comment. More info at https://github.com/Homebrew/homebrew-cask/blob/HEAD/doc/cask_language_reference/stanzas/url.md#when-url-and-homepage-hostnames-differ-add-a-comment' Enabled: true @@ -13,11 +17,11 @@ Cask/NoDslVersion: Enabled: true Cask/StanzaGrouping: - Description: 'Ensure that cask stanzas are grouped correctly. More info at https://github.com/Homebrew/homebrew-cask/blob/HEAD/CONTRIBUTING.md#stanza-order' + Description: 'Ensure that cask stanzas are grouped correctly. More info at https://github.com/Homebrew/homebrew-cask/blob/HEAD/doc/cask_language_reference/readme.md#stanza-order' Enabled: true Cask/StanzaOrder: - Description: 'Ensure that cask stanzas are sorted correctly. More info at https://github.com/Homebrew/homebrew-cask/blob/HEAD/CONTRIBUTING.md#stanza-order' + Description: 'Ensure that cask stanzas are sorted correctly. More info at https://github.com/Homebrew/homebrew-cask/blob/HEAD/doc/cask_language_reference/readme.md#stanza-order' Enabled: true # don't want these for casks but re-enabled for Library/Homebrew diff --git a/Library/Homebrew/cask/cask.rb b/Library/Homebrew/cask/cask.rb index 710753fa4a..bdda5b6e77 100644 --- a/Library/Homebrew/cask/cask.rb +++ b/Library/Homebrew/cask/cask.rb @@ -155,6 +155,7 @@ module Cask { "token" => token, "name" => name, + "desc" => desc, "homepage" => homepage, "url" => url, "appcast" => appcast, diff --git a/Library/Homebrew/cask/cmd/create.rb b/Library/Homebrew/cask/cmd/create.rb index 43145bfc35..0c9e44ed42 100644 --- a/Library/Homebrew/cask/cmd/create.rb +++ b/Library/Homebrew/cask/cmd/create.rb @@ -30,6 +30,7 @@ module Cask url "https://" name "" + desc "" homepage "" app "" diff --git a/Library/Homebrew/cask/dsl.rb b/Library/Homebrew/cask/dsl.rb index 87b83e8d3f..3f5ec39412 100644 --- a/Library/Homebrew/cask/dsl.rb +++ b/Library/Homebrew/cask/dsl.rb @@ -64,6 +64,7 @@ module Cask :caveats, :conflicts_with, :container, + :desc, :depends_on, :homepage, :language, @@ -93,6 +94,10 @@ module Cask @name.concat(args.flatten) end + def desc(description = nil) + set_unique_stanza(:desc, description.nil?) { description } + end + def set_unique_stanza(stanza, should_return) return instance_variable_get("@#{stanza}") if should_return diff --git a/Library/Homebrew/rubocops/cask/ast/cask_header.rb b/Library/Homebrew/rubocops/cask/ast/cask_header.rb index 8668c2daad..7646552eec 100644 --- a/Library/Homebrew/rubocops/cask/ast/cask_header.rb +++ b/Library/Homebrew/rubocops/cask/ast/cask_header.rb @@ -29,7 +29,13 @@ module RuboCop end def cask_token - @cask_token ||= pair_node.val_node.children.first + @cask_token ||= begin + if dsl_version? + pair_node.val_node.children.first + else + method_node.first_argument.str_content + end + end end def hash_node diff --git a/Library/Homebrew/rubocops/cask/constants/stanza.rb b/Library/Homebrew/rubocops/cask/constants/stanza.rb index 00335bb1f2..e0bda8dc7b 100644 --- a/Library/Homebrew/rubocops/cask/constants/stanza.rb +++ b/Library/Homebrew/rubocops/cask/constants/stanza.rb @@ -6,7 +6,7 @@ module RuboCop module Constants STANZA_GROUPS = [ [:version, :sha256], - [:url, :appcast, :name, :homepage], + [:url, :appcast, :desc, :name, :homepage], [ :auto_updates, :conflicts_with, diff --git a/Library/Homebrew/rubocops/cask/desc.rb b/Library/Homebrew/rubocops/cask/desc.rb new file mode 100644 index 0000000000..90ceefab9f --- /dev/null +++ b/Library/Homebrew/rubocops/cask/desc.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require "forwardable" +require "uri" +require "rubocops/cask/mixin/on_desc_stanza" +require "rubocops/shared/desc_helper" + +module RuboCop + module Cop + module Cask + # This cop audits `desc` in Casks. + # See the `DescHelper` module for details of the checks. + class Desc < Cop + include OnDescStanza + include DescHelper + + def on_desc_stanza(stanza) + name = cask_block.header.cask_token + desc_call = stanza.stanza_node + audit_desc(:cask, name, desc_call) + end + + def autocorrect(node) + name = cask_block.header.cask_token + autocorrect_desc(node, name) + end + end + end + end +end diff --git a/Library/Homebrew/rubocops/cask/mixin/on_desc_stanza.rb b/Library/Homebrew/rubocops/cask/mixin/on_desc_stanza.rb new file mode 100644 index 0000000000..067b6c30e4 --- /dev/null +++ b/Library/Homebrew/rubocops/cask/mixin/on_desc_stanza.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Cask + # Common functionality for checking desc stanzas. + module OnDescStanza + extend Forwardable + include CaskHelp + + def on_cask(cask_block) + @cask_block = cask_block + + toplevel_stanzas.select(&:desc?).each do |stanza| + on_desc_stanza(stanza) + end + end + + private + + attr_reader :cask_block + + def_delegators :cask_block, + :toplevel_stanzas + end + end + end +end diff --git a/Library/Homebrew/rubocops/cask/stanza_grouping.rb b/Library/Homebrew/rubocops/cask/stanza_grouping.rb index c29d8d71c8..b49101e63c 100644 --- a/Library/Homebrew/rubocops/cask/stanza_grouping.rb +++ b/Library/Homebrew/rubocops/cask/stanza_grouping.rb @@ -6,7 +6,7 @@ module RuboCop module Cop module Cask # This cop checks that a cask's stanzas are grouped correctly. - # See https://github.com/Homebrew/homebrew-cask/blob/HEAD/CONTRIBUTING.md#stanza-order + # See https://github.com/Homebrew/homebrew-cask/blob/HEAD/doc/cask_language_reference/readme.md#stanza-order # for more info. class StanzaGrouping < Cop extend Forwardable diff --git a/Library/Homebrew/rubocops/cask/stanza_order.rb b/Library/Homebrew/rubocops/cask/stanza_order.rb index 71dad3cb8e..41b818df6c 100644 --- a/Library/Homebrew/rubocops/cask/stanza_order.rb +++ b/Library/Homebrew/rubocops/cask/stanza_order.rb @@ -6,7 +6,7 @@ module RuboCop module Cop module Cask # This cop checks that a cask's stanzas are ordered correctly. - # See https://github.com/Homebrew/homebrew-cask/blob/HEAD/CONTRIBUTING.md#stanza-order + # See https://github.com/Homebrew/homebrew-cask/blob/HEAD/doc/cask_language_reference/readme.md#stanza-order # for more info. class StanzaOrder < Cop extend Forwardable diff --git a/Library/Homebrew/rubocops/extend/formula.rb b/Library/Homebrew/rubocops/extend/formula.rb index b7e5bfccb8..8f165acc68 100644 --- a/Library/Homebrew/rubocops/extend/formula.rb +++ b/Library/Homebrew/rubocops/extend/formula.rb @@ -10,11 +10,13 @@ ensure end require "extend/string" +require "rubocops/shared/helper_functions" module RuboCop module Cop class FormulaCop < Cop include RangeHelp + include HelperFunctions attr_accessor :file_path @@ -32,28 +34,6 @@ module RuboCop audit_formula(node, class_node, parent_class_node, @body) end - # Checks for regex match of pattern in the node and - # sets the appropriate instance variables to report the match - def regex_match_group(node, pattern) - string_repr = string_content(node).encode("UTF-8", invalid: :replace) - match_object = string_repr.match(pattern) - return unless match_object - - node_begin_pos = start_column(node) - line_begin_pos = line_start_column(node) - @column = if node_begin_pos == line_begin_pos - node_begin_pos + match_object.begin(0) - line_begin_pos - else - node_begin_pos + match_object.begin(0) - line_begin_pos + 1 - end - @length = match_object.to_s.length - @line_no = line_number(node) - @source_buf = source_buffer(node) - @offense_source_range = source_range(@source_buf, @line_no, @column, @length) - @offensive_node = node - match_object - end - # Yields to block when there is a match. # @param urls [Array] url/mirror method call nodes # @param regex [Regexp] pattern to match urls @@ -442,26 +422,11 @@ module RuboCop end end - # Returns the begin position of the node's line in source code - def line_start_column(node) - node.source_range.source_buffer.line_range(node.loc.line).begin_pos - end - - # Returns the begin position of the node in source code - def start_column(node) - node.source_range.begin_pos - end - # Returns the ending position of the node in source code def end_column(node) node.source_range.end_pos end - # Returns the line number of the node - def line_number(node) - node.loc.line - end - # Returns the class node's name, nil if not a class node def class_name(node) @offensive_node = node @@ -484,35 +449,6 @@ module RuboCop block.loc.end.line - block.loc.begin.line end - # Source buffer is required as an argument to report style violations - def source_buffer(node) - node.source_range.source_buffer - end - - # Returns the string representation if node is of type str(plain) or dstr(interpolated) or const - def string_content(node) - case node.type - when :str - node.str_content - when :dstr - content = "" - node.each_child_node(:str, :begin) do |child| - content += if child.begin_type? - child.source - else - child.str_content - end - end - content - when :const - node.const_name - when :sym - node.children.first.to_s - else - "" - end - end - # Returns true if the formula is versioned def versioned_formula? @formula_name.include?("@") @@ -532,10 +468,6 @@ module RuboCop match_obj[1] end - def problem(msg) - add_offense(@offensive_node, location: @offense_source_range, message: msg) - end - private def formula_class?(node) diff --git a/Library/Homebrew/rubocops/formula_desc.rb b/Library/Homebrew/rubocops/formula_desc.rb index 3449ee43a8..57e5066e13 100644 --- a/Library/Homebrew/rubocops/formula_desc.rb +++ b/Library/Homebrew/rubocops/formula_desc.rb @@ -1,105 +1,24 @@ # frozen_string_literal: true require "rubocops/extend/formula" +require "rubocops/shared/desc_helper" require "extend/string" module RuboCop module Cop module FormulaAudit # This cop audits `desc` in Formulae. - # - # - Checks for existence of `desc` - # - Checks if size of `desc` > 80 - # - Checks for leading/trailing whitespace in `desc` - # - Checks if `desc` begins with an article - # - Checks for correct usage of `command-line` in `desc` - # - Checks description starts with a capital letter - # - Checks if `desc` contains the formula name - # - Checks if `desc` ends with a full stop (apart from in the case of "etc.") + # See the `DescHelper` module for details of the checks. class Desc < FormulaCop - VALID_LOWERCASE_WORDS = %w[ - macOS - ].freeze + include DescHelper def audit_formula(_node, _class_node, _parent_class_node, body_node) desc_call = find_node_method_by_name(body_node, :desc) - - # Check if a formula's desc is present - if desc_call.nil? - problem "Formula should have a desc (Description)." - return - end - - desc = parameters(desc_call).first - - # Check the formula's desc length. Should be >0 and <80 characters. - pure_desc_length = string_content(desc).length - if pure_desc_length.zero? - problem "The desc (description) should not be an empty string." - return - end - - # Check for leading whitespace. - problem "Description shouldn't have a leading space" if regex_match_group(desc, /^\s+/) - - # Check for trailing whitespace. - problem "Description shouldn't have a trailing space" if regex_match_group(desc, /\s+$/) - - # Check if command-line is wrongly used in formula's desc - if match = regex_match_group(desc, /(command ?line)/i) - c = match.to_s[0] - problem "Description should use \"#{c}ommand-line\" instead of \"#{match}\"" - end - - # Check if a/an are used in a formula's desc - if match = regex_match_group(desc, /^(an?)\s/i) - problem "Description shouldn't start with an indefinite article, i.e. \"#{match.to_s.strip}\"" - end - - # Check if invalid uppercase words are at the start of a - # formula's desc - if !VALID_LOWERCASE_WORDS.include?(string_content(desc).split.first) && - regex_match_group(desc, /^[a-z]/) - problem "Description should start with a capital letter" - end - - # Check if formula's desc starts with formula's name - if regex_match_group(desc, /^#{@formula_name} /i) - problem "Description shouldn't start with the formula name" - end - - # Check if a full stop is used at the end of a formula's desc (apart from in the case of "etc.") - if regex_match_group(desc, /\.$/) && !string_content(desc).end_with?("etc.") - problem "Description shouldn't end with a full stop" - end - - desc_length = "#{@formula_name}: #{string_content(desc)}".length - max_desc_length = 80 - return if desc_length <= max_desc_length - - problem "Description is too long. \"name: desc\" should be less than #{max_desc_length} characters. " \ - "Length is calculated as #{@formula_name} + desc. (currently #{desc_length})" + audit_desc(:formula, @formula_name, desc_call) end def autocorrect(node) - lambda do |corrector| - correction = node.source - first_word = string_content(node).split.first - unless VALID_LOWERCASE_WORDS.include?(first_word) - first_char = first_word.to_s[0] - correction.sub!(/^(['"]?)([a-z])/, "\\1#{first_char.upcase}") if first_char - end - correction.sub!(/^(['"]?)an?\s/i, "\\1") - correction.gsub!(/(ommand ?line)/i, "ommand-line") - correction.gsub!(/(^|[^a-z])#{@formula_name}([^a-z]|$)/i, "\\1\\2") - correction.gsub!(/^(['"]?)\s+/, "\\1") - correction.gsub!(/\s+(['"]?)$/, "\\1") - correction.gsub!(/\.(['"]?)$/, "\\1") - correction.gsub!(/^\s+/, "") - correction.gsub!(/\s+$/, "") - corrector.insert_before(node.source_range, correction) - corrector.remove(node.source_range) - end + autocorrect_desc(node, @formula_name) end end end diff --git a/Library/Homebrew/rubocops/rubocop-cask.rb b/Library/Homebrew/rubocops/rubocop-cask.rb index 3af610ebef..646e483994 100644 --- a/Library/Homebrew/rubocops/rubocop-cask.rb +++ b/Library/Homebrew/rubocops/rubocop-cask.rb @@ -11,6 +11,7 @@ require "rubocops/cask/extend/string" require "rubocops/cask/extend/node" require "rubocops/cask/mixin/cask_help" require "rubocops/cask/mixin/on_homepage_stanza" +require "rubocops/cask/desc" require "rubocops/cask/homepage_matches_url" require "rubocops/cask/homepage_url_trailing_slash" require "rubocops/cask/no_dsl_version" diff --git a/Library/Homebrew/rubocops/shared/desc_helper.rb b/Library/Homebrew/rubocops/shared/desc_helper.rb new file mode 100644 index 0000000000..1ff7a80ad7 --- /dev/null +++ b/Library/Homebrew/rubocops/shared/desc_helper.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +require "rubocops/shared/helper_functions" + +module RuboCop + module Cop + # This module performs common checks the `desc` field in both Formulae and Casks. + module DescHelper + include HelperFunctions + + VALID_LOWERCASE_WORDS = %w[ + macOS + ].freeze + + def audit_desc(type, name, desc_call) + # Check if a desc is present. + if desc_call.nil? + problem "#{type.to_s.capitalize} should have a desc (Description)." + return + end + + desc = desc_call.first_argument + + # Check if the desc is empty. + pure_desc_length = string_content(desc).length + if pure_desc_length.zero? + problem "The desc (description) should not be an empty string." + return + end + + # Check the desc for leading whitespace. + problem "Description shouldn't have leading spaces." if regex_match_group(desc, /^\s+/) + + # Check the desc for trailing whitespace. + problem "Description shouldn't have trailing spaces." if regex_match_group(desc, /\s+$/) + + # Check if "command-line" is spelled incorrectly in the desc. + if match = regex_match_group(desc, /(command ?line)/i) + c = match.to_s[0] + problem "Description should use \"#{c}ommand-line\" instead of \"#{match}\"." + end + + # Check if the desc starts with "A" or "An". + if match = regex_match_group(desc, /^(an?)(?=\s)/i) + problem "Description shouldn't start with an indefinite article, i.e. \"#{match}\"." + end + + # Check if invalid lowercase words are at the start of a desc. + if !VALID_LOWERCASE_WORDS.include?(string_content(desc).split.first) && + regex_match_group(desc, /^[a-z]/) + problem "Description should start with a capital letter." + end + + # Check if the desc starts with the formula's or cask's name. + problem "Description shouldn't start with the #{type} name." if regex_match_group(desc, /^#{name} /i) + + # Check if a full stop is used at the end of a desc (apart from in the case of "etc."). + if regex_match_group(desc, /\.$/) && !string_content(desc).end_with?("etc.") + problem "Description shouldn't end with a full stop." + end + + # Check if the desc length exceeds 80 characters. + desc_length = "#{name}: #{string_content(desc)}".length + max_desc_length = 80 + return if desc_length <= max_desc_length + + problem "Description is too long. \"name: desc\" should be less than #{max_desc_length} characters. " \ + "The current combined length is #{desc_length}." + end + + def autocorrect_desc(node, name) + lambda do |corrector| + /\A(?["'])(?.*)(?:\k)\Z/ =~ node.source + + next if correction.nil? + + correction.gsub!(/^\s+/, "") + correction.gsub!(/\s+$/, "") + + correction.sub!(/^an?\s+/i, "") + + first_word = correction.split.first + unless VALID_LOWERCASE_WORDS.include?(first_word) + first_char = first_word.to_s[0] + correction[0] = first_char.upcase if first_char + end + + correction.gsub!(/(ommand ?line)/i, "ommand-line") + correction.gsub!(/(^|[^a-z])#{name}([^a-z]|$)/i, "\\1\\2") + correction.gsub!(/^\s+/, "") + correction.gsub!(/\s+$/, "") + correction.gsub!(/\.$/, "") + + corrector.replace(node.source_range, "#{quote}#{correction}#{quote}") + end + end + end + end +end diff --git a/Library/Homebrew/rubocops/shared/helper_functions.rb b/Library/Homebrew/rubocops/shared/helper_functions.rb new file mode 100644 index 0000000000..a5e893c6ae --- /dev/null +++ b/Library/Homebrew/rubocops/shared/helper_functions.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module HelperFunctions + include RangeHelp + + # Checks for regex match of pattern in the node and + # sets the appropriate instance variables to report the match + def regex_match_group(node, pattern) + string_repr = string_content(node).encode("UTF-8", invalid: :replace) + match_object = string_repr.match(pattern) + return unless match_object + + node_begin_pos = start_column(node) + line_begin_pos = line_start_column(node) + @column = if node_begin_pos == line_begin_pos + node_begin_pos + match_object.begin(0) - line_begin_pos + else + node_begin_pos + match_object.begin(0) - line_begin_pos + 1 + end + @length = match_object.to_s.length + @line_no = line_number(node) + @source_buf = source_buffer(node) + @offense_source_range = source_range(@source_buf, @line_no, @column, @length) + @offensive_node = node + match_object + end + + # Returns the begin position of the node's line in source code + def line_start_column(node) + node.source_range.source_buffer.line_range(node.loc.line).begin_pos + end + + # Returns the begin position of the node in source code + def start_column(node) + node.source_range.begin_pos + end + + # Returns the line number of the node + def line_number(node) + node.loc.line + end + + # Source buffer is required as an argument to report style violations + def source_buffer(node) + node.source_range.source_buffer + end + + # Returns the string representation if node is of type str(plain) or dstr(interpolated) or const + def string_content(node) + case node.type + when :str + node.str_content + when :dstr + content = "" + node.each_child_node(:str, :begin) do |child| + content += if child.begin_type? + child.source + else + child.str_content + end + end + content + when :const + node.const_name + when :sym + node.children.first.to_s + else + "" + end + end + + def problem(msg) + add_offense(@offensive_node, location: @offense_source_range, message: msg) + end + end + end +end diff --git a/Library/Homebrew/test/cask/cmd/create_spec.rb b/Library/Homebrew/test/cask/cmd/create_spec.rb index d656e90d44..ab9a0c95b2 100644 --- a/Library/Homebrew/test/cask/cmd/create_spec.rb +++ b/Library/Homebrew/test/cask/cmd/create_spec.rb @@ -35,6 +35,7 @@ describe Cask::Cmd::Create, :cask do url "https://" name "" + desc "" homepage "" app "" diff --git a/Library/Homebrew/test/cask/cmd/list_spec.rb b/Library/Homebrew/test/cask/cmd/list_spec.rb index 82a486b0d5..b3af63e31f 100644 --- a/Library/Homebrew/test/cask/cmd/list_spec.rb +++ b/Library/Homebrew/test/cask/cmd/list_spec.rb @@ -90,7 +90,7 @@ describe Cask::Cmd::List, :cask do let(:casks) { ["local-caffeine", "local-transmission"] } let(:expected_output) { <<~EOS - [{"token":"local-caffeine","name":[],"homepage":"https://brew.sh/","url":"file:///usr/local/Homebrew/Library/Homebrew/test/support/fixtures/cask/caffeine.zip","appcast":null,"version":"1.2.3","sha256":"67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94","artifacts":[["Caffeine.app"]],"caveats":null,"depends_on":{},"conflicts_with":null,"container":null,"auto_updates":null},{"token":"local-transmission","name":["Transmission"],"homepage":"https://brew.sh/","url":"file:///usr/local/Homebrew/Library/Homebrew/test/support/fixtures/cask/transmission-2.61.dmg","appcast":null,"version":"2.61","sha256":"e44ffa103fbf83f55c8d0b1bea309a43b2880798dae8620b1ee8da5e1095ec68","artifacts":[["Transmission.app"]],"caveats":null,"depends_on":{},"conflicts_with":null,"container":null,"auto_updates":null}] + [{"token":"local-caffeine","name":[],"desc":null,"homepage":"https://brew.sh/","url":"file:///usr/local/Homebrew/Library/Homebrew/test/support/fixtures/cask/caffeine.zip","appcast":null,"version":"1.2.3","sha256":"67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94","artifacts":[["Caffeine.app"]],"caveats":null,"depends_on":{},"conflicts_with":null,"container":null,"auto_updates":null},{"token":"local-transmission","name":["Transmission"],"desc":null,"homepage":"https://brew.sh/","url":"file:///usr/local/Homebrew/Library/Homebrew/test/support/fixtures/cask/transmission-2.61.dmg","appcast":null,"version":"2.61","sha256":"e44ffa103fbf83f55c8d0b1bea309a43b2880798dae8620b1ee8da5e1095ec68","artifacts":[["Transmission.app"]],"caveats":null,"depends_on":{},"conflicts_with":null,"container":null,"auto_updates":null}] EOS } diff --git a/Library/Homebrew/test/cask/dsl_spec.rb b/Library/Homebrew/test/cask/dsl_spec.rb index 949a1c804f..cebf4c1af7 100644 --- a/Library/Homebrew/test/cask/dsl_spec.rb +++ b/Library/Homebrew/test/cask/dsl_spec.rb @@ -107,6 +107,16 @@ describe Cask::DSL, :cask do end end + describe "desc stanza" do + it "lets you set the description via a desc stanza" do + cask = Cask::Cask.new("desc-cask") do + desc "The package's description" + end + + expect(cask.desc).to eq("The package's description") + end + end + describe "sha256 stanza" do it "lets you set checksum via sha256" do cask = Cask::Cask.new("checksum-cask") do diff --git a/Library/Homebrew/test/rubocops/cask/desc_spec.rb b/Library/Homebrew/test/rubocops/cask/desc_spec.rb new file mode 100644 index 0000000000..28a2b6d3f7 --- /dev/null +++ b/Library/Homebrew/test/rubocops/cask/desc_spec.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require "rubocops/rubocop-cask" +require "test/rubocops/cask/shared_examples/cask_cop" + +describe RuboCop::Cop::Cask::Desc do + include CaskCop + + subject(:cop) { described_class.new } + + context "with incorrect `desc` stanza" do + let(:source) { + <<~RUBY + cask "foo" do + desc "A bar program" + end + RUBY + } + let(:correct_source) { + <<~RUBY + cask "foo" do + desc "Bar program" + end + RUBY + } + let(:expected_offenses) do + [{ + message: "Description shouldn't start with an indefinite article, i.e. \"A\".", + severity: :convention, + line: 2, + column: 8, + source: "A", + }] + end + + include_examples "reports offenses" + + include_examples "autocorrects source" + end + + context "with correct `desc` stanza" do + let(:source) { + <<~RUBY + cask "foo" do + desc "Bar program" + end + RUBY + } + + include_examples "does not report any offenses" + end +end diff --git a/Library/Homebrew/test/rubocops/cask/no_dsl_version_spec.rb b/Library/Homebrew/test/rubocops/cask/no_dsl_version_spec.rb index 9f52bd7bf2..2f6d5747c7 100644 --- a/Library/Homebrew/test/rubocops/cask/no_dsl_version_spec.rb +++ b/Library/Homebrew/test/rubocops/cask/no_dsl_version_spec.rb @@ -8,31 +8,27 @@ describe RuboCop::Cop::Cask::NoDslVersion do subject(:cop) { described_class.new } - context "with header method `cask`" do - let(:header_method) { "cask" } + context "with no dsl version" do + let(:source) { "cask 'foo' do; end" } - context "with no dsl version" do - let(:source) { "cask 'foo' do; end" } + include_examples "does not report any offenses" + end - include_examples "does not report any offenses" + context "with dsl version" do + let(:source) { "cask :v1 => 'foo' do; end" } + let(:correct_source) { "cask 'foo' do; end" } + let(:expected_offenses) do + [{ + message: "Use `cask 'foo'` instead of `cask :v1 => 'foo'`", + severity: :convention, + line: 1, + column: 0, + source: "cask :v1 => 'foo'", + }] end - context "with dsl version" do - let(:source) { "cask :v1 => 'foo' do; end" } - let(:correct_source) { "cask 'foo' do; end" } - let(:expected_offenses) do - [{ - message: "Use `cask 'foo'` instead of `cask :v1 => 'foo'`", - severity: :convention, - line: 1, - column: 0, - source: "cask :v1 => 'foo'", - }] - end + include_examples "reports offenses" - include_examples "reports offenses" - - include_examples "autocorrects source" - end + include_examples "autocorrects source" end end diff --git a/Library/Homebrew/test/rubocops/formula_desc_spec.rb b/Library/Homebrew/test/rubocops/formula_desc_spec.rb index 0b9f7dcb28..8f7ea8f806 100644 --- a/Library/Homebrew/test/rubocops/formula_desc_spec.rb +++ b/Library/Homebrew/test/rubocops/formula_desc_spec.rb @@ -15,7 +15,7 @@ describe RuboCop::Cop::FormulaAudit::Desc do RUBY end - it "reports an offense when desc is an empty string" do + it "When desc is an empty string" do expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") class Foo < Formula url 'https://brew.sh/foo-1.0.tgz' @@ -30,81 +30,30 @@ describe RuboCop::Cop::FormulaAudit::Desc do class Foo < Formula url 'https://brew.sh/foo-1.0.tgz' desc 'Bar#{"bar" * 29}' - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Description is too long. "name: desc" should be less than 80 characters. Length is calculated as foo + desc. (currently 95) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Description is too long. "name: desc" should be less than 80 characters. The current combined length is 95. end RUBY end - it "When desc is multiline string" do + it "When desc is a multiline string" do expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") class Foo < Formula url 'https://brew.sh/foo-1.0.tgz' desc 'Bar#{"bar" * 9}'\ '#{"foo" * 21}' - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Description is too long. "name: desc" should be less than 80 characters. Length is calculated as foo + desc. (currently 98) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Description is too long. "name: desc" should be less than 80 characters. The current combined length is 98. end RUBY end end context "When auditing formula desc" do - it "When wrong \"command-line\" usage in desc" do - expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") - class Foo < Formula - url 'https://brew.sh/foo-1.0.tgz' - desc 'command line' - ^ Description should start with a capital letter - ^^^^^^^^^^^^ Description should use \"command-line\" instead of \"command line\" - end - RUBY - end - - it "When an article is used in desc" do - expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") - class Foo < Formula - url 'https://brew.sh/foo-1.0.tgz' - desc 'An aardvark' - ^^^ Description shouldn\'t start with an indefinite article, i.e. \"An\" - end - RUBY - end - - it "When an lowercase letter starts a desc" do - expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") - class Foo < Formula - url 'https://brew.sh/foo-1.0.tgz' - desc 'bar' - ^ Description should start with a capital letter - end - RUBY - end - - it "When formula name is in desc" do - expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") - class Foo < Formula - url 'https://brew.sh/foo-1.0.tgz' - desc 'Foo is a foobar' - ^^^^ Description shouldn\'t start with the formula name - end - RUBY - end - - it "When the description ends with a full stop" do - expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") - class Foo < Formula - url 'https://brew.sh/foo-1.0.tgz' - desc 'Description with a full stop at the end.' - ^ Description shouldn\'t end with a full stop - end - RUBY - end - it "When the description starts with a leading space" do expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") class Foo < Formula url 'https://brew.sh/foo-1.0.tgz' desc ' Description with a leading space' - ^ Description shouldn\'t have a leading space + ^ Description shouldn\'t have leading spaces. end RUBY end @@ -114,7 +63,58 @@ describe RuboCop::Cop::FormulaAudit::Desc do class Foo < Formula url 'https://brew.sh/foo-1.0.tgz' desc 'Description with a trailing space ' - ^ Description shouldn\'t have a trailing space + ^ Description shouldn\'t have trailing spaces. + end + RUBY + end + + it "When \"command-line\" is incorrectly spelled in the desc" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + desc 'command line' + ^ Description should start with a capital letter. + ^^^^^^^^^^^^ Description should use \"command-line\" instead of \"command line\". + end + RUBY + end + + it "When an article is used in the desc" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + desc 'An aardvark' + ^^ Description shouldn\'t start with an indefinite article, i.e. \"An\". + end + RUBY + end + + it "When the desc starts with a lowercase letter" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + desc 'bar' + ^ Description should start with a capital letter. + end + RUBY + end + + it "When the desc starts with the formula name" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + desc 'Foo is a foobar' + ^^^^ Description shouldn\'t start with the formula name. + end + RUBY + end + + it "When the description ends with a full stop" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + desc 'Description with a full stop at the end.' + ^ Description shouldn\'t end with a full stop. end RUBY end @@ -130,7 +130,7 @@ describe RuboCop::Cop::FormulaAudit::Desc do correct_source = <<~RUBY class Foo < Formula url 'https://brew.sh/foo-1.0.tgz' - desc 'an bar: command-line' + desc 'Bar: command-line' end RUBY