From da4246ad2677f3a91353b6f3024832e4a5aff7b4 Mon Sep 17 00:00:00 2001 From: Swell <5782559+sultan@users.noreply.github.com> Date: Tue, 20 Dec 2022 18:32:27 +0100 Subject: [PATCH] [MNG-7644] Fix version comparison where .X1 < -X2 for any string qualifier X This closes #930 --- .../versioning/ComparableVersion.java | 21 ++++++++++++++++++- .../versioning/ComparableVersionTest.java | 21 +++++++++++++++++-- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/ComparableVersion.java b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/ComparableVersion.java index 41a9ad153707..17aa8cc7a703 100644 --- a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/ComparableVersion.java +++ b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/ComparableVersion.java @@ -53,7 +53,10 @@ * * Unknown qualifiers are considered after known qualifiers, with lexical order (always case insensitive), * - *
  • a hyphen usually precedes a qualifier, and is always less important than something preceded with a dot.
  • + *
  • a hyphen usually precedes a qualifier, and is always less important than digits/number, for example + * {@code 1.0.RC2 < 1.0-RC3 < 1.0.1}; but prefer {@code 1.0.0-RC1} over {@code 1.0.0.RC1}, and more + * generally: {@code 1.0.X2 < 1.0-X3 < 1.0.1} for any string {@code X}; but prefer {@code 1.0.0-X1} + * over {@code 1.0.0.X1}.
  • * * * @see "Versioning" on Maven Wiki @@ -676,6 +679,14 @@ else if ( Character.isDigit( c ) ) { if ( !isDigit && i > startIndex ) { + // 1.0.0.X1 < 1.0.0-X2 + // treat .X as -X for any string qualifier X + if ( !list.isEmpty() ) + { + list.add( list = new ListItem() ); + stack.push( list ); + } + list.add( new StringItem( version.substring( startIndex, i ), true ) ); startIndex = i; @@ -702,6 +713,14 @@ else if ( Character.isDigit( c ) ) if ( version.length() > startIndex ) { + // 1.0.0.X1 < 1.0.0-X2 + // treat .X as -X for any string qualifier X + if ( !isDigit && !list.isEmpty() ) + { + list.add( list = new ListItem() ); + stack.push( list ); + } + list.add( parseItem( isDigit, version.substring( startIndex ) ) ); } diff --git a/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/ComparableVersionTest.java b/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/ComparableVersionTest.java index 97fb46d55f8b..832ab179b83f 100644 --- a/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/ComparableVersionTest.java +++ b/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/ComparableVersionTest.java @@ -51,8 +51,8 @@ private Comparable newComparable( String version ) "1-1", "1-2", "1-123" }; private static final String[] VERSIONS_NUMBER = - { "2.0", "2-1", "2.0.a", "2.0.0.a", "2.0.2", "2.0.123", "2.1.0", "2.1-a", "2.1b", "2.1-c", "2.1-1", "2.1.0.1", - "2.2", "2.123", "11.a2", "11.a11", "11.b2", "11.b11", "11.m2", "11.m11", "11", "11.a", "11b", "11c", "11m" }; + { "2.0", "2.0.a", "2-1", "2.0.2", "2.0.123", "2.1.0", "2.1-a", "2.1b", "2.1-c", "2.1-1", "2.1.0.1", "2.2", + "2.123", "11.a2", "11.a11", "11.b2", "11.b11", "11.m2", "11.m11", "11", "11.a", "11b", "11c", "11m" }; private void checkVersionsOrder( String[] versions ) { @@ -337,4 +337,21 @@ public void testReuse() assertEquals( "reused instance should be equivalent to new instance", c1, c2 ); } + + /** + * Test MNG-7644 edge cases + * 1.0.0.RC1 < 1.0.0-RC2 and more generally: + * 1.0.0.X1 < 1.0.0-X2 for any string X + */ + public void testMng7644() + { + for ( String x : new String[]{ "abc", "alpha", "a", "beta", "b", "def", "milestone", "m", "RC" } ) { + // 1.0.0.X1 < 1.0.0-X2 for any string x + checkVersionsOrder( "1.0.0." + x + "1", "1.0.0-" + x + "2" ); + // 2.0.X == 2-X == 2.0.0.X for any string x + checkVersionsEqual( "2-" + x, "2.0." + x ); // previously ordered, now equals + checkVersionsEqual( "2-" + x, "2.0.0." + x ); // previously ordered, now equals + checkVersionsEqual( "2.0." + x, "2.0.0." + x ); // previously ordered, now equals + } + } }