brew/Library/Homebrew/test/cask/audit_spec.rb

534 lines
15 KiB
Ruby
Raw Normal View History

2017-03-05 19:26:56 +01:00
describe Hbc::Audit, :cask do
def include_msg?(messages, msg)
if msg.is_a?(Regexp)
Array(messages).any? { |m| m =~ msg }
else
Array(messages).include?(msg)
end
end
matcher :pass do
match do |audit|
!audit.errors? && !audit.warnings?
end
end
matcher :fail do
match(&:errors?)
end
matcher :warn do
match do |audit|
audit.warnings? && !audit.errors?
end
end
matcher :fail_with do |error_msg|
match do |audit|
include_msg?(audit.errors, error_msg)
end
end
matcher :warn_with do |warning_msg|
match do |audit|
include_msg?(audit.warnings, warning_msg)
end
end
2016-08-18 22:11:42 +03:00
let(:cask) { instance_double(Hbc::Cask) }
let(:download) { false }
let(:check_token_conflicts) { false }
let(:fake_system_command) { class_double(Hbc::SystemCommand) }
let(:audit) {
Hbc::Audit.new(cask, download: download,
check_token_conflicts: check_token_conflicts,
command: fake_system_command)
}
describe "#result" do
subject { audit.result }
context "when there are errors" do
before do
audit.add_error "bad"
end
it { is_expected.to match(/failed/) }
2016-08-18 22:11:42 +03:00
end
context "when there are warnings" do
before do
audit.add_warning "eh"
end
it { is_expected.to match(/warning/) }
2016-08-18 22:11:42 +03:00
end
context "when there are errors and warnings" do
before do
audit.add_error "bad"
audit.add_warning "eh"
end
it { is_expected.to match(/failed/) }
2016-08-18 22:11:42 +03:00
end
context "when there are no errors or warnings" do
it { is_expected.to match(/passed/) }
2016-08-18 22:11:42 +03:00
end
end
describe "#run!" do
subject { audit.run! }
let(:cask) { Hbc::CaskLoader.load(cask_token) }
2016-08-18 22:11:42 +03:00
describe "required stanzas" do
2016-10-06 21:27:44 +08:00
%w[version sha256 url name homepage].each do |stanza|
2016-08-18 22:11:42 +03:00
context "when missing #{stanza}" do
let(:cask_token) { "missing-#{stanza}" }
it { is_expected.to fail_with(/#{stanza} stanza is required/) }
2016-08-18 22:11:42 +03:00
end
end
2018-03-25 15:30:16 +10:00
end
describe "pkg allow_untrusted checks" do
2018-06-05 19:09:14 +10:00
let(:warning_msg) { "allow_untrusted is not permitted in official Homebrew-Cask taps" }
2018-03-25 15:30:16 +10:00
context "when the Cask has no pkg stanza" do
let(:cask_token) { "basic-cask" }
2018-03-28 22:05:56 +10:00
2018-06-05 19:09:14 +10:00
it { is_expected.not_to warn_with(warning_msg) }
2018-03-25 15:30:16 +10:00
end
context "when the Cask does not have allow_untrusted" do
let(:cask_token) { "with-uninstall-pkgutil" }
2018-03-28 22:05:56 +10:00
2018-06-05 19:09:14 +10:00
it { is_expected.not_to warn_with(warning_msg) }
2018-03-25 15:30:16 +10:00
end
context "when the Cask has allow_untrusted" do
let(:cask_token) { "with-allow-untrusted" }
2018-03-28 22:05:56 +10:00
2018-06-05 19:09:14 +10:00
it { is_expected.to warn_with(warning_msg) }
2018-03-25 15:30:16 +10:00
end
2016-08-18 22:11:42 +03:00
end
describe "when the Cask stanza requires uninstall" do
2018-06-05 19:09:14 +10:00
let(:warning_msg) { "installer and pkg stanzas require an uninstall stanza" }
context "when the Cask does not require an uninstall" do
let(:cask_token) { "basic-cask" }
2018-06-05 19:09:14 +10:00
it { is_expected.not_to warn_with(warning_msg) }
end
context "when the pkg Cask has an uninstall" do
let(:cask_token) { "with-uninstall-pkgutil" }
2018-06-05 19:09:14 +10:00
it { is_expected.not_to warn_with(warning_msg) }
end
context "when the installer Cask has an uninstall" do
let(:cask_token) { "installer-with-uninstall" }
2018-06-05 19:09:14 +10:00
it { is_expected.not_to warn_with(warning_msg) }
end
context "when the installer Cask does not have an uninstall" do
let(:cask_token) { "with-installer-manual" }
2018-06-05 19:09:14 +10:00
it { is_expected.to warn_with(warning_msg) }
end
context "when the pkg Cask does not have an uninstall" do
let(:cask_token) { "pkg-without-uninstall" }
2018-06-05 19:09:14 +10:00
it { is_expected.to warn_with(warning_msg) }
end
end
describe "preflight stanza checks" do
2018-06-05 19:09:14 +10:00
let(:warning_msg) { "only a single preflight stanza is allowed" }
2018-03-27 08:41:32 +10:00
context "when the Cask has no preflight stanza" do
let(:cask_token) { "with-zap-rmdir" }
2018-06-05 19:09:14 +10:00
it { is_expected.not_to warn_with(warning_msg) }
end
2018-03-27 08:41:32 +10:00
context "when the Cask has only one preflight stanza" do
let(:cask_token) { "with-preflight" }
2018-06-05 19:09:14 +10:00
it { is_expected.not_to warn_with(warning_msg) }
end
2018-03-27 08:41:32 +10:00
context "when the Cask has multiple preflight stanzas" do
let(:cask_token) { "with-preflight-multi" }
2018-06-05 19:09:14 +10:00
it { is_expected.to warn_with(warning_msg) }
end
end
describe "uninstall_postflight stanza checks" do
2018-06-05 19:09:14 +10:00
let(:warning_msg) { "only a single postflight stanza is allowed" }
2018-03-27 08:41:32 +10:00
context "when the Cask has no postflight stanza" do
let(:cask_token) { "with-zap-rmdir" }
2018-06-05 19:09:14 +10:00
it { is_expected.not_to warn_with(warning_msg) }
end
2018-03-27 08:41:32 +10:00
context "when the Cask has only one postflight stanza" do
let(:cask_token) { "with-postflight" }
2018-06-05 19:09:14 +10:00
it { is_expected.not_to warn_with(warning_msg) }
end
2018-03-27 08:41:32 +10:00
context "when the Cask has multiple postflight stanzas" do
let(:cask_token) { "with-postflight-multi" }
2018-06-05 19:09:14 +10:00
it { is_expected.to warn_with(warning_msg) }
end
end
describe "uninstall stanza checks" do
2018-06-05 19:09:14 +10:00
let(:warning_msg) { "only a single uninstall stanza is allowed" }
2018-03-27 08:41:32 +10:00
context "when the Cask has no uninstall stanza" do
let(:cask_token) { "with-zap-rmdir" }
2018-06-05 19:09:14 +10:00
it { is_expected.not_to warn_with(warning_msg) }
end
2018-03-27 08:41:32 +10:00
context "when the Cask has only one uninstall stanza" do
let(:cask_token) { "with-uninstall-rmdir" }
2018-06-05 19:09:14 +10:00
it { is_expected.not_to warn_with(warning_msg) }
end
2018-03-27 08:41:32 +10:00
context "when the Cask has multiple uninstall stanzas" do
let(:cask_token) { "with-uninstall-multi" }
2018-06-05 19:09:14 +10:00
it { is_expected.to warn_with(warning_msg) }
end
end
describe "uninstall_preflight stanza checks" do
2018-06-05 19:09:14 +10:00
let(:warning_msg) { "only a single uninstall_preflight stanza is allowed" }
2018-03-27 08:41:32 +10:00
context "when the Cask has no uninstall_preflight stanza" do
let(:cask_token) { "with-zap-rmdir" }
2018-06-05 19:09:14 +10:00
it { is_expected.not_to warn_with(warning_msg) }
end
2018-03-27 08:41:32 +10:00
context "when the Cask has only one uninstall_preflight stanza" do
let(:cask_token) { "with-uninstall-preflight" }
2018-06-05 19:09:14 +10:00
it { is_expected.not_to warn_with(warning_msg) }
end
2018-03-27 08:41:32 +10:00
context "when the Cask has multiple uninstall_preflight stanzas" do
let(:cask_token) { "with-uninstall-preflight-multi" }
2018-06-05 19:09:14 +10:00
it { is_expected.to warn_with(warning_msg) }
end
end
describe "uninstall_postflight stanza checks" do
2018-06-05 19:09:14 +10:00
let(:warning_msg) { "only a single uninstall_postflight stanza is allowed" }
2018-03-27 08:41:32 +10:00
context "when the Cask has no uninstall_postflight stanza" do
let(:cask_token) { "with-zap-rmdir" }
2018-06-05 19:09:14 +10:00
it { is_expected.not_to warn_with(warning_msg) }
end
2018-03-27 08:41:32 +10:00
context "when the Cask has only one uninstall_postflight stanza" do
let(:cask_token) { "with-uninstall-postflight" }
2018-06-05 19:09:14 +10:00
it { is_expected.not_to warn_with(warning_msg) }
end
2018-03-27 08:41:32 +10:00
context "when the Cask has multiple uninstall_postflight stanzas" do
let(:cask_token) { "with-uninstall-postflight-multi" }
2018-06-05 19:09:14 +10:00
it { is_expected.to warn_with(warning_msg) }
end
end
describe "zap stanza checks" do
2018-06-05 19:09:14 +10:00
let(:warning_msg) { "only a single zap stanza is allowed" }
2018-03-27 08:41:32 +10:00
context "when the Cask has no zap stanza" do
let(:cask_token) { "with-uninstall-rmdir" }
2018-06-05 19:09:14 +10:00
it { is_expected.not_to warn_with(warning_msg) }
end
2018-03-27 08:41:32 +10:00
context "when the Cask has only one zap stanza" do
let(:cask_token) { "with-zap-rmdir" }
2018-06-05 19:09:14 +10:00
it { is_expected.not_to warn_with(warning_msg) }
end
2018-03-27 08:41:32 +10:00
context "when the Cask has multiple zap stanzas" do
let(:cask_token) { "with-zap-multi" }
2018-06-05 19:09:14 +10:00
it { is_expected.to warn_with(warning_msg) }
end
end
2016-08-18 22:11:42 +03:00
describe "version checks" do
let(:error_msg) { "you should use version :latest instead of version 'latest'" }
context "when version is 'latest'" do
let(:cask_token) { "version-latest-string" }
2016-08-27 11:52:14 +02:00
it { is_expected.to fail_with(error_msg) }
2016-08-18 22:11:42 +03:00
end
context "when version is :latest" do
let(:cask_token) { "version-latest-with-checksum" }
it { is_expected.not_to fail_with(error_msg) }
2016-08-18 22:11:42 +03:00
end
end
describe "sha256 checks" do
context "when version is :latest and sha256 is not :no_check" do
let(:cask_token) { "version-latest-with-checksum" }
2016-08-27 11:52:14 +02:00
it { is_expected.to fail_with("you should use sha256 :no_check when version is :latest") }
2016-08-18 22:11:42 +03:00
end
context "when sha256 is not a legal SHA-256 digest" do
let(:cask_token) { "invalid-sha256" }
2016-08-27 11:52:14 +02:00
it { is_expected.to fail_with("sha256 string must be of 64 hexadecimal characters") }
2016-08-18 22:11:42 +03:00
end
context "when sha256 is sha256 for empty string" do
let(:cask_token) { "sha256-for-empty-string" }
it { is_expected.to fail_with(/cannot use the sha256 for an empty string/) }
2016-08-18 22:11:42 +03:00
end
end
2018-06-09 08:28:03 +10:00
describe "appcast checkpoint check" do
let(:error_msg) { "Appcast checkpoints have been removed from Homebrew-Cask" }
2018-06-09 08:28:03 +10:00
context "when the Cask does not have a checkpoint" do
let(:cask_token) { "with-appcast" }
2018-06-09 08:28:03 +10:00
it { is_expected.not_to fail_with(error_msg) }
2016-08-18 22:11:42 +03:00
end
2018-06-09 08:28:03 +10:00
context "when the Cask has a checkpoint" do
let(:cask_token) { "appcast-with-checkpoint" }
2016-08-18 22:11:42 +03:00
2018-06-09 08:28:03 +10:00
it { is_expected.to fail_with(error_msg) }
2016-08-18 22:11:42 +03:00
end
end
describe "GitHub releases appcast check" do
2018-06-05 19:20:38 +10:00
let(:appcast_warning) { /Download uses GitHub releases/ }
2018-06-05 19:20:38 +10:00
context "when the download does not use GitHub releases" do
let(:cask_token) { "basic-cask" }
2018-03-28 22:05:56 +10:00
2018-06-05 19:20:38 +10:00
it { is_expected.not_to warn_with(appcast_warning) }
end
2018-06-05 19:20:38 +10:00
context "when the download uses GitHub releases and has an appcast" do
let(:cask_token) { "github-with-appcast" }
2018-03-28 22:05:56 +10:00
2018-06-05 19:20:38 +10:00
it { is_expected.not_to warn_with(appcast_warning) }
end
2018-06-05 19:20:38 +10:00
context "when the download uses GitHub releases and does not have an appcast" do
let(:cask_token) { "github-without-appcast" }
2018-03-28 22:05:56 +10:00
2018-06-05 19:20:38 +10:00
it { is_expected.to warn_with(appcast_warning) }
end
end
describe "SourceForge appcast check" do
2018-06-05 19:20:38 +10:00
let(:appcast_warning) { /Download is hosted on SourceForge/ }
2018-06-05 19:20:38 +10:00
context "when the download is not hosted on SourceForge" do
let(:cask_token) { "basic-cask" }
2018-06-05 19:20:38 +10:00
it { is_expected.not_to warn_with(appcast_warning) }
end
2018-06-05 19:20:38 +10:00
context "when the download is hosted on SourceForge and has an appcast" do
let(:cask_token) { "sourceforge-with-appcast" }
2018-06-05 19:20:38 +10:00
it { is_expected.not_to warn_with(appcast_warning) }
end
2018-06-05 19:20:38 +10:00
context "when the download is hosted on SourceForge and does not have an appcast" do
let(:cask_token) { "sourceforge-correct-url-format" }
2018-06-05 19:20:38 +10:00
it { is_expected.to warn_with(appcast_warning) }
end
end
describe "latest with appcast checks" do
2018-06-05 19:09:14 +10:00
let(:warning_msg) { "Casks with an appcast should not use version :latest" }
context "when the Cask is :latest and does not have an appcast" do
let(:cask_token) { "version-latest" }
2018-03-28 22:05:56 +10:00
2018-06-05 19:09:14 +10:00
it { is_expected.not_to warn_with(warning_msg) }
end
context "when the Cask is versioned and has an appcast" do
let(:cask_token) { "with-appcast" }
2018-03-28 22:05:56 +10:00
2018-06-05 19:09:14 +10:00
it { is_expected.not_to warn_with(warning_msg) }
end
context "when the Cask is :latest and has an appcast" do
let(:cask_token) { "latest-with-appcast" }
2018-03-28 22:05:56 +10:00
2018-06-05 19:09:14 +10:00
it { is_expected.to warn_with(warning_msg) }
end
end
2016-08-18 22:11:42 +03:00
describe "preferred download URL formats" do
let(:warning_msg) { /URL format incorrect/ }
2016-08-18 22:11:42 +03:00
context "with incorrect SourceForge URL format" do
let(:cask_token) { "sourceforge-incorrect-url-format" }
2016-08-27 11:52:14 +02:00
it { is_expected.to warn_with(warning_msg) }
2016-08-18 22:11:42 +03:00
end
context "with correct SourceForge URL format" do
let(:cask_token) { "sourceforge-correct-url-format" }
it { is_expected.not_to warn_with(warning_msg) }
2016-08-18 22:11:42 +03:00
end
context "with correct SourceForge URL format for version :latest" do
let(:cask_token) { "sourceforge-version-latest-correct-url-format" }
it { is_expected.not_to warn_with(warning_msg) }
2016-08-18 22:11:42 +03:00
end
context "with incorrect OSDN URL format" do
let(:cask_token) { "osdn-incorrect-url-format" }
2016-08-27 11:52:14 +02:00
it { is_expected.to warn_with(warning_msg) }
2016-08-18 22:11:42 +03:00
end
context "with correct OSDN URL format" do
let(:cask_token) { "osdn-correct-url-format" }
it { is_expected.not_to warn_with(warning_msg) }
2016-08-18 22:11:42 +03:00
end
end
describe "generic artifact checks" do
context "with relative target" do
let(:cask_token) { "generic-artifact-relative-target" }
it { is_expected.to fail_with(/target must be absolute path for Generic Artifact/) }
2016-08-18 22:11:42 +03:00
end
context "with absolute target" do
let(:cask_token) { "generic-artifact-absolute-target" }
it { is_expected.not_to fail_with(/target required for Generic Artifact/) }
2016-08-18 22:11:42 +03:00
end
end
describe "url checks" do
context "given a block" do
let(:cask_token) { "booby-trap" }
context "when loading the cask" do
it "does not evaluate the block" do
2016-08-27 11:52:14 +02:00
expect { cask }.not_to raise_error
2016-08-18 22:11:42 +03:00
end
end
context "when doing the audit" do
it "evaluates the block" do
expect(subject).to fail_with(/Boom/)
2016-08-18 22:11:42 +03:00
end
end
end
end
describe "token conflicts" do
let(:cask_token) { "with-binary" }
let(:check_token_conflicts) { true }
before do
expect(audit).to receive(:core_formula_names).and_return(formula_names)
end
context "when cask token conflicts with a core formula" do
let(:formula_names) { %w[with-binary other-formula] }
it { is_expected.to warn_with(/possible duplicate/) }
2016-08-18 22:11:42 +03:00
end
context "when cask token does not conflict with a core formula" do
let(:formula_names) { %w[other-formula] }
it { is_expected.not_to warn_with(/possible duplicate/) }
2016-08-18 22:11:42 +03:00
end
end
describe "audit of downloads" do
let(:cask_token) { "with-binary" }
let(:cask) { Hbc::CaskLoader.load(cask_token) }
2016-08-18 22:11:42 +03:00
let(:download) { instance_double(Hbc::Download) }
let(:verify) { class_double(Hbc::Verify).as_stubbed_const }
let(:error_msg) { "Download Failed" }
context "when download and verification succeed" do
before do
2016-10-19 23:01:52 +02:00
expect(download).to receive(:perform)
expect(verify).to receive(:all)
2016-08-18 22:11:42 +03:00
end
it { is_expected.not_to fail_with(/#{error_msg}/) }
2016-08-18 22:11:42 +03:00
end
context "when download fails" do
before do
2016-10-19 23:01:52 +02:00
expect(download).to receive(:perform).and_raise(StandardError.new(error_msg))
2016-08-18 22:11:42 +03:00
end
it { is_expected.to fail_with(/#{error_msg}/) }
2016-08-18 22:11:42 +03:00
end
context "when verification fails" do
before do
2016-10-19 23:01:52 +02:00
expect(download).to receive(:perform)
expect(verify).to receive(:all).and_raise(StandardError.new(error_msg))
2016-08-18 22:11:42 +03:00
end
it { is_expected.to fail_with(/#{error_msg}/) }
2016-08-18 22:11:42 +03:00
end
end
context "when an exception is raised" do
let(:cask) { instance_double(Hbc::Cask) }
2016-08-18 22:11:42 +03:00
before do
2016-10-19 23:01:52 +02:00
expect(cask).to receive(:version).and_raise(StandardError.new)
2016-08-18 22:11:42 +03:00
end
it { is_expected.to fail_with(/exception while auditing/) }
2016-08-18 22:11:42 +03:00
end
end
end