diff --git a/Library/Homebrew/test/cmd/autoremove_spec.rb b/Library/Homebrew/test/cmd/autoremove_spec.rb index 07b29812107b3..c15d45437a733 100644 --- a/Library/Homebrew/test/cmd/autoremove_spec.rb +++ b/Library/Homebrew/test/cmd/autoremove_spec.rb @@ -13,17 +13,17 @@ before do # Make testball1 poured from a bottle install_test_formula "testball1" - tab = Tab.for_name("testball1") + tab = Tab.for_formula_name("testball1") tab.poured_from_bottle = true - tab.write + tab.write_formula_file # Make testball2 poured from a bottle and an unused dependency install_test_formula "testball2" - tab = Tab.for_name("testball2") + tab = Tab.for_formula_name("testball2") tab.installed_on_request = false tab.installed_as_dependency = true tab.poured_from_bottle = true - tab.write + tab.write_formula_file end it "only removes unused dependencies", :integration_test do diff --git a/Library/Homebrew/test/formula_spec.rb b/Library/Homebrew/test/formula_spec.rb index 6fc08f61d1215..b2f754d2bdbd0 100644 --- a/Library/Homebrew/test/formula_spec.rb +++ b/Library/Homebrew/test/formula_spec.rb @@ -280,13 +280,13 @@ oldname_prefix.mkpath oldname_tab = Tab.empty oldname_tab.tabfile = oldname_prefix/Tab::FILENAME - oldname_tab.write + oldname_tab.write_formula_file expect(f).not_to need_migration oldname_tab.tabfile.unlink oldname_tab.source["tap"] = "homebrew/core" - oldname_tab.write + oldname_tab.write_formula_file expect(f).to need_migration @@ -348,7 +348,7 @@ tab = Tab.empty tab.tabfile = head_prefix/Tab::FILENAME tab.source["versions"] = { "stable" => "1.0" } - tab.write + tab.write_formula_file expect(f.latest_installed_prefix).to eq(stable_prefix) end @@ -380,7 +380,7 @@ tab = Tab.empty tab.tabfile = prefix/Tab::FILENAME tab.source_modified_time = stamp - tab.write + tab.write_formula_file end prefix = HOMEBREW_CELLAR/f.name/"HEAD-222222_2" @@ -887,9 +887,9 @@ def post_install formula = Class.new(Testball).new formula.brew { formula.install } - tab = Tab.create(formula, DevelopmentTools.default_compiler, :libcxx) + tab = Tab.create_from_formula(formula, DevelopmentTools.default_compiler, :libcxx) tab.runtime_dependencies = ["foo"] - tab.write + tab.write_formula_file keg = Keg.for(formula.latest_installed_prefix) keg.link @@ -1068,7 +1068,7 @@ class FooVariations < Formula [f1, f2, f3, f4].each do |f| f.brew { f.install } - Tab.create(f, DevelopmentTools.default_compiler, :libcxx).write + Tab.create_from_formula(f, DevelopmentTools.default_compiler, :libcxx).write_formula_file end expect(f1).to be_latest_version_installed @@ -1108,7 +1108,7 @@ class FooVariations < Formula tab = Tab.empty tab.tabfile = prefix/Tab::FILENAME tab.source_modified_time = 1 - tab.write + tab.write_formula_file end eligible_kegs = f.installed_kegs - [Keg.new(f.prefix("HEAD-111111_1")), Keg.new(f.prefix("0.1"))] @@ -1345,7 +1345,7 @@ def setup_tab_for_prefix(prefix, options = {}) tab.source["tap"] = options[:tap] if options[:tap] tab.source["versions"] = options[:versions] if options[:versions] tab.source_modified_time = options[:source_modified_time].to_i - tab.write unless options[:no_write] + tab.write_formula_file unless options[:no_write] tab end @@ -1502,7 +1502,7 @@ def setup_tab_for_prefix(prefix, options = {}) expect(f.outdated_kegs).not_to be_empty tab.source["versions"] = { "stable" => f.version.to_s } - tab.write + tab.write_formula_file described_class.clear_cache expect(f.outdated_kegs).to be_empty @@ -1541,7 +1541,7 @@ def setup_tab_for_prefix(prefix, options = {}) expect(f.outdated_kegs(fetch_head: true)).not_to be_empty tab_a.source["versions"] = { "stable" => f.version.to_s } - tab_a.write + tab_a.write_formula_file described_class.clear_cache expect(f.outdated_kegs(fetch_head: true)).not_to be_empty diff --git a/Library/Homebrew/test/installed_dependents_spec.rb b/Library/Homebrew/test/installed_dependents_spec.rb index 4bcbd383c44f4..ce67e6a9b65e9 100644 --- a/Library/Homebrew/test/installed_dependents_spec.rb +++ b/Library/Homebrew/test/installed_dependents_spec.rb @@ -41,7 +41,7 @@ def setup_test_keg(name, version, &block) describe "::find_some_installed_dependents" do def setup_test_keg(name, version, &block) keg = super - Tab.create(keg.to_formula, DevelopmentTools.default_compiler, :libcxx).write + Tab.create_from_formula(keg.to_formula, DevelopmentTools.default_compiler, :libcxx).write_formula_file keg end @@ -53,7 +53,7 @@ def setup_test_keg(name, version, &block) def alter_tab(keg) tab = keg.tab yield tab - tab.write + tab.write_formula_file end # 1.1.6 is the earliest version of Homebrew that generates correct runtime diff --git a/Library/Homebrew/test/migrator_spec.rb b/Library/Homebrew/test/migrator_spec.rb index 8a1608f88d596..c723407af495f 100644 --- a/Library/Homebrew/test/migrator_spec.rb +++ b/Library/Homebrew/test/migrator_spec.rb @@ -33,7 +33,7 @@ old_tab.tabfile = HOMEBREW_CELLAR/"oldname/0.1/INSTALL_RECEIPT.json" old_tab.source["path"] = "/oldname" - old_tab.write + old_tab.write_formula_file keg.link keg.optlink @@ -67,7 +67,7 @@ tab = Tab.empty tab.tabfile = HOMEBREW_CELLAR/"oldname/0.1/INSTALL_RECEIPT.json" tab.source["tap"] = "homebrew/core" - tab.write + tab.write_formula_file expect do described_class.new(new_formula, "oldname") @@ -151,7 +151,7 @@ tab = Tab.empty tab.tabfile = HOMEBREW_CELLAR/"newname/0.1/INSTALL_RECEIPT.json" tab.source["path"] = "/path/that/must/be/changed/by/update_tabs" - tab.write + tab.write_formula_file migrator.update_tabs expect(Tab.for_keg(new_keg_record).source["path"]).to eq(new_formula.path.to_s) end @@ -160,7 +160,7 @@ tab = Tab.empty tab.tabfile = HOMEBREW_CELLAR/"oldname/0.1/INSTALL_RECEIPT.json" tab.source["path"] = old_formula.path.to_s - tab.write + tab.write_formula_file migrator.migrate @@ -205,7 +205,7 @@ tab = Tab.empty tab.tabfile = HOMEBREW_CELLAR/"oldname/0.1/INSTALL_RECEIPT.json" tab.source["path"] = "/should/be/the/same" - tab.write + tab.write_formula_file migrator = described_class.new(new_formula, "oldname") tab.tabfile.delete migrator.backup_old_tabs diff --git a/Library/Homebrew/test/sbom_spec.rb b/Library/Homebrew/test/sbom_spec.rb index c270b2a0fda50..e162f3a0d5d0b 100644 --- a/Library/Homebrew/test/sbom_spec.rb +++ b/Library/Homebrew/test/sbom_spec.rb @@ -59,7 +59,7 @@ "declared_directly" => true, } end - expect(Tab).to receive(:runtime_deps_hash).and_return(runtime_deps_hash) + expect(Tab).to receive(:formula_runtime_deps_hash).and_return(runtime_deps_hash) tab = Tab.create(f, DevelopmentTools.default_compiler, :libcxx) expect(Formulary).to receive(:factory).with("beanstalkd").and_return(beanstalkd) diff --git a/Library/Homebrew/test/support/fixtures/cask_receipt.json b/Library/Homebrew/test/support/fixtures/cask_receipt.json new file mode 100644 index 0000000000000..d84bbfef80200 --- /dev/null +++ b/Library/Homebrew/test/support/fixtures/cask_receipt.json @@ -0,0 +1,53 @@ +{ + "homebrew_version": "4.3.7", + "loaded_from_api": false, + "caskfile_only": true, + "installed_as_dependency": false, + "installed_on_request": true, + "time": 1719289256, + "runtime_dependencies": { + "cask": [ + { + "full_name": "bar", + "version": "2.0", + "declared_directly": true + } + ], + "formula": [ + { + "full_name": "baz", + "version": "3.0", + "revision": 0, + "pkg_version": "3.0", + "declared_directly": true + } + ], + "macos": { + ">=": [ + "12" + ] + } + }, + "source": { + "path": "/opt/homebrew/Library/Taps/homebrew/homebrew-cask/Casks/f/foo.rb", + "tap": "homebrew/cask", + "tap_git_head": "8b79aa759500f0ffdf65a23e12950cbe3bf8fe17", + "version": "1.2.3" + }, + "arch": "arm64", + "uninstall_artifacts": [ + { + "app": [ + "Foo.app" + ] + } + ], + "built_on": { + "os": "Macintosh", + "os_version": "macOS 14", + "cpu_family": "arm_firestorm_icestorm", + "xcode": "15.4", + "clt": "15.3.0.0.1.1708646388", + "preferred_perl": "5.34" + } +} diff --git a/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb b/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb index c11c4e4d4df9d..9ad4b73830a2e 100644 --- a/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb +++ b/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb @@ -190,12 +190,12 @@ class #{Formulary.class_s(name)} < Formula keg = Formula[name].prefix keg.mkpath - tab = Tab.for_name(name) + tab = Tab.for_formula_name(name) tab.tabfile ||= keg/Tab::FILENAME tab_attributes.each do |key, value| tab.instance_variable_set(:"@#{key}", value) end - tab.write + tab.write_formula_file formula_path end diff --git a/Library/Homebrew/test/tab_spec.rb b/Library/Homebrew/test/tab_spec.rb index 961f9c0e5cded..75f52068ddba3 100644 --- a/Library/Homebrew/test/tab_spec.rb +++ b/Library/Homebrew/test/tab_spec.rb @@ -18,8 +18,32 @@ end end + matcher :be_installed_as_dependency do + match do |actual| + actual.installed_as_dependency == true + end + end + + matcher :be_installed_on_request do + match do |actual| + actual.installed_on_request == true + end + end + + matcher :be_loaded_from_api do + match do |actual| + actual.loaded_from_api == true + end + end + + matcher :be_caskfile_only do + match do |actual| + actual.caskfile_only == true + end + end + subject(:tab) do - described_class.new( + attributes = { "homebrew_version" => HOMEBREW_VERSION, "used_options" => used_options.as_flags, "unused_options" => unused_options.as_flags, @@ -42,7 +66,34 @@ }, "arch" => Hardware::CPU.arch, "built_on" => DevelopmentTools.build_system_info, - ) + } + + described_class.new(attributes) + end + + let(:cask_tab) do + attributes = { + "homebrew_version" => HOMEBREW_VERSION, + "loaded_from_api" => false, + "caskfile_only" => true, + "installed_as_dependency" => false, + "installed_on_request" => true, + "time" => time, + "runtime_dependencies" => { + "cask" => [{ "full_name" => "bar", "version" => "2.0", "declared_directly" => false }], + }, + "source" => { + "path" => CoreCaskTap.instance.path.to_s, + "tap" => CoreCaskTap.instance.to_s, + "tap_git_head" => "8b79aa759500f0ffdf65a23e12950cbe3bf8fe17", + "version" => "1.2.3", + }, + "arch" => Hardware::CPU.arch, + "uninstall_artifacts" => [{ "app" => ["Foo.app"] }], + "built_on" => DevelopmentTools.build_system_info, + } + + described_class.new(attributes) end let(:time) { Time.now.to_i } @@ -53,7 +104,7 @@ let(:f_tab_path) { f.prefix/"INSTALL_RECEIPT.json" } let(:f_tab_content) { (TEST_FIXTURE_DIR/"receipt.json").read } - specify "defaults" do + specify "formula defaults" do # < 1.1.7 runtime_dependencies were wrong so are ignored stub_const("HOMEBREW_VERSION", "1.1.7") @@ -77,6 +128,22 @@ expect(tab.source["path"]).to be_nil end + specify "cask defaults" do + stub_const("HOMEBREW_VERSION", "4.3.7") + + tab = described_class.empty + + expect(tab.homebrew_version).to eq(HOMEBREW_VERSION) + expect(tab).not_to be_installed_as_dependency + expect(tab).not_to be_installed_on_request + expect(tab).not_to be_loaded_from_api + expect(tab).not_to be_caskfile_only + expect(tab.tap).to be_nil + expect(tab.time).to be_nil + expect(tab.runtime_dependencies).to be_nil + expect(tab.source["path"]).to be_nil + end + specify "#include?" do expect(tab).to include("with-foo") expect(tab).to include("without-bar") @@ -132,11 +199,11 @@ expect(tab.runtime_dependencies).not_to be_nil end - specify "::runtime_deps_hash" do + specify "::formula_runtime_deps_hash" do runtime_deps = [Dependency.new("foo")] foo = formula("foo") { url "foo-1.0" } stub_formula_loader foo - runtime_deps_hash = described_class.runtime_deps_hash(foo, runtime_deps) + runtime_deps_hash = described_class.formula_runtime_deps_hash(foo, runtime_deps) tab = described_class.new tab.homebrew_version = "1.1.6" tab.runtime_dependencies = runtime_deps_hash @@ -158,10 +225,10 @@ expect(tab).to be_poured_from_bottle end - describe "::from_file" do - it "parses a Tab from a file" do + describe "::from_formula_file" do + it "parses a formula Tab from a file" do path = Pathname.new("#{TEST_FIXTURE_DIR}/receipt.json") - tab = described_class.from_file(path) + tab = described_class.from_formula_file(path) source_path = "/usr/local/Library/Taps/homebrew/homebrew-core/Formula/foo.rb" runtime_dependencies = [{ "full_name" => "foo", "version" => "1.0" }] changed_files = %w[INSTALL_RECEIPT.json bin/foo] @@ -185,10 +252,51 @@ end end - describe "::from_file_content" do - it "parses a Tab from a file" do + describe "::from_cask_file" do + it "parses a cask Tab from a file" do + path = Pathname.new("#{TEST_FIXTURE_DIR}/cask_receipt.json") + tab = described_class.from_cask_file(path) + source_path = "/opt/homebrew/Library/Taps/homebrew/homebrew-cask/Casks/f/foo.rb" + runtime_dependencies = { + "cask" => [ + { + "full_name" => "bar", + "version" => "2.0", + "declared_directly" => true, + }, + ], + "formula" => [ + { + "full_name" => "baz", + "version" => "3.0", + "revision" => 0, + "pkg_version" => "3.0", + "declared_directly" => true, + }, + ], + "macos" => { + ">=" => [ + "12", + ], + }, + } + + expect(tab).not_to be_loaded_from_api + expect(tab).to be_caskfile_only + expect(tab).not_to be_installed_as_dependency + expect(tab).to be_installed_on_request + expect(tab.time).to eq(Time.at(1_719_289_256).to_i) + expect(tab.runtime_dependencies).to eq(runtime_dependencies) + expect(tab.source["path"]).to eq(source_path) + expect(tab.cask_version).to eq("1.2.3") + expect(tab.tap.name).to eq("homebrew/cask") + end + end + + describe "::from_formula_file_content" do + it "parses a formula Tab from a file" do path = Pathname.new("#{TEST_FIXTURE_DIR}/receipt.json") - tab = described_class.from_file_content(path.read, path) + tab = described_class.from_formula_file_content(path.read, path) source_path = "/usr/local/Library/Taps/homebrew/homebrew-core/Formula/foo.rb" runtime_dependencies = [{ "full_name" => "foo", "version" => "1.0" }] changed_files = %w[INSTALL_RECEIPT.json bin/foo] @@ -211,9 +319,9 @@ expect(tab.source["path"]).to eq(source_path) end - it "can parse an old Tab file" do + it "can parse an old formula Tab file" do path = Pathname.new("#{TEST_FIXTURE_DIR}/receipt_old.json") - tab = described_class.from_file_content(path.read, path) + tab = described_class.from_formula_file_content(path.read, path) expect(tab.used_options.sort).to eq(used_options.sort) expect(tab.unused_options.sort).to eq(unused_options.sort) @@ -230,15 +338,64 @@ end it "raises a parse exception message including the Tab filename" do - expect { described_class.from_file_content("''", "receipt.json") }.to raise_error( + expect { described_class.from_formula_file_content("''", "receipt.json") }.to raise_error( JSON::ParserError, /receipt.json:/, ) end end - describe "::create" do - it "creates a Tab" do + describe "::from_cask_file_content" do + it "parses a cask Tab from a file" do + path = Pathname.new("#{TEST_FIXTURE_DIR}/cask_receipt.json") + tab = described_class.from_cask_file_content(path.read, path) + source_path = "/opt/homebrew/Library/Taps/homebrew/homebrew-cask/Casks/f/foo.rb" + runtime_dependencies = { + "cask" => [ + { + "full_name" => "bar", + "version" => "2.0", + "declared_directly" => true, + }, + ], + "formula" => [ + { + "full_name" => "baz", + "version" => "3.0", + "revision" => 0, + "pkg_version" => "3.0", + "declared_directly" => true, + }, + ], + "macos" => { + ">=" => [ + "12", + ], + }, + } + + expect(tab).not_to be_loaded_from_api + expect(tab).to be_caskfile_only + expect(tab).not_to be_installed_as_dependency + expect(tab).to be_installed_on_request + expect(tab.tabfile).to eq(path) + expect(tab.time).to eq(Time.at(1_719_289_256).to_i) + expect(tab.runtime_dependencies).to eq(runtime_dependencies) + expect(tab.source["path"]).to eq(source_path) + expect(tab.cask_version).to eq("1.2.3") + expect(tab.tap.name).to eq("homebrew/cask") + end + + it "raises a parse exception message including the Tab filename" do + expect { described_class.from_cask_file_content("''", "receipt.json") }.to raise_error( + JSON::ParserError, + /receipt.json:/, + ) + end + end + + describe "::create_from_formula" do + it "creates a formula Tab" do # < 1.1.7 runtime dependencies were wrong so are ignored stub_const("HOMEBREW_VERSION", "1.1.7") @@ -264,7 +421,7 @@ compiler = DevelopmentTools.default_compiler stdlib = :libcxx - tab = described_class.create(f, compiler, stdlib) + tab = described_class.create_from_formula(f, compiler, stdlib) runtime_dependencies = [ { "full_name" => "bar", "version" => "2.0", "revision" => 0, "pkg_version" => "2.0", @@ -277,12 +434,12 @@ expect(tab.source["path"]).to eq(f.path.to_s) end - it "can create a Tab from an alias" do + it "can create a formula Tab from an alias" do alias_path = CoreTap.instance.alias_dir/"bar" f = formula(alias_path:) { url "foo-1.0" } compiler = DevelopmentTools.default_compiler stdlib = :libcxx - tab = described_class.create(f, compiler, stdlib) + tab = described_class.create_from_formula(f, compiler, stdlib) expect(tab.source["path"]).to eq(f.alias_path.to_s) end @@ -362,25 +519,47 @@ end end - specify "#to_json" do - json_tab = described_class.new(JSON.parse(tab.to_json)) - expect(json_tab.homebrew_version).to eq(tab.homebrew_version) - expect(json_tab.used_options.sort).to eq(tab.used_options.sort) - expect(json_tab.unused_options.sort).to eq(tab.unused_options.sort) - expect(json_tab.built_as_bottle).to eq(tab.built_as_bottle) - expect(json_tab.poured_from_bottle).to eq(tab.poured_from_bottle) - expect(json_tab.changed_files).to eq(tab.changed_files) - expect(json_tab.tap).to eq(tab.tap) - expect(json_tab.spec).to eq(tab.spec) - expect(json_tab.time).to eq(tab.time) - expect(json_tab.compiler).to eq(tab.compiler) - expect(json_tab.stdlib).to eq(tab.stdlib) - expect(json_tab.runtime_dependencies).to eq(tab.runtime_dependencies) - expect(json_tab.stable_version).to eq(tab.stable_version) - expect(json_tab.head_version).to eq(tab.head_version) - expect(json_tab.source["path"]).to eq(tab.source["path"]) - expect(json_tab.arch).to eq(tab.arch.to_s) - expect(json_tab.built_on["os"]).to eq(tab.built_on["os"]) + describe "#to_formula_json" do + it "returns a JSON representation of a formula Tab" do + json_tab = described_class.new(JSON.parse(tab.to_formula_json)) + expect(json_tab.homebrew_version).to eq(tab.homebrew_version) + expect(json_tab.used_options.sort).to eq(tab.used_options.sort) + expect(json_tab.unused_options.sort).to eq(tab.unused_options.sort) + expect(json_tab.built_as_bottle).to eq(tab.built_as_bottle) + expect(json_tab.poured_from_bottle).to eq(tab.poured_from_bottle) + expect(json_tab.changed_files).to eq(tab.changed_files) + expect(json_tab.tap).to eq(tab.tap) + expect(json_tab.spec).to eq(tab.spec) + expect(json_tab.time).to eq(tab.time) + expect(json_tab.compiler).to eq(tab.compiler) + expect(json_tab.stdlib).to eq(tab.stdlib) + expect(json_tab.runtime_dependencies).to eq(tab.runtime_dependencies) + expect(json_tab.stable_version).to eq(tab.stable_version) + expect(json_tab.head_version).to eq(tab.head_version) + expect(json_tab.source["path"]).to eq(tab.source["path"]) + expect(json_tab.arch).to eq(tab.arch.to_s) + expect(json_tab.built_on["os"]).to eq(tab.built_on["os"]) + end + end + + describe "#to_cask_json" do + it "returns a JSON representation of a cask Tab" do + json_tab = described_class.new(JSON.parse(cask_tab.to_cask_json)) + expect(json_tab.homebrew_version).to eq(cask_tab.homebrew_version) + expect(json_tab.loaded_from_api).to eq(cask_tab.loaded_from_api) + expect(json_tab.caskfile_only).to eq(cask_tab.caskfile_only) + expect(json_tab.installed_as_dependency).to eq(cask_tab.installed_as_dependency) + expect(json_tab.installed_on_request).to eq(cask_tab.installed_on_request) + expect(json_tab.time).to eq(cask_tab.time) + expect(json_tab.runtime_dependencies).to eq(cask_tab.runtime_dependencies) + expect(json_tab.source["path"]).to eq(cask_tab.source["path"]) + expect(json_tab.tap).to eq(cask_tab.tap) + expect(json_tab.source["tap_git_head"]).to eq(cask_tab.source["tap_git_head"]) + expect(json_tab.cask_version).to eq(cask_tab.cask_version) + expect(json_tab.arch).to eq(cask_tab.arch.to_s) + expect(json_tab.uninstall_artifacts).to eq(cask_tab.uninstall_artifacts) + expect(json_tab.built_on["os"]).to eq(cask_tab.built_on["os"]) + end end specify "#to_bottle_hash" do diff --git a/Library/Homebrew/test/uninstall_spec.rb b/Library/Homebrew/test/uninstall_spec.rb index e4cc7d1f9191d..1207c1bdc4ab5 100644 --- a/Library/Homebrew/test/uninstall_spec.rb +++ b/Library/Homebrew/test/uninstall_spec.rb @@ -37,7 +37,7 @@ tab.runtime_dependencies = [ { "full_name" => "dependency", "version" => "1" }, ] - tab.write + tab.write_formula_file Cask::Caskroom.path.join("dependent_cask", dependent_cask.version).mkpath