aboutsummaryrefslogtreecommitdiffstats
path: root/Library/Homebrew/test/cask/artifact
diff options
context:
space:
mode:
authorMarkus Reiter2017-03-05 06:31:36 +0100
committerMarkus Reiter2017-03-05 23:08:14 +0100
commit9fc6c7b2be300ff35dc52d80f4dc38d36d52ddc2 (patch)
tree43e99a683329471c1dc965dcc92daccb57df7e8d /Library/Homebrew/test/cask/artifact
parent67ec76d1492fbb03959a782a85c4fb985d6a5884 (diff)
downloadbrew-9fc6c7b2be300ff35dc52d80f4dc38d36d52ddc2.tar.bz2
Move Cask specs into `brew tests`.
Diffstat (limited to 'Library/Homebrew/test/cask/artifact')
-rw-r--r--Library/Homebrew/test/cask/artifact/alt_target_spec.rb77
-rw-r--r--Library/Homebrew/test/cask/artifact/app_spec.rb243
-rw-r--r--Library/Homebrew/test/cask/artifact/binary_spec.rb90
-rw-r--r--Library/Homebrew/test/cask/artifact/generic_artifact_spec.rb45
-rw-r--r--Library/Homebrew/test/cask/artifact/nested_container_spec.rb15
-rw-r--r--Library/Homebrew/test/cask/artifact/pkg_spec.rb69
-rw-r--r--Library/Homebrew/test/cask/artifact/postflight_block_spec.rb39
-rw-r--r--Library/Homebrew/test/cask/artifact/preflight_block_spec.rb39
-rw-r--r--Library/Homebrew/test/cask/artifact/suite_spec.rb47
-rw-r--r--Library/Homebrew/test/cask/artifact/two_apps_correct_spec.rb91
-rw-r--r--Library/Homebrew/test/cask/artifact/two_apps_incorrect_spec.rb9
-rw-r--r--Library/Homebrew/test/cask/artifact/uninstall_no_zap_spec.rb19
-rw-r--r--Library/Homebrew/test/cask/artifact/uninstall_spec.rb351
-rw-r--r--Library/Homebrew/test/cask/artifact/zap_spec.rb352
14 files changed, 1486 insertions, 0 deletions
diff --git a/Library/Homebrew/test/cask/artifact/alt_target_spec.rb b/Library/Homebrew/test/cask/artifact/alt_target_spec.rb
new file mode 100644
index 000000000..9bcdd27a1
--- /dev/null
+++ b/Library/Homebrew/test/cask/artifact/alt_target_spec.rb
@@ -0,0 +1,77 @@
+describe Hbc::Artifact::App, :cask do
+ describe "activate to alternate target" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-alt-target.rb") }
+
+ let(:install_phase) {
+ -> { Hbc::Artifact::App.new(cask).install_phase }
+ }
+
+ let(:source_path) { cask.staged_path.join("Caffeine.app") }
+ let(:target_path) { Hbc.appdir.join("AnotherName.app") }
+
+ before do
+ InstallHelper.install_without_artifacts(cask)
+ end
+
+ it "installs the given apps using the proper target directory" do
+ expect(source_path).to be_a_directory
+ expect(target_path).not_to exist
+
+ shutup do
+ install_phase.call
+ end
+
+ expect(target_path).to be_a_directory
+ expect(source_path).not_to exist
+ end
+
+ describe "when app is in a subdirectory" do
+ let(:cask) {
+ Hbc::Cask.new("subdir") do
+ url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
+ homepage "http://example.com/local-caffeine"
+ version "1.2.3"
+ sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94"
+ app "subdir/Caffeine.app", target: "AnotherName.app"
+ end
+ }
+
+ it "installs the given apps using the proper target directory" do
+ appsubdir = cask.staged_path.join("subdir").tap(&:mkpath)
+ FileUtils.mv(source_path, appsubdir)
+
+ shutup do
+ install_phase.call
+ end
+
+ expect(target_path).to be_a_directory
+ expect(appsubdir.join("Caffeine.app")).not_to exist
+ end
+ end
+
+ it "only uses apps when they are specified" do
+ staged_app_copy = source_path.sub("Caffeine.app", "Caffeine Deluxe.app")
+ FileUtils.cp_r source_path, staged_app_copy
+
+ shutup do
+ install_phase.call
+ end
+
+ expect(target_path).to be_a_directory
+ expect(source_path).not_to exist
+
+ expect(Hbc.appdir.join("Caffeine Deluxe.app")).not_to exist
+ expect(cask.staged_path.join("Caffeine Deluxe.app")).to be_a_directory
+ end
+
+ it "avoids clobbering an existing app by moving over it" do
+ target_path.mkpath
+
+ expect(install_phase).to raise_error(Hbc::CaskError, "It seems there is already an App at '#{target_path}'.")
+
+ expect(source_path).to be_a_directory
+ expect(target_path).to be_a_directory
+ expect(File.identical?(source_path, target_path)).to be false
+ end
+ end
+end
diff --git a/Library/Homebrew/test/cask/artifact/app_spec.rb b/Library/Homebrew/test/cask/artifact/app_spec.rb
new file mode 100644
index 000000000..bfd2d5cd4
--- /dev/null
+++ b/Library/Homebrew/test/cask/artifact/app_spec.rb
@@ -0,0 +1,243 @@
+describe Hbc::Artifact::App, :cask do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/local-caffeine.rb") }
+ let(:command) { Hbc::SystemCommand }
+ let(:force) { false }
+ let(:app) { Hbc::Artifact::App.new(cask, command: command, force: force) }
+
+ let(:source_path) { cask.staged_path.join("Caffeine.app") }
+ let(:target_path) { Hbc.appdir.join("Caffeine.app") }
+
+ let(:install_phase) { -> { app.install_phase } }
+ let(:uninstall_phase) { -> { app.uninstall_phase } }
+
+ before(:each) do
+ InstallHelper.install_without_artifacts(cask)
+ end
+
+ describe "install_phase" do
+ it "installs the given app using the proper target directory" do
+ shutup do
+ install_phase.call
+ end
+
+ expect(target_path).to be_a_directory
+ expect(source_path).not_to exist
+ end
+
+ describe "when app is in a subdirectory" do
+ let(:cask) {
+ Hbc::Cask.new("subdir") do
+ url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
+ homepage "http://example.com/local-caffeine"
+ version "1.2.3"
+ sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94"
+ app "subdir/Caffeine.app"
+ end
+ }
+
+ it "installs the given app using the proper target directory" do
+ appsubdir = cask.staged_path.join("subdir").tap(&:mkpath)
+ FileUtils.mv(source_path, appsubdir)
+
+ shutup do
+ install_phase.call
+ end
+
+ expect(target_path).to be_a_directory
+ expect(appsubdir.join("Caffeine.app")).not_to exist
+ end
+ end
+
+ it "only uses apps when they are specified" do
+ staged_app_copy = source_path.sub("Caffeine.app", "Caffeine Deluxe.app")
+ FileUtils.cp_r source_path, staged_app_copy
+
+ shutup do
+ install_phase.call
+ end
+
+ expect(target_path).to be_a_directory
+ expect(source_path).not_to exist
+
+ expect(Hbc.appdir.join("Caffeine Deluxe.app")).not_to exist
+ expect(cask.staged_path.join("Caffeine Deluxe.app")).to exist
+ end
+
+ describe "when the target already exists" do
+ before(:each) do
+ target_path.mkpath
+ end
+
+ it "avoids clobbering an existing app" do
+ expect(install_phase).to raise_error(Hbc::CaskError, "It seems there is already an App at '#{target_path}'.")
+
+ expect(source_path).to be_a_directory
+ expect(target_path).to be_a_directory
+ expect(File.identical?(source_path, target_path)).to be false
+
+ contents_path = target_path.join("Contents/Info.plist")
+ expect(contents_path).not_to exist
+ end
+
+ describe "given the force option" do
+ let(:force) { true }
+
+ before(:each) do
+ allow(Hbc::Utils).to receive(:current_user).and_return("fake_user")
+ end
+
+ describe "target is both writable and user-owned" do
+ it "overwrites the existing app" do
+ stdout = <<-EOS.undent
+ ==> Removing App: '#{target_path}'
+ ==> Moving App 'Caffeine.app' to '#{target_path}'
+ EOS
+
+ stderr = <<-EOS.undent
+ Warning: It seems there is already an App at '#{target_path}'; overwriting.
+ EOS
+
+ expect {
+ expect(install_phase).to output(stdout).to_stdout
+ }.to output(stderr).to_stderr
+
+ expect(source_path).not_to exist
+ expect(target_path).to be_a_directory
+
+ contents_path = target_path.join("Contents/Info.plist")
+ expect(contents_path).to exist
+ end
+ end
+
+ describe "target is user-owned but contains read-only files" do
+ before(:each) do
+ system "/usr/bin/touch", "--", "#{target_path}/foo"
+ system "/bin/chmod", "--", "0555", target_path
+ end
+
+ it "overwrites the existing app" do
+ expect(command).to receive(:run).with("/bin/chmod", args: ["-R", "--", "u+rwx", target_path], must_succeed: false)
+ .and_call_original
+ expect(command).to receive(:run).with("/bin/chmod", args: ["-R", "-N", target_path], must_succeed: false)
+ .and_call_original
+ expect(command).to receive(:run).with("/usr/bin/chflags", args: ["-R", "--", "000", target_path], must_succeed: false)
+ .and_call_original
+
+ stdout = <<-EOS.undent
+ ==> Removing App: '#{target_path}'
+ ==> Moving App 'Caffeine.app' to '#{target_path}'
+ EOS
+
+ stderr = <<-EOS.undent
+ Warning: It seems there is already an App at '#{target_path}'; overwriting.
+ EOS
+
+ expect {
+ expect(install_phase).to output(stdout).to_stdout
+ }.to output(stderr).to_stderr
+
+ expect(source_path).not_to exist
+ expect(target_path).to be_a_directory
+
+ contents_path = target_path.join("Contents/Info.plist")
+ expect(contents_path).to exist
+ end
+
+ after(:each) do
+ system "/bin/chmod", "--", "0755", target_path
+ end
+ end
+ end
+ end
+
+ describe "when the target is a broken symlink" do
+ let(:deleted_path) { cask.staged_path.join("Deleted.app") }
+
+ before(:each) do
+ deleted_path.mkdir
+ File.symlink(deleted_path, target_path)
+ deleted_path.rmdir
+ end
+
+ it "leaves the target alone" do
+ expect(install_phase).to raise_error(Hbc::CaskError, "It seems there is already an App at '#{target_path}'.")
+ expect(target_path).to be_a_symlink
+ end
+
+ describe "given the force option" do
+ let(:force) { true }
+
+ it "overwrites the existing app" do
+ stdout = <<-EOS.undent
+ ==> Removing App: '#{target_path}'
+ ==> Moving App 'Caffeine.app' to '#{target_path}'
+ EOS
+
+ stderr = <<-EOS.undent
+ Warning: It seems there is already an App at '#{target_path}'; overwriting.
+ EOS
+
+ expect {
+ expect(install_phase).to output(stdout).to_stdout
+ }.to output(stderr).to_stderr
+
+ expect(source_path).not_to exist
+ expect(target_path).to be_a_directory
+
+ contents_path = target_path.join("Contents/Info.plist")
+ expect(contents_path).to exist
+ end
+ end
+ end
+
+ it "gives a warning if the source doesn't exist" do
+ source_path.rmtree
+
+ message = "It seems the App source is not there: '#{source_path}'"
+
+ expect(install_phase).to raise_error(Hbc::CaskError, message)
+ end
+ end
+
+ describe "uninstall_phase" do
+ it "deletes managed apps" do
+ shutup do
+ install_phase.call
+ end
+
+ expect(target_path).to exist
+
+ shutup do
+ uninstall_phase.call
+ end
+
+ expect(target_path).not_to exist
+ end
+ end
+
+ describe "summary" do
+ let(:description) { app.summary[:english_description] }
+ let(:contents) { app.summary[:contents] }
+
+ it "returns the correct english_description" do
+ expect(description).to eq("Apps")
+ end
+
+ describe "app is correctly installed" do
+ it "returns the path to the app" do
+ shutup do
+ install_phase.call
+ end
+
+ expect(contents).to eq(["#{target_path} (#{target_path.abv})"])
+ end
+ end
+
+ describe "app is missing" do
+ it "returns a warning and the supposed path to the app" do
+ expect(contents.size).to eq(1)
+ expect(contents[0]).to match(/.*Missing App.*: #{target_path}/)
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/test/cask/artifact/binary_spec.rb b/Library/Homebrew/test/cask/artifact/binary_spec.rb
new file mode 100644
index 000000000..1b26773ca
--- /dev/null
+++ b/Library/Homebrew/test/cask/artifact/binary_spec.rb
@@ -0,0 +1,90 @@
+describe Hbc::Artifact::Binary, :cask do
+ let(:cask) {
+ Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-binary.rb").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(expected_path).to be_a_symlink
+ expect(expected_path.readlink).to exist
+ end
+
+ it "avoids clobbering an existing binary by linking over it" do
+ FileUtils.touch expected_path
+
+ expect {
+ shutup do
+ Hbc::Artifact::Binary.new(cask).install_phase
+ end
+ }.to raise_error(Hbc::CaskError)
+
+ expect(expected_path).not_to 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::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-embedded-binary.rb").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(expected_path).to be_a_symlink
+ expect(expected_path.readlink).to exist
+ end
+ end
+end
diff --git a/Library/Homebrew/test/cask/artifact/generic_artifact_spec.rb b/Library/Homebrew/test/cask/artifact/generic_artifact_spec.rb
new file mode 100644
index 000000000..b383e2d4e
--- /dev/null
+++ b/Library/Homebrew/test/cask/artifact/generic_artifact_spec.rb
@@ -0,0 +1,45 @@
+describe Hbc::Artifact::Artifact, :cask do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-generic-artifact.rb") }
+
+ let(:install_phase) {
+ -> { Hbc::Artifact::Artifact.new(cask).install_phase }
+ }
+
+ let(:source_path) { cask.staged_path.join("Caffeine.app") }
+ let(:target_path) { Hbc.appdir.join("Caffeine.app") }
+
+ before do
+ InstallHelper.install_without_artifacts(cask)
+ end
+
+ describe "with no target" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-generic-artifact-no-target.rb") }
+
+ it "fails to install with no target" do
+ expect(install_phase).to raise_error(Hbc::CaskInvalidError)
+ end
+ end
+
+ it "moves the artifact to the proper directory" do
+ shutup do
+ install_phase.call
+ end
+
+ expect(target_path).to be_a_directory
+ expect(source_path).not_to exist
+ end
+
+ it "avoids clobbering an existing artifact" do
+ target_path.mkpath
+
+ expect {
+ shutup do
+ install_phase.call
+ end
+ }.to raise_error(Hbc::CaskError)
+
+ expect(source_path).to be_a_directory
+ expect(target_path).to be_a_directory
+ expect(File.identical?(source_path, target_path)).to be false
+ end
+end
diff --git a/Library/Homebrew/test/cask/artifact/nested_container_spec.rb b/Library/Homebrew/test/cask/artifact/nested_container_spec.rb
new file mode 100644
index 000000000..3e9a549ea
--- /dev/null
+++ b/Library/Homebrew/test/cask/artifact/nested_container_spec.rb
@@ -0,0 +1,15 @@
+describe Hbc::Artifact::NestedContainer, :cask do
+ describe "install" do
+ it "extracts the specified paths as containers" do
+ cask = Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/nested-app.rb").tap do |c|
+ InstallHelper.install_without_artifacts(c)
+ end
+
+ shutup do
+ Hbc::Artifact::NestedContainer.new(cask).install_phase
+ end
+
+ expect(cask.staged_path.join("MyNestedApp.app")).to be_a_directory
+ end
+ end
+end
diff --git a/Library/Homebrew/test/cask/artifact/pkg_spec.rb b/Library/Homebrew/test/cask/artifact/pkg_spec.rb
new file mode 100644
index 000000000..249439900
--- /dev/null
+++ b/Library/Homebrew/test/cask/artifact/pkg_spec.rb
@@ -0,0 +1,69 @@
+describe Hbc::Artifact::Pkg, :cask do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-installable.rb") }
+ let(:fake_system_command) { class_double(Hbc::SystemCommand) }
+
+ before(:each) do
+ shutup do
+ InstallHelper.install_without_artifacts(cask)
+ end
+ end
+
+ describe "install_phase" do
+ it "runs the system installer on the specified pkgs" do
+ pkg = Hbc::Artifact::Pkg.new(cask, command: fake_system_command)
+
+ expect(fake_system_command).to receive(:run!).with(
+ "/usr/sbin/installer",
+ args: ["-pkg", cask.staged_path.join("MyFancyPkg", "Fancy.pkg"), "-target", "/"],
+ sudo: true,
+ print_stdout: true,
+ )
+
+ shutup do
+ pkg.install_phase
+ end
+ end
+ end
+
+ describe "choices" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-choices.rb") }
+
+ it "passes the choice changes xml to the system installer" do
+ pkg = Hbc::Artifact::Pkg.new(cask, command: fake_system_command)
+
+ file = double(path: Pathname.new("/tmp/choices.xml"))
+
+ expect(file).to receive(:write).with(<<-EOS.undent)
+ <?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+ <plist version="1.0">
+ <array>
+ \t<dict>
+ \t\t<key>attributeSetting</key>
+ \t\t<integer>1</integer>
+ \t\t<key>choiceAttribute</key>
+ \t\t<string>selected</string>
+ \t\t<key>choiceIdentifier</key>
+ \t\t<string>choice1</string>
+ \t</dict>
+ </array>
+ </plist>
+ EOS
+
+ expect(file).to receive(:close)
+ expect(file).to receive(:unlink)
+ expect(Tempfile).to receive(:open).and_yield(file)
+
+ expect(fake_system_command).to receive(:run!).with(
+ "/usr/sbin/installer",
+ args: ["-pkg", cask.staged_path.join("MyFancyPkg", "Fancy.pkg"), "-target", "/", "-applyChoiceChangesXML", cask.staged_path.join("/tmp/choices.xml")],
+ sudo: true,
+ print_stdout: true,
+ )
+
+ shutup do
+ pkg.install_phase
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/test/cask/artifact/postflight_block_spec.rb b/Library/Homebrew/test/cask/artifact/postflight_block_spec.rb
new file mode 100644
index 000000000..51b1431f0
--- /dev/null
+++ b/Library/Homebrew/test/cask/artifact/postflight_block_spec.rb
@@ -0,0 +1,39 @@
+describe Hbc::Artifact::PostflightBlock, :cask do
+ describe "install_phase" do
+ it "calls the specified block after installing, passing a Cask mini-dsl" do
+ called = false
+ yielded_arg = nil
+
+ cask = Hbc::Cask.new("with-postflight") do
+ postflight do |c|
+ called = true
+ yielded_arg = c
+ end
+ end
+
+ described_class.new(cask).install_phase
+
+ expect(called).to be true
+ expect(yielded_arg).to be_kind_of(Hbc::DSL::Postflight)
+ end
+ end
+
+ describe "uninstall_phase" do
+ it "calls the specified block after uninstalling, passing a Cask mini-dsl" do
+ called = false
+ yielded_arg = nil
+
+ cask = Hbc::Cask.new("with-uninstall-postflight") do
+ uninstall_postflight do |c|
+ called = true
+ yielded_arg = c
+ end
+ end
+
+ described_class.new(cask).uninstall_phase
+
+ expect(called).to be true
+ expect(yielded_arg).to be_kind_of(Hbc::DSL::UninstallPostflight)
+ end
+ end
+end
diff --git a/Library/Homebrew/test/cask/artifact/preflight_block_spec.rb b/Library/Homebrew/test/cask/artifact/preflight_block_spec.rb
new file mode 100644
index 000000000..b13c4ab9d
--- /dev/null
+++ b/Library/Homebrew/test/cask/artifact/preflight_block_spec.rb
@@ -0,0 +1,39 @@
+describe Hbc::Artifact::PreflightBlock, :cask do
+ describe "install_phase" do
+ it "calls the specified block before installing, passing a Cask mini-dsl" do
+ called = false
+ yielded_arg = nil
+
+ cask = Hbc::Cask.new("with-preflight") do
+ preflight do |c|
+ called = true
+ yielded_arg = c
+ end
+ end
+
+ described_class.new(cask).install_phase
+
+ expect(called).to be true
+ expect(yielded_arg).to be_kind_of Hbc::DSL::Preflight
+ end
+ end
+
+ describe "uninstall_phase" do
+ it "calls the specified block before uninstalling, passing a Cask mini-dsl" do
+ called = false
+ yielded_arg = nil
+
+ cask = Hbc::Cask.new("with-uninstall-preflight") do
+ uninstall_preflight do |c|
+ called = true
+ yielded_arg = c
+ end
+ end
+
+ described_class.new(cask).uninstall_phase
+
+ expect(called).to be true
+ expect(yielded_arg).to be_kind_of Hbc::DSL::UninstallPreflight
+ end
+ end
+end
diff --git a/Library/Homebrew/test/cask/artifact/suite_spec.rb b/Library/Homebrew/test/cask/artifact/suite_spec.rb
new file mode 100644
index 000000000..98ae93311
--- /dev/null
+++ b/Library/Homebrew/test/cask/artifact/suite_spec.rb
@@ -0,0 +1,47 @@
+describe Hbc::Artifact::Suite, :cask do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-suite.rb") }
+
+ let(:install_phase) { -> { Hbc::Artifact::Suite.new(cask).install_phase } }
+
+ let(:target_path) { Hbc.appdir.join("Caffeine") }
+ let(:source_path) { cask.staged_path.join("Caffeine") }
+
+ before(:each) do
+ InstallHelper.install_without_artifacts(cask)
+ end
+
+ it "moves the suite to the proper directory" do
+ skip("flaky test") # FIXME
+
+ shutup do
+ install_phase.call
+ end
+
+ expect(target_path).to be_a_directory
+ expect(target_path).to be_a_symlink
+ expect(target_path.readlink).to exist
+ expect(source_path).not_to exist
+ end
+
+ it "creates a suite containing the expected app" do
+ shutup do
+ install_phase.call
+ end
+
+ expect(target_path.join("Caffeine.app")).to exist
+ end
+
+ it "avoids clobbering an existing suite by moving over it" do
+ target_path.mkpath
+
+ expect {
+ shutup do
+ install_phase.call
+ end
+ }.to raise_error(Hbc::CaskError)
+
+ expect(source_path).to be_a_directory
+ expect(target_path).to be_a_directory
+ expect(File.identical?(source_path, target_path)).to be false
+ end
+end
diff --git a/Library/Homebrew/test/cask/artifact/two_apps_correct_spec.rb b/Library/Homebrew/test/cask/artifact/two_apps_correct_spec.rb
new file mode 100644
index 000000000..9db22b2a3
--- /dev/null
+++ b/Library/Homebrew/test/cask/artifact/two_apps_correct_spec.rb
@@ -0,0 +1,91 @@
+describe Hbc::Artifact::App, :cask do
+ describe "multiple apps" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-two-apps-correct.rb") }
+
+ let(:install_phase) {
+ -> { Hbc::Artifact::App.new(cask).install_phase }
+ }
+
+ let(:source_path_mini) { cask.staged_path.join("Caffeine Mini.app") }
+ let(:target_path_mini) { Hbc.appdir.join("Caffeine Mini.app") }
+
+ let(:source_path_pro) { cask.staged_path.join("Caffeine Pro.app") }
+ let(:target_path_pro) { Hbc.appdir.join("Caffeine Pro.app") }
+
+ before(:each) do
+ InstallHelper.install_without_artifacts(cask)
+ end
+
+ it "installs both apps using the proper target directory" do
+ shutup do
+ install_phase.call
+ end
+
+ expect(target_path_mini).to be_a_directory
+ expect(source_path_mini).not_to exist
+
+ expect(target_path_pro).to be_a_directory
+ expect(source_path_pro).not_to exist
+ end
+
+ describe "when apps are in a subdirectory" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-two-apps-subdir.rb") }
+
+ it "installs both apps using the proper target directory" do
+ shutup do
+ install_phase.call
+ end
+
+ expect(target_path_mini).to be_a_directory
+ expect(source_path_mini).not_to exist
+
+ expect(target_path_pro).to be_a_directory
+ expect(source_path_pro).not_to exist
+ end
+ end
+
+ it "only uses apps when they are specified" do
+ FileUtils.cp_r source_path_mini, source_path_mini.sub("Caffeine Mini.app", "Caffeine Deluxe.app")
+
+ shutup do
+ install_phase.call
+ end
+
+ expect(target_path_mini).to be_a_directory
+ expect(source_path_mini).not_to exist
+
+ expect(Hbc.appdir.join("Caffeine Deluxe.app")).not_to exist
+ expect(cask.staged_path.join("Caffeine Deluxe.app")).to exist
+ end
+
+ describe "avoids clobbering an existing app" do
+ it "when the first app of two already exists" do
+ target_path_mini.mkpath
+
+ expect {
+ expect(install_phase).to output(<<-EOS.undent).to_stdout
+ ==> Moving App 'Caffeine Pro.app' to '#{target_path_pro}'
+ EOS
+ }.to raise_error(Hbc::CaskError, "It seems there is already an App at '#{target_path_mini}'.")
+
+ expect(source_path_mini).to be_a_directory
+ expect(target_path_mini).to be_a_directory
+ expect(File.identical?(source_path_mini, target_path_mini)).to be false
+ end
+
+ it "when the second app of two already exists" do
+ target_path_pro.mkpath
+
+ expect {
+ expect(install_phase).to output(<<-EOS.undent).to_stdout
+ ==> Moving App 'Caffeine Mini.app' to '#{target_path_mini}'
+ EOS
+ }.to raise_error(Hbc::CaskError, "It seems there is already an App at '#{target_path_pro}'.")
+
+ expect(source_path_pro).to be_a_directory
+ expect(target_path_pro).to be_a_directory
+ expect(File.identical?(source_path_pro, target_path_pro)).to be false
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/test/cask/artifact/two_apps_incorrect_spec.rb b/Library/Homebrew/test/cask/artifact/two_apps_incorrect_spec.rb
new file mode 100644
index 000000000..6427ec32c
--- /dev/null
+++ b/Library/Homebrew/test/cask/artifact/two_apps_incorrect_spec.rb
@@ -0,0 +1,9 @@
+describe Hbc::Artifact::App, :cask do
+ # FIXME: Doesn't actually raise because the `app` stanza is not evaluated on load.
+ # it "must raise" do
+ # lambda {
+ # Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-two-apps-incorrect.rb")
+ # }.must_raise
+ # # TODO: later give the user a nice exception for this case and check for it here
+ # end
+end
diff --git a/Library/Homebrew/test/cask/artifact/uninstall_no_zap_spec.rb b/Library/Homebrew/test/cask/artifact/uninstall_no_zap_spec.rb
new file mode 100644
index 000000000..f88aaa49d
--- /dev/null
+++ b/Library/Homebrew/test/cask/artifact/uninstall_no_zap_spec.rb
@@ -0,0 +1,19 @@
+describe Hbc::Artifact::Zap, :cask do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-installable.rb") }
+
+ let(:zap_artifact) {
+ Hbc::Artifact::Zap.new(cask)
+ }
+
+ before do
+ shutup do
+ InstallHelper.install_without_artifacts(cask)
+ end
+ end
+
+ describe "#uninstall_phase" do
+ subject { zap_artifact }
+
+ it { is_expected.not_to respond_to(:uninstall_phase) }
+ end
+end
diff --git a/Library/Homebrew/test/cask/artifact/uninstall_spec.rb b/Library/Homebrew/test/cask/artifact/uninstall_spec.rb
new file mode 100644
index 000000000..b7deb4575
--- /dev/null
+++ b/Library/Homebrew/test/cask/artifact/uninstall_spec.rb
@@ -0,0 +1,351 @@
+describe Hbc::Artifact::Uninstall, :cask do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-installable.rb") }
+
+ let(:uninstall_artifact) {
+ Hbc::Artifact::Uninstall.new(cask, command: Hbc::FakeSystemCommand)
+ }
+
+ let(:dir) { TEST_TMPDIR }
+ let(:absolute_path) { Pathname.new("#{dir}/absolute_path") }
+ let(:path_with_tilde) { Pathname.new("#{dir}/path_with_tilde") }
+ let(:glob_path1) { Pathname.new("#{dir}/glob_path1") }
+ let(:glob_path2) { Pathname.new("#{dir}/glob_path2") }
+
+ around(:each) do |example|
+ begin
+ ENV["HOME"] = dir
+
+ paths = [
+ absolute_path,
+ path_with_tilde,
+ glob_path1,
+ glob_path2,
+ ]
+
+ FileUtils.touch paths
+
+ shutup do
+ InstallHelper.install_without_artifacts(cask)
+ end
+
+ example.run
+ ensure
+ FileUtils.rm_f paths
+ end
+ end
+
+ describe "uninstall_phase" do
+ subject {
+ shutup do
+ uninstall_artifact.uninstall_phase
+ end
+ }
+
+ context "when using launchctl" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-uninstall-launchctl.rb") }
+ let(:launchctl_list_cmd) { %w[/bin/launchctl list my.fancy.package.service] }
+ let(:launchctl_remove_cmd) { %w[/bin/launchctl remove my.fancy.package.service] }
+ let(:unknown_response) { "launchctl list returned unknown response\n" }
+ let(:service_info) {
+ <<-EOS.undent
+ {
+ "LimitLoadToSessionType" = "Aqua";
+ "Label" = "my.fancy.package.service";
+ "TimeOut" = 30;
+ "OnDemand" = true;
+ "LastExitStatus" = 0;
+ "ProgramArguments" = (
+ "argument";
+ );
+ };
+ EOS
+ }
+
+ context "when launchctl job is owned by user" do
+ it "can uninstall" do
+ Hbc::FakeSystemCommand.stubs_command(
+ launchctl_list_cmd,
+ service_info,
+ )
+
+ Hbc::FakeSystemCommand.stubs_command(
+ sudo(launchctl_list_cmd),
+ unknown_response,
+ )
+
+ Hbc::FakeSystemCommand.expects_command(launchctl_remove_cmd)
+
+ subject
+ end
+ end
+
+ context "when launchctl job is owned by system" do
+ it "can uninstall" do
+ Hbc::FakeSystemCommand.stubs_command(
+ launchctl_list_cmd,
+ unknown_response,
+ )
+
+ Hbc::FakeSystemCommand.stubs_command(
+ sudo(launchctl_list_cmd),
+ service_info,
+ )
+
+ Hbc::FakeSystemCommand.expects_command(sudo(launchctl_remove_cmd))
+
+ subject
+ end
+ end
+ end
+
+ context "when using pkgutil" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-uninstall-pkgutil.rb") }
+ let(:main_pkg_id) { "my.fancy.package.main" }
+ let(:agent_pkg_id) { "my.fancy.package.agent" }
+ let(:main_files) {
+ %w[
+ fancy/bin/fancy.exe
+ fancy/var/fancy.data
+ ]
+ }
+ let(:main_dirs) {
+ %w[
+ fancy
+ fancy/bin
+ fancy/var
+ ]
+ }
+ let(:agent_files) {
+ %w[
+ fancy/agent/fancy-agent.exe
+ fancy/agent/fancy-agent.pid
+ fancy/agent/fancy-agent.log
+ ]
+ }
+ let(:agent_dirs) {
+ %w[
+ fancy
+ fancy/agent
+ ]
+ }
+ let(:pkg_info_plist) {
+ <<-EOS.undent
+ <?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+ <plist version="1.0">
+ <dict>
+ <key>install-location</key>
+ <string>tmp</string>
+ <key>volume</key>
+ <string>/</string>
+ </dict>
+ </plist>
+ EOS
+ }
+
+ it "can uninstall" do
+ Hbc::FakeSystemCommand.stubs_command(
+ %w[/usr/sbin/pkgutil --pkgs=my.fancy.package.*],
+ "#{main_pkg_id}\n#{agent_pkg_id}",
+ )
+
+ [
+ [main_pkg_id, main_files, main_dirs],
+ [agent_pkg_id, agent_files, agent_dirs],
+ ].each do |pkg_id, pkg_files, pkg_dirs|
+ Hbc::FakeSystemCommand.stubs_command(
+ %W[/usr/sbin/pkgutil --only-files --files #{pkg_id}],
+ pkg_files.join("\n"),
+ )
+
+ Hbc::FakeSystemCommand.stubs_command(
+ %W[/usr/sbin/pkgutil --only-dirs --files #{pkg_id}],
+ pkg_dirs.join("\n"),
+ )
+
+ Hbc::FakeSystemCommand.stubs_command(
+ %W[/usr/sbin/pkgutil --files #{pkg_id}],
+ (pkg_files + pkg_dirs).join("\n"),
+ )
+
+ Hbc::FakeSystemCommand.stubs_command(
+ %W[/usr/sbin/pkgutil --pkg-info-plist #{pkg_id}],
+ pkg_info_plist,
+ )
+
+ Hbc::FakeSystemCommand.expects_command(sudo(%W[/usr/sbin/pkgutil --forget #{pkg_id}]))
+
+ Hbc::FakeSystemCommand.expects_command(
+ sudo(%w[/bin/rm -f --] + pkg_files.map { |path| Pathname("/tmp/#{path}") }),
+ )
+ end
+
+ subject
+ end
+ end
+
+ context "when using kext" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-uninstall-kext.rb") }
+ let(:kext_id) { "my.fancy.package.kernelextension" }
+
+ it "can uninstall" do
+ Hbc::FakeSystemCommand.stubs_command(
+ sudo(%W[/usr/sbin/kextstat -l -b #{kext_id}]), "loaded"
+ )
+
+ Hbc::FakeSystemCommand.expects_command(
+ sudo(%W[/sbin/kextunload -b #{kext_id}]),
+ )
+
+ Hbc::FakeSystemCommand.expects_command(
+ sudo(%W[/usr/sbin/kextfind -b #{kext_id}]), "/Library/Extensions/FancyPackage.kext\n"
+ )
+
+ Hbc::FakeSystemCommand.expects_command(
+ sudo(["/bin/rm", "-rf", "/Library/Extensions/FancyPackage.kext"]),
+ )
+
+ subject
+ end
+ end
+
+ context "when using quit" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-uninstall-quit.rb") }
+ let(:bundle_id) { "my.fancy.package.app" }
+ let(:quit_application_script) {
+ %Q(tell application id "#{bundle_id}" to quit)
+ }
+
+ it "can uninstall" do
+ Hbc::FakeSystemCommand.stubs_command(
+ %w[/bin/launchctl list], "999\t0\t#{bundle_id}\n"
+ )
+
+ Hbc::FakeSystemCommand.stubs_command(
+ %w[/bin/launchctl list],
+ )
+
+ subject
+ end
+ end
+
+ context "when using signal" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-uninstall-signal.rb") }
+ let(:bundle_id) { "my.fancy.package.app" }
+ let(:signals) { %w[TERM KILL] }
+ let(:unix_pids) { [12_345, 67_890] }
+
+ it "can uninstall" do
+ Hbc::FakeSystemCommand.stubs_command(
+ %w[/bin/launchctl list], unix_pids.map { |pid| [pid, 0, bundle_id].join("\t") }.join("\n")
+ )
+
+ signals.each do |signal|
+ expect(Process).to receive(:kill).with(signal, *unix_pids)
+ end
+
+ subject
+ end
+ end
+
+ context "when using delete" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-uninstall-delete.rb") }
+
+ it "can uninstall" do
+ Hbc::FakeSystemCommand.expects_command(
+ sudo(%w[/bin/rm -rf --],
+ absolute_path,
+ path_with_tilde,
+ glob_path1,
+ glob_path2),
+ )
+
+ subject
+ end
+ end
+
+ context "when using trash" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-uninstall-trash.rb") }
+
+ it "can uninstall" do
+ Hbc::FakeSystemCommand.expects_command(
+ sudo(%w[/bin/rm -rf --],
+ absolute_path,
+ path_with_tilde,
+ glob_path1,
+ glob_path2),
+ )
+
+ subject
+ end
+ end
+
+ context "when using rmdir" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-uninstall-rmdir.rb") }
+ let(:empty_directory_path) { Pathname.new("#{TEST_TMPDIR}/empty_directory_path") }
+
+ before(:each) do
+ empty_directory_path.mkdir
+ end
+
+ after(:each) do
+ empty_directory_path.rmdir
+ end
+
+ it "can uninstall" do
+ Hbc::FakeSystemCommand.expects_command(
+ sudo(%w[/bin/rm -f --], empty_directory_path/".DS_Store"),
+ )
+
+ Hbc::FakeSystemCommand.expects_command(
+ sudo(%w[/bin/rmdir --], empty_directory_path),
+ )
+
+ subject
+ end
+ end
+
+ context "when using script" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-uninstall-script.rb") }
+ let(:script_pathname) { cask.staged_path.join("MyFancyPkg", "FancyUninstaller.tool") }
+
+ it "can uninstall" do
+ Hbc::FakeSystemCommand.expects_command(%w[/bin/chmod -- +x] + [script_pathname])
+
+ Hbc::FakeSystemCommand.expects_command(
+ sudo(cask.staged_path.join("MyFancyPkg", "FancyUninstaller.tool"), "--please"),
+ )
+
+ subject
+ end
+ end
+
+ context "when using early_script" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-uninstall-early-script.rb") }
+ let(:script_pathname) { cask.staged_path.join("MyFancyPkg", "FancyUninstaller.tool") }
+
+ it "can uninstall" do
+ Hbc::FakeSystemCommand.expects_command(%w[/bin/chmod -- +x] + [script_pathname])
+
+ Hbc::FakeSystemCommand.expects_command(
+ sudo(cask.staged_path.join("MyFancyPkg", "FancyUninstaller.tool"), "--please"),
+ )
+
+ subject
+ end
+ end
+
+ context "when using login_item" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-uninstall-login-item.rb") }
+
+ it "can uninstall" do
+ Hbc::FakeSystemCommand.expects_command(
+ ["/usr/bin/osascript", "-e", 'tell application "System Events" to delete every login ' \
+ 'item whose name is "Fancy"'],
+ )
+
+ subject
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/test/cask/artifact/zap_spec.rb b/Library/Homebrew/test/cask/artifact/zap_spec.rb
new file mode 100644
index 000000000..fdf2e4f9d
--- /dev/null
+++ b/Library/Homebrew/test/cask/artifact/zap_spec.rb
@@ -0,0 +1,352 @@
+# TODO: test that zap removes an alternate version of the same Cask
+describe Hbc::Artifact::Zap, :cask do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-installable.rb") }
+
+ let(:zap_artifact) {
+ Hbc::Artifact::Zap.new(cask, command: Hbc::FakeSystemCommand)
+ }
+
+ let(:dir) { TEST_TMPDIR }
+ let(:absolute_path) { Pathname.new("#{dir}/absolute_path") }
+ let(:path_with_tilde) { Pathname.new("#{dir}/path_with_tilde") }
+ let(:glob_path1) { Pathname.new("#{dir}/glob_path1") }
+ let(:glob_path2) { Pathname.new("#{dir}/glob_path2") }
+
+ around(:each) do |example|
+ begin
+ ENV["HOME"] = dir
+
+ paths = [
+ absolute_path,
+ path_with_tilde,
+ glob_path1,
+ glob_path2,
+ ]
+
+ FileUtils.touch paths
+
+ shutup do
+ InstallHelper.install_without_artifacts(cask)
+ end
+
+ example.run
+ ensure
+ FileUtils.rm_f paths
+ end
+ end
+
+ describe "#zap_phase" do
+ subject {
+ shutup do
+ zap_artifact.zap_phase
+ end
+ }
+
+ context "when using launchctl" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-zap-launchctl.rb") }
+ let(:launchctl_list_cmd) { %w[/bin/launchctl list my.fancy.package.service] }
+ let(:launchctl_remove_cmd) { %w[/bin/launchctl remove my.fancy.package.service] }
+ let(:unknown_response) { "launchctl list returned unknown response\n" }
+ let(:service_info) {
+ <<-EOS.undent
+ {
+ "LimitLoadToSessionType" = "Aqua";
+ "Label" = "my.fancy.package.service";
+ "TimeOut" = 30;
+ "OnDemand" = true;
+ "LastExitStatus" = 0;
+ "ProgramArguments" = (
+ "argument";
+ );
+ };
+ EOS
+ }
+
+ context "when launchctl job is owned by user" do
+ it "can zap" do
+ Hbc::FakeSystemCommand.stubs_command(
+ launchctl_list_cmd,
+ service_info,
+ )
+
+ Hbc::FakeSystemCommand.stubs_command(
+ sudo(launchctl_list_cmd),
+ unknown_response,
+ )
+
+ Hbc::FakeSystemCommand.expects_command(launchctl_remove_cmd)
+
+ subject
+ end
+ end
+
+ describe "when launchctl job is owned by system" do
+ it "can zap" do
+ Hbc::FakeSystemCommand.stubs_command(
+ launchctl_list_cmd,
+ unknown_response,
+ )
+
+ Hbc::FakeSystemCommand.stubs_command(
+ sudo(launchctl_list_cmd),
+ service_info,
+ )
+
+ Hbc::FakeSystemCommand.expects_command(sudo(launchctl_remove_cmd))
+
+ subject
+ end
+ end
+ end
+
+ context "when using pkgutil" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-zap-pkgutil.rb") }
+ let(:main_pkg_id) { "my.fancy.package.main" }
+ let(:agent_pkg_id) { "my.fancy.package.agent" }
+ let(:main_files) {
+ %w[
+ fancy/bin/fancy.exe
+ fancy/var/fancy.data
+ ]
+ }
+ let(:main_dirs) {
+ %w[
+ fancy
+ fancy/bin
+ fancy/var
+ ]
+ }
+ let(:agent_files) {
+ %w[
+ fancy/agent/fancy-agent.exe
+ fancy/agent/fancy-agent.pid
+ fancy/agent/fancy-agent.log
+ ]
+ }
+ let(:agent_dirs) {
+ %w[
+ fancy
+ fancy/agent
+ ]
+ }
+ let(:pkg_info_plist) {
+ <<-EOS.undent
+ <?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+ <plist version="1.0">
+ <dict>
+ <key>install-location</key>
+ <string>tmp</string>
+ <key>volume</key>
+ <string>/</string>
+ </dict>
+ </plist>
+ EOS
+ }
+
+ it "can zap" do
+ Hbc::FakeSystemCommand.stubs_command(
+ %w[/usr/sbin/pkgutil --pkgs=my.fancy.package.*],
+ "#{main_pkg_id}\n#{agent_pkg_id}",
+ )
+
+ [
+ [main_pkg_id, main_files, main_dirs],
+ [agent_pkg_id, agent_files, agent_dirs],
+ ].each do |pkg_id, pkg_files, pkg_dirs|
+ Hbc::FakeSystemCommand.stubs_command(
+ %W[/usr/sbin/pkgutil --only-files --files #{pkg_id}],
+ pkg_files.join("\n"),
+ )
+
+ Hbc::FakeSystemCommand.stubs_command(
+ %W[/usr/sbin/pkgutil --only-dirs --files #{pkg_id}],
+ pkg_dirs.join("\n"),
+ )
+
+ Hbc::FakeSystemCommand.stubs_command(
+ %W[/usr/sbin/pkgutil --files #{pkg_id}],
+ (pkg_files + pkg_dirs).join("\n"),
+ )
+
+ Hbc::FakeSystemCommand.stubs_command(
+ %W[/usr/sbin/pkgutil --pkg-info-plist #{pkg_id}],
+ pkg_info_plist,
+ )
+
+ Hbc::FakeSystemCommand.expects_command(sudo(%W[/usr/sbin/pkgutil --forget #{pkg_id}]))
+
+ Hbc::FakeSystemCommand.expects_command(
+ sudo(%w[/bin/rm -f --] + pkg_files.map { |path| Pathname("/tmp/#{path}") }),
+ )
+ end
+
+ subject
+ end
+ end
+
+ context "when using kext" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-zap-kext.rb") }
+ let(:kext_id) { "my.fancy.package.kernelextension" }
+
+ it "can zap" do
+ Hbc::FakeSystemCommand.stubs_command(
+ sudo(%W[/usr/sbin/kextstat -l -b #{kext_id}]), "loaded"
+ )
+
+ Hbc::FakeSystemCommand.expects_command(
+ sudo(%W[/sbin/kextunload -b #{kext_id}]),
+ )
+
+ Hbc::FakeSystemCommand.expects_command(
+ sudo(%W[/usr/sbin/kextfind -b #{kext_id}]), "/Library/Extensions/FancyPackage.kext\n"
+ )
+
+ Hbc::FakeSystemCommand.expects_command(
+ sudo(["/bin/rm", "-rf", "/Library/Extensions/FancyPackage.kext"]),
+ )
+
+ subject
+ end
+ end
+
+ context "when using quit" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-zap-quit.rb") }
+ let(:bundle_id) { "my.fancy.package.app" }
+ let(:quit_application_script) {
+ %Q(tell application id "#{bundle_id}" to quit)
+ }
+
+ it "can zap" do
+ Hbc::FakeSystemCommand.stubs_command(
+ %w[/bin/launchctl list], "999\t0\t#{bundle_id}\n"
+ )
+
+ Hbc::FakeSystemCommand.stubs_command(
+ %w[/bin/launchctl list],
+ )
+
+ subject
+ end
+ end
+
+ context "when using signal" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-zap-signal.rb") }
+ let(:bundle_id) { "my.fancy.package.app" }
+ let(:signals) { %w[TERM KILL] }
+ let(:unix_pids) { [12_345, 67_890] }
+
+ it "can zap" do
+ Hbc::FakeSystemCommand.stubs_command(
+ %w[/bin/launchctl list], unix_pids.map { |pid| [pid, 0, bundle_id].join("\t") }.join("\n")
+ )
+
+ signals.each do |signal|
+ expect(Process).to receive(:kill).with(signal, *unix_pids)
+ end
+
+ subject
+ end
+ end
+
+ context "when using delete" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-zap-delete.rb") }
+
+ it "can zap" do
+ Hbc::FakeSystemCommand.expects_command(
+ sudo(%w[/bin/rm -rf --],
+ absolute_path,
+ path_with_tilde,
+ glob_path1,
+ glob_path2),
+ )
+
+ subject
+ end
+ end
+
+ context "when using trash" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-zap-trash.rb") }
+
+ it "can zap" do
+ Hbc::FakeSystemCommand.expects_command(
+ sudo(%w[/bin/rm -rf --],
+ absolute_path,
+ path_with_tilde,
+ glob_path1,
+ glob_path2),
+ )
+
+ subject
+ end
+ end
+
+ context "when using rmdir" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-zap-rmdir.rb") }
+ let(:empty_directory_path) { Pathname.new("#{TEST_TMPDIR}/empty_directory_path") }
+
+ before(:each) do
+ empty_directory_path.mkdir
+ end
+
+ after(:each) do
+ empty_directory_path.rmdir
+ end
+
+ it "can zap" do
+ Hbc::FakeSystemCommand.expects_command(
+ sudo(%w[/bin/rm -f --], empty_directory_path/".DS_Store"),
+ )
+
+ Hbc::FakeSystemCommand.expects_command(
+ sudo(%w[/bin/rmdir --], empty_directory_path),
+ )
+
+ subject
+ end
+ end
+
+ context "when using script" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-zap-script.rb") }
+ let(:script_pathname) { cask.staged_path.join("MyFancyPkg", "FancyUninstaller.tool") }
+
+ it "can zap" do
+ Hbc::FakeSystemCommand.expects_command(%w[/bin/chmod -- +x] + [script_pathname])
+
+ Hbc::FakeSystemCommand.expects_command(
+ sudo(cask.staged_path.join("MyFancyPkg", "FancyUninstaller.tool"), "--please"),
+ )
+
+ subject
+ end
+ end
+
+ context "when using early_script" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-zap-early-script.rb") }
+ let(:script_pathname) { cask.staged_path.join("MyFancyPkg", "FancyUninstaller.tool") }
+
+ it "can zap" do
+ Hbc::FakeSystemCommand.expects_command(%w[/bin/chmod -- +x] + [script_pathname])
+
+ Hbc::FakeSystemCommand.expects_command(
+ sudo(cask.staged_path.join("MyFancyPkg", "FancyUninstaller.tool"), "--please"),
+ )
+
+ subject
+ end
+ end
+
+ context "when using login_item" do
+ let(:cask) { Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-zap-login-item.rb") }
+
+ it "can zap" do
+ Hbc::FakeSystemCommand.expects_command(
+ ["/usr/bin/osascript", "-e", 'tell application "System Events" to delete every login ' \
+ 'item whose name is "Fancy"'],
+ )
+
+ subject
+ end
+ end
+ end
+end