# typed: true
# frozen_string_literal: true

require "cmd/shared_examples/args_parse"
require "dev-cmd/bottle"

RSpec.describe Homebrew::DevCmd::Bottle do
  def stub_hash(parameters)
    <<~JSON
      {
        "#{parameters[:name]}":{
           "formula":{
              "pkg_version":"#{parameters[:version]}",
              "path":"#{parameters[:path]}"
           },
           "bottle":{
              "root_url":"#{parameters[:root_url] || HOMEBREW_BOTTLE_DEFAULT_DOMAIN}",
              "prefix":"/usr/local",
              "cellar":"#{parameters[:cellar]}",
              "rebuild":0,
              "tags":{
                 "#{parameters[:os]}":{
                    "filename":"#{parameters[:filename]}",
                    "local_filename":"#{parameters[:local_filename]}",
                    "sha256":"#{parameters[:sha256]}"
                    #{",\"sbom\":#{parameters[:sbom].to_json}" if parameters[:sbom]}
                 }
              }
           }
        }
      }
    JSON
  end

  it_behaves_like "parseable arguments"

  it "builds a bottle for the given Formula", :integration_test, :needs_network do
    install_test_formula "testball", build_bottle: true

    # `brew bottle` should not fail with dead symlink
    # https://github.com/Homebrew/legacy-homebrew/issues/49007
    (HOMEBREW_CELLAR/"testball/0.1").cd do
      FileUtils.ln_s "not-exist", "symlink"
    end

    begin
      expect { brew "bottle", "--no-rebuild", "testball" }
        .to output(/testball--0\.1.*\.bottle\.tar\.gz/).to_stdout
        .and not_to_output.to_stderr
        .and be_a_success
      expect(HOMEBREW_CELLAR/"testball-bottle.tar").not_to exist
    ensure
      FileUtils.rm_f Dir.glob("testball--0.1*.bottle.tar.gz")
    end
  end

  describe "--merge", :integration_test do
    let(:core_tap) { CoreTap.instance }
    let(:tarball) do
      if OS.linux?
        TEST_FIXTURE_DIR/"tarballs/testball-0.1-linux.tbz"
      else
        TEST_FIXTURE_DIR/"tarballs/testball-0.1.tbz"
      end
    end

    before do
      Pathname("#{TEST_TMPDIR}/testball-1.0.arm64_big_sur.bottle.json").write stub_hash(
        name:           "testball",
        version:        "1.0",
        path:           "#{core_tap.path}/Formula/testball.rb",
        cellar:         "any_skip_relocation",
        os:             "arm64_big_sur",
        filename:       "testball-1.0.arm64_big_sur.bottle.tar.gz",
        local_filename: "testball--1.0.arm64_big_sur.bottle.tar.gz",
        sha256:         "8f9aecd233463da6a4ea55f5f88fc5841718c013f3e2a7941350d6130f1dc149",
      )

      Pathname("#{TEST_TMPDIR}/testball-1.0.big_sur.bottle.json").write stub_hash(
        name:           "testball",
        version:        "1.0",
        path:           "#{core_tap.path}/Formula/testball.rb",
        cellar:         "any_skip_relocation",
        os:             "big_sur",
        filename:       "hello-1.0.big_sur.bottle.tar.gz",
        local_filename: "hello--1.0.big_sur.bottle.tar.gz",
        sha256:         "a0af7dcbb5c83f6f3f7ecd507c2d352c1a018f894d51ad241ce8492fa598010f",
      )

      Pathname("#{TEST_TMPDIR}/testball-1.0.catalina.bottle.json").write stub_hash(
        name:           "testball",
        version:        "1.0",
        path:           "#{core_tap.path}/Formula/testball.rb",
        cellar:         "any_skip_relocation",
        os:             "catalina",
        filename:       "testball-1.0.catalina.bottle.tar.gz",
        local_filename: "testball--1.0.catalina.bottle.tar.gz",
        sha256:         "5334dd344986e46b2aa4f0471cac7b0914bd7de7cb890a34415771788d03f2ac",
      )
    end

    after do
      FileUtils.rm_f "#{TEST_TMPDIR}/testball-1.0.arm64_big_sur.bottle.json"
      FileUtils.rm_f "#{TEST_TMPDIR}/testball-1.0.catalina.bottle.json"
      FileUtils.rm_f "#{TEST_TMPDIR}/testball-1.0.big_sur.bottle.json"
    end

    it "adds the bottle block to a formula that has none" do
      core_tap.path.cd do
        system "git", "-c", "init.defaultBranch=master", "init"
        setup_test_formula "testball"
        system "git", "add", "--all"
        system "git", "commit", "-m", "testball 0.1"
      end

      # RuboCop would align the `.and` with `.to_stdout` which is too floaty.
      # rubocop:disable Layout/MultilineMethodCallIndentation
      expect do
        brew "bottle",
             "--merge",
             "--write",
             "#{TEST_TMPDIR}/testball-1.0.arm64_big_sur.bottle.json",
             "#{TEST_TMPDIR}/testball-1.0.big_sur.bottle.json",
             "#{TEST_TMPDIR}/testball-1.0.catalina.bottle.json"
      end.to output(Regexp.new(<<~'EOS')).to_stdout
        ==> testball
          bottle do
            sha256 cellar: :any_skip_relocation, arm64_big_sur: "8f9aecd233463da6a4ea55f5f88fc5841718c013f3e2a7941350d6130f1dc149"
            sha256 cellar: :any_skip_relocation, big_sur:       "a0af7dcbb5c83f6f3f7ecd507c2d352c1a018f894d51ad241ce8492fa598010f"
            sha256 cellar: :any_skip_relocation, catalina:      "5334dd344986e46b2aa4f0471cac7b0914bd7de7cb890a34415771788d03f2ac"
          end
        \[master [0-9a-f]{4,40}\] testball: add 1\.0 bottle\.
         1 file changed, 6 insertions\(\+\)
      EOS
      .and not_to_output.to_stderr
      .and be_a_success
      # rubocop:enable Layout/MultilineMethodCallIndentation

      expect((core_tap.path/"Formula/testball.rb").read).to eq <<~RUBY
        class Testball < Formula
          desc "Some test"
          homepage "https://brew.sh/testball"
          url "file://#{tarball}"
          sha256 "#{tarball.sha256}"

          bottle do
            sha256 cellar: :any_skip_relocation, arm64_big_sur: "8f9aecd233463da6a4ea55f5f88fc5841718c013f3e2a7941350d6130f1dc149"
            sha256 cellar: :any_skip_relocation, big_sur:       "a0af7dcbb5c83f6f3f7ecd507c2d352c1a018f894d51ad241ce8492fa598010f"
            sha256 cellar: :any_skip_relocation, catalina:      "5334dd344986e46b2aa4f0471cac7b0914bd7de7cb890a34415771788d03f2ac"
          end

          option "with-foo", "Build with foo"

          def install
            (prefix/"foo"/"test").write("test") if build.with? "foo"
            prefix.install Dir["*"]
            (buildpath/"test.c").write \
            "#include <stdio.h>\\nint main(){printf(\\"test\\");return 0;}"
            bin.mkpath
            system ENV.cc, "test.c", "-o", bin/"test"
          end



          # something here

        end
      RUBY
    end

    it "replaces the bottle block in a formula that already has a bottle block" do
      core_tap.path.cd do
        system "git", "-c", "init.defaultBranch=master", "init"
        setup_test_formula "testball", bottle_block: <<~RUBY

          bottle do
            sha256 cellar: :any_skip_relocation, arm64_big_sur: "c3c650d75f5188f5d6edd351dd3215e141b73b8ec1cf9144f30e39cbc45de72e"
            sha256 cellar: :any_skip_relocation, big_sur:       "6b276491297d4052538bd2fd22d5129389f27d90a98f831987236a5b90511b98"
            sha256 cellar: :any_skip_relocation, catalina:      "16cf230afdfcb6306c208d169549cf8773c831c8653d2c852315a048960d7e72"
          end
        RUBY
        system "git", "add", "--all"
        system "git", "commit", "-m", "testball 0.1"
      end

      # RuboCop would align the `.and` with `.to_stdout` which is too floaty.
      # rubocop:disable Layout/MultilineMethodCallIndentation
      expect do
        brew "bottle",
             "--merge",
             "--write",
             "#{TEST_TMPDIR}/testball-1.0.arm64_big_sur.bottle.json",
             "#{TEST_TMPDIR}/testball-1.0.big_sur.bottle.json",
             "#{TEST_TMPDIR}/testball-1.0.catalina.bottle.json"
      end.to output(Regexp.new(<<~'EOS')).to_stdout
        ==> testball
          bottle do
            sha256 cellar: :any_skip_relocation, arm64_big_sur: "8f9aecd233463da6a4ea55f5f88fc5841718c013f3e2a7941350d6130f1dc149"
            sha256 cellar: :any_skip_relocation, big_sur:       "a0af7dcbb5c83f6f3f7ecd507c2d352c1a018f894d51ad241ce8492fa598010f"
            sha256 cellar: :any_skip_relocation, catalina:      "5334dd344986e46b2aa4f0471cac7b0914bd7de7cb890a34415771788d03f2ac"
          end
        \[master [0-9a-f]{4,40}\] testball: update 1\.0 bottle\.
         1 file changed, 3 insertions\(\+\), 3 deletions\(\-\)
      EOS
      .and not_to_output.to_stderr
      .and be_a_success
      # rubocop:enable Layout/MultilineMethodCallIndentation

      expect((core_tap.path/"Formula/testball.rb").read).to eq <<~RUBY
        class Testball < Formula
          desc "Some test"
          homepage "https://brew.sh/testball"
          url "file://#{tarball}"
          sha256 "#{tarball.sha256}"

          option "with-foo", "Build with foo"

          bottle do
            sha256 cellar: :any_skip_relocation, arm64_big_sur: "8f9aecd233463da6a4ea55f5f88fc5841718c013f3e2a7941350d6130f1dc149"
            sha256 cellar: :any_skip_relocation, big_sur:       "a0af7dcbb5c83f6f3f7ecd507c2d352c1a018f894d51ad241ce8492fa598010f"
            sha256 cellar: :any_skip_relocation, catalina:      "5334dd344986e46b2aa4f0471cac7b0914bd7de7cb890a34415771788d03f2ac"
          end

          def install
            (prefix/"foo"/"test").write("test") if build.with? "foo"
            prefix.install Dir["*"]
            (buildpath/"test.c").write \
            "#include <stdio.h>\\nint main(){printf(\\"test\\");return 0;}"
            bin.mkpath
            system ENV.cc, "test.c", "-o", bin/"test"
          end



          # something here

        end
      RUBY
    end

    it "updates the bottle block in a formula that already has a bottle block when using --keep-old" do
      core_tap.path.cd do
        system "git", "-c", "init.defaultBranch=master", "init"
        setup_test_formula "testball", bottle_block: <<~RUBY

          bottle do
            sha256 cellar: :any, sonoma: "6971b6eebf4c00eaaed72a1104a49be63861eabc95d679a0c84040398e320059"
          end
        RUBY
        system "git", "add", "--all"
        system "git", "commit", "-m", "testball 0.1"
      end

      # RuboCop would align the `.and` with `.to_stdout` which is too floaty.
      # rubocop:disable Layout/MultilineMethodCallIndentation
      expect do
        brew "bottle",
             "--merge",
             "--write",
             "--keep-old",
             "#{TEST_TMPDIR}/testball-1.0.arm64_big_sur.bottle.json",
             "#{TEST_TMPDIR}/testball-1.0.big_sur.bottle.json",
             "#{TEST_TMPDIR}/testball-1.0.catalina.bottle.json"
      end.to output(Regexp.new(<<~'EOS')).to_stdout
        ==> testball
          bottle do
            sha256 cellar: :any_skip_relocation, arm64_big_sur: "8f9aecd233463da6a4ea55f5f88fc5841718c013f3e2a7941350d6130f1dc149"
            sha256 cellar: :any,                 sonoma:        "6971b6eebf4c00eaaed72a1104a49be63861eabc95d679a0c84040398e320059"
            sha256 cellar: :any_skip_relocation, big_sur:       "a0af7dcbb5c83f6f3f7ecd507c2d352c1a018f894d51ad241ce8492fa598010f"
            sha256 cellar: :any_skip_relocation, catalina:      "5334dd344986e46b2aa4f0471cac7b0914bd7de7cb890a34415771788d03f2ac"
          end
        \[master [0-9a-f]{4,40}\] testball: update 1\.0 bottle\.
         1 file changed, 4 insertions\(\+\), 1 deletion\(\-\)
      EOS
      .and not_to_output.to_stderr
      .and be_a_success
      # rubocop:enable Layout/MultilineMethodCallIndentation

      expect((core_tap.path/"Formula/testball.rb").read).to eq <<~RUBY
        class Testball < Formula
          desc "Some test"
          homepage "https://brew.sh/testball"
          url "file://#{tarball}"
          sha256 "#{tarball.sha256}"

          option "with-foo", "Build with foo"

          bottle do
            sha256 cellar: :any_skip_relocation, arm64_big_sur: "8f9aecd233463da6a4ea55f5f88fc5841718c013f3e2a7941350d6130f1dc149"
            sha256 cellar: :any,                 sonoma:        "6971b6eebf4c00eaaed72a1104a49be63861eabc95d679a0c84040398e320059"
            sha256 cellar: :any_skip_relocation, big_sur:       "a0af7dcbb5c83f6f3f7ecd507c2d352c1a018f894d51ad241ce8492fa598010f"
            sha256 cellar: :any_skip_relocation, catalina:      "5334dd344986e46b2aa4f0471cac7b0914bd7de7cb890a34415771788d03f2ac"
          end

          def install
            (prefix/"foo"/"test").write("test") if build.with? "foo"
            prefix.install Dir["*"]
            (buildpath/"test.c").write \
            "#include <stdio.h>\\nint main(){printf(\\"test\\");return 0;}"
            bin.mkpath
            system ENV.cc, "test.c", "-o", bin/"test"
          end



          # something here

        end
      RUBY
    end

    it "writes an all bottle JSON for matching platform bottles" do
      core_tap.path.cd do
        system "git", "-c", "init.defaultBranch=master", "init"
        setup_test_formula "testball"
        system "git", "add", "--all"
        system "git", "commit", "-m", "testball 0.1"
      end

      mktmpdir.cd do
        sha256 = "8f9aecd233463da6a4ea55f5f88fc5841718c013f3e2a7941350d6130f1dc149"
        bottle_json_paths = ["arm64_big_sur", "big_sur"].map do |tag|
          Pathname("testball--1.0.#{tag}.bottle.tar.gz").write("test")
          Pathname("#{TEST_TMPDIR}/testball-1.0.#{tag}.bottle.json").tap do |path|
            path.write stub_hash(
              name:           "testball",
              version:        "1.0",
              path:           "#{core_tap.path}/Formula/testball.rb",
              cellar:         "any_skip_relocation",
              os:             tag,
              filename:       "testball-1.0.#{tag}.bottle.tar.gz",
              local_filename: "testball--1.0.#{tag}.bottle.tar.gz",
              sha256:,
              sbom:           { "packages" => [{ "SPDXID" => "SPDXRef-#{tag}" }] },
            )
          end
        end

        # RuboCop would align the `.and` with `.to_stdout` which is too floaty.
        # rubocop:disable Layout/MultilineMethodCallIndentation
        expect do
          brew "bottle", "--merge", "--write", "--no-commit", *bottle_json_paths
        end.to output(/sha256 cellar: :any_skip_relocation, all: "#{sha256}"/).to_stdout
        .and not_to_output.to_stderr
        .and be_a_success
        # rubocop:enable Layout/MultilineMethodCallIndentation

        all_bottle_hash = JSON.parse(Pathname("testball--1.0.all.bottle.json").read)
        all_bottle_tag_hash = all_bottle_hash.dig("testball", "bottle", "tags", "all")

        expect(all_bottle_hash.dig("testball", "bottle", "cellar")).to eq("any_skip_relocation")
        expect(all_bottle_hash.dig("testball", "bottle", "tags").keys).to eq(["all"])
        expect(all_bottle_tag_hash).to include(
          "filename"       => "testball-1.0.all.bottle.tar.gz",
          "local_filename" => "testball--1.0.all.bottle.tar.gz",
          "sha256"         => sha256,
        )
        expect(all_bottle_tag_hash.dig("sbom", "tags").keys).to contain_exactly("arm64_big_sur", "big_sur")
        expect(all_bottle_tag_hash).not_to have_key("cellar")
        expect(Pathname("testball--1.0.all.bottle.tar.gz")).to exist
      end
    end

    it "merges when an all bottle cannot be created" do
      core_tap.path.cd do
        system "git", "-c", "init.defaultBranch=master", "init"
        setup_test_formula "testball", bottle_block: <<~RUBY

          bottle do
            sha256 cellar: :any_skip_relocation, all: "d7b9f4e8bf83608b71fe958a99f19f2e5e68bb2582965d32e41759c24f1aef97"
          end
        RUBY
        system "git", "add", "--all"
        system "git", "commit", "-m", "testball 0.1"
      end

      expect do
        brew "bottle",
             "--merge",
             "--write",
             "--no-commit",
             "#{TEST_TMPDIR}/testball-1.0.arm64_big_sur.bottle.json",
             "#{TEST_TMPDIR}/testball-1.0.big_sur.bottle.json",
             { "GITHUB_EVENT_PATH" => nil }
      end.to output(/sha256 cellar: :any_skip_relocation, arm64_big_sur:/).to_stdout
                                                                          .and not_to_output.to_stderr
                                                                                            .and be_a_success

      formula_contents = (core_tap.path/"Formula/testball.rb").read
      expect(formula_contents).to include("big_sur:")
      expect(formula_contents).not_to include("all:")
    end
  end

  describe "bottle_cmd" do
    subject(:homebrew) { described_class.new(["foo"]) }

    let(:hello_hash_big_sur) do
      JSON.parse stub_hash(
        name:           "hello",
        version:        "1.0",
        path:           "/home/hello.rb",
        cellar:         "any_skip_relocation",
        os:             "big_sur",
        filename:       "hello-1.0.big_sur.bottle.tar.gz",
        local_filename: "hello--1.0.big_sur.bottle.tar.gz",
        sha256:         "a0af7dcbb5c83f6f3f7ecd507c2d352c1a018f894d51ad241ce8492fa598010f",
      )
    end
    let(:hello_hash_catalina) do
      JSON.parse stub_hash(
        name:           "hello",
        version:        "1.0",
        path:           "/home/hello.rb",
        cellar:         "any_skip_relocation",
        os:             "catalina",
        filename:       "hello-1.0.catalina.bottle.tar.gz",
        local_filename: "hello--1.0.catalina.bottle.tar.gz",
        sha256:         "5334dd344986e46b2aa4f0471cac7b0914bd7de7cb890a34415771788d03f2ac",
      )
    end
    let(:unzip_hash_big_sur) do
      JSON.parse stub_hash(
        name:           "unzip",
        version:        "2.0",
        path:           "/home/unzip.rb",
        cellar:         "any_skip_relocation",
        os:             "big_sur",
        filename:       "unzip-2.0.big_sur.bottle.tar.gz",
        local_filename: "unzip--2.0.big_sur.bottle.tar.gz",
        sha256:         "16cf230afdfcb6306c208d169549cf8773c831c8653d2c852315a048960d7e72",
      )
    end
    let(:unzip_hash_catalina) do
      JSON.parse stub_hash(
        name:           "unzip",
        version:        "2.0",
        path:           "/home/unzip.rb",
        cellar:         "any",
        os:             "catalina",
        filename:       "unzip-2.0.catalina.bottle.tar.gz",
        local_filename: "unzip--2.0.catalina.bottle.tar.gz",
        sha256:         "d9cc50eec8ac243148a121049c236cba06af4a0b1156ab397d0a2850aa79c137",
      )
    end

    specify "::parse_json_files" do
      Tempfile.open("hello--1.0.big_sur.bottle.json") do |f|
        f.write stub_hash(
          name:           "hello",
          version:        "1.0",
          path:           "/home/hello.rb",
          cellar:         "any_skip_relocation",
          os:             "big_sur",
          filename:       "hello-1.0.big_sur.bottle.tar.gz",
          local_filename: "hello--1.0.big_sur.bottle.tar.gz",
          sha256:         "a0af7dcbb5c83f6f3f7ecd507c2d352c1a018f894d51ad241ce8492fa598010f",
        )
        f.close
        expect(
          homebrew.parse_json_files([f.path]).first["hello"]["bottle"]["tags"]["big_sur"]["filename"],
        ).to eq("hello-1.0.big_sur.bottle.tar.gz")
      end
    end

    describe "::merge_json_files" do
      it "merges JSON files" do
        bottles_hash = homebrew.merge_json_files(
          [hello_hash_big_sur, hello_hash_catalina, unzip_hash_big_sur, unzip_hash_catalina],
        )

        hello_hash = bottles_hash["hello"]
        expect(hello_hash["bottle"]["tags"]["big_sur"]["cellar"]).to eq("any_skip_relocation")
        expect(hello_hash["bottle"]["tags"]["big_sur"]["filename"]).to eq("hello-1.0.big_sur.bottle.tar.gz")
        expect(hello_hash["bottle"]["tags"]["big_sur"]["local_filename"]).to eq("hello--1.0.big_sur.bottle.tar.gz")
        expect(hello_hash["bottle"]["tags"]["big_sur"]["sha256"]).to eq(
          "a0af7dcbb5c83f6f3f7ecd507c2d352c1a018f894d51ad241ce8492fa598010f",
        )
        expect(hello_hash["bottle"]["tags"]["catalina"]["cellar"]).to eq("any_skip_relocation")
        expect(hello_hash["bottle"]["tags"]["catalina"]["filename"]).to eq("hello-1.0.catalina.bottle.tar.gz")
        expect(hello_hash["bottle"]["tags"]["catalina"]["local_filename"]).to eq("hello--1.0.catalina.bottle.tar.gz")
        expect(hello_hash["bottle"]["tags"]["catalina"]["sha256"]).to eq(
          "5334dd344986e46b2aa4f0471cac7b0914bd7de7cb890a34415771788d03f2ac",
        )
        unzip_hash = bottles_hash["unzip"]
        expect(unzip_hash["bottle"]["tags"]["big_sur"]["cellar"]).to eq("any_skip_relocation")
        expect(unzip_hash["bottle"]["tags"]["big_sur"]["filename"]).to eq("unzip-2.0.big_sur.bottle.tar.gz")
        expect(unzip_hash["bottle"]["tags"]["big_sur"]["local_filename"]).to eq("unzip--2.0.big_sur.bottle.tar.gz")
        expect(unzip_hash["bottle"]["tags"]["big_sur"]["sha256"]).to eq(
          "16cf230afdfcb6306c208d169549cf8773c831c8653d2c852315a048960d7e72",
        )
        expect(unzip_hash["bottle"]["tags"]["catalina"]["cellar"]).to eq("any")
        expect(unzip_hash["bottle"]["tags"]["catalina"]["filename"]).to eq("unzip-2.0.catalina.bottle.tar.gz")
        expect(unzip_hash["bottle"]["tags"]["catalina"]["local_filename"]).to eq("unzip--2.0.catalina.bottle.tar.gz")
        expect(unzip_hash["bottle"]["tags"]["catalina"]["sha256"]).to eq(
          "d9cc50eec8ac243148a121049c236cba06af4a0b1156ab397d0a2850aa79c137",
        )
      end

      # TODO: add deduplication tests e.g.
      #       it "deduplicates JSON files with matching macOS checksums"
      #       it "deduplicates JSON files with matching OS checksums" do
    end

    describe "#merge_bottle_spec" do
      it "allows new bottle hash to be empty" do
        valid_keys = [:root_url, :cellar, :rebuild, :sha256]
        old_spec = BottleSpecification.new
        old_spec.sha256(big_sur: "f59bc65c91e4e698f6f050e1efea0040f57372d4dcf0996cbb8f97ced320403b")
        expect { homebrew.merge_bottle_spec(valid_keys, old_spec, {}) }.not_to raise_error
      end

      it "checks for conflicting root URL" do
        old_spec = BottleSpecification.new
        old_spec.root_url("https://failbrew.bintray.com/bottles")
        new_hash = { "root_url" => "https://testbrew.bintray.com/bottles" }
        expect(homebrew.merge_bottle_spec([:root_url], old_spec, new_hash)).to eq [
          ['root_url: old: "https://failbrew.bintray.com/bottles", new: "https://testbrew.bintray.com/bottles"'],
          [],
        ]
      end

      it "checks for conflicting rebuild number" do
        old_spec = BottleSpecification.new
        old_spec.rebuild(1)
        new_hash = { "rebuild" => 2 }
        expect(homebrew.merge_bottle_spec([:rebuild], old_spec, new_hash)).to eq [
          ['rebuild: old: "1", new: "2"'],
          [],
        ]
      end

      it "checks for conflicting checksums" do
        old_spec = BottleSpecification.new
        old_sequoia_sha256 = "109c0cb581a7b5d84da36d84b221fb9dd0f8a927b3044d82611791c9907e202e"
        old_spec.sha256(sequoia: old_sequoia_sha256)
        old_spec.sha256(sonoma: "7571772bf7a0c9fe193e70e521318b53993bee6f351976c9b6e01e00d13d6c3f")
        new_sequoia_sha256 = "ec6d7f08412468f28dee2be17ad8cd8b883b16b34329efcecce019b8c9736428"
        new_hash = { "tags" => { "sequoia" => { "sha256" => new_sequoia_sha256 } } }
        expected_checksum_hash = { sonoma: "7571772bf7a0c9fe193e70e521318b53993bee6f351976c9b6e01e00d13d6c3f" }
        expected_checksum_hash[:cellar] = Homebrew::DEFAULT_MACOS_CELLAR
        expect(homebrew.merge_bottle_spec([:sha256], old_spec, new_hash)).to eq [
          ["sha256 sequoia: old: #{old_sequoia_sha256.inspect}, new: #{new_sequoia_sha256.inspect}"],
          [expected_checksum_hash],
        ]
      end
    end

    describe "::generate_sha256_line" do
      it "generates a string without cellar" do
        expect(homebrew.generate_sha256_line(:sequoia, "deadbeef", nil, 0, 10)).to eq(
          <<~RUBY.chomp,
            sha256 sequoia:  "deadbeef"
          RUBY
        )
      end

      it "generates a string with cellar symbol" do
        expect(homebrew.generate_sha256_line(:sequoia, "deadbeef", :any, 14, 24)).to eq(
          <<~RUBY.chomp,
            sha256 cellar: :any, sequoia:  "deadbeef"
          RUBY
        )
      end

      it "generates a string with default cellar path" do
        expect(homebrew.generate_sha256_line(:sequoia, "deadbeef", Homebrew::DEFAULT_LINUX_CELLAR, 0, 10)).to eq(
          <<~RUBY.chomp,
            sha256 sequoia:  "deadbeef"
          RUBY
        )
      end

      it "generates a string with non-default cellar path" do
        expect(homebrew.generate_sha256_line(:sequoia, "deadbeef", "/home/test", 22, 32)).to eq(
          <<~RUBY.chomp,
            sha256 cellar: "/home/test", sequoia:  "deadbeef"
          RUBY
        )
      end

      context "with offsets" do
        it "generates a string without cellar" do
          expect(homebrew.generate_sha256_line(:sequoia, "deadbeef", nil, 0, 15)).to eq(
            <<~RUBY.chomp,
              sha256 sequoia:       "deadbeef"
            RUBY
          )
        end

        it "generates a string with cellar symbol" do
          expect(homebrew.generate_sha256_line(:sequoia, "deadbeef", :any, 20, 35)).to eq(
            <<~RUBY.chomp,
              sha256 cellar: :any,       sequoia:       "deadbeef"
            RUBY
          )
        end

        it "generates a string with default cellar path" do
          expect(homebrew.generate_sha256_line(:sequoia, "deadbeef", Homebrew::DEFAULT_LINUX_CELLAR, 14, 30)).to eq(
            <<~RUBY.chomp,
              sha256               sequoia:        "deadbeef"
            RUBY
          )
        end

        it "generates a string with non-default cellar path" do
          expect(homebrew.generate_sha256_line(:sequoia, "deadbeef", "/home/test", 25, 36)).to eq(
            <<~RUBY.chomp,
              sha256 cellar: "/home/test",    sequoia:   "deadbeef"
            RUBY
          )
        end
      end
    end

    describe "::bottle_output" do
      it "includes a custom root_url" do
        bottle = BottleSpecification.new
        bottle.root_url("https://example.com")
        bottle.sha256(catalina: "109c0cb581a7b5d84da36d84b221fb9dd0f8a927b3044d82611791c9907e202e")

        expect(homebrew.bottle_output(bottle, nil)).to eq(
          <<-RUBY,
  bottle do
    root_url "https://example.com"
    sha256 catalina: "109c0cb581a7b5d84da36d84b221fb9dd0f8a927b3044d82611791c9907e202e"
  end
          RUBY
        )
      end

      it "includes download strategy for custom root_url" do
        bottle = BottleSpecification.new
        bottle.root_url("https://example.com")
        bottle.sha256(catalina: "109c0cb581a7b5d84da36d84b221fb9dd0f8a927b3044d82611791c9907e202e")

        expect(homebrew.bottle_output(bottle, "ExampleStrategy")).to eq(
          <<-RUBY,
  bottle do
    root_url "https://example.com",
      using: ExampleStrategy
    sha256 catalina: "109c0cb581a7b5d84da36d84b221fb9dd0f8a927b3044d82611791c9907e202e"
  end
          RUBY
        )
      end
    end
  end
end
