diff --git a/common/lib/dependabot/config/ignore_condition.rb b/common/lib/dependabot/config/ignore_condition.rb index fcae512822..190ebdaba1 100644 --- a/common/lib/dependabot/config/ignore_condition.rb +++ b/common/lib/dependabot/config/ignore_condition.rb @@ -57,54 +57,20 @@ def versions_by_type(dependency) version = correct_version_for(dependency) return [] unless version - semver = version.to_semver - transformed_update_types.flat_map do |t| case t when PATCH_VERSION_TYPE - ignore_patch(semver) + version.ignored_patch_versions when MINOR_VERSION_TYPE - ignore_minor(semver) + version.ignored_minor_versions when MAJOR_VERSION_TYPE - ignore_major(semver) + version.ignored_major_versions else [] end end.compact end - sig { params(version: String).returns(T::Array[String]) } - def ignore_patch(version) - parts = version.split(".") - version_parts = parts.fill("0", parts.length...2) - upper_parts = version_parts.first(1) + [version_parts[1].to_i + 1] - lower_bound = "> #{version}" - upper_bound = "< #{upper_parts.join('.')}" - - ["#{lower_bound}, #{upper_bound}"] - end - - sig { params(version: String).returns(T::Array[String]) } - def ignore_minor(version) - parts = version.split(".") - version_parts = parts.fill("0", parts.length...2) - lower_parts = version_parts.first(1) + [version_parts[1].to_i + 1] + ["a"] - upper_parts = version_parts.first(0) + [version_parts[0].to_i + 1] - lower_bound = ">= #{lower_parts.join('.')}" - upper_bound = "< #{upper_parts.join('.')}" - - ["#{lower_bound}, #{upper_bound}"] - end - - sig { params(version: String).returns(T::Array[String]) } - def ignore_major(version) - version_parts = version.split(".") - lower_parts = [version_parts[0].to_i + 1] + ["a"] - lower_bound = ">= #{lower_parts.join('.')}" - - [lower_bound] - end - sig { params(dependency: Dependency).returns(T.nilable(Version)) } def correct_version_for(dependency) version = dependency.version diff --git a/common/lib/dependabot/version.rb b/common/lib/dependabot/version.rb index 5b9debb59e..e7b6a2d2de 100644 --- a/common/lib/dependabot/version.rb +++ b/common/lib/dependabot/version.rb @@ -36,5 +36,37 @@ def self.correct?(version) def to_semver @original_version end + + sig { overridable.returns(T::Array[String]) } + def ignored_patch_versions + parts = to_semver.split(".") + version_parts = parts.fill("0", parts.length...2) + upper_parts = version_parts.first(1) + [version_parts[1].to_i + 1] + lower_bound = "> #{to_semver}" + upper_bound = "< #{upper_parts.join('.')}" + + ["#{lower_bound}, #{upper_bound}"] + end + + sig { overridable.returns(T::Array[String]) } + def ignored_minor_versions + parts = to_semver.split(".") + version_parts = parts.fill("0", parts.length...2) + lower_parts = version_parts.first(1) + [version_parts[1].to_i + 1] + ["a"] + upper_parts = version_parts.first(0) + [version_parts[0].to_i + 1] + lower_bound = ">= #{lower_parts.join('.')}" + upper_bound = "< #{upper_parts.join('.')}" + + ["#{lower_bound}, #{upper_bound}"] + end + + sig { overridable.returns(T::Array[String]) } + def ignored_major_versions + version_parts = to_semver.split(".") + lower_parts = [version_parts[0].to_i + 1] + ["a"] + lower_bound = ">= #{lower_parts.join('.')}" + + [lower_bound] + end end end diff --git a/common/spec/dependabot/version_spec.rb b/common/spec/dependabot/version_spec.rb new file mode 100644 index 0000000000..6a46334aed --- /dev/null +++ b/common/spec/dependabot/version_spec.rb @@ -0,0 +1,33 @@ +# typed: true +# frozen_string_literal: true + +require "spec_helper" +require "dependabot/version" + +RSpec.describe Dependabot::Version do + subject(:version) { described_class.new(version_string) } + + describe "#ignored_major_versions" do + subject(:ignored_versions) { version.ignored_major_versions } + + let(:version_string) { "1.2.3-alpha.1" } + + it { is_expected.to eq([">= 2.a"]) } + end + + describe "#ignored_minor_versions" do + subject(:ignored_versions) { version.ignored_minor_versions } + + let(:version_string) { "1.2.3-alpha.1" } + + it { is_expected.to eq([">= 1.3.a, < 2"]) } + end + + describe "#ignored_patch_versions" do + subject(:ignored_versions) { version.ignored_patch_versions } + + let(:version_string) { "1.2.3-alpha.1" } + + it { is_expected.to eq(["> #{version_string}, < 1.3"]) } + end +end diff --git a/maven/lib/dependabot/maven/new_version.rb b/maven/lib/dependabot/maven/new_version.rb deleted file mode 100644 index 592d7eedae..0000000000 --- a/maven/lib/dependabot/maven/new_version.rb +++ /dev/null @@ -1,71 +0,0 @@ -# typed: strict -# frozen_string_literal: true - -require "dependabot/maven/version_parser" -require "dependabot/version" -require "dependabot/utils" - -# See https://maven.apache.org/pom.html#Version_Order_Specification for details. - -module Dependabot - module Maven - class NewVersion - extend T::Sig - extend T::Helpers - - PRERELEASE_QUALIFIERS = T.let([ - Dependabot::Maven::VersionParser::ALPHA, - Dependabot::Maven::VersionParser::BETA, - Dependabot::Maven::VersionParser::MILESTONE, - Dependabot::Maven::VersionParser::RC, - Dependabot::Maven::VersionParser::SNAPSHOT - ].freeze, T::Array[Integer]) - - sig { returns(Dependabot::Maven::TokenBucket) } - attr_accessor :token_bucket - - sig { params(version: String).returns(T::Boolean) } - def self.correct?(version) - return false if version.empty? - - Dependabot::Maven::VersionParser.parse(version.to_s).to_a.any? - rescue Dependabot::BadRequirementError - Dependabot.logger.info("Malformed version string - #{version}") - false - end - - sig { params(version: String).void } - def initialize(version) - @version_string = T.let(version, String) - @token_bucket = T.let(Dependabot::Maven::VersionParser.parse(version), Dependabot::Maven::TokenBucket) - end - - sig { returns(String) } - def inspect - "#<#{self.class} #{version_string}>" - end - - sig { returns(String) } - def to_s - version_string - end - - sig { returns(T::Boolean) } - def prerelease? - token_bucket.to_a.flatten.any? do |token| - token.is_a?(Integer) && token.negative? - end - end - - sig { params(other: ::Dependabot::Maven::NewVersion).returns(Integer) } - def <=>(other) - T.must(token_bucket <=> other.token_bucket) - end - - private - - sig { returns(String) } - attr_reader :version_string - end - end -end diff --git a/maven/lib/dependabot/maven/update_checker/requirements_updater.rb b/maven/lib/dependabot/maven/update_checker/requirements_updater.rb index 8d3774edf6..25ee2267b6 100644 --- a/maven/lib/dependabot/maven/update_checker/requirements_updater.rb +++ b/maven/lib/dependabot/maven/update_checker/requirements_updater.rb @@ -50,12 +50,8 @@ def updated_requirements attr_reader :properties_to_update def update_requirement(req_string) - if req_string.include?(".+") - update_dynamic_requirement(req_string) - else - # Since range requirements are excluded this must be exact - update_exact_requirement(req_string) - end + # Since range requirements are excluded this must be exact + update_exact_requirement(req_string) end def update_exact_requirement(req_string) @@ -64,16 +60,6 @@ def update_exact_requirement(req_string) req_string.gsub(old_version.to_s, latest_version.to_s) end - # This is really only a Gradle thing, but Gradle relies on this - # RequirementsUpdater too - def update_dynamic_requirement(req_string) - precision = req_string.split(".").take_while { |s| s != "+" }.count - - version_parts = latest_version.segments.first(precision) - - version_parts.join(".") + ".+" - end - def version_class Maven::Version end diff --git a/maven/lib/dependabot/maven/version.rb b/maven/lib/dependabot/maven/version.rb index 0cd26fe8f8..92fbf8af49 100644 --- a/maven/lib/dependabot/maven/version.rb +++ b/maven/lib/dependabot/maven/version.rb @@ -1,192 +1,119 @@ -# typed: true +# typed: strict # frozen_string_literal: true +require "dependabot/maven/version_parser" require "dependabot/version" require "dependabot/utils" -# Java versions use dots and dashes when tokenising their versions. -# Gem::Version converts a "-" to ".pre.", so we override the `to_s` method. -# # See https://maven.apache.org/pom.html#Version_Order_Specification for details. module Dependabot module Maven class Version < Dependabot::Version - NULL_VALUES = %w(0 final ga).freeze - PREFIXED_TOKEN_HIERARCHY = { - "." => { qualifier: 1, number: 4 }, - "-" => { qualifier: 2, number: 3 }, - "+" => { qualifier: 3, number: 2 } - }.freeze - NAMED_QUALIFIERS_HIERARCHY = { - "a" => 1, "alpha" => 1, - "b" => 2, "beta" => 2, - "m" => 3, "milestone" => 3, - "rc" => 4, "cr" => 4, "pr" => 4, "pre" => 4, - "snapshot" => 5, "dev" => 5, - "ga" => 6, "" => 6, "final" => 6, - "sp" => 7 - }.freeze + extend T::Sig + extend T::Helpers + + PRERELEASE_QUALIFIERS = T.let([ + Dependabot::Maven::VersionParser::ALPHA, + Dependabot::Maven::VersionParser::BETA, + Dependabot::Maven::VersionParser::MILESTONE, + Dependabot::Maven::VersionParser::RC, + Dependabot::Maven::VersionParser::SNAPSHOT + ].freeze, T::Array[Integer]) + VERSION_PATTERN = "[0-9a-zA-Z]+" \ '(?>\.[0-9a-zA-Z]*)*' \ '([_\-\+][0-9A-Za-z_-]*(\.[0-9A-Za-z_-]*)*)?' - ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})?\s*\z/ + sig { returns(Dependabot::Maven::TokenBucket) } + attr_accessor :token_bucket + + sig { override.params(version: VersionParameter).returns(T::Boolean) } def self.correct?(version) - return false if version.nil? + return false if version.to_s.empty? - version.to_s.match?(ANCHORED_VERSION_PATTERN) + Dependabot::Maven::VersionParser.parse(version.to_s).to_a.any? + rescue ArgumentError + Dependabot.logger.info("Malformed version string #{version}") + false end + sig { override.params(version: VersionParameter).void } def initialize(version) - @version_string = version.to_s + raise BadRequirementError, "Malformed version string - string is nil" if version.nil? + + @version_string = T.let(version.to_s, String) + @token_bucket = T.let(Dependabot::Maven::VersionParser.parse(version_string), Dependabot::Maven::TokenBucket) super(version.to_s.tr("_", "-")) end + sig { returns(String) } def inspect - "#<#{self.class} #{@version_string}>" + "#<#{self.class} #{version_string}>" end + sig { returns(String) } def to_s - @version_string + version_string end + sig { returns(T::Boolean) } def prerelease? - tokens.any? do |token| - next true if token == "eap" - next false unless NAMED_QUALIFIERS_HIERARCHY[token] - - NAMED_QUALIFIERS_HIERARCHY[token] < 6 + token_bucket.to_a.flatten.any? do |token| + token.is_a?(Integer) && token.negative? end end + sig { params(other: VersionParameter).returns(Integer) } def <=>(other) - version = stringify_version(@version_string) - version = fill_tokens(version) - version = trim_version(version) - - other_version = stringify_version(other) - other_version = fill_tokens(other_version) - other_version = trim_version(other_version) - - version, other_version = convert_dates(version, other_version) - - prefixed_tokens = split_into_prefixed_tokens(version) - other_prefixed_tokens = split_into_prefixed_tokens(other_version) - - prefixed_tokens, other_prefixed_tokens = - pad_for_comparison(prefixed_tokens, other_prefixed_tokens) - - prefixed_tokens.count.times.each do |index| - comp = compare_prefixed_token( - prefix: prefixed_tokens[index][0], - token: prefixed_tokens[index][1..-1] || "", - other_prefix: other_prefixed_tokens[index][0], - other_token: other_prefixed_tokens[index][1..-1] || "" - ) - return comp unless comp.zero? - end - - 0 + other = Dependabot::Maven::Version.new(other.to_s) unless other.is_a? Dependabot::Maven::Version + T.must(token_bucket <=> T.cast(other, Dependabot::Maven::Version).token_bucket) end - private - - def tokens - @tokens ||= - begin - version = @version_string.to_s.downcase - version = fill_tokens(version) - version = trim_version(version) - split_into_prefixed_tokens(version).map { |t| t[1..-1] } - end - end + sig { override.returns(T::Array[String]) } + def ignored_patch_versions + parts = token_bucket.tokens # e.g [1,2,3] if version is 1.2.3-alpha3 + return [] if parts.empty? # for non-semver versions - def stringify_version(version) - version = version.to_s.downcase + version_parts = parts.fill("0", parts.length...2) + # the a0 is so we can get the next earliest prerelease patch version + upper_parts = version_parts.first(1) + [version_parts[1].to_i + 1] + ["a0"] + lower_bound = "> #{to_semver}" + upper_bound = "< #{upper_parts.join('.')}" - # Not technically correct, but pragmatic - version.gsub(/^v(?=\d)/, "") + ["#{lower_bound}, #{upper_bound}"] end - def fill_tokens(version) - # Add separators when transitioning from digits to characters - version = version.gsub(/(\d)([A-Za-z])/, '\1-\2') - version = version.gsub(/([A-Za-z])(\d)/, '\1-\2') + sig { override.returns(T::Array[String]) } + def ignored_minor_versions + parts = token_bucket.tokens # e.g [1,2,3] if version is 1.2.3-alpha3 + return [] if parts.empty? # for non-semver versions - # Replace empty tokens with 0 - version = version.gsub(/([\.\-])([\.\-])/, '\10\2') - version = version.gsub(/^([\.\-])/, '0\1') - version.gsub(/([\.\-])$/, '\10') - end + version_parts = parts.fill("0", parts.length...2) + lower_parts = version_parts.first(1) + [version_parts[1].to_i + 1] + ["a0"] + upper_parts = version_parts.first(0) + [version_parts[0].to_i + 1] + ["a0"] + lower_bound = ">= #{lower_parts.join('.')}" + upper_bound = "< #{upper_parts.join('.')}" - def trim_version(version) - version.split("-").filter_map do |v| - parts = v.split(".") - parts = parts[0..-2] while NULL_VALUES.include?(parts&.last) - parts&.join(".") - end.reject(&:empty?).join("-") + ["#{lower_bound}, #{upper_bound}"] end - def convert_dates(version, other_version) - default = [version, other_version] - return default unless version.match?(/^\d{4}-?\d{2}-?\d{2}$/) - return default unless other_version.match?(/^\d{4}-?\d{2}-?\d{2}$/) + sig { override.returns(T::Array[String]) } + def ignored_major_versions + version_parts = token_bucket.tokens # e.g [1,2,3] if version is 1.2.3-alpha3 + return [] if version_parts.empty? # for non-semver versions - [version.delete("-"), other_version.delete("-")] - end + lower_parts = [version_parts[0].to_i + 1] + ["a0"] # earliest next major version prerelease + lower_bound = ">= #{lower_parts.join('.')}" - def split_into_prefixed_tokens(version) - ".#{version}".split(/(?=[\-\.\+])/) + [lower_bound] end - def pad_for_comparison(prefixed_tokens, other_prefixed_tokens) - prefixed_tokens = prefixed_tokens.dup - other_prefixed_tokens = other_prefixed_tokens.dup - - longest = [prefixed_tokens, other_prefixed_tokens].max_by(&:count) - shortest = [prefixed_tokens, other_prefixed_tokens].min_by(&:count) - - longest.count.times do |index| - next unless shortest[index].nil? - - shortest[index] = longest[index].start_with?(".") ? ".0" : "-" - end - - [prefixed_tokens, other_prefixed_tokens] - end - - def compare_prefixed_token(prefix:, token:, other_prefix:, other_token:) - token_type = token.match?(/^\d+$/) ? :number : :qualifier - other_token_type = other_token.match?(/^\d+$/) ? :number : :qualifier - - hierarchy = PREFIXED_TOKEN_HIERARCHY.fetch(prefix).fetch(token_type) - other_hierarchy = - PREFIXED_TOKEN_HIERARCHY.fetch(other_prefix).fetch(other_token_type) - - hierarchy_comparison = hierarchy <=> other_hierarchy - return hierarchy_comparison unless hierarchy_comparison.zero? - - compare_token(token: token, other_token: other_token) - end - - def compare_token(token:, other_token:) - if (token_hierarchy = NAMED_QUALIFIERS_HIERARCHY[token]) - return -1 unless NAMED_QUALIFIERS_HIERARCHY[other_token] - - return token_hierarchy <=> NAMED_QUALIFIERS_HIERARCHY[other_token] - end - - return 1 if NAMED_QUALIFIERS_HIERARCHY[other_token] - - if token.match?(/\A\d+\z/) && other_token.match?(/\A\d+\z/) - token = token.to_i - other_token = other_token.to_i - end + private - token <=> other_token - end + sig { returns(String) } + attr_reader :version_string end end end diff --git a/maven/spec/dependabot/maven/new_version_spec.rb b/maven/spec/dependabot/maven/new_version_spec.rb deleted file mode 100644 index ad0dddee55..0000000000 --- a/maven/spec/dependabot/maven/new_version_spec.rb +++ /dev/null @@ -1,503 +0,0 @@ -# typed: false -# frozen_string_literal: true - -require "spec_helper" -require "dependabot/maven/new_version" - -RSpec.describe Dependabot::Maven::NewVersion do - subject(:version) { described_class.new(version_string) } - - let(:version_string) { "1.0.0" } - - describe ".correct?" do - subject { described_class.correct?(version_string) } - - context "with a normal version" do - let(:version_string) { "1.0.0" } - - it { is_expected.to be(true) } - end - - context "with a normal version" do - let(:version_string) { "Finchley" } - - it { is_expected.to be(true) } - end - - context "with a dynamic version" do - let(:version_string) { "1.+" } - - it { is_expected.to be(true) } - end - - context "with an empty string" do - let(:version_string) { "" } - - it { is_expected.to be(false) } - end - - context "with a malformed version string" do - let(:version_string) { "-" } - - it { is_expected.to be(false) } - end - end - - describe "#to_s" do - subject { version.to_s } - - context "with no dashes" do - let(:version_string) { "1.0.0" } - - it { is_expected.to eq("1.0.0") } - end - - context "with a + separated build number" do - let(:version_string) { "1.0.0+100" } - - it { is_expected.to eq("1.0.0+100") } - end - - context "with a + separated alphanumeric build identifier" do - let(:version_string) { "1.0.0+build1" } - - it { is_expected.to eq("1.0.0+build1") } - end - - context "with a dot-specified prerelease" do - let(:version_string) { "1.0.0.pre1" } - - it { is_expected.to eq("1.0.0.pre1") } - end - - context "with a dash-specified prerelease" do - let(:version_string) { "1.0.0-pre1" } - - it { is_expected.to eq("1.0.0-pre1") } - end - - context "with an underscore-specified prerelease" do - let(:version_string) { "1.0.0_pre1" } - - it { is_expected.to eq("1.0.0_pre1") } - end - - context "with space as version" do - let(:version_string) { "" } - let(:err_msg) { "Malformed version string - string is empty" } - - it "raises an exception" do - expect { version }.to raise_error(Dependabot::BadRequirementError, err_msg) - end - end - - context "with a dot as version" do - let(:version_string) { "." } - let(:err_msg) { "Malformed version string - #{version_string}" } - - it "raises an exception" do - expect { version }.to raise_error(Dependabot::BadRequirementError, err_msg) - end - end - - context "with a hyphen as a version" do - let(:version_string) { "-" } - let(:err_msg) { "Malformed version string - #{version_string}" } - - it "raises an exception" do - expect { version }.to raise_error(Dependabot::BadRequirementError, err_msg) - end - end - end - - describe "#prerelease?" do - subject { version.prerelease? } - - context "with an alpha" do - let(:version_string) { "1.0.0-alpha" } - - it { is_expected.to be(true) } - end - - context "with a capitalised alpha" do - let(:version_string) { "1.0.0-Alpha" } - - it { is_expected.to be(true) } - end - - context "with an alpha separated with a ." do - let(:version_string) { "1.0.0.alpha" } - - it { is_expected.to be(true) } - end - - context "with an alpha with no separator" do - let(:version_string) { "1.0.0alpha" } - - it { is_expected.to be(true) } - end - - context "with an alligator" do - let(:version_string) { "1.0.0alligator" } - - it { is_expected.to be(false) } - end - - context "with a release" do - let(:version_string) { "1.0.0" } - - it { is_expected.to be(false) } - end - - context "with a post-release" do - let(:version_string) { "1.0.0.sp7" } - - it { is_expected.to be(false) } - end - end - - describe "#inspect" do - subject { described_class.new(version_string).inspect } - - let(:version_string) { "1.0.0+build1" } - - it { is_expected.to eq("#<#{described_class} #{version_string}>") } - end - - describe "#<=>" do - subject { version.send(:<=>, other_version) } - - context "with semantic versions" do - let(:versions) do - [ - ["1.2.3", "1.2.2", 1], - ["1.2.3", "1.2.3", 0], - ["1.2.3", "v1.2.3", 0] - ] - end - - it "returns the correct result" do - versions.each do |input| - version1, version2, result = input - version = described_class.new(version1) - other_version = described_class.new(version2) - expect(version <=> other_version).to eq(result) - expect(other_version <=> version).to eq(-result) - end - end - end - - context "with semantic versions that have a build number" do - let(:versions) do - [ - ["1.2.3", "1.2.3-1", -1], - ["1.2.3", "1.2.3-0-1", -1], - ["1.2.3", "1.2.3-0.1", -1], - ["1.2.3-2", "1.2.3-1", 1], - ["1.2.3-0.2", "1.2.3-1.1", -1] - ] - end - - it "returns the correct result" do - versions.each do |input| - version1, version2, result = input - version = described_class.new(version1) - other_version = described_class.new(version2) - expect(version <=> other_version).to eq(result) - expect(other_version <=> version).to eq(-result) - end - end - end - - context "with semantic versions that have a qualifier" do - let(:versions) do - [ - ["1.2.3", "1.2.3-a0", 1], # alpha has lower precedence - ["1.2.3", "1.2.3-a", -1] # 'a' without a following int is not alpha - - ] - end - - it "returns the correct result" do - versions.each do |input| - version1, version2, result = input - version = described_class.new(version1) - other_version = described_class.new(version2) - expect(version <=> other_version).to eq(result) - expect(other_version <=> version).to eq(-result) - end - end - end - - context "with versions that have trailing nulls" do - let(:versions) do - [ - ["1alpha-0", "1alpha", 0], - ["1alpha-0", "1alpha0", 0], - ["1alpha-0", "1alpha.0", 0], - ["1alpha-0", "1alpha.z", -1], - - ["1beta-0", "1beta", 0], - ["1beta-0", "1beta0", 0], - ["1beta-0", "1beta.0", 0], - ["1beta-0", "1beta.z", -1], - - ["1rc-0", "1rc0", 0], - ["1rc-0", "1rc", 0], - ["1rc-0", "1rc.0", 0], - ["1rc-0", "1rc.z", -1], - - ["1sp-0", "1sp0", 0], - ["1sp-0", "1sp", 0], - ["1sp-0", "1sp.0", 0], - ["1sp-0", "1sp.z", -1], - - ["1.ga", "1-ga", 0], - ["1.0", "1.ga", 0], - ["1.0.FINAL", "1", 0], - ["1.0", "1.release", 0], - - ["1.2.0", "1.2", 0], - ["1.2.3", "1.2.3-0", 0], - ["1.2.3-0", "1.2.3-0", 0], - ["1.2.3-0", "1.2.3-a0", 1], - ["1.2.3-0", "1.2.3-a", -1], - ["1.2.3-0", "1.2.3-1", -1], - ["1.2.3-0", "1.2.3-0-1", -1], - - ["1snapshot-0", "1snapshot0", 0], - ["1snapshot-0", "1snapshot", 0], - ["1snapshot-0", "1snapshot.0", 0], - ["1snapshot-0", "1snapshot.z", -1], - - ["1milestone-0", "1milestone", 0], - ["1milestone-0", "1milestone0", 0], - ["1milestone-0", "1milestone.0", 0], - ["1milestone-0", "1milestone.z", -1] - ] - end - - it "returns the correct result" do - versions.each do |input| - version1, version2, result = input - version = described_class.new(version1) - other_version = described_class.new(version2) - expect(version <=> other_version).to eq(result) - expect(other_version <=> version).to eq(-result) - end - end - end - - context "with equivalent shortened qualifiers" do - let(:versions) do - [ - ["1alpha-0", "1a0", 0], - ["1beta-0", "1b0", 0], - ["1milestone-0", "1m0", 0] - ] - end - - it "returns 0" do - versions.each do |input| - version1, version2, result = input - version = described_class.new(version1) - other_version = described_class.new(version2) - expect(version <=> other_version).to eq(result) - expect(other_version <=> version).to eq(-result) - end - end - end - - context "with dot, hyphen and digit / qualifier transitions as separators" do - let(:versions) do - [ - ["1alpha.z", "1alpha-z", 0], - ["1alpha1", "1alpha-1", 0], - ["1alpha-1", "1alpha.1", -1], - ["1beta.z", "1beta-z", 0], - ["1beta1", "1beta-1", 0], - ["1beta-1", "1beta.1", -1], - ["1-a", "1a", 0], - ["1-a", "1.a", 0], - ["1-b", "1-b-1", -1], - ["1-b-1", "1-b.1", -1], - ["1sp.z", "1sp-z", 0], - ["1sp1", "1sp-1", 0], - ["1sp-1", "1sp.1", -1], - ["1rc.z", "1rc-z", 0], - ["1rc1", "1rc-1", 0], - ["1rc-1", "1rc.1", -1], - ["1milestone.z", "1milestone-z", 0], - ["1milestone1", "1milestone-1", 0], - ["1milestone-1", "1milestone.1", -1], - ["1snapshot.z", "1snapshot-z", 0], - ["1snapshot1", "1snapshot-1", 0], - ["1snapshot-1", "1snapshot.1", -1] - ] - end - - it "returns 0" do - versions.each do |input| - version1, version2, result = input - version = described_class.new(version1) - other_version = described_class.new(version2) - expect(version <=> other_version).to eq(result) - expect(other_version <=> version).to eq(-result) - end - end - end - - context "with qualifiers with different precedence" do - let(:versions) do - [ - ["1alpha.1", "1beta.1", -1], - ["1beta.1", "1milestone.1", -1], - ["1milestone.1", "1rc.1", -1], - ["1rc.1", "1snapshot.1", -1], - ["1.sp", "1.ga", 1], - ["1.release", "1.ga", 0] - ] - end - - it "returns the correct value" do - versions.each do |input| - version1, version2, result = input - version = described_class.new(version1) - other_version = described_class.new(version2) - expect(version <=> other_version).to eq(result) - expect(other_version <=> version).to eq(-result) - end - end - end - - context "with equivalent qualifiers cr and rc" do - let(:version) { described_class.new("1.0rc-1") } - let(:other_version) { described_class.new("1.0-cr1") } - - it "returns 0" do - expect(version <=> other_version).to eq(0) - expect(other_version <=> version).to eq(0) - end - end - - context "when comparing alphanumerically" do - let(:versions) do - [ - ["1alpha-z", "1alpha1", -1], - ["1beta-z", "1beta1", -1], - ["1milestone-z", "1milestone1", -1], - ["1rc-z", "1rc1", -1], - ["1snapshot-z", "1snapshot1", -1], - ["1sp-z", "1sp1", -1], - ["181", "DEV", 1] - ] - end - - it "gives higher precedence to digits" do - versions.each do |input| - version1, version2, result = input - version = described_class.new(version1) - other_version = described_class.new(version2) - expect(version <=> other_version).to eq(result) - expect(other_version <=> version).to eq(-result) - end - end - end - - context "when comparing alphabetically" do - let(:versions) do - [ - ["1-a", "1-b", -1], - ["Finchley", "Edgware", 1], - ["1.something", "1.SOMETHING", 0] - ] - end - - it "returns the correct result" do - versions.each do |input| - version1, version2, result = input - version = described_class.new(version1) - other_version = described_class.new(version2) - expect(version <=> other_version).to eq(result) - expect(other_version <=> version).to eq(-result) - end - end - end - - context "when comparing numerically" do - let(:versions) do - [ - ["1-b.1", "1-b.2", -1], - ["9.0.0+102", "9.0.0+91", 1], - ["1-foo2", "1-foo10", -1] - - ] - end - - it "returns the correct result" do - versions.each do |input| - version1, version2, result = input - version = described_class.new(version1) - other_version = described_class.new(version2) - expect(version <=> other_version).to eq(result) - expect(other_version <=> version).to eq(-result) - end - end - end - - context "when comparing padded versions" do - let(:versions) do - [ - ["1snapshot.1", "1", -1], - ["1-snapshot", "1", -1], - ["1", "1sp0", -1], - ["1sp.1", "1-a", -1], - ["1", "1.1", -1], - ["1", "1-sp", -1], - ["1-ga-1", "1-1", -1] - ] - end - - it "returns the correct result" do - versions.each do |input| - version1, version2, result = input - version = described_class.new(version1) - other_version = described_class.new(version2) - expect(version <=> other_version).to eq(result) - expect(other_version <=> version).to eq(-result) - end - end - end - - context "when ordering versions" do - let(:versions) do - [ - described_class.new("NotAVersionSting"), - described_class.new("1.0-alpha"), - described_class.new("1.0a1-SNAPSHOT"), - described_class.new("1.0-alpha1"), - described_class.new("1.0beta1-SNAPSHOT"), - described_class.new("1.0-b2"), - described_class.new("1.0-beta3.SNAPSHOT"), - described_class.new("1.0-beta3"), - described_class.new("1.0-milestone1-SNAPSHOT"), - described_class.new("1.0-m2"), - described_class.new("1.0-rc1-SNAPSHOT"), - described_class.new("1.0-cr1"), - described_class.new("1.0-SNAPSHOT"), - described_class.new("1.0-RELEASE"), - described_class.new("1.0-sp"), - described_class.new("1.0-a"), - described_class.new("1.0-whatever"), - described_class.new("1.0.z"), - described_class.new("1.0.1"), - described_class.new("1.0.1.0.0.0.0.0.0.0.0.0.0.0.1") - ] - end - - it "sorts versions correctly" do - expect(versions.shuffle.sort).to eq(versions) - end - end - end -end diff --git a/maven/spec/dependabot/maven/requirement_spec.rb b/maven/spec/dependabot/maven/requirement_spec.rb index 064377ccb8..1d53a79979 100644 --- a/maven/spec/dependabot/maven/requirement_spec.rb +++ b/maven/spec/dependabot/maven/requirement_spec.rb @@ -16,7 +16,7 @@ context "with a pre-release version" do let(:requirement_string) { "1.3.alpha" } - it { is_expected.to be_satisfied_by(Gem::Version.new("1.3.a")) } + it { is_expected.to be_satisfied_by(Gem::Version.new("1.3.alpha")) } end context "with a version that wouldn't be a valid Gem::Version" do diff --git a/maven/spec/dependabot/maven/update_checker/requirements_updater_spec.rb b/maven/spec/dependabot/maven/update_checker/requirements_updater_spec.rb index 50de622276..e017876393 100644 --- a/maven/spec/dependabot/maven/update_checker/requirements_updater_spec.rb +++ b/maven/spec/dependabot/maven/update_checker/requirements_updater_spec.rb @@ -80,12 +80,6 @@ its([:requirement]) { is_expected.to eq("[23.6-jre]") } end - context "when a dynamic requirement was previously specified" do - let(:pom_req_string) { "22.+" } - - its([:requirement]) { is_expected.to eq("23.+") } - end - context "when there were multiple requirements" do let(:requirements) { [pom_req, other_pom_req] } diff --git a/maven/spec/dependabot/maven/version_spec.rb b/maven/spec/dependabot/maven/version_spec.rb index 934c90779e..821adec006 100644 --- a/maven/spec/dependabot/maven/version_spec.rb +++ b/maven/spec/dependabot/maven/version_spec.rb @@ -29,6 +29,24 @@ it { is_expected.to be(true) } end + + context "with a nil version" do + let(:version_string) { nil } + + it { is_expected.to be(false) } + end + + context "with an empty version" do + let(:version_string) { "" } + + it { is_expected.to be(false) } + end + + context "with a malformed version string" do + let(:version_string) { "-" } + + it { is_expected.to be(false) } + end end describe "#to_s" do @@ -69,6 +87,33 @@ it { is_expected.to eq("1.0.0_pre1") } end + + context "with a nil version" do + let(:version_string) { nil } + let(:err_msg) { "Malformed version string - string is nil" } + + it "raises an exception" do + expect { version }.to raise_error(Dependabot::BadRequirementError, err_msg) + end + end + + context "with an empty version" do + let(:version_string) { "" } + let(:err_msg) { "Malformed version string - string is empty" } + + it "raises an exception" do + expect { version }.to raise_error(Dependabot::BadRequirementError, err_msg) + end + end + + context "with a malformed version string" do + let(:version_string) { "-" } + let(:err_msg) { "Malformed version string - #{version_string}" } + + it "raises an exception" do + expect { version }.to raise_error(Dependabot::BadRequirementError, err_msg) + end + end end describe "#prerelease?" do @@ -115,24 +160,22 @@ it { is_expected.to be(false) } end + end - context "with a 'pr' pre-release separated with a ." do - let(:version_string) { "2.10.0.pr3" } + describe "#inspect" do + subject { described_class.new(version_string).inspect } - it { is_expected.to be(true) } - end + let(:version_string) { "1.0.0+build1" } - context "with a 'pre' pre-release separated with a -" do - let(:version_string) { "2.10.0-pre0" } + it { is_expected.to eq("#<#{described_class} #{version_string}>") } + end - it { is_expected.to be(true) } - end + describe "#to_semver" do + subject { described_class.new(version_string).to_semver } - context "with a dev token" do - let(:version_string) { "1.2.1-dev-65" } + let(:version_string) { "1.0.0+build1" } - it { is_expected.to be(true) } - end + it { is_expected.to eq version_string } end describe "#<=>" do @@ -158,229 +201,362 @@ end end - context "when comparing to a Maven::Version" do - context "when lower" do - let(:other_version) { described_class.new("0.9.0") } - - it { is_expected.to eq(1) } + context "with semantic versions" do + let(:versions) do + [ + ["1.2.3", "1.2.2", 1], + ["1.2.3", "1.2.3", 0], + ["1.2.3", "v1.2.3", 0] + ] end - context "when equal" do - let(:other_version) { described_class.new("1.0.0") } - - it { is_expected.to eq(0) } - - context "when prefixed with a v" do - let(:other_version) { described_class.new("v1.0.0") } - - it { is_expected.to eq(0) } - end - - context "when using different date formats" do - let(:version_string) { "20181003" } - let(:other_version) { described_class.new("v2018-10-03") } - - it { is_expected.to eq(0) } + it "returns the correct result" do + versions.each do |input| + version1, version2, result = input + version = described_class.new(version1) + other_version = described_class.new(version2) + expect(version <=> other_version).to eq(result) + expect(other_version <=> version).to eq(-result) end end + end - context "when greater" do - let(:other_version) { described_class.new("1.1.0") } - - it { is_expected.to eq(-1) } - end - - context "when the version is a post-release" do - let(:other_version) { described_class.new("1.0.0u1") } - - it { is_expected.to eq(-1) } + context "with semantic versions that have a build number" do + let(:versions) do + [ + ["1.2.3", "1.2.3-1", -1], + ["1.2.3", "1.2.3-0-1", -1], + ["1.2.3", "1.2.3-0.1", -1], + ["1.2.3-2", "1.2.3-1", 1], + ["1.2.3-0.2", "1.2.3-1.1", -1] + ] end - context "when the version is a pre-release" do - let(:other_version) { described_class.new("1.0.0a1") } - - it { is_expected.to eq(1) } + it "returns the correct result" do + versions.each do |input| + version1, version2, result = input + version = described_class.new(version1) + other_version = described_class.new(version2) + expect(version <=> other_version).to eq(result) + expect(other_version <=> version).to eq(-result) + end end + end - context "when the version is non-numeric" do - let(:version) { described_class.new("Finchley") } - let(:other_version) { described_class.new("Edgware") } + context "with semantic versions that have a qualifier" do + let(:versions) do + [ + ["1.2.3", "1.2.3-a0", 1], # alpha has lower precedence + ["1.2.3", "1.2.3-a", -1] # 'a' without a following int is not alpha - it { is_expected.to eq(1) } + ] end - describe "with a + separated alphanumeric build identifier" do - context "when equal" do - let(:version_string) { "9.0.0+100" } - let(:other_version) { described_class.new("9.0.0+100") } - - it { is_expected.to eq(0) } - end - - context "when greater" do - let(:version_string) { "9.0.0+102" } - let(:other_version) { described_class.new("9.0.0+101") } - - it { is_expected.to eq(1) } - end - - context "when less than" do - let(:version_string) { "9.0.0+100" } - let(:other_version) { described_class.new("9.0.0+101") } - - it { is_expected.to eq(-1) } + it "returns the correct result" do + versions.each do |input| + version1, version2, result = input + version = described_class.new(version1) + other_version = described_class.new(version2) + expect(version <=> other_version).to eq(result) + expect(other_version <=> version).to eq(-result) end end + end - describe "from the spec" do - context "when dealing with number padding" do - let(:version) { described_class.new("1") } - let(:other_version) { described_class.new("1.1") } - - it { is_expected.to eq(-1) } - end - - context "when dealing with qualifier padding" do - let(:version) { described_class.new("1-snapshot") } - let(:other_version) { described_class.new("1") } - - it { is_expected.to eq(-1) } - end - - context "when dealing with qualifier padding 1" do - let(:version) { described_class.new("1") } - let(:other_version) { described_class.new("1-sp") } - - it { is_expected.to eq(-1) } - end - - context "when dealing with switching" do - let(:version) { described_class.new("1-foo2") } - let(:other_version) { described_class.new("1-foo10") } - - it { is_expected.to eq(-1) } - end - - context "when dealing with prefixes" do - let(:version) { described_class.new("1.foo") } - let(:other_version) { described_class.new("1-foo") } - - it { is_expected.to eq(-1) } - end - - context "when dealing with prefixes2" do - let(:version) { described_class.new("1-foo") } - let(:other_version) { described_class.new("1-1") } + context "with versions that have trailing nulls" do + let(:versions) do + [ + ["1alpha-0", "1alpha", 0], + ["1alpha-0", "1alpha0", 0], + ["1alpha-0", "1alpha.0", 0], + ["1alpha-0", "1alpha.z", -1], + + ["1beta-0", "1beta", 0], + ["1beta-0", "1beta0", 0], + ["1beta-0", "1beta.0", 0], + ["1beta-0", "1beta.z", -1], + + ["1rc-0", "1rc0", 0], + ["1rc-0", "1rc", 0], + ["1rc-0", "1rc.0", 0], + ["1rc-0", "1rc.z", -1], + + ["1sp-0", "1sp0", 0], + ["1sp-0", "1sp", 0], + ["1sp-0", "1sp.0", 0], + ["1sp-0", "1sp.z", -1], + + ["1.ga", "1-ga", 0], + ["1.0", "1.ga", 0], + ["1.0.FINAL", "1", 0], + ["1.0", "1.release", 0], + + ["1.2.0", "1.2", 0], + ["1.2.3", "1.2.3-0", 0], + ["1.2.3-0", "1.2.3-0", 0], + ["1.2.3-0", "1.2.3-a0", 1], + ["1.2.3-0", "1.2.3-a", -1], + ["1.2.3-0", "1.2.3-1", -1], + ["1.2.3-0", "1.2.3-0-1", -1], + + ["1snapshot-0", "1snapshot0", 0], + ["1snapshot-0", "1snapshot", 0], + ["1snapshot-0", "1snapshot.0", 0], + ["1snapshot-0", "1snapshot.z", -1], + + ["1milestone-0", "1milestone", 0], + ["1milestone-0", "1milestone0", 0], + ["1milestone-0", "1milestone.0", 0], + ["1milestone-0", "1milestone.z", -1] + ] + end - it { is_expected.to eq(-1) } + it "returns the correct result" do + versions.each do |input| + version1, version2, result = input + version = described_class.new(version1) + other_version = described_class.new(version2) + expect(version <=> other_version).to eq(result) + expect(other_version <=> version).to eq(-result) end + end + end - context "when dealing with prefixes3" do - let(:version) { described_class.new("1-1") } - let(:other_version) { described_class.new("1.1") } + context "with equivalent shortened qualifiers" do + let(:versions) do + [ + ["1alpha-0", "1a0", 0], + ["1beta-0", "1b0", 0], + ["1milestone-0", "1m0", 0] + ] + end - it { is_expected.to eq(-1) } + it "returns 0" do + versions.each do |input| + version1, version2, result = input + version = described_class.new(version1) + other_version = described_class.new(version2) + expect(version <=> other_version).to eq(result) + expect(other_version <=> version).to eq(-result) end + end + end - context "when dealing with null values" do - let(:version) { described_class.new("1.ga") } - let(:other_version) { described_class.new("1-ga") } + context "with dot, hyphen and digit / qualifier transitions as separators" do + let(:versions) do + [ + ["1alpha.z", "1alpha-z", 0], + ["1alpha1", "1alpha-1", 0], + ["1alpha-1", "1alpha.1", -1], + ["1beta.z", "1beta-z", 0], + ["1beta1", "1beta-1", 0], + ["1beta-1", "1beta.1", -1], + ["1-a", "1a", 0], + ["1-a", "1.a", 0], + ["1-b", "1-b-1", -1], + ["1-b-1", "1-b.1", -1], + ["1sp.z", "1sp-z", 0], + ["1sp1", "1sp-1", 0], + ["1sp-1", "1sp.1", -1], + ["1rc.z", "1rc-z", 0], + ["1rc1", "1rc-1", 0], + ["1rc-1", "1rc.1", -1], + ["1milestone.z", "1milestone-z", 0], + ["1milestone1", "1milestone-1", 0], + ["1milestone-1", "1milestone.1", -1], + ["1snapshot.z", "1snapshot-z", 0], + ["1snapshot1", "1snapshot-1", 0], + ["1snapshot-1", "1snapshot.1", -1] + ] + end - it { is_expected.to eq(0) } + it "returns 0" do + versions.each do |input| + version1, version2, result = input + version = described_class.new(version1) + other_version = described_class.new(version2) + expect(version <=> other_version).to eq(result) + expect(other_version <=> version).to eq(-result) end + end + end - context "when dealing with null values 2" do - let(:version) { described_class.new("1-ga") } - let(:other_version) { described_class.new("1-0") } + context "with qualifiers with different precedence" do + let(:versions) do + [ + ["1alpha.1", "1beta.1", -1], + ["1beta.1", "1milestone.1", -1], + ["1milestone.1", "1rc.1", -1], + ["1rc.1", "1snapshot.1", -1], + ["1.sp", "1.ga", 1], + ["1.release", "1.ga", 0] + ] + end - it { is_expected.to eq(0) } + it "returns the correct value" do + versions.each do |input| + version1, version2, result = input + version = described_class.new(version1) + other_version = described_class.new(version2) + expect(version <=> other_version).to eq(result) + expect(other_version <=> version).to eq(-result) end + end + end - context "when dealing with null values 3" do - let(:version) { described_class.new("1-0") } - let(:other_version) { described_class.new("1.0") } + context "with equivalent qualifiers cr and rc" do + let(:version) { described_class.new("1.0rc-1") } + let(:other_version) { described_class.new("1.0-cr1") } - it { is_expected.to eq(0) } - end + it "returns 0" do + expect(version <=> other_version).to eq(0) + expect(other_version <=> version).to eq(0) + end + end - context "when dealing with null values 4" do - let(:version) { described_class.new("1.0") } - let(:other_version) { described_class.new("1") } + context "when comparing alphanumerically" do + let(:versions) do + [ + ["1alpha-z", "1alpha1", -1], + ["1beta-z", "1beta1", -1], + ["1milestone-z", "1milestone1", -1], + ["1rc-z", "1rc1", -1], + ["1snapshot-z", "1snapshot1", -1], + ["1sp-z", "1sp1", -1], + ["181", "DEV", 1] + ] + end - it { is_expected.to eq(0) } + it "gives higher precedence to digits" do + versions.each do |input| + version1, version2, result = input + version = described_class.new(version1) + other_version = described_class.new(version2) + expect(version <=> other_version).to eq(result) + expect(other_version <=> version).to eq(-result) end + end + end - context "when dealing with null values 5" do - let(:version) { described_class.new("1.0.") } - let(:other_version) { described_class.new("1") } + context "when comparing alphabetically" do + let(:versions) do + [ + ["1-a", "1-b", -1], + ["Finchley", "Edgware", 1], + ["1.something", "1.SOMETHING", 0] + ] + end - it { is_expected.to eq(0) } + it "returns the correct result" do + versions.each do |input| + version1, version2, result = input + version = described_class.new(version1) + other_version = described_class.new(version2) + expect(version <=> other_version).to eq(result) + expect(other_version <=> version).to eq(-result) end + end + end - context "when dealing with null values 6" do - let(:version) { described_class.new("1.0-.2") } - let(:other_version) { described_class.new("1.0-0.2") } + context "when comparing numerically" do + let(:versions) do + [ + ["1-b.1", "1-b.2", -1], + ["9.0.0+102", "9.0.0+91", 1], + ["1-foo2", "1-foo10", -1] - it { is_expected.to eq(0) } - end - - context "when dealing with case insensitivity" do - let(:version) { described_class.new("1.0.FINAL") } - let(:other_version) { described_class.new("1") } + ] + end - it { is_expected.to eq(0) } + it "returns the correct result" do + versions.each do |input| + version1, version2, result = input + version = described_class.new(version1) + other_version = described_class.new(version2) + expect(version <=> other_version).to eq(result) + expect(other_version <=> version).to eq(-result) end + end + end - context "when dealing with case insensitivity 2" do - let(:version) { described_class.new("1.something") } - let(:other_version) { described_class.new("1.SOMETHING") } + context "when comparing padded versions" do + let(:versions) do + [ + ["1snapshot.1", "1", -1], + ["1-snapshot", "1", -1], + ["1", "1sp0", -1], + ["1sp.1", "1-a", -1], + ["1", "1.1", -1], + ["1", "1-sp", -1], + ["1-ga-1", "1-1", -1] + ] + end - it { is_expected.to eq(0) } + it "returns the correct result" do + versions.each do |input| + version1, version2, result = input + version = described_class.new(version1) + other_version = described_class.new(version2) + expect(version <=> other_version).to eq(result) + expect(other_version <=> version).to eq(-result) end + end + end - context "when dealing with post releases" do - let(:version) { described_class.new("1-sp") } - let(:other_version) { described_class.new("1-ga") } - - it { is_expected.to eq(1) } - end + context "when ordering versions" do + let(:versions) do + [ + described_class.new("NotAVersionSting"), + described_class.new("1.0-alpha"), + described_class.new("1.0a1-SNAPSHOT"), + described_class.new("1.0-alpha1"), + described_class.new("1.0beta1-SNAPSHOT"), + described_class.new("1.0-b2"), + described_class.new("1.0-beta3.SNAPSHOT"), + described_class.new("1.0-beta3"), + described_class.new("1.0-milestone1-SNAPSHOT"), + described_class.new("1.0-m2"), + described_class.new("1.0-rc1-SNAPSHOT"), + described_class.new("1.0-cr1"), + described_class.new("1.0-SNAPSHOT"), + described_class.new("1.0-RELEASE"), + described_class.new("1.0-sp"), + described_class.new("1.0-a"), + described_class.new("1.0-whatever"), + described_class.new("1.0.z"), + described_class.new("1.0.1"), + described_class.new("1.0.1.0.0.0.0.0.0.0.0.0.0.0.1") + ] + end - context "when dealing with post releases 2" do - let(:version) { described_class.new("1-sp.1") } - let(:other_version) { described_class.new("1-ga.1") } + it "sorts versions correctly" do + expect(versions.shuffle.sort).to eq(versions) + end + end + end - it { is_expected.to eq(1) } - end + describe "#ignored_major_versions" do + subject(:ignored_versions) { version.ignored_major_versions } - context "when dealing with null values (again)" do - let(:version) { described_class.new("1-sp-1") } - let(:other_version) { described_class.new("1-ga-1") } + let(:version_string) { "1.2.3-alpha.1" } - it { is_expected.to eq(-1) } - end + it { is_expected.to eq([">= 2.a0"]) } + end - context "when dealing with null values (again 2)" do - let(:version) { described_class.new("1-ga-1") } - let(:other_version) { described_class.new("1-1") } + describe "#ignored_minor_versions" do + subject(:ignored_versions) { version.ignored_minor_versions } - it { is_expected.to eq(0) } - end + let(:version_string) { "1.2.3-alpha.1" } - context "when dealing with named values" do - let(:version) { described_class.new("1-a1") } - let(:other_version) { described_class.new("1-alpha-1") } + it { is_expected.to eq([">= 1.3.a0, < 2.a0"]) } + end - it { is_expected.to eq(0) } - end + describe "#ignored_patch_versions" do + subject(:ignored_versions) { version.ignored_patch_versions } - context "when comparing string versions with integer ones" do - let(:version) { described_class.new("181") } - let(:other_version) { described_class.new("dev") } + let(:version_string) { "1.2.3-alpha.1" } - it { is_expected.to eq(1) } - end - end - end + it { is_expected.to eq(["> #{version_string}, < 1.3.a0"]) } end describe "compatibility with Gem::Requirement" do