Files
brew/Library/Homebrew/test/cask/download_spec.rb
T
Mike McQuaid 204ea7e964 Make tests use public APIs and enable their cops
- Make every statically-poked method public and call it directly,
  keeping `public_send` only for dynamically-named public methods.
- Read and write state through public `attr_*` accessors instead of
  instance variable reflection.
- Enable `Homebrew/NoSendInTests` and
  `Homebrew/NoInstanceVariableAccessInTests` now the test suite is
  clean, so neither pattern creeps back in.
- Keep rare justified disables, e.g. `Module#remove_const` is
  private core Ruby and raw memoisation state has no accessor.
2026-07-27 08:11:46 +01:00

173 lines
5.8 KiB
Ruby

# typed: false
# frozen_string_literal: true
RSpec.describe Cask::Download, :cask do
describe "#download_name" do
subject(:download_name) { described_class.new(cask).download_name }
let(:token) { "example-cask" }
let(:full_token) { token }
let(:url) { instance_double(URL, to_s: url_to_s, specs: {}) }
let(:url_to_s) { "https://example.com/app.dmg" }
let(:cask) { instance_double(Cask::Cask, token:, full_token:, version:, url:) }
context "when cask has no version" do
let(:version) { nil }
it "returns the cask token" do
expect(download_name).to eq "example-cask"
end
end
context "when the URL basename would create a short symlink name" do
let(:version) { "1.0.0" }
it "returns the cask token" do
expect(download_name).to eq "example-cask"
end
end
context "when the URL basename would create a long symlink name" do
let(:version) do
"1.2.3,kch23dmbz6whmoogcbss45yi4c2kkq15gmemwys0hgwd3l7cahmx2ciagrlrgppatxaxarzazmdoerzmiisuf7mul4lgcays2dl3nl"
end
let(:url_to_s) { "https://example.com/app.dmg?#{Array.new(50) { |i| "param#{i}=value#{i}" }.join("&")}" }
it "returns the cask token" do
expect(download_name).to eq "example-cask"
end
context "when the cask is in a third-party tap" do
let(:full_token) { "third-party/tap/example-cask" }
it "returns the cask token" do
expect(download_name).to eq "example-cask"
end
end
end
end
describe "#fetch" do
it "fails before downloading if sha256 :no_check is used with --require-sha" do
no_checksum = Cask::CaskLoader.load(cask_path("no-checksum"))
download = described_class.new(no_checksum, require_sha: true)
expect(download).not_to receive(:downloader)
expect { download.fetch }.to raise_error(/--require-sha/)
end
end
describe "#stage_from_download_queue?" do
it "does not mutate download state" do
cask = Cask::CaskLoader.load(cask_path("local-caffeine"))
download = described_class.new(cask)
expect(download).not_to receive(:primary_container)
expect(download.stage_from_download_queue?(TEST_FIXTURE_DIR/"cask/caffeine.zip", pour: true)).to be(true)
expect(cask.download).to be_nil
end
end
describe "#purge_staged_from_download_queue" do
it "removes stale markers with permission-aware removal" do
cask = Cask::CaskLoader.load(cask_path("local-caffeine"))
download = described_class.new(cask)
staged_marker = download.staged_path_from_download_queue_marker
staged_marker.dirname.mkpath
FileUtils.ln_s(download.staged_path_from_download_queue, staged_marker)
expect(Cask::Utils).to receive(:gain_permissions_remove).with(staged_marker,
command: SystemCommand).and_call_original
download.purge_staged_from_download_queue
expect(staged_marker).not_to exist
end
end
describe "#downloaded_and_valid?" do
it "quarantines valid cached downloads" do
cached_download = HOMEBREW_CACHE/"downloads/cask.zip"
cached_download.dirname.mkpath
cached_download.write("already downloaded")
checksum = Checksum.new(cached_download.sha256)
cask = instance_double(Cask::Cask, sha256: checksum)
download = described_class.new(cask, quarantine: true)
allow(download).to receive(:cached_download).and_return(cached_download)
allow(download).to receive(:verify_download_integrity) do |filename|
filename.verify_checksum(checksum)
end
allow(Cask::Quarantine).to receive(:available?).and_return(true)
expect(Cask::Quarantine).to receive(:cask!).with(cask:, download_path: cached_download)
expect(download.downloaded_and_valid?).to be(true)
end
end
describe "#verify_download_integrity" do
subject(:verification) { described_class.new(cask).verify_download_integrity(downloaded_path) }
let(:tap) { nil }
let(:cask) { instance_double(Cask::Cask, token: "cask", sha256: expected_sha256, tap:) }
let(:cafebabe) { "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe" }
let(:deadbeef) { "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" }
let(:computed_sha256) { cafebabe }
let(:downloaded_path) { Pathname.new("cask.zip") }
before do
allow(downloaded_path).to receive_messages(file?: true, sha256: computed_sha256)
end
context "when the expected checksum is :no_check" do
let(:expected_sha256) { :no_check }
it "warns about skipping the check" do
expect { verification }.to output(/skipping verification/).to_stderr
end
context "with an official tap" do
let(:tap) { CoreCaskTap.instance }
it "does not warn about skipping the check" do
expect { verification }.not_to output(/skipping verification/).to_stderr
end
end
end
context "when expected and computed checksums match" do
let(:expected_sha256) { Checksum.new(cafebabe) }
it "does not raise an error" do
expect { verification }.not_to raise_error
end
end
context "when the expected checksum is nil" do
let(:expected_sha256) { nil }
it "outputs an error" do
expect { verification }.to output(/sha256 "#{computed_sha256}"/).to_stderr
end
end
context "when the expected checksum is empty" do
let(:expected_sha256) { Checksum.new("") }
it "outputs an error" do
expect { verification }.to output(/sha256 "#{computed_sha256}"/).to_stderr
end
end
context "when expected and computed checksums do not match" do
let(:expected_sha256) { Checksum.new(deadbeef) }
it "raises an error" do
expect { verification }.to raise_error ChecksumMismatchError
end
end
end
end