Jelajahi Sumber

Updated SemVerComparator to support pre-release versions.

Sebastian Stenzel 8 tahun lalu
induk
melakukan
9aa8c46560

+ 42 - 3
main/commons/src/main/java/org/cryptomator/common/SemVerComparator.java

@@ -12,12 +12,51 @@ import java.util.Comparator;
 
 import org.apache.commons.lang3.StringUtils;
 
+/**
+ * Compares version strings according to <a href="http://semver.org/spec/v2.0.0.html">SemVer 2.0.0</a>.
+ */
 public class SemVerComparator implements Comparator<String> {
 
+	private static final char VERSION_SEP = '.'; // http://semver.org/spec/v2.0.0.html#spec-item-2
+	private static final String PRE_RELEASE_SEP = "-"; // http://semver.org/spec/v2.0.0.html#spec-item-9
+	private static final String BUILD_SEP = "+"; // http://semver.org/spec/v2.0.0.html#spec-item-10
+
 	@Override
 	public int compare(String version1, String version2) {
-		final String[] vComps1 = StringUtils.split(version1, '.');
-		final String[] vComps2 = StringUtils.split(version2, '.');
+		// "Build metadata SHOULD be ignored when determining version precedence.
+		// Thus two versions that differ only in the build metadata, have the same precedence."
+		String v1WithoutBuildMetadata = StringUtils.substringBefore(version1, BUILD_SEP);
+		String v2WithoutBuildMetadata = StringUtils.substringBefore(version2, BUILD_SEP);
+
+		if (v1WithoutBuildMetadata.equals(v2WithoutBuildMetadata)) {
+			return 0;
+		}
+
+		String v1MajorMinorPatch = StringUtils.substringBefore(v1WithoutBuildMetadata, PRE_RELEASE_SEP);
+		String v2MajorMinorPatch = StringUtils.substringBefore(v2WithoutBuildMetadata, PRE_RELEASE_SEP);
+		String v1PreReleaseVersion = StringUtils.substringAfter(v1WithoutBuildMetadata, PRE_RELEASE_SEP);
+		String v2PreReleaseVersion = StringUtils.substringAfter(v2WithoutBuildMetadata, PRE_RELEASE_SEP);
+		return compare(v1MajorMinorPatch, v1PreReleaseVersion, v2MajorMinorPatch, v2PreReleaseVersion);
+	}
+
+	private int compare(String v1MajorMinorPatch, String v1PreReleaseVersion, String v2MajorMinorPatch, String v2PreReleaseVersion) {
+		int comparisonResult = compareNumericallyThenLexicographically(v1MajorMinorPatch, v2MajorMinorPatch);
+		if (comparisonResult == 0) {
+			if (v1PreReleaseVersion.isEmpty()) {
+				return 1; // 1.0.0 > 1.0.0-BETA
+			} else if (v2PreReleaseVersion.isEmpty()) {
+				return -1; // 1.0.0-BETA < 1.0.0
+			} else {
+				return compareNumericallyThenLexicographically(v1PreReleaseVersion, v2PreReleaseVersion);
+			}
+		} else {
+			return comparisonResult;
+		}
+	}
+
+	private int compareNumericallyThenLexicographically(String version1, String version2) {
+		final String[] vComps1 = StringUtils.split(version1, VERSION_SEP);
+		final String[] vComps2 = StringUtils.split(version2, VERSION_SEP);
 		final int commonCompCount = Math.min(vComps1.length, vComps2.length);
 
 		for (int i = 0; i < commonCompCount; i++) {
@@ -35,7 +74,7 @@ public class SemVerComparator implements Comparator<String> {
 			}
 		}
 
-		// all in common so far? longest version string wins:
+		// all in common so far? longest version string is considered the higher version:
 		return vComps1.length - vComps2.length;
 	}
 

+ 14 - 5
main/commons/src/test/java/org/cryptomator/common/SemVerComparatorTest.java

@@ -10,7 +10,6 @@ package org.cryptomator.common;
 
 import java.util.Comparator;
 
-import org.cryptomator.common.SemVerComparator;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -22,8 +21,10 @@ public class SemVerComparatorTest {
 
 	@Test
 	public void compareEqualVersions() {
-		final int comparisonResult = semVerComparator.compare("1.23.4", "1.23.4");
-		Assert.assertEquals(0, Integer.signum(comparisonResult));
+		Assert.assertEquals(0, Integer.signum(semVerComparator.compare("1.23.4", "1.23.4")));
+		Assert.assertEquals(0, Integer.signum(semVerComparator.compare("1.23.4-alpha", "1.23.4-alpha")));
+		Assert.assertEquals(0, Integer.signum(semVerComparator.compare("1.23.4+20170101", "1.23.4+20171231")));
+		Assert.assertEquals(0, Integer.signum(semVerComparator.compare("1.23.4-alpha+20170101", "1.23.4-alpha+20171231")));
 	}
 
 	// newer versions in first argument
@@ -33,7 +34,11 @@ public class SemVerComparatorTest {
 		Assert.assertEquals(1, Integer.signum(semVerComparator.compare("1.23.5", "1.23.4")));
 		Assert.assertEquals(1, Integer.signum(semVerComparator.compare("1.24.4", "1.23.4")));
 		Assert.assertEquals(1, Integer.signum(semVerComparator.compare("1.23.4", "1.23")));
-		Assert.assertEquals(1, Integer.signum(semVerComparator.compare("1.23.4a", "1.23.4")));
+		Assert.assertEquals(1, Integer.signum(semVerComparator.compare("1.23.4", "1.23.4-SNAPSHOT")));
+		Assert.assertEquals(1, Integer.signum(semVerComparator.compare("1.23.4", "1.23.4-56.78")));
+		Assert.assertEquals(1, Integer.signum(semVerComparator.compare("1.23.4-beta", "1.23.4-alpha")));
+		Assert.assertEquals(1, Integer.signum(semVerComparator.compare("1.23.4-alpha.1", "1.23.4-alpha")));
+		Assert.assertEquals(1, Integer.signum(semVerComparator.compare("1.23.4-56.79", "1.23.4-56.78")));
 	}
 
 	// newer versions in second argument
@@ -43,7 +48,11 @@ public class SemVerComparatorTest {
 		Assert.assertEquals(-1, Integer.signum(semVerComparator.compare("1.23.4", "1.23.5")));
 		Assert.assertEquals(-1, Integer.signum(semVerComparator.compare("1.23.4", "1.24.4")));
 		Assert.assertEquals(-1, Integer.signum(semVerComparator.compare("1.23", "1.23.4")));
-		Assert.assertEquals(-1, Integer.signum(semVerComparator.compare("1.23.4", "1.23.4a")));
+		Assert.assertEquals(-1, Integer.signum(semVerComparator.compare("1.23.4-SNAPSHOT", "1.23.4")));
+		Assert.assertEquals(-1, Integer.signum(semVerComparator.compare("1.23.4-56.78", "1.23.4")));
+		Assert.assertEquals(-1, Integer.signum(semVerComparator.compare("1.23.4-alpha", "1.23.4-beta")));
+		Assert.assertEquals(-1, Integer.signum(semVerComparator.compare("1.23.4-alpha", "1.23.4-alpha.1")));
+		Assert.assertEquals(-1, Integer.signum(semVerComparator.compare("1.23.4-56.78", "1.23.4-56.79")));
 	}
 
 }