diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersion.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersion.java
index 0edbee215..97e0e0616 100644
--- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersion.java
+++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersion.java
@@ -235,8 +235,8 @@ public boolean next() {
index++;
break;
} else {
- int digit = Character.digit(c, 10);
- if (digit >= 0) {
+ if (c >= '0' && c <= '9') { // only ASCII digits
+ int digit = c - '0';
if (state == -1) {
end = index;
terminatedByNumber = true;
diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/package-info.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/package-info.java
index c4147f9f1..50b00cc65 100644
--- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/package-info.java
+++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/package-info.java
@@ -18,7 +18,7 @@
* under the License.
*/
/**
- * Ready-to-use version scheme for parsing/comparing versions and utility classes.
+ * Version scheme for parsing/comparing versions and utility classes.
*
* Contains the "generic" scheme {@link org.eclipse.aether.util.version.GenericVersionScheme}
* that serves the purpose of "factory" (and/or parser) for all corresponding elements (all those are package private).
@@ -28,12 +28,13 @@
*
* Below is the Generic Version Spec described:
*
- * Version string is parsed into version according to these rules below:
+ * Version string is parsed into version according to these rules:
*
* - The version string is parsed into segments, from left to right.
- * - Segments are explicitly delimited by single {@code "." (dot)}, {@code "-" (hyphen)} or {@code "_" (underscore)} character.
- * - Segments are implicitly delimited by transition between digits and non-digits.
- * - Segments are classified as numeric, string, qualifiers (special case of string) and min/max.
+ * - Segments are explicitly delimited by a single {@code "." (dot)}, {@code "-" (hyphen)}, or {@code "_" (underscore)} character.
+ * - Segments are implicitly delimited by a transition between ASCII digits and non-digits.
+ * - Segments are classified as numeric, string, qualifiers (special case of string), and min/max.
+ * - Numeric segments are composed of the ASCII digits 0-9. Non-ASCII digits are treated as letters.
*
- Numeric segments are sorted numerically, ascending.
* - Non-numeric segments may be qualifiers (predefined) or strings (non-empty letter sequence). All of them are interpreted as being case-insensitive in terms of the ROOT locale.
* - Qualifier segments (strings listed below) and their sort order (ascending) are:
@@ -48,7 +49,7 @@
*
*
* String segments are sorted lexicographically and case-insensitively per ROOT locale, ascending.
- * There are two special segments, {@code "min"} and {@code "max"}, they represent absolute minimum and absolute maximum in comparisons. They can be used only as trailing segment.
+ * There are two special segments, {@code "min"} and {@code "max"} that represent absolute minimum and absolute maximum in comparisons. They can be used only as the trailing segment.
* As last step, trailing "zero segments" are trimmed. Similarly, "zero segments" positioned before numeric and non-numeric transitions (either explicitly or implicitly delimited) are trimmed.
* When trimming, "zero segments" are qualifiers {@code "ga"}, {@code "final"}, {@code "release"} only if being last (right-most) segment, empty string and "0" always.
* In comparison of same kind segments, the given type of segment determines comparison rules.
@@ -57,11 +58,11 @@
* It is common that a version identifier starts with numeric segment (consider this "best practice").
*
*
- * Note: this version spec does not document (nor cover) many corner cases, that we believe are "atypical" or not
+ * Note: this version spec does not document (or cover) many corner cases that we believe are "atypical" or not
* used commonly. None of these are enforced, but in future implementations they probably will be. Some known examples are:
*
- * - Using "min" or "max" special segments as non-trailing segment. This yields in "undefined" behaviour and should be avoided.
- * - Having non-number as first segment of version. Versions are expected (but not enforced) to start with numbers.
+ * - Using "min" or "max" special segments as a non-trailing segment. This yields in "undefined" behaviour and should be avoided.
+ * - Having a non-number as the first segment of a version. Versions are expected (but not enforced) to start with numbers.
*
*
*/
diff --git a/maven-resolver-util/src/test/java/org/eclipse/aether/util/version/GenericVersionTest.java b/maven-resolver-util/src/test/java/org/eclipse/aether/util/version/GenericVersionTest.java
index 53ebb62d7..7c898ff22 100644
--- a/maven-resolver-util/src/test/java/org/eclipse/aether/util/version/GenericVersionTest.java
+++ b/maven-resolver-util/src/test/java/org/eclipse/aether/util/version/GenericVersionTest.java
@@ -282,7 +282,7 @@ void testUnlimitedNumberOfDigitsInNumericComponent() {
}
@Test
- void testTransitionFromDigitToLetterAndViceVersaIsEqualivantToDelimiter() {
+ void testTransitionFromDigitToLetterAndViceVersaIsEquivalentToDelimiter() {
assertOrder(X_EQ_Y, "1alpha10", "1.alpha.10");
assertOrder(X_EQ_Y, "1alpha10", "1-alpha-10");
@@ -495,8 +495,32 @@ void testMaximumSegment() {
assertOrder(X_LT_Y, "1.max", "2.min");
}
+ @Test
+ void testCompareLettersToNumbers() {
+ assertOrder(X_GT_Y, "1.7", "J");
+ }
+
+ @Test
+ void testCompareDigitToLetter() {
+ assertOrder(X_GT_Y, "7", "J");
+ assertOrder(X_GT_Y, "7", "c");
+ }
+
+ @Test
+ void testNonAsciiDigits() { // These should not be treated as digits.
+ String arabicEight = "\u0668";
+ assertOrder(X_GT_Y, "1", arabicEight);
+ assertOrder(X_GT_Y, "9", arabicEight);
+ }
+
+ @Test
+ void testLexicographicOrder() {
+ assertOrder(X_GT_Y, "zebra", "aardvark");
+ assertOrder(X_GT_Y, "ζέβρα", "zebra");
+ }
+
/**
- * UT for MRESOLVER-314.
+ * Test for MRESOLVER-314.
*
* Generates random UUID string based versions and tries to sort them. While this test is not as reliable
* as {@link #testCompareUuidVersionStringStream()}, it covers broader range and in case it fails it records