diff --git a/Library/Homebrew/rubocops/cask/no_dsl_version.rb b/Library/Homebrew/rubocops/cask/no_dsl_version.rb index 4e8e7410fb..ecff2a19ee 100644 --- a/Library/Homebrew/rubocops/cask/no_dsl_version.rb +++ b/Library/Homebrew/rubocops/cask/no_dsl_version.rb @@ -23,7 +23,7 @@ module RuboCop extend AutoCorrector include CaskHelp - MESSAGE = "Use `%s` instead of `%s`" + MESSAGE = "Use `%s` instead of `%s`." def on_cask(cask_block) @cask_header = cask_block.header diff --git a/Library/Homebrew/rubocops/cask/no_overrides.rb b/Library/Homebrew/rubocops/cask/no_overrides.rb index aa2721d1f3..03ba9a7c4a 100644 --- a/Library/Homebrew/rubocops/cask/no_overrides.rb +++ b/Library/Homebrew/rubocops/cask/no_overrides.rb @@ -13,10 +13,9 @@ module RuboCop :appcast, :arch, :auto_updates, :conflicts_with, :container, :desc, :homepage, :sha256, :url, :version ].freeze - MESSAGE = <<~EOS - Do not use a top-level `%s` stanza as the default. Add it to an `on_{system}` block instead. - Use `:or_older` or `:or_newer` to specify a range of macOS versions. - EOS + MESSAGE = "Do not use a top-level `%s` stanza as the default. " \ + "Add it to an `on_{system}` block instead. " \ + "Use `:or_older` or `:or_newer` to specify a range of macOS versions." def on_cask(cask_block) cask_stanzas = cask_block.toplevel_stanzas diff --git a/Library/Homebrew/rubocops/cask/url_legacy_comma_separators.rb b/Library/Homebrew/rubocops/cask/url_legacy_comma_separators.rb index 8a750372c2..67e0babdd2 100644 --- a/Library/Homebrew/rubocops/cask/url_legacy_comma_separators.rb +++ b/Library/Homebrew/rubocops/cask/url_legacy_comma_separators.rb @@ -4,13 +4,13 @@ module RuboCop module Cop module Cask - # This cop checks for version.before_comma and version.after_comma + # This cop checks for `version.before_comma` and `version.after_comma`. class UrlLegacyCommaSeparators < Url include OnUrlStanza extend AutoCorrector - MSG_CSV = "Use 'version.csv.first' instead of 'version.before_comma' " \ - "and 'version.csv.second' instead of 'version.after_comma'" + MSG_CSV = "Use `version.csv.first` instead of `version.before_comma` " \ + "and `version.csv.second` instead of `version.after_comma`." def on_url_stanza(stanza) return if stanza.stanza_node.type == :block diff --git a/Library/Homebrew/rubocops/cask/variables.rb b/Library/Homebrew/rubocops/cask/variables.rb index 574e6f1dc3..95352ddd22 100644 --- a/Library/Homebrew/rubocops/cask/variables.rb +++ b/Library/Homebrew/rubocops/cask/variables.rb @@ -50,7 +50,7 @@ module RuboCop replacement_parameters << "intel: #{intel_node.source}" unless blank_node?(intel_node) replacement_string += replacement_parameters.join(", ") - add_offense(node, message: "Use `#{replacement_string}` instead of `#{node.source}`") do |corrector| + add_offense(node, message: "Use `#{replacement_string}` instead of `#{node.source}`.") do |corrector| corrector.replace(node, replacement_string) end end diff --git a/Library/Homebrew/test/rubocops/cask/desc_spec.rb b/Library/Homebrew/test/rubocops/cask/desc_spec.rb index 77688913f6..d219d39d50 100644 --- a/Library/Homebrew/test/rubocops/cask/desc_spec.rb +++ b/Library/Homebrew/test/rubocops/cask/desc_spec.rb @@ -1,11 +1,8 @@ # frozen_string_literal: true require "rubocops/rubocop-cask" -require "test/rubocops/cask/shared_examples/cask_cop" - -describe RuboCop::Cop::Cask::Desc do - subject(:cop) { described_class.new } +describe RuboCop::Cop::Cask::Desc, :config do it "does not start with an article" do expect_no_offenses <<~RUBY cask "foo" do @@ -16,14 +13,14 @@ describe RuboCop::Cop::Cask::Desc do expect_offense <<~RUBY, "/homebrew-cask/Casks/foo.rb" cask 'foo' do desc 'A bar program' - ^ Cask/Desc: Description shouldn't start with an article. + ^ Description shouldn't start with an article. end RUBY expect_offense <<~RUBY, "/homebrew-cask/Casks/foo.rb" cask 'foo' do desc 'The bar program' - ^^^ Cask/Desc: Description shouldn't start with an article. + ^^^ Description shouldn't start with an article. end RUBY @@ -38,35 +35,35 @@ describe RuboCop::Cop::Cask::Desc do expect_offense <<~RUBY, "/homebrew-cask/Casks/foo.rb" cask 'foobar' do desc 'Foo bar program' - ^^^^^^^ Cask/Desc: Description shouldn't start with the cask name. + ^^^^^^^ Description shouldn't start with the cask name. end RUBY expect_offense <<~RUBY, "/homebrew-cask/Casks/foo.rb" cask 'foobar' do desc 'Foo-Bar program' - ^^^^^^^ Cask/Desc: Description shouldn't start with the cask name. + ^^^^^^^ Description shouldn't start with the cask name. end RUBY expect_offense <<~RUBY, "/homebrew-cask/Casks/foo.rb" cask 'foo-bar' do desc 'Foo bar program' - ^^^^^^^ Cask/Desc: Description shouldn't start with the cask name. + ^^^^^^^ Description shouldn't start with the cask name. end RUBY expect_offense <<~RUBY, "/homebrew-cask/Casks/foo.rb" cask 'foo-bar' do desc 'Foo-Bar program' - ^^^^^^^ Cask/Desc: Description shouldn't start with the cask name. + ^^^^^^^ Description shouldn't start with the cask name. end RUBY expect_offense <<~RUBY, "/homebrew-cask/Casks/foo.rb" cask 'foo-bar' do desc 'Foo Bar' - ^^^^^^^ Cask/Desc: Description shouldn't start with the cask name. + ^^^^^^^ Description shouldn't start with the cask name. end RUBY end @@ -75,28 +72,28 @@ describe RuboCop::Cop::Cask::Desc do expect_offense <<~RUBY, "/homebrew-cask/Casks/foo.rb" cask 'foo-bar' do desc 'macOS status bar monitor' - ^^^^^ Cask/Desc: Description shouldn't contain the platform. + ^^^^^ Description shouldn't contain the platform. end RUBY expect_offense <<~RUBY, "/homebrew-cask/Casks/foo.rb" cask 'foo-bar' do desc 'Toggles dark mode on Mac OS Mojave' - ^^^^^^ Cask/Desc: Description shouldn't contain the platform. + ^^^^^^ Description shouldn't contain the platform. end RUBY expect_offense <<~RUBY, "/homebrew-cask/Casks/foo.rb" cask 'foo-bar' do desc 'Better input source switcher for OS X' - ^^^^ Cask/Desc: Description shouldn't contain the platform. + ^^^^ Description shouldn't contain the platform. end RUBY expect_offense <<~RUBY, "/homebrew-cask/Casks/foo.rb" cask 'foo-bar' do desc 'Media Manager for Mac OS X' - ^^^^^^^^ Cask/Desc: Description shouldn't contain the platform. + ^^^^^^^^ Description shouldn't contain the platform. end RUBY @@ -109,7 +106,7 @@ describe RuboCop::Cop::Cask::Desc do expect_offense <<~RUBY cask 'foo' do desc 'Application for managing macOS virtual machines on macOS' - ^^^^^ Cask/Desc: Description shouldn't contain the platform. + ^^^^^ Description shouldn't contain the platform. end RUBY diff --git a/Library/Homebrew/test/rubocops/cask/homepage_url_trailing_slash_spec.rb b/Library/Homebrew/test/rubocops/cask/homepage_url_trailing_slash_spec.rb index d7c9acaa75..9cb668817b 100644 --- a/Library/Homebrew/test/rubocops/cask/homepage_url_trailing_slash_spec.rb +++ b/Library/Homebrew/test/rubocops/cask/homepage_url_trailing_slash_spec.rb @@ -1,64 +1,36 @@ # frozen_string_literal: true require "rubocops/rubocop-cask" -require "test/rubocops/cask/shared_examples/cask_cop" -describe RuboCop::Cop::Cask::HomepageUrlTrailingSlash do - include CaskCop - - subject(:cop) { described_class.new } - - context "when the homepage URL ends with a slash" do - let(:source) do - <<~CASK - cask 'foo' do - homepage 'https://foo.brew.sh/' - end - CASK - end - - include_examples "does not report any offenses" +describe RuboCop::Cop::Cask::HomepageUrlTrailingSlash, :config do + it "accepts a homepage URL ending with a slash" do + expect_no_offenses <<~CASK + cask 'foo' do + homepage 'https://foo.brew.sh/' + end + CASK end - context "when the homepage URL does not end with a slash but has a path" do - let(:source) do - <<~CASK - cask 'foo' do - homepage 'https://foo.brew.sh/path' - end - CASK - end - - include_examples "does not report any offenses" + it "accepts a homepage URL with a path" do + expect_no_offenses <<~CASK + cask 'foo' do + homepage 'https://foo.brew.sh/path' + end + CASK end - context "when the homepage URL does not end with a slash and has no path" do - let(:source) do - <<~CASK - cask 'foo' do - homepage 'https://foo.brew.sh' - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - homepage 'https://foo.brew.sh/' - end - CASK - end - let(:expected_offenses) do - [{ - message: "Cask/HomepageUrlTrailingSlash: 'https://foo.brew.sh' must have a slash after the domain.", - severity: :convention, - line: 2, - column: 11, - source: "'https://foo.brew.sh'", - }] - end + it "reports an offense when the homepage URL does not end with a slash and has no path" do + expect_offense <<~CASK + cask 'foo' do + homepage 'https://foo.brew.sh' + ^^^^^^^^^^^^^^^^^^^^^ 'https://foo.brew.sh' must have a slash after the domain. + end + CASK - include_examples "reports offenses" - - include_examples "autocorrects source" + expect_correction <<~CASK + cask 'foo' do + homepage 'https://foo.brew.sh/' + end + CASK 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 d54e2e3b89..fe336d3601 100644 --- a/Library/Homebrew/test/rubocops/cask/no_dsl_version_spec.rb +++ b/Library/Homebrew/test/rubocops/cask/no_dsl_version_spec.rb @@ -1,34 +1,20 @@ # frozen_string_literal: true require "rubocops/rubocop-cask" -require "test/rubocops/cask/shared_examples/cask_cop" -describe RuboCop::Cop::Cask::NoDslVersion do - include CaskCop - - subject(:cop) { described_class.new } - - context "with no dsl version" do - let(:source) { "cask 'foo' do; end" } - - include_examples "does not report any offenses" +describe RuboCop::Cop::Cask::NoDslVersion, :config do + it "accepts `cask` without a DSL version" do + expect_no_offenses "cask 'foo' do; end" 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: "Cask/NoDslVersion: Use `cask 'foo'` instead of `cask :v1 => 'foo'`", - severity: :convention, - line: 1, - column: 0, - source: "cask :v1 => 'foo'", - }] - end + it "reports an offense when `cask` has a DSL version" do + expect_offense <<~CASK + cask :v1 => 'foo' do; end + ^^^^^^^^^^^^^^^^^ Use `cask 'foo'` instead of `cask :v1 => 'foo'`. + CASK - include_examples "reports offenses" - - include_examples "autocorrects source" + expect_correction <<~CASK + cask 'foo' do; end + CASK end end diff --git a/Library/Homebrew/test/rubocops/cask/no_overrides_spec.rb b/Library/Homebrew/test/rubocops/cask/no_overrides_spec.rb index 187ee582fb..fb1bcde025 100644 --- a/Library/Homebrew/test/rubocops/cask/no_overrides_spec.rb +++ b/Library/Homebrew/test/rubocops/cask/no_overrides_spec.rb @@ -1,254 +1,176 @@ # frozen_string_literal: true require "rubocops/rubocop-cask" -require "test/rubocops/cask/shared_examples/cask_cop" -describe RuboCop::Cop::Cask::NoOverrides do - include CaskCop +describe RuboCop::Cop::Cask::NoOverrides, :config do + it "accepts when there are no `on_*` blocks" do + expect_no_offenses <<~CASK + cask 'foo' do + version '1.2.3' + url 'https://brew.sh/foo.pkg' - subject(:cop) { described_class.new } + name 'Foo' + end + CASK + end - context "when there are no on_system blocks" do - let(:source) do - <<~CASK - cask 'foo' do + it "accepts when there are no top-level standalone stanzas" do + expect_no_offenses <<~CASK + cask 'foo' do + on_mojave :or_later do + version :latest + end + end + CASK + end + + it "accepts non-overridable stanzas in `on_*` blocks" do + expect_no_offenses <<~CASK + cask 'foo' do + version '1.2.3' + + on_arm do + binary "foo-\#{version}-arm64" + end + + app "foo-\#{version}.app" + + binary "foo-\#{version}" + end + CASK + end + + it "accepts `arch` and `version` interpolations in strings in `on_*` blocks" do + expect_no_offenses <<~CASK + cask 'foo' do + arch arm: "arm64", intel: "x86" + version '1.2.3' + + on_mojave :or_later do + sha256 "aaa" + + url "https://brew.sh/foo-\#{version}-\#{arch}.pkg" + end + end + CASK + end + + it "accepts `version` interpolations with method calls in strings in `on_*` blocks" do + expect_no_offenses <<~CASK + cask 'foo' do + version '0.99,123.3' + + on_mojave :or_later do + url "https://brew.sh/foo-\#{version.csv.first}-\#{version.csv.second}.pkg" + end + end + CASK + end + + it "accepts `arch` interpolations in regexes in `on_*` blocks" do + expect_no_offenses <<~CASK + cask 'foo' do + arch arm: "arm64", intel: "x86" + + version '0.99,123.3' + + on_mojave :or_later do + url "https://brew.sh/foo-\#{arch}-\#{version.csv.first}-\#{version.csv.last}.pkg" + + livecheck do + url "https://brew.sh/foo/releases.html" + regex(/href=.*?foo[._-]v?(\d+(?:.\d+)+)-\#{arch}.pkg/i) + end + end + end + CASK + end + + it "ignores contents of single-line `livecheck` blocks in `on_*` blocks" do + expect_no_offenses <<~CASK + cask 'foo' do + on_intel do + livecheck do + url 'https://brew.sh/foo' # Livecheck should be allowed since it's a different "kind" of URL. + end version '1.2.3' - url 'https://brew.sh/foo.pkg' - - name 'Foo' end - CASK - end + on_arm do + version '2.3.4' + end - include_examples "does not report any offenses" + url 'https://brew.sh/foo.pkg' + sha256 "bbb" + end + CASK end - context "when there are no top-level standalone stanzas" do - let(:source) do - <<~CASK - cask 'foo' do - on_mojave :or_later do - version :latest + it "ignores contents of multi-line `livecheck` blocks in `on_*` blocks" do + expect_no_offenses <<~CASK + cask 'foo' do + on_intel do + livecheck do + url 'https://brew.sh/foo' # Livecheck should be allowed since it's a different "kind" of URL. + strategy :sparkle end - end - CASK - end - - include_examples "does not report any offenses" - end - - context "when there are top-level stanzas also in `on_*` blocks that should not override" do - let(:source) do - <<~CASK - cask 'foo' do version '1.2.3' - - on_arm do - binary "foo-\#{version}-arm64" - end - - app "foo-\#{version}.app" - - binary "foo-\#{version}" end - CASK - end + on_arm do + version '2.3.4' + end - include_examples "does not report any offenses" + url 'https://brew.sh/foo.pkg' + sha256 "bbb" + end + CASK end - context "when there are `arch` variables in the `url` in the `on_*` blocks" do - let(:source) do - <<~CASK - cask 'foo' do - arch arm: "arm64", intel: "x86" - version '1.2.3' - on_mojave :or_later do - url "https://brew.sh/foo-\#{version}-\#{arch}.pkg" - sha256 "aaa" - end - end - CASK - end + it "accepts `on_*` blocks that don't override upper-level stanzas" do + expect_no_offenses <<~CASK + cask "foo" do + version "1.2.3" - include_examples "does not report any offenses" - end - - context "when there are `version` interpolations in `on_*` blocks with methods called on them" do - let(:source) do - <<~CASK - cask 'foo' do - version 0.99,123.3 - - on_mojave :or_later do - url "https://brew.sh/foo-\#{version.csv.first}-\#{version.csv.second}.pkg" - end - end - CASK - end - - include_examples "does not report any offenses" - end - - context "when there are `arch` interpolations in regexps in `on_*` blocks" do - let(:source) do - <<~CASK - cask 'foo' do - arch arm: "arm64", intel: "x86" - - version 0.99,123.3 - - on_mojave :or_later do - url "https://brew.sh/foo-\#{arch}-\#{version.csv.first}-\#{version.csv.last}.pkg" - - livecheck do - url "https://brew.sh/foo/releases.html" - regex(/href=.*?foo[._-]v?(\d+(?:.\d+)+)-\#{arch}.pkg/i) - end - end - end - CASK - end - - include_examples "does not report any offenses" - end - - context "when there are single-line livecheck blocks within `on_*` blocks, ignore their contents" do - let(:source) do - <<~CASK - cask 'foo' do - on_intel do - livecheck do - url 'https://brew.sh/foo' # Livecheck should be allowed since it's a different "kind" of URL. - end - version '1.2.3' - end - on_arm do - version '2.3.4' - end - - url 'https://brew.sh/foo.pkg' + on_big_sur :or_older do sha256 "bbb" + url "https://brew.sh/legacy/foo-2.3.4.dmg" end - CASK - end - - include_examples "does not report any offenses" - end - - context "when there are multi-line livecheck blocks within `on_*` blocks, ignore their contents" do - let(:source) do - <<~CASK - cask 'foo' do - on_intel do - livecheck do - url 'https://brew.sh/foo' # Livecheck should be allowed since it's a different "kind" of URL. - strategy :sparkle - end - version '1.2.3' - end - on_arm do - version '2.3.4' - end - - url 'https://brew.sh/foo.pkg' - sha256 "bbb" - end - CASK - end - - include_examples "does not report any offenses" - end - - context "when there's only one difference between the `on_*` blocks" do - let(:source) do - <<~CASK - cask "foo" do - version "1.2.3" - - on_big_sur :or_older do - sha256 "bbb" - url "https://brew.sh/legacy/foo-2.3.4.dmg" - end - on_monterey :or_newer do - sha256 "aaa" - url "https://brew.sh/foo-2.3.4.dmg" - end - end - CASK - end - - include_examples "does not report any offenses" - end - - context "when there are multiple differences between the `on_*` blocks" do - let(:source) do - <<~CASK - cask "foo" do - version "1.2.3" + on_monterey :or_newer do sha256 "aaa" url "https://brew.sh/foo-2.3.4.dmg" - - on_big_sur :or_older do - sha256 "bbb" - url "https://brew.sh/legacy/foo-2.3.4.dmg" - end end - CASK - end - - let(:expected_offenses) do - [{ - message: <<~EOS, - Cask/NoOverrides: Do not use a top-level `sha256` stanza as the default. Add it to an `on_{system}` block instead. - Use `:or_older` or `:or_newer` to specify a range of macOS versions. - EOS - severity: :convention, - line: 3, - column: 2, - source: "sha256 \"aaa\"", - }, { - message: <<~EOS, - Cask/NoOverrides: Do not use a top-level `url` stanza as the default. Add it to an `on_{system}` block instead. - Use `:or_older` or `:or_newer` to specify a range of macOS versions. - EOS - severity: :convention, - line: 4, - column: 2, - source: "url \"https://brew.sh/foo-2.3.4.dmg\"", - }] - end - - include_examples "reports offenses" + end + CASK end - context "when there are top-level standalone stanzas" do - let(:source) do - <<~CASK - cask 'foo' do - version '2.3.4' - on_mojave :or_older do - version '1.2.3' - end + it "reports an offense when `on_*` blocks override a single upper-level stanza" do + expect_offense <<~CASK + cask 'foo' do + version '2.3.4' + ^^^^^^^^^^^^^^^ Do not use a top-level `version` stanza as the default. Add it to an `on_{system}` block instead. Use `:or_older` or `:or_newer` to specify a range of macOS versions. - url 'https://brew.sh/foo-2.3.4.dmg' + on_mojave :or_older do + version '1.2.3' end - CASK - end - let(:expected_offenses) do - [{ - message: <<~EOS, - Cask/NoOverrides: Do not use a top-level `version` stanza as the default. Add it to an `on_{system}` block instead. - Use `:or_older` or `:or_newer` to specify a range of macOS versions. - EOS - severity: :convention, - line: 2, - column: 2, - source: "version '2.3.4'", - }] - end + url 'https://brew.sh/foo-2.3.4.dmg' + end + CASK + end - include_examples "reports offenses" + it "reports an offense when `on_*` blocks override multiple upper-level stanzas" do + expect_offense <<~CASK + cask "foo" do + version "1.2.3" + sha256 "aaa" + ^^^^^^^^^^^^ Do not use a top-level `sha256` stanza as the default. Add it to an `on_{system}` block instead. Use `:or_older` or `:or_newer` to specify a range of macOS versions. + url "https://brew.sh/foo-2.3.4.dmg" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use a top-level `url` stanza as the default. Add it to an `on_{system}` block instead. Use `:or_older` or `:or_newer` to specify a range of macOS versions. + + on_big_sur :or_older do + sha256 "bbb" + url "https://brew.sh/legacy/foo-2.3.4.dmg" + end + end + CASK end end diff --git a/Library/Homebrew/test/rubocops/cask/on_system_conditionals_spec.rb b/Library/Homebrew/test/rubocops/cask/on_system_conditionals_spec.rb index 4bf93898d6..5327ac93c8 100644 --- a/Library/Homebrew/test/rubocops/cask/on_system_conditionals_spec.rb +++ b/Library/Homebrew/test/rubocops/cask/on_system_conditionals_spec.rb @@ -1,458 +1,249 @@ # frozen_string_literal: true require "rubocops/rubocop-cask" -require "test/rubocops/cask/shared_examples/cask_cop" - -describe RuboCop::Cop::Cask::OnSystemConditionals do - include CaskCop - - subject(:cop) { described_class.new } +describe RuboCop::Cop::Cask::OnSystemConditionals, :config do context "when auditing `postflight` stanzas" do - context "when there are no on_system blocks" do - let(:source) do - <<~CASK - cask 'foo' do - postflight do + it "accepts when there are no `on_*` blocks" do + expect_no_offenses <<~CASK + cask 'foo' do + postflight do + foobar + end + end + CASK + end + + it "reports an offense it contains an `on_intel` block" do + expect_offense <<~CASK + cask 'foo' do + postflight do + on_intel do + ^^^^^^^^ Don't use `on_intel` in `postflight do`, use `if Hardware::CPU.intel?` instead. foobar end end - CASK - end + end + CASK - include_examples "does not report any offenses" + # FIXME: Infinite loop alternating between `if Hardware::CPU.intel?` and `on_intel do`. + expect_correction <<~CASK, loop: false + cask 'foo' do + postflight do + if Hardware::CPU.intel? + foobar + end + end + end + CASK end - context "when there is an `on_intel` block" do - let(:source) do - <<~CASK - cask 'foo' do - postflight do - on_intel do - foobar - end + it "reports an offense when it contains an `on_monterey` block" do + expect_offense <<~CASK + cask 'foo' do + postflight do + on_monterey do + ^^^^^^^^^^^ Don't use `on_monterey` in `postflight do`, use `if MacOS.version == :monterey` instead. + foobar end end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - postflight do - if Hardware::CPU.intel? - foobar - end + end + CASK + + # FIXME: Infinite loop alternating between `if MacOS.version == :monterey` and `on_monterey do`. + expect_correction <<~CASK, loop: false + cask 'foo' do + postflight do + if MacOS.version == :monterey + foobar end end - CASK - end - let(:expected_offenses) do - [{ - message: <<~EOS.chomp, - Cask/OnSystemConditionals: Don't use `on_intel` in `postflight do`, use `if Hardware::CPU.intel?` instead. - EOS - severity: :convention, - line: 3, - column: 4, - source: "on_intel", - }] - end - - include_examples "reports offenses" - - include_examples "autocorrects source" + end + CASK end - context "when there is an `on_monterey` block" do - let(:source) do - <<~CASK - cask 'foo' do - postflight do - on_monterey do - foobar - end + it "reports an offense when it contains an `on_monterey :or_older` block" do + expect_offense <<~CASK + cask 'foo' do + postflight do + on_monterey :or_older do + ^^^^^^^^^^^^^^^^^^^^^ Don't use `on_monterey :or_older` in `postflight do`, use `if MacOS.version <= :monterey` instead. + foobar end end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - postflight do - if MacOS.version == :monterey - foobar - end + end + CASK + + # FIXME: Infinite loop alternating between `if MacOS.version <= :monterey` and `on_monterey :or_older do`. + expect_correction <<~CASK, loop: false + cask 'foo' do + postflight do + if MacOS.version <= :monterey + foobar end end - CASK - end - let(:expected_offenses) do - [{ - message: "Cask/OnSystemConditionals: Don't use `on_monterey` in `postflight do`, use " \ - "`if MacOS.version == :monterey` instead.", - severity: :convention, - line: 3, - column: 4, - source: "on_monterey", - }] - end - - include_examples "reports offenses" - - include_examples "autocorrects source" - end - - context "when there is an `on_monterey :or_older` block" do - let(:source) do - <<~CASK - cask 'foo' do - postflight do - on_monterey :or_older do - foobar - end - end - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - postflight do - if MacOS.version <= :monterey - foobar - end - end - end - CASK - end - let(:expected_offenses) do - [{ - message: "Cask/OnSystemConditionals: Don't use `on_monterey :or_older` in `postflight do`, " \ - "use `if MacOS.version <= :monterey` instead.", - severity: :convention, - line: 3, - column: 4, - source: "on_monterey :or_older", - }] - end - - include_examples "reports offenses" - - include_examples "autocorrects source" + end + CASK end end - context "when auditing `sha256` stanzas inside on_arch blocks" do - context "when there are no on_arch blocks" do - let(:source) do - <<~CASK - cask 'foo' do + context "when auditing `sha256` stanzas inside `on_arch` blocks" do + it "accepts when there are no `on_arch` blocks" do + expect_no_offenses <<~CASK + cask 'foo' do + sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" + end + CASK + end + + it "accepts when the `sha256` stanza is used with keyword arguments" do + expect_no_offenses <<~CASK + cask 'foo' do + sha256 arm: "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94", + intel: "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" + end + CASK + end + + it "accepts when there is only one `on_arch` block" do + expect_no_offenses <<~CASK + cask 'foo' do + on_intel do sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" end - CASK - end - - include_examples "does not report any offenses" + end + CASK end - context "when the proper `sha256` stanza is used" do - let(:source) do - <<~CASK - cask 'foo' do - sha256 arm: "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94", - intel: "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" + it "reports an offense when `sha256` is specified in all `on_arch` blocks" do + expect_offense <<~CASK + cask 'foo' do + on_intel do + sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" end - CASK - end - - include_examples "does not report any offenses" - end - - context "when the `sha256` stanza needs to be removed from the on_arch blocks" do - let(:source) do - <<~CASK - cask 'foo' do - on_intel do - sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" - end - on_arm do - sha256 "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" - end - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - #{" "} - sha256 arm: "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b", intel: "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" - end - CASK - end - let(:offense_source) do - <<~CASK on_arm do - sha256 "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" - end - CASK - end - let(:expected_offenses) do - [{ - message: <<~EOS.chomp, - Cask/OnSystemConditionals: Use `sha256 arm: "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b", intel: "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94"` instead of nesting the `sha256` stanzas in `on_intel` and `on_arm` blocks - EOS - severity: :convention, - line: 5, - column: 2, - source: offense_source.strip, - }] - end + ^^^^^^^^^ Use `sha256 arm: "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b", intel: "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94"` instead of nesting the `sha256` stanzas in `on_intel` and `on_arm` blocks + sha256 "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" + end + end + CASK - include_examples "reports offenses" - - include_examples "autocorrects source" + expect_correction <<~CASK + cask 'foo' do + #{" "} + sha256 arm: "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b", intel: "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" + end + CASK end - context "when there is only one on_arch block" do - let(:source) do - <<~CASK - cask 'foo' do - on_intel do - sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" - end + it "accepts when there is also a `version` stanza inside the `on_arch` blocks" do + expect_no_offenses <<~CASK + cask 'foo' do + on_intel do + version "1.0.0" + sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" end - CASK - end - - include_examples "does not report any offenses" + on_arm do + version "2.0.0" + sha256 "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" + end + end + CASK end - context "when there is also a `version` stanza inside the on_arch blocks" do - let(:source) do - <<~CASK - cask 'foo' do - on_intel do - version "1.0.0" - sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" - end - on_arm do - version "2.0.0" - sha256 "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" - end + it "accepts when there is also a `version` stanza inside only a single `on_arch` block" do + expect_no_offenses <<~CASK + cask 'foo' do + on_intel do + version "2.0.0" + sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" end - CASK - end - - include_examples "does not report any offenses" - end - - context "when there is also a `version` stanza inside only a single on_arch block" do - let(:source) do - <<~CASK - cask 'foo' do - on_intel do - version "2.0.0" - sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" - end - on_arm do - sha256 "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" - end + on_arm do + sha256 "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" end - CASK - end - - include_examples "does not report any offenses" + end + CASK end end context "when auditing loose `Hardware::CPU` method calls" do - context "when there is a `Hardware::CPU.arm?` reference" do - let(:source) do - <<~CASK - cask 'foo' do - if Hardware::CPU.arm? && other_condition - sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" - else - sha256 "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" - end - end - CASK - end - let(:expected_offenses) do - [{ - message: <<~EOS.chomp, - Cask/OnSystemConditionals: Don't use `Hardware::CPU.arm?`, use `on_arm` and `on_intel` blocks instead. - EOS - severity: :convention, - line: 2, - column: 5, - source: "Hardware::CPU.arm?", - }] - end - - include_examples "reports offenses" - end - - context "when there is a `Hardware::CPU.intel?` reference" do - let(:source) do - <<~CASK - cask 'foo' do - if Hardware::CPU.intel? && other_condition - sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" - else - sha256 "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" - end - end - CASK - end - let(:expected_offenses) do - [{ - message: <<~EOS.chomp, - Cask/OnSystemConditionals: Don't use `Hardware::CPU.intel?`, use `on_arm` and `on_intel` blocks instead. - EOS - severity: :convention, - line: 2, - column: 5, - source: "Hardware::CPU.intel?", - }] - end - - include_examples "reports offenses" - end - - context "when there is a `Hardware::CPU.arch` reference" do - let(:source) do - <<~CASK - cask 'foo' do - version "1.2.3" + it "reports an offense when `Hardware::CPU.arm?` is used" do + expect_offense <<~CASK + cask 'foo' do + if Hardware::CPU.arm? && other_condition + ^^^^^^^^^^^^^^^^^^ Don't use `Hardware::CPU.arm?`, use `on_arm` and `on_intel` blocks instead. sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" - - url "https://example.com/foo-\#{version}-\#{Hardware::CPU.arch}.zip" + else + sha256 "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" end - CASK - end - let(:expected_offenses) do - [{ - message: <<~EOS.chomp, - Cask/OnSystemConditionals: Don't use `Hardware::CPU.arch`, use `on_arm` and `on_intel` blocks instead. - EOS - severity: :convention, - line: 5, - column: 44, - source: "Hardware::CPU.arch", - }] - end + end + CASK + end - include_examples "reports offenses" + it "reports an offense when `Hardware::CPU.intel?` is used" do + expect_offense <<~CASK + cask 'foo' do + if Hardware::CPU.intel? && other_condition + ^^^^^^^^^^^^^^^^^^^^ Don't use `Hardware::CPU.intel?`, use `on_arm` and `on_intel` blocks instead. + sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" + else + sha256 "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" + end + end + CASK + end + + it "reports an offense when `Hardware::CPU.arch` is used" do + expect_offense <<~'CASK' + cask 'foo' do + version "1.2.3" + sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" + + url "https://example.com/foo-#{version}-#{Hardware::CPU.arch}.zip" + ^^^^^^^^^^^^^^^^^^ Don't use `Hardware::CPU.arch`, use `on_arm` and `on_intel` blocks instead. + end + CASK end end context "when auditing loose `MacOS.version` method calls" do - context "when there is a `MacOS.version ==` reference" do - let(:source) do - <<~CASK - cask 'foo' do - if MacOS.version == :catalina - version "1.0.0" - else - version "2.0.0" - end + it "reports an offense when `MacOS.version ==` is used" do + expect_offense <<~CASK + cask 'foo' do + if MacOS.version == :catalina + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if MacOS.version == :catalina`, use `on_catalina do` instead. + version "1.0.0" + else + version "2.0.0" end - CASK - end - let(:expected_offenses) do - [{ - message: <<~EOS.chomp, - Cask/OnSystemConditionals: Don't use `if MacOS.version == :catalina`, use `on_catalina do` instead. - EOS - severity: :convention, - line: 2, - column: 2, - source: "if MacOS.version == :catalina\n version \"1.0.0\"\n else\n version \"2.0.0\"\n end", - }] - end - - include_examples "reports offenses" + end + CASK end - context "when there is a `MacOS.version <=` reference" do - let(:source) do - <<~CASK - cask 'foo' do - if MacOS.version <= :catalina - version "1.0.0" - else - version "2.0.0" - end + it "reports an offense when `MacOS.version <=` is used" do + expect_offense <<~CASK + cask 'foo' do + if MacOS.version <= :catalina + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if MacOS.version <= :catalina`, use `on_catalina :or_older do` instead. + version "1.0.0" + else + version "2.0.0" end - CASK - end - let(:expected_offenses) do - [{ - message: <<~EOS.chomp, - Cask/OnSystemConditionals: Don't use `if MacOS.version <= :catalina`, use `on_catalina :or_older do` instead. - EOS - severity: :convention, - line: 2, - column: 2, - source: "if MacOS.version <= :catalina\n version \"1.0.0\"\n else\n version \"2.0.0\"\n end", - }] - end - - include_examples "reports offenses" + end + CASK end - context "when there is a `MacOS.version >=` reference" do - let(:source) do - <<~CASK - cask 'foo' do - if MacOS.version >= :catalina - version "1.0.0" - else - version "2.0.0" - end + it "reports an offense when `MacOS.version >=` is used" do + expect_offense <<~CASK + cask 'foo' do + if MacOS.version >= :catalina + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if MacOS.version >= :catalina`, use `on_catalina :or_newer do` instead. + version "1.0.0" + else + version "2.0.0" end - CASK - end - let(:expected_offenses) do - [{ - message: <<~EOS.chomp, - Cask/OnSystemConditionals: Don't use `if MacOS.version >= :catalina`, use `on_catalina :or_newer do` instead. - EOS - severity: :convention, - line: 2, - column: 2, - source: "if MacOS.version >= :catalina\n version \"1.0.0\"\n else\n version \"2.0.0\"\n end", - }] - end - - include_examples "reports offenses" - end - - context "when there is a `MacOS.version` reference" do - let(:source) do - <<~CASK - cask 'foo' do - version "1.2.3" - sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" - - url "https://example.com/foo-\#{version}-\#{MacOS.version == :monterey}.zip" - end - CASK - end - let(:expected_offenses) do - [{ - message: <<~EOS.chomp, - Cask/OnSystemConditionals: Don't use `MacOS.version == :monterey`, use `on_{macos_version}` blocks instead. - EOS - severity: :convention, - line: 5, - column: 44, - source: "MacOS.version == :monterey", - }] - end - - include_examples "reports offenses" + end + CASK end end end diff --git a/Library/Homebrew/test/rubocops/cask/shared_examples/cask_cop.rb b/Library/Homebrew/test/rubocops/cask/shared_examples/cask_cop.rb deleted file mode 100644 index c5cdcde9e8..0000000000 --- a/Library/Homebrew/test/rubocops/cask/shared_examples/cask_cop.rb +++ /dev/null @@ -1,62 +0,0 @@ -# frozen_string_literal: true - -module CaskCop - shared_examples "does not report any offenses" do - it "does not report any offenses" do - expect_no_offenses(source) - end - end - - shared_examples "reports offenses" do - it "reports offenses" do - expect_reported_offenses(source, expected_offenses) - end - end - - shared_examples "autocorrects source" do - it "autocorrects source" do - expect_autocorrected_source(source, correct_source) - end - end - - def expect_no_offenses(source) - expect(inspect_source(source)).to be_empty - end - - def expect_reported_offenses(source, expected_offenses) - offenses = inspect_source(source) - expect(offenses.size).to eq(expected_offenses.size) - expected_offenses.zip(offenses).each do |expected, actual| - expect_offense2(expected, actual) - end - end - - def expect_offense2(expected, actual) - expect(actual.message).to eq(expected[:message]) - expect(actual.severity).to eq(expected[:severity]) - expect(actual.line).to eq(expected[:line]) - expect(actual.column).to eq(expected[:column]) - expect(actual.location.source).to eq(expected[:source]) - end - - # TODO: Replace with `expect_correction` from `rubocop-rspec`. - def expect_autocorrected_source(source, correct_source) - correct_source = Array(correct_source).join("\n") - - current_source = source - - # RuboCop runs auto-correction in a loop to handle nested offenses. - loop do - current_source = autocorrect_source(current_source) - - if (ignored_nodes = cop.instance_variable_get(:@ignored_nodes)) && ignored_nodes.any? - ignored_nodes.clear - next - end - - break - end - - expect(current_source).to eq correct_source - end -end diff --git a/Library/Homebrew/test/rubocops/cask/stanza_grouping_spec.rb b/Library/Homebrew/test/rubocops/cask/stanza_grouping_spec.rb index bc5fea59b0..c2dee22c98 100644 --- a/Library/Homebrew/test/rubocops/cask/stanza_grouping_spec.rb +++ b/Library/Homebrew/test/rubocops/cask/stanza_grouping_spec.rb @@ -1,337 +1,205 @@ # frozen_string_literal: true require "rubocops/rubocop-cask" -require "test/rubocops/cask/shared_examples/cask_cop" -describe RuboCop::Cop::Cask::StanzaGrouping do - include CaskCop - - subject(:cop) { described_class.new } - - let(:missing_line_msg) do - "Cask/StanzaGrouping: stanza groups should be separated by a single empty line" - end - let(:extra_line_msg) do - "Cask/StanzaGrouping: stanzas within the same group should have no lines between them" +describe RuboCop::Cop::Cask::StanzaGrouping, :config do + it "accepts a sole stanza" do + expect_no_offenses <<~CASK + cask 'foo' do + version :latest + end + CASK end - context "when there is only one stanza" do - let(:source) do - <<~CASK - cask 'foo' do - version :latest - end - CASK - end - - include_examples "does not report any offenses" + it "accepts correctly grouped stanzas" do + expect_no_offenses <<~CASK + cask 'foo' do + version :latest + sha256 :no_check + end + CASK end - context "when no stanzas are incorrectly grouped" do - let(:source) do - <<~CASK - cask 'foo' do - version :latest - sha256 :no_check - end - CASK - end + it "accepts correctly grouped stanzas and variable assignments" do + expect_no_offenses <<~CASK + cask 'foo' do + arch arm: "arm64", intel: "x86_64" + folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" - include_examples "does not report any offenses" + version :latest + sha256 :no_check + end + CASK end - context "when no stanzas or variable assignments are incorrectly grouped" do - let(:source) do - <<~CASK - cask 'foo' do - arch arm: "arm64", intel: "x86_64" - folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" + it "reports an offense when a stanza is grouped incorrectly" do + expect_offense <<~CASK + cask 'foo' do + version :latest - version :latest - sha256 :no_check - end - CASK - end + ^{} stanzas within the same group should have no lines between them + sha256 :no_check + end + CASK - include_examples "does not report any offenses" + expect_correction <<~CASK + cask 'foo' do + version :latest + sha256 :no_check + end + CASK end - context "when one stanza is incorrectly grouped" do - let(:source) do - <<~CASK - cask 'foo' do - version :latest + it "reports an offense for an incorrectly grouped `arch` stanza" do + expect_offense <<~CASK + cask 'foo' do + arch arm: "arm64", intel: "x86_64" + version :latest + ^^^^^^^^^^^^^^^^^ stanza groups should be separated by a single empty line + sha256 :no_check + end + CASK - sha256 :no_check - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - version :latest - sha256 :no_check - end - CASK - end - let(:expected_offenses) do - [{ - message: extra_line_msg, - severity: :convention, - line: 3, - column: 0, - source: "\n", - }] - end + expect_correction <<~CASK + cask 'foo' do + arch arm: "arm64", intel: "x86_64" - include_examples "reports offenses" - - include_examples "autocorrects source" + version :latest + sha256 :no_check + end + CASK end - context "when the arch stanza is incorrectly grouped" do - let(:source) do - <<~CASK - cask 'foo' do - arch arm: "arm64", intel: "x86_64" - version :latest - sha256 :no_check - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - arch arm: "arm64", intel: "x86_64" + it "reports an offense for an incorrectly grouped variable assignment" do + expect_offense <<~CASK + cask 'foo' do + arch arm: "arm64", intel: "x86_64" + folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" + version :latest + ^^^^^^^^^^^^^^^^^ stanza groups should be separated by a single empty line + sha256 :no_check + end + CASK - version :latest - sha256 :no_check - end - CASK - end - let(:expected_offenses) do - [{ - message: missing_line_msg, - severity: :convention, - line: 3, - column: 0, - source: " version :latest", - }] - end + expect_correction <<~CASK + cask 'foo' do + arch arm: "arm64", intel: "x86_64" + folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" - include_examples "reports offenses" - - include_examples "autocorrects source" + version :latest + sha256 :no_check + end + CASK end - context "when one variable assignment is incorrectly grouped" do - let(:source) do - <<~CASK - cask 'foo' do - arch arm: "arm64", intel: "x86_64" - folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" - version :latest - sha256 :no_check - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - arch arm: "arm64", intel: "x86_64" - folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" + it "reports an offense for multiple incorrectly grouped stanzas" do + expect_offense <<~CASK + cask 'foo' do + version :latest + sha256 :no_check + url 'https://foo.brew.sh/foo.zip' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ stanza groups should be separated by a single empty line - version :latest - sha256 :no_check - end - CASK - end - let(:expected_offenses) do - [{ - message: missing_line_msg, - severity: :convention, - line: 4, - column: 0, - source: " version :latest", - }] - end + ^{} stanzas within the same group should have no lines between them + name 'Foo' - include_examples "reports offenses" + ^{} stanzas within the same group should have no lines between them + homepage 'https://foo.brew.sh' - include_examples "autocorrects source" + app 'Foo.app' + uninstall :quit => 'com.example.foo', + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ stanza groups should be separated by a single empty line + :kext => 'com.example.foo.kextextension' + end + CASK + + expect_correction <<~CASK + cask 'foo' do + version :latest + sha256 :no_check + + url 'https://foo.brew.sh/foo.zip' + name 'Foo' + homepage 'https://foo.brew.sh' + + app 'Foo.app' + + uninstall :quit => 'com.example.foo', + :kext => 'com.example.foo.kextextension' + end + CASK end - context "when many stanzas are incorrectly grouped" do - let(:source) do - <<~CASK - cask 'foo' do - version :latest - sha256 :no_check - url 'https://foo.brew.sh/foo.zip' - - name 'Foo' - - homepage 'https://foo.brew.sh' - - app 'Foo.app' - uninstall :quit => 'com.example.foo', - :kext => 'com.example.foo.kextextension' - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - version :latest - sha256 :no_check - - url 'https://foo.brew.sh/foo.zip' - name 'Foo' - homepage 'https://foo.brew.sh' - - app 'Foo.app' - - uninstall :quit => 'com.example.foo', - :kext => 'com.example.foo.kextextension' - end - CASK - end - let(:expected_offenses) do - [{ - message: missing_line_msg, - severity: :convention, - line: 4, - column: 0, - source: " url 'https://foo.brew.sh/foo.zip'", - }, { - message: extra_line_msg, - severity: :convention, - line: 5, - column: 0, - source: "\n", - }, { - message: extra_line_msg, - severity: :convention, - line: 7, - column: 0, - source: "\n", - }, { - message: missing_line_msg, - severity: :convention, - line: 11, - column: 0, - source: " uninstall :quit => 'com.example.foo',", - }] - end - - include_examples "reports offenses" - - include_examples "autocorrects source" - end - - context "when many stanzas and variable assignments are incorrectly grouped" do - let(:source) do - <<~CASK - cask 'foo' do - arch arm: "arm64", intel: "x86_64" - folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" - - platform = on_arch_conditional arm: "darwin-arm64", intel: "darwin" - version :latest - sha256 :no_check - url 'https://foo.brew.sh/foo.zip' - - name 'Foo' - - homepage 'https://foo.brew.sh' - - app 'Foo.app' - uninstall :quit => 'com.example.foo', - :kext => 'com.example.foo.kextextension' - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - arch arm: "arm64", intel: "x86_64" - folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" - platform = on_arch_conditional arm: "darwin-arm64", intel: "darwin" - - version :latest - sha256 :no_check - - url 'https://foo.brew.sh/foo.zip' - name 'Foo' - homepage 'https://foo.brew.sh' - - app 'Foo.app' - - uninstall :quit => 'com.example.foo', - :kext => 'com.example.foo.kextextension' - end - CASK - end - let(:expected_offenses) do - [{ - message: extra_line_msg, - severity: :convention, - line: 4, - column: 0, - source: "\n", - }, { - message: missing_line_msg, - severity: :convention, - line: 6, - column: 0, - source: " version :latest", - }, { - message: missing_line_msg, - severity: :convention, - line: 8, - column: 0, - source: " url 'https://foo.brew.sh/foo.zip'", - }, { - message: extra_line_msg, - severity: :convention, - line: 9, - column: 0, - source: "\n", - }, { - message: extra_line_msg, - severity: :convention, - line: 11, - column: 0, - source: "\n", - }, { - message: missing_line_msg, - severity: :convention, - line: 15, - column: 0, - source: " uninstall :quit => 'com.example.foo',", - }] - end - - include_examples "reports offenses" - - include_examples "autocorrects source" - end - - context "when caveats stanza is incorrectly grouped" do - let(:source) do - format(<<~CASK, caveats: caveats.strip) + it "reports an offense for multiple incorrectly grouped stanzas and variable assignments" do + expect_offense <<~CASK + cask 'foo' do + arch arm: "arm64", intel: "x86_64" + folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" + + ^{} stanzas within the same group should have no lines between them + platform = on_arch_conditional arm: "darwin-arm64", intel: "darwin" + version :latest + ^^^^^^^^^^^^^^^^^ stanza groups should be separated by a single empty line + sha256 :no_check + + url 'https://foo.brew.sh/foo.zip' + + ^{} stanzas within the same group should have no lines between them + name 'Foo' + + ^{} stanzas within the same group should have no lines between them + homepage 'https://foo.brew.sh' + + app 'Foo.app' + uninstall :quit => 'com.example.foo', + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ stanza groups should be separated by a single empty line + :kext => 'com.example.foo.kextextension' + end + CASK + + expect_correction <<~CASK + cask 'foo' do + arch arm: "arm64", intel: "x86_64" + folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" + platform = on_arch_conditional arm: "darwin-arm64", intel: "darwin" + + version :latest + sha256 :no_check + + url 'https://foo.brew.sh/foo.zip' + name 'Foo' + homepage 'https://foo.brew.sh' + + app 'Foo.app' + + uninstall :quit => 'com.example.foo', + :kext => 'com.example.foo.kextextension' + end + CASK + end + + shared_examples "caveats" do + it "reports an offense for an incorrectly grouped `caveats` stanza" do + # Indent all except the first line. + interpolated_caveats = caveats.strip + + expect_offense <<~CASK cask 'foo' do version :latest sha256 :no_check url 'https://foo.brew.sh/foo.zip' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ stanza groups should be separated by a single empty line name 'Foo' app 'Foo.app' - %s + ^^^^^^^^^^^^^^^ stanza groups should be separated by a single empty line + #{interpolated_caveats} end CASK - end - let(:correct_source) do - format(<<~CASK, caveats: caveats.strip) + + # Remove offense annotations. + corrected_caveats = interpolated_caveats.gsub(/\n\s*\^+\s+.*$/, "") + + expect_correction <<~CASK cask 'foo' do version :latest sha256 :no_check @@ -341,242 +209,232 @@ describe RuboCop::Cop::Cask::StanzaGrouping do app 'Foo.app' - %s + #{corrected_caveats} end CASK end + end - context "when caveats is a one-line string" do - let(:caveats) { "caveats 'This is a one-line caveat.'" } - - include_examples "autocorrects source" + context "when `caveats` is a one-line string" do + let(:caveats) do + <<~CAVEATS + caveats 'This is a one-line caveat.' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ stanza groups should be separated by a single empty line + CAVEATS end - context "when caveats is a heredoc" do - let(:caveats) do - <<~CAVEATS + include_examples "caveats" + end + + context "when `caveats` is a heredoc" do + let(:caveats) do + <<~CAVEATS caveats <<~EOS - This is a multiline caveat. + ^^^^^^^^^^^^^^^^ stanza groups should be separated by a single empty line + This is a multiline caveat. - Let's hope it doesn't cause any problems! - EOS - CAVEATS - end - - include_examples "autocorrects source" + Let's hope it doesn't cause any problems! + EOS + CAVEATS end - context "when caveats is a block" do - let(:caveats) do - <<~CAVEATS + include_examples "caveats" + end + + context "when `caveats` is a block" do + let(:caveats) do + <<~CAVEATS caveats do - puts 'This is a multiline caveat.' + ^^^^^^^^^^^^ stanza groups should be separated by a single empty line + puts 'This is a multiline caveat.' - puts "Let's hope it doesn't cause any problems!" - end - CAVEATS - end - - include_examples "autocorrects source" + puts "Let's hope it doesn't cause any problems!" + end + CAVEATS end + + include_examples "caveats" end - context "when the postflight stanza is incorrectly grouped" do - let(:source) do - <<~CASK - cask 'foo' do - version :latest - sha256 :no_check - url 'https://foo.brew.sh/foo.zip' - name 'Foo' - app 'Foo.app' - postflight do - puts 'We have liftoff!' - end + it "reports an offense for an incorrectly grouped `postflight` stanza" do + expect_offense <<~CASK + cask 'foo' do + version :latest + sha256 :no_check + url 'https://foo.brew.sh/foo.zip' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ stanza groups should be separated by a single empty line + name 'Foo' + app 'Foo.app' + ^^^^^^^^^^^^^^^ stanza groups should be separated by a single empty line + postflight do + ^^^^^^^^^^^^^^^ stanza groups should be separated by a single empty line + puts 'We have liftoff!' end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - version :latest - sha256 :no_check + end + CASK - url 'https://foo.brew.sh/foo.zip' - name 'Foo' + expect_correction <<~CASK + cask 'foo' do + version :latest + sha256 :no_check - app 'Foo.app' + url 'https://foo.brew.sh/foo.zip' + name 'Foo' - postflight do - puts 'We have liftoff!' - end + app 'Foo.app' + + postflight do + puts 'We have liftoff!' end - CASK - end - - include_examples "autocorrects source" + end + CASK end - context "when a stanza has a comment" do - let(:source) do - <<~CASK - cask 'foo' do - version :latest - sha256 :no_check - # comment with an empty line between + it "reports an offense for incorrectly grouped comments" do + expect_offense <<~CASK + cask 'foo' do + version :latest + sha256 :no_check + # comment with an empty line between + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ stanza groups should be separated by a single empty line - # comment directly above - postflight do - puts 'We have liftoff!' - end - url 'https://foo.brew.sh/foo.zip' - name 'Foo' - app 'Foo.app' + # comment directly above + postflight do + puts 'We have liftoff!' end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - version :latest - sha256 :no_check + url 'https://foo.brew.sh/foo.zip' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ stanza groups should be separated by a single empty line + name 'Foo' + app 'Foo.app' + ^^^^^^^^^^^^^^^ stanza groups should be separated by a single empty line + end + CASK - # comment with an empty line between + expect_correction <<~CASK + cask 'foo' do + version :latest + sha256 :no_check - # comment directly above - postflight do - puts 'We have liftoff!' - end + # comment with an empty line between - url 'https://foo.brew.sh/foo.zip' - name 'Foo' - - app 'Foo.app' + # comment directly above + postflight do + puts 'We have liftoff!' end - CASK - end - include_examples "autocorrects source" + url 'https://foo.brew.sh/foo.zip' + name 'Foo' + + app 'Foo.app' + end + CASK end - context "when a stanza has a comment and there is a variable assignment" do - let(:source) do - <<~CASK - cask 'foo' do - arch arm: "arm64", intel: "x86_64" - folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" - # comment with an empty line between - version :latest - sha256 :no_check + it "reports an offense for incorrectly grouped comments and variable assignments" do + expect_offense <<~CASK + cask 'foo' do + arch arm: "arm64", intel: "x86_64" + folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" + # comment with an empty line between + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ stanza groups should be separated by a single empty line + version :latest + sha256 :no_check - # comment directly above - postflight do - puts 'We have liftoff!' - end - url 'https://foo.brew.sh/foo.zip' - name 'Foo' - app 'Foo.app' + # comment directly above + postflight do + puts 'We have liftoff!' end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - arch arm: "arm64", intel: "x86_64" - folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" + url 'https://foo.brew.sh/foo.zip' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ stanza groups should be separated by a single empty line + name 'Foo' + app 'Foo.app' + ^^^^^^^^^^^^^^^ stanza groups should be separated by a single empty line + end + CASK - # comment with an empty line between - version :latest - sha256 :no_check + expect_correction <<~CASK + cask 'foo' do + arch arm: "arm64", intel: "x86_64" + folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" - # comment directly above - postflight do - puts 'We have liftoff!' - end + # comment with an empty line between + version :latest + sha256 :no_check - url 'https://foo.brew.sh/foo.zip' - name 'Foo' - - app 'Foo.app' + # comment directly above + postflight do + puts 'We have liftoff!' end - CASK - end - include_examples "autocorrects source" + url 'https://foo.brew.sh/foo.zip' + name 'Foo' + + app 'Foo.app' + end + CASK end - context "when stanzas are nested one-level in `on_*` blocks" do - describe "basic nesting" do - let(:source) do - <<~CASK - cask 'foo' do - on_arm do - version "1.0.2" + it "reports an offense for incorrectly grouped stanzas in `on_*` blocks" do + expect_offense <<~CASK + cask 'foo' do + on_arm do + version "1.0.2" - sha256 :no_check - end - on_intel do - version "0.9.8" - sha256 :no_check - url "https://foo.brew.sh/foo-intel.zip" - end - end - CASK + ^{} stanzas within the same group should have no lines between them + sha256 :no_check + end + on_intel do + version "0.9.8" + sha256 :no_check + url "https://foo.brew.sh/foo-intel.zip" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ stanza groups should be separated by a single empty line + end end + CASK - let(:correct_source) do - <<~CASK - cask 'foo' do - on_arm do - version "1.0.2" - sha256 :no_check - end - on_intel do - version "0.9.8" - sha256 :no_check + expect_correction <<~CASK + cask 'foo' do + on_arm do + version "1.0.2" + sha256 :no_check + end + on_intel do + version "0.9.8" + sha256 :no_check - url "https://foo.brew.sh/foo-intel.zip" - end - end - CASK + url "https://foo.brew.sh/foo-intel.zip" + end end + CASK + end - include_examples "autocorrects source" - end + it "reports an offense for incorrectly grouped stanzas with comments in `on_*` blocks" do + expect_offense <<~CASK + cask 'foo' do + on_arm do + version "1.0.2" - describe "nested `on_*` blocks with comments" do - let(:source) do - <<~CASK - cask 'foo' do - on_arm do - version "1.0.2" - - sha256 :no_check # comment on same line - end - on_intel do - version "0.9.8" - sha256 :no_check - end - end - CASK + ^{} stanzas within the same group should have no lines between them + sha256 :no_check # comment on same line + end + on_intel do + version "0.9.8" + sha256 :no_check + end end + CASK - let(:correct_source) do - <<~CASK - cask 'foo' do - on_arm do - version "1.0.2" - sha256 :no_check # comment on same line - end - on_intel do - version "0.9.8" - sha256 :no_check - end - end - CASK + expect_correction <<~CASK + cask 'foo' do + on_arm do + version "1.0.2" + sha256 :no_check # comment on same line + end + on_intel do + version "0.9.8" + sha256 :no_check + end end - - include_examples "autocorrects source" - end + CASK end end diff --git a/Library/Homebrew/test/rubocops/cask/stanza_order_spec.rb b/Library/Homebrew/test/rubocops/cask/stanza_order_spec.rb index 9075f1f6a2..3c497675e5 100644 --- a/Library/Homebrew/test/rubocops/cask/stanza_order_spec.rb +++ b/Library/Homebrew/test/rubocops/cask/stanza_order_spec.rb @@ -1,501 +1,385 @@ # frozen_string_literal: true require "rubocops/rubocop-cask" -require "test/rubocops/cask/shared_examples/cask_cop" describe RuboCop::Cop::Cask::StanzaOrder, :config do - include CaskCop - - context "when there is only one stanza" do - let(:source) do - <<~CASK - cask 'foo' do - version :latest - end - CASK - end - - include_examples "does not report any offenses" - end - - context "when no stanzas are out of order" do - let(:source) do - <<~CASK - cask 'foo' do - arch arm: "arm", intel: "x86_64" - folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" - version :latest - sha256 :no_check - foo = "bar" - end - CASK - end - - include_examples "does not report any offenses" - end - - context "when one pair of stanzas is out of order" do - let(:source) do - <<~CASK - cask 'foo' do - sha256 :no_check - version :latest - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - version :latest - sha256 :no_check - end - CASK - end - let(:expected_offenses) do - [{ - message: "`sha256` stanza out of order", - severity: :convention, - line: 2, - column: 2, - source: "sha256 :no_check", - }, { - message: "`version` stanza out of order", - severity: :convention, - line: 3, - column: 2, - source: "version :latest", - }] - end - - include_examples "reports offenses" - - include_examples "autocorrects source" - end - - context "when the arch stanza is out of order" do - let(:source) do - <<~CASK - cask 'foo' do - version :latest - sha256 :no_check - arch arm: "arm", intel: "x86_64" - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - arch arm: "arm", intel: "x86_64" - version :latest - sha256 :no_check - end - CASK - end - let(:expected_offenses) do - [{ - message: "`version` stanza out of order", - severity: :convention, - line: 2, - column: 2, - source: "version :latest", - }, { - message: "`sha256` stanza out of order", - severity: :convention, - line: 3, - column: 2, - source: "sha256 :no_check", - }, { - message: "`arch` stanza out of order", - severity: :convention, - line: 4, - column: 2, - source: 'arch arm: "arm", intel: "x86_64"', - }] - end - - include_examples "reports offenses" - - include_examples "autocorrects source" - end - - context "when an arch variable assignment is out of order" do - let(:source) do - <<~CASK - cask 'foo' do - arch arm: "arm", intel: "x86_64" - sha256 :no_check - version :latest - folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - arch arm: "arm", intel: "x86_64" - folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" - version :latest - sha256 :no_check - end - CASK - end - let(:expected_offenses) do - [{ - message: "`sha256` stanza out of order", - severity: :convention, - line: 3, - column: 2, - source: "sha256 :no_check", - }, { - message: "`on_arch_conditional` stanza out of order", - severity: :convention, - line: 5, - column: 2, - source: 'folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin"', - }] - end - - include_examples "reports offenses" - - include_examples "autocorrects source" - end - - context "when an arch variable assignment is above the arch stanza" do - let(:source) do - <<~CASK - cask 'foo' do - folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" - arch arm: "arm", intel: "x86_64" - version :latest - sha256 :no_check - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - arch arm: "arm", intel: "x86_64" - folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" - version :latest - sha256 :no_check - end - CASK - end - let(:expected_offenses) do - [{ - message: "`on_arch_conditional` stanza out of order", - severity: :convention, - line: 2, - column: 2, - source: 'folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin"', - }, { - message: "`arch` stanza out of order", - severity: :convention, - line: 3, - column: 2, - source: 'arch arm: "arm", intel: "x86_64"', - }] - end - - include_examples "reports offenses" - - include_examples "autocorrects source" - end - - context "when many stanzas are out of order" do - let(:source) do - <<~CASK - cask 'foo' do - url 'https://foo.brew.sh/foo.zip' - uninstall :quit => 'com.example.foo', - :kext => 'com.example.foo.kext' - version :latest - app 'Foo.app' - sha256 :no_check - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - version :latest - sha256 :no_check - url 'https://foo.brew.sh/foo.zip' - app 'Foo.app' - uninstall :quit => 'com.example.foo', - :kext => 'com.example.foo.kext' - end - CASK - end - let(:expected_offenses) do - [{ - message: "`url` stanza out of order", - severity: :convention, - line: 2, - column: 2, - source: "url 'https://foo.brew.sh/foo.zip'", - }, { - message: "`uninstall` stanza out of order", - severity: :convention, - line: 3, - column: 2, - source: "uninstall :quit => 'com.example.foo'," \ - "\n :kext => 'com.example.foo.kext'", - }, { - message: "`version` stanza out of order", - severity: :convention, - line: 5, - column: 2, - source: "version :latest", - }, { - message: "`sha256` stanza out of order", - severity: :convention, - line: 7, - column: 2, - source: "sha256 :no_check", - }] - end - - include_examples "reports offenses" - - include_examples "autocorrects source" - end - - context "when a stanza appears multiple times" do - let(:source) do - <<~CASK - cask 'foo' do - name 'Foo' - url 'https://foo.brew.sh/foo.zip' - name 'FancyFoo' - version :latest - app 'Foo.app' - sha256 :no_check - name 'FunkyFoo' - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - version :latest - sha256 :no_check - url 'https://foo.brew.sh/foo.zip' - name 'Foo' - name 'FancyFoo' - name 'FunkyFoo' - app 'Foo.app' - end - CASK - end - - it "preserves the original order" do - expect_autocorrected_source(source, correct_source) - end - end - - context "when a stanza has a comment" do - let(:source) do - <<~CASK - cask 'foo' do - version :latest - # comment with an empty line between - - # comment directly above - postflight do - puts 'We have liftoff!' - end - sha256 :no_check # comment on same line - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - version :latest - sha256 :no_check # comment on same line - # comment with an empty line between - - # comment directly above - postflight do - puts 'We have liftoff!' - end - end - CASK - end - - include_examples "autocorrects source" - end - - context "when a variable assignment is out of order with a comment" do - let(:source) do - <<~CASK - cask 'foo' do - version :latest - sha256 :no_check - # comment with an empty line between - - # comment directly above - postflight do - puts 'We have liftoff!' - end - folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" # comment on same line - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" # comment on same line - version :latest - sha256 :no_check - # comment with an empty line between - - # comment directly above - postflight do - puts 'We have liftoff!' - end - end - CASK - end - - include_examples "autocorrects source" - end - - context "when the caveats stanza is out of order" do - let(:source) do - format(<<~CASK, caveats: caveats.strip) - cask 'foo' do - name 'Foo' - url 'https://foo.brew.sh/foo.zip' - %s - version :latest - app 'Foo.app' - sha256 :no_check - end - CASK - end - let(:correct_source) do - format(<<~CASK, caveats: caveats.strip) - cask 'foo' do - version :latest - sha256 :no_check - url 'https://foo.brew.sh/foo.zip' - name 'Foo' - app 'Foo.app' - %s - end - CASK - end - - context "when caveats is a one-line string" do - let(:caveats) { "caveats 'This is a one-line caveat.'" } - - include_examples "autocorrects source" - end - - context "when caveats is a heredoc" do - let(:caveats) do - <<~CAVEATS - caveats <<~EOS - This is a multiline caveat. - - Let's hope it doesn't cause any problems! - EOS - CAVEATS + it "accepts a sole stanza" do + expect_no_offenses <<~CASK + cask 'foo' do + version :latest end + CASK + end - include_examples "autocorrects source" - end - - context "when caveats is a block" do - let(:caveats) do - <<~CAVEATS - caveats do - puts 'This is a multiline caveat.' - - puts "Let's hope it doesn't cause any problems!" - end - CAVEATS + it "accepts when all stanzas are in order" do + expect_no_offenses <<~CASK + cask 'foo' do + arch arm: "arm", intel: "x86_64" + folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" + version :latest + sha256 :no_check + foo = "bar" end - - include_examples "autocorrects source" - end + CASK end - context "when the postflight stanza is out of order" do - let(:source) do - <<~CASK + it "reports an offense when stanzas are out of order" do + expect_offense <<~CASK + cask 'foo' do + sha256 :no_check + ^^^^^^^^^^^^^^^^ `sha256` stanza out of order + version :latest + ^^^^^^^^^^^^^^^ `version` stanza out of order + end + CASK + + expect_correction <<~CASK + cask 'foo' do + version :latest + sha256 :no_check + end + CASK + end + + it "reports an offense when an `arch` stanza is out of order" do + expect_offense <<~CASK + cask 'foo' do + version :latest + ^^^^^^^^^^^^^^^ `version` stanza out of order + sha256 :no_check + ^^^^^^^^^^^^^^^^ `sha256` stanza out of order + arch arm: "arm", intel: "x86_64" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `arch` stanza out of order + end + CASK + + expect_correction <<~CASK + cask 'foo' do + arch arm: "arm", intel: "x86_64" + version :latest + sha256 :no_check + end + CASK + end + + it "reports an offense when an `on_arch_conditional` variable assignment is out of order" do + expect_offense <<~CASK + cask 'foo' do + arch arm: "arm", intel: "x86_64" + sha256 :no_check + ^^^^^^^^^^^^^^^^ `sha256` stanza out of order + version :latest + folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `on_arch_conditional` stanza out of order + end + CASK + + expect_correction <<~CASK + cask 'foo' do + arch arm: "arm", intel: "x86_64" + folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" + version :latest + sha256 :no_check + end + CASK + end + + it "reports an offense when an `on_arch_conditional` variable assignment is above an `arch` stanza" do + expect_offense <<~CASK + cask 'foo' do + folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `on_arch_conditional` stanza out of order + arch arm: "arm", intel: "x86_64" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `arch` stanza out of order + version :latest + sha256 :no_check + end + CASK + + expect_correction <<~CASK + cask 'foo' do + arch arm: "arm", intel: "x86_64" + folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" + version :latest + sha256 :no_check + end + CASK + end + + it "reports an offense when multiple stanzas are out of order" do + expect_offense <<~CASK + cask 'foo' do + url 'https://foo.brew.sh/foo.zip' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `url` stanza out of order + uninstall :quit => 'com.example.foo', + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `uninstall` stanza out of order + :kext => 'com.example.foo.kext' + version :latest + ^^^^^^^^^^^^^^^ `version` stanza out of order + app 'Foo.app' + sha256 :no_check + ^^^^^^^^^^^^^^^^ `sha256` stanza out of order + end + CASK + + expect_correction <<~CASK + cask 'foo' do + version :latest + sha256 :no_check + url 'https://foo.brew.sh/foo.zip' + app 'Foo.app' + uninstall :quit => 'com.example.foo', + :kext => 'com.example.foo.kext' + end + CASK + end + + it "does not reorder multiple stanzas of the same type" do + expect_offense <<~CASK + cask 'foo' do + name 'Foo' + ^^^^^^^^^^ `name` stanza out of order + url 'https://foo.brew.sh/foo.zip' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `url` stanza out of order + name 'FancyFoo' + ^^^^^^^^^^^^^^^ `name` stanza out of order + version :latest + ^^^^^^^^^^^^^^^ `version` stanza out of order + app 'Foo.app' + ^^^^^^^^^^^^^ `app` stanza out of order + sha256 :no_check + ^^^^^^^^^^^^^^^^ `sha256` stanza out of order + name 'FunkyFoo' + ^^^^^^^^^^^^^^^ `name` stanza out of order + end + CASK + + expect_correction <<~CASK + cask 'foo' do + version :latest + sha256 :no_check + url 'https://foo.brew.sh/foo.zip' + name 'Foo' + name 'FancyFoo' + name 'FunkyFoo' + app 'Foo.app' + end + CASK + end + + it "keeps associated comments when auto-correcting" do + expect_offense <<~CASK + cask 'foo' do + version :latest + # comment with an empty line between + + # comment directly above + postflight do + ^^^^^^^^^^^^^ `postflight` stanza out of order + puts 'We have liftoff!' + end + sha256 :no_check # comment on same line + ^^^^^^^^^^^^^^^^ `sha256` stanza out of order + end + CASK + + expect_correction <<~CASK, loop: false + cask 'foo' do + version :latest + sha256 :no_check # comment on same line + # comment with an empty line between + + # comment directly above + postflight do + puts 'We have liftoff!' + end + end + CASK + end + + it "reports an offense when an `on_arch_conditional` variable assignment with a comment is out of order" do + expect_offense <<~CASK + cask 'foo' do + version :latest + ^^^^^^^^^^^^^^^ `version` stanza out of order + sha256 :no_check + ^^^^^^^^^^^^^^^^ `sha256` stanza out of order + # comment with an empty line between + + # comment directly above + postflight do + ^^^^^^^^^^^^^ `postflight` stanza out of order + puts 'We have liftoff!' + end + folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" # comment on same line + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `on_arch_conditional` stanza out of order + end + CASK + + expect_correction <<~CASK + cask 'foo' do + folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" # comment on same line + version :latest + sha256 :no_check + # comment with an empty line between + + # comment directly above + postflight do + puts 'We have liftoff!' + end + end + CASK + end + + shared_examples "caveats" do + it "reports an offense when a `caveats` stanza is out of order" do + # Indent all except the first line. + interpolated_caveats = caveats.lines.map { |l| " #{l}" }.join.strip + + expect_offense <<~CASK cask 'foo' do name 'Foo' + ^^^^^^^^^^ `name` stanza out of order url 'https://foo.brew.sh/foo.zip' - postflight do - puts 'We have liftoff!' - end + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `url` stanza out of order + #{interpolated_caveats} version :latest + ^^^^^^^^^^^^^^^ `version` stanza out of order app 'Foo.app' sha256 :no_check + ^^^^^^^^^^^^^^^^ `sha256` stanza out of order end CASK - end - let(:correct_source) do - <<~CASK + + # Remove offense annotations. + corrected_caveats = interpolated_caveats.gsub(/\n\s*\^+\s+.*$/, "") + + expect_correction <<~CASK cask 'foo' do version :latest sha256 :no_check url 'https://foo.brew.sh/foo.zip' name 'Foo' app 'Foo.app' - postflight do - puts 'We have liftoff!' - end + #{corrected_caveats} end CASK end - - include_examples "autocorrects source" end - context "when `on_arch` blocks and their contents are out of order" do - let(:source) do - <<~CASK - cask 'foo' do - on_intel do - url "https://foo.brew.sh/foo-intel.zip" - - version :latest - sha256 :no_check - end - on_arm do - version :latest - sha256 :no_check - - url "https://foo.brew.sh/foo-arm.zip" - end - end - CASK + context "when caveats is a one-line string" do + let(:caveats) do + <<~CAVEATS + caveats 'This is a one-line caveat.' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `caveats` stanza out of order + CAVEATS end - let(:correct_source) do - <<~CASK - cask 'foo' do - on_arm do - version :latest - sha256 :no_check + include_examples "caveats" + end - url "https://foo.brew.sh/foo-arm.zip" - end - on_intel do - version :latest + context "when caveats is a heredoc" do + let(:caveats) do + <<~CAVEATS + caveats <<~EOS + ^^^^^^^^^^^^^^ `caveats` stanza out of order + This is a multiline caveat. - sha256 :no_check - url "https://foo.brew.sh/foo-intel.zip" - end - end - CASK + Let's hope it doesn't cause any problems! + EOS + CAVEATS end - include_examples "autocorrects source" + include_examples "caveats" + end + + context "when caveats is a block" do + let(:caveats) do + <<~CAVEATS + caveats do + ^^^^^^^^^^ `caveats` stanza out of order + puts 'This is a multiline caveat.' + + puts "Let's hope it doesn't cause any problems!" + end + CAVEATS + end + + include_examples "caveats" + end + + it "reports an offense when the `postflight` stanza is out of order" do + expect_offense <<~CASK + cask 'foo' do + name 'Foo' + ^^^^^^^^^^ `name` stanza out of order + url 'https://foo.brew.sh/foo.zip' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `url` stanza out of order + postflight do + ^^^^^^^^^^^^^ `postflight` stanza out of order + puts 'We have liftoff!' + end + version :latest + ^^^^^^^^^^^^^^^ `version` stanza out of order + app 'Foo.app' + sha256 :no_check + ^^^^^^^^^^^^^^^^ `sha256` stanza out of order + end + CASK + + expect_correction <<~CASK + cask 'foo' do + version :latest + sha256 :no_check + url 'https://foo.brew.sh/foo.zip' + name 'Foo' + app 'Foo.app' + postflight do + puts 'We have liftoff!' + end + end + CASK + end + + it "supports `on_arch` blocks and their contents" do + expect_offense <<~CASK + cask 'foo' do + on_intel do + ^^^^^^^^^^^ `on_intel` stanza out of order + url "https://foo.brew.sh/foo-intel.zip" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `url` stanza out of order + + version :latest + ^^^^^^^^^^^^^^^ `version` stanza out of order + sha256 :no_check + ^^^^^^^^^^^^^^^^ `sha256` stanza out of order + end + on_arm do + ^^^^^^^^^ `on_arm` stanza out of order + version :latest + sha256 :no_check + + url "https://foo.brew.sh/foo-arm.zip" + end + end + CASK + + expect_correction <<~CASK + cask 'foo' do + on_arm do + version :latest + sha256 :no_check + + url "https://foo.brew.sh/foo-arm.zip" + end + on_intel do + version :latest + + sha256 :no_check + url "https://foo.brew.sh/foo-intel.zip" + end + end + CASK end it "registers an offense when `on_os` stanzas and their contents are out of order" do diff --git a/Library/Homebrew/test/rubocops/cask/url_legacy_comma_separators_spec.rb b/Library/Homebrew/test/rubocops/cask/url_legacy_comma_separators_spec.rb index 6c8f155d75..5b9489f48c 100644 --- a/Library/Homebrew/test/rubocops/cask/url_legacy_comma_separators_spec.rb +++ b/Library/Homebrew/test/rubocops/cask/url_legacy_comma_separators_spec.rb @@ -1,102 +1,57 @@ # frozen_string_literal: true require "rubocops/rubocop-cask" -require "test/rubocops/cask/shared_examples/cask_cop" -describe RuboCop::Cop::Cask::UrlLegacyCommaSeparators do - include CaskCop - - subject(:cop) { described_class.new } - - context "when url version interpolation does not include version.before_comma or version.after_comma" do - let(:source) do - <<~CASK - cask 'foo' do - version '1.1' - url 'https://foo.brew.sh/foo-\#{version}.dmg' - end - CASK - end - - include_examples "does not report any offenses" +describe RuboCop::Cop::Cask::UrlLegacyCommaSeparators, :config do + it "accepts a simple `version` interpolation" do + expect_no_offenses <<~'CASK' + cask 'foo' do + version '1.1' + url 'https://foo.brew.sh/foo-#{version}.dmg' + end + CASK end - context "when the url uses csv" do - let(:source) do - <<~CASK - cask 'foo' do - version '1.1,111' - url 'https://foo.brew.sh/foo-\#{version.csv.first}.dmg' - end - CASK - end - - include_examples "does not report any offenses" + it "accepts an interpolation using `version.csv`" do + expect_no_offenses <<~'CASK' + cask 'foo' do + version '1.1,111' + url 'https://foo.brew.sh/foo-#{version.csv.first}.dmg' + end + CASK end - context "when the url uses version.before_comma" do - let(:source) do - <<~CASK - cask 'foo' do - version '1.1,111' - url 'https://foo.brew.sh/foo-\#{version.before_comma}.dmg' - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - version '1.1,111' - url 'https://foo.brew.sh/foo-\#{version.csv.first}.dmg' - end - CASK - end - let(:expected_offenses) do - [{ - message: "Cask/UrlLegacyCommaSeparators: Use 'version.csv.first' instead of 'version.before_comma' " \ - "and 'version.csv.second' instead of 'version.after_comma'", - severity: :convention, - line: 3, - column: 6, - source: "'https://foo.brew.sh/foo-\#{version.before_comma}.dmg'", - }] - end + it "reports an offense for an interpolation using `version.before_comma`" do + expect_offense <<~'CASK' + cask 'foo' do + version '1.1,111' + url 'https://foo.brew.sh/foo-#{version.before_comma}.dmg' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `version.csv.first` instead of `version.before_comma` and `version.csv.second` instead of `version.after_comma`. + end + CASK - include_examples "reports offenses" - - include_examples "autocorrects source" + expect_correction <<~'CASK' + cask 'foo' do + version '1.1,111' + url 'https://foo.brew.sh/foo-#{version.csv.first}.dmg' + end + CASK end - context "when the url uses version.after_comma" do - let(:source) do - <<~CASK - cask 'foo' do - version '1.1,111' - url 'https://foo.brew.sh/foo-\#{version.after_comma}.dmg' - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - version '1.1,111' - url 'https://foo.brew.sh/foo-\#{version.csv.second}.dmg' - end - CASK - end - let(:expected_offenses) do - [{ - message: "Cask/UrlLegacyCommaSeparators: Use 'version.csv.first' instead of 'version.before_comma' " \ - "and 'version.csv.second' instead of 'version.after_comma'", - severity: :convention, - line: 3, - column: 6, - source: "'https://foo.brew.sh/foo-\#{version.after_comma}.dmg'", - }] - end + it "reports an offense for an interpolation using `version.after_comma`" do + expect_offense <<~'CASK' + cask 'foo' do + version '1.1,111' + url 'https://foo.brew.sh/foo-#{version.after_comma}.dmg' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `version.csv.first` instead of `version.before_comma` and `version.csv.second` instead of `version.after_comma`. + end + CASK - include_examples "reports offenses" - - include_examples "autocorrects source" + expect_correction <<~'CASK' + cask 'foo' do + version '1.1,111' + url 'https://foo.brew.sh/foo-#{version.csv.second}.dmg' + end + CASK end end diff --git a/Library/Homebrew/test/rubocops/cask/url_spec.rb b/Library/Homebrew/test/rubocops/cask/url_spec.rb index 80e716ae4d..a541434382 100644 --- a/Library/Homebrew/test/rubocops/cask/url_spec.rb +++ b/Library/Homebrew/test/rubocops/cask/url_spec.rb @@ -1,138 +1,85 @@ # frozen_string_literal: true require "rubocops/rubocop-cask" -require "test/rubocops/cask/shared_examples/cask_cop" -describe RuboCop::Cop::Cask::Url do - include CaskCop +describe RuboCop::Cop::Cask::Url, :config do + it "accepts a `verified` value that does not start with a protocol" do + expect_no_offenses <<~CASK + cask "foo" do + url "https://example.com/download/foo-v1.2.0.dmg", + verified: "example.com/download/" + end + CASK + end - subject(:cop) { described_class.new } + it "reports an offense for a `verified` value that starts with a protocol" do + expect_offense <<~CASK + cask "foo" do + url "https://example.com/download/foo-v1.2.0.dmg", + verified: "https://example.com/download/" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Verified URL parameter value should not contain a URL scheme. + end + CASK - context "when url 'verified' value does not start with a protocol" do - let(:source) do - <<~CASK + expect_correction <<~CASK + cask "foo" do + url "https://example.com/download/foo-v1.2.0.dmg", + verified: "example.com/download/" + end + CASK + end + + context "when then URL does not have a path and ends with a /" do + it "accepts a `verified` value ending with a /" do + expect_no_offenses <<~CASK cask "foo" do - url "https://example.com/download/foo-v1.2.0.dmg", - verified: "example.com/download/" + url "https://example.org/", + verified: "example.org/" end CASK end - include_examples "does not report any offenses" + it "reports an offense for a `verified` value not ending a /" do + expect_offense <<~CASK + cask "foo" do + url "https://example.org/", + verified: "example.org" + ^^^^^^^^^^^^^ Verified URL parameter value should end with a /. + end + CASK + + expect_correction <<~CASK + cask "foo" do + url "https://example.org/", + verified: "example.org/" + end + CASK + end end - context "when url 'verified' value starts with a protocol" do - let(:source) do - <<~CASK + context "when the URL has a path and does not end with a /" do + it "accepts a `verified` value with one path component" do + expect_no_offenses <<~CASK cask "foo" do - url "https://example.com/download/foo-v1.2.0.dmg", - verified: "https://example.com/download/" + url "https://github.com/Foo", + verified: "github.com/Foo" end CASK end - let(:expected_offenses) do - [{ - message: "Cask/Url: Verified URL parameter value should not contain a URL scheme.", - severity: :convention, - line: 3, - column: 16, - source: "\"https://example.com/download/\"", - }] - end - - let(:correct_source) do - <<~CASK + it "accepts a `verified` value with two path components" do + expect_no_offenses <<~CASK cask "foo" do - url "https://example.com/download/foo-v1.2.0.dmg", - verified: "example.com/download/" + url "https://github.com/foo/foo.git", + verified: "github.com/foo/foo" end CASK end - - include_examples "reports offenses" - include_examples "autocorrects source" end - context "when url 'verified' value does not have a path component" do - context "when the URL ends with a slash" do - let(:source) do - <<~CASK - cask "foo" do - url "https://example.org/", - verified: "example.org/" - end - CASK - end - - include_examples "does not report any offenses" - end - - context "when the URL does not end with a slash" do - let(:source) do - <<~CASK - cask "foo" do - url "https://example.org/", - verified: "example.org" - end - CASK - end - - let(:expected_offenses) do - [{ - message: "Cask/Url: Verified URL parameter value should end with a /.", - severity: :convention, - line: 3, - column: 16, - source: "\"example.org\"", - }] - end - - let(:correct_source) do - <<~CASK - cask "foo" do - url "https://example.org/", - verified: "example.org/" - end - CASK - end - - include_examples "reports offenses" - include_examples "autocorrects source" - end - end - - context "when the URL does not end with a slash" do - describe "and it has one path component" do - let(:source) do - <<~CASK - cask "foo" do - url "https://github.com/Foo", - verified: "github.com/Foo" - end - CASK - end - - include_examples "does not report any offenses" - end - - describe "and it has two path components" do - let(:source) do - <<~CASK - cask "foo" do - url "https://github.com/foo/foo.git", - verified: "github.com/foo/foo" - end - CASK - end - - include_examples "does not report any offenses" - end - end - - context "when the url ends with a / and the verified value does too" do - let(:source) do - <<~CASK + context "when the url ends with a /" do + it "accepts a `verified` value ending with a /" do + expect_no_offenses <<~CASK cask "foo" do url "https://github.com/", verified: "github.com/" @@ -140,58 +87,36 @@ describe RuboCop::Cop::Cask::Url do CASK end - include_examples "does not report any offenses" - end - - context "when the url ends with a / and the verified value does not" do - let(:source) do - <<~CASK + it "reports an offense for a `verified` value not ending with a /" do + expect_offense <<~CASK cask "foo" do url "https://github.com/", verified: "github.com" + ^^^^^^^^^^^^ Verified URL parameter value should end with a /. end CASK - end - let(:expected_offenses) do - [{ - message: "Cask/Url: Verified URL parameter value should end with a /.", - severity: :convention, - line: 3, - column: 16, - source: "\"github.com\"", - }] - end - - let(:correct_source) do - <<~CASK + expect_correction <<~CASK cask "foo" do url "https://github.com/", verified: "github.com/" end CASK end - - include_examples "reports offenses" - include_examples "autocorrects source" end - context "when url 'verified' value has a path component that ends with a /" do - let(:source) do - <<~CASK - cask "foo" do - url "https://github.com/Foo/foo/releases/download/v1.2.0/foo-v1.2.0.dmg", - verified: "github.com/Foo/foo/" - end - CASK - end - - include_examples "does not report any offenses" + it "accepts a `verified` value with a path ending with a /" do + expect_no_offenses <<~CASK + cask "foo" do + url "https://github.com/Foo/foo/releases/download/v1.2.0/foo-v1.2.0.dmg", + verified: "github.com/Foo/foo/" + end + CASK end - context "when the url has interpolation in it and the verified url ends with a /" do - let(:source) do - <<~CASK + context "when the URL uses interpolation" do + it "accepts a `verified` value with a path ending with a /" do + expect_no_offenses <<~CASK cask "foo" do version "1.2.3" url "Cask/Url: https://example.com/download/foo-v\#{version}.dmg", @@ -199,40 +124,22 @@ describe RuboCop::Cop::Cask::Url do end CASK end - - include_examples "does not report any offenses" end - context "when the url 'verified' value has a path component that doesn't end with a /" do - let(:source) do - <<~CASK - cask "foo" do - url "https://github.com/Foo/foo/releases/download/v1.2.0/foo-v1.2.0.dmg", - verified: "github.com/Foo/foo" - end - CASK - end + it "reports an offense for a `verified` value with a path component that doesn't end with a /" do + expect_offense <<~CASK + cask "foo" do + url "https://github.com/Foo/foo/releases/download/v1.2.0/foo-v1.2.0.dmg", + verified: "github.com/Foo/foo" + ^^^^^^^^^^^^^^^^^^^^ Verified URL parameter value should end with a /. + end + CASK - let(:expected_offenses) do - [{ - message: "Cask/Url: Verified URL parameter value should end with a /.", - severity: :convention, - line: 3, - column: 16, - source: "\"github.com/Foo/foo\"", - }] - end - - let(:correct_source) do - <<~CASK - cask "foo" do - url "https://github.com/Foo/foo/releases/download/v1.2.0/foo-v1.2.0.dmg", - verified: "github.com/Foo/foo/" - end - CASK - end - - include_examples "reports offenses" - include_examples "autocorrects source" + expect_correction <<~CASK + cask "foo" do + url "https://github.com/Foo/foo/releases/download/v1.2.0/foo-v1.2.0.dmg", + verified: "github.com/Foo/foo/" + end + CASK end end diff --git a/Library/Homebrew/test/rubocops/cask/variables_spec.rb b/Library/Homebrew/test/rubocops/cask/variables_spec.rb index 6ae8895940..25229c6d6c 100644 --- a/Library/Homebrew/test/rubocops/cask/variables_spec.rb +++ b/Library/Homebrew/test/rubocops/cask/variables_spec.rb @@ -1,281 +1,140 @@ # frozen_string_literal: true require "rubocops/rubocop-cask" -require "test/rubocops/cask/shared_examples/cask_cop" -describe RuboCop::Cop::Cask::Variables do - include CaskCop - - subject(:cop) { described_class.new } - - context "when there are no variables" do - let(:source) do - <<~CASK - cask "foo" do - version :latest - end - CASK - end - - include_examples "does not report any offenses" +describe RuboCop::Cop::Cask::Variables, :config do + it "accepts when there are no variables" do + expect_no_offenses <<~CASK + cask "foo" do + version :latest + end + CASK end - context "when there is an arch stanza" do - let(:source) do - <<~CASK - cask "foo" do - arch arm: "darwin-arm64", intel: "darwin" - end - CASK - end - - include_examples "does not report any offenses" + it "accepts when there is an `arch` stanza" do + expect_no_offenses <<~CASK + cask "foo" do + arch arm: "darwin-arm64", intel: "darwin" + end + CASK end - context "when there is a non-arch variable that uses the arch conditional" do - let(:source) do - <<~CASK - cask "foo" do - folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" - end - CASK - end - - include_examples "does not report any offenses" + it "accepts an `on_arch_conditional` variable" do + expect_no_offenses <<~CASK + cask "foo" do + folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" + end + CASK end - context "when there is an arch variable" do - let(:source) do - <<~CASK - cask 'foo' do - arch = Hardware::CPU.intel? ? "darwin" : "darwin-arm64" - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - arch arm: "darwin-arm64", intel: "darwin" - end - CASK - end - let(:expected_offenses) do - [{ - message: 'Cask/Variables: Use `arch arm: "darwin-arm64", intel: "darwin"` instead of ' \ - '`arch = Hardware::CPU.intel? ? "darwin" : "darwin-arm64"`', - severity: :convention, - line: 2, - column: 2, - source: 'arch = Hardware::CPU.intel? ? "darwin" : "darwin-arm64"', - }] - end + it "reports an offense for an `arch` variable using strings" do + expect_offense <<~CASK + cask 'foo' do + arch = Hardware::CPU.intel? ? "darwin" : "darwin-arm64" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `arch arm: "darwin-arm64", intel: "darwin"` instead of `arch = Hardware::CPU.intel? ? "darwin" : "darwin-arm64"`. + end + CASK - include_examples "reports offenses" - - include_examples "autocorrects source" + expect_correction <<~CASK + cask 'foo' do + arch arm: "darwin-arm64", intel: "darwin" + end + CASK end - context "when there is an arch variable that doesn't use strings" do - let(:source) do - <<~CASK - cask 'foo' do - arch = Hardware::CPU.intel? ? :darwin : :darwin_arm64 - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - arch arm: :darwin_arm64, intel: :darwin - end - CASK - end - let(:expected_offenses) do - [{ - message: "Cask/Variables: Use `arch arm: :darwin_arm64, intel: :darwin` instead of " \ - "`arch = Hardware::CPU.intel? ? :darwin : :darwin_arm64`", - severity: :convention, - line: 2, - column: 2, - source: "arch = Hardware::CPU.intel? ? :darwin : :darwin_arm64", - }] - end + it "reports an offense for an `arch` variable using symbols" do + expect_offense <<~CASK + cask 'foo' do + arch = Hardware::CPU.intel? ? :darwin : :darwin_arm64 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `arch arm: :darwin_arm64, intel: :darwin` instead of `arch = Hardware::CPU.intel? ? :darwin : :darwin_arm64`. + end + CASK - include_examples "reports offenses" - - include_examples "autocorrects source" + expect_correction <<~CASK + cask 'foo' do + arch arm: :darwin_arm64, intel: :darwin + end + CASK end - context "when there is an arch with an empty string" do - let(:source) do - <<~CASK - cask 'foo' do - arch = Hardware::CPU.intel? ? "" : "arm64" - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - arch arm: "arm64" - end - CASK - end - let(:expected_offenses) do - [{ - message: 'Cask/Variables: Use `arch arm: "arm64"` instead of ' \ - '`arch = Hardware::CPU.intel? ? "" : "arm64"`', - severity: :convention, - line: 2, - column: 2, - source: 'arch = Hardware::CPU.intel? ? "" : "arm64"', - }] - end + it "reports an offense for an `arch` variable with an empty string" do + expect_offense <<~CASK + cask 'foo' do + arch = Hardware::CPU.intel? ? "" : "arm64" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `arch arm: "arm64"` instead of `arch = Hardware::CPU.intel? ? "" : "arm64"`. + end + CASK - include_examples "reports offenses" - - include_examples "autocorrects source" + expect_correction <<~CASK + cask 'foo' do + arch arm: "arm64" + end + CASK end - context "when there is a non-arch variable" do - let(:source) do - <<~CASK - cask 'foo' do - folder = Hardware::CPU.intel? ? "darwin" : "darwin-arm64" - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" - end - CASK - end - let(:expected_offenses) do - [{ - message: 'Cask/Variables: Use `folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin"` ' \ - 'instead of `folder = Hardware::CPU.intel? ? "darwin" : "darwin-arm64"`', - severity: :convention, - line: 2, - column: 2, - source: 'folder = Hardware::CPU.intel? ? "darwin" : "darwin-arm64"', - }] - end + it "reports an offense for a non-`arch` variable using strings" do + expect_offense <<~CASK + cask 'foo' do + folder = Hardware::CPU.intel? ? "darwin" : "darwin-arm64" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin"` instead of `folder = Hardware::CPU.intel? ? "darwin" : "darwin-arm64"`. + end + CASK - include_examples "reports offenses" - - include_examples "autocorrects source" + expect_correction <<~CASK + cask 'foo' do + folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" + end + CASK end - context "when there is a non-arch variable with an empty string" do - let(:source) do - <<~CASK - cask 'foo' do - folder = Hardware::CPU.intel? ? "amd64" : "" - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - folder = on_arch_conditional intel: "amd64" - end - CASK - end - let(:expected_offenses) do - [{ - message: 'Cask/Variables: Use `folder = on_arch_conditional intel: "amd64"` instead of ' \ - '`folder = Hardware::CPU.intel? ? "amd64" : ""`', - severity: :convention, - line: 2, - column: 2, - source: 'folder = Hardware::CPU.intel? ? "amd64" : ""', - }] - end + it "reports an offense for a non-`arch` variable with an empty string" do + expect_offense <<~CASK + cask 'foo' do + folder = Hardware::CPU.intel? ? "amd64" : "" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `folder = on_arch_conditional intel: "amd64"` instead of `folder = Hardware::CPU.intel? ? "amd64" : ""`. + end + CASK - include_examples "reports offenses" - - include_examples "autocorrects source" + expect_correction <<~CASK + cask 'foo' do + folder = on_arch_conditional intel: "amd64" + end + CASK end - context "when there is an arch and a non-arch variable" do - let(:source) do - <<~CASK - cask 'foo' do - arch = Hardware::CPU.arm? ? "darwin-arm64" : "darwin" - folder = Hardware::CPU.arm? ? "darwin-arm64" : "darwin" - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - arch arm: "darwin-arm64", intel: "darwin" - folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" - end - CASK - end - let(:expected_offenses) do - [{ - message: 'Cask/Variables: Use `arch arm: "darwin-arm64", intel: "darwin"` instead of ' \ - '`arch = Hardware::CPU.arm? ? "darwin-arm64" : "darwin"`', - severity: :convention, - line: 2, - column: 2, - source: 'arch = Hardware::CPU.arm? ? "darwin-arm64" : "darwin"', - }, { - message: 'Cask/Variables: Use `folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin"` ' \ - 'instead of `folder = Hardware::CPU.arm? ? "darwin-arm64" : "darwin"`', - severity: :convention, - line: 3, - column: 2, - source: 'folder = Hardware::CPU.arm? ? "darwin-arm64" : "darwin"', - }] - end + it "reports an offense for consecutive `arch` and non-`arch` variables" do + expect_offense <<~CASK + cask 'foo' do + arch = Hardware::CPU.arm? ? "darwin-arm64" : "darwin" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `arch arm: "darwin-arm64", intel: "darwin"` instead of `arch = Hardware::CPU.arm? ? "darwin-arm64" : "darwin"`. + folder = Hardware::CPU.arm? ? "darwin-arm64" : "darwin" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin"` instead of `folder = Hardware::CPU.arm? ? "darwin-arm64" : "darwin"`. + end + CASK - include_examples "reports offenses" - - include_examples "autocorrects source" + expect_correction <<~CASK + cask 'foo' do + arch arm: "darwin-arm64", intel: "darwin" + folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" + end + CASK end - context "when there are two non-arch variables" do - let(:source) do - <<~CASK - cask 'foo' do - folder = Hardware::CPU.arm? ? "darwin-arm64" : "darwin" - platform = Hardware::CPU.intel? ? "darwin": "darwin-arm64" - end - CASK - end - let(:correct_source) do - <<~CASK - cask 'foo' do - folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" - platform = on_arch_conditional arm: "darwin-arm64", intel: "darwin" - end - CASK - end - let(:expected_offenses) do - [{ - message: 'Cask/Variables: Use `folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin"` instead ' \ - 'of `folder = Hardware::CPU.arm? ? "darwin-arm64" : "darwin"`', - severity: :convention, - line: 2, - column: 2, - source: 'folder = Hardware::CPU.arm? ? "darwin-arm64" : "darwin"', - }, { - message: 'Cask/Variables: Use `platform = on_arch_conditional arm: "darwin-arm64", intel: "darwin"` ' \ - 'instead of `platform = Hardware::CPU.intel? ? "darwin": "darwin-arm64"`', - severity: :convention, - line: 3, - column: 2, - source: 'platform = Hardware::CPU.intel? ? "darwin": "darwin-arm64"', - }] - end + it "reports an offense for two consecutive non-`arch` variables" do + expect_offense <<~CASK + cask 'foo' do + folder = Hardware::CPU.arm? ? "darwin-arm64" : "darwin" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin"` instead of `folder = Hardware::CPU.arm? ? "darwin-arm64" : "darwin"`. + platform = Hardware::CPU.intel? ? "darwin": "darwin-arm64" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `platform = on_arch_conditional arm: "darwin-arm64", intel: "darwin"` instead of `platform = Hardware::CPU.intel? ? "darwin": "darwin-arm64"`. + end + CASK - include_examples "reports offenses" - - include_examples "autocorrects source" + expect_correction <<~CASK + cask 'foo' do + folder = on_arch_conditional arm: "darwin-arm64", intel: "darwin" + platform = on_arch_conditional arm: "darwin-arm64", intel: "darwin" + end + CASK end end