aboutsummaryrefslogtreecommitdiffstats
path: root/Library/Homebrew/cask/spec
diff options
context:
space:
mode:
authorAnastasiaSulyagina2016-08-18 22:11:42 +0300
committerAnastasiaSulyagina2016-08-19 14:50:14 +0300
commite81f4ab7deeb40308f240be5ea00091fc8786d7a (patch)
treeb5418f9149de71c0f05f90cb2b39ab47f46e27b4 /Library/Homebrew/cask/spec
parent5c7c9de669025bbe4cad9829be39c5cf3b31ad25 (diff)
downloadbrew-e81f4ab7deeb40308f240be5ea00091fc8786d7a.tar.bz2
init
Diffstat (limited to 'Library/Homebrew/cask/spec')
-rw-r--r--Library/Homebrew/cask/spec/cask/artifact/binary_spec.rb88
-rw-r--r--Library/Homebrew/cask/spec/cask/audit_spec.rb333
-rw-r--r--Library/Homebrew/cask/spec/cask/cask_spec.rb25
-rw-r--r--Library/Homebrew/cask/spec/cask/cli/cleanup_spec.rb68
-rw-r--r--Library/Homebrew/cask/spec/cask/cli/doctor_spec.rb16
-rw-r--r--Library/Homebrew/cask/spec/cask/cli/style_spec.rb224
-rw-r--r--Library/Homebrew/cask/spec/cask/cli_spec.rb63
-rw-r--r--Library/Homebrew/cask/spec/cask/download_strategy_spec.rb308
-rw-r--r--Library/Homebrew/cask/spec/cask/dsl/stanza_proxy_spec.rb32
-rw-r--r--Library/Homebrew/cask/spec/cask/dsl/version_spec.rb227
-rw-r--r--Library/Homebrew/cask/spec/cask/macos_spec.rb69
-rw-r--r--Library/Homebrew/cask/spec/cask/scopes_spec.rb47
-rw-r--r--Library/Homebrew/cask/spec/cask/system_command_spec.rb141
-rw-r--r--Library/Homebrew/cask/spec/cask/underscore_supporting_uri_spec.rb16
-rw-r--r--Library/Homebrew/cask/spec/cask/verify/checksum_spec.rb95
-rw-r--r--Library/Homebrew/cask/spec/cask/verify_spec.rb65
-rw-r--r--Library/Homebrew/cask/spec/spec_helper.rb67
l---------Library/Homebrew/cask/spec/support/Casks/.rubocop.yml1
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/appcast-checkpoint-sha256-for-empty-string.rb4
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/appcast-invalid-checkpoint.rb4
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/appcast-missing-checkpoint.rb3
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/appcast-valid-checkpoint.rb4
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/booby-trap.rb8
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/generic-artifact-absolute-target.rb3
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/generic-artifact-no-target.rb3
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/generic-artifact-relative-target.rb3
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/invalid-sha256.rb4
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/missing-homepage.rb5
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/missing-license.rb5
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/missing-name.rb5
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/missing-sha256.rb5
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/missing-url.rb5
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/missing-version.rb4
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/osdn-correct-url-format.rb6
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/osdn-incorrect-url-format.rb6
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/sha256-for-empty-string.rb4
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/sourceforge-correct-url-format.rb6
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/sourceforge-incorrect-url-format.rb6
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/sourceforge-version-latest-correct-url-format.rb6
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/version-latest-string.rb4
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/version-latest-with-checksum.rb4
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/with-binary.rb10
-rw-r--r--Library/Homebrew/cask/spec/support/Casks/with-embedded-binary.rb10
-rw-r--r--Library/Homebrew/cask/spec/support/audit_matchers.rb39
-rw-r--r--Library/Homebrew/cask/spec/support/binaries/AppWithBinary.zipbin0 -> 306 bytes
-rw-r--r--Library/Homebrew/cask/spec/support/binaries/AppWithEmbeddedBinary.zipbin0 -> 618 bytes
-rw-r--r--Library/Homebrew/cask/spec/support/env_helper.rb16
-rw-r--r--Library/Homebrew/cask/spec/support/expectations_hash_helper.rb10
-rw-r--r--Library/Homebrew/cask/spec/support/file_helper.rb16
-rw-r--r--Library/Homebrew/cask/spec/support/install_helper.rb10
-rw-r--r--Library/Homebrew/cask/spec/support/kernel_at_exit_hacks.rb13
-rw-r--r--Library/Homebrew/cask/spec/support/sha256_helper.rb8
-rw-r--r--Library/Homebrew/cask/spec/support/shutup_helper.rb18
53 files changed, 2142 insertions, 0 deletions
diff --git a/Library/Homebrew/cask/spec/cask/artifact/binary_spec.rb b/Library/Homebrew/cask/spec/cask/artifact/binary_spec.rb
new file mode 100644
index 000000000..81e5c9026
--- /dev/null
+++ b/Library/Homebrew/cask/spec/cask/artifact/binary_spec.rb
@@ -0,0 +1,88 @@
+require "spec_helper"
+
+describe Hbc::Artifact::Binary do
+ let(:cask) {
+ Hbc.load("with-binary").tap do |cask|
+ shutup do
+ InstallHelper.install_without_artifacts(cask)
+ end
+ end
+ }
+ let(:expected_path) {
+ Hbc.binarydir.join("binary")
+ }
+ before(:each) do
+ Hbc.binarydir.mkpath
+ end
+ after(:each) do
+ FileUtils.rm expected_path if expected_path.exist?
+ end
+
+ it "links the binary to the proper directory" do
+ shutup do
+ Hbc::Artifact::Binary.new(cask).install_phase
+ end
+ expect(FileHelper.valid_alias?(expected_path)).to be true
+ end
+
+ it "avoids clobbering an existing binary by linking over it" do
+ FileUtils.touch expected_path
+
+ shutup do
+ Hbc::Artifact::Binary.new(cask).install_phase
+ end
+
+ expect(expected_path).to_not be :symlink?
+ end
+
+ it "clobbers an existing symlink" do
+ expected_path.make_symlink("/tmp")
+
+ shutup do
+ Hbc::Artifact::Binary.new(cask).install_phase
+ end
+
+ expect(File.readlink(expected_path)).not_to eq("/tmp")
+ end
+
+ it "respects --no-binaries flag" do
+ Hbc.no_binaries = true
+
+ shutup do
+ Hbc::Artifact::Binary.new(cask).install_phase
+ end
+
+ expect(expected_path.exist?).to be false
+
+ Hbc.no_binaries = false
+ end
+
+ it "creates parent directory if it doesn't exist" do
+ FileUtils.rmdir Hbc.binarydir
+
+ shutup do
+ Hbc::Artifact::Binary.new(cask).install_phase
+ end
+
+ expect(expected_path.exist?).to be true
+ end
+
+ context "binary is inside an app package" do
+ let(:cask) {
+ Hbc.load("with-embedded-binary").tap do |cask|
+ shutup do
+ InstallHelper.install_without_artifacts(cask)
+ end
+ end
+ }
+
+ it "links the binary to the proper directory" do
+ shutup do
+ Hbc::Artifact::App.new(cask).install_phase
+ Hbc::Artifact::Binary.new(cask).install_phase
+ end
+
+ expect(FileHelper.valid_alias?(expected_path)).to be true
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/spec/cask/audit_spec.rb b/Library/Homebrew/cask/spec/cask/audit_spec.rb
new file mode 100644
index 000000000..65a1335a5
--- /dev/null
+++ b/Library/Homebrew/cask/spec/cask/audit_spec.rb
@@ -0,0 +1,333 @@
+require "spec_helper"
+
+describe Hbc::Audit do
+ include AuditMatchers
+ include Sha256Helper
+
+ 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 { should match(%r{failed}) }
+ end
+
+ context "when there are warnings" do
+ before do
+ audit.add_warning "eh"
+ end
+
+ it { should match(%r{warning}) }
+ end
+
+ context "when there are errors and warnings" do
+ before do
+ audit.add_error "bad"
+ audit.add_warning "eh"
+ end
+
+ it { should match(%r{failed}) }
+ end
+
+ context "when there are no errors or warnings" do
+ it { should match(%r{passed}) }
+ end
+ end
+
+ describe "#run!" do
+ let(:cask) { Hbc.load(cask_token) }
+ subject { audit.run! }
+
+ describe "required stanzas" do
+ %w[version sha256 url name homepage license].each do |stanza|
+ context "when missing #{stanza}" do
+ let(:cask_token) { "missing-#{stanza}" }
+ it { should fail_with(%r{#{stanza} stanza is required}) }
+ end
+ end
+ end
+
+ 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" }
+ it { should fail_with(error_msg) }
+ end
+
+ context "when version is :latest" do
+ let(:cask_token) { "version-latest-with-checksum" }
+ it { should_not fail_with(error_msg) }
+ 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" }
+ it { should fail_with("you should use sha256 :no_check when version is :latest") }
+ end
+
+ context "when sha256 is not a legal SHA-256 digest" do
+ let(:cask_token) { "invalid-sha256" }
+ it { should fail_with("sha256 string must be of 64 hexadecimal characters") }
+ end
+
+ context "when sha256 is sha256 for empty string" do
+ let(:cask_token) { "sha256-for-empty-string" }
+ it { should fail_with(%r{cannot use the sha256 for an empty string}) }
+ end
+ end
+
+ describe "appcast checks" do
+ context "when appcast has no sha256" do
+ let(:cask_token) { "appcast-missing-checkpoint" }
+ it { should fail_with(%r{checkpoint sha256 is required for appcast}) }
+ end
+
+ context "when appcast checkpoint is not a string of 64 hexadecimal characters" do
+ let(:cask_token) { "appcast-invalid-checkpoint" }
+ it { should fail_with(%r{string must be of 64 hexadecimal characters}) }
+ end
+
+ context "when appcast checkpoint is sha256 for empty string" do
+ let(:cask_token) { "appcast-checkpoint-sha256-for-empty-string" }
+ it { should fail_with(%r{cannot use the sha256 for an empty string}) }
+ end
+
+ context "when appcast checkpoint is valid sha256" do
+ let(:cask_token) { "appcast-valid-checkpoint" }
+ it { should_not fail_with(%r{appcast :checkpoint}) }
+ end
+
+ context "when verifying appcast HTTP code" do
+ let(:cask_token) { "appcast-valid-checkpoint" }
+ let(:download) { instance_double(Hbc::Download) }
+ let(:wrong_code_msg) { %r{unexpected HTTP response code} }
+ let(:curl_error_msg) { %r{error retrieving appcast} }
+ let(:fake_curl_result) { instance_double(Hbc::SystemCommand::Result) }
+
+ before do
+ allow(audit).to receive(:check_appcast_checkpoint_accuracy)
+ allow(fake_system_command).to receive(:run).and_return(fake_curl_result)
+ allow(fake_curl_result).to receive(:success?).and_return(success)
+ end
+
+ context "when curl succeeds" do
+ let(:success) { true }
+
+ before do
+ allow(fake_curl_result).to receive(:stdout).and_return(stdout)
+ end
+
+ context "when HTTP code is 200" do
+ let(:stdout) { "200" }
+ it { should_not warn_with(wrong_code_msg) }
+ end
+
+ context "when HTTP code is not 200" do
+ let(:stdout) { "404" }
+ it { should warn_with(wrong_code_msg) }
+ end
+ end
+
+ context "when curl fails" do
+ let(:success) { false }
+
+ before do
+ allow(fake_curl_result).to receive(:stderr).and_return("Some curl error")
+ end
+
+ it { should warn_with(curl_error_msg) }
+ end
+ end
+
+ context "when verifying appcast checkpoint" do
+ let(:cask_token) { "appcast-valid-checkpoint" }
+ let(:download) { instance_double(Hbc::Download) }
+ let(:mismatch_msg) { %r{appcast checkpoint mismatch} }
+ let(:curl_error_msg) { %r{error retrieving appcast} }
+ let(:fake_curl_result) { instance_double(Hbc::SystemCommand::Result) }
+ let(:expected_checkpoint) { "d5b2dfbef7ea28c25f7a77cd7fa14d013d82b626db1d82e00e25822464ba19e2" }
+
+ before do
+ allow(audit).to receive(:check_appcast_http_code)
+ allow(fake_system_command).to receive(:run).and_return(fake_curl_result)
+ allow(fake_curl_result).to receive(:success?).and_return(success)
+ end
+
+ context "when appcast download succeeds" do
+ let(:success) { true }
+ let(:appcast_text) { instance_double(::String) }
+
+ before do
+ allow(fake_curl_result).to receive(:stdout).and_return(appcast_text)
+ allow(appcast_text).to receive(:gsub).and_return(appcast_text)
+ allow(appcast_text).to receive(:end_with?).with("\n").and_return(true)
+ allow(Digest::SHA2).to receive(:hexdigest).and_return(actual_checkpoint)
+ end
+
+ context "when appcast checkpoint is out of date" do
+ let(:actual_checkpoint) { random_sha256 }
+ it { should warn_with(mismatch_msg) }
+ it { should_not warn_with(curl_error_msg) }
+ end
+
+ context "when appcast checkpoint is up to date" do
+ let(:actual_checkpoint) { expected_checkpoint }
+ it { should_not warn_with(mismatch_msg) }
+ it { should_not warn_with(curl_error_msg) }
+ end
+ end
+
+ context "when appcast download fails" do
+ let(:success) { false }
+
+ before do
+ allow(fake_curl_result).to receive(:stderr).and_return("Some curl error")
+ end
+
+ it { should warn_with(curl_error_msg) }
+ end
+ end
+ end
+
+ describe "preferred download URL formats" do
+ let(:warning_msg) { %r{URL format incorrect} }
+
+ context "with incorrect SourceForge URL format" do
+ let(:cask_token) { "sourceforge-incorrect-url-format" }
+ it { should warn_with(warning_msg) }
+ end
+
+ context "with correct SourceForge URL format" do
+ let(:cask_token) { "sourceforge-correct-url-format" }
+ it { should_not warn_with(warning_msg) }
+ end
+
+ context "with correct SourceForge URL format for version :latest" do
+ let(:cask_token) { "sourceforge-version-latest-correct-url-format" }
+ it { should_not warn_with(warning_msg) }
+ end
+
+ context "with incorrect OSDN URL format" do
+ let(:cask_token) { "osdn-incorrect-url-format" }
+ it { should warn_with(warning_msg) }
+ end
+
+ context "with correct OSDN URL format" do
+ let(:cask_token) { "osdn-correct-url-format" }
+ it { should_not warn_with(warning_msg) }
+ end
+ end
+
+ describe "generic artifact checks" do
+ context "with no target" do
+ let(:cask_token) { "generic-artifact-no-target" }
+ it { should fail_with(%r{target required for generic artifact}) }
+ end
+
+ context "with relative target" do
+ let(:cask_token) { "generic-artifact-relative-target" }
+ it { should fail_with(%r{target must be absolute path for generic artifact}) }
+ end
+
+ context "with absolute target" do
+ let(:cask_token) { "generic-artifact-absolute-target" }
+ it { should_not fail_with(%r{target required for generic artifact}) }
+ 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
+ expect { cask }.to_not raise_error
+ end
+ end
+
+ context "when doing the audit" do
+ it "evaluates the block" do
+ expect(subject).to fail_with(%r{Boom})
+ 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 { should warn_with(%r{possible duplicate}) }
+ end
+
+ context "when cask token does not conflict with a core formula" do
+ let(:formula_names) { %w[other-formula] }
+ it { should_not warn_with(%r{possible duplicate}) }
+ end
+ end
+
+ describe "audit of downloads" do
+ let(:cask_token) { "with-binary" }
+ let(:cask) { Hbc.load(cask_token) }
+ 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
+ download.expects(:perform)
+ verify.expects(:all)
+ end
+
+ it { should_not fail_with(%r{#{error_msg}}) }
+ end
+
+ context "when download fails" do
+ before do
+ download.expects(:perform).raises(StandardError.new(error_msg))
+ end
+
+ it { should fail_with(%r{#{error_msg}}) }
+ end
+
+ context "when verification fails" do
+ before do
+ download.expects(:perform)
+ verify.expects(:all).raises(StandardError.new(error_msg))
+ end
+
+ it { should fail_with(%r{#{error_msg}}) }
+ end
+ end
+
+ context "when an exception is raised" do
+ let(:cask) { instance_double(Hbc::Cask) }
+ before do
+ cask.expects(:version).raises(StandardError.new)
+ end
+
+ it { should fail_with(%r{exception while auditing}) }
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/spec/cask/cask_spec.rb b/Library/Homebrew/cask/spec/cask/cask_spec.rb
new file mode 100644
index 000000000..f31bee023
--- /dev/null
+++ b/Library/Homebrew/cask/spec/cask/cask_spec.rb
@@ -0,0 +1,25 @@
+require "spec_helper"
+
+describe Hbc::Cask do
+ let(:cask) { described_class.new("versioned-cask") }
+
+ context "when multiple versions are installed" do
+ describe "#versions" do
+ context "and there are duplicate versions" do
+ it "uses the last unique version" do
+ allow(cask).to receive(:timestamped_versions).and_return([
+ ["1.2.2", "0999"],
+ ["1.2.3", "1000"],
+ ["1.2.2", "1001"],
+ ])
+
+ expect(cask).to receive(:timestamped_versions)
+ expect(cask.versions).to eq([
+ "1.2.3",
+ "1.2.2",
+ ])
+ end
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/spec/cask/cli/cleanup_spec.rb b/Library/Homebrew/cask/spec/cask/cli/cleanup_spec.rb
new file mode 100644
index 000000000..e77576ae3
--- /dev/null
+++ b/Library/Homebrew/cask/spec/cask/cli/cleanup_spec.rb
@@ -0,0 +1,68 @@
+require "spec_helper"
+
+describe Hbc::CLI::Cleanup do
+ let(:cache_location) { Pathname.new(Dir.mktmpdir).realpath }
+ let(:cleanup_outdated) { false }
+
+ subject { described_class.new(cache_location, cleanup_outdated) }
+
+ after do
+ cache_location.rmtree
+ end
+
+ describe "cleanup!" do
+ it "removes cached downloads" do
+ cached_download = cache_location.join("SomeDownload.dmg")
+ FileUtils.touch(cached_download)
+ cleanup_size = subject.disk_cleanup_size
+
+ expect {
+ subject.cleanup!
+ }.to output(<<-OUTPUT.undent).to_stdout
+ ==> Removing cached downloads
+ #{cached_download}
+ ==> This operation has freed approximately #{disk_usage_readable(cleanup_size)} of disk space.
+ OUTPUT
+
+ expect(cached_download.exist?).to eq(false)
+ end
+
+ it "does not removed locked files" do
+ cached_download = cache_location.join("SomeDownload.dmg")
+ FileUtils.touch(cached_download)
+ cleanup_size = subject.disk_cleanup_size
+
+ File.new(cached_download).flock(File::LOCK_EX)
+
+ expect(Hbc::Utils).to be_file_locked(cached_download)
+
+ expect {
+ subject.cleanup!
+ }.to output(<<-OUTPUT.undent).to_stdout
+ ==> Removing cached downloads
+ skipping: #{cached_download} is locked
+ ==> This operation has freed approximately #{disk_usage_readable(cleanup_size)} of disk space.
+ OUTPUT
+
+ expect(cached_download.exist?).to eq(true)
+ end
+
+ context "when cleanup_outdated is specified" do
+ let(:cleanup_outdated) { true }
+
+ it "does not remove cache files newer than 10 days old" do
+ cached_download = cache_location.join("SomeNewDownload.dmg")
+ FileUtils.touch(cached_download)
+
+ expect {
+ subject.cleanup!
+ }.to output(<<-OUTPUT.undent).to_stdout
+ ==> Removing cached downloads older than 10 days old
+ Nothing to do
+ OUTPUT
+
+ expect(cached_download.exist?).to eq(true)
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/spec/cask/cli/doctor_spec.rb b/Library/Homebrew/cask/spec/cask/cli/doctor_spec.rb
new file mode 100644
index 000000000..3c9c66150
--- /dev/null
+++ b/Library/Homebrew/cask/spec/cask/cli/doctor_spec.rb
@@ -0,0 +1,16 @@
+require "spec_helper"
+require "hbc/version"
+
+describe Hbc::CLI::Doctor do
+ it "displays some nice info about the environment" do
+ expect {
+ Hbc::CLI::Doctor.run
+ }.to output(%r{\A==> macOS Release:}).to_stdout
+ end
+
+ it "raises an exception when arguments are given" do
+ expect {
+ Hbc::CLI::Doctor.run("argument")
+ }.to raise_error(ArgumentError)
+ end
+end
diff --git a/Library/Homebrew/cask/spec/cask/cli/style_spec.rb b/Library/Homebrew/cask/spec/cask/cli/style_spec.rb
new file mode 100644
index 000000000..0e53d62a2
--- /dev/null
+++ b/Library/Homebrew/cask/spec/cask/cli/style_spec.rb
@@ -0,0 +1,224 @@
+require "English"
+require "spec_helper"
+
+describe Hbc::CLI::Style do
+ let(:args) { [] }
+ let(:cli) { described_class.new(args) }
+
+ around do |example|
+ shutup { example.run }
+ end
+
+ describe ".run" do
+ subject { described_class.run(args) }
+
+ before do
+ allow(described_class).to receive(:new).and_return(cli)
+ allow(cli).to receive(:run).and_return(retval)
+ end
+
+ context "when rubocop succeeds" do
+ let(:retval) { true }
+
+ it "exits successfully" do
+ subject
+ end
+ end
+
+ context "when rubocop fails" do
+ let(:retval) { false }
+
+ it "raises an exception" do
+ expect { subject }.to raise_error(Hbc::CaskError)
+ end
+ end
+ end
+
+ describe "#run" do
+ subject { cli.run }
+
+ before do
+ allow(cli).to receive_messages(install_rubocop: nil,
+ system: nil,
+ rubocop_args: nil,
+ cask_paths: nil)
+ allow($CHILD_STATUS).to receive(:success?).and_return(success)
+ end
+
+ context "when rubocop succeeds" do
+ let(:success) { true }
+ it { is_expected.to be_truthy }
+ end
+
+ context "when rubocop fails" do
+ let(:success) { false }
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ describe "#install_rubocop" do
+ subject { cli.install_rubocop }
+
+ context "when installation succeeds" do
+ before do
+ allow(Homebrew).to receive(:install_gem_setup_path!)
+ end
+
+ it "exits successfully" do
+ expect { subject }.to_not raise_error
+ end
+ end
+
+ context "when installation fails" do
+ before do
+ allow(Homebrew).to receive(:install_gem_setup_path!).and_raise(SystemExit)
+ end
+
+ it "raises an error" do
+ expect { subject }.to raise_error(Hbc::CaskError)
+ end
+ end
+ end
+
+ describe "#cask_paths" do
+ subject { cli.cask_paths }
+
+ before do
+ allow(cli).to receive(:cask_tokens).and_return(tokens)
+ end
+
+ context "when no cask tokens are given" do
+ let(:tokens) { [] }
+
+ before do
+ allow(Hbc).to receive(:all_tapped_cask_dirs).and_return(%w[Casks MoreCasks])
+ end
+
+ it { is_expected.to eq(%w[Casks MoreCasks]) }
+ end
+
+ context "when at least one cask token is a path that exists" do
+ let(:tokens) { ["adium", "Casks/dropbox.rb"] }
+ before do
+ allow(File).to receive(:exist?).and_return(false, true)
+ end
+
+ it "treats all tokens as paths" do
+ expect(subject).to eq(tokens)
+ end
+ end
+
+ context "when no cask tokens are paths that exist" do
+ let(:tokens) { %w[adium dropbox] }
+ before do
+ allow(File).to receive(:exist?).and_return(false)
+ end
+
+ it "tries to find paths for all tokens" do
+ expect(Hbc).to receive(:path).twice
+ subject
+ end
+ end
+ end
+
+ describe "#cask_tokens" do
+ subject { cli.cask_tokens }
+
+ context "when no args are given" do
+ let(:args) { [] }
+ it { is_expected.to be_empty }
+ end
+
+ context "when only flags are given" do
+ let(:args) { ["--fix"] }
+ it { is_expected.to be_empty }
+ end
+
+ context "when only empty args are given" do
+ let(:args) { ["", ""] }
+ it { is_expected.to be_empty }
+ end
+
+ context "when a cask token is given" do
+ let(:args) { ["adium"] }
+ it { is_expected.to eq(["adium"]) }
+ end
+
+ context "when multiple cask tokens are given" do
+ let(:args) { %w[adium dropbox] }
+ it { is_expected.to eq(%w[adium dropbox]) }
+ end
+
+ context "when cask tokens are given with flags" do
+ let(:args) { ["adium", "dropbox", "--fix"] }
+ it { is_expected.to eq(%w[adium dropbox]) }
+ end
+ end
+
+ describe "#rubocop_args" do
+ subject { cli.rubocop_args }
+
+ before do
+ allow(cli).to receive(:fix?).and_return(fix)
+ end
+
+ context "when fix? is true" do
+ let(:fix) { true }
+ it { is_expected.to include("--auto-correct") }
+ end
+
+ context "when fix? is false" do
+ let(:fix) { false }
+ it { is_expected.not_to include("--auto-correct") }
+ end
+ end
+
+ describe "#default_args" do
+ subject { cli.default_args }
+ let(:rubocop_config) { ".rubocop.yml" }
+ before do
+ allow(cli).to receive(:rubocop_config).and_return(rubocop_config)
+ end
+
+ it { is_expected.to include("--format", "simple", "--force-exclusion", "--config", rubocop_config) }
+ end
+
+ describe "#autocorrect_args" do
+ subject { cli.autocorrect_args }
+ let(:default_args) { ["--format", "simple"] }
+
+ it "should add --auto-correct to default args" do
+ allow(cli).to receive(:default_args).and_return(default_args)
+ expect(subject).to include("--auto-correct", *default_args)
+ end
+ end
+
+ describe "#fix?" do
+ subject { cli.fix? }
+
+ context "when --fix is passed as an argument" do
+ let(:args) { ["adium", "--fix"] }
+ it { should be_truthy }
+ end
+
+ context "when --correct is passed as an argument" do
+ let(:args) { ["adium", "--correct"] }
+ it { should be_truthy }
+ end
+
+ context "when --auto-correct is passed as an argument" do
+ let(:args) { ["adium", "--auto-correct"] }
+ it { should be_truthy }
+ end
+
+ context "when --auto-correct is misspelled as --autocorrect" do
+ let(:args) { ["adium", "--autocorrect"] }
+ it { should be_truthy }
+ end
+
+ context "when no flag equivalent to --fix is passed as an argument" do
+ let(:args) { ["adium"] }
+ it { should be_falsey }
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/spec/cask/cli_spec.rb b/Library/Homebrew/cask/spec/cask/cli_spec.rb
new file mode 100644
index 000000000..cb21dbd25
--- /dev/null
+++ b/Library/Homebrew/cask/spec/cask/cli_spec.rb
@@ -0,0 +1,63 @@
+require "spec_helper"
+
+describe Hbc::CLI do
+ it "lists the taps for Casks that show up in two taps" do
+ listing = Hbc::CLI.nice_listing(%w[
+ caskroom/cask/adium
+ caskroom/cask/google-chrome
+ passcod/homebrew-cask/adium
+ ])
+
+ expect(listing).to eq(%w[
+ caskroom/cask/adium
+ google-chrome
+ passcod/cask/adium
+ ])
+ end
+
+ context ".process" do
+ let(:noop_command) { double("CLI::Noop") }
+
+ before do
+ allow(Hbc).to receive(:init)
+ allow(described_class).to receive(:lookup_command).with("noop").and_return(noop_command)
+ allow(noop_command).to receive(:run)
+ end
+
+ around do |example|
+ shutup { example.run }
+ end
+
+ it "passes `--version` along to the subcommand" do
+ expect(described_class).to receive(:run_command).with(noop_command, "--version")
+ described_class.process(%w[noop --version])
+ end
+
+ it "prints help output when subcommand receives `--help` flag" do
+ expect(described_class).to receive(:run_command).with("help")
+ described_class.process(%w[noop --help])
+ expect(Hbc.help).to eq(true)
+ Hbc.help = false
+ end
+
+ it "respects the env variable when choosing what appdir to create" do
+ EnvHelper.with_env_var("HOMEBREW_CASK_OPTS", "--appdir=/custom/appdir") do
+ expect(Hbc).to receive(:appdir=).with(Pathname("/custom/appdir"))
+ described_class.process("noop")
+ end
+ end
+
+ it "respects the env variable when choosing a non-default Caskroom location" do
+ EnvHelper.with_env_var "HOMEBREW_CASK_OPTS", "--caskroom=/custom/caskdir" do
+ expect(Hbc).to receive(:caskroom=).with(Pathname("/custom/caskdir"))
+ described_class.process("noop")
+ end
+ end
+
+ it "exits with a status of 1 when something goes wrong" do
+ allow(described_class).to receive(:lookup_command).and_raise(Hbc::CaskError)
+ expect(described_class).to receive(:exit).with(1)
+ described_class.process("noop")
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/spec/cask/download_strategy_spec.rb b/Library/Homebrew/cask/spec/cask/download_strategy_spec.rb
new file mode 100644
index 000000000..9b1c4d8e3
--- /dev/null
+++ b/Library/Homebrew/cask/spec/cask/download_strategy_spec.rb
@@ -0,0 +1,308 @@
+require "spec_helper"
+
+describe "download strategies" do
+ let(:url) { "http://example.com/cask.dmg" }
+ let(:url_options) { Hash.new }
+ let(:cask) {
+ instance_double(Hbc::Cask, token: "some-cask",
+ url: Hbc::URL.new(url, url_options),
+ version: "1.2.3.4")
+ }
+
+ describe Hbc::CurlDownloadStrategy do
+ let(:downloader) { Hbc::CurlDownloadStrategy.new(cask) }
+
+ before do
+ allow(downloader.temporary_path).to receive(:rename)
+ end
+
+ it "properly assigns a name and uri based on the Cask" do
+ expect(downloader.name).to eq("some-cask")
+ expect(downloader.url).to eq("http://example.com/cask.dmg")
+ expect(downloader.version.to_s).to eq("1.2.3.4")
+ end
+
+ it "calls curl with default arguments for a simple Cask" do
+ allow(downloader).to receive(:curl)
+
+ shutup do
+ downloader.fetch
+ end
+
+ expect(downloader).to have_received(:curl).with(
+ cask.url.to_s,
+ "-C", 0,
+ "-o", kind_of(Pathname)
+ )
+ end
+
+ context "with an explicit user agent" do
+ let(:url_options) { { user_agent: "Mozilla/25.0.1" } }
+
+ it "adds the appropriate curl args" do
+ curl_args = []
+ allow(downloader).to receive(:curl) { |*args| curl_args = args }
+
+ shutup do
+ downloader.fetch
+ end
+
+ expect(curl_args.each_cons(2)).to include(["-A", "Mozilla/25.0.1"])
+ end
+ end
+
+ context "with a generalized fake user agent" do
+ let(:url_options) { { user_agent: :fake } }
+
+ it "adds the appropriate curl args" do
+ curl_args = []
+ allow(downloader).to receive(:curl) { |*args| curl_args = args }
+
+ shutup do
+ downloader.fetch
+ end
+
+ expect(curl_args.each_cons(2)).to include(["-A", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10) http://caskroom.io"])
+ end
+ end
+
+ context "with cookies set" do
+ let(:url_options) {
+ {
+ cookies: {
+ coo: "kie",
+ mon: "ster",
+ },
+ }
+ }
+
+ it "adds curl args for cookies" do
+ curl_args = []
+ allow(downloader).to receive(:curl) { |*args| curl_args = args }
+
+ shutup do
+ downloader.fetch
+ end
+
+ expect(curl_args.each_cons(2)).to include(["-b", "coo=kie;mon=ster"])
+ end
+ end
+
+ context "with referer set" do
+ let(:url_options) { { referer: "http://somehost/also" } }
+
+ it "adds curl args for referer" do
+ curl_args = []
+ allow(downloader).to receive(:curl) { |*args| curl_args = args }
+
+ shutup do
+ downloader.fetch
+ end
+
+ expect(curl_args.each_cons(2)).to include(["-e", "http://somehost/also"])
+ end
+ end
+ end
+
+ describe Hbc::CurlPostDownloadStrategy do
+ let(:downloader) { Hbc::CurlPostDownloadStrategy.new(cask) }
+
+ before do
+ allow(downloader.temporary_path).to receive(:rename)
+ end
+
+ context "with :using and :data specified" do
+ let(:url_options) {
+ {
+ using: :post,
+ data: {
+ form: "data",
+ is: "good",
+ },
+ }
+ }
+
+ it "adds curl args for post arguments" do
+ curl_args = []
+ allow(downloader).to receive(:curl) { |*args| curl_args = args }
+
+ shutup do
+ downloader.fetch
+ end
+
+ expect(curl_args.each_cons(2)).to include(["-d", "form=data"])
+ expect(curl_args.each_cons(2)).to include(["-d", "is=good"])
+ end
+ end
+
+ context "with :using but no :data" do
+ let(:url_options) { { using: :post } }
+
+ it "adds curl args for a POST request" do
+ curl_args = []
+ allow(downloader).to receive(:curl) { |*args| curl_args = args }
+
+ shutup do
+ downloader.fetch
+ end
+
+ expect(curl_args.each_cons(2)).to include(["-X", "POST"])
+ end
+ end
+ end
+
+ describe Hbc::SubversionDownloadStrategy do
+ let(:url_options) { { using: :svn } }
+ let(:fake_system_command) { class_double(Hbc::SystemCommand) }
+ let(:downloader) { Hbc::SubversionDownloadStrategy.new(cask, fake_system_command) }
+ before do
+ allow(fake_system_command).to receive(:run!)
+ end
+
+ it "returns a tarball path on fetch" do
+ allow(downloader).to receive(:compress)
+ allow(downloader).to receive(:fetch_repo)
+
+ retval = shutup { downloader.fetch }
+
+ expect(retval).to equal(downloader.tarball_path)
+ end
+
+ it "calls fetch_repo with default arguments for a simple Cask" do
+ allow(downloader).to receive(:compress)
+ allow(downloader).to receive(:fetch_repo)
+
+ shutup do
+ downloader.fetch
+ end
+
+ expect(downloader).to have_received(:fetch_repo).with(
+ downloader.cached_location,
+ cask.url.to_s
+ )
+ end
+
+ it "calls svn with default arguments for a simple Cask" do
+ allow(downloader).to receive(:compress)
+
+ shutup do
+ downloader.fetch
+ end
+
+ expect(fake_system_command).to have_received(:run!).with(
+ "/usr/bin/svn",
+ hash_including(args: [
+ "checkout",
+ "--force",
+ "--config-option",
+ "config:miscellany:use-commit-times=yes",
+ cask.url.to_s,
+ downloader.cached_location,
+ ])
+ )
+ end
+
+ context "with trust_cert set on the URL" do
+ let(:url_options) {
+ {
+ using: :svn,
+ trust_cert: true,
+ }
+ }
+
+ it "adds svn arguments for :trust_cert" do
+ allow(downloader).to receive(:compress)
+
+ shutup do
+ downloader.fetch
+ end
+
+ expect(fake_system_command).to have_received(:run!).with(
+ "/usr/bin/svn",
+ hash_including(args: [
+ "checkout",
+ "--force",
+ "--config-option",
+ "config:miscellany:use-commit-times=yes",
+ "--trust-server-cert",
+ "--non-interactive",
+ cask.url.to_s,
+ downloader.cached_location,
+ ])
+ )
+ end
+ end
+
+ context "with :revision set on url" do
+ let(:url_options) {
+ {
+ using: :svn,
+ revision: "10",
+ }
+ }
+
+ it "adds svn arguments for :revision" do
+ allow(downloader).to receive(:compress)
+
+ shutup do
+ downloader.fetch
+ end
+
+ expect(fake_system_command).to have_received(:run!).with(
+ "/usr/bin/svn",
+ hash_including(args: [
+ "checkout",
+ "--force",
+ "--config-option",
+ "config:miscellany:use-commit-times=yes",
+ cask.url.to_s,
+ downloader.cached_location,
+ "-r",
+ "10",
+ ])
+ )
+ end
+ end
+
+ it "runs tar to serialize svn downloads" do
+ # sneaky stub to remake the directory, since homebrew code removes it
+ # before tar is called
+ allow(downloader).to receive(:fetch_repo) {
+ downloader.cached_location.mkdir
+ }
+
+ shutup do
+ downloader.fetch
+ end
+
+ expect(fake_system_command).to have_received(:run!).with(
+ "/usr/bin/tar",
+ hash_including(args: [
+ '-s/^\\.//',
+ "--exclude",
+ ".svn",
+ "-cf",
+ downloader.tarball_path,
+ "--",
+ ".",
+ ])
+ )
+ end
+ end
+
+ # does not work yet, because (for unknown reasons), the tar command
+ # returns an error code when running under the test suite
+ # it 'creates a tarball matching the expected checksum' do
+ # cask = Hbc.load('svn-download-check-cask')
+ # downloader = Hbc::SubversionDownloadStrategy.new(cask)
+ # # special mocking required for tar to have something to work with
+ # def downloader.fetch_repo(target, url, revision = nil, ignore_externals=false)
+ # target.mkpath
+ # FileUtils.touch(target.join('empty_file.txt'))
+ # File.utime(1000,1000,target.join('empty_file.txt'))
+ # end
+ # expect(shutup { downloader.fetch }).to equal(downloader.tarball_path)
+ # d = Hbc::Download.new(cask)
+ # d.send(:_check_sums, downloader.tarball_path, cask.sums)
+ # end
+end
diff --git a/Library/Homebrew/cask/spec/cask/dsl/stanza_proxy_spec.rb b/Library/Homebrew/cask/spec/cask/dsl/stanza_proxy_spec.rb
new file mode 100644
index 000000000..8516f0d38
--- /dev/null
+++ b/Library/Homebrew/cask/spec/cask/dsl/stanza_proxy_spec.rb
@@ -0,0 +1,32 @@
+describe Hbc::DSL::StanzaProxy do
+ let(:stanza_proxy) {
+ described_class.new(Array) { %i{foo bar cake} }
+ }
+
+ subject { stanza_proxy }
+ it { is_expected.to be_a_proxy }
+ it { is_expected.to respond_to(:pop) }
+ its(:pop) { is_expected.to eq(:cake) }
+ its(:type) { is_expected.to eq(Array) }
+ its(:to_s) { is_expected.to eq("[:foo, :bar, :cake]") }
+
+ describe "when initialized" do
+ let(:initializing) {
+ proc { |b| described_class.new(Array, &b) }
+ }
+
+ it "does not evaluate the block" do
+ expect(&initializing).not_to yield_control
+ end
+ end
+
+ describe "when receiving a message" do
+ let(:receiving_a_message) {
+ proc { |b| described_class.new(Array, &b).to_s }
+ }
+
+ it "evaluates the block" do
+ expect(&receiving_a_message).to yield_with_no_args
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/spec/cask/dsl/version_spec.rb b/Library/Homebrew/cask/spec/cask/dsl/version_spec.rb
new file mode 100644
index 000000000..04dcd06ca
--- /dev/null
+++ b/Library/Homebrew/cask/spec/cask/dsl/version_spec.rb
@@ -0,0 +1,227 @@
+require "spec_helper"
+
+describe Hbc::DSL::Version do
+ include ExpectationsHashHelper
+
+ let(:version) { described_class.new(raw_version) }
+
+ shared_examples "version equality" do
+ let(:raw_version) { "1.2.3" }
+
+ context "when other is nil" do
+ let(:other) { nil }
+ it { should == false }
+ end
+
+ context "when other is a String" do
+ context "when other == self.raw_version" do
+ let(:other) { "1.2.3" }
+ it { should == true }
+ end
+
+ context "when other != self.raw_version" do
+ let(:other) { "1.2.3.4" }
+ it { should == false }
+ end
+ end
+
+ context "when other is a #{described_class}" do
+ context "when other.raw_version == self.raw_version" do
+ let(:other) { described_class.new("1.2.3") }
+ it { should == true }
+ end
+
+ context "when other.raw_version != self.raw_version" do
+ let(:other) { described_class.new("1.2.3.4") }
+ it { should == false }
+ end
+ end
+ end
+
+ describe "#==" do
+ subject { version == other }
+ include_examples "version equality"
+ end
+
+ describe "#eql?" do
+ subject { version.eql?(other) }
+ include_examples "version equality"
+ end
+
+ shared_examples "version expectations hash" do |method, hash|
+ subject { version.send(method) }
+ include_examples "expectations hash", :raw_version,
+ { :latest => "latest",
+ "latest" => "latest",
+ "" => "",
+ nil => "" }.merge(hash)
+ end
+
+ describe "#latest?" do
+ include_examples "version expectations hash", :latest?,
+ :latest => true,
+ "latest" => true,
+ "" => false,
+ nil => false,
+ "1.2.3" => false
+ end
+
+ describe "string manipulation helpers" do
+ describe "#major" do
+ include_examples "version expectations hash", :major,
+ "1" => "1",
+ "1.2" => "1",
+ "1.2.3" => "1",
+ "1.2.3_4-5" => "1"
+ end
+
+ describe "#minor" do
+ include_examples "version expectations hash", :minor,
+ "1" => "",
+ "1.2" => "2",
+ "1.2.3" => "2",
+ "1.2.3_4-5" => "2"
+ end
+
+ describe "#patch" do
+ include_examples "version expectations hash", :patch,
+ "1" => "",
+ "1.2" => "",
+ "1.2.3" => "3",
+ "1.2.3_4-5" => "3"
+ end
+
+ describe "#major_minor" do
+ include_examples "version expectations hash", :major_minor,
+ "1" => "1",
+ "1.2" => "1.2",
+ "1.2.3" => "1.2",
+ "1.2.3_4-5" => "1.2"
+ end
+
+ describe "#major_minor_patch" do
+ include_examples "version expectations hash", :major_minor_patch,
+ "1" => "1",
+ "1.2" => "1.2",
+ "1.2.3" => "1.2.3",
+ "1.2.3_4-5" => "1.2.3"
+ end
+
+ describe "#before_comma" do
+ include_examples "version expectations hash", :before_comma,
+ "1.2.3" => "1.2.3",
+ "1.2.3," => "1.2.3",
+ ",abc" => "",
+ "1.2.3,abc" => "1.2.3"
+ end
+
+ describe "#after_comma" do
+ include_examples "version expectations hash", :after_comma,
+ "1.2.3" => "",
+ "1.2.3," => "",
+ ",abc" => "abc",
+ "1.2.3,abc" => "abc"
+ end
+
+ describe "#before_colon" do
+ include_examples "version expectations hash", :before_colon,
+ "1.2.3" => "1.2.3",
+ "1.2.3:" => "1.2.3",
+ ":abc" => "",
+ "1.2.3:abc" => "1.2.3"
+ end
+
+ describe "#after_colon" do
+ include_examples "version expectations hash", :after_colon,
+ "1.2.3" => "",
+ "1.2.3:" => "",
+ ":abc" => "abc",
+ "1.2.3:abc" => "abc"
+ end
+
+ describe "#dots_to_hyphens" do
+ include_examples "version expectations hash", :dots_to_hyphens,
+ "1.2.3_4-5" => "1-2-3_4-5"
+ end
+
+ describe "#dots_to_underscores" do
+ include_examples "version expectations hash", :dots_to_underscores,
+ "1.2.3_4-5" => "1_2_3_4-5"
+ end
+
+ describe "#dots_to_slashes" do
+ include_examples "version expectations hash", :dots_to_slashes,
+ "1.2.3_4-5" => "1/2/3_4-5"
+ end
+
+ describe "#hyphens_to_dots" do
+ include_examples "version expectations hash", :hyphens_to_dots,
+ "1.2.3_4-5" => "1.2.3_4.5"
+ end
+
+ describe "#hyphens_to_underscores" do
+ include_examples "version expectations hash", :hyphens_to_underscores,
+ "1.2.3_4-5" => "1.2.3_4_5"
+ end
+
+ describe "#hyphens_to_slashes" do
+ include_examples "version expectations hash", :hyphens_to_slashes,
+ "1.2.3_4-5" => "1.2.3_4/5"
+ end
+
+ describe "#underscores_to_dots" do
+ include_examples "version expectations hash", :underscores_to_dots,
+ "1.2.3_4-5" => "1.2.3.4-5"
+ end
+
+ describe "#underscores_to_hyphens" do
+ include_examples "version expectations hash", :underscores_to_hyphens,
+ "1.2.3_4-5" => "1.2.3-4-5"
+ end
+
+ describe "#underscores_to_slashes" do
+ include_examples "version expectations hash", :underscores_to_slashes,
+ "1.2.3_4-5" => "1.2.3/4-5"
+ end
+
+ describe "#slashes_to_dots" do
+ include_examples "version expectations hash", :slashes_to_dots,
+ "1.2.3/abc" => "1.2.3.abc"
+ end
+
+ describe "#slashes_to_hyphens" do
+ include_examples "version expectations hash", :slashes_to_hyphens,
+ "1.2.3/abc" => "1.2.3-abc"
+ end
+
+ describe "#slashes_to_underscores" do
+ include_examples "version expectations hash", :slashes_to_underscores,
+ "1.2.3/abc" => "1.2.3_abc"
+ end
+
+ describe "#no_dots" do
+ include_examples "version expectations hash", :no_dots,
+ "1.2.3_4-5" => "123_4-5"
+ end
+
+ describe "#no_hyphens" do
+ include_examples "version expectations hash", :no_hyphens,
+ "1.2.3_4-5" => "1.2.3_45"
+ end
+
+ describe "#no_underscores" do
+ include_examples "version expectations hash", :no_underscores,
+ "1.2.3_4-5" => "1.2.34-5"
+ end
+
+ describe "#no_slashes" do
+ include_examples "version expectations hash", :no_slashes,
+ "1.2.3/abc" => "1.2.3abc"
+ end
+
+ describe "#no_dividers" do
+ include_examples "version expectations hash", :no_dividers,
+ "1.2.3_4-5" => "12345"
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/spec/cask/macos_spec.rb b/Library/Homebrew/cask/spec/cask/macos_spec.rb
new file mode 100644
index 000000000..902c80d7a
--- /dev/null
+++ b/Library/Homebrew/cask/spec/cask/macos_spec.rb
@@ -0,0 +1,69 @@
+require "spec_helper"
+
+describe MacOS do
+ it "says '/' is undeletable" do
+ expect(MacOS).to be_undeletable(
+ "/"
+ )
+ expect(MacOS).to be_undeletable(
+ "/."
+ )
+ expect(MacOS).to be_undeletable(
+ "/usr/local/Library/Taps/../../../.."
+ )
+ end
+
+ it "says '/Applications' is undeletable" do
+ expect(MacOS).to be_undeletable(
+ "/Applications"
+ )
+ expect(MacOS).to be_undeletable(
+ "/Applications/"
+ )
+ expect(MacOS).to be_undeletable(
+ "/Applications/."
+ )
+ expect(MacOS).to be_undeletable(
+ "/Applications/Mail.app/.."
+ )
+ end
+
+ it "says the home directory is undeletable" do
+ expect(MacOS).to be_undeletable(
+ Dir.home
+ )
+ expect(MacOS).to be_undeletable(
+ "#{Dir.home}/"
+ )
+ expect(MacOS).to be_undeletable(
+ "#{Dir.home}/Documents/.."
+ )
+ end
+
+ it "says the user library directory is undeletable" do
+ expect(MacOS).to be_undeletable(
+ "#{Dir.home}/Library"
+ )
+ expect(MacOS).to be_undeletable(
+ "#{Dir.home}/Library/"
+ )
+ expect(MacOS).to be_undeletable(
+ "#{Dir.home}/Library/."
+ )
+ expect(MacOS).to be_undeletable(
+ "#{Dir.home}/Library/Preferences/.."
+ )
+ end
+
+ it "says '/Applications/.app' is deletable" do
+ expect(MacOS).not_to be_undeletable(
+ "/Applications/.app"
+ )
+ end
+
+ it "says '/Applications/SnakeOil Professional.app' is deletable" do
+ expect(MacOS).not_to be_undeletable(
+ "/Applications/SnakeOil Professional.app"
+ )
+ end
+end
diff --git a/Library/Homebrew/cask/spec/cask/scopes_spec.rb b/Library/Homebrew/cask/spec/cask/scopes_spec.rb
new file mode 100644
index 000000000..0e592c990
--- /dev/null
+++ b/Library/Homebrew/cask/spec/cask/scopes_spec.rb
@@ -0,0 +1,47 @@
+require "spec_helper"
+
+describe Hbc::Scopes do
+ describe "installed" do
+ let(:fake_caskroom) { Pathname(Dir.mktmpdir) }
+
+ before do
+ allow(Hbc).to receive(:caskroom) { fake_caskroom }
+ end
+
+ after do
+ fake_caskroom.rmtree
+ end
+
+ it "returns a list installed Casks by loading Casks for all the dirs that exist in the caskroom" do
+ allow(Hbc).to receive(:load) { |token| "loaded-#{token}" }
+
+ fake_caskroom.join("cask-bar").mkdir
+ fake_caskroom.join("cask-foo").mkdir
+
+ installed_casks = Hbc.installed
+
+ expect(Hbc).to have_received(:load).with("cask-bar")
+ expect(Hbc).to have_received(:load).with("cask-foo")
+ expect(installed_casks).to eq(%w[
+ loaded-cask-bar
+ loaded-cask-foo
+ ])
+ end
+
+ it "optimizes performance by resolving to a fully qualified path before calling Hbc.load" do
+ fake_tapped_cask_dir = Pathname(Dir.mktmpdir).join("Casks")
+ absolute_path_to_cask = fake_tapped_cask_dir.join("some-cask.rb")
+
+ allow(Hbc).to receive(:load)
+ allow(Hbc).to receive(:all_tapped_cask_dirs) { [fake_tapped_cask_dir] }
+
+ fake_caskroom.join("some-cask").mkdir
+ fake_tapped_cask_dir.mkdir
+ FileUtils.touch(absolute_path_to_cask)
+
+ Hbc.installed
+
+ expect(Hbc).to have_received(:load).with(absolute_path_to_cask)
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/spec/cask/system_command_spec.rb b/Library/Homebrew/cask/spec/cask/system_command_spec.rb
new file mode 100644
index 000000000..e85a1976a
--- /dev/null
+++ b/Library/Homebrew/cask/spec/cask/system_command_spec.rb
@@ -0,0 +1,141 @@
+require "spec_helper"
+
+describe Hbc::SystemCommand do
+ describe "when the exit code is 0" do
+ describe "its result" do
+ subject { described_class.run("/usr/bin/true") }
+
+ it { is_expected.to be_a_success }
+ its(:exit_status) { is_expected.to eq(0) }
+ end
+ end
+
+ describe "when the exit code is 1" do
+ let(:command) { "/usr/bin/false" }
+
+ describe "and the command must succeed" do
+ it "throws an error" do
+ expect {
+ described_class.run!(command)
+ }.to raise_error(Hbc::CaskCommandFailedError)
+ end
+ end
+
+ describe "and the command does not have to succeed" do
+ describe "its result" do
+ subject { described_class.run(command) }
+
+ it { is_expected.not_to be_a_success }
+ its(:exit_status) { is_expected.to eq(1) }
+ end
+ end
+ end
+
+ describe "given a pathname" do
+ let(:command) { "/bin/ls" }
+ let(:path) { Pathname(Dir.mktmpdir) }
+
+ before do
+ FileUtils.touch(path.join("somefile"))
+ end
+
+ describe "its result" do
+ subject { described_class.run(command, args: [path]) }
+
+ it { is_expected.to be_a_success }
+ its(:stdout) { is_expected.to eq("somefile\n") }
+ end
+ end
+
+ describe "with both STDOUT and STDERR output from upstream" do
+ let(:command) { "/bin/bash" }
+ let(:options) {
+ { args: [
+ "-c",
+ "for i in $(seq 1 2 5); do echo $i; echo $(($i + 1)) >&2; done",
+ ] }
+ }
+
+ shared_examples "it returns '1 2 3 4 5 6'" do
+ describe "its result" do
+ subject { shutup { described_class.run(command, options) } }
+
+ it { is_expected.to be_a_success }
+ its(:stdout) { is_expected.to eq([1, 3, 5, nil].join("\n")) }
+ its(:stderr) { is_expected.to eq([2, 4, 6, nil].join("\n")) }
+ end
+ end
+
+ describe "with default options" do
+ it "echoes only STDERR" do
+ expected = [2, 4, 6].map { |i| "==> #{i}\n" }.join("")
+ expect {
+ described_class.run(command, options)
+ }.to output(expected).to_stdout
+ end
+
+ include_examples("it returns '1 2 3 4 5 6'")
+ end
+
+ describe "with print_stdout" do
+ before do
+ options.merge!(print_stdout: true)
+ end
+
+ it "echoes both STDOUT and STDERR" do
+ (1..6).each do |i|
+ expect {
+ described_class.run(command, options)
+ }.to output(%r{==> #{ i }}).to_stdout
+ end
+ end
+
+ include_examples("it returns '1 2 3 4 5 6'")
+ end
+
+ describe "without print_stderr" do
+ before do
+ options.merge!(print_stderr: false)
+ end
+
+ it "echoes nothing" do
+ expect {
+ described_class.run(command, options)
+ }.to output("").to_stdout
+ end
+
+ include_examples("it returns '1 2 3 4 5 6'")
+ end
+
+ describe "with print_stdout but without print_stderr" do
+ before do
+ options.merge!(print_stdout: true, print_stderr: false)
+ end
+
+ it "echoes only STDOUT" do
+ expected = [1, 3, 5].map { |i| "==> #{i}\n" }.join("")
+ expect {
+ described_class.run(command, options)
+ }.to output(expected).to_stdout
+ end
+
+ include_examples("it returns '1 2 3 4 5 6'")
+ end
+ end
+
+ describe "with a very long STDERR output" do
+ let(:command) { "/bin/bash" }
+ let(:options) {
+ { args: [
+ "-c",
+ "for i in $(seq 1 2 100000); do echo $i; echo $(($i + 1)) >&2; done",
+ ] }
+ }
+
+ it "returns without deadlocking" do
+ wait(10).for {
+ shutup { described_class.run(command, options) }
+ }.to be_a_success
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/spec/cask/underscore_supporting_uri_spec.rb b/Library/Homebrew/cask/spec/cask/underscore_supporting_uri_spec.rb
new file mode 100644
index 000000000..a8756fde0
--- /dev/null
+++ b/Library/Homebrew/cask/spec/cask/underscore_supporting_uri_spec.rb
@@ -0,0 +1,16 @@
+require "spec_helper"
+
+describe Hbc::UnderscoreSupportingURI do
+ describe "parse" do
+ it "works like normal on normal URLs" do
+ uri = Hbc::UnderscoreSupportingURI.parse("http://example.com/TestCask.dmg")
+ expect(uri).to eq(URI("http://example.com/TestCask.dmg"))
+ end
+
+ it "works just fine on URIs with underscores" do
+ uri = Hbc::UnderscoreSupportingURI.parse("http://dl_dir.qq.com/qqfile/qq/QQforMac/QQ_V3.0.0.dmg")
+ expect(uri.host).to include("_")
+ expect(uri.to_s).to eq("http://dl_dir.qq.com/qqfile/qq/QQforMac/QQ_V3.0.0.dmg")
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/spec/cask/verify/checksum_spec.rb b/Library/Homebrew/cask/spec/cask/verify/checksum_spec.rb
new file mode 100644
index 000000000..7209556c9
--- /dev/null
+++ b/Library/Homebrew/cask/spec/cask/verify/checksum_spec.rb
@@ -0,0 +1,95 @@
+require "spec_helper"
+
+describe Hbc::Verify::Checksum do
+ include Sha256Helper
+
+ let(:cask) { double("cask") }
+ let(:downloaded_path) { double("downloaded_path") }
+ let(:verification) { described_class.new(cask, downloaded_path) }
+
+ before do
+ allow(cask).to receive(:sha256).and_return(sha256)
+ end
+
+ around do |example|
+ shutup { example.run }
+ end
+
+ describe ".me?" do
+ subject { described_class.me?(cask) }
+
+ context "sha256 is :no_check" do
+ let(:sha256) { :no_check }
+
+ it { should == false }
+ end
+
+ context "sha256 is nil" do
+ let(:sha256) { nil }
+
+ it { should == true }
+ end
+
+ context "sha256 is empty" do
+ let(:sha256) { "" }
+
+ it { should == true }
+ end
+
+ context "sha256 is a valid shasum" do
+ let(:sha256) { random_sha256 }
+
+ it { should == true }
+ end
+ end
+
+ describe "#verify" do
+ subject { verification.verify }
+
+ let(:computed) { random_sha256 }
+
+ before do
+ allow(verification).to receive(:computed).and_return(computed)
+ end
+
+ context "sha256 matches computed" do
+ let(:sha256) { computed }
+
+ it "does not raise an error" do
+ expect { subject }.to_not raise_error
+ end
+ end
+
+ context "sha256 is :no_check" do
+ let(:sha256) { :no_check }
+
+ it "does not raise an error" do
+ expect { subject }.to_not raise_error
+ end
+ end
+
+ context "sha256 does not match computed" do
+ let(:sha256) { random_sha256 }
+
+ it "raises an error" do
+ expect { subject }.to raise_error(Hbc::CaskSha256MismatchError)
+ end
+ end
+
+ context "sha256 is nil" do
+ let(:sha256) { nil }
+
+ it "raises an error" do
+ expect { subject }.to raise_error(Hbc::CaskSha256MissingError)
+ end
+ end
+
+ context "sha256 is empty" do
+ let(:sha256) { "" }
+
+ it "raises an error" do
+ expect { subject }.to raise_error(Hbc::CaskSha256MissingError)
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/spec/cask/verify_spec.rb b/Library/Homebrew/cask/spec/cask/verify_spec.rb
new file mode 100644
index 000000000..7df77fea1
--- /dev/null
+++ b/Library/Homebrew/cask/spec/cask/verify_spec.rb
@@ -0,0 +1,65 @@
+require "spec_helper"
+
+describe Hbc::Verify do
+ let(:cask) { double("cask") }
+
+ let(:verification_classes) {
+ [
+ applicable_verification_class,
+ inapplicable_verification_class,
+ ]
+ }
+
+ let(:applicable_verification_class) {
+ double("applicable_verification_class", me?: true)
+ }
+
+ let(:inapplicable_verification_class) {
+ double("inapplicable_verification_class", me?: false)
+ }
+
+ before do
+ allow(described_class).to receive(:verifications)
+ .and_return(verification_classes)
+ end
+
+ describe ".for_cask" do
+ subject { described_class.for_cask(cask) }
+
+ it "checks applicability of each verification" do
+ verification_classes.each do |verify_class|
+ expect(verify_class).to receive(:me?).with(cask)
+ end
+ subject
+ end
+
+ it "includes applicable verifications" do
+ expect(subject).to include(applicable_verification_class)
+ end
+
+ it "excludes inapplicable verifications" do
+ expect(subject).to_not include(inapplicable_verification_class)
+ end
+ end
+
+ describe ".all" do
+ let(:downloaded_path) { double("downloaded_path") }
+ let(:applicable_verification) { double("applicable_verification") }
+ let(:inapplicable_verification) { double("inapplicable_verification") }
+
+ subject { described_class.all(cask, downloaded_path) }
+
+ before do
+ allow(applicable_verification_class).to receive(:new)
+ .and_return(applicable_verification)
+ allow(inapplicable_verification_class).to receive(:new)
+ .and_return(inapplicable_verification)
+ end
+
+ it "runs only applicable verifications" do
+ expect(applicable_verification).to receive(:verify)
+ expect(inapplicable_verification).to_not receive(:verify)
+ subject
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/spec/spec_helper.rb b/Library/Homebrew/cask/spec/spec_helper.rb
new file mode 100644
index 000000000..e86e20027
--- /dev/null
+++ b/Library/Homebrew/cask/spec/spec_helper.rb
@@ -0,0 +1,67 @@
+require "pathname"
+require "rspec/its"
+require "rspec/wait"
+
+if ENV["COVERAGE"]
+ require "coveralls"
+ Coveralls.wear_merged!
+end
+
+project_root = Pathname.new(File.expand_path("../..", __FILE__))
+
+# add Homebrew to load path
+$LOAD_PATH.unshift(File.expand_path("#{ENV['HOMEBREW_REPOSITORY']}/Library/Homebrew"))
+
+require "global"
+require "extend/pathname"
+
+# add Homebrew-Cask to load path
+$LOAD_PATH.push(project_root.join("lib").to_s)
+
+# force some environment variables
+ENV["HOMEBREW_NO_EMOJI"] = "1"
+ENV["HOMEBREW_CASK_OPTS"] = nil
+
+Dir["#{project_root}/spec/support/*.rb"].each(&method(:require))
+
+# from Homebrew. Provides expects method.
+require "mocha/api"
+
+require "hbc"
+
+class Hbc::TestCask < Hbc::Cask; end
+
+TEST_TMPDIR = Dir.mktmpdir("homebrew_cask_tests")
+at_exit do
+ FileUtils.remove_entry(TEST_TMPDIR)
+end
+
+# override Homebrew locations
+Hbc.homebrew_prefix = Pathname.new(TEST_TMPDIR).join("prefix")
+Hbc.homebrew_repository = Hbc.homebrew_prefix
+Hbc.binarydir = Hbc.homebrew_prefix.join("binarydir", "bin")
+Hbc.appdir = Pathname.new(TEST_TMPDIR).join("appdir")
+
+# Override Tap::TAP_DIRECTORY to use our test Tap directory.
+class Tap
+ send(:remove_const, :TAP_DIRECTORY)
+ TAP_DIRECTORY = Hbc.homebrew_repository.join("Library", "Taps")
+end
+
+Hbc.default_tap = Tap.fetch("caskroom", "speccasks")
+Hbc.default_tap.path.dirname.mkpath
+
+# also jack in some test Casks
+FileUtils.ln_s project_root.join("spec", "support"), Tap::TAP_DIRECTORY.join("caskroom", "homebrew-speccasks")
+
+# create cache directory
+Hbc.homebrew_cache = Pathname.new(TEST_TMPDIR).join("cache")
+Hbc.cache.mkpath
+
+# our own testy caskroom
+Hbc.caskroom = Hbc.homebrew_prefix.join("TestCaskroom")
+
+RSpec.configure do |config|
+ config.order = :random
+ config.include ShutupHelper
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/.rubocop.yml b/Library/Homebrew/cask/spec/support/Casks/.rubocop.yml
new file mode 120000
index 000000000..ee5c2b948
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/.rubocop.yml
@@ -0,0 +1 @@
+../../../Casks/.rubocop.yml \ No newline at end of file
diff --git a/Library/Homebrew/cask/spec/support/Casks/appcast-checkpoint-sha256-for-empty-string.rb b/Library/Homebrew/cask/spec/support/Casks/appcast-checkpoint-sha256-for-empty-string.rb
new file mode 100644
index 000000000..f40f244f2
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/appcast-checkpoint-sha256-for-empty-string.rb
@@ -0,0 +1,4 @@
+test_cask 'appcast-checkpoint-sha256-for-empty-string' do
+ appcast 'http://localhost/appcast.xml',
+ checkpoint: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/appcast-invalid-checkpoint.rb b/Library/Homebrew/cask/spec/support/Casks/appcast-invalid-checkpoint.rb
new file mode 100644
index 000000000..e182c2389
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/appcast-invalid-checkpoint.rb
@@ -0,0 +1,4 @@
+test_cask 'appcast-invalid-checkpoint' do
+ appcast 'http://localhost/appcast.xml',
+ checkpoint: 'not a valid shasum'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/appcast-missing-checkpoint.rb b/Library/Homebrew/cask/spec/support/Casks/appcast-missing-checkpoint.rb
new file mode 100644
index 000000000..5ab2c0665
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/appcast-missing-checkpoint.rb
@@ -0,0 +1,3 @@
+test_cask 'appcast-missing-checkpoint' do
+ appcast 'http://localhost/appcast.xml'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/appcast-valid-checkpoint.rb b/Library/Homebrew/cask/spec/support/Casks/appcast-valid-checkpoint.rb
new file mode 100644
index 000000000..96d7edbba
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/appcast-valid-checkpoint.rb
@@ -0,0 +1,4 @@
+test_cask 'appcast-valid-checkpoint' do
+ appcast 'http://localhost/appcast.xml',
+ checkpoint: 'd5b2dfbef7ea28c25f7a77cd7fa14d013d82b626db1d82e00e25822464ba19e2'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/booby-trap.rb b/Library/Homebrew/cask/spec/support/Casks/booby-trap.rb
new file mode 100644
index 000000000..21bd97952
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/booby-trap.rb
@@ -0,0 +1,8 @@
+cask 'booby-trap' do
+ version '0.0.7'
+
+ url do
+ # to be lazily evaluated
+ fail 'Boom'
+ end
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/generic-artifact-absolute-target.rb b/Library/Homebrew/cask/spec/support/Casks/generic-artifact-absolute-target.rb
new file mode 100644
index 000000000..475fb055f
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/generic-artifact-absolute-target.rb
@@ -0,0 +1,3 @@
+test_cask 'generic-artifact-absolute-target' do
+ artifact 'Caffeine.app', target: "#{Hbc.appdir}/Caffeine.app"
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/generic-artifact-no-target.rb b/Library/Homebrew/cask/spec/support/Casks/generic-artifact-no-target.rb
new file mode 100644
index 000000000..f7657dbb5
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/generic-artifact-no-target.rb
@@ -0,0 +1,3 @@
+test_cask 'generic-artifact-no-target' do
+ artifact 'Caffeine.app'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/generic-artifact-relative-target.rb b/Library/Homebrew/cask/spec/support/Casks/generic-artifact-relative-target.rb
new file mode 100644
index 000000000..f97441751
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/generic-artifact-relative-target.rb
@@ -0,0 +1,3 @@
+test_cask 'generic-artifact-relative-target' do
+ artifact 'Caffeine.app', target: 'Caffeine.app'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/invalid-sha256.rb b/Library/Homebrew/cask/spec/support/Casks/invalid-sha256.rb
new file mode 100644
index 000000000..aac00f495
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/invalid-sha256.rb
@@ -0,0 +1,4 @@
+test_cask 'invalid-sha256' do
+ version '1.2.3'
+ sha256 'not a valid shasum'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/missing-homepage.rb b/Library/Homebrew/cask/spec/support/Casks/missing-homepage.rb
new file mode 100644
index 000000000..ff924541d
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/missing-homepage.rb
@@ -0,0 +1,5 @@
+test_cask 'missing-homepage' do
+ version '1.2.3'
+
+ url 'http://localhost/something.dmg'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/missing-license.rb b/Library/Homebrew/cask/spec/support/Casks/missing-license.rb
new file mode 100644
index 000000000..30f3791c7
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/missing-license.rb
@@ -0,0 +1,5 @@
+test_cask 'missing-license' do
+ version '1.2.3'
+
+ url 'http://localhost/something.dmg'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/missing-name.rb b/Library/Homebrew/cask/spec/support/Casks/missing-name.rb
new file mode 100644
index 000000000..a5265b379
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/missing-name.rb
@@ -0,0 +1,5 @@
+test_cask 'missing-name' do
+ version '1.2.3'
+
+ url 'http://localhost/something.dmg'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/missing-sha256.rb b/Library/Homebrew/cask/spec/support/Casks/missing-sha256.rb
new file mode 100644
index 000000000..7f8027907
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/missing-sha256.rb
@@ -0,0 +1,5 @@
+test_cask 'missing-sha256' do
+ version '1.2.3'
+
+ url 'http://localhost/something.dmg'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/missing-url.rb b/Library/Homebrew/cask/spec/support/Casks/missing-url.rb
new file mode 100644
index 000000000..1b3e76b9c
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/missing-url.rb
@@ -0,0 +1,5 @@
+test_cask 'missing-url' do
+ version '1.2.3'
+
+ homepage 'http://example.com'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/missing-version.rb b/Library/Homebrew/cask/spec/support/Casks/missing-version.rb
new file mode 100644
index 000000000..da2160bce
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/missing-version.rb
@@ -0,0 +1,4 @@
+test_cask 'missing-version' do
+ url 'http://localhost/something.dmg'
+ homepage 'http://example.com'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/osdn-correct-url-format.rb b/Library/Homebrew/cask/spec/support/Casks/osdn-correct-url-format.rb
new file mode 100644
index 000000000..da6ff0fcd
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/osdn-correct-url-format.rb
@@ -0,0 +1,6 @@
+test_cask 'osdn-correct-url-format' do
+ version '1.2.3'
+
+ url 'http://user.dl.osdn.jp/something/id/Something-1.2.3.dmg'
+ homepage 'http://osdn.jp/projects/something/'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/osdn-incorrect-url-format.rb b/Library/Homebrew/cask/spec/support/Casks/osdn-incorrect-url-format.rb
new file mode 100644
index 000000000..8400159a1
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/osdn-incorrect-url-format.rb
@@ -0,0 +1,6 @@
+test_cask 'osdn-incorrect-url-format' do
+ version '1.2.3'
+
+ url 'http://osdn.jp/projects/something/files/Something-1.2.3.dmg/download'
+ homepage 'http://osdn.jp/projects/something/'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/sha256-for-empty-string.rb b/Library/Homebrew/cask/spec/support/Casks/sha256-for-empty-string.rb
new file mode 100644
index 000000000..b97764071
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/sha256-for-empty-string.rb
@@ -0,0 +1,4 @@
+test_cask 'sha256-for-empty-string' do
+ version '1.2.3'
+ sha256 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/sourceforge-correct-url-format.rb b/Library/Homebrew/cask/spec/support/Casks/sourceforge-correct-url-format.rb
new file mode 100644
index 000000000..41ef73500
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/sourceforge-correct-url-format.rb
@@ -0,0 +1,6 @@
+test_cask 'sourceforge-correct-url-format' do
+ version '1.2.3'
+
+ url 'https://downloads.sourceforge.net/something/Something-1.2.3.dmg'
+ homepage 'https://sourceforge.net/projects/something/'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/sourceforge-incorrect-url-format.rb b/Library/Homebrew/cask/spec/support/Casks/sourceforge-incorrect-url-format.rb
new file mode 100644
index 000000000..27b5490b7
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/sourceforge-incorrect-url-format.rb
@@ -0,0 +1,6 @@
+test_cask 'sourceforge-incorrect-url-format' do
+ version '1.2.3'
+
+ url 'http://sourceforge.net/projects/something/files/Something-1.2.3.dmg/download'
+ homepage 'http://sourceforge.net/projects/something/'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/sourceforge-version-latest-correct-url-format.rb b/Library/Homebrew/cask/spec/support/Casks/sourceforge-version-latest-correct-url-format.rb
new file mode 100644
index 000000000..d9546c5e1
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/sourceforge-version-latest-correct-url-format.rb
@@ -0,0 +1,6 @@
+test_cask 'sourceforge-version-latest-correct-url-format' do
+ version :latest
+
+ url 'https://sourceforge.net/projects/something/files/latest/download'
+ homepage 'https://sourceforge.net/projects/something/'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/version-latest-string.rb b/Library/Homebrew/cask/spec/support/Casks/version-latest-string.rb
new file mode 100644
index 000000000..3b4723f45
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/version-latest-string.rb
@@ -0,0 +1,4 @@
+test_cask 'version-latest-string' do
+ version 'latest'
+ sha256 :no_check
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/version-latest-with-checksum.rb b/Library/Homebrew/cask/spec/support/Casks/version-latest-with-checksum.rb
new file mode 100644
index 000000000..8dbca1a69
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/version-latest-with-checksum.rb
@@ -0,0 +1,4 @@
+test_cask 'version-latest-with-checksum' do
+ version :latest
+ sha256 '9203c30951f9aab41ac294bbeb1dcef7bed401ff0b353dcb34d68af32ea51853'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/with-binary.rb b/Library/Homebrew/cask/spec/support/Casks/with-binary.rb
new file mode 100644
index 000000000..a06787125
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/with-binary.rb
@@ -0,0 +1,10 @@
+test_cask 'with-binary' do
+ version '1.2.3'
+ sha256 'd5b2dfbef7ea28c25f7a77cd7fa14d013d82b626db1d82e00e25822464ba19e2'
+
+ url FileHelper.local_binary_url('AppWithBinary.zip')
+ homepage 'http://example.com/with-binary'
+
+ app 'App.app'
+ binary 'binary'
+end
diff --git a/Library/Homebrew/cask/spec/support/Casks/with-embedded-binary.rb b/Library/Homebrew/cask/spec/support/Casks/with-embedded-binary.rb
new file mode 100644
index 000000000..796f28c78
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/Casks/with-embedded-binary.rb
@@ -0,0 +1,10 @@
+test_cask 'with-embedded-binary' do
+ version '1.2.3'
+ sha256 'fe052d3e77d92676775fd916ddb8942e72a565b844ea7f6d055474c99bb4e47b'
+
+ url FileHelper.local_binary_url('AppWithEmbeddedBinary.zip')
+ homepage 'http://example.com/with-binary'
+
+ app 'App.app'
+ binary "#{appdir}/App.app/Contents/MacOS/App/binary"
+end
diff --git a/Library/Homebrew/cask/spec/support/audit_matchers.rb b/Library/Homebrew/cask/spec/support/audit_matchers.rb
new file mode 100644
index 000000000..fc1e0e876
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/audit_matchers.rb
@@ -0,0 +1,39 @@
+module AuditMatchers
+ extend RSpec::Matchers::DSL
+
+ 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
+
+ def include_msg?(messages, msg)
+ if msg.is_a?(Regexp)
+ Array(messages).any? { |m| m =~ msg }
+ else
+ Array(messages).include?(msg)
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/spec/support/binaries/AppWithBinary.zip b/Library/Homebrew/cask/spec/support/binaries/AppWithBinary.zip
new file mode 100644
index 000000000..4a5b318ba
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/binaries/AppWithBinary.zip
Binary files differ
diff --git a/Library/Homebrew/cask/spec/support/binaries/AppWithEmbeddedBinary.zip b/Library/Homebrew/cask/spec/support/binaries/AppWithEmbeddedBinary.zip
new file mode 100644
index 000000000..7c708038c
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/binaries/AppWithEmbeddedBinary.zip
Binary files differ
diff --git a/Library/Homebrew/cask/spec/support/env_helper.rb b/Library/Homebrew/cask/spec/support/env_helper.rb
new file mode 100644
index 000000000..0a302ef45
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/env_helper.rb
@@ -0,0 +1,16 @@
+module EnvHelper
+ class << self
+ def with_env_var(key, val)
+ was_defined = ENV.key? "key"
+ old_value = ENV["key"]
+ ENV[key] = val
+ yield
+ ensure
+ if was_defined
+ ENV[key] = old_value
+ else
+ ENV.delete(key)
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/spec/support/expectations_hash_helper.rb b/Library/Homebrew/cask/spec/support/expectations_hash_helper.rb
new file mode 100644
index 000000000..8d386767d
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/expectations_hash_helper.rb
@@ -0,0 +1,10 @@
+module ExpectationsHashHelper
+ shared_examples "expectations hash" do |input_name, expectations|
+ expectations.each do |input_value, expected_output|
+ context "when #{input_name} is #{input_value.inspect}" do
+ let(input_name.to_sym) { input_value }
+ it { should == expected_output }
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/spec/support/file_helper.rb b/Library/Homebrew/cask/spec/support/file_helper.rb
new file mode 100644
index 000000000..8eb78f759
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/file_helper.rb
@@ -0,0 +1,16 @@
+module FileHelper
+ class << self
+ def local_binary_path(name)
+ File.expand_path(File.join(File.dirname(__FILE__), "binaries", name))
+ end
+
+ def local_binary_url(name)
+ "file://" + local_binary_path(name)
+ end
+
+ def valid_alias?(candidate)
+ return false unless candidate.symlink?
+ candidate.readlink.exist?
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/spec/support/install_helper.rb b/Library/Homebrew/cask/spec/support/install_helper.rb
new file mode 100644
index 000000000..c8023c66b
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/install_helper.rb
@@ -0,0 +1,10 @@
+module InstallHelper
+ class << self
+ def install_without_artifacts(cask)
+ Hbc::Installer.new(cask).tap do |i|
+ i.download
+ i.extract_primary_container
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/spec/support/kernel_at_exit_hacks.rb b/Library/Homebrew/cask/spec/support/kernel_at_exit_hacks.rb
new file mode 100644
index 000000000..b5c84869b
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/kernel_at_exit_hacks.rb
@@ -0,0 +1,13 @@
+module Kernel
+ alias real_at_exit at_exit
+
+ def at_exit(&block)
+ real_at_exit(&block) unless ENV["DISABLE_AT_EXIT"]
+ end
+
+ def with_disabled_at_exit
+ ENV["DISABLE_AT_EXIT"] = "1"
+ yield
+ ENV.delete("DISABLE_AT_EXIT")
+ end
+end
diff --git a/Library/Homebrew/cask/spec/support/sha256_helper.rb b/Library/Homebrew/cask/spec/support/sha256_helper.rb
new file mode 100644
index 000000000..14f2a2519
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/sha256_helper.rb
@@ -0,0 +1,8 @@
+require"digest"
+
+module Sha256Helper
+ def random_sha256
+ seed = "--#{rand(10_000)}--#{Time.now}--"
+ Digest::SHA2.hexdigest(seed)
+ end
+end
diff --git a/Library/Homebrew/cask/spec/support/shutup_helper.rb b/Library/Homebrew/cask/spec/support/shutup_helper.rb
new file mode 100644
index 000000000..98dde01a6
--- /dev/null
+++ b/Library/Homebrew/cask/spec/support/shutup_helper.rb
@@ -0,0 +1,18 @@
+module ShutupHelper
+ def shutup
+ if ENV.key?("VERBOSE_TESTS")
+ yield
+ else
+ begin
+ tmperr = $stderr.clone
+ tmpout = $stdout.clone
+ $stderr.reopen "/dev/null", "w"
+ $stdout.reopen "/dev/null", "w"
+ yield
+ ensure
+ $stderr.reopen tmperr
+ $stdout.reopen tmpout
+ end
+ end
+ end
+end