diff options
Diffstat (limited to 'spec/bundler/bundler/gem_version_promoter_spec.rb')
-rw-r--r-- | spec/bundler/bundler/gem_version_promoter_spec.rb | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/spec/bundler/bundler/gem_version_promoter_spec.rb b/spec/bundler/bundler/gem_version_promoter_spec.rb new file mode 100644 index 0000000000..c7620e2620 --- /dev/null +++ b/spec/bundler/bundler/gem_version_promoter_spec.rb @@ -0,0 +1,179 @@ +# frozen_string_literal: true +require "spec_helper" + +RSpec.describe Bundler::GemVersionPromoter do + context "conservative resolver" do + def versions(result) + result.flatten.map(&:version).map(&:to_s) + end + + def make_instance(*args) + @gvp = Bundler::GemVersionPromoter.new(*args).tap do |gvp| + gvp.class.class_eval { public :filter_dep_specs, :sort_dep_specs } + end + end + + def unlocking(options) + make_instance(Bundler::SpecSet.new([]), ["foo"]).tap do |p| + p.level = options[:level] if options[:level] + p.strict = options[:strict] if options[:strict] + end + end + + def keep_locked(options) + make_instance(Bundler::SpecSet.new([]), ["bar"]).tap do |p| + p.level = options[:level] if options[:level] + p.strict = options[:strict] if options[:strict] + end + end + + def build_spec_group(name, version) + Bundler::Resolver::SpecGroup.new(build_spec(name, version)) + end + + # Rightmost (highest array index) in result is most preferred. + # Leftmost (lowest array index) in result is least preferred. + # `build_spec_group` has all version of gem in index. + # `build_spec` is the version currently in the .lock file. + # + # In default (not strict) mode, all versions in the index will + # be returned, allowing Bundler the best chance to resolve all + # dependencies, but sometimes resulting in upgrades that some + # would not consider conservative. + context "filter specs (strict) level patch" do + it "when keeping build_spec, keep current, next release" do + keep_locked(:level => :patch) + res = @gvp.filter_dep_specs( + build_spec_group("foo", %w(1.7.8 1.7.9 1.8.0)), + build_spec("foo", "1.7.8").first + ) + expect(versions(res)).to eq %w(1.7.9 1.7.8) + end + + it "when unlocking prefer next release first" do + unlocking(:level => :patch) + res = @gvp.filter_dep_specs( + build_spec_group("foo", %w(1.7.8 1.7.9 1.8.0)), + build_spec("foo", "1.7.8").first + ) + expect(versions(res)).to eq %w(1.7.8 1.7.9) + end + + it "when unlocking keep current when already at latest release" do + unlocking(:level => :patch) + res = @gvp.filter_dep_specs( + build_spec_group("foo", %w(1.7.9 1.8.0 2.0.0)), + build_spec("foo", "1.7.9").first + ) + expect(versions(res)).to eq %w(1.7.9) + end + end + + context "filter specs (strict) level minor" do + it "when unlocking favor next releases, remove minor and major increases" do + unlocking(:level => :minor) + res = @gvp.filter_dep_specs( + build_spec_group("foo", %w(0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.0 2.0.1)), + build_spec("foo", "0.2.0").first + ) + expect(versions(res)).to eq %w(0.2.0 0.3.0 0.3.1 0.9.0) + end + + it "when keep locked, keep current, then favor next release, remove minor and major increases" do + keep_locked(:level => :minor) + res = @gvp.filter_dep_specs( + build_spec_group("foo", %w(0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.0 2.0.1)), + build_spec("foo", "0.2.0").first + ) + expect(versions(res)).to eq %w(0.3.0 0.3.1 0.9.0 0.2.0) + end + end + + context "sort specs (not strict) level patch" do + it "when not unlocking, same order but make sure build_spec version is most preferred to stay put" do + keep_locked(:level => :patch) + res = @gvp.sort_dep_specs( + build_spec_group("foo", %w(1.5.4 1.6.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 2.0.0 2.0.1)), + build_spec("foo", "1.7.7").first + ) + expect(versions(res)).to eq %w(1.5.4 1.6.5 1.7.6 2.0.0 2.0.1 1.8.0 1.8.1 1.7.8 1.7.9 1.7.7) + end + + it "when unlocking favor next release, then current over minor increase" do + unlocking(:level => :patch) + res = @gvp.sort_dep_specs( + build_spec_group("foo", %w(1.7.7 1.7.8 1.7.9 1.8.0)), + build_spec("foo", "1.7.8").first + ) + expect(versions(res)).to eq %w(1.7.7 1.8.0 1.7.8 1.7.9) + end + + it "when unlocking do proper integer comparison, not string" do + unlocking(:level => :patch) + res = @gvp.sort_dep_specs( + build_spec_group("foo", %w(1.7.7 1.7.8 1.7.9 1.7.15 1.8.0)), + build_spec("foo", "1.7.8").first + ) + expect(versions(res)).to eq %w(1.7.7 1.8.0 1.7.8 1.7.9 1.7.15) + end + + it "leave current when unlocking but already at latest release" do + unlocking(:level => :patch) + res = @gvp.sort_dep_specs( + build_spec_group("foo", %w(1.7.9 1.8.0 2.0.0)), + build_spec("foo", "1.7.9").first + ) + expect(versions(res)).to eq %w(2.0.0 1.8.0 1.7.9) + end + end + + context "sort specs (not strict) level minor" do + it "when unlocking favor next release, then minor increase over current" do + unlocking(:level => :minor) + res = @gvp.sort_dep_specs( + build_spec_group("foo", %w(0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.0 2.0.1)), + build_spec("foo", "0.2.0").first + ) + expect(versions(res)).to eq %w(2.0.0 2.0.1 1.0.0 0.2.0 0.3.0 0.3.1 0.9.0) + end + end + + context "level error handling" do + subject { Bundler::GemVersionPromoter.new } + + it "should raise if not major, minor or patch is passed" do + expect { subject.level = :minjor }.to raise_error ArgumentError + end + + it "should raise if invalid classes passed" do + [123, nil].each do |value| + expect { subject.level = value }.to raise_error ArgumentError + end + end + + it "should accept major, minor patch symbols" do + [:major, :minor, :patch].each do |value| + subject.level = value + expect(subject.level).to eq value + end + end + + it "should accept major, minor patch strings" do + %w(major minor patch).each do |value| + subject.level = value + expect(subject.level).to eq value.to_sym + end + end + end + + context "debug output" do + it "should not kerblooie on its own debug output" do + gvp = unlocking(:level => :patch) + dep = Bundler::DepProxy.new(dep("foo", "1.2.0").first, "ruby") + result = gvp.send(:debug_format_result, dep, [build_spec_group("foo", "1.2.0"), + build_spec_group("foo", "1.3.0")]) + expect(result.class).to eq Array + end + end + end +end |