spec/lib/asdf/tool_versions_spec.rb (213 lines of code) (raw):
# frozen_string_literal: true
RSpec.describe Asdf::ToolVersions do
let(:software_name) { 'golang' }
let(:wanted_software_versions) { ['1.17.2', '1.21.9'] }
let(:unnecessary_software_version) { '1.17.1' }
let(:unnecessary_software_tool_version) { Asdf::ToolVersion.new(software_name, unnecessary_software_version) }
let(:tmp_dir_we_pretend_exists) { '/tmp/dir/that/we/pretend/exists/asdf' }
subject { described_class.new }
describe '#default_tool_version_for' do
context 'postgres' do
it 'returns instance of Asdf::ToolVersion' do
tool_version = subject.default_tool_version_for('postgres')
expect(tool_version).to be_instance_of(Asdf::ToolVersion)
expect(tool_version.version).to eq('16.8')
end
end
end
describe '#default_version_for' do
context 'when a .tool-versions file is in the root directory' do
it 'returns postgres version 16.8' do
expect(subject.default_version_for('postgres')).to eq('16.8')
end
end
context 'when a .tool-versions file is one level deep' do
let(:first_level_file) { GDK.root.join('level1/.tool-versions') }
before do
allow(GDK.root).to receive(:glob).with('{.tool-versions,{*,*/*}/.tool-versions}').and_return([first_level_file])
allow(File).to receive(:readlines).with(first_level_file).and_return(['gitleaks 8.18.2'])
end
it 'retrieves the correct version' do
expect(subject.default_version_for('gitleaks')).to eq('8.18.2')
end
end
context 'when a .tool-versions file is more than one level deep' do
let(:second_level_file) { GDK.root.join('level1/level2/.tool-versions') }
before do
allow(GDK.root).to receive(:glob).with('{.tool-versions,{*,*/*}/.tool-versions}').and_return([])
allow(File).to receive(:readlines).with(second_level_file).and_return(['nonexistent 1.2.3'])
end
it 'does not retrieve versions' do
expect(subject.default_version_for('nonexistent')).to be_nil
end
end
end
describe '#unnecessary_software_to_uninstall?' do
before do
stub_asdf_data_installs_dir(tmp_dir_we_pretend_exists, exist: true)
end
context "when there isn't any software to uninstall" do
it 'returns false' do
stub_no_unnecessary_installed_software
expect(subject.unnecessary_software_to_uninstall?).to be_falsey
end
end
context 'when there is software to uninstall' do
it 'returns true' do
stub_some_unnecessary_installed_software
expect(subject.unnecessary_software_to_uninstall?).to be_truthy
end
end
end
describe '#unnecessary_installed_versions_of_software' do
before do
stub_some_unnecessary_installed_software
end
it 'returns a Hash of software and versions that can be uninstalled' do
expect(subject.unnecessary_installed_versions_of_software).to be_a(Hash)
end
it 'contains golang 1.17.1' do
unnecessary_installed_versions_of_software = subject.unnecessary_installed_versions_of_software
expect(unnecessary_installed_versions_of_software).to include(software_name => { unnecessary_software_version => unnecessary_software_tool_version })
end
end
describe '#uninstall_unnecessary_software!' do
context 'when asdf installs directory does not exist (asdf not in use)' do
it 'informs and returns true' do
non_existent_asdf_dir = '/tmp/dir/that/doesnt/exist/asdf'
stub_asdf_data_installs_dir(non_existent_asdf_dir, exist: false)
expect(GDK::Output).to receive(:info).with("Skipping because '#{non_existent_asdf_dir}/installs' does not exist.")
expect(subject.uninstall_unnecessary_software!).to be_truthy
end
end
context 'when asdf installs directory does exist' do
before do
stub_asdf_data_installs_dir(tmp_dir_we_pretend_exists, exist: true)
end
context 'when asdf.opt_out is set to true' do
it 'informs and returns true' do
allow_any_instance_of(GDK::Config).to receive_message_chain('asdf.opt_out?').and_return(true)
expect(GDK::Output).to receive(:info).with('Skipping because asdf.opt_out is set to true.')
expect(subject.uninstall_unnecessary_software!).to be_truthy
end
end
context 'when there is no software to uninstall' do
it 'informs and returns true' do
stub_no_unnecessary_installed_software
expect(GDK::Output).to receive(:info).with('No unnecessary asdf software to uninstall.')
expect(subject.uninstall_unnecessary_software!).to be_truthy
end
end
context 'when there is software to uninstall' do
before do
stub_some_unnecessary_installed_software
end
context 'when prompted' do
context 'and the user accepts' do
context 'but an unhandled exception occurs' do
it 'aborts with exception', :hide_output do
stub_prompt('y')
expect_warn_and_puts
expect(unnecessary_software_tool_version).to receive(:uninstall!).and_raise(StandardError)
expect { subject.uninstall_unnecessary_software! }.to raise_error(StandardError)
end
end
context 'but the uninstall command returns a non-zero exit code' do
it 'return false' do
stub_prompt('y')
expect_warn_and_puts
expect(unnecessary_software_tool_version).to receive(:uninstall!).and_raise(Asdf::ToolVersion::UninstallFailedError)
expect_uninstall_failure
expect(subject.uninstall_unnecessary_software!).to be_falsey
end
end
end
context 'but the user does not accept' do
it 'does not uninstall and returns true' do
stub_prompt('n')
expect_warn_and_puts
expect(unnecessary_software_tool_version).not_to receive(:uninstall!)
expect(subject.uninstall_unnecessary_software!).to be_truthy
end
end
context 'when software succeeds in uninstalling' do
context 'and the user accepts' do
context 'by setting GDK_ASDF_UNINSTALL_UNNECESSARY_SOFTWARE_CONFIRM to true' do
it 'uninstalls returns true' do
stub_env('GDK_ASDF_UNINSTALL_UNNECESSARY_SOFTWARE_CONFIRM', 'true')
expect_warn_and_puts
expect(unnecessary_software_tool_version).to receive(:uninstall!).and_return(true)
expect_uninstall_success
expect(subject.uninstall_unnecessary_software!).to be_truthy
end
end
context 'via a direct response' do
it 'uninstalls returns true' do
stub_prompt('y')
expect_warn_and_puts
expect(unnecessary_software_tool_version).to receive(:uninstall!).and_return(true)
expect_uninstall_success
expect(subject.uninstall_unnecessary_software!).to be_truthy
end
end
end
end
end
context 'when asked to not prompt' do
context 'when software succeeds in uninstalling' do
it 'returns true' do
expect(GDK::Output).not_to receive(:warn).with('About to uninstall the following asdf software:')
expect(GDK::Output).not_to receive(:puts).with("#{software_name} #{unnecessary_software_version}")
expect(GDK::Output).not_to receive(:prompt).with('Are you sure? [y/N]')
expect(unnecessary_software_tool_version).to receive(:uninstall!).and_return(true)
expect_uninstall_success
expect(subject.uninstall_unnecessary_software!(prompt: false)).to be_truthy
end
end
end
end
end
def expect_warn_and_puts
expect(GDK::Output).to receive(:warn).with('About to uninstall the following asdf software:').ordered
expect(GDK::Output).to receive(:puts).with(stderr: true).ordered
expect(GDK::Output).to receive(:puts).with("#{software_name} #{unnecessary_software_version}").ordered
expect(GDK::Output).to receive(:puts).with(stderr: true).ordered
end
def expect_uninstall_info
expect(GDK::Output).to receive(:print).with("Uninstalling #{software_name} ").ordered
expect(GDK::Output).to receive(:print).with(unnecessary_software_version).ordered
end
def expect_uninstall_success
expect_uninstall_info
expect(GDK::Output).to receive(:puts).with(" #{GDK::Output.icon(:success)}").ordered
end
def expect_uninstall_failure
expect_uninstall_info
expect(GDK::Output).to receive(:puts).with(" #{GDK::Output.icon(:error)}").ordered
expect(GDK::Output).to receive(:puts).with(stderr: true).ordered
expect(GDK::Output).to receive(:warn).with("Failed to uninstall the following:\n\n").ordered
expect(GDK::Output).to receive(:puts).with("#{software_name} #{unnecessary_software_version}").ordered
end
end
def stub_asdf_data_installs_dir(dir, exist:)
stub_env('HOME', '/home/gdk')
stub_env('ASDF_DATA_DIR', dir)
asdf_data_installs_dir_double = instance_double(Pathname, exist?: exist, to_s: "#{dir}/installs")
asdf_data_dir_double = instance_double(Pathname, join: asdf_data_installs_dir_double)
allow(Pathname).to receive(:new).and_call_original
allow(Pathname).to receive(:new).with(dir).and_return(asdf_data_dir_double)
end
def stub_no_unnecessary_installed_software
stub_software(wanted_versions: wanted_software_versions, installed_versions: wanted_software_versions)
end
def stub_some_unnecessary_installed_software
stub_software(wanted_versions: wanted_software_versions, installed_versions: [unnecessary_software_version])
end
def stub_software(wanted_versions:, installed_versions:)
allow(Asdf::ToolVersion).to receive(:new).and_call_original
allow(subject).to receive(:raw_tool_versions_lines).and_return(wanted_versions.map { |version| "#{software_name} #{version}" })
allow(subject).to receive(:asdf_install_dirs_for).with(software_name).and_return(installed_versions.map { |version| Pathname.new("/tmp/.asdf_fake/installs/#{software_name}/#{version}") })
(wanted_versions + installed_versions).each do |version|
allow(Asdf::ToolVersion).to receive(:new).with(software_name, version).and_return(Asdf::ToolVersion.new(software_name, version))
end
end
end