diff --git a/Library/Homebrew/test/keg_spec.rb b/Library/Homebrew/test/keg_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..f40002dd263dc995ded6e6bce0a17cc600988735 --- /dev/null +++ b/Library/Homebrew/test/keg_spec.rb @@ -0,0 +1,486 @@ +require "keg" +require "stringio" + +describe Keg do + include FileUtils + + def setup_test_keg(name, version) + path = HOMEBREW_CELLAR/name/version + (path/"bin").mkpath + + %w[hiworld helloworld goodbye_cruel_world].each do |file| + touch path/"bin"/file + end + + keg = described_class.new(path) + kegs << keg + keg + end + + around(:each) do |example| + begin + @old_stdout = $stdout + $stdout = StringIO.new + + example.run + ensure + $stdout = @old_stdout + end + end + + let(:dst) { HOMEBREW_PREFIX/"bin"/"helloworld" } + let(:nonexistent) { Pathname.new("/some/nonexistent/path") } + let(:mode) { OpenStruct.new } + let!(:keg) { setup_test_keg("foo", "1.0") } + let(:kegs) { [] } + + before(:each) do + (HOMEBREW_PREFIX/"bin").mkpath + (HOMEBREW_PREFIX/"lib").mkpath + end + + after(:each) do + kegs.each(&:unlink) + rmtree HOMEBREW_PREFIX/"lib" + end + + specify "::all" do + Formula.clear_racks_cache + expect(described_class.all).to eq([keg]) + end + + specify "#empty_installation?" do + %w[.DS_Store INSTALL_RECEIPT.json LICENSE.txt].each do |file| + touch keg/file + end + + expect(keg).to exist + expect(keg).to be_a_directory + expect(keg).not_to be_an_empty_installation + + (keg/"bin").rmtree + expect(keg).to be_an_empty_installation + end + + specify "#oldname_opt_record" do + expect(keg.oldname_opt_record).to be nil + oldname_opt_record = HOMEBREW_PREFIX/"opt/oldfoo" + oldname_opt_record.make_relative_symlink(HOMEBREW_CELLAR/"foo/1.0") + expect(keg.oldname_opt_record).to eq(oldname_opt_record) + end + + specify "#remove_oldname_opt_record" do + oldname_opt_record = HOMEBREW_PREFIX/"opt/oldfoo" + oldname_opt_record.make_relative_symlink(HOMEBREW_CELLAR/"foo/2.0") + keg.remove_oldname_opt_record + expect(oldname_opt_record).to be_a_symlink + oldname_opt_record.unlink + oldname_opt_record.make_relative_symlink(HOMEBREW_CELLAR/"foo/1.0") + keg.remove_oldname_opt_record + expect(oldname_opt_record).not_to be_a_symlink + end + + describe "#link" do + it "links a Keg" do + expect(keg.link).to eq(3) + (HOMEBREW_PREFIX/"bin").children.each do |c| + expect(c.readlink).to be_relative + end + end + + context "with dry run set to true" do + it "only prints what would be done" do + mode.dry_run = true + + expect(keg.link(mode)).to eq(0) + expect(keg).not_to be_linked + + ["hiworld", "helloworld", "goodbye_cruel_world"].each do |file| + expect($stdout.string).to match("#{HOMEBREW_PREFIX}/bin/#{file}") + end + expect($stdout.string.lines.count).to eq(3) + end + end + + it "fails when already linked" do + keg.link + + expect { keg.link }.to raise_error(Keg::AlreadyLinkedError) + end + + it "fails when files exist" do + touch dst + + expect { keg.link }.to raise_error(Keg::ConflictError) + end + + it "ignores broken symlinks at target" do + src = keg/"bin"/"helloworld" + dst.make_symlink(nonexistent) + keg.link + expect(dst.readlink).to eq(src.relative_path_from(dst.dirname)) + end + + context "with overwrite set to true" do + it "overwrite existing files" do + touch dst + mode.overwrite = true + expect(keg.link(mode)).to eq(3) + expect(keg).to be_linked + end + + it "overwrites broken symlinks" do + dst.make_symlink "nowhere" + mode.overwrite = true + expect(keg.link(mode)).to eq(3) + expect(keg).to be_linked + end + + it "still supports dryrun" do + touch dst + mode.overwrite = true + mode.dry_run = true + + expect(keg.link(mode)).to eq(0) + expect(keg).not_to be_linked + + expect($stdout.string).to eq("#{dst}\n") + end + end + + it "also creates an opt link" do + expect(keg).not_to be_optlinked + keg.link + expect(keg).to be_optlinked + end + + specify "pkgconfig directory is created" do + link = HOMEBREW_PREFIX/"lib"/"pkgconfig" + (keg/"lib"/"pkgconfig").mkpath + keg.link + expect(link.lstat).to be_a_directory + end + + specify "cmake directory is created" do + link = HOMEBREW_PREFIX/"lib"/"cmake" + (keg/"lib"/"cmake").mkpath + keg.link + expect(link.lstat).to be_a_directory + end + + specify "symlinks are linked directly" do + link = HOMEBREW_PREFIX/"lib"/"pkgconfig" + + (keg/"lib"/"example").mkpath + (keg/"lib"/"pkgconfig").make_symlink "example" + keg.link + + expect(link.resolved_path).to be_a_symlink + expect(link.lstat).to be_a_symlink + end + end + + describe "#unlink" do + it "unlinks a Keg" do + keg.link + expect(dst).to be_a_symlink + expect(keg.unlink).to eq(3) + expect(dst).not_to be_a_symlink + end + + it "prunes empty top-level directories" do + mkpath HOMEBREW_PREFIX/"lib/foo/bar" + mkpath keg/"lib/foo/bar" + touch keg/"lib/foo/bar/file1" + + keg.unlink + + expect(HOMEBREW_PREFIX/"lib/foo").not_to be_a_directory + end + + it "ignores .DS_Store when pruning empty directories" do + mkpath HOMEBREW_PREFIX/"lib/foo/bar" + touch HOMEBREW_PREFIX/"lib/foo/.DS_Store" + mkpath keg/"lib/foo/bar" + touch keg/"lib/foo/bar/file1" + + keg.unlink + + expect(HOMEBREW_PREFIX/"lib/foo").not_to be_a_directory + expect(HOMEBREW_PREFIX/"lib/foo/.DS_Store").not_to exist + end + + it "doesn't remove opt link" do + keg.link + keg.unlink + expect(keg).to be_optlinked + end + + it "preverves broken symlinks pointing outside the Keg" do + keg.link + dst.delete + dst.make_symlink(nonexistent) + keg.unlink + expect(dst).to be_a_symlink + end + + it "preverves broken symlinks pointing into the Keg" do + keg.link + dst.resolved_path.delete + keg.unlink + expect(dst).to be_a_symlink + end + + it "preverves symlinks pointing outside the Keg" do + keg.link + dst.delete + dst.make_symlink(Pathname.new("/bin/sh")) + keg.unlink + expect(dst).to be_a_symlink + end + + it "preserves real files" do + keg.link + dst.delete + touch dst + keg.unlink + expect(dst).to be_a_file + end + + it "ignores nonexistent file" do + keg.link + dst.delete + expect(keg.unlink).to eq(2) + end + + it "doesn't remove links to symlinks" do + a = HOMEBREW_CELLAR/"a"/"1.0" + b = HOMEBREW_CELLAR/"b"/"1.0" + + (a/"lib"/"example").mkpath + (a/"lib"/"example2").make_symlink "example" + (b/"lib"/"example2").mkpath + + a = described_class.new(a) + b = described_class.new(b) + a.link + + lib = HOMEBREW_PREFIX/"lib" + expect(lib.children.length).to eq(2) + expect { b.link }.to raise_error(Keg::ConflictError) + expect(lib.children.length).to eq(2) + end + + it "removes broken symlinks that conflict with directories" do + a = HOMEBREW_CELLAR/"a"/"1.0" + (a/"lib"/"foo").mkpath + + keg = described_class.new(a) + + link = HOMEBREW_PREFIX/"lib"/"foo" + link.parent.mkpath + link.make_symlink(nonexistent) + + keg.link + end + end + + describe "#optlink" do + it "creates an opt link" do + oldname_opt_record = HOMEBREW_PREFIX/"opt/oldfoo" + oldname_opt_record.make_relative_symlink(HOMEBREW_CELLAR/"foo/1.0") + keg_record = HOMEBREW_CELLAR/"foo"/"2.0" + (keg_record/"bin").mkpath + keg = described_class.new(keg_record) + keg.optlink + expect(keg_record).to eq(oldname_opt_record.resolved_path) + keg.uninstall + expect(oldname_opt_record).not_to be_a_symlink + end + + it "doesn't fail if already opt-linked" do + keg.opt_record.make_relative_symlink Pathname.new(keg) + keg.optlink + expect(keg).to be_optlinked + end + + it "replaces an existing directory" do + keg.opt_record.mkpath + keg.optlink + expect(keg).to be_optlinked + end + + it "replaces an existing file" do + keg.opt_record.parent.mkpath + keg.opt_record.write("foo") + keg.optlink + expect(keg).to be_optlinked + end + end + + specify "#link and #unlink" do + expect(keg).not_to be_linked + keg.link + expect(keg).to be_linked + keg.unlink + expect(keg).not_to be_linked + end + + describe "::find_some_installed_dependents" do + def stub_formula_name(name) + f = formula(name) { url "foo-1.0" } + stub_formula_loader f + stub_formula_loader f, "homebrew/core/#{f}" + f + end + + def setup_test_keg(name, version) + f = stub_formula_name(name) + keg = super + Tab.create(f, DevelopmentTools.default_compiler, :libcxx).write + keg + end + + before(:each) do + keg.link + end + + def alter_tab(keg = dependent) + tab = Tab.for_keg(keg) + yield tab + tab.write + end + + # 1.1.6 is the earliest version of Homebrew that generates correct runtime + # dependency lists in Tabs. + def dependencies(deps, homebrew_version: "1.1.6") + alter_tab do |tab| + tab.homebrew_version = homebrew_version + tab.tabfile = dependent/Tab::FILENAME + tab.runtime_dependencies = deps + end + end + + def unreliable_dependencies(deps) + # 1.1.5 is (hopefully!) the last version of Homebrew that generates + # incorrect runtime dependency lists in Tabs. + dependencies(deps, homebrew_version: "1.1.5") + end + + let(:dependent) { setup_test_keg("bar", "1.0") } + + # Test with a keg whose formula isn't known. + # This can happen if e.g. a formula is installed + # from a file path or URL. + specify "unknown Formula" do + allow(Formulary).to receive(:loader_for).and_call_original + alter_tab(keg) do |t| + t.source["tap"] = "some/tap" + t.source["path"] = nil + end + + dependencies [{ "full_name" => "some/tap/foo", "version" => "1.0" }] + expect(keg.installed_dependents).to eq([dependent]) + expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar 1.0"]]) + + dependencies nil + # It doesn't make sense for a keg with no formula to have any dependents, + # so that can't really be tested. + expect(described_class.find_some_installed_dependents([keg])).to be nil + end + + specify "a dependency with no Tap in Tab" do + tap_dep = setup_test_keg("baz", "1.0") + + alter_tab(keg) { |t| t.source["tap"] = nil } + + dependencies nil + Formula["bar"].class.depends_on "foo" + Formula["bar"].class.depends_on "baz" + + result = described_class.find_some_installed_dependents([keg, tap_dep]) + expect(result).to eq([[keg, tap_dep], ["bar"]]) + end + + specify "no dependencies anywhere" do + dependencies nil + expect(keg.installed_dependents).to be_empty + expect(described_class.find_some_installed_dependents([keg])).to be nil + end + + specify "missing Formula dependency" do + dependencies nil + Formula["bar"].class.depends_on "foo" + expect(keg.installed_dependents).to be_empty + expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar"]]) + end + + specify "uninstalling dependent and dependency" do + dependencies nil + Formula["bar"].class.depends_on "foo" + expect(keg.installed_dependents).to be_empty + expect(described_class.find_some_installed_dependents([keg, dependent])).to be nil + end + + specify "renamed dependency" do + dependencies nil + + stub_formula_loader Formula["foo"], "homebrew/core/foo-old" + renamed_path = HOMEBREW_CELLAR/"foo-old" + (HOMEBREW_CELLAR/"foo").rename(renamed_path) + renamed_keg = described_class.new(renamed_path/"1.0") + + Formula["bar"].class.depends_on "foo" + + result = described_class.find_some_installed_dependents([renamed_keg]) + expect(result).to eq([[renamed_keg], ["bar"]]) + end + + specify "empty dependencies in Tab" do + dependencies [] + expect(keg.installed_dependents).to be_empty + expect(described_class.find_some_installed_dependents([keg])).to be nil + end + + specify "same name but different version in Tab" do + dependencies [{ "full_name" => "foo", "version" => "1.1" }] + expect(keg.installed_dependents).to eq([dependent]) + expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar 1.0"]]) + end + + specify "different name and same version in Tab" do + stub_formula_name("baz") + dependencies [{ "full_name" => "baz", "version" => keg.version.to_s }] + expect(keg.installed_dependents).to be_empty + expect(described_class.find_some_installed_dependents([keg])).to be nil + end + + specify "same name and version in Tab" do + dependencies [{ "full_name" => "foo", "version" => "1.0" }] + expect(keg.installed_dependents).to eq([dependent]) + expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar 1.0"]]) + end + + specify "fallback for old versions" do + unreliable_dependencies [{ "full_name" => "baz", "version" => "1.0" }] + Formula["bar"].class.depends_on "foo" + expect(keg.installed_dependents).to be_empty + expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar"]]) + end + + specify "non-opt-linked" do + keg.remove_opt_record + dependencies [{ "full_name" => "foo", "version" => "1.0" }] + expect(keg.installed_dependents).to be_empty + expect(described_class.find_some_installed_dependents([keg])).to be nil + end + + specify "keg-only" do + keg.unlink + Formula["foo"].class.keg_only "a good reason" + dependencies [{ "full_name" => "foo", "version" => "1.1" }] # different version + expect(keg.installed_dependents).to eq([dependent]) + expect(described_class.find_some_installed_dependents([keg])).to eq([[keg], ["bar 1.0"]]) + end + end +end diff --git a/Library/Homebrew/test/keg_test.rb b/Library/Homebrew/test/keg_test.rb deleted file mode 100644 index bd42320383d6bfc9a6177598620d402563455874..0000000000000000000000000000000000000000 --- a/Library/Homebrew/test/keg_test.rb +++ /dev/null @@ -1,475 +0,0 @@ -require "testing_env" -require "keg" -require "stringio" - -class LinkTestCase < Homebrew::TestCase - include FileUtils - - def setup_test_keg(name, version) - path = HOMEBREW_CELLAR.join(name, version) - path.join("bin").mkpath - - %w[hiworld helloworld goodbye_cruel_world].each do |file| - touch path.join("bin", file) - end - - keg = Keg.new(path) - @kegs ||= [] - @kegs << keg - keg - end - - def setup - super - - @keg = setup_test_keg("foo", "1.0") - @dst = HOMEBREW_PREFIX.join("bin", "helloworld") - @nonexistent = Pathname.new("/some/nonexistent/path") - - @mode = OpenStruct.new - - @old_stdout = $stdout - $stdout = StringIO.new - - mkpath HOMEBREW_PREFIX/"bin" - mkpath HOMEBREW_PREFIX/"lib" - end - - def teardown - @kegs.each(&:unlink) - $stdout = @old_stdout - rmtree HOMEBREW_PREFIX/"lib" - super - end -end - -class LinkTests < LinkTestCase - def test_all - Formula.clear_racks_cache - assert_equal [@keg], Keg.all - end - - def test_empty_installation - %w[.DS_Store INSTALL_RECEIPT.json LICENSE.txt].each do |file| - touch @keg/file - end - assert_predicate @keg, :exist? - assert_predicate @keg, :directory? - refute_predicate @keg, :empty_installation? - - (@keg/"bin").rmtree - assert_predicate @keg, :empty_installation? - end - - def test_linking_keg - assert_equal 3, @keg.link - (HOMEBREW_PREFIX/"bin").children.each { |c| assert_predicate c.readlink, :relative? } - end - - def test_unlinking_keg - @keg.link - assert_predicate @dst, :symlink? - assert_equal 3, @keg.unlink - refute_predicate @dst, :symlink? - end - - def test_oldname_opt_record - assert_nil @keg.oldname_opt_record - oldname_opt_record = HOMEBREW_PREFIX/"opt/oldfoo" - oldname_opt_record.make_relative_symlink(HOMEBREW_CELLAR/"foo/1.0") - assert_equal oldname_opt_record, @keg.oldname_opt_record - end - - def test_optlink_relink - oldname_opt_record = HOMEBREW_PREFIX/"opt/oldfoo" - oldname_opt_record.make_relative_symlink(HOMEBREW_CELLAR/"foo/1.0") - keg_record = HOMEBREW_CELLAR.join("foo", "2.0") - keg_record.join("bin").mkpath - keg = Keg.new(keg_record) - keg.optlink - assert_equal keg_record, oldname_opt_record.resolved_path - keg.uninstall - refute_predicate oldname_opt_record, :symlink? - end - - def test_remove_oldname_opt_record - oldname_opt_record = HOMEBREW_PREFIX/"opt/oldfoo" - oldname_opt_record.make_relative_symlink(HOMEBREW_CELLAR/"foo/2.0") - @keg.remove_oldname_opt_record - assert_predicate oldname_opt_record, :symlink? - oldname_opt_record.unlink - oldname_opt_record.make_relative_symlink(HOMEBREW_CELLAR/"foo/1.0") - @keg.remove_oldname_opt_record - refute_predicate oldname_opt_record, :symlink? - end - - def test_link_dry_run - @mode.dry_run = true - - assert_equal 0, @keg.link(@mode) - refute_predicate @keg, :linked? - - ["hiworld", "helloworld", "goodbye_cruel_world"].each do |file| - assert_match "#{HOMEBREW_PREFIX}/bin/#{file}", $stdout.string - end - assert_equal 3, $stdout.string.lines.count - end - - def test_linking_fails_when_already_linked - @keg.link - assert_raises(Keg::AlreadyLinkedError) { @keg.link } - end - - def test_linking_fails_when_files_exist - touch @dst - assert_raises(Keg::ConflictError) { @keg.link } - end - - def test_link_ignores_broken_symlinks_at_target - src = @keg.join("bin", "helloworld") - @dst.make_symlink(@nonexistent) - @keg.link - assert_equal src.relative_path_from(@dst.dirname), @dst.readlink - end - - def test_link_overwrite - touch @dst - @mode.overwrite = true - assert_equal 3, @keg.link(@mode) - assert_predicate @keg, :linked? - end - - def test_link_overwrite_broken_symlinks - @dst.make_symlink "nowhere" - @mode.overwrite = true - assert_equal 3, @keg.link(@mode) - assert_predicate @keg, :linked? - end - - def test_link_overwrite_dryrun - touch @dst - @mode.overwrite = true - @mode.dry_run = true - - assert_equal 0, @keg.link(@mode) - refute_predicate @keg, :linked? - - assert_equal "#{@dst}\n", $stdout.string - end - - def test_unlink_prunes_empty_toplevel_directories - mkpath HOMEBREW_PREFIX/"lib/foo/bar" - mkpath @keg/"lib/foo/bar" - touch @keg/"lib/foo/bar/file1" - - @keg.unlink - - refute_predicate HOMEBREW_PREFIX/"lib/foo", :directory? - end - - def test_unlink_ignores_ds_store_when_pruning_empty_dirs - mkpath HOMEBREW_PREFIX/"lib/foo/bar" - touch HOMEBREW_PREFIX/"lib/foo/.DS_Store" - mkpath @keg/"lib/foo/bar" - touch @keg/"lib/foo/bar/file1" - - @keg.unlink - - refute_predicate HOMEBREW_PREFIX/"lib/foo", :directory? - refute_predicate HOMEBREW_PREFIX/"lib/foo/.DS_Store", :exist? - end - - def test_linking_creates_opt_link - refute_predicate @keg, :optlinked? - @keg.link - assert_predicate @keg, :optlinked? - end - - def test_unlinking_does_not_remove_opt_link - @keg.link - @keg.unlink - assert_predicate @keg, :optlinked? - end - - def test_existing_opt_link - @keg.opt_record.make_relative_symlink Pathname.new(@keg) - @keg.optlink - assert_predicate @keg, :optlinked? - end - - def test_existing_opt_link_directory - @keg.opt_record.mkpath - @keg.optlink - assert_predicate @keg, :optlinked? - end - - def test_existing_opt_link_file - @keg.opt_record.parent.mkpath - @keg.opt_record.write("foo") - @keg.optlink - assert_predicate @keg, :optlinked? - end - - def test_linked_keg - refute_predicate @keg, :linked? - @keg.link - assert_predicate @keg, :linked? - @keg.unlink - refute_predicate @keg, :linked? - end - - def test_unlink_preserves_broken_symlink_pointing_outside_the_keg - @keg.link - @dst.delete - @dst.make_symlink(@nonexistent) - @keg.unlink - assert_predicate @dst, :symlink? - end - - def test_unlink_preserves_broken_symlink_pointing_into_the_keg - @keg.link - @dst.resolved_path.delete - @keg.unlink - assert_predicate @dst, :symlink? - end - - def test_unlink_preserves_symlink_pointing_outside_of_keg - @keg.link - @dst.delete - @dst.make_symlink(Pathname.new("/bin/sh")) - @keg.unlink - assert_predicate @dst, :symlink? - end - - def test_unlink_preserves_real_file - @keg.link - @dst.delete - touch @dst - @keg.unlink - assert_predicate @dst, :file? - end - - def test_unlink_ignores_nonexistent_file - @keg.link - @dst.delete - assert_equal 2, @keg.unlink - end - - def test_pkgconfig_is_mkpathed - link = HOMEBREW_PREFIX.join("lib", "pkgconfig") - @keg.join("lib", "pkgconfig").mkpath - @keg.link - assert_predicate link.lstat, :directory? - end - - def test_cmake_is_mkpathed - link = HOMEBREW_PREFIX.join("lib", "cmake") - @keg.join("lib", "cmake").mkpath - @keg.link - assert_predicate link.lstat, :directory? - end - - def test_symlinks_are_linked_directly - link = HOMEBREW_PREFIX.join("lib", "pkgconfig") - - @keg.join("lib", "example").mkpath - @keg.join("lib", "pkgconfig").make_symlink "example" - @keg.link - - assert_predicate link.resolved_path, :symlink? - assert_predicate link.lstat, :symlink? - end - - def test_links_to_symlinks_are_not_removed - a = HOMEBREW_CELLAR.join("a", "1.0") - b = HOMEBREW_CELLAR.join("b", "1.0") - - a.join("lib", "example").mkpath - a.join("lib", "example2").make_symlink "example" - b.join("lib", "example2").mkpath - - a = Keg.new(a) - b = Keg.new(b) - a.link - - lib = HOMEBREW_PREFIX.join("lib") - assert_equal 2, lib.children.length - assert_raises(Keg::ConflictError) { b.link } - assert_equal 2, lib.children.length - ensure - a.unlink - end - - def test_removes_broken_symlinks_that_conflict_with_directories - a = HOMEBREW_CELLAR.join("a", "1.0") - a.join("lib", "foo").mkpath - - keg = Keg.new(a) - - link = HOMEBREW_PREFIX.join("lib", "foo") - link.parent.mkpath - link.make_symlink(@nonexistent) - - keg.link - ensure - keg.unlink - end -end - -class InstalledDependantsTests < LinkTestCase - def stub_formula_name(name) - f = formula(name) { url "foo-1.0" } - stub_formula_loader f - stub_formula_loader f, "homebrew/core/#{f}" - f - end - - def setup_test_keg(name, version) - f = stub_formula_name(name) - keg = super - Tab.create(f, DevelopmentTools.default_compiler, :libcxx).write - keg - end - - def setup - super - @dependent = setup_test_keg("bar", "1.0") - @keg.link - end - - def alter_tab(keg = @dependent) - tab = Tab.for_keg(keg) - yield tab - tab.write - end - - # 1.1.6 is the earliest version of Homebrew that generates correct runtime - # dependency lists in tabs. - def dependencies(deps, homebrew_version: "1.1.6") - alter_tab do |tab| - tab.homebrew_version = homebrew_version - tab.tabfile = @dependent.join("INSTALL_RECEIPT.json") - tab.runtime_dependencies = deps - end - end - - def unreliable_dependencies(deps) - # 1.1.5 is (hopefully!) the last version of Homebrew that generates - # incorrect runtime dependency lists in tabs. - dependencies(deps, homebrew_version: "1.1.5") - end - - # Test with a keg whose formula isn't known. - # This can happen if e.g. a formula is installed - # from a file path or URL. - def test_unknown_formula - Formulary.unstub(:loader_for) - alter_tab(@keg) do |t| - t.source["tap"] = "some/tap" - t.source["path"] = nil - end - - dependencies [{ "full_name" => "some/tap/foo", "version" => "1.0" }] - assert_equal [@dependent], @keg.installed_dependents - assert_equal [[@keg], ["bar 1.0"]], Keg.find_some_installed_dependents([@keg]) - - dependencies nil - # It doesn't make sense for a keg with no formula to have any dependents, - # so that can't really be tested. - assert_nil Keg.find_some_installed_dependents([@keg]) - end - - def test_a_dependency_with_no_tap_in_tab - @tap_dep = setup_test_keg("baz", "1.0") - - alter_tab(@keg) { |t| t.source["tap"] = nil } - - dependencies nil - Formula["bar"].class.depends_on "foo" - Formula["bar"].class.depends_on "baz" - - result = Keg.find_some_installed_dependents([@keg, @tap_dep]) - assert_equal [[@keg, @tap_dep], ["bar"]], result - end - - def test_no_dependencies_anywhere - dependencies nil - assert_empty @keg.installed_dependents - assert_nil Keg.find_some_installed_dependents([@keg]) - end - - def test_missing_formula_dependency - dependencies nil - Formula["bar"].class.depends_on "foo" - assert_empty @keg.installed_dependents - assert_equal [[@keg], ["bar"]], Keg.find_some_installed_dependents([@keg]) - end - - def test_uninstalling_dependent_and_dependency - dependencies nil - Formula["bar"].class.depends_on "foo" - assert_empty @keg.installed_dependents - assert_nil Keg.find_some_installed_dependents([@keg, @dependent]) - end - - def test_renamed_dependency - dependencies nil - - stub_formula_loader Formula["foo"], "homebrew/core/foo-old" - renamed_path = HOMEBREW_CELLAR/"foo-old" - (HOMEBREW_CELLAR/"foo").rename(renamed_path) - renamed_keg = Keg.new(renamed_path.join("1.0")) - - Formula["bar"].class.depends_on "foo" - - result = Keg.find_some_installed_dependents([renamed_keg]) - assert_equal [[renamed_keg], ["bar"]], result - end - - def test_empty_dependencies_in_tab - dependencies [] - assert_empty @keg.installed_dependents - assert_nil Keg.find_some_installed_dependents([@keg]) - end - - def test_same_name_different_version_in_tab - dependencies [{ "full_name" => "foo", "version" => "1.1" }] - assert_equal [@dependent], @keg.installed_dependents - assert_equal [[@keg], ["bar 1.0"]], Keg.find_some_installed_dependents([@keg]) - end - - def test_different_name_same_version_in_tab - stub_formula_name("baz") - dependencies [{ "full_name" => "baz", "version" => @keg.version.to_s }] - assert_empty @keg.installed_dependents - assert_nil Keg.find_some_installed_dependents([@keg]) - end - - def test_same_name_and_version_in_tab - dependencies [{ "full_name" => "foo", "version" => "1.0" }] - assert_equal [@dependent], @keg.installed_dependents - assert_equal [[@keg], ["bar 1.0"]], Keg.find_some_installed_dependents([@keg]) - end - - def test_fallback_for_old_versions - unreliable_dependencies [{ "full_name" => "baz", "version" => "1.0" }] - Formula["bar"].class.depends_on "foo" - assert_empty @keg.installed_dependents - assert_equal [[@keg], ["bar"]], Keg.find_some_installed_dependents([@keg]) - end - - def test_nonoptlinked - @keg.remove_opt_record - dependencies [{ "full_name" => "foo", "version" => "1.0" }] - assert_empty @keg.installed_dependents - assert_nil Keg.find_some_installed_dependents([@keg]) - end - - def test_keg_only - @keg.unlink - Formula["foo"].class.keg_only "a good reason" - dependencies [{ "full_name" => "foo", "version" => "1.1" }] # different version - assert_equal [@dependent], @keg.installed_dependents - assert_equal [[@keg], ["bar 1.0"]], Keg.find_some_installed_dependents([@keg]) - end -end