diff options
author | Homu <homu@barosl.com> | 2016-01-16 12:32:53 -0800 |
---|---|---|
committer | Homu <homu@barosl.com> | 2016-01-16 12:32:53 -0800 |
commit | 15a98915e568c7bde7e89ddd0e4ecd5bdd2f0b29 (patch) | |
tree | 8ab53a7e61999521bd0dab5fb7f61c3308f82e19 | |
parent | 7148859353e0c175bd2c26104553af9d0cc96c88 (diff) | |
parent | aa0dd2d4dbdb1d929ce19f15f2670e4fca9fe469 (diff) | |
download | bundler-15a98915e568c7bde7e89ddd0e4ecd5bdd2f0b29.tar.gz |
Auto merge of #4209 - RochesterinNYC:refactor-ruby-version-add-unit-tests, r=segiddins
Refactor and add unit tests for `Bundler::RubyVersion`
- Add extensive unit test coverage for `lib/bundler/ruby_version.rb`
- Refactors `Bundler::RubyVersionRequirement` as a subclass of `Bundler::RubyVersion` (eliminates the odd, misdirecting code involving input_engine) and redundant methods.
-rw-r--r-- | lib/bundler.rb | 6 | ||||
-rw-r--r-- | lib/bundler/definition.rb | 12 | ||||
-rw-r--r-- | lib/bundler/fetcher.rb | 2 | ||||
-rw-r--r-- | lib/bundler/installer/standalone.rb | 2 | ||||
-rw-r--r-- | lib/bundler/ruby_dsl.rb | 2 | ||||
-rw-r--r-- | lib/bundler/ruby_version.rb | 111 | ||||
-rw-r--r-- | spec/bundler/ruby_version_spec.rb | 376 | ||||
-rw-r--r-- | spec/resolver/basic_spec.rb | 2 |
8 files changed, 352 insertions, 161 deletions
diff --git a/lib/bundler.rb b/lib/bundler.rb index a03452b677..146d343bd9 100644 --- a/lib/bundler.rb +++ b/lib/bundler.rb @@ -48,9 +48,7 @@ module Bundler autoload :StubSpecification, "bundler/stub_specification" autoload :Source, "bundler/source" autoload :SourceList, "bundler/source_list" - autoload :SystemRubyVersion, "bundler/ruby_version" autoload :RubyGemsGemInstaller, "bundler/rubygems_gem_installer" - autoload :RubyVersionRequirement, "bundler/ruby_version" autoload :UI, "bundler/ui" class << self @@ -364,10 +362,6 @@ module Bundler @git_present = Bundler.which("git") || Bundler.which("git.exe") end - def ruby_version - @ruby_version ||= SystemRubyVersion.new - end - def reset! @definition = nil end diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index deb6af5cbb..98c6f66e72 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -40,7 +40,7 @@ module Bundler # @param sources [Bundler::SourceList] # @param unlock [Hash, Boolean, nil] Gems that have been requested # to be updated or true if all gems should be updated - # @param ruby_version [Bundler::RubyVersionRequirement, nil] Requested Ruby Version + # @param ruby_version [Bundler::RubyVersion, nil] Requested Ruby Version # @param optional_groups [Array(String)] A list of optional groups def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = []) @unlocking = unlock == true || !unlock.empty? @@ -280,15 +280,15 @@ module Bundler def locked_ruby_version if @unlock[:ruby] if ruby_version && !@locked_ruby_version - return Bundler.ruby_version + return Bundler::RubyVersion.system elsif ruby_version && @locked_ruby_version - return Bundler.ruby_version + return Bundler::RubyVersion.system elsif !ruby_version && @locked_ruby_version return nil end else if ruby_version && !@locked_ruby_version - return Bundler.ruby_version + return Bundler::RubyVersion.system elsif ruby_version && @locked_ruby_version return @locked_ruby_version elsif !ruby_version && @locked_ruby_version @@ -404,7 +404,7 @@ module Bundler def validate_ruby! return unless ruby_version - if diff = ruby_version.diff(Bundler.ruby_version) + if diff = ruby_version.diff(Bundler::RubyVersion.system) problem, expected, actual = diff msg = case problem @@ -413,7 +413,7 @@ module Bundler when :version "Your Ruby version is #{actual}, but your Gemfile specified #{expected}" when :engine_version - "Your #{Bundler.ruby_version.engine} version is #{actual}, but your Gemfile specified #{ruby_version.engine} #{expected}" + "Your #{Bundler::RubyVersion.system.engine} version is #{actual}, but your Gemfile specified #{ruby_version.engine} #{expected}" when :patchlevel if !expected.is_a?(String) "The Ruby patchlevel in your Gemfile must be a string" diff --git a/lib/bundler/fetcher.rb b/lib/bundler/fetcher.rb index af190bae21..c8c21a92ff 100644 --- a/lib/bundler/fetcher.rb +++ b/lib/bundler/fetcher.rb @@ -151,7 +151,7 @@ module Bundler def user_agent @user_agent ||= begin - ruby = Bundler.ruby_version + ruby = Bundler::RubyVersion.system agent = "bundler/#{Bundler::VERSION}" agent << " rubygems/#{Gem::VERSION}" diff --git a/lib/bundler/installer/standalone.rb b/lib/bundler/installer/standalone.rb index 35ad98891e..40100b9540 100644 --- a/lib/bundler/installer/standalone.rb +++ b/lib/bundler/installer/standalone.rb @@ -33,7 +33,7 @@ module Bundler end def version_dir - "#{Bundler.ruby_version.engine}/#{RbConfig::CONFIG["ruby_version"]}" + "#{Bundler::RubyVersion.system.engine}/#{RbConfig::CONFIG["ruby_version"]}" end def bundler_path diff --git a/lib/bundler/ruby_dsl.rb b/lib/bundler/ruby_dsl.rb index 745fb19185..46587e98cf 100644 --- a/lib/bundler/ruby_dsl.rb +++ b/lib/bundler/ruby_dsl.rb @@ -5,7 +5,7 @@ module Bundler raise GemfileError, "Please define :engine" if options[:engine_version] && options[:engine].nil? raise GemfileEvalError, "ruby_version must match the :engine_version for MRI" if options[:engine] == "ruby" && options[:engine_version] && ruby_version != options[:engine_version] - @ruby_version = RubyVersionRequirement.new(ruby_version, options[:patchlevel], options[:engine], options[:engine_version]) + @ruby_version = RubyVersion.new(ruby_version, options[:patchlevel], options[:engine], options[:engine_version]) end end end diff --git a/lib/bundler/ruby_version.rb b/lib/bundler/ruby_version.rb index a456ebca46..71ed828f71 100644 --- a/lib/bundler/ruby_version.rb +++ b/lib/bundler/ruby_version.rb @@ -16,9 +16,8 @@ module Bundler # specified must match the version. @version = version - @engine = engine || "ruby" - # keep track of the engine specified by the user @input_engine = engine + @engine = engine || "ruby" @engine_version = engine_version || version @patchlevel = patchlevel end @@ -49,59 +48,6 @@ module Bundler def gem_version Gem::Version.new(version) end - end - - # A subclass of RubyVersion that implements version, - # engine and engine_version based upon the current - # information in the system. It can be used anywhere - # a RubyVersion object is expected, and can be - # compared with a RubyVersion object. - class SystemRubyVersion < RubyVersion - def initialize(*) - # override the default initialize, because - # we will implement version, engine and - # engine_version dynamically - end - - def version - RUBY_VERSION.dup - end - - def gem_version - @gem_version ||= Gem::Version.new(version) - end - - def engine - if defined?(RUBY_ENGINE) - RUBY_ENGINE.dup - else - # not defined in ruby 1.8.7 - "ruby" - end - end - - def engine_version - case engine - when "ruby" - RUBY_VERSION.dup - when "rbx" - Rubinius::VERSION.dup - when "jruby" - JRUBY_VERSION.dup - else - raise BundlerError, "RUBY_ENGINE value #{RUBY_ENGINE} is not recognized" - end - end - - def patchlevel - RUBY_PATCHLEVEL.to_s - end - end - - class RubyVersionRequirement - def initialize(version, patchlevel, engine, engine_version) - @ruby_version = RubyVersion.new version, patchlevel, engine, engine_version - end # Returns a tuple of these things: # [diff, this, other] @@ -110,50 +56,35 @@ module Bundler # 2. ruby_version # 3. engine_version def diff(other) - if engine != other.engine && input_engine + if engine != other.engine && @input_engine [:engine, engine, other.engine] elsif !version || !matches?(version, other.version) [:version, version, other.version] - elsif input_engine && !matches?(engine_version, other.engine_version) + elsif @input_engine && !matches?(engine_version, other.engine_version) [:engine_version, engine_version, other.engine_version] elsif patchlevel && (!patchlevel.is_a?(String) || !other.patchlevel.is_a?(String) || !matches?(patchlevel, other.patchlevel)) [:patchlevel, patchlevel, other.patchlevel] end end - def gem_version - @ruby_version.gem_version - end - - def ==(other) - version == other.version && - engine == other.engine && - engine_version == other.engine_version && - patchlevel == other.patchlevel - end - - def input_engine - @ruby_version.instance_variable_get(:@input_engine) - end - - def engine - @ruby_version.engine - end - - def patchlevel - @ruby_version.patchlevel - end - - def engine_version - @ruby_version.engine_version - end - - def version - @ruby_version.version - end - - def to_s - @ruby_version.to_s + def self.system + ruby_engine = if defined?(RUBY_ENGINE) && !RUBY_ENGINE.nil? + RUBY_ENGINE.dup + else + # not defined in ruby 1.8.7 + "ruby" + end + ruby_engine_version = case ruby_engine + when "ruby" + RUBY_VERSION.dup + when "rbx" + Rubinius::VERSION.dup + when "jruby" + JRUBY_VERSION.dup + else + raise BundlerError, "RUBY_ENGINE value #{RUBY_ENGINE} is not recognized" + end + @ruby_version ||= RubyVersion.new(RUBY_VERSION.dup, RUBY_PATCHLEVEL.to_s, ruby_engine, ruby_engine_version) end private diff --git a/spec/bundler/ruby_version_spec.rb b/spec/bundler/ruby_version_spec.rb index 2fb7956047..d7ab0105fd 100644 --- a/spec/bundler/ruby_version_spec.rb +++ b/spec/bundler/ruby_version_spec.rb @@ -1,80 +1,346 @@ require "spec_helper" require "bundler/ruby_version" -describe Bundler::RubyVersion do - def requirement(version, patchlevel = nil, engine = nil, engine_version = nil) - Bundler::RubyVersionRequirement.new( - version, patchlevel, engine, engine_version) - end +describe "Bundler::RubyVersion and its subclasses" do + let(:version) { "2.0.0" } + let(:patchlevel) { "645" } + let(:engine) { "jruby" } + let(:engine_version) { "2.0.1" } - def version(version, patchlevel = nil, engine = nil, engine_version = nil) - Bundler::RubyVersion.new(version, patchlevel, engine, engine_version) - end + describe Bundler::RubyVersion do + subject { Bundler::RubyVersion.new(version, patchlevel, engine, engine_version) } - it "matches simple version requirements" do - expect(requirement("2.0.0").diff(version("2.0.0"))).to be_nil - end + let(:ruby_version) { subject } + let(:other_version) { version } + let(:other_patchlevel) { patchlevel } + let(:other_engine) { engine } + let(:other_engine_version) { engine_version } + let(:other_ruby_version) { Bundler::RubyVersion.new(other_version, other_patchlevel, other_engine, other_engine_version) } - it "matches simple patchlevel requirements" do - req = requirement("2.0.0", "645") - ver = version("2.0.0", "645") + describe "#initialize" do + context "no engine is passed" do + let(:engine) { nil } - expect(req.diff(ver)).to be_nil - end + it "should set ruby as the engine" do + expect(subject.engine).to eq("ruby") + end + end - it "matches engine" do - req = requirement("2.0.0", "645", "ruby") - ver = version("2.0.0", "645", "ruby") + context "no engine_version is passed" do + let(:engine_version) { nil } - expect(req.diff(ver)).to be_nil - end + it "should set engine version as the passed version" do + expect(subject.engine_version).to eq("2.0.0") + end + end + end + describe "#to_s" do + it "should return info string with the ruby version, patchlevel, engine, and engine version" do + expect(subject.to_s).to eq("ruby 2.0.0p645 (jruby 2.0.1)") + end - it "matches simple engine version requirements" do - req = requirement("2.0.0", "645", "ruby", "2.0.1") - ver = version("2.0.0", "645", "ruby", "2.0.1") + context "no patchlevel" do + let(:patchlevel) { nil } - expect(req.diff(ver)).to be_nil - end + it "should return info string with the version, engine, and engine version" do + expect(subject.to_s).to eq("ruby 2.0.0 (jruby 2.0.1)") + end + end - it "detects engine discrepancies first" do - req = requirement("2.0.0", "645", "ruby", "2.0.1") - ver = requirement("2.0.1", "643", "rbx", "2.0.0") + context "engine is ruby" do + let(:engine) { "ruby" } - expect(req.diff(ver)).to eq([:engine, "ruby", "rbx"]) - end + it "should return info string with the ruby version and patchlevel" do + expect(subject.to_s).to eq("ruby 2.0.0p645") + end + end + end - it "detects version discrepancies second" do - req = requirement("2.0.0", "645", "ruby", "2.0.1") - ver = requirement("2.0.1", "643", "ruby", "2.0.0") + describe "#==" do + shared_examples_for "two ruby versions are not equal" do + it "should return false" do + expect(subject).to_not eq(other_ruby_version) + end + end - expect(req.diff(ver)).to eq([:version, "2.0.0", "2.0.1"]) - end + context "the versions, pathlevels, engines, and engine_versions match" do + it "should return true" do + expect(subject).to eq(other_ruby_version) + end + end - it "detects engine version discrepancies third" do - req = requirement("2.0.0", "645", "ruby", "2.0.1") - ver = requirement("2.0.0", "643", "ruby", "2.0.0") + context "the versions do not match" do + let(:other_version) { "1.21.6" } - expect(req.diff(ver)).to eq([:engine_version, "2.0.1", "2.0.0"]) - end + it_behaves_like "two ruby versions are not equal" + end - it "detects patchlevel discrepancies last" do - req = requirement("2.0.0", "645", "ruby", "2.0.1") - ver = requirement("2.0.0", "643", "ruby", "2.0.1") + context "the patchlevels do not match" do + let(:other_patchlevel) { "21" } - expect(req.diff(ver)).to eq([:patchlevel, "645", "643"]) - end + it_behaves_like "two ruby versions are not equal" + end - it "successfully matches gem requirements" do - req = requirement(">= 2.0.0", "< 643", "ruby", "~> 2.0.1") - ver = version("2.0.0", "642", "ruby", "2.0.5") + context "the engines do not match" do + let(:other_engine) { "ruby" } - expect(req.diff(ver)).to be_nil - end + it_behaves_like "two ruby versions are not equal" + end + + context "the engine versions do not match" do + let(:other_engine_version) { "1.11.2" } + + it_behaves_like "two ruby versions are not equal" + end + end + + describe "#host" do + before do + allow(RbConfig::CONFIG).to receive(:[]).with("host_cpu").and_return("x86_64") + allow(RbConfig::CONFIG).to receive(:[]).with("host_vendor").and_return("apple") + allow(RbConfig::CONFIG).to receive(:[]).with("host_os").and_return("darwin14.5.0") + end + + it "should return an info string with the host cpu, vendor, and os" do + expect(subject.host).to eq("x86_64-apple-darwin14.5.0") + end + + it "memoizes the info string with the host cpu, vendor, and os" do + expect(RbConfig::CONFIG).to receive(:[]).with("host_cpu").once.and_call_original + expect(RbConfig::CONFIG).to receive(:[]).with("host_vendor").once.and_call_original + expect(RbConfig::CONFIG).to receive(:[]).with("host_os").once.and_call_original + 2.times { ruby_version.host } + end + end + + describe "#gem_version" do + let(:gem_version_obj) { Gem::Version.new(version) } + + it "should return a Gem::Version instance with the correct version" do + expect(ruby_version.gem_version).to eq(gem_version_obj) + expect(ruby_version.gem_version.version).to eq("2.0.0") + end + end + + describe "#diff" do + let(:engine) { "ruby" } + + shared_examples_for "there is a difference in the engines" do + it "should return a tuple with :engine and the two different engines" do + expect(ruby_version.diff(other_ruby_version)).to eq([:engine, engine, other_engine]) + end + end + + shared_examples_for "there is a difference in the versions" do + it "should return a tuple with :version and the two different versions" do + expect(ruby_version.diff(other_ruby_version)).to eq([:version, version, other_version]) + end + end + + shared_examples_for "there is a difference in the engine versions" do + it "should return a tuple with :engine_version and the two different engine versions" do + expect(ruby_version.diff(other_ruby_version)).to eq([:engine_version, engine_version, other_engine_version]) + end + end + + shared_examples_for "there is a difference in the patchlevels" do + it "should return a tuple with :patchlevel and the two different patchlevels" do + expect(ruby_version.diff(other_ruby_version)).to eq([:patchlevel, patchlevel, other_patchlevel]) + end + end + + shared_examples_for "there are no differences" do + it "should return nil" do + expect(ruby_version.diff(other_ruby_version)).to be_nil + end + end + + context "all things match exactly" do + it_behaves_like "there are no differences" + end + + context "detects engine discrepancies first" do + let(:other_version) { "2.0.1" } + let(:other_patchlevel) { "643" } + let(:other_engine) { "rbx" } + let(:other_engine_version) { "2.0.0" } + + it_behaves_like "there is a difference in the engines" + end + + context "detects version discrepancies second" do + let(:other_version) { "2.0.1" } + let(:other_patchlevel) { "643" } + let(:other_engine_version) { "2.0.0" } + + it_behaves_like "there is a difference in the versions" + end + + context "detects engine version discrepancies third" do + let(:other_patchlevel) { "643" } + let(:other_engine_version) { "2.0.0" } + + it_behaves_like "there is a difference in the engine versions" + end + + context "detects patchlevel discrepancies last" do + let(:other_patchlevel) { "643" } + + it_behaves_like "there is a difference in the patchlevels" + end + + context "successfully matches gem requirements" do + let(:version) { ">= 2.0.0" } + let(:patchlevel) { "< 643" } + let(:engine) { "ruby" } + let(:engine_version) { "~> 2.0.1" } + let(:other_version) { "2.0.0" } + let(:other_patchlevel) { "642" } + let(:other_engine) { "ruby" } + let(:other_engine_version) { "2.0.5" } + + it_behaves_like "there are no differences" + end + + context "successfully detects bad gem requirements with versions" do + let(:version) { "~> 2.0.0" } + let(:patchlevel) { "< 643" } + let(:engine) { "ruby" } + let(:engine_version) { "~> 2.0.1" } + let(:other_version) { "2.1.0" } + let(:other_patchlevel) { "642" } + let(:other_engine) { "ruby" } + let(:other_engine_version) { "2.0.5" } + + it_behaves_like "there is a difference in the versions" + end + + context "successfully detects bad gem requirements with patchlevels" do + let(:version) { ">= 2.0.0" } + let(:patchlevel) { "< 643" } + let(:engine) { "ruby" } + let(:engine_version) { "~> 2.0.1" } + let(:other_version) { "2.0.0" } + let(:other_patchlevel) { "645" } + let(:other_engine) { "ruby" } + let(:other_engine_version) { "2.0.5" } + + it_behaves_like "there is a difference in the patchlevels" + end + + context "successfully detects bad gem requirements with engine versions" do + let(:version) { ">= 2.0.0" } + let(:patchlevel) { "< 643" } + let(:engine) { "ruby" } + let(:engine_version) { "~> 2.0.1" } + let(:other_version) { "2.0.0" } + let(:other_patchlevel) { "642" } + let(:other_engine) { "ruby" } + let(:other_engine_version) { "2.1.0" } + + it_behaves_like "there is a difference in the engine versions" + end + end + + describe "#system" do + subject { Bundler::RubyVersion.system } + + let(:bundler_system_ruby_version) { subject } + + before do + Bundler::RubyVersion.instance_variable_set("@ruby_version", nil) + end + + it "should return an instance of Bundler::RubyVersion" do + expect(subject).to be_kind_of(Bundler::RubyVersion) + end + + it "memoizes the instance of Bundler::RubyVersion" do + expect(Bundler::RubyVersion).to receive(:new).once.and_call_original + 2.times { subject } + end + + describe "#version" do + it "should return a copy of the value of RUBY_VERSION" do + expect(subject.version).to eq(RUBY_VERSION) + expect(subject.version).to_not be(RUBY_VERSION) + end + end + + describe "#engine" do + context "RUBY_ENGINE is defined" do + before { stub_const("RUBY_ENGINE", "jruby") } + before { stub_const("JRUBY_VERSION", "2.1.1") } + + it "should return a copy of the value of RUBY_ENGINE" do + expect(subject.engine).to eq("jruby") + expect(subject.engine).to_not be(RUBY_ENGINE) + end + end + + context "RUBY_ENGINE is not defined" do + before { stub_const("RUBY_ENGINE", nil) } + + it "should return the string 'ruby'" do + expect(subject.engine).to eq("ruby") + end + end + end + + describe "#engine_version" do + context "engine is ruby" do + before do + stub_const("RUBY_VERSION", "2.2.4") + allow(Bundler).to receive(:ruby_engine).and_return("ruby") + end + + it "should return a copy of the value of RUBY_VERSION" do + expect(bundler_system_ruby_version.engine_version).to eq("2.2.4") + expect(bundler_system_ruby_version.engine_version).to_not be(RUBY_VERSION) + end + end + + context "engine is rbx" do + before do + stub_const("RUBY_ENGINE", "rbx") + stub_const("Rubinius::VERSION", "2.0.0") + end + + it "should return a copy of the value of Rubinius::VERSION" do + expect(bundler_system_ruby_version.engine_version).to eq("2.0.0") + expect(bundler_system_ruby_version.engine_version).to_not be(Rubinius::VERSION) + end + end + + context "engine is jruby" do + before do + stub_const("RUBY_ENGINE", "jruby") + stub_const("JRUBY_VERSION", "2.1.1") + end + + it "should return a copy of the value of JRUBY_VERSION" do + expect(subject.engine_version).to eq("2.1.1") + expect(bundler_system_ruby_version.engine_version).to_not be(JRUBY_VERSION) + end + end + + context "engine is some other ruby engine" do + before do + stub_const("RUBY_ENGINE", "not_supported_ruby_engine") + allow(Bundler).to receive(:ruby_engine).and_return("not_supported_ruby_engine") + end - it "successfully detects bad gem requirements" do - req = requirement(">= 2.0.0", "< 643", "ruby", "~> 2.0.1") - ver = version("2.0.0", "642", "ruby", "2.1.0") + it "should raise a BundlerError with a 'not recognized' message" do + expect { bundler_system_ruby_version.engine_version }.to raise_error(Bundler::BundlerError, "RUBY_ENGINE value not_supported_ruby_engine is not recognized") + end + end + end - expect(req.diff(ver)).to eq([:engine_version, "~> 2.0.1", "2.1.0"]) + describe "#patchlevel" do + it "should return a string with the value of RUBY_PATCHLEVEL" do + expect(subject.patchlevel).to eq(RUBY_PATCHLEVEL.to_s) + end + end + end end end diff --git a/spec/resolver/basic_spec.rb b/spec/resolver/basic_spec.rb index 0bf11bff34..0cfaf925da 100644 --- a/spec/resolver/basic_spec.rb +++ b/spec/resolver/basic_spec.rb @@ -99,7 +99,7 @@ describe "Resolving" do deps << Bundler::DepProxy.new(d, "ruby") end - got = Bundler::Resolver.resolve(deps, @index, {}, [], Bundler::RubyVersionRequirement.new("1.8.7", nil, nil, nil)) + got = Bundler::Resolver.resolve(deps, @index, {}, [], Bundler::RubyVersion.new("1.8.7", nil, nil, nil)) got = got.map(&:full_name).sort expect(got).to eq(%w(foo-1.0.0 bar-1.0.0).sort) end |