File: //usr/local/rvm/src/ruby-3.0.2/spec/bundler/bundler/definition_spec.rb
# frozen_string_literal: true
require "bundler/definition"
RSpec.describe Bundler::Definition do
describe "#lock" do
before do
allow(Bundler).to receive(:settings) { Bundler::Settings.new(".") }
allow(Bundler::SharedHelpers).to receive(:find_gemfile) { Pathname.new("Gemfile") }
allow(Bundler).to receive(:ui) { double("UI", :info => "", :debug => "") }
end
context "when it's not possible to write to the file" do
subject { Bundler::Definition.new(nil, [], Bundler::SourceList.new, []) }
it "raises an PermissionError with explanation" do
allow(File).to receive(:open).and_call_original
expect(File).to receive(:open).with("Gemfile.lock", "wb").
and_raise(Errno::EACCES)
expect { subject.lock("Gemfile.lock") }.
to raise_error(Bundler::PermissionError, /Gemfile\.lock/)
end
end
context "when a temporary resource access issue occurs" do
subject { Bundler::Definition.new(nil, [], Bundler::SourceList.new, []) }
it "raises a TemporaryResourceError with explanation" do
allow(File).to receive(:open).and_call_original
expect(File).to receive(:open).with("Gemfile.lock", "wb").
and_raise(Errno::EAGAIN)
expect { subject.lock("Gemfile.lock") }.
to raise_error(Bundler::TemporaryResourceError, /temporarily unavailable/)
end
end
end
describe "detects changes" do
it "for a path gem with changes" do
build_lib "foo", "1.0", :path => lib_path("foo")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
G
build_lib "foo", "1.0", :path => lib_path("foo") do |s|
s.add_dependency "rack", "1.0"
end
bundle :install, :env => { "DEBUG" => "1" }
expect(out).to match(/re-resolving dependencies/)
lockfile_should_be <<-G
PATH
remote: #{lib_path("foo")}
specs:
foo (1.0)
rack (= 1.0)
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
foo!
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "for a path gem with deps and no changes" do
build_lib "foo", "1.0", :path => lib_path("foo") do |s|
s.add_dependency "rack", "1.0"
s.add_development_dependency "net-ssh", "1.0"
end
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
G
bundle :check, :env => { "DEBUG" => "1" }
expect(out).to match(/using resolution from the lockfile/)
lockfile_should_be <<-G
PATH
remote: #{lib_path("foo")}
specs:
foo (1.0)
rack (= 1.0)
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
foo!
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "for a locked gem for another platform" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "only_java", platform: :jruby
G
bundle "lock --add-platform java"
bundle :check, :env => { "DEBUG" => "1" }
expect(out).to match(/using resolution from the lockfile/)
lockfile_should_be <<-G
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
only_java (1.1-java)
PLATFORMS
java
#{lockfile_platforms}
DEPENDENCIES
only_java
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "for a rubygems gem" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "foo"
G
bundle :check, :env => { "DEBUG" => "1" }
expect(out).to match(/using resolution from the lockfile/)
lockfile_should_be <<-G
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
foo (1.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
foo
BUNDLED WITH
#{Bundler::VERSION}
G
end
end
describe "initialize" do
context "gem version promoter" do
context "with lockfile" do
before do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "foo"
G
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
end
it "should get a locked specs list when updating all" do
definition = Bundler::Definition.new(bundled_app_lock, [], Bundler::SourceList.new, true)
locked_specs = definition.gem_version_promoter.locked_specs
expect(locked_specs.to_a.map(&:name)).to eq ["foo"]
expect(definition.instance_variable_get("@locked_specs").empty?).to eq true
end
end
context "without gemfile or lockfile" do
it "should not attempt to parse empty lockfile contents" do
definition = Bundler::Definition.new(nil, [], mock_source_list, true)
expect(definition.gem_version_promoter.locked_specs.to_a).to eq []
end
end
context "eager unlock" do
let(:source_list) do
Bundler::SourceList.new.tap do |source_list|
source_list.add_global_rubygems_remote(file_uri_for(gem_repo4))
end
end
before do
gemfile <<-G
source "#{file_uri_for(gem_repo4)}"
gem 'isolated_owner'
gem 'shared_owner_a'
gem 'shared_owner_b'
G
lockfile <<-L
GEM
remote: #{file_uri_for(gem_repo4)}
specs:
isolated_dep (2.0.1)
isolated_owner (1.0.1)
isolated_dep (~> 2.0)
shared_dep (5.0.1)
shared_owner_a (3.0.1)
shared_dep (~> 5.0)
shared_owner_b (4.0.1)
shared_dep (~> 5.0)
PLATFORMS
ruby
DEPENDENCIES
shared_owner_a
shared_owner_b
isolated_owner
BUNDLED WITH
1.13.0
L
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
end
it "should not eagerly unlock shared dependency with bundle install conservative updating behavior" do
updated_deps_in_gemfile = [Bundler::Dependency.new("isolated_owner", ">= 0"),
Bundler::Dependency.new("shared_owner_a", "3.0.2"),
Bundler::Dependency.new("shared_owner_b", ">= 0")]
unlock_hash_for_bundle_install = {}
definition = Bundler::Definition.new(
bundled_app_lock,
updated_deps_in_gemfile,
source_list,
unlock_hash_for_bundle_install
)
locked = definition.send(:converge_locked_specs).map(&:name)
expect(locked).to include "shared_dep"
end
it "should not eagerly unlock shared dependency with bundle update conservative updating behavior" do
updated_deps_in_gemfile = [Bundler::Dependency.new("isolated_owner", ">= 0"),
Bundler::Dependency.new("shared_owner_a", ">= 0"),
Bundler::Dependency.new("shared_owner_b", ">= 0")]
definition = Bundler::Definition.new(
bundled_app_lock,
updated_deps_in_gemfile,
source_list,
:gems => ["shared_owner_a"], :conservative => true
)
locked = definition.send(:converge_locked_specs).map(&:name)
expect(locked).to eq %w[isolated_dep isolated_owner shared_dep shared_owner_b]
expect(locked.include?("shared_dep")).to be_truthy
end
end
end
end
def mock_source_list
Class.new do
def all_sources
[]
end
def path_sources
[]
end
def rubygems_remotes
[]
end
def replace_sources!(arg)
nil
end
end.new
end
end