diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java
index d90c1bf3fd4e..02e8294cab1b 100644
--- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java
+++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java
@@ -2850,18 +2850,13 @@ public class StringUtil extends StringUtilRt {
int length1 = s1.length();
int length2 = s2.length();
int i = 0;
- int j = 0;
- for (; i < length1 && j < length2; i++, j++) {
- int diff = compare(s1.charAt(i), s2.charAt(j), ignoreCase);
+ for (; i < length1 && i < length2; i++) {
+ int diff = compare(s1.charAt(i), s2.charAt(i), ignoreCase);
if (diff != 0) {
return diff;
}
}
- if (i < length1) return +1;
- if (j < length2) return -1;
- if (length1 != length2) return length1 - length2;
-
- return ignoreCase ? compare(s1, s2, false) : 0;
+ return length1 - length2;
}
@Contract(pure = true)
diff --git a/platform/util/src/com/intellij/util/text/SemVer.java b/platform/util/src/com/intellij/util/text/SemVer.java
index 5893cfe06088..57dd86c1e23c 100644
--- a/platform/util/src/com/intellij/util/text/SemVer.java
+++ b/platform/util/src/com/intellij/util/text/SemVer.java
@@ -21,6 +21,8 @@ import org.jetbrains.annotations.Nullable;
import java.util.Objects;
+import static com.intellij.openapi.util.text.StringUtil.isNotNegativeNumber;
+
/**
* Holds Semantic Version.
*/
@@ -151,13 +153,15 @@ public final class SemVer implements Comparable {
CharSequence segment1 = new CharSequenceSubSequence(pre1, start1, end1);
CharSequence segment2 = new CharSequenceSubSequence(pre2, start2, end2);
- if (isNumeric(segment1)) {
- if (!isNumeric(segment2)) {
+ if (isNotNegativeNumber(segment1)) {
+ if (!isNotNegativeNumber(segment2)) {
+ // According to SemVer specification numeric segments has lower precedence
+ // than non-numeric segments
return -1;
}
diff = compareNumeric(segment1, segment2);
}
- else if (isNumeric(segment2)) {
+ else if (isNotNegativeNumber(segment2)) {
return 1;
}
else {
@@ -184,23 +188,12 @@ public final class SemVer implements Comparable {
int length1 = segment1.length();
int length2 = segment2.length();
int diff = Integer.compare(length1, length2);
- for (int i = 0; i <= length1 && diff == 0; i++) {
+ for (int i = 0; i < length1 && diff == 0; i++) {
diff = segment1.charAt(i) - segment2.charAt(i);
}
return diff;
}
- private static boolean isNumeric(CharSequence segment) {
- int length = segment.length();
- for (int i = 0; i < length; i++) {
- int ch = segment.charAt(i);
- if (ch < '0' || ch > '9') {
- return false;
- }
- }
- return true;
- }
-
@Nullable
public static SemVer parseFromText(@Nullable String text) {
if (text != null) {
diff --git a/platform/util/testSrc/com/intellij/util/text/SemVerTest.java b/platform/util/testSrc/com/intellij/util/text/SemVerTest.java
index 395ce47c6c9c..be4670e8b1b0 100644
--- a/platform/util/testSrc/com/intellij/util/text/SemVerTest.java
+++ b/platform/util/testSrc/com/intellij/util/text/SemVerTest.java
@@ -15,6 +15,7 @@
*/
package com.intellij.util.text;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.junit.Assert;
import org.junit.Test;
@@ -50,27 +51,37 @@ public class SemVerTest {
assertThat(parse("11.123.0-a.b.c-1")).isEqualByComparingTo(parse("11.123.0-a.b.c-1"));
assertPrecedence("0.10.0", "1.0.0");
- assertPrecedence("1.0.0","2.10.0");
+ assertPrecedence("1.0.0", "2.10.0");
assertPrecedence("0.5.1000", "0.30.0");
- assertPrecedence("0.30.10","0.100.0");
+ assertPrecedence("0.30.10", "0.100.0");
assertPrecedence("2.9.100", "2.9.123-test");
- assertPrecedence("2.9.123-test","2.9.124");
- assertPrecedence("2.9.123","2.9.124-test");
+ assertPrecedence("2.9.123-test", "2.9.124");
+ assertPrecedence("2.9.123", "2.9.124-test");
- assertPrecedence("1.2.3-a","1.2.3");
+ assertPrecedence("1.2.3-a", "1.2.3");
- assertPrecedence("1.2.3-12","1.2.3-a");
- assertPrecedence("1.2.3-22","1.2.3-100");
- assertPrecedence("1.2.3-22","1.2.3-31");
+ assertPrecedence("1.2.3-12", "1.2.3-a");
+ assertPrecedence("1.2.3-22", "1.2.3-100");
+ assertPrecedence("1.2.3-22", "1.2.3-31");
+ assertPrecedence("1.2.3-22", "1.2.3-222");
- assertPrecedence("1.2.3-a.b.c","1.2.3-a.b.d");
- assertPrecedence("1.2.3-a.b.c","1.2.3-a.b.c.a");
+ assertPrecedence("1.2.3-a.b.c", "1.2.3-a.b.d");
+ assertPrecedence("1.2.3-a.b.c", "1.2.3-a.b.c.a");
- assertPrecedence("1.2.3-a.b.1","1.2.3-a.b.c");
- assertPrecedence("1.2.3-a.b.1","1.2.3-a.c.1");
- assertPrecedence("1.2.3-a.cbc.100","1.2.3-a.cca.1");
- assertPrecedence("1.2.3-a.cb.1","1.2.3-a.cba.1");
+ assertPrecedence("1.2.3-a.b.1", "1.2.3-a.b.c");
+ assertPrecedence("1.2.3-a.b.1", "1.2.3-a.c.1");
+ assertPrecedence("1.2.3-a.cbc.100", "1.2.3-a.cca.1");
+ assertPrecedence("1.2.3-a.cb.1", "1.2.3-a.cba.1");
+
+ // Example from SemVer documentation https://semver.org/#spec-item-11
+ assertPrecedence("1.0.0-alpha", "1.0.0-alpha.1");
+ assertPrecedence("1.0.0-alpha.1", "1.0.0-alpha.beta");
+ assertPrecedence("1.0.0-alpha.beta", "1.0.0-beta");
+ assertPrecedence("1.0.0-beta", "1.0.0-beta.2");
+ assertPrecedence("1.0.0-beta.2", "1.0.0-beta.11");
+ assertPrecedence("1.0.0-beta.11", "1.0.0-rc.1");
+ assertPrecedence("1.0.0-rc.1", "1.0.0");
Assert.assertTrue(parse("4.12.5").isGreaterOrEqualThan(4, 12, 5));
Assert.assertTrue(parse("4.12.5-a").isGreaterOrEqualThan(4, 12, 5));
@@ -95,7 +106,11 @@ public class SemVerTest {
assertThat(v1).isNotEqualTo(v2);
}
- private static void assertParsed(String version, int expectedMajor, int expectedMinor, int expectedPatch, @Nullable String expectedPreRelease) {
+ private static void assertParsed(@NotNull String version,
+ int expectedMajor,
+ int expectedMinor,
+ int expectedPatch,
+ @Nullable String expectedPreRelease) {
assertThat(parse(version)).isEqualTo(new SemVer(version, expectedMajor, expectedMinor, expectedPatch, expectedPreRelease));
}
diff --git a/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java b/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java
index 07afecb1b2e8..94fee88d55ab 100644
--- a/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java
+++ b/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java
@@ -9,6 +9,7 @@ import com.intellij.openapi.util.text.LineColumn;
import com.intellij.openapi.util.text.NaturalComparator;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.LineSeparator;
+import com.intellij.util.TripleFunction;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.xml.util.XmlStringUtil;
import org.jdom.Verifier;
@@ -199,16 +200,16 @@ public class StringUtilTest {
@Test
public void testNaturalCompare() {
- final List numbers = Arrays.asList("1a000001", "000001a1", "001a0001", "0001A001" , "00001a01", "01a00001");
+ final List numbers = Arrays.asList("1a000001", "000001a1", "001a0001", "0001A001", "00001a01", "01a00001");
numbers.sort(NaturalComparator.INSTANCE);
- assertEquals(Arrays.asList("1a000001", "01a00001", "001a0001", "0001A001" , "00001a01", "000001a1"), numbers);
+ assertEquals(Arrays.asList("1a000001", "01a00001", "001a0001", "0001A001", "00001a01", "000001a1"), numbers);
final List test = Arrays.asList("test011", "test10", "test10a", "test010");
test.sort(NaturalComparator.INSTANCE);
assertEquals(Arrays.asList("test10", "test10a", "test010", "test011"), test);
final List strings = Arrays.asList("Test99", "tes0", "test0", "testing", "test", "test99", "test011", "test1",
- "test 3", "test2", "test10a", "test10", "1.2.10.5", "1.2.9.1");
+ "test 3", "test2", "test10a", "test10", "1.2.10.5", "1.2.9.1");
strings.sort(NaturalComparator.INSTANCE);
assertEquals(Arrays.asList("1.2.9.1", "1.2.10.5", "tes0", "test", "test0", "test1", "test2", "test 3", "test10", "test10a",
"test011", "Test99", "test99", "testing"), strings);
@@ -216,13 +217,14 @@ public class StringUtilTest {
final List strings2 = Arrays.asList("t1", "t001", "T2", "T002", "T1", "t2");
strings2.sort(NaturalComparator.INSTANCE);
assertEquals(Arrays.asList("T1", "t1", "t001", "T2", "t2", "T002"), strings2);
- assertEquals(1 ,StringUtil.naturalCompare("7403515080361171695", "07403515080361171694"));
+ assertEquals(1, StringUtil.naturalCompare("7403515080361171695", "07403515080361171694"));
assertEquals(-14, StringUtil.naturalCompare("_firstField", "myField1"));
//idea-80853
final List strings3 =
Arrays.asList("C148A_InsomniaCure", "C148B_Escape", "C148C_TersePrincess", "C148D_BagOfMice", "C148E_Porcelain");
strings3.sort(NaturalComparator.INSTANCE);
- assertEquals(Arrays.asList("C148A_InsomniaCure", "C148B_Escape", "C148C_TersePrincess", "C148D_BagOfMice", "C148E_Porcelain"), strings3);
+ assertEquals(Arrays.asList("C148A_InsomniaCure", "C148B_Escape", "C148C_TersePrincess", "C148D_BagOfMice", "C148E_Porcelain"),
+ strings3);
final List l = Arrays.asList("a0002", "a0 2", "a001");
l.sort(NaturalComparator.INSTANCE);
@@ -374,7 +376,8 @@ public class StringUtilTest {
@SuppressWarnings("StringToUpperCaseOrToLowerCaseWithoutLocale")
public void testReplaceReturnReplacementIfTextEqualsToReplacedText() {
String str = "/tmp";
- assertSame(str, StringUtil.replace("$PROJECT_FILE$", "$PROJECT_FILE$".toLowerCase().toUpperCase() /* ensure new String instance */, str));
+ assertSame(str,
+ StringUtil.replace("$PROJECT_FILE$", "$PROJECT_FILE$".toLowerCase().toUpperCase() /* ensure new String instance */, str));
}
@Test
@@ -453,6 +456,36 @@ public class StringUtilTest {
assertTrue(StringUtil.contains("12", "2"));
}
+ @Test
+ public void testCompareCharSequence() {
+ TripleFunction assertPrecedence =
+ (lesser, greater, ignoreCase) -> {
+ assertTrue(StringUtil.compare(lesser, greater, ignoreCase) < 0);
+ assertTrue(StringUtil.compare(greater, lesser, ignoreCase) > 0);
+ return true;
+ };
+ TripleFunction assertEquality =
+ (lesser, greater, ignoreCase) -> {
+ assertEquals(0, StringUtil.compare(lesser, greater, ignoreCase));
+ assertEquals(0, StringUtil.compare(greater, lesser, ignoreCase));
+ return true;
+ };
+
+ assertPrecedence.fun("A","b", true);
+ assertPrecedence.fun("a","aa", true);
+ assertPrecedence.fun("abb","abC", true);
+
+ assertPrecedence.fun("A","a", false);
+ assertPrecedence.fun("Aa","a", false);
+ assertPrecedence.fun("a","aa", false);
+ assertPrecedence.fun("-","A", false);
+
+ assertEquality.fun("a","A",true);
+ assertEquality.fun("aa12b","Aa12B",true);
+
+ assertEquality.fun("aa12b","aa12b",false);
+ }
+
@Test
public void testDetectSeparators() {
assertNull(StringUtil.detectSeparators(""));
@@ -549,7 +582,7 @@ public class StringUtilTest {
assertEquals("2 m 3 s", StringUtil.formatDurationApproximate(123456));
assertEquals("1 h 1 m", StringUtil.formatDurationApproximate(3659009));
assertEquals("2 h", StringUtil.formatDurationApproximate(7199000));
- assertEquals("1 d", StringUtil.formatDurationApproximate((23*60*60 + 59*60 + 59) * 1000L));
+ assertEquals("1 d", StringUtil.formatDurationApproximate((23 * 60 * 60 + 59 * 60 + 59) * 1000L));
assertEquals("1 yr 1 mo", StringUtil.formatDurationApproximate(33786061001L));
}
@@ -558,7 +591,8 @@ public class StringUtilTest {
assertEquals("", XmlStringUtil.wrapInCDATA("abc"));
assertEquals("]]>", XmlStringUtil.wrapInCDATA("abc]]>"));
assertEquals("def]]>", XmlStringUtil.wrapInCDATA("abc]]>def"));
- assertEquals("]]]>]]]>", XmlStringUtil.wrapInCDATA("123]]>]]>]]]>]]]>",
+ XmlStringUtil.wrapInCDATA("123]]>]]>