diff options
author | Diego Steiner <diego.steiner@renuo.ch> | 2016-09-27 14:07:35 +0200 |
---|---|---|
committer | Diego Steiner <diego.steiner@renuo.ch> | 2016-09-27 14:07:35 +0200 |
commit | f809209b0c13a48a6da75692483bb51cf3ac0342 (patch) | |
tree | 37ca2dd297079ef5b91faefc423cd1b997d3991f /spec | |
parent | 14c1a12b711878c7d7d7f360cb70c9398496b018 (diff) | |
parent | 121ada2a1842ebe9989f35567e2dd829ec06b7a1 (diff) | |
download | bundler-f809209b0c13a48a6da75692483bb51cf3ac0342.tar.gz |
Merge remote-tracking branch 'origin/master' into 4854-gemnotfound-error
Diffstat (limited to 'spec')
38 files changed, 744 insertions, 136 deletions
diff --git a/spec/bundler/definition_spec.rb b/spec/bundler/definition_spec.rb index c72f50f0d1..71e5bb00aa 100644 --- a/spec/bundler/definition_spec.rb +++ b/spec/bundler/definition_spec.rb @@ -137,7 +137,7 @@ describe Bundler::Definition do describe "initialize" do context "gem version promoter" do context "with lockfile" do - before :each do + before do install_gemfile <<-G source "file://#{gem_repo1}" gem "foo" @@ -159,6 +159,73 @@ describe Bundler::Definition do end end + context "shared dependent gems" do + before do + build_repo4 do + build_gem "isolated_owner", %w(1.0.1 1.0.2) do |s| + s.add_dependency "isolated_dep", "~> 2.0" + end + build_gem "isolated_dep", %w(2.0.1 2.0.2) + + build_gem "shared_owner_a", %w(3.0.1 3.0.2) do |s| + s.add_dependency "shared_dep", "~> 5.0" + end + build_gem "shared_owner_b", %w(4.0.1 4.0.2) do |s| + s.add_dependency "shared_dep", "~> 5.0" + end + build_gem "shared_dep", %w(5.0.1 5.0.2) + end + + gemfile <<-G + source "file://#{gem_repo4}" + gem 'isolated_owner' + + gem 'shared_owner_a' + gem 'shared_owner_b' + G + + lockfile <<-L + GEM + remote: file://#{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 + end + + it "should unlock isolated and shared dependencies equally" do + # setup for these test costs about 3/4 of a second, much faster to just jam them all in here. + # the global before :each defeats any ability to have re-usable setup for many examples in a + # single context by wiping out the tmp dir and contents. + + unlock_deps_test(%w(isolated_owner), %w(isolated_dep isolated_owner)) + unlock_deps_test(%w(isolated_owner shared_owner_a), %w(isolated_dep isolated_owner shared_dep shared_owner_a)) + end + + def unlock_deps_test(passed_unlocked, expected_calculated) + definition = Bundler::Definition.new(bundled_app("Gemfile.lock"), [], Bundler::SourceList.new, :gems => passed_unlocked) + unlock_gems = definition.gem_version_promoter.unlock_gems + expect(unlock_gems.sort).to eq expected_calculated + end + end + def mock_source_list Class.new do def all_sources diff --git a/spec/bundler/endpoint_specification_spec.rb b/spec/bundler/endpoint_specification_spec.rb index 6718b24971..b1e71df39a 100644 --- a/spec/bundler/endpoint_specification_spec.rb +++ b/spec/bundler/endpoint_specification_spec.rb @@ -50,4 +50,17 @@ describe Bundler::EndpointSpecification do end end end + + describe "#parse_metadata" do + context "when the metadata has malformed requirements" do + let(:metadata) { { "rubygems" => ">\n" } } + it "raises a helpful error message" do + expect { subject }.to raise_error( + Bundler::GemspecError, + a_string_including("There was an error parsing the metadata for the gem foo (1.0.0)"). + and(a_string_including('The metadata was {"rubygems"=>">\n"}')) + ) + end + end + end end diff --git a/spec/bundler/env_spec.rb b/spec/bundler/env_spec.rb index 73d1f1d7df..245073d9b8 100644 --- a/spec/bundler/env_spec.rb +++ b/spec/bundler/env_spec.rb @@ -15,6 +15,7 @@ describe Bundler::Env do expect(out).to include(Gem::VERSION) expect(out).to include(env.send(:ruby_version)) expect(out).to include(env.send(:git_version)) + expect(out).to include(OpenSSL::OPENSSL_VERSION) end context "when there is a Gemfile and a lockfile and print_gemfile is true" do @@ -48,6 +49,14 @@ describe Bundler::Env do end end + context "when there no Gemfile and print_gemfile is true" do + let(:output) { env.report(:print_gemfile => true) } + + it "prints the environment" do + expect(output).to start_with("Environment") + end + end + context "when Gemfile contains a gemspec and print_gemspecs is true" do let(:gemspec) do <<-GEMSPEC.gsub(/^\s+/, "") diff --git a/spec/bundler/mirror_spec.rb b/spec/bundler/mirror_spec.rb index eb0ccf0bdf..6a81ef2af4 100644 --- a/spec/bundler/mirror_spec.rb +++ b/spec/bundler/mirror_spec.rb @@ -131,6 +131,16 @@ describe Bundler::Settings::Mirror do end end end + + describe "#==" do + it "returns true if uri and fallback timeout are the same" do + uri = "https://ruby.taobao.org" + mirror = Bundler::Settings::Mirror.new(uri, 1) + another_mirror = Bundler::Settings::Mirror.new(uri, 1) + + expect(mirror == another_mirror).to be true + end + end end end diff --git a/spec/bundler/remote_specification_spec.rb b/spec/bundler/remote_specification_spec.rb index 6a8e9a6434..d958ca85eb 100644 --- a/spec/bundler/remote_specification_spec.rb +++ b/spec/bundler/remote_specification_spec.rb @@ -158,16 +158,30 @@ describe Bundler::RemoteSpecification do describe "method missing" do context "and is present in Gem::Specification" do - let(:remote_spec) { double(:remote_spec) } + let(:remote_spec) { double(:remote_spec, :authors => "abcd") } before do - allow_any_instance_of(Gem::Specification).to receive(:respond_to?).and_return(true) allow(subject).to receive(:_remote_specification).and_return(remote_spec) + expect(subject.methods.map(&:to_sym)).not_to include(:authors) end it "should send through to Gem::Specification" do - expect(remote_spec).to receive(:send).with(:missing_method_call).once - subject.missing_method_call + expect(subject.authors).to eq("abcd") + end + end + end + + describe "respond to missing?" do + context "and is present in Gem::Specification" do + let(:remote_spec) { double(:remote_spec, :authors => "abcd") } + + before do + allow(subject).to receive(:_remote_specification).and_return(remote_spec) + expect(subject.methods.map(&:to_sym)).not_to include(:authors) + end + + it "should send through to Gem::Specification" do + expect(subject.respond_to?(:authors)).to be_truthy end end end diff --git a/spec/bundler/ruby_version_spec.rb b/spec/bundler/ruby_version_spec.rb index abcd0303d0..e983c18484 100644 --- a/spec/bundler/ruby_version_spec.rb +++ b/spec/bundler/ruby_version_spec.rb @@ -35,6 +35,14 @@ describe "Bundler::RubyVersion and its subclasses" do end end + context "with engine in symbol" do + let(:engine) { :jruby } + + it "should coerce engine to string" do + expect(subject.engine).to eq("jruby") + end + end + context "is called with multiple requirements" do let(:version) { ["<= 2.0.0", "> 1.9.3"] } let(:engine_version) { nil } diff --git a/spec/bundler/settings_spec.rb b/spec/bundler/settings_spec.rb index 0f7d2a0138..5a9d0cb08b 100644 --- a/spec/bundler/settings_spec.rb +++ b/spec/bundler/settings_spec.rb @@ -54,6 +54,16 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow end describe "#[]" do + context "when the local config file is not found" do + subject(:settings) { described_class.new } + + it "does not raise" do + expect do + subject["foo"] + end.not_to raise_error + end + end + context "when not set" do context "when default value present" do it "retrieves value" do @@ -96,6 +106,18 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow end end + describe "#temporary" do + it "reset after used" do + Bundler.settings[:no_install] = true + + Bundler.settings.temporary(:no_install => false) do + expect(Bundler.settings[:no_install]).to eq false + end + + expect(Bundler.settings[:no_install]).to eq true + end + end + describe "#set_global" do context "when it's not possible to write to the file" do it "raises an PermissionError with explanation" do diff --git a/spec/bundler/source_spec.rb b/spec/bundler/source_spec.rb index 25abd90c96..ea171d387c 100644 --- a/spec/bundler/source_spec.rb +++ b/spec/bundler/source_spec.rb @@ -22,7 +22,7 @@ describe Bundler::Source do end describe "#version_message" do - let(:spec) { double(:spec, :name => "nokogiri", :version => ">= 1.6") } + let(:spec) { double(:spec, :name => "nokogiri", :version => ">= 1.6", :platform => rb) } shared_examples_for "the lockfile specs are not relevant" do it "should return a string with the spec name and version" do @@ -61,7 +61,7 @@ describe Bundler::Source do before { Bundler.ui = Bundler::UI::Shell.new } it "should return a string with the spec name and version and locked spec version" do - expect(subject.version_message(spec)).to eq("nokogiri >= 1.6 (\e[32mwas < 1.5\e[0m)") + expect(subject.version_message(spec)).to eq("nokogiri >= 1.6\e[32m (was < 1.5)\e[0m") end end diff --git a/spec/bundler/yaml_serializer_spec.rb b/spec/bundler/yaml_serializer_spec.rb index 0b3261336c..bf86d2a076 100644 --- a/spec/bundler/yaml_serializer_spec.rb +++ b/spec/bundler/yaml_serializer_spec.rb @@ -125,6 +125,29 @@ describe Bundler::YAMLSerializer do expect(serializer.load(yaml)).to eq(hash) end + + it "handles windows-style CRLF line endings" do + yaml = strip_whitespace(<<-YAML).gsub("\n", "\r\n") + --- + nested_hash: + contains_array: + - "Why shouldn't you write with a broken pencil?" + - "Because it's pointless!" + - oh so silly + YAML + + hash = { + "nested_hash" => { + "contains_array" => [ + "Why shouldn't you write with a broken pencil?", + "Because it's pointless!", + "oh so silly", + ], + }, + } + + expect(serializer.load(yaml)).to eq(hash) + end end describe "against yaml lib" do diff --git a/spec/commands/add_spec.rb b/spec/commands/add_spec.rb deleted file mode 100644 index d6b9b46f94..0000000000 --- a/spec/commands/add_spec.rb +++ /dev/null @@ -1,86 +0,0 @@ -# frozen_string_literal: true -require "spec_helper" - -describe "bundle add" do - before :each do - build_repo2 - - gemfile <<-G - source "file://#{gem_repo2}" - G - end - - context "when version number is set" do - it "adds gem with provided version" do - bundle "add activesupport 2.3.5" - expect(bundled_app("Gemfile").read).to include("gem 'activesupport', '~> 2.3.5'") - end - - it "adds gem with provided version and version operator" do - update_repo2 do - build_gem "activesupport", "3.0.0" - end - - bundle "add activesupport '> 2.3.5'" - expect(bundled_app("Gemfile").read).to include("gem 'activesupport', '> 2.3.5'") - end - end - - context "when version number is not set" do - it "adds gem with last stable version" do - bundle "add activesupport" - expect(bundled_app("Gemfile").read).to include("gem 'activesupport', '~> 2.3.5'") - end - - it "`--pre` flag adds the gem with the latest prerelease version" do - update_repo2 do - build_gem "activesupport", "3.0.0.beta" - end - - bundle "add activesupport --pre" - expect(bundled_app("Gemfile").read).to include("gem 'activesupport', '~> 3.0.0.beta'") - end - - it "`--pre` flag adds the gem with the latest non-prerelease version if it is available" do - update_repo2 do - build_gem "activesupport", "3.0.0.beta" - build_gem "activesupport", "3.0.0" - end - - bundle "add activesupport --pre" - expect(bundled_app("Gemfile").read).to include("gem 'activesupport', '~> 3.0.0'") - end - end - - context "when group is set" do - it "adds the gem with the specified groups" do - bundle "add activesupport --group development test" - expect(bundled_app("Gemfile").read).to include("gem 'activesupport', '~> 2.3.5', :group => [:development, :test]") - end - end - - context "when source is set" do - it "adds the gem with a specified source" do - bundle "add activesupport --source file://#{gem_repo2}" - expect(bundled_app("Gemfile").read).to include("gem 'activesupport', '~> 2.3.5', :source => 'file:\/\/#{gem_repo2}'") - end - end - - context "when multiple options are set" do - before :each do - update_repo2 do - build_gem "activesupport", "3.0.0" - end - end - - it "adds the gem with a specified group and source" do - bundle "add activesupport --group test --source file://#{gem_repo2}" - expect(bundled_app("Gemfile").read).to include("gem 'activesupport', '~> 3.0.0', :group => [:test], :source => 'file:\/\/#{gem_repo2}'") - end - - it "adds the gem with a specified version, group, and source" do - bundle "add activesupport 2.3.5 --group development --source file://#{gem_repo2}" - expect(bundled_app("Gemfile").read).to include("gem 'activesupport', '~> 2.3.5', :group => [:development], :source => 'file:\/\/#{gem_repo2}'") - end - end -end diff --git a/spec/commands/doctor_spec.rb b/spec/commands/doctor_spec.rb index 236138a6c8..8debeb55e4 100644 --- a/spec/commands/doctor_spec.rb +++ b/spec/commands/doctor_spec.rb @@ -55,7 +55,10 @@ describe "bundle doctor" do expect(doctor).to receive(:dylibs).exactly(2).times.and_return ["/usr/local/opt/icu4c/lib/libicui18n.57.1.dylib"] allow(File).to receive(:exist?).and_call_original allow(File).to receive(:exist?).with("/usr/local/opt/icu4c/lib/libicui18n.57.1.dylib").and_return(false) - expect { doctor.run }.to raise_error SystemExit - expect(@stdout.string).to include("libicui18n.57.1.dylib") + expect { doctor.run }.to raise_error Bundler::ProductionError, strip_whitespace(<<-E).strip + The following gems are missing OS dependencies: + * bundler: /usr/local/opt/icu4c/lib/libicui18n.57.1.dylib + * rack: /usr/local/opt/icu4c/lib/libicui18n.57.1.dylib + E end end diff --git a/spec/commands/exec_spec.rb b/spec/commands/exec_spec.rb index 3d861c0799..4d374cebdd 100644 --- a/spec/commands/exec_spec.rb +++ b/spec/commands/exec_spec.rb @@ -564,6 +564,42 @@ describe "bundle exec" do it_behaves_like "it runs" end + context "regarding $0 and __FILE__" do + let(:executable) { super() + <<-'RUBY' } + + puts "$0: #{$0.inspect}" + puts "__FILE__: #{__FILE__.inspect}" + RUBY + + let(:expected) { super() + <<-EOS.chomp } + +$0: #{path.to_s.inspect} +__FILE__: #{path.to_s.inspect} + EOS + + it_behaves_like "it runs" + + context "when the path is relative" do + let(:path) { super().relative_path_from(bundled_app) } + + if LessThanProc.with(RUBY_VERSION).call("1.9") + pending "relative paths have ./ __FILE__" + else + it_behaves_like "it runs" + end + end + + context "when the path is relative with a leading ./" do + let(:path) { Pathname.new("./#{super().relative_path_from(Pathname.pwd)}") } + + if LessThanProc.with(RUBY_VERSION).call("< 1.9") + pending "relative paths with ./ have absolute __FILE__" + else + it_behaves_like "it runs" + end + end + end + context "signals being trapped by bundler" do let(:executable) { strip_whitespace <<-RUBY } #{shebang} diff --git a/spec/commands/lock_spec.rb b/spec/commands/lock_spec.rb index 693c1a6fe0..5600434607 100644 --- a/spec/commands/lock_spec.rb +++ b/spec/commands/lock_spec.rb @@ -10,9 +10,11 @@ describe "bundle lock" do strip_lockfile bundled_app(file).read end + let(:repo) { gem_repo1 } + before :each do gemfile <<-G - source "file://#{gem_repo1}" + source "file://#{repo}" gem "rails" gem "with_license" gem "foo" @@ -20,7 +22,7 @@ describe "bundle lock" do @lockfile = strip_lockfile <<-L GEM - remote: file:#{gem_repo1}/ + remote: file:#{repo}/ specs: actionmailer (2.3.2) activesupport (= 2.3.2) @@ -77,7 +79,7 @@ describe "bundle lock" do it "writes a lockfile when there is an outdated lockfile using --update" do lockfile @lockfile.gsub("2.3.2", "2.3.1") - bundle "lock --update" + bundle! "lock --update" expect(read_lockfile).to eq(@lockfile) end @@ -132,4 +134,119 @@ describe "bundle lock" do bundle "lock --remove-platform #{local}" expect(out).to include("Removing all platforms from the bundle is not allowed") end + + # from https://github.com/bundler/bundler/issues/4896 + it "properly adds platforms when platform requirements come from different dependencies" do + build_repo4 do + build_gem "ffi", "1.9.14" + build_gem "ffi", "1.9.14" do |s| + s.platform = mingw + end + + build_gem "gssapi", "0.1" + build_gem "gssapi", "0.2" + build_gem "gssapi", "0.3" + build_gem "gssapi", "1.2.0" do |s| + s.add_dependency "ffi", ">= 1.0.1" + end + + build_gem "mixlib-shellout", "2.2.6" + build_gem "mixlib-shellout", "2.2.6" do |s| + s.platform = "universal-mingw32" + s.add_dependency "win32-process", "~> 0.8.2" + end + + # we need all these versions to get the sorting the same as it would be + # pulling from rubygems.org + %w(0.8.3 0.8.2 0.8.1 0.8.0).each do |v| + build_gem "win32-process", v do |s| + s.add_dependency "ffi", ">= 1.0.0" + end + end + end + + gemfile <<-G + source "file:#{gem_repo4}" + + gem "mixlib-shellout" + gem "gssapi" + G + + simulate_platform(mingw) { bundle! :lock } + + expect(the_bundle.lockfile).to read_as(strip_whitespace(<<-G)) + GEM + remote: file:#{gem_repo4}/ + specs: + ffi (1.9.14-x86-mingw32) + gssapi (1.2.0) + ffi (>= 1.0.1) + mixlib-shellout (2.2.6-universal-mingw32) + win32-process (~> 0.8.2) + win32-process (0.8.3) + ffi (>= 1.0.0) + + PLATFORMS + x86-mingw32 + + DEPENDENCIES + gssapi + mixlib-shellout + + BUNDLED WITH + #{Bundler::VERSION} + G + + simulate_platform(rb) { bundle! :lock } + + expect(the_bundle.lockfile).to read_as(strip_whitespace(<<-G)) + GEM + remote: file:#{gem_repo4}/ + specs: + ffi (1.9.14) + ffi (1.9.14-x86-mingw32) + gssapi (1.2.0) + ffi (>= 1.0.1) + mixlib-shellout (2.2.6) + mixlib-shellout (2.2.6-universal-mingw32) + win32-process (~> 0.8.2) + win32-process (0.8.3) + ffi (>= 1.0.0) + + PLATFORMS + ruby + x86-mingw32 + + DEPENDENCIES + gssapi + mixlib-shellout + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + context "when an update is available" do + let(:repo) { gem_repo2 } + + before do + lockfile(@lockfile) + build_repo2 do + build_gem "foo", "2.0" + end + end + + it "does not implicitly update" do + bundle! "lock" + + expect(read_lockfile).to eq(@lockfile) + end + + it "accounts for changes in the gemfile" do + gemfile gemfile.gsub('"foo"', '"foo", "2.0"') + bundle! "lock" + + expect(read_lockfile).to eq(@lockfile.sub("foo (1.0)", "foo (2.0)").sub(/foo$/, "foo (= 2.0)")) + end + end end diff --git a/spec/commands/newgem_spec.rb b/spec/commands/newgem_spec.rb index cb3c48132a..6e80aa7a60 100644 --- a/spec/commands/newgem_spec.rb +++ b/spec/commands/newgem_spec.rb @@ -112,6 +112,35 @@ describe "bundle gem" do end end + context "README.md" do + let(:gem_name) { "test_gem" } + let(:generated_gem) { Bundler::GemHelper.new(bundled_app(gem_name).to_s) } + + context "git config user.name present" do + before do + execute_bundle_gem(gem_name) + end + + it "contribute URL set to git username" do + expect(bundled_app("test_gem/README.md").read).not_to include("[USERNAME]") + end + end + + context "git config user.name is absent" do + before do + `git config --unset user.name` + reset! + in_app_root + bundle "gem #{gem_name}" + remove_push_guard(gem_name) + end + + it "contribute URL set to [USERNAME]" do + expect(bundled_app("test_gem/README.md").read).to include("[USERNAME]") + end + end + end + it "generates a valid gemspec" do system_gems ["rake-10.0.2"] diff --git a/spec/commands/update_spec.rb b/spec/commands/update_spec.rb index 19fbb8388c..8a9867d1e9 100644 --- a/spec/commands/update_spec.rb +++ b/spec/commands/update_spec.rb @@ -72,6 +72,42 @@ describe "bundle update" do end end + describe "when a possible resolve requires an older version of a locked gem" do + context "and only_update_to_newer_versions is set" do + before do + bundle! "config only_update_to_newer_versions true" + end + it "does not go to an older version" do + build_repo4 do + build_gem "a" do |s| + s.add_dependency "b" + s.add_dependency "c" + end + build_gem "b" + build_gem "c" + build_gem "c", "2.0" + end + + install_gemfile! <<-G + source "file:#{gem_repo4}" + gem "a" + G + + expect(the_bundle).to include_gems("a 1.0", "b 1.0", "c 2.0") + + update_repo4 do + build_gem "b", "2.0" do |s| + s.add_dependency "c", "< 2" + end + end + + bundle! "update" + + expect(the_bundle).to include_gems("a 1.0", "b 1.0", "c 2.0") + end + end + end + describe "with --local option" do it "doesn't hit repo2" do FileUtils.rm_rf(gem_repo2) diff --git a/spec/install/gemfile/eval_gemfile_spec.rb b/spec/install/gemfile/eval_gemfile_spec.rb index 2660ac98c2..29f27550e4 100644 --- a/spec/install/gemfile/eval_gemfile_spec.rb +++ b/spec/install/gemfile/eval_gemfile_spec.rb @@ -26,6 +26,24 @@ describe "bundle install with gemfile that uses eval_gemfile" do end end + context "eval-ed Gemfile has relative-path gems" do + before do + build_lib("a", :path => "gems/a") + create_file "nested/Gemfile-nested", <<-G + gem "a", :path => "../gems/a" + G + + gemfile <<-G + eval_gemfile "nested/Gemfile-nested" + G + end + + it "installs the path gem" do + bundle! :install + expect(the_bundle).to include_gem("a 1.0") + end + end + context "Gemfile uses gemspec paths after eval-ing a Gemfile" do before { create_file "other/Gemfile-other" } diff --git a/spec/install/gemfile/specific_platform_spec.rb b/spec/install/gemfile/specific_platform_spec.rb new file mode 100644 index 0000000000..3e12f94c86 --- /dev/null +++ b/spec/install/gemfile/specific_platform_spec.rb @@ -0,0 +1,95 @@ +# frozen_string_literal: true +require "spec_helper" + +describe "bundle install with specific_platform enabled" do + before do + bundle "config specific_platform true" + + build_repo2 do + build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") + build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") {|s| s.platform = "x86_64-linux" } + build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") {|s| s.platform = "x86-mingw32" } + build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") {|s| s.platform = "x86-linux" } + build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") {|s| s.platform = "x64-mingw32" } + build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") {|s| s.platform = "universal-darwin" } + + build_gem("google-protobuf", "3.0.0.alpha.5.0.5") {|s| s.platform = "x86_64-linux" } + build_gem("google-protobuf", "3.0.0.alpha.5.0.5") {|s| s.platform = "x86-linux" } + build_gem("google-protobuf", "3.0.0.alpha.5.0.5") {|s| s.platform = "x64-mingw32" } + build_gem("google-protobuf", "3.0.0.alpha.5.0.5") {|s| s.platform = "x86-mingw32" } + build_gem("google-protobuf", "3.0.0.alpha.5.0.5") + + build_gem("google-protobuf", "3.0.0.alpha.5.0.4") {|s| s.platform = "universal-darwin" } + build_gem("google-protobuf", "3.0.0.alpha.5.0.4") {|s| s.platform = "x86_64-linux" } + build_gem("google-protobuf", "3.0.0.alpha.5.0.4") {|s| s.platform = "x86-mingw32" } + build_gem("google-protobuf", "3.0.0.alpha.5.0.4") {|s| s.platform = "x86-linux" } + build_gem("google-protobuf", "3.0.0.alpha.5.0.4") {|s| s.platform = "x64-mingw32" } + build_gem("google-protobuf", "3.0.0.alpha.5.0.4") + + build_gem("google-protobuf", "3.0.0.alpha.5.0.3") + build_gem("google-protobuf", "3.0.0.alpha.5.0.3") {|s| s.platform = "x86_64-linux" } + build_gem("google-protobuf", "3.0.0.alpha.5.0.3") {|s| s.platform = "x86-mingw32" } + build_gem("google-protobuf", "3.0.0.alpha.5.0.3") {|s| s.platform = "x86-linux" } + build_gem("google-protobuf", "3.0.0.alpha.5.0.3") {|s| s.platform = "x64-mingw32" } + build_gem("google-protobuf", "3.0.0.alpha.5.0.3") {|s| s.platform = "universal-darwin" } + + build_gem("google-protobuf", "3.0.0.alpha.4.0") + build_gem("google-protobuf", "3.0.0.alpha.3.1.pre") + build_gem("google-protobuf", "3.0.0.alpha.3") + build_gem("google-protobuf", "3.0.0.alpha.2.0") + build_gem("google-protobuf", "3.0.0.alpha.1.1") + build_gem("google-protobuf", "3.0.0.alpha.1.0") + end + end + + let(:google_protobuf) { <<-G } + source "file:#{gem_repo2}" + gem "google-protobuf" + G + + context "when on a darwin machine" do + before { simulate_platform "x86_64-darwin-15" } + + it "locks to both the specific darwin platform and ruby" do + install_gemfile!(google_protobuf) + expect(the_bundle.locked_gems.platforms).to eq([pl("ruby"), pl("x86_64-darwin-15")]) + expect(the_bundle).to include_gem("google-protobuf 3.0.0.alpha.5.0.5.1 universal-darwin") + expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w( + google-protobuf-3.0.0.alpha.5.0.5.1 + google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin + )) + end + + it "caches both the universal-darwin and ruby gems when --all-platforms is passed" do + gemfile(google_protobuf) + bundle! "package --all-platforms" + expect([cached_gem("google-protobuf-3.0.0.alpha.5.0.5.1"), cached_gem("google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin")]). + to all(exist) + end + + context "when adding a platform via lock --add_platform" do + it "adds the foreign platform" do + install_gemfile!(google_protobuf) + bundle! "lock --add-platform=#{x64_mingw}" + + expect(the_bundle.locked_gems.platforms).to eq([rb, x64_mingw, pl("x86_64-darwin-15")]) + expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w( + google-protobuf-3.0.0.alpha.5.0.5.1 + google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin + google-protobuf-3.0.0.alpha.5.0.5.1-x64-mingw32 + )) + end + + it "falls back on plain ruby when that version doesnt have a platform-specific gem" do + install_gemfile!(google_protobuf) + bundle! "lock --add-platform=#{java}" + + expect(the_bundle.locked_gems.platforms).to eq([java, rb, pl("x86_64-darwin-15")]) + expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w( + google-protobuf-3.0.0.alpha.5.0.5.1 + google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin + )) + end + end + end +end diff --git a/spec/install/gemfile_spec.rb b/spec/install/gemfile_spec.rb index 98abc30c86..03ae344987 100644 --- a/spec/install/gemfile_spec.rb +++ b/spec/install/gemfile_spec.rb @@ -66,4 +66,33 @@ describe "bundle install" do expect(out).to match(/You passed :lib as an option for gem 'rack', but it is invalid/) end end + + context "with engine specified in symbol" do + it "does not raise any error parsing Gemfile" do + simulate_ruby_version "2.3.0" do + simulate_ruby_engine "jruby", "9.1.2.0" do + install_gemfile! <<-G + source "https://rubygems.org" + ruby "2.3.0", :engine => :jruby, :engine_version => "9.1.2.0" + G + + expect(out).to match(/Bundle complete!/) + end + end + end + + it "installation succeeds" do + simulate_ruby_version "2.3.0" do + simulate_ruby_engine "jruby", "9.1.2.0" do + install_gemfile! <<-G + source "file://#{gem_repo1}" + ruby "2.3.0", :engine => :jruby, :engine_version => "9.1.2.0" + gem "rack" + G + + expect(the_bundle).to include_gems "rack 1.0.0" + end + end + end + end end diff --git a/spec/install/gems/compact_index_spec.rb b/spec/install/gems/compact_index_spec.rb index 0edd1d20e7..228d8ddcc9 100644 --- a/spec/install/gems/compact_index_spec.rb +++ b/spec/install/gems/compact_index_spec.rb @@ -695,4 +695,47 @@ The checksum of /versions does not match the checksum provided by the server! So expect(File.read(versions)).to start_with("created_at") expect(the_bundle).to include_gems "rack 1.0.0" end + + it "fails gracefully when the source URI has an invalid scheme" do + install_gemfile <<-G + source "htps://rubygems.org" + gem "rack" + G + expect(exitstatus).to eq(15) if exitstatus + expect(out).to end_with(<<-E.strip) + The request uri `htps://index.rubygems.org/versions` has an invalid scheme (`htps`). Did you mean `http` or `https`? + E + end + + describe "checksum validation", :rubygems => ">= 2.3.0" do + it "raises when the checksum does not match" do + install_gemfile <<-G, :artifice => "compact_index_wrong_gem_checksum" + source "#{source_uri}" + gem "rack" + G + expect(exitstatus).to eq(19) if exitstatus + expect(out). + to include("The checksum for the downloaded `rack-1.0.0.gem` did not match the checksum given by the API."). + and include("This means that the contents of the gem appear to be different from what was uploaded, and could be an indicator of a security issue."). + and match(/\(The expected SHA256 checksum was "#{"ab" * 22}", but the checksum for the downloaded gem was ".+?"\.\)/). + and include("Bundler cannot continue installing rack (1.0.0).") + end + + it "raises when the checksum is the wrong length" do + install_gemfile <<-G, :artifice => "compact_index_wrong_gem_checksum", :env => { "BUNDLER_SPEC_RACK_CHECKSUM" => "checksum!" } + source "#{source_uri}" + gem "rack" + G + expect(exitstatus).to eq(5) if exitstatus + expect(out).to include("The given checksum for rack-1.0.0 (\"checksum!\") is not a valid SHA256 hexdigest nor base64digest") + end + + it "does not raise when disable_checksum_validation is set" do + bundle! "config disable_checksum_validation true" + install_gemfile! <<-G, :artifice => "compact_index_wrong_gem_checksum" + source "#{source_uri}" + gem "rack" + G + end + end end diff --git a/spec/install/gems/resolving_spec.rb b/spec/install/gems/resolving_spec.rb index 816799c0f8..0204a222f9 100644 --- a/spec/install/gems/resolving_spec.rb +++ b/spec/install/gems/resolving_spec.rb @@ -119,20 +119,58 @@ describe "bundle install with install-time dependencies" do end context "allows no gems" do - it "does not try to install those gems" do + before do build_repo2 do build_gem "require_ruby" do |s| s.required_ruby_version = "> 9000" end end + end - install_gemfile <<-G - source "file://#{gem_repo2}" - gem 'require_ruby' - G + let(:ruby_requirement) { %("#{RUBY_VERSION}") } + let(:error_message_requirement) { "~> #{RUBY_VERSION}.0" } + + shared_examples_for "ruby version conflicts" do + it "raises an error during resolution" do + install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2 } + source "http://localgemserver.test/" + ruby #{ruby_requirement} + gem 'require_ruby' + G + + expect(out).to_not include("Gem::InstallError: require_ruby requires Ruby version > 9000") + + nice_error = strip_whitespace(<<-E).strip + Fetching gem metadata from http://localgemserver.test/. + Fetching version metadata from http://localgemserver.test/ + Resolving dependencies... + Bundler could not find compatible versions for gem "ruby\0": + In Gemfile: + ruby\0 (#{error_message_requirement}) + + require_ruby was resolved to 1.0, which depends on + ruby\0 (> 9000) + + Could not find gem 'ruby\0 (> 9000)', which is required by gem 'require_ruby', in any of the sources. + E + expect(out).to eq(nice_error) + end + end + + it_behaves_like "ruby version conflicts" + + describe "with a < requirement" do + let(:ruby_requirement) { %("< 5000") } + let(:error_message_requirement) { "< 5000" } + + it_behaves_like "ruby version conflicts" + end + + describe "with a compound requirement" do + let(:ruby_requirement) { %("< 5000", "> 0.1") } + let(:error_message_requirement) { "< 5000, > 0.1" } - expect(out).to_not include("Gem::InstallError: require_ruby requires Ruby version > 9000") - expect(out).to include("require_ruby-1.0 requires ruby version > 9000, which is incompatible with the current version, #{Bundler::RubyVersion.system}") + it_behaves_like "ruby version conflicts" end end end diff --git a/spec/install/gemspecs_spec.rb b/spec/install/gemspecs_spec.rb index 3e6021b7e2..8f719bf601 100644 --- a/spec/install/gemspecs_spec.rb +++ b/spec/install/gemspecs_spec.rb @@ -50,7 +50,7 @@ describe "bundle install" do context "when ruby version is specified in gemspec and gemfile" do it "installs when patch level is not specified and the version matches" do build_lib("foo", :path => bundled_app) do |s| - s.required_ruby_version = RUBY_VERSION + s.required_ruby_version = "~> #{RUBY_VERSION}.0" end install_gemfile <<-G diff --git a/spec/install/path_spec.rb b/spec/install/path_spec.rb index 3d84fffd58..03c42f008c 100644 --- a/spec/install/path_spec.rb +++ b/spec/install/path_spec.rb @@ -130,21 +130,21 @@ describe "bundle install" do end end - describe "to a dead symlink" do + describe "to a file" do before do in_app_root do - `ln -s /tmp/idontexist bundle` + `touch /tmp/idontexist bundle` end end - it "reports the symlink is dead" do + it "reports the file exists" do gemfile <<-G source "file://#{gem_repo1}" gem "rack" G bundle "install --path bundle" - expect(out).to match(/invalid symlink/) + expect(out).to match(/file already exists/) end end end diff --git a/spec/other/major_deprecation_spec.rb b/spec/other/major_deprecation_spec.rb index c8a2633279..6505023d13 100644 --- a/spec/other/major_deprecation_spec.rb +++ b/spec/other/major_deprecation_spec.rb @@ -4,6 +4,22 @@ require "spec_helper" describe "major deprecations" do let(:warnings) { out } # change to err in 2.0 + context "in a .99 version" do + before do + simulate_bundler_version "1.99.1" + bundle "config --delete major_deprecations" + end + + it "prints major deprecations without being configured" do + ruby <<-R + require "bundler" + Bundler::SharedHelpers.major_deprecation(Bundler::VERSION) + R + + expect(warnings).to have_major_deprecation("1.99.1") + end + end + before do bundle "config major_deprecations true" diff --git a/spec/other/trampoline_spec.rb b/spec/other/trampoline_spec.rb index 2aac0a2c1d..9a8e0a4a5d 100644 --- a/spec/other/trampoline_spec.rb +++ b/spec/other/trampoline_spec.rb @@ -59,6 +59,24 @@ describe "bundler version trampolining" do end end + context "without BUNDLE_ENABLE_TRAMPOLINE" do + before { ENV["BUNDLE_ENABLE_TRAMPOLINE"] = nil } + + context "when the version is >= 2" do + let(:version) { "2.7182818285" } + before do + simulate_bundler_version version do + install_gemfile! "" + end + end + + it "trampolines automatically", :realworld => true do + bundle "--version" + expect(err).to include("Installing locked Bundler version #{version}...") + end + end + end + context "installing missing bundler versions", :realworld => true do before do ENV["BUNDLER_VERSION"] = "1.12.3" diff --git a/spec/realworld/edgecases_spec.rb b/spec/realworld/edgecases_spec.rb index 7a78a114b4..06e588044c 100644 --- a/spec/realworld/edgecases_spec.rb +++ b/spec/realworld/edgecases_spec.rb @@ -48,8 +48,16 @@ describe "real world edgecases", :realworld => true, :sometimes => true do gem 'capybara', '~> 2.2.0' gem 'rack-cache', '1.2.0' # last version that works on Ruby 1.9 G - bundle :lock - expect(lockfile).to include("rails (3.2.22.4)") + bundle! :lock + rails_version = ruby(<<-R) + require 'rubygems' + require 'bundler' + fetcher = Bundler::Fetcher.new(Bundler::Source::Rubygems::Remote.new(URI('https://rubygems.org'))) + index = fetcher.specs(%w(rails), nil) + rails = index.search(Gem::Dependency.new("rails", "~> 3.0")).last + puts rails.version + R + expect(lockfile).to include("rails (#{rails_version})") expect(lockfile).to include("capybara (2.2.1)") end diff --git a/spec/resolver/basic_spec.rb b/spec/resolver/basic_spec.rb index b7b8b4c3b8..3e8883d1d4 100644 --- a/spec/resolver/basic_spec.rb +++ b/spec/resolver/basic_spec.rb @@ -92,15 +92,18 @@ describe "Resolving" do gem "bar", "2.0.0" do |s| s.required_ruby_version = "~> 2.0.0" end + + gem "ruby\0", "1.8.7" end dep "foo" + dep "ruby\0", "1.8.7" deps = [] @deps.each do |d| deps << Bundler::DepProxy.new(d, "ruby") end - should_resolve_and_include %w(foo-1.0.0 bar-1.0.0), [{}, [], Bundler::RubyVersion.new("1.8.7", nil, nil, nil)] + should_resolve_and_include %w(foo-1.0.0 bar-1.0.0), [{}, []] end context "conservative" do diff --git a/spec/resolver/platform_spec.rb b/spec/resolver/platform_spec.rb index d5f217684c..fa91eab9c2 100644 --- a/spec/resolver/platform_spec.rb +++ b/spec/resolver/platform_spec.rb @@ -50,7 +50,7 @@ describe "Resolving platform craziness" do # mingw is _not_ hardcoded to add CPU x86 in rubygems platforms "x86-mingw32" dep "thin" - should_resolve_as %w(thin-1.2.7-x86-mingw32) + should_resolve_as %w(thin-1.2.7-mingw32) end it "finds x64-mingw gems" do diff --git a/spec/support/artifice/compact_index.rb b/spec/support/artifice/compact_index.rb index 233c192a67..0afd7fc526 100644 --- a/spec/support/artifice/compact_index.rb +++ b/spec/support/artifice/compact_index.rb @@ -78,7 +78,12 @@ class CompactIndexAPI < Endpoint reqs = d.requirement.requirements.map {|r| r.join(" ") }.join(", ") CompactIndex::Dependency.new(d.name, reqs) end - CompactIndex::GemVersion.new(spec.version.version, spec.platform.to_s, nil, nil, + checksum = begin + Digest::SHA256.file("#{GEM_REPO}/gems/#{spec.original_name}.gem").base64digest + rescue + nil + end + CompactIndex::GemVersion.new(spec.version.version, spec.platform.to_s, checksum, nil, deps, spec.required_ruby_version, spec.required_rubygems_version) end CompactIndex::Gem.new(name, gem_versions) @@ -98,8 +103,8 @@ class CompactIndexAPI < Endpoint file = tmp("versions.list") file.delete if file.file? file = CompactIndex::VersionsFile.new(file.to_s) - file.update_with(gems) - CompactIndex.versions(file, nil, {}) + file.create(gems) + file.contents end end diff --git a/spec/support/artifice/compact_index_concurrent_download.rb b/spec/support/artifice/compact_index_concurrent_download.rb index 30a2171a30..b788a852cf 100644 --- a/spec/support/artifice/compact_index_concurrent_download.rb +++ b/spec/support/artifice/compact_index_concurrent_download.rb @@ -22,8 +22,8 @@ class CompactIndexConcurrentDownload < CompactIndexAPI file = tmp("versions.list") file.delete if file.file? file = CompactIndex::VersionsFile.new(file.to_s) - file.update_with(gems) - CompactIndex.versions(file, nil, {}) + file.create(gems) + file.contents end end end diff --git a/spec/support/artifice/compact_index_extra_api.rb b/spec/support/artifice/compact_index_extra_api.rb index 063e5589d4..844a9ca9f2 100644 --- a/spec/support/artifice/compact_index_extra_api.rb +++ b/spec/support/artifice/compact_index_extra_api.rb @@ -15,8 +15,8 @@ class CompactIndexExtraApi < CompactIndexAPI file = tmp("versions.list") file.delete if file.file? file = CompactIndex::VersionsFile.new(file.to_s) - file.update_with(gems(gem_repo4)) - CompactIndex.versions(file, nil, {}) + file.create(gems(gem_repo4)) + file.contents end end diff --git a/spec/support/artifice/compact_index_wrong_gem_checksum.rb b/spec/support/artifice/compact_index_wrong_gem_checksum.rb new file mode 100644 index 0000000000..3a12a59ae7 --- /dev/null +++ b/spec/support/artifice/compact_index_wrong_gem_checksum.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +require File.expand_path("../compact_index", __FILE__) + +Artifice.deactivate + +class CompactIndexWrongGemChecksum < CompactIndexAPI + get "/info/:name" do + etag_response do + name = params[:name] + gem = gems.find {|g| g.name == name } + checksum = ENV.fetch("BUNDLER_SPEC_#{name.upcase}_CHECKSUM") { "ab" * 22 } + versions = gem ? gem.versions : [] + versions.each {|v| v.checksum = checksum } + CompactIndex.info(versions) + end + end +end + +Artifice.activate_with(CompactIndexWrongGemChecksum) diff --git a/spec/support/builders.rb b/spec/support/builders.rb index 337234f14a..7436779d15 100644 --- a/spec/support/builders.rb +++ b/spec/support/builders.rb @@ -610,7 +610,10 @@ module Spec end def _default_files - @_default_files ||= { "lib/#{name}.rb" => "#{Builders.constantize(name)} = '#{version}'" } + @_default_files ||= begin + platform_string = " #{@spec.platform}" unless @spec.platform == Gem::Platform::RUBY + { "lib/#{name}.rb" => "#{Builders.constantize(name)} = '#{version}#{platform_string}'" } + end end def _default_path diff --git a/spec/support/helpers.rb b/spec/support/helpers.rb index fe79604f30..b30c44d1cb 100644 --- a/spec/support/helpers.rb +++ b/spec/support/helpers.rb @@ -208,7 +208,11 @@ module Spec end def gemfile(*args) - create_file("Gemfile", *args) + if args.empty? + File.open("Gemfile", "r", &:read) + else + create_file("Gemfile", *args) + end end def lockfile(*args) diff --git a/spec/support/indexes.rb b/spec/support/indexes.rb index 9a7879bc74..29780014fc 100644 --- a/spec/support/indexes.rb +++ b/spec/support/indexes.rb @@ -62,7 +62,7 @@ module Spec s.level = opts.first s.strict = opts.include?(:strict) end - should_resolve_and_include specs, [{}, @base, nil, search] + should_resolve_and_include specs, [{}, @base, search] end def an_awesome_index diff --git a/spec/support/matchers.rb b/spec/support/matchers.rb index 9476f18984..9248360639 100644 --- a/spec/support/matchers.rb +++ b/spec/support/matchers.rb @@ -110,15 +110,9 @@ module Spec define_compound_matcher :read_as, [exist] do |file_contents| diffable - attr_reader :strip_whitespace - - chain :stripping_whitespace do - @strip_whitespace = true - end match do |actual| @actual = Bundler.read_file(actual) - file_contents = strip_whitespace(file_contents) if strip_whitespace values_match?(file_contents, @actual) end end diff --git a/spec/support/platforms.rb b/spec/support/platforms.rb index b1dedb05fa..a2a3afba00 100644 --- a/spec/support/platforms.rb +++ b/spec/support/platforms.rb @@ -11,6 +11,10 @@ module Spec Gem::Platform.new("x86-darwin-10") end + def x64_mac + Gem::Platform.new("x86_64-darwin-15") + end + def java Gem::Platform.new([nil, "java", nil]) end diff --git a/spec/support/rubygems_ext.rb b/spec/support/rubygems_ext.rb index 4ddbc3312a..e2b8c6a45e 100644 --- a/spec/support/rubygems_ext.rb +++ b/spec/support/rubygems_ext.rb @@ -9,7 +9,8 @@ module Spec # rack 2.x requires Ruby version >= 2.2.2. # artifice doesn't support rack 2.x now. "rack" => "< 2", - "fakeweb artifice compact_index" => nil, + "fakeweb artifice" => nil, + "compact_index" => "~> 0.11.0", "sinatra" => "1.2.7", # Rake version has to be consistent for tests to pass "rake" => "10.0.2", @@ -36,7 +37,7 @@ module Spec FileUtils.rm_rf(Path.base_system_gems) FileUtils.mkdir_p(Path.base_system_gems) puts "installing gems for the tests to use..." - DEPS.sort {|a, _| a[1].nil? ? 1 : -1 }.each {|n, v| install_gem(n, v) } + install_gems(DEPS) File.open(manifest_path, "w") {|f| f << manifest.join } end @@ -45,10 +46,14 @@ module Spec Gem::DefaultUserInteraction.ui = Gem::SilentUI.new end - def self.install_gem(name, version = nil) - cmd = "gem install #{name} --no-rdoc --no-ri" - cmd += " --version '#{version}'" if version - system(cmd) || raise("Installing gem #{name} for the tests to use failed!") + def self.install_gems(gems) + reqs, no_reqs = gems.partition {|_, req| !req.nil? && !req.split(" ").empty? } + no_reqs.map!(&:first) + reqs.map! {|name, req| "'#{name}:#{req}'" } + deps = reqs.concat(no_reqs).join(" ") + cmd = "gem install #{deps} --no-rdoc --no-ri" + puts cmd + system(cmd) || raise("Installing gems #{deps} for the tests to use failed!") end end end diff --git a/spec/support/the_bundle.rb b/spec/support/the_bundle.rb index 86df9cd9c7..742d393425 100644 --- a/spec/support/the_bundle.rb +++ b/spec/support/the_bundle.rb @@ -27,5 +27,10 @@ module Spec def lockfile bundle_dir.join("Gemfile.lock") end + + def locked_gems + raise "Cannot read lockfile if it doesn't exist" unless locked? + Bundler::LockfileParser.new(lockfile.read) + end end end |