From 40911ddadbd052e342ebb99ad4188efffc8290c1 Mon Sep 17 00:00:00 2001 From: Adam Wanninger Date: Sun, 29 Oct 2017 12:24:09 -0400 Subject: [PATCH 1/9] check Bundler.home permissions in doctor command --- lib/bundler/cli/doctor.rb | 34 ++++++++++++++++++++++ spec/commands/doctor_spec.rb | 55 ++++++++++++++++++++++++++---------- 2 files changed, 74 insertions(+), 15 deletions(-) diff --git a/lib/bundler/cli/doctor.rb b/lib/bundler/cli/doctor.rb index 7f28a5eb130..93366c33a93 100644 --- a/lib/bundler/cli/doctor.rb +++ b/lib/bundler/cli/doctor.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require "rbconfig" +require "find" module Bundler class CLI::Doctor @@ -61,6 +62,7 @@ def check! end def run + check_home_permissions Bundler.ui.level = "error" if options[:quiet] Bundler.settings.validate! check! @@ -90,5 +92,37 @@ def run Bundler.ui.info "No issues found with the installed bundle" end end + + private + + def check_home_permissions + check_for_files_not_owned_by_current_user_but_still_rw + check_for_files_not_readable_or_writable + end + + def check_for_files_not_owned_by_current_user_but_still_rw + return unless any_files_not_owned_by_current_user_but_still_rw? + Bundler.ui.warn "Files exist in Bundler home that are owned by another " \ + "user, but are stil readable/writable" + end + + def check_for_files_not_readable_or_writable + return unless any_files_not_readable_or_writable? + raise ProductionError, "Files exist in Bundler home that are not " \ + "readable/writable to the current user" + end + + def any_files_not_readable_or_writable? + Find.find(Bundler.home.to_s).any? do |f| + !(File.writable?(f) && File.readable?(f)) + end + end + + def any_files_not_owned_by_current_user_but_still_rw? + Find.find(Bundler.home.to_s).any? do |f| + (File.stat(f).uid != Process.uid) && + (File.writable?(f) && File.readable?(f)) + end + end end end diff --git a/spec/commands/doctor_spec.rb b/spec/commands/doctor_spec.rb index 2572d4ff4d8..3e58adff36f 100644 --- a/spec/commands/doctor_spec.rb +++ b/spec/commands/doctor_spec.rb @@ -6,6 +6,19 @@ RSpec.describe "bundle doctor" do before(:each) do + install_gemfile! <<-G + source "file://#{gem_repo1}" + gem "rack" + G + + stat = double("stat") + unwritable_file = double("file") + allow(Find).to receive(:find).with(Bundler.home.to_s) { [unwritable_file] } + allow(File).to receive(:stat).with(unwritable_file) { stat } + allow(stat).to receive(:uid) { Process.uid } + allow(File).to receive(:writable?).with(unwritable_file) { true } + allow(File).to receive(:readable?).with(unwritable_file) { true } + @stdout = StringIO.new [:error, :warn].each do |method| @@ -17,21 +30,11 @@ end it "exits with no message if the installed gem has no C extensions" do - install_gemfile! <<-G - source "file://#{gem_repo1}" - gem "rack" - G - expect { Bundler::CLI::Doctor.new({}).run }.not_to raise_error expect(@stdout.string).to be_empty end it "exits with no message if the installed gem's C extension dylib breakage is fine" do - install_gemfile! <<-G - source "file://#{gem_repo1}" - gem "rack" - G - doctor = Bundler::CLI::Doctor.new({}) expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/rack/rack.bundle"] expect(doctor).to receive(:dylibs).exactly(2).times.and_return ["/usr/lib/libSystem.dylib"] @@ -42,11 +45,6 @@ end it "exits with a message if one of the linked libraries is missing" do - install_gemfile! <<-G - source "file://#{gem_repo1}" - gem "rack" - G - doctor = Bundler::CLI::Doctor.new({}) expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/rack/rack.bundle"] expect(doctor).to receive(:dylibs).exactly(2).times.and_return ["/usr/local/opt/icu4c/lib/libicui18n.57.1.dylib"] @@ -58,4 +56,31 @@ * rack: /usr/local/opt/icu4c/lib/libicui18n.57.1.dylib E end + + it "exits with an error if home contains files that are not read/write" do + stat = double("stat") + unwritable_file = double("file") + doctor = Bundler::CLI::Doctor.new({}) + allow(Find).to receive(:find).with(Bundler.home.to_s) { [unwritable_file] } + allow(File).to receive(:stat).with(unwritable_file) { stat } + allow(stat).to receive(:uid) { Process.uid } + allow(File).to receive(:writable?).with(unwritable_file) { false } + allow(File).to receive(:readable?).with(unwritable_file) { false } + expect { doctor.run }.to raise_error( + Bundler::ProductionError, + "Files exist in Bundler home that are not readable/writable to the current user" + ) + end + + it "exits with a warning if home contains files that are read/write but not owned by current user" do + stat = double("stat") + unwritable_file = double("file") + allow(Find).to receive(:find).with(Bundler.home.to_s) { [unwritable_file] } + allow(File).to receive(:stat).with(unwritable_file) { stat } + allow(stat).to receive(:uid) { 0o0000 } + allow(File).to receive(:writable?).with(unwritable_file) { true } + allow(File).to receive(:readable?).with(unwritable_file) { true } + expect { Bundler::CLI::Doctor.new({}).run }.not_to raise_error + expect(@stdout.string).to include("Files exist in Bundler home that are owned by another user, but are stil readable/writable") + end end From 0c9fb52e7ec69b970a554bb2101f746c0226d0fb Mon Sep 17 00:00:00 2001 From: Adam Wanninger Date: Mon, 27 Nov 2017 18:36:03 -0500 Subject: [PATCH 2/9] use Bundler.ui.info instead of exception --- lib/bundler/cli/doctor.rb | 18 +++++++++--------- spec/commands/doctor_spec.rb | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/bundler/cli/doctor.rb b/lib/bundler/cli/doctor.rb index 93366c33a93..95be4bca0b2 100644 --- a/lib/bundler/cli/doctor.rb +++ b/lib/bundler/cli/doctor.rb @@ -101,25 +101,25 @@ def check_home_permissions end def check_for_files_not_owned_by_current_user_but_still_rw - return unless any_files_not_owned_by_current_user_but_still_rw? + return unless files_not_owned_by_current_user_but_still_rw.any? Bundler.ui.warn "Files exist in Bundler home that are owned by another " \ - "user, but are stil readable/writable" + "user, but are stil readable/writable. These files are: #{files_not_owned_by_current_user_but_still_rw.join("\n")}" end def check_for_files_not_readable_or_writable - return unless any_files_not_readable_or_writable? - raise ProductionError, "Files exist in Bundler home that are not " \ - "readable/writable to the current user" + return unless files_not_readable_or_writable.any? + Bundler.ui.warn "Files exist in Bundler home that are not " \ + "readable/writable to the current user. These files are: #{files_not_readable_or_writable.join("\n")}" end - def any_files_not_readable_or_writable? - Find.find(Bundler.home.to_s).any? do |f| + def files_not_readable_or_writable + Find.find(Bundler.home.to_s).select do |f| !(File.writable?(f) && File.readable?(f)) end end - def any_files_not_owned_by_current_user_but_still_rw? - Find.find(Bundler.home.to_s).any? do |f| + def files_not_owned_by_current_user_but_still_rw + Find.find(Bundler.home.to_s).select do |f| (File.stat(f).uid != Process.uid) && (File.writable?(f) && File.readable?(f)) end diff --git a/spec/commands/doctor_spec.rb b/spec/commands/doctor_spec.rb index 3e58adff36f..3effaf955cc 100644 --- a/spec/commands/doctor_spec.rb +++ b/spec/commands/doctor_spec.rb @@ -66,9 +66,9 @@ allow(stat).to receive(:uid) { Process.uid } allow(File).to receive(:writable?).with(unwritable_file) { false } allow(File).to receive(:readable?).with(unwritable_file) { false } - expect { doctor.run }.to raise_error( - Bundler::ProductionError, - "Files exist in Bundler home that are not readable/writable to the current user" + expect { doctor.run }.not_to raise_error + expect(@stdout.string).to include( + "Files exist in Bundler home that are not readable/writable to the current user. These files are: #{unwritable_file}" ) end @@ -81,6 +81,6 @@ allow(File).to receive(:writable?).with(unwritable_file) { true } allow(File).to receive(:readable?).with(unwritable_file) { true } expect { Bundler::CLI::Doctor.new({}).run }.not_to raise_error - expect(@stdout.string).to include("Files exist in Bundler home that are owned by another user, but are stil readable/writable") + expect(@stdout.string).to include("Files exist in Bundler home that are owned by another user, but are stil readable/writable. These files are: #{unwritable_file}") end end From bc072d8ffb0e9e7a56c309ef872cf71d1858ed42 Mon Sep 17 00:00:00 2001 From: Adam Wanninger Date: Fri, 1 Dec 2017 06:50:22 -0500 Subject: [PATCH 3/9] prefix outputted files with a - for readability --- lib/bundler/cli/doctor.rb | 4 ++-- spec/commands/doctor_spec.rb | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/bundler/cli/doctor.rb b/lib/bundler/cli/doctor.rb index 95be4bca0b2..e4e15fe1a26 100644 --- a/lib/bundler/cli/doctor.rb +++ b/lib/bundler/cli/doctor.rb @@ -103,13 +103,13 @@ def check_home_permissions def check_for_files_not_owned_by_current_user_but_still_rw return unless files_not_owned_by_current_user_but_still_rw.any? Bundler.ui.warn "Files exist in Bundler home that are owned by another " \ - "user, but are stil readable/writable. These files are: #{files_not_owned_by_current_user_but_still_rw.join("\n")}" + "user, but are stil readable/writable. These files are:\n - #{files_not_owned_by_current_user_but_still_rw.join("\n - ")}" end def check_for_files_not_readable_or_writable return unless files_not_readable_or_writable.any? Bundler.ui.warn "Files exist in Bundler home that are not " \ - "readable/writable to the current user. These files are: #{files_not_readable_or_writable.join("\n")}" + "readable/writable to the current user. These files are:\n - #{files_not_readable_or_writable.join("\n - ")}" end def files_not_readable_or_writable diff --git a/spec/commands/doctor_spec.rb b/spec/commands/doctor_spec.rb index 3effaf955cc..6d2c5ef6a33 100644 --- a/spec/commands/doctor_spec.rb +++ b/spec/commands/doctor_spec.rb @@ -68,7 +68,7 @@ allow(File).to receive(:readable?).with(unwritable_file) { false } expect { doctor.run }.not_to raise_error expect(@stdout.string).to include( - "Files exist in Bundler home that are not readable/writable to the current user. These files are: #{unwritable_file}" + "Files exist in Bundler home that are not readable/writable to the current user. These files are:\n - #{unwritable_file}" ) end @@ -81,6 +81,8 @@ allow(File).to receive(:writable?).with(unwritable_file) { true } allow(File).to receive(:readable?).with(unwritable_file) { true } expect { Bundler::CLI::Doctor.new({}).run }.not_to raise_error - expect(@stdout.string).to include("Files exist in Bundler home that are owned by another user, but are stil readable/writable. These files are: #{unwritable_file}") + expect(@stdout.string).to include( + "Files exist in Bundler home that are owned by another user, but are stil readable/writable. These files are:\n - #{unwritable_file}" + ) end end From f0e5f9c0e85fd4d1442939bd4517814e655a0c60 Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Fri, 1 Dec 2017 11:38:43 -0600 Subject: [PATCH 4/9] [CLI::Doctor] Avoid looping over all files twice --- lib/bundler/cli/doctor.rb | 50 ++++++++++++++++++------------------ spec/commands/doctor_spec.rb | 7 +++-- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/lib/bundler/cli/doctor.rb b/lib/bundler/cli/doctor.rb index e4e15fe1a26..e7294eb2857 100644 --- a/lib/bundler/cli/doctor.rb +++ b/lib/bundler/cli/doctor.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "rbconfig" -require "find" module Bundler class CLI::Doctor @@ -62,7 +61,6 @@ def check! end def run - check_home_permissions Bundler.ui.level = "error" if options[:quiet] Bundler.settings.validate! check! @@ -80,6 +78,8 @@ def run end end + permissions_valid = check_home_permissions + if broken_links.any? message = "The following gems are missing OS dependencies:" broken_links.map do |spec, paths| @@ -88,7 +88,7 @@ def run end end.flatten.sort.each {|m| message += m } raise ProductionError, message - else + elsif !permissions_valid Bundler.ui.info "No issues found with the installed bundle" end end @@ -96,33 +96,33 @@ def run private def check_home_permissions - check_for_files_not_owned_by_current_user_but_still_rw - check_for_files_not_readable_or_writable - end - - def check_for_files_not_owned_by_current_user_but_still_rw - return unless files_not_owned_by_current_user_but_still_rw.any? - Bundler.ui.warn "Files exist in Bundler home that are owned by another " \ - "user, but are stil readable/writable. These files are:\n - #{files_not_owned_by_current_user_but_still_rw.join("\n - ")}" - end + require "find" + files_not_readable_or_writable = [] + files_not_owned_by_current_user_but_still_rw = [] + Find.find(Bundler.home.to_s).each do |f| + if !File.writable?(f) || !File.readable?(f) + files_not_readable_or_writable << f + elsif File.stat(f).uid != Process.uid + files_not_owned_by_current_user_but_still_rw << f + end + end - def check_for_files_not_readable_or_writable - return unless files_not_readable_or_writable.any? - Bundler.ui.warn "Files exist in Bundler home that are not " \ - "readable/writable to the current user. These files are:\n - #{files_not_readable_or_writable.join("\n - ")}" - end + ok = true + if files_not_owned_by_current_user_but_still_rw.any? + Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \ + "user, but are stil readable/writable. These files are:\n - #{files_not_owned_by_current_user_but_still_rw.join("\n - ")}" - def files_not_readable_or_writable - Find.find(Bundler.home.to_s).select do |f| - !(File.writable?(f) && File.readable?(f)) + ok = false end - end - def files_not_owned_by_current_user_but_still_rw - Find.find(Bundler.home.to_s).select do |f| - (File.stat(f).uid != Process.uid) && - (File.writable?(f) && File.readable?(f)) + if files_not_readable_or_writable.any? + Bundler.ui.warn "Files exist in the Bundler home that are not " \ + "readable/writable to the current user. These files are:\n - #{files_not_readable_or_writable.join("\n - ")}" + + ok = false end + + ok end end end diff --git a/spec/commands/doctor_spec.rb b/spec/commands/doctor_spec.rb index 6d2c5ef6a33..ef33bedb570 100644 --- a/spec/commands/doctor_spec.rb +++ b/spec/commands/doctor_spec.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require "find" require "stringio" require "bundler/cli" require "bundler/cli/doctor" @@ -68,8 +69,9 @@ allow(File).to receive(:readable?).with(unwritable_file) { false } expect { doctor.run }.not_to raise_error expect(@stdout.string).to include( - "Files exist in Bundler home that are not readable/writable to the current user. These files are:\n - #{unwritable_file}" + "Files exist in the Bundler home that are not readable/writable to the current user. These files are:\n - #{unwritable_file}" ) + expect(@stdout.string).not_to include("No issues") end it "exits with a warning if home contains files that are read/write but not owned by current user" do @@ -82,7 +84,8 @@ allow(File).to receive(:readable?).with(unwritable_file) { true } expect { Bundler::CLI::Doctor.new({}).run }.not_to raise_error expect(@stdout.string).to include( - "Files exist in Bundler home that are owned by another user, but are stil readable/writable. These files are:\n - #{unwritable_file}" + "Files exist in the Bundler home that are owned by another user, but are stil readable/writable. These files are:\n - #{unwritable_file}" ) + expect(@stdout.string).not_to include("No issues") end end From c5e1be8e9ecfd82dc239a579d85902c95f7a6524 Mon Sep 17 00:00:00 2001 From: Adam Wanninger Date: Sun, 14 Jan 2018 09:48:26 -0500 Subject: [PATCH 5/9] 'to the current user' should be 'by the current user' --- lib/bundler/cli/doctor.rb | 2 +- spec/commands/doctor_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/bundler/cli/doctor.rb b/lib/bundler/cli/doctor.rb index e7294eb2857..64981c5b9b3 100644 --- a/lib/bundler/cli/doctor.rb +++ b/lib/bundler/cli/doctor.rb @@ -117,7 +117,7 @@ def check_home_permissions if files_not_readable_or_writable.any? Bundler.ui.warn "Files exist in the Bundler home that are not " \ - "readable/writable to the current user. These files are:\n - #{files_not_readable_or_writable.join("\n - ")}" + "readable/writable by the current user. These files are:\n - #{files_not_readable_or_writable.join("\n - ")}" ok = false end diff --git a/spec/commands/doctor_spec.rb b/spec/commands/doctor_spec.rb index ef33bedb570..c99cea68f64 100644 --- a/spec/commands/doctor_spec.rb +++ b/spec/commands/doctor_spec.rb @@ -69,7 +69,7 @@ allow(File).to receive(:readable?).with(unwritable_file) { false } expect { doctor.run }.not_to raise_error expect(@stdout.string).to include( - "Files exist in the Bundler home that are not readable/writable to the current user. These files are:\n - #{unwritable_file}" + "Files exist in the Bundler home that are not readable/writable by the current user. These files are:\n - #{unwritable_file}" ) expect(@stdout.string).not_to include("No issues") end From 6ee9f72766d440788701270f3e87bb1514c137d5 Mon Sep 17 00:00:00 2001 From: Adam Wanninger Date: Sun, 14 Jan 2018 09:49:31 -0500 Subject: [PATCH 6/9] readable/writable is more descriptive than read/write --- spec/commands/doctor_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/commands/doctor_spec.rb b/spec/commands/doctor_spec.rb index c99cea68f64..c66528a47b7 100644 --- a/spec/commands/doctor_spec.rb +++ b/spec/commands/doctor_spec.rb @@ -58,7 +58,7 @@ E end - it "exits with an error if home contains files that are not read/write" do + it "exits with an error if home contains files that are not readable/writable" do stat = double("stat") unwritable_file = double("file") doctor = Bundler::CLI::Doctor.new({}) From b1fd32c2f34512525253a5da2882e3e4612967b1 Mon Sep 17 00:00:00 2001 From: Adam Wanninger Date: Sun, 14 Jan 2018 09:50:31 -0500 Subject: [PATCH 7/9] corrected spelling of stil to still --- lib/bundler/cli/doctor.rb | 2 +- spec/commands/doctor_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/bundler/cli/doctor.rb b/lib/bundler/cli/doctor.rb index 64981c5b9b3..6fd9f177bb3 100644 --- a/lib/bundler/cli/doctor.rb +++ b/lib/bundler/cli/doctor.rb @@ -110,7 +110,7 @@ def check_home_permissions ok = true if files_not_owned_by_current_user_but_still_rw.any? Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \ - "user, but are stil readable/writable. These files are:\n - #{files_not_owned_by_current_user_but_still_rw.join("\n - ")}" + "user, but are still readable/writable. These files are:\n - #{files_not_owned_by_current_user_but_still_rw.join("\n - ")}" ok = false end diff --git a/spec/commands/doctor_spec.rb b/spec/commands/doctor_spec.rb index c66528a47b7..cd0e020b68c 100644 --- a/spec/commands/doctor_spec.rb +++ b/spec/commands/doctor_spec.rb @@ -84,7 +84,7 @@ allow(File).to receive(:readable?).with(unwritable_file) { true } expect { Bundler::CLI::Doctor.new({}).run }.not_to raise_error expect(@stdout.string).to include( - "Files exist in the Bundler home that are owned by another user, but are stil readable/writable. These files are:\n - #{unwritable_file}" + "Files exist in the Bundler home that are owned by another user, but are still readable/writable. These files are:\n - #{unwritable_file}" ) expect(@stdout.string).not_to include("No issues") end From 2a21e5e3ac377e87a81b7ddd910d7a85bf256dd6 Mon Sep 17 00:00:00 2001 From: Adam Wanninger Date: Sun, 14 Jan 2018 10:38:57 -0500 Subject: [PATCH 8/9] warn user if a file is not R/W and owned by another user --- lib/bundler/cli/doctor.rb | 14 +++++++++++++- spec/commands/doctor_spec.rb | 16 ++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/bundler/cli/doctor.rb b/lib/bundler/cli/doctor.rb index 6fd9f177bb3..3e0898ff8a8 100644 --- a/lib/bundler/cli/doctor.rb +++ b/lib/bundler/cli/doctor.rb @@ -98,10 +98,15 @@ def run def check_home_permissions require "find" files_not_readable_or_writable = [] + files_not_rw_and_owned_by_different_user = [] files_not_owned_by_current_user_but_still_rw = [] Find.find(Bundler.home.to_s).each do |f| if !File.writable?(f) || !File.readable?(f) - files_not_readable_or_writable << f + if File.stat(f).uid != Process.uid + files_not_rw_and_owned_by_different_user << f + else + files_not_readable_or_writable << f + end elsif File.stat(f).uid != Process.uid files_not_owned_by_current_user_but_still_rw << f end @@ -115,6 +120,13 @@ def check_home_permissions ok = false end + if files_not_rw_and_owned_by_different_user.any? + Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \ + "user, and are not readable/writable. These files are:\n - #{files_not_rw_and_owned_by_different_user.join("\n - ")}" + + ok = false + end + if files_not_readable_or_writable.any? Bundler.ui.warn "Files exist in the Bundler home that are not " \ "readable/writable by the current user. These files are:\n - #{files_not_readable_or_writable.join("\n - ")}" diff --git a/spec/commands/doctor_spec.rb b/spec/commands/doctor_spec.rb index cd0e020b68c..55417134583 100644 --- a/spec/commands/doctor_spec.rb +++ b/spec/commands/doctor_spec.rb @@ -74,6 +74,22 @@ expect(@stdout.string).not_to include("No issues") end + it "exits with an error if home contains files that are not readable/writable and are not owned by the current user" do + stat = double("stat") + unwritable_file = double("file") + doctor = Bundler::CLI::Doctor.new({}) + allow(Find).to receive(:find).with(Bundler.home.to_s) { [unwritable_file] } + allow(File).to receive(:stat).with(unwritable_file) { stat } + allow(stat).to receive(:uid) { 0o0000 } + allow(File).to receive(:writable?).with(unwritable_file) { false } + allow(File).to receive(:readable?).with(unwritable_file) { false } + expect { doctor.run }.not_to raise_error + expect(@stdout.string).to include( + "Files exist in the Bundler home that are owned by another user, and are not readable/writable. These files are:\n - #{unwritable_file}" + ) + expect(@stdout.string).not_to include("No issues") + end + it "exits with a warning if home contains files that are read/write but not owned by current user" do stat = double("stat") unwritable_file = double("file") From d82a9ef14af86048ecf79826a55b633d5122d2c7 Mon Sep 17 00:00:00 2001 From: Adam Wanninger Date: Mon, 15 Jan 2018 10:04:08 -0500 Subject: [PATCH 9/9] wrap similar tests in context blocks --- spec/commands/doctor_spec.rb | 153 ++++++++++++++++++----------------- 1 file changed, 78 insertions(+), 75 deletions(-) diff --git a/spec/commands/doctor_spec.rb b/spec/commands/doctor_spec.rb index 55417134583..5260e6cb36b 100644 --- a/spec/commands/doctor_spec.rb +++ b/spec/commands/doctor_spec.rb @@ -12,14 +12,6 @@ gem "rack" G - stat = double("stat") - unwritable_file = double("file") - allow(Find).to receive(:find).with(Bundler.home.to_s) { [unwritable_file] } - allow(File).to receive(:stat).with(unwritable_file) { stat } - allow(stat).to receive(:uid) { Process.uid } - allow(File).to receive(:writable?).with(unwritable_file) { true } - allow(File).to receive(:readable?).with(unwritable_file) { true } - @stdout = StringIO.new [:error, :warn].each do |method| @@ -30,78 +22,89 @@ end end - it "exits with no message if the installed gem has no C extensions" do - expect { Bundler::CLI::Doctor.new({}).run }.not_to raise_error - expect(@stdout.string).to be_empty - end + context "when all files in home are readable/writable" do + before(:each) do + stat = double("stat") + unwritable_file = double("file") + allow(Find).to receive(:find).with(Bundler.home.to_s) { [unwritable_file] } + allow(File).to receive(:stat).with(unwritable_file) { stat } + allow(stat).to receive(:uid) { Process.uid } + allow(File).to receive(:writable?).with(unwritable_file) { true } + allow(File).to receive(:readable?).with(unwritable_file) { true } + end - it "exits with no message if the installed gem's C extension dylib breakage is fine" do - doctor = Bundler::CLI::Doctor.new({}) - expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/rack/rack.bundle"] - expect(doctor).to receive(:dylibs).exactly(2).times.and_return ["/usr/lib/libSystem.dylib"] - allow(File).to receive(:exist?).and_call_original - allow(File).to receive(:exist?).with("/usr/lib/libSystem.dylib").and_return(true) - expect { doctor.run }.not_to(raise_error, @stdout.string) - expect(@stdout.string).to be_empty - end + it "exits with no message if the installed gem has no C extensions" do + expect { Bundler::CLI::Doctor.new({}).run }.not_to raise_error + expect(@stdout.string).to be_empty + end - it "exits with a message if one of the linked libraries is missing" do - doctor = Bundler::CLI::Doctor.new({}) - expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/rack/rack.bundle"] - 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(Bundler::ProductionError, strip_whitespace(<<-E).strip), @stdout.string - 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 + it "exits with no message if the installed gem's C extension dylib breakage is fine" do + doctor = Bundler::CLI::Doctor.new({}) + expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/rack/rack.bundle"] + expect(doctor).to receive(:dylibs).exactly(2).times.and_return ["/usr/lib/libSystem.dylib"] + allow(File).to receive(:exist?).and_call_original + allow(File).to receive(:exist?).with("/usr/lib/libSystem.dylib").and_return(true) + expect { doctor.run }.not_to(raise_error, @stdout.string) + expect(@stdout.string).to be_empty + end - it "exits with an error if home contains files that are not readable/writable" do - stat = double("stat") - unwritable_file = double("file") - doctor = Bundler::CLI::Doctor.new({}) - allow(Find).to receive(:find).with(Bundler.home.to_s) { [unwritable_file] } - allow(File).to receive(:stat).with(unwritable_file) { stat } - allow(stat).to receive(:uid) { Process.uid } - allow(File).to receive(:writable?).with(unwritable_file) { false } - allow(File).to receive(:readable?).with(unwritable_file) { false } - expect { doctor.run }.not_to raise_error - expect(@stdout.string).to include( - "Files exist in the Bundler home that are not readable/writable by the current user. These files are:\n - #{unwritable_file}" - ) - expect(@stdout.string).not_to include("No issues") + it "exits with a message if one of the linked libraries is missing" do + doctor = Bundler::CLI::Doctor.new({}) + expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/rack/rack.bundle"] + 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(Bundler::ProductionError, strip_whitespace(<<-E).strip), @stdout.string + 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 - it "exits with an error if home contains files that are not readable/writable and are not owned by the current user" do - stat = double("stat") - unwritable_file = double("file") - doctor = Bundler::CLI::Doctor.new({}) - allow(Find).to receive(:find).with(Bundler.home.to_s) { [unwritable_file] } - allow(File).to receive(:stat).with(unwritable_file) { stat } - allow(stat).to receive(:uid) { 0o0000 } - allow(File).to receive(:writable?).with(unwritable_file) { false } - allow(File).to receive(:readable?).with(unwritable_file) { false } - expect { doctor.run }.not_to raise_error - expect(@stdout.string).to include( - "Files exist in the Bundler home that are owned by another user, and are not readable/writable. These files are:\n - #{unwritable_file}" - ) - expect(@stdout.string).not_to include("No issues") - end + context "when home contains files that are not readable/writable" do + before(:each) do + @stat = double("stat") + @unwritable_file = double("file") + allow(Find).to receive(:find).with(Bundler.home.to_s) { [@unwritable_file] } + allow(File).to receive(:stat).with(@unwritable_file) { @stat } + end + + it "exits with an error if home contains files that are not readable/writable" do + allow(@stat).to receive(:uid) { Process.uid } + allow(File).to receive(:writable?).with(@unwritable_file) { false } + allow(File).to receive(:readable?).with(@unwritable_file) { false } + expect { Bundler::CLI::Doctor.new({}).run }.not_to raise_error + expect(@stdout.string).to include( + "Files exist in the Bundler home that are not readable/writable by the current user. These files are:\n - #{@unwritable_file}" + ) + expect(@stdout.string).not_to include("No issues") + end + + context "when home contains files that are not owned by the current process" do + before(:each) do + allow(@stat).to receive(:uid) { 0o0000 } + end - it "exits with a warning if home contains files that are read/write but not owned by current user" do - stat = double("stat") - unwritable_file = double("file") - allow(Find).to receive(:find).with(Bundler.home.to_s) { [unwritable_file] } - allow(File).to receive(:stat).with(unwritable_file) { stat } - allow(stat).to receive(:uid) { 0o0000 } - allow(File).to receive(:writable?).with(unwritable_file) { true } - allow(File).to receive(:readable?).with(unwritable_file) { true } - expect { Bundler::CLI::Doctor.new({}).run }.not_to raise_error - expect(@stdout.string).to include( - "Files exist in the Bundler home that are owned by another user, but are still readable/writable. These files are:\n - #{unwritable_file}" - ) - expect(@stdout.string).not_to include("No issues") + it "exits with an error if home contains files that are not readable/writable and are not owned by the current user" do + allow(File).to receive(:writable?).with(@unwritable_file) { false } + allow(File).to receive(:readable?).with(@unwritable_file) { false } + expect { Bundler::CLI::Doctor.new({}).run }.not_to raise_error + expect(@stdout.string).to include( + "Files exist in the Bundler home that are owned by another user, and are not readable/writable. These files are:\n - #{@unwritable_file}" + ) + expect(@stdout.string).not_to include("No issues") + end + + it "exits with a warning if home contains files that are read/write but not owned by current user" do + allow(File).to receive(:writable?).with(@unwritable_file) { true } + allow(File).to receive(:readable?).with(@unwritable_file) { true } + expect { Bundler::CLI::Doctor.new({}).run }.not_to raise_error + expect(@stdout.string).to include( + "Files exist in the Bundler home that are owned by another user, but are still readable/writable. These files are:\n - #{@unwritable_file}" + ) + expect(@stdout.string).not_to include("No issues") + end + end end end