mirror of
https://github.com/Homebrew/brew.git
synced 2026-08-12 22:29:27 +04:00
- Make every statically-poked method public and call it directly, keeping `public_send` only for dynamically-named public methods. - Read and write state through public `attr_*` accessors instead of instance variable reflection. - Enable `Homebrew/NoSendInTests` and `Homebrew/NoInstanceVariableAccessInTests` now the test suite is clean, so neither pattern creeps back in. - Keep rare justified disables, e.g. `Module#remove_const` is private core Ruby and raw memoisation state has no accessor.
1574 lines
57 KiB
Ruby
1574 lines
57 KiB
Ruby
# typed: false
|
|
# frozen_string_literal: true
|
|
|
|
require "cmd/info"
|
|
require "cmd/shared_examples/args_parse"
|
|
|
|
RSpec.describe Homebrew::Cmd::Info do
|
|
before do
|
|
allow(DevelopmentTools).to receive_messages(needs_libc_formula?: false, needs_compiler_formula?: false)
|
|
end
|
|
|
|
RSpec::Matchers.define :a_json_string do
|
|
match do |actual|
|
|
JSON.parse(actual)
|
|
true
|
|
rescue JSON::ParserError
|
|
false
|
|
end
|
|
end
|
|
|
|
def installed_info_formula
|
|
test_formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
desc "Some test"
|
|
end
|
|
(HOMEBREW_CELLAR/"testball/0.1").mkpath
|
|
test_formula
|
|
end
|
|
|
|
def installed_info_cask
|
|
cask = Cask::Cask.new("local-transmission") do
|
|
version "2.61"
|
|
name "Transmission"
|
|
desc "BitTorrent client"
|
|
url "https://example.com/local-transmission.zip"
|
|
end
|
|
allow(cask).to receive(:installed_version).and_return("2.61")
|
|
cask
|
|
end
|
|
|
|
it_behaves_like "parseable arguments"
|
|
|
|
it "prints as json with the --json=v1 flag" do
|
|
test_formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
desc "Some test"
|
|
end
|
|
info = described_class.new(["--json=v1", "testball"])
|
|
allow(info.args.named).to receive(:to_formulae).and_return([test_formula])
|
|
|
|
expect { info.run }
|
|
.to output(a_json_string).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "prints as json with the --json=v2 flag", :integration_test do
|
|
setup_test_formula "testball"
|
|
|
|
expect { brew "info", "testball", "--json=v2" }
|
|
.to output(a_json_string).to_stdout
|
|
.and not_to_output.to_stderr
|
|
.and be_a_success
|
|
end
|
|
|
|
it "does not include installed casks in formula JSON" do
|
|
formula = installed_info_formula
|
|
|
|
allow(Formula).to receive(:installed).and_return([formula])
|
|
expect(Cask::Caskroom).not_to receive(:casks)
|
|
|
|
output = +""
|
|
expect { described_class.new(["--json=v2", "--installed", "--formula"]).run }
|
|
.to output(satisfy { |s|
|
|
output << s
|
|
true
|
|
}).to_stdout
|
|
.and not_to_output.to_stderr
|
|
|
|
json = JSON.parse(output)
|
|
expect(json["formulae"].length).to eq(1)
|
|
expect(json["casks"]).to be_empty
|
|
end
|
|
|
|
it "does not include eval-all casks in formula JSON" do
|
|
formula = installed_info_formula
|
|
|
|
allow(Formula).to receive(:all).and_return([formula])
|
|
allow(Homebrew::EnvConfig).to receive(:tap_trust_configured?).and_return(true)
|
|
expect(Cask::Cask).not_to receive(:all)
|
|
|
|
output = +""
|
|
expect { described_class.new(["--json=v2", "--formula"]).run }
|
|
.to output(satisfy { |s|
|
|
output << s
|
|
true
|
|
}).to_stdout
|
|
.and not_to_output.to_stderr
|
|
|
|
json = JSON.parse(output)
|
|
expect(json["formulae"].length).to eq(1)
|
|
expect(json["casks"]).to be_empty
|
|
end
|
|
|
|
it "prints installed formulae in a human-readable inventory" do
|
|
mktmpdir do |dir|
|
|
tabfile = dir/AbstractTab::FILENAME
|
|
tabfile.write("{}")
|
|
formula = installed_info_formula
|
|
|
|
allow(Formula).to receive(:installed).and_return([formula])
|
|
allow(Tab).to receive(:for_formula).with(formula).and_return(
|
|
Tab.new(installed_on_request: true, source: { "tap" => "homebrew/core" }, tabfile:),
|
|
)
|
|
allow(Cask::Caskroom).to receive(:casks).and_return([])
|
|
|
|
expected_output = <<~EOS
|
|
==> testball: Some test
|
|
Formula from homebrew/core
|
|
Installed: 0.1 (on request)
|
|
EOS
|
|
expect { described_class.new(["--installed"]).run }
|
|
.to output(expected_output).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
end
|
|
|
|
it "prints installed casks in a human-readable inventory" do
|
|
mktmpdir do |dir|
|
|
tabfile = dir/AbstractTab::FILENAME
|
|
tabfile.write("{}")
|
|
cask = installed_info_cask
|
|
|
|
allow(Formula).to receive(:installed).and_return([])
|
|
allow(Cask::Caskroom).to receive(:casks).and_return([cask])
|
|
allow(Cask::Tab).to receive(:for_cask).with(cask).and_return(
|
|
Cask::Tab.new(installed_on_request: false, source: { "tap" => "homebrew/cask" }, tabfile:),
|
|
)
|
|
|
|
expected_output = <<~EOS
|
|
==> local-transmission: (Transmission) BitTorrent client
|
|
Cask from homebrew/cask
|
|
Installed: 2.61 (dependency)
|
|
EOS
|
|
expect { described_class.new(["--installed"]).run }
|
|
.to output(expected_output).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
end
|
|
|
|
it "omits missing cask descriptions from the installed inventory" do
|
|
mktmpdir do |dir|
|
|
tabfile = dir/AbstractTab::FILENAME
|
|
tabfile.write("{}")
|
|
cask = Cask::Cask.new("no-description") do
|
|
version "1.0"
|
|
name "No Description"
|
|
url "https://example.com/no-description.zip"
|
|
end
|
|
allow(cask).to receive(:installed_version).and_return("1.0")
|
|
|
|
allow(Formula).to receive(:installed).and_return([])
|
|
allow(Cask::Caskroom).to receive(:casks).and_return([cask])
|
|
allow(Cask::Tab).to receive(:for_cask).with(cask).and_return(
|
|
Cask::Tab.new(source: { "tap" => "homebrew/cask" }, tabfile:),
|
|
)
|
|
|
|
expected_output = <<~EOS
|
|
==> no-description
|
|
Cask from homebrew/cask
|
|
Installed: 1.0
|
|
EOS
|
|
expect { described_class.new(["--installed"]).run }
|
|
.to output(expected_output).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
end
|
|
|
|
it "omits install reason when receipt intent is unavailable" do
|
|
mktmpdir do |dir|
|
|
tabfile = dir/AbstractTab::FILENAME
|
|
tabfile.write("{}")
|
|
formula = installed_info_formula
|
|
cask = installed_info_cask
|
|
|
|
allow(Formula).to receive(:installed).and_return([formula])
|
|
allow(Tab).to receive(:for_formula).with(formula).and_return(
|
|
Tab.new(source: { "tap" => "homebrew/core" }, tabfile:),
|
|
)
|
|
allow(Cask::Caskroom).to receive(:casks).and_return([cask])
|
|
allow(Cask::Tab).to receive(:for_cask).with(cask).and_return(
|
|
Cask::Tab.new(source: { "tap" => "homebrew/cask" }, tabfile:),
|
|
)
|
|
|
|
expected_output = <<~EOS
|
|
==> testball: Some test
|
|
Formula from homebrew/core
|
|
Installed: 0.1
|
|
|
|
==> local-transmission: (Transmission) BitTorrent client
|
|
Cask from homebrew/cask
|
|
Installed: 2.61
|
|
EOS
|
|
expect { described_class.new(["--installed"]).run }
|
|
.to output(expected_output).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
end
|
|
|
|
it "marks installed formulae in interactive inventory output" do
|
|
allow_any_instance_of(StringIO).to receive(:tty?).and_return(true)
|
|
mktmpdir do |dir|
|
|
tabfile = dir/AbstractTab::FILENAME
|
|
tabfile.write("{}")
|
|
formula = installed_info_formula
|
|
|
|
allow(Formula).to receive(:installed).and_return([formula])
|
|
allow(Tab).to receive(:for_formula).with(formula).and_return(
|
|
Tab.new(installed_on_request: true, source: { "tap" => "homebrew/core" }, tabfile:),
|
|
)
|
|
allow(Cask::Caskroom).to receive(:casks).and_return([])
|
|
|
|
expect { described_class.new(["--installed"]).run }
|
|
.to output(/testball .*✔.*: Some test/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
end
|
|
|
|
it "prints verbose installed inventory as full info" do
|
|
info = described_class.new(["--verbose", "--installed"])
|
|
formula = installed_info_formula
|
|
cask = installed_info_cask
|
|
|
|
allow(Formula).to receive(:installed).and_return([formula])
|
|
allow(Cask::Caskroom).to receive(:casks).and_return([cask])
|
|
expect(info).to receive(:info_formula).with(formula, shadowed_by: nil)
|
|
expect(info).to receive(:info_cask).with(cask)
|
|
|
|
expect { info.run }
|
|
.to output("\n").to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "prints quiet formula information in the slim inventory format" do
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
desc "Some test"
|
|
end
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
|
|
expected_output = <<~EOS
|
|
==> testball: Some test
|
|
Formula from https://example.com/testball.rb
|
|
Not installed
|
|
EOS
|
|
expect { info.info_formula_summary(formula) }
|
|
.to output(expected_output).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "uses slim formula information when quiet is passed" do
|
|
test_formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
desc "Some test"
|
|
end
|
|
info = described_class.new(["--quiet", "testball"])
|
|
allow(info.args.named).to receive(:to_formulae_and_casks_and_unavailable).and_return([test_formula])
|
|
|
|
expect(info).to receive(:info_formula_summary).with(test_formula)
|
|
expect { info.run }
|
|
.to not_to_output.to_stderr
|
|
end
|
|
|
|
it "prints inline summary information for formulae" do
|
|
allow_any_instance_of(StringIO).to receive(:tty?).and_return(true)
|
|
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
homepage "https://brew.sh/testball"
|
|
desc "Some test"
|
|
|
|
option "with-foo", "Build with foo"
|
|
end
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(core_formula?: false, missing_library_linkage: [[], Set.new])
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to output(/Installs from source: yes/).to_stdout
|
|
.and not_to_output(/Metadata/).to_stdout
|
|
.and not_to_output(/supports macOS and Linux/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "shows a conflict by its resolved full name" do
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
conflicts_with "other"
|
|
end
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
other = formula("other") { url "https://brew.sh/other-0.1.tar.gz" }
|
|
allow(other).to receive(:full_name).and_return("someuser/tap/other")
|
|
allow(Formulary).to receive(:factory).with("other").and_return(other)
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to output(%r{Conflicts with:\n someuser/tap/other}).to_stdout
|
|
end
|
|
|
|
it "omits a stale conflict that resolves to the formula itself" do
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
conflicts_with "testball"
|
|
end
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(Formulary).to receive(:factory).with("testball").and_return(formula)
|
|
|
|
expect { info.info_formula(formula) }
|
|
.not_to output(/Conflicts with:/).to_stdout
|
|
end
|
|
|
|
it "marks a deprecated formula with `(deprecated)` in the title" do
|
|
allow_any_instance_of(StringIO).to receive(:tty?).and_return(true)
|
|
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
desc "Some test"
|
|
deprecate! date: "2024-01-01", because: :versioned_formula
|
|
end
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(core_formula?: false, missing_library_linkage: [[], Set.new])
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to output(/==> .*testball.*\(deprecated\):/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "marks a disabled formula with `(disabled)` in the title" do
|
|
allow_any_instance_of(StringIO).to receive(:tty?).and_return(true)
|
|
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
desc "Some test"
|
|
disable! date: "2024-01-01", because: :unmaintained
|
|
end
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(core_formula?: false, missing_library_linkage: [[], Set.new])
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to output(/==> .*testball.*\(disabled\):/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "shows separate blocks for an unqualified and a qualified input that resolve to the same shadowed formula" do
|
|
info = described_class.new([])
|
|
core = installed_info_formula
|
|
keg_path = HOMEBREW_CELLAR/"testball/0.1"
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.source["tap"] = "ataraxy-labs/tap"
|
|
tab.write
|
|
allow(core).to receive(:tap).and_return(Tap.fetch("homebrew/core"))
|
|
installed = formula("testball") { url "https://brew.sh/testball-0.1.tar.gz" }
|
|
allow(installed).to receive_messages(tap: Tap.fetch("ataraxy-labs/tap"), full_name: "ataraxy-labs/tap/testball")
|
|
allow(Formulary).to receive(:factory).with("ataraxy-labs/tap/testball").and_return(installed)
|
|
allow(info).to receive(:github_info).and_return("https://example.com/testball.rb")
|
|
allow(info.args.named).to receive_messages(
|
|
downcased_unique_named: ["testball", "homebrew/core/testball"],
|
|
to_formulae_and_casks_and_unavailable: [core, core],
|
|
)
|
|
|
|
expect { info.print_info }
|
|
.to output(%r{ataraxy-labs/tap/testball.*homebrew/core/testball.*Not installed}m).to_stdout
|
|
end
|
|
|
|
it "reports an unavailable name without raising" do
|
|
info = described_class.new([])
|
|
error = FormulaOrCaskUnavailableError.new("nonexistent-formula")
|
|
allow(info.args.named).to receive_messages(
|
|
downcased_unique_named: ["nonexistent-formula"],
|
|
to_formulae_and_casks_and_unavailable: [error],
|
|
)
|
|
|
|
expect { info.print_info }
|
|
.to output(/No available formula or cask with the name "nonexistent-formula"/).to_stderr
|
|
end
|
|
|
|
it "qualifies the name, reports not installed and shows the shadowing keg when the keg belongs to another tap" do
|
|
info = described_class.new([])
|
|
formula = installed_info_formula
|
|
keg_path = HOMEBREW_CELLAR/"testball/0.1"
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.source["tap"] = "ataraxy-labs/tap"
|
|
tab.write
|
|
allow(formula).to receive(:tap).and_return(Tap.fetch("homebrew/core"))
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
shadowing = formula("testball") { url "https://brew.sh/testball-0.1.tar.gz" }
|
|
allow(shadowing).to receive_messages(tap: Tap.fetch("ataraxy-labs/tap"), full_name: "ataraxy-labs/tap/testball")
|
|
allow(Formulary).to receive(:factory).with("ataraxy-labs/tap/testball").and_return(shadowing)
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to output(%r{homebrew/core/testball.*Not installed.*ataraxy-labs/tap/testball}m).to_stdout
|
|
end
|
|
|
|
it "reloads the formula from the install receipt's tap and reports the shadowing tap" do
|
|
info = described_class.new([])
|
|
formula = installed_info_formula
|
|
|
|
keg_path = HOMEBREW_CELLAR/"testball/0.1"
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.source["tap"] = "ataraxy-labs/tap"
|
|
tab.write
|
|
|
|
shadowing_tap = Tap.fetch("homebrew/core")
|
|
allow(formula).to receive(:tap).and_return(shadowing_tap)
|
|
keg_formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
end
|
|
allow(Formulary).to receive(:factory).with("ataraxy-labs/tap/testball").and_return(keg_formula)
|
|
|
|
expect(info.installed_resolution(formula)).to eq([keg_formula, shadowing_tap])
|
|
end
|
|
|
|
it "resolves the keg's own name when it differs from the formula (installed via alias)" do
|
|
info = described_class.new([])
|
|
formula = installed_info_formula
|
|
tab = instance_double(Tab, tap: Tap.fetch("stripe/stripe-cli"))
|
|
keg = instance_double(Keg, name: "stripe", tab:)
|
|
allow(formula).to receive_messages(tap: Tap.fetch("homebrew/core"), installed_kegs: [keg])
|
|
keg_formula = formula("stripe") { url "https://brew.sh/stripe-1.0.tar.gz" }
|
|
allow(Formulary).to receive(:factory).with("stripe/stripe-cli/stripe").and_return(keg_formula)
|
|
|
|
expect(info.installed_resolution(formula)).to eq([keg_formula, Tap.fetch("homebrew/core")])
|
|
end
|
|
|
|
it "returns the original formula and no shadowing tap when the install receipt has no tap" do
|
|
info = described_class.new([])
|
|
formula = installed_info_formula
|
|
|
|
keg_path = HOMEBREW_CELLAR/"testball/0.1"
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.write
|
|
|
|
expect(info.installed_resolution(formula)).to eq([formula, nil])
|
|
end
|
|
|
|
it "returns the original formula and no shadowing tap when the install receipt's tap matches" do
|
|
info = described_class.new([])
|
|
formula = installed_info_formula
|
|
|
|
keg_path = HOMEBREW_CELLAR/"testball/0.1"
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.source["tap"] = "homebrew/core"
|
|
tab.write
|
|
|
|
allow(formula).to receive(:tap).and_return(Tap.fetch("homebrew/core"))
|
|
expect(info.installed_resolution(formula)).to eq([formula, nil])
|
|
end
|
|
|
|
it "warns about a shadowing tap when info_formula is given one" do
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
end
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(core_formula?: false, missing_library_linkage: [[], Set.new])
|
|
|
|
expect { info.info_formula(formula, shadowed_by: Tap.fetch("homebrew/core")) }
|
|
.to output(%r{Warning: `testball` shadows `homebrew/core/testball`}).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "treats a `tap/name` input as user-qualified" do
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
end
|
|
allow(formula).to receive(:tap).and_return(Tap.fetch("homebrew/core"))
|
|
|
|
qualified = Set["homebrew/core/testball"]
|
|
expect(info.formula_qualified_by_user?(formula, qualified)).to be(true)
|
|
end
|
|
|
|
it "treats a bare unqualified input as not user-qualified" do
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
end
|
|
|
|
expect(info.formula_qualified_by_user?(formula, Set.new)).to be(false)
|
|
end
|
|
|
|
it "--json swaps an unqualified-input formula to its installed tap" do
|
|
info = described_class.new(["--json", "testball"])
|
|
shadowed_formula = installed_info_formula
|
|
|
|
keg_path = HOMEBREW_CELLAR/"testball/0.1"
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.source["tap"] = "ataraxy-labs/tap"
|
|
tab.write
|
|
|
|
allow(shadowed_formula).to receive(:tap).and_return(Tap.fetch("homebrew/core"))
|
|
installed_formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
end
|
|
allow(installed_formula).to receive(:tap).and_return(Tap.fetch("ataraxy-labs/tap"))
|
|
allow(info.args.named).to receive(:to_formulae).and_return([shadowed_formula])
|
|
allow(Formulary).to receive(:factory).with("ataraxy-labs/tap/testball").and_return(installed_formula)
|
|
|
|
output = +""
|
|
expect { info.run }.to output(satisfy { |s|
|
|
output << s
|
|
true
|
|
}).to_stdout
|
|
expect(JSON.parse(output).first["tap"]).to eq("ataraxy-labs/tap")
|
|
end
|
|
|
|
it "--json honours a tap-qualified input without swapping" do
|
|
info = described_class.new(["--json", "homebrew/core/testball"])
|
|
formula = installed_info_formula
|
|
|
|
keg_path = HOMEBREW_CELLAR/"testball/0.1"
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.source["tap"] = "ataraxy-labs/tap"
|
|
tab.write
|
|
|
|
allow(formula).to receive(:tap).and_return(Tap.fetch("homebrew/core"))
|
|
allow(info.args.named).to receive(:to_formulae).and_return([formula])
|
|
|
|
output = +""
|
|
expect { info.run }.to output(satisfy { |s|
|
|
output << s
|
|
true
|
|
}).to_stdout
|
|
expect(JSON.parse(output).first["tap"]).to eq("homebrew/core")
|
|
end
|
|
|
|
it "prints required, recursive runtime, and dependent counts in the dependencies section" do
|
|
allow_any_instance_of(StringIO).to receive(:tty?).and_return(true)
|
|
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
homepage "https://brew.sh/testball"
|
|
desc "Some test"
|
|
|
|
depends_on "bar"
|
|
end
|
|
direct_dependency = formula.deps.required.first
|
|
|
|
# Simulate an installed keg with tab runtime dependencies
|
|
keg_path = HOMEBREW_CELLAR/"testball/0.1"
|
|
keg_path.mkpath
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.runtime_dependencies = [
|
|
{ "full_name" => "installed-dep", "version" => "1.0" },
|
|
{ "full_name" => "missing-dep", "version" => "2.0" },
|
|
]
|
|
tab.write
|
|
|
|
# Create a rack for the installed dependency
|
|
installed_dep_path = HOMEBREW_CELLAR/"installed-dep/1.0"
|
|
installed_dep_path.mkpath
|
|
installed_dep_tab = Tab.empty
|
|
installed_dep_tab.tabfile = installed_dep_path/AbstractTab::FILENAME
|
|
installed_dep_tab.write
|
|
|
|
# Create a dependent keg whose tab references testball
|
|
dependent_keg_path = HOMEBREW_CELLAR/"some-dependent/1.0"
|
|
dependent_keg_path.mkpath
|
|
dependent_tab = Tab.empty
|
|
dependent_tab.tabfile = dependent_keg_path/AbstractTab::FILENAME
|
|
dependent_tab.runtime_dependencies = [
|
|
{ "full_name" => "testball", "version" => "0.1" },
|
|
]
|
|
dependent_tab.write
|
|
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(core_formula?: false, missing_library_linkage: [[], Set.new])
|
|
allow(direct_dependency).to receive(:satisfied?).and_return(true)
|
|
|
|
expected_output = Regexp.new(
|
|
"==> Dependencies\nRequired \\(1\\): .*bar.*\n" \
|
|
"Recursive Runtime \\(2\\): 1 installed .*✔, 1 missing .*✘\nDependents: 1",
|
|
)
|
|
expect { info.info_formula(formula) }
|
|
.to output(expected_output).to_stdout
|
|
.and not_to_output(/^Dependencies: /).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "lists installed dependents inline under Dependencies with --verbose" do
|
|
allow_any_instance_of(StringIO).to receive(:tty?).and_return(true)
|
|
|
|
info = described_class.new(["--verbose"])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
homepage "https://brew.sh/testball"
|
|
desc "Some test"
|
|
end
|
|
|
|
keg_path = HOMEBREW_CELLAR/"testball/0.1"
|
|
keg_path.mkpath
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.write
|
|
|
|
%w[some-dependent another-dependent].each do |dependent_name|
|
|
dependent_keg_path = HOMEBREW_CELLAR/"#{dependent_name}/1.0"
|
|
dependent_keg_path.mkpath
|
|
dependent_tab = Tab.empty
|
|
dependent_tab.tabfile = dependent_keg_path/AbstractTab::FILENAME
|
|
dependent_tab.runtime_dependencies = [
|
|
{ "full_name" => "testball", "version" => "0.1" },
|
|
]
|
|
dependent_tab.write
|
|
end
|
|
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(core_formula?: false, missing_library_linkage: [[], Set.new])
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to output(/^Dependents \(2\): another-dependent, some-dependent$/).to_stdout
|
|
.and not_to_output(/^Dependents: /).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "summarises recursive runtime dependencies as all installed when none are missing" do
|
|
allow_any_instance_of(StringIO).to receive(:tty?).and_return(true)
|
|
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
homepage "https://brew.sh/testball"
|
|
desc "Some test"
|
|
|
|
depends_on "bar"
|
|
end
|
|
direct_dependency = formula.deps.required.first
|
|
|
|
keg_path = HOMEBREW_CELLAR/"testball/0.1"
|
|
keg_path.mkpath
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.runtime_dependencies = [{ "full_name" => "installed-dep", "version" => "1.0" }]
|
|
tab.write
|
|
|
|
installed_dep_path = HOMEBREW_CELLAR/"installed-dep/1.0"
|
|
installed_dep_path.mkpath
|
|
installed_dep_tab = Tab.empty
|
|
installed_dep_tab.tabfile = installed_dep_path/AbstractTab::FILENAME
|
|
installed_dep_tab.write
|
|
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(core_formula?: false, missing_library_linkage: [[], Set.new])
|
|
allow(direct_dependency).to receive(:satisfied?).and_return(true)
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to output(/Recursive Runtime \(1\): all installed .*✔/).to_stdout
|
|
.and not_to_output(/missing/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "marks a tab-listed dep with no installed rack as unsatisfied" do
|
|
allow_any_instance_of(StringIO).to receive(:tty?).and_return(true)
|
|
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
desc "Some test"
|
|
|
|
depends_on "bar"
|
|
end
|
|
|
|
keg_path = HOMEBREW_CELLAR/"testball/0.1"
|
|
keg_path.mkpath
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.runtime_dependencies = [{ "full_name" => "bar", "version" => "1.0", "pkg_version" => "1.0" }]
|
|
tab.write
|
|
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(core_formula?: false, missing_library_linkage: [[], Set.new])
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to output(/Required \(1\): .*bar.*✘/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "marks a tab-listed dep with an installed rack as satisfied when the dep formula is not outdated" do
|
|
allow_any_instance_of(StringIO).to receive(:tty?).and_return(true)
|
|
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
desc "Some test"
|
|
|
|
depends_on "bar"
|
|
end
|
|
direct_dependency = formula.deps.required.first
|
|
|
|
keg_path = HOMEBREW_CELLAR/"testball/0.1"
|
|
keg_path.mkpath
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.runtime_dependencies = [{ "full_name" => "bar", "version" => "1.0", "pkg_version" => "1.0" }]
|
|
tab.write
|
|
|
|
bar_keg_path = HOMEBREW_CELLAR/"bar/1.0"
|
|
bar_keg_path.mkpath
|
|
bar_tab = Tab.empty
|
|
bar_tab.tabfile = bar_keg_path/AbstractTab::FILENAME
|
|
bar_tab.write
|
|
|
|
bar_formula = instance_double(Formula, outdated?: false)
|
|
allow(direct_dependency).to receive(:to_formula).and_return(bar_formula)
|
|
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(core_formula?: false, missing_library_linkage: [[], Set.new])
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to output(/Required \(1\): .*bar.*✔/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "marks a tab-listed dep with an installed rack as outdated when the dep formula is outdated" do
|
|
allow_any_instance_of(StringIO).to receive(:tty?).and_return(true)
|
|
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
desc "Some test"
|
|
|
|
depends_on "bar"
|
|
end
|
|
direct_dependency = formula.deps.required.first
|
|
|
|
keg_path = HOMEBREW_CELLAR/"testball/0.1"
|
|
keg_path.mkpath
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.runtime_dependencies = [{ "full_name" => "bar", "version" => "1.0", "pkg_version" => "1.0" }]
|
|
tab.write
|
|
|
|
bar_keg_path = HOMEBREW_CELLAR/"bar/1.0"
|
|
bar_keg_path.mkpath
|
|
bar_tab = Tab.empty
|
|
bar_tab.tabfile = bar_keg_path/AbstractTab::FILENAME
|
|
bar_tab.write
|
|
|
|
bar_formula = instance_double(Formula, outdated?: true)
|
|
allow(direct_dependency).to receive(:to_formula).and_return(bar_formula)
|
|
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(core_formula?: false, missing_library_linkage: [[], Set.new])
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to output(/Required \(1\): .*bar.*↑/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "marks an installed dep on an uninstalled formula as satisfied" do
|
|
allow_any_instance_of(StringIO).to receive(:tty?).and_return(true)
|
|
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
desc "Some test"
|
|
|
|
depends_on "bar"
|
|
end
|
|
direct_dependency = formula.deps.required.first
|
|
|
|
bar_keg_path = HOMEBREW_CELLAR/"bar/1.0"
|
|
bar_keg_path.mkpath
|
|
bar_tab = Tab.empty
|
|
bar_tab.tabfile = bar_keg_path/AbstractTab::FILENAME
|
|
bar_tab.write
|
|
|
|
bar_formula = instance_double(Formula, outdated?: false)
|
|
allow(direct_dependency).to receive(:to_formula).and_return(bar_formula)
|
|
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(core_formula?: false, missing_library_linkage: [[], Set.new])
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to output(/Required \(1\): .*bar.*✔/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "marks an outdated installed dep on an uninstalled formula as upgradable" do
|
|
allow_any_instance_of(StringIO).to receive(:tty?).and_return(true)
|
|
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
desc "Some test"
|
|
|
|
depends_on "bar"
|
|
end
|
|
direct_dependency = formula.deps.required.first
|
|
|
|
bar_keg_path = HOMEBREW_CELLAR/"bar/1.0"
|
|
bar_keg_path.mkpath
|
|
bar_tab = Tab.empty
|
|
bar_tab.tabfile = bar_keg_path/AbstractTab::FILENAME
|
|
bar_tab.write
|
|
|
|
bar_formula = instance_double(Formula, outdated?: true)
|
|
allow(direct_dependency).to receive(:to_formula).and_return(bar_formula)
|
|
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(core_formula?: false, missing_library_linkage: [[], Set.new])
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to output(/Required \(1\): .*bar.*↑/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "marks an aliased dep as installed when the underlying rack exists under a different name" do
|
|
allow_any_instance_of(StringIO).to receive(:tty?).and_return(true)
|
|
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
desc "Some test"
|
|
|
|
depends_on "pkg-config"
|
|
end
|
|
direct_dependency = formula.deps.required.first
|
|
|
|
pkgconf_keg_path = HOMEBREW_CELLAR/"pkgconf/2.5.1"
|
|
pkgconf_keg_path.mkpath
|
|
pkgconf_tab = Tab.empty
|
|
pkgconf_tab.tabfile = pkgconf_keg_path/AbstractTab::FILENAME
|
|
pkgconf_tab.write
|
|
|
|
pkgconf_formula = instance_double(Formula, any_version_installed?: true, outdated?: false)
|
|
allow(direct_dependency).to receive(:to_formula).and_return(pkgconf_formula)
|
|
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(core_formula?: false, missing_library_linkage: [[], Set.new])
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to output(/Required \(1\): .*pkg-config.*✔/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "does not mark a missing dep on an uninstalled formula" do
|
|
allow_any_instance_of(StringIO).to receive(:tty?).and_return(true)
|
|
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
desc "Some test"
|
|
|
|
depends_on "bar"
|
|
end
|
|
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(core_formula?: false, missing_library_linkage: [[], Set.new])
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to output(/Required \(1\): bar\n/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "marks a dep absent from the installed keg's tab as unsatisfied when its rack is also missing" do
|
|
allow_any_instance_of(StringIO).to receive(:tty?).and_return(true)
|
|
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
desc "Some test"
|
|
|
|
depends_on "bar"
|
|
end
|
|
|
|
keg_path = HOMEBREW_CELLAR/"testball/0.1"
|
|
keg_path.mkpath
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.runtime_dependencies = []
|
|
tab.write
|
|
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(core_formula?: false, missing_library_linkage: [[], Set.new])
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to output(/Required \(1\): .*bar.*✘/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "marks a dep absent from the installed keg's tab as installed when its rack exists" do
|
|
allow_any_instance_of(StringIO).to receive(:tty?).and_return(true)
|
|
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
desc "Some test"
|
|
|
|
depends_on "bar"
|
|
end
|
|
|
|
keg_path = HOMEBREW_CELLAR/"testball/0.1"
|
|
keg_path.mkpath
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.runtime_dependencies = []
|
|
tab.write
|
|
|
|
bar_keg_path = HOMEBREW_CELLAR/"bar/1.0"
|
|
bar_keg_path.mkpath
|
|
bar_tab = Tab.empty
|
|
bar_tab.tabfile = bar_keg_path/AbstractTab::FILENAME
|
|
bar_tab.write
|
|
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(core_formula?: false, missing_library_linkage: [[], Set.new])
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to output(/Required \(1\): .*bar.*↑/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "omits build dependencies when a formula would pour from a bottle" do
|
|
allow_any_instance_of(StringIO).to receive(:tty?).and_return(true)
|
|
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
homepage "https://brew.sh/testball"
|
|
desc "Some test"
|
|
|
|
depends_on "bar" => :build
|
|
end
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(
|
|
core_formula?: false,
|
|
recursive_dependencies: [],
|
|
stable: instance_double(
|
|
SoftwareSpec,
|
|
version: Version.new("0.1"),
|
|
bottled?: true,
|
|
),
|
|
pour_bottle?: true,
|
|
)
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to not_to_output(/Build \(1\): .*bar.*/).to_stdout
|
|
.and not_to_output(/==> Dependencies/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "shows the installed and stable versions in the headline when outdated" do
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
homepage "https://brew.sh/testball"
|
|
desc "Some test"
|
|
end
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(core_formula?: false, outdated?: true)
|
|
|
|
keg_path = HOMEBREW_CELLAR/"testball/0.0.1"
|
|
keg_path.mkpath
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.write
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to output(/\A==> testball: 0\.0\.1 → stable 0\.1\n/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "prints Linux requirements through the requirements section" do
|
|
allow_any_instance_of(StringIO).to receive(:tty?).and_return(true)
|
|
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
homepage "https://brew.sh/testball"
|
|
desc "Some test"
|
|
end
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(
|
|
core_formula?: false,
|
|
requirements: Requirements.new(LinuxRequirement.new),
|
|
)
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to output(/Requirements\nRequired: .*Linux/).to_stdout
|
|
.and not_to_output(/supports Linux/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "hides source install metadata for formulae that only run on another OS" do
|
|
allow_any_instance_of(StringIO).to receive(:tty?).and_return(true)
|
|
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
homepage "https://brew.sh/testball"
|
|
desc "Some test"
|
|
end
|
|
os_requirement = OS.mac? ? LinuxRequirement.new : MacOSRequirement.new([:sonoma])
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(
|
|
core_formula?: false,
|
|
requirements: Requirements.new(os_requirement),
|
|
)
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to not_to_output(/Installs from source: yes/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "prints a Binaries section listing executables in bin and sbin with --verbose" do
|
|
info = described_class.new(["--verbose"])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
homepage "https://brew.sh/testball"
|
|
desc "Some test"
|
|
end
|
|
|
|
keg_path = HOMEBREW_CELLAR/"testball/0.1"
|
|
(keg_path/"bin").mkpath
|
|
(keg_path/"sbin").mkpath
|
|
["bin/testball", "bin/another", "sbin/daemon"].each do |rel|
|
|
file = keg_path/rel
|
|
file.write("#!/bin/sh\n")
|
|
file.chmod(0755)
|
|
end
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.write
|
|
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(core_formula?: false, missing_library_linkage: [[], Set.new])
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to output(a_string_including("==> Binaries\nanother\ndaemon\ntestball\n")).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "prints a Binaries section from the bottle manifest when the formula is not installed with --verbose" do
|
|
info = described_class.new(["--verbose"])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
homepage "https://brew.sh/testball"
|
|
desc "Some test"
|
|
end
|
|
|
|
bottle = instance_double(
|
|
Bottle,
|
|
path_exec_files: ["bin/testball", "bin/another", "sbin/daemon"],
|
|
bottle_size: nil,
|
|
installed_size: nil,
|
|
)
|
|
allow(bottle).to receive(:fetch_tab)
|
|
allow(formula).to receive_messages(bottle:, core_formula?: false)
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to output(a_string_including("==> Binaries\nanother\ndaemon\ntestball\n")).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "omits the Binaries section without --verbose" do
|
|
info = described_class.new([])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
homepage "https://brew.sh/testball"
|
|
desc "Some test"
|
|
end
|
|
|
|
keg_path = HOMEBREW_CELLAR/"testball/0.1"
|
|
(keg_path/"bin").mkpath
|
|
binary = keg_path/"bin/testball"
|
|
binary.write("#!/bin/sh\n")
|
|
binary.chmod(0755)
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.write
|
|
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(core_formula?: false, missing_library_linkage: [[], Set.new])
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to not_to_output(/==> Binaries/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "omits the Binaries section when no executables are installed" do
|
|
info = described_class.new(["--verbose"])
|
|
formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
homepage "https://brew.sh/testball"
|
|
desc "Some test"
|
|
end
|
|
|
|
keg_path = HOMEBREW_CELLAR/"testball/0.1"
|
|
(keg_path/"lib").mkpath
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.write
|
|
|
|
allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb")
|
|
allow(formula).to receive_messages(core_formula?: false, missing_library_linkage: [[], Set.new])
|
|
|
|
expect { info.info_formula(formula) }
|
|
.to not_to_output(/==> Binaries/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
describe "::installation_status" do
|
|
it "prints on-request installs explicitly" do
|
|
expect(described_class.installation_status(instance_double(Tab, installed_on_request: true)))
|
|
.to eq("Installed (on request)")
|
|
end
|
|
|
|
it "treats non-requested installs as dependency installs" do
|
|
expect(described_class.installation_status(instance_double(Tab, installed_on_request: false)))
|
|
.to eq("Installed (as dependency)")
|
|
end
|
|
end
|
|
|
|
describe "::metadata_lines" do
|
|
before { allow($stdout).to receive(:tty?).and_return(true) }
|
|
|
|
it "returns summary lines for pinned formulae" do
|
|
test_formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-1.0"
|
|
end
|
|
allow(test_formula).to receive_messages(any_version_installed?: true, pinned?: true, pinned_version: "1.0")
|
|
|
|
mktmpdir do |dir|
|
|
pin_path = Pathname(dir/"testball")
|
|
pin_path.write("pin")
|
|
pin_time = Time.at(1_720_189_900)
|
|
File.utime(pin_time, pin_time, pin_path)
|
|
allow(FormulaPin).to receive(:new).with(test_formula).and_return(instance_double(FormulaPin, path: pin_path))
|
|
|
|
expect(described_class.metadata_lines(test_formula)).to eq([
|
|
"Pinned: 1.0 on #{pin_time.strftime("%Y-%m-%d at %H:%M:%S")}",
|
|
])
|
|
end
|
|
end
|
|
|
|
it "returns summary lines for pinned casks" do
|
|
cask = Cask::Cask.new("test-cask") do
|
|
version "1.0"
|
|
url "https://brew.sh/test-cask.zip"
|
|
end
|
|
allow(cask).to receive_messages(pinned?: true, pinned_version: "1.0")
|
|
|
|
mktmpdir do |dir|
|
|
pin_path = Pathname(dir/"test-cask")
|
|
pin_path.write("pin")
|
|
pin_time = Time.at(1_720_189_900)
|
|
File.utime(pin_time, pin_time, pin_path)
|
|
allow(cask).to receive(:pin_path).and_return(pin_path)
|
|
|
|
expect(described_class.metadata_lines(cask)).to eq([
|
|
"Pinned: 1.0 on #{pin_time.strftime("%Y-%m-%d at %H:%M:%S")}",
|
|
])
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "::github_remote_path" do
|
|
let(:remote) { "https://github.com/Homebrew/homebrew-core" }
|
|
|
|
specify "returns correct URLs" do
|
|
expect(described_class.new([]).github_remote_path(remote, "Formula/git.rb"))
|
|
.to eq("https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/git.rb")
|
|
|
|
expect(described_class.new([]).github_remote_path("#{remote}.git", "Formula/git.rb"))
|
|
.to eq("https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/git.rb")
|
|
|
|
expect(described_class.new([]).github_remote_path("git@github.com:user/repo", "foo.rb"))
|
|
.to eq("https://github.com/user/repo/blob/HEAD/foo.rb")
|
|
|
|
expect(described_class.new([]).github_remote_path("https://mywebsite.com", "foo/bar.rb"))
|
|
.to eq("https://mywebsite.com/foo/bar.rb")
|
|
end
|
|
end
|
|
|
|
describe "Aliases and Old Names rows" do
|
|
it "lists aliases on their own row when the formula has any" do
|
|
info = described_class.new([])
|
|
main_formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-1.0.tar.gz"
|
|
end
|
|
allow(main_formula).to receive_messages(aliases: ["testball@1.0", "tball", "googleball"], oldnames: [])
|
|
allow(info).to receive(:github_info).with(main_formula).and_return("https://example.com/testball.rb")
|
|
|
|
expect { info.info_formula(main_formula) }
|
|
.to output(/^Aliases: testball@1\.0, tball, googleball$/).to_stdout
|
|
.and not_to_output(/^Old Names:/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "renders aliases and old names on separate rows when both exist" do
|
|
info = described_class.new([])
|
|
main_formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-1.0.tar.gz"
|
|
end
|
|
allow(main_formula).to receive_messages(aliases: ["testball@1.0", "tball"], oldnames: ["foo", "bar"])
|
|
allow(info).to receive(:github_info).with(main_formula).and_return("https://example.com/testball.rb")
|
|
|
|
expect { info.info_formula(main_formula) }
|
|
.to output(/^Aliases: testball@1\.0, tball\nOld Names: foo, bar$/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "renders only an Old Names row when there are no aliases" do
|
|
info = described_class.new([])
|
|
main_formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-1.0.tar.gz"
|
|
end
|
|
allow(main_formula).to receive_messages(aliases: [], oldnames: ["foo"])
|
|
allow(info).to receive(:github_info).with(main_formula).and_return("https://example.com/testball.rb")
|
|
|
|
expect { info.info_formula(main_formula) }
|
|
.to output(/^Old Names: foo$/).to_stdout
|
|
.and not_to_output(/^Aliases:/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "omits both rows when there are none" do
|
|
info = described_class.new([])
|
|
main_formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-1.0.tar.gz"
|
|
end
|
|
allow(main_formula).to receive_messages(aliases: [], oldnames: [])
|
|
allow(info).to receive(:github_info).with(main_formula).and_return("https://example.com/testball.rb")
|
|
|
|
expect { info.info_formula(main_formula) }
|
|
.to not_to_output(/^Aliases:/).to_stdout
|
|
.and not_to_output(/^Old Names:/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
end
|
|
|
|
describe "Installed section" do
|
|
it "lists this formula alongside installed sibling versioned formulae" do
|
|
info = described_class.new([])
|
|
main_formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-1.0.tar.gz"
|
|
end
|
|
versioned = formula("testball@0.9") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.9.tar.gz"
|
|
keg_only :versioned_formula
|
|
end
|
|
|
|
main_keg = HOMEBREW_CELLAR/"testball/1.0"
|
|
main_keg.mkpath
|
|
main_tab = Tab.empty
|
|
main_tab.tabfile = main_keg/AbstractTab::FILENAME
|
|
main_tab.write
|
|
|
|
sibling_keg = HOMEBREW_CELLAR/"testball@0.9/0.9"
|
|
sibling_keg.mkpath
|
|
sibling_tab = Tab.empty
|
|
sibling_tab.tabfile = sibling_keg/AbstractTab::FILENAME
|
|
sibling_tab.write
|
|
|
|
allow(main_formula).to receive(:versioned_formulae).and_return([versioned])
|
|
allow(info).to receive(:github_info).with(main_formula).and_return("https://example.com/testball.rb")
|
|
|
|
expect { info.info_formula(main_formula) }
|
|
.to output(Regexp.new(
|
|
"==> Installed Versions\n" \
|
|
".*testball\\b.*\\s+1\\.0\\s+\\(.*\\)\n" \
|
|
".*testball@0\\.9\\b.*\\s+0\\.9\\s+\\(",
|
|
)).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "shows installed → latest only on the newest installed keg of an outdated formula" do
|
|
info = described_class.new([])
|
|
main_formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-2.0.tar.gz"
|
|
version "2.0"
|
|
end
|
|
|
|
["1.0", "0.9"].each do |version|
|
|
keg_path = HOMEBREW_CELLAR/"testball/#{version}"
|
|
keg_path.mkpath
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.write
|
|
end
|
|
|
|
allow(main_formula).to receive_messages(versioned_formulae: [], outdated?: true)
|
|
allow(info).to receive(:github_info).with(main_formula).and_return("https://example.com/testball.rb")
|
|
|
|
expect { info.info_formula(main_formula) }
|
|
.to output(/==> Installed Versions\n.*testball\b.*\s+1\.0 → 2\.0\s+\(/).to_stdout
|
|
.and not_to_output(/0\.9 →/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "hides older non-linked kegs by default" do
|
|
info = described_class.new([])
|
|
main_formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-1.0.tar.gz"
|
|
end
|
|
|
|
["1.0", "0.9"].each do |version|
|
|
keg_path = HOMEBREW_CELLAR/"testball/#{version}"
|
|
keg_path.mkpath
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.write
|
|
end
|
|
|
|
allow(main_formula).to receive(:versioned_formulae).and_return([])
|
|
allow(info).to receive(:github_info).with(main_formula).and_return("https://example.com/testball.rb")
|
|
|
|
expect { info.info_formula(main_formula) }
|
|
.to output(/==> Installed Versions\n.*testball\b.*\s+1\.0\s+\(/).to_stdout
|
|
.and not_to_output(/\s+0\.9\s+\(/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "marks the currently linked version with `*`" do
|
|
info = described_class.new([])
|
|
main_formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-1.0.tar.gz"
|
|
end
|
|
versioned = formula("testball@0.9") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.9.tar.gz"
|
|
keg_only :versioned_formula
|
|
end
|
|
|
|
main_keg = HOMEBREW_CELLAR/"testball/1.0"
|
|
main_keg.mkpath
|
|
main_tab = Tab.empty
|
|
main_tab.tabfile = main_keg/AbstractTab::FILENAME
|
|
main_tab.write
|
|
(HOMEBREW_LINKED_KEGS/"testball").parent.mkpath
|
|
FileUtils.ln_s(main_keg, HOMEBREW_LINKED_KEGS/"testball")
|
|
|
|
sibling_keg = HOMEBREW_CELLAR/"testball@0.9/0.9"
|
|
sibling_keg.mkpath
|
|
sibling_tab = Tab.empty
|
|
sibling_tab.tabfile = sibling_keg/AbstractTab::FILENAME
|
|
sibling_tab.write
|
|
|
|
allow(main_formula).to receive_messages(versioned_formulae: [versioned], linked?: true,
|
|
linked_version: PkgVersion.parse("1.0"))
|
|
allow(info).to receive(:github_info).with(main_formula).and_return("https://example.com/testball.rb")
|
|
|
|
expect { info.info_formula(main_formula) }
|
|
.to output(/.*testball\b.*\s+1\.0\s+\(.*\)\s+\[Linked\]/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "includes the unversioned parent when run on a versioned formula" do
|
|
info = described_class.new([])
|
|
versioned = formula("testball@0.9") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.9.tar.gz"
|
|
keg_only :versioned_formula
|
|
end
|
|
parent = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-1.0.tar.gz"
|
|
end
|
|
|
|
versioned_keg = HOMEBREW_CELLAR/"testball@0.9/0.9"
|
|
versioned_keg.mkpath
|
|
versioned_tab = Tab.empty
|
|
versioned_tab.tabfile = versioned_keg/AbstractTab::FILENAME
|
|
versioned_tab.write
|
|
|
|
parent_keg = HOMEBREW_CELLAR/"testball/1.0"
|
|
(parent_keg/"bin").mkpath
|
|
parent_tab = Tab.empty
|
|
parent_tab.tabfile = parent_keg/AbstractTab::FILENAME
|
|
parent_tab.write
|
|
|
|
allow(versioned).to receive(:versioned_formulae).and_return([])
|
|
allow(Formulary).to receive(:factory).with("testball").and_return(parent)
|
|
allow(info).to receive(:github_info).with(versioned).and_return("https://example.com/testball.rb")
|
|
|
|
expect { info.info_formula(versioned) }
|
|
.to output(Regexp.new(
|
|
"==> Installed Versions\n" \
|
|
".*testball\\b.*\\s+1\\.0\\s+\\(.*\\)\n" \
|
|
".*testball@0\\.9\\b.*\\s+0\\.9\\s+\\(",
|
|
)).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "renders the section even when only the current formula is installed" do
|
|
info = described_class.new([])
|
|
main_formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-1.0.tar.gz"
|
|
end
|
|
|
|
keg_path = HOMEBREW_CELLAR/"testball/1.0"
|
|
keg_path.mkpath
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.write
|
|
|
|
allow(main_formula).to receive(:versioned_formulae).and_return([])
|
|
allow(info).to receive(:github_info).with(main_formula).and_return("https://example.com/testball.rb")
|
|
|
|
expect { info.info_formula(main_formula) }
|
|
.to output(/==> Installed Versions\n.*testball\b.*\s+1\.0\s+\(/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "renders the section when the queried formula is uninstalled but a sibling is installed" do
|
|
info = described_class.new([])
|
|
versioned = formula("testball@0.9") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.9.tar.gz"
|
|
keg_only :versioned_formula
|
|
end
|
|
parent = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-1.0.tar.gz"
|
|
end
|
|
|
|
parent_keg = HOMEBREW_CELLAR/"testball/1.0"
|
|
parent_keg.mkpath
|
|
parent_tab = Tab.empty
|
|
parent_tab.tabfile = parent_keg/AbstractTab::FILENAME
|
|
parent_tab.write
|
|
|
|
allow(versioned).to receive(:versioned_formulae).and_return([])
|
|
allow(Formulary).to receive(:factory).with("testball").and_return(parent)
|
|
allow(info).to receive(:github_info).with(versioned).and_return("https://example.com/testball.rb")
|
|
|
|
expect { info.info_formula(versioned) }
|
|
.to output(/==> Installed Versions\n.*testball\b.*\s+1\.0\s+\(/).to_stdout
|
|
.and not_to_output(/testball@0\.9 \(0\.9\)/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "lists every installed keg of a formula, newest first, with --verbose" do
|
|
info = described_class.new(["--verbose"])
|
|
main_formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-1.0.tar.gz"
|
|
end
|
|
|
|
["0.9", "1.0", "0.10"].each do |version|
|
|
keg_path = HOMEBREW_CELLAR/"testball/#{version}"
|
|
keg_path.mkpath
|
|
tab = Tab.empty
|
|
tab.tabfile = keg_path/AbstractTab::FILENAME
|
|
tab.write
|
|
end
|
|
|
|
allow(main_formula).to receive(:versioned_formulae).and_return([])
|
|
allow(info).to receive(:github_info).with(main_formula).and_return("https://example.com/testball.rb")
|
|
|
|
expect { info.info_formula(main_formula) }
|
|
.to output(Regexp.new(
|
|
"==> Installed Kegs and Versions\n" \
|
|
".*testball\\b.*\\s+1\\.0\\b.*\\(.*\\)\n" \
|
|
"(?: .*\n)*" \
|
|
".*testball\\b.*\\s+0\\.10\\s+\\(.*\\)\n" \
|
|
"(?: .*\n)*" \
|
|
".*testball\\b.*\\s+0\\.9\\s+\\(",
|
|
)).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
|
|
it "omits the section when nothing in the family is installed" do
|
|
info = described_class.new([])
|
|
main_formula = formula("testball") do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-1.0.tar.gz"
|
|
end
|
|
allow(main_formula).to receive(:versioned_formulae).and_return([])
|
|
allow(info).to receive(:github_info).with(main_formula).and_return("https://example.com/testball.rb")
|
|
|
|
expect { info.info_formula(main_formula) }
|
|
.to not_to_output(/==> Installed Versions\b/).to_stdout
|
|
.and not_to_output.to_stderr
|
|
end
|
|
end
|
|
|
|
describe "#github_info" do
|
|
let(:tap) { CoreTap.instance }
|
|
|
|
it "returns the local path for a formula whose file lives outside its tap" do
|
|
# Simulates a formula that was removed from its tap but is still installed,
|
|
# so it gets loaded from the keg's `.brew/` directory by `FromKegLoader`.
|
|
keg_formula_path = HOMEBREW_CELLAR/"testball/0.1/.brew/testball.rb"
|
|
formula_instance = formula("testball", path: keg_formula_path, tap:) do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
end
|
|
|
|
expect(described_class.new([]).github_info(formula_instance))
|
|
.to eq(keg_formula_path.to_s)
|
|
end
|
|
|
|
it "returns a GitHub URL for a formula whose file lives inside its tap" do
|
|
formula_path = tap.new_formula_path("testball")
|
|
formula_instance = formula("testball", path: formula_path, tap:) do
|
|
T.bind(self, T.class_of(Formula))
|
|
url "https://brew.sh/testball-0.1.tar.gz"
|
|
end
|
|
|
|
expect(described_class.new([]).github_info(formula_instance))
|
|
.to eq("https://github.com/Homebrew/homebrew-core/blob/HEAD/" \
|
|
"#{formula_path.relative_path_from(tap.path)}")
|
|
end
|
|
end
|
|
end
|