更新游戏版本比较规则 (#2700)

* Create GameVersionNumber

* Update GameVersionNumber

* Rename DefaultVersionNumber

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update versions.txt

* update

* update

* update
This commit is contained in:
Glavo
2024-02-13 13:46:01 +08:00
committed by GitHub
parent fe608e32f1
commit 95afaa5112
25 changed files with 1802 additions and 263 deletions

View File

@@ -17,8 +17,8 @@
*/
package org.jackhuang.hmcl.game;
import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
import org.jackhuang.hmcl.util.versioning.VersionNumber;
import org.jackhuang.hmcl.util.versioning.VersionRange;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
@@ -28,10 +28,10 @@ public class JavaVersionConstraintTest {
@Test
public void vanillaJava16() {
JavaVersionConstraint.VersionRanges range = JavaVersionConstraint.findSuitableJavaVersionRange(
VersionNumber.asVersion("1.17"),
GameVersionNumber.asGameVersion("1.17"),
null
);
assertEquals(VersionRange.atLeast("16"), range.getMandatory());
assertEquals(VersionNumber.atLeast("16"), range.getMandatory());
}
}

View File

@@ -0,0 +1,218 @@
package org.jackhuang.hmcl.util.versioning;
import org.junit.jupiter.api.Test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.*;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author Glavo
*/
public class GameVersionNumberTest {
@Test
public void testSortVersions() throws IOException {
List<String> versions = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(GameVersionNumber.class.getResourceAsStream("/assets/game/versions.txt"), StandardCharsets.UTF_8))) {
for (String line; (line = reader.readLine()) != null && !line.isEmpty(); ) {
versions.add(line);
}
}
List<String> copied = new ArrayList<>(versions);
Collections.shuffle(copied, new Random(0));
copied.sort(Comparator.comparing(GameVersionNumber::asGameVersion));
assertIterableEquals(versions, copied);
}
private static String errorMessage(String version1, String version2) {
return String.format("version1=%s, version2=%s", version1, version2);
}
private static void assertGameVersionEquals(String version) {
assertGameVersionEquals(version, version);
}
private static void assertGameVersionEquals(String version1, String version2) {
assertEquals(0, GameVersionNumber.asGameVersion(version1).compareTo(version2), errorMessage(version1, version2));
}
private static void assertLessThan(String version1, String version2) {
assertTrue(GameVersionNumber.asGameVersion(version1).compareTo(version2) < 0, errorMessage(version1, version2));
}
private static void assertOrder(String... versions) {
for (int i = 0; i < versions.length - 1; i++) {
GameVersionNumber version1 = GameVersionNumber.asGameVersion(versions[i]);
//noinspection EqualsWithItself
assertEquals(0, version1.compareTo(version1), "version=" + versions[i]);
for (int j = i + 1; j < versions.length; j++) {
GameVersionNumber version2 = GameVersionNumber.asGameVersion(versions[j]);
assertEquals(-1, version1.compareTo(version2), String.format("version1=%s, version2=%s", versions[i], versions[j]));
assertEquals(1, version2.compareTo(version1), String.format("version1=%s, version2=%s", versions[i], versions[j]));
}
}
assertGameVersionEquals(versions[versions.length - 1]);
}
@Test
public void testParseOld() {
{
GameVersionNumber version = GameVersionNumber.asGameVersion("b1.0");
assertInstanceOf(GameVersionNumber.Old.class, version);
GameVersionNumber.Old old = (GameVersionNumber.Old) version;
assertEquals(GameVersionNumber.Type.BETA, old.type);
assertEquals(1, old.major);
assertEquals(0, old.minor);
assertEquals(0, old.patch);
assertEquals(0, old.additional);
}
{
GameVersionNumber version = GameVersionNumber.asGameVersion("b1.0_01");
assertInstanceOf(GameVersionNumber.Old.class, version);
GameVersionNumber.Old old = (GameVersionNumber.Old) version;
assertEquals(GameVersionNumber.Type.BETA, old.type);
assertEquals(1, old.major);
assertEquals(0, old.minor);
assertEquals(0, old.patch);
assertEquals(1, old.additional);
}
}
@Test
public void testCompareRelease() {
assertGameVersionEquals("0.0");
assertGameVersionEquals("1.100");
assertGameVersionEquals("1.100.1");
assertGameVersionEquals("1.100.1-pre1");
assertGameVersionEquals("1.100.1-pre1", "1.100.1 Pre-Release 1");
assertOrder(
"0.0",
"1.0",
"1.99",
"1.99.1-unknown1",
"1.99.1-pre1",
"1.99.1 Pre-Release 2",
"1.99.1-rc1",
"1.99.1",
"1.100",
"1.100.1"
);
}
@Test
public void testCompareSnapshot() {
assertOrder(
"90w01a",
"90w01b",
"90w01e",
"90w01~",
"90w02a"
);
}
@Test
public void testCompareMix() {
assertOrder(
"rd-132211",
"rd-161348",
"rd-20090515",
"c0.0.11a",
"c0.0.13a",
"c0.0.13a_03",
"c0.30_01c",
"inf-20100330-1",
"inf-20100330-2",
"inf-20100618",
"a1.0.4",
"a1.0.17_02",
"a1.0.17_04",
"a1.1.0",
"b1.0",
"b1.0_01",
"b1.1_02",
"b1.2",
"b1.8.1",
"0.0",
"1.0",
"11w47a",
"1.1",
"1.5.1",
"2.0",
"1.5.2",
"1.9.2",
"1.RV-Pre1",
"16w14a",
"1.9.3-pre1",
"1.13.2",
"19w13b",
"3D Shareware v1.34",
"19w14a",
"1.14 Pre-Release 1",
"1.14",
"1.15.2",
"20w06a",
"20w14infinite",
"20w22a",
"1.16-pre1",
"1.16",
"1.18.2",
"22w13oneblockatatime",
"22w11a",
"1.19-pre1",
"1.19.4",
"23w13a",
"23w13a_or_b",
"23w14a",
"1.20",
"Unknown",
"100.0"
);
}
@Test
public void testCompareUnknown() {
assertOrder(
"23w35a",
"1.20.2-pre1",
"1.20.2-rc1",
"1.20.2",
"23w35b", // fictional version number
"23w40a"
);
assertOrder(
"1.20.4",
"24w04a",
"1.100" // fictional version number
);
assertOrder(
"1.19.4",
"23w18a", // fictional version number
"1.19.5",
"1.20"
);
assertOrder(
"1.0",
"10w47a", // fictional version number
"11w47a",
"1.1"
);
}
}

View File

@@ -9,43 +9,46 @@ public class VersionRangeTest {
@Test
public void testContains() {
assertTrue(between("10", "20").contains("10"));
assertTrue(between("10", "20").contains("15"));
assertTrue(between("10", "20").contains("20"));
assertFalse(between("10", "20").contains("5"));
assertFalse(between("10", "20").contains("25"));
VersionRange<VersionNumber> empty = VersionRange.empty();
VersionRange<VersionNumber> all = all();
assertTrue(between("10", "10").contains("10"));
assertFalse(between("10", "10").contains("5"));
assertFalse(between("10", "10").contains("15"));
assertTrue(VersionNumber.between("10", "20").contains(VersionNumber.asVersion("10")));
assertTrue(VersionNumber.between("10", "20").contains(VersionNumber.asVersion("15")));
assertTrue(VersionNumber.between("10", "20").contains(VersionNumber.asVersion("20")));
assertFalse(VersionNumber.between("10", "20").contains(VersionNumber.asVersion("5")));
assertFalse(VersionNumber.between("10", "20").contains(VersionNumber.asVersion("25")));
assertTrue(atLeast("10").contains("10"));
assertTrue(atLeast("10").contains("20"));
assertFalse(atLeast("10").contains("5"));
assertTrue(VersionNumber.between("10", "10").contains(VersionNumber.asVersion("10")));
assertFalse(VersionNumber.between("10", "10").contains(VersionNumber.asVersion("5")));
assertFalse(VersionNumber.between("10", "10").contains(VersionNumber.asVersion("15")));
assertTrue(atMost("10").contains("10"));
assertTrue(atMost("10").contains("5"));
assertFalse(atMost("10").contains("20"));
assertTrue(VersionNumber.atLeast("10").contains(VersionNumber.asVersion("10")));
assertTrue(VersionNumber.atLeast("10").contains(VersionNumber.asVersion("20")));
assertFalse(VersionNumber.atLeast("10").contains(VersionNumber.asVersion("5")));
assertFalse(empty().contains("0"));
assertFalse(empty().contains("10"));
assertTrue(VersionNumber.atMost("10").contains(VersionNumber.asVersion("10")));
assertTrue(VersionNumber.atMost("10").contains(VersionNumber.asVersion("5")));
assertFalse(VersionNumber.atMost("10").contains(VersionNumber.asVersion("20")));
assertTrue(all().contains("0"));
assertTrue(all().contains("10"));
assertFalse(empty.contains(VersionNumber.asVersion("0")));
assertFalse(empty.contains(VersionNumber.asVersion("10")));
assertFalse(all().contains((String) null));
assertFalse(empty().contains((String) null));
assertFalse(between("0", "10").contains((String) null));
assertFalse(atLeast("10").contains((String) null));
assertFalse(atMost("10").contains((String) null));
assertFalse(all().contains((VersionNumber) null));
assertFalse(empty().contains((VersionNumber) null));
assertFalse(between("0", "10").contains((VersionNumber) null));
assertFalse(atLeast("10").contains((VersionNumber) null));
assertFalse(atMost("10").contains((VersionNumber) null));
assertTrue(all.contains(VersionNumber.asVersion("0")));
assertTrue(all.contains(VersionNumber.asVersion("10")));
assertFalse(all.contains(null));
assertFalse(empty.contains( null));
assertFalse(VersionNumber.between("0", "10").contains(null));
assertFalse(VersionNumber.atLeast("10").contains(null));
assertFalse(VersionNumber.atMost("10").contains(null));
assertFalse(all.contains(null));
assertFalse(empty.contains(null));
assertFalse(VersionNumber.between("0", "10").contains(null));
assertFalse(VersionNumber.atLeast("10").contains(null));
assertFalse(VersionNumber.atMost("10").contains(null));
}
private static void assertIsOverlappedBy(boolean value, VersionRange range1, VersionRange range2) {
private static void assertIsOverlappedBy(boolean value, VersionRange<VersionNumber> range1, VersionRange<VersionNumber> range2) {
assertEquals(value, range1.isOverlappedBy(range2));
assertEquals(value, range2.isOverlappedBy(range1));
}
@@ -56,38 +59,38 @@ public class VersionRangeTest {
assertIsOverlappedBy(false, all(), empty());
assertIsOverlappedBy(false, empty(), empty());
assertIsOverlappedBy(true, all(), between("10", "20"));
assertIsOverlappedBy(true, all(), atLeast("10"));
assertIsOverlappedBy(true, all(), atMost("10"));
assertIsOverlappedBy(true, all(), VersionNumber.between("10", "20"));
assertIsOverlappedBy(true, all(), VersionNumber.atLeast("10"));
assertIsOverlappedBy(true, all(), VersionNumber.atMost("10"));
assertIsOverlappedBy(false, empty(), between("10", "20"));
assertIsOverlappedBy(false, empty(), atLeast("10"));
assertIsOverlappedBy(false, empty(), atMost("10"));
assertIsOverlappedBy(false, empty(), VersionNumber.between("10", "20"));
assertIsOverlappedBy(false, empty(), VersionNumber.atLeast("10"));
assertIsOverlappedBy(false, empty(), VersionNumber.atMost("10"));
assertIsOverlappedBy(true, between("10", "20"), between("10", "20"));
assertIsOverlappedBy(true, between("10", "20"), between("5", "20"));
assertIsOverlappedBy(true, between("10", "20"), between("5", "15"));
assertIsOverlappedBy(true, between("10", "20"), between("5", "10"));
assertIsOverlappedBy(false, between("10", "20"), between("5", "5"));
assertIsOverlappedBy(true, between("10", "20"), between("10", "30"));
assertIsOverlappedBy(true, between("10", "20"), between("15", "30"));
assertIsOverlappedBy(true, between("10", "20"), between("20", "30"));
assertIsOverlappedBy(false, between("10", "20"), between("21", "30"));
assertIsOverlappedBy(true, between("10", "20"), atLeast("5"));
assertIsOverlappedBy(true, between("10", "20"), atLeast("10"));
assertIsOverlappedBy(true, between("10", "20"), atLeast("15"));
assertIsOverlappedBy(true, between("10", "20"), atLeast("20"));
assertIsOverlappedBy(false, between("10", "20"), atLeast("25"));
assertIsOverlappedBy(true, VersionNumber.between("10", "20"), VersionNumber.between("10", "20"));
assertIsOverlappedBy(true, VersionNumber.between("10", "20"), VersionNumber.between("5", "20"));
assertIsOverlappedBy(true, VersionNumber.between("10", "20"), VersionNumber.between("5", "15"));
assertIsOverlappedBy(true, VersionNumber.between("10", "20"), VersionNumber.between("5", "10"));
assertIsOverlappedBy(false, VersionNumber.between("10", "20"), VersionNumber.between("5", "5"));
assertIsOverlappedBy(true, VersionNumber.between("10", "20"), VersionNumber.between("10", "30"));
assertIsOverlappedBy(true, VersionNumber.between("10", "20"), VersionNumber.between("15", "30"));
assertIsOverlappedBy(true, VersionNumber.between("10", "20"), VersionNumber.between("20", "30"));
assertIsOverlappedBy(false, VersionNumber.between("10", "20"), VersionNumber.between("21", "30"));
assertIsOverlappedBy(true, VersionNumber.between("10", "20"), VersionNumber.atLeast("5"));
assertIsOverlappedBy(true, VersionNumber.between("10", "20"), VersionNumber.atLeast("10"));
assertIsOverlappedBy(true, VersionNumber.between("10", "20"), VersionNumber.atLeast("15"));
assertIsOverlappedBy(true, VersionNumber.between("10", "20"), VersionNumber.atLeast("20"));
assertIsOverlappedBy(false, VersionNumber.between("10", "20"), VersionNumber.atLeast("25"));
assertIsOverlappedBy(true, atLeast("10"), atLeast("10"));
assertIsOverlappedBy(true, atLeast("10"), atLeast("20"));
assertIsOverlappedBy(true, atLeast("10"), atLeast("5"));
assertIsOverlappedBy(true, atLeast("10"), atMost("10"));
assertIsOverlappedBy(true, atLeast("10"), atMost("20"));
assertIsOverlappedBy(false, atLeast("10"), atMost("5"));
assertIsOverlappedBy(true, VersionNumber.atLeast("10"), VersionNumber.atLeast("10"));
assertIsOverlappedBy(true, VersionNumber.atLeast("10"), VersionNumber.atLeast("20"));
assertIsOverlappedBy(true, VersionNumber.atLeast("10"), VersionNumber.atLeast("5"));
assertIsOverlappedBy(true, VersionNumber.atLeast("10"), VersionNumber.atMost("10"));
assertIsOverlappedBy(true, VersionNumber.atLeast("10"), VersionNumber.atMost("20"));
assertIsOverlappedBy(false, VersionNumber.atLeast("10"), VersionNumber.atMost("5"));
}
private static void assertIntersectionWith(VersionRange range1, VersionRange range2, VersionRange result) {
private static void assertIntersectionWith(VersionRange<VersionNumber> range1, VersionRange<VersionNumber> range2, VersionRange<VersionNumber> result) {
assertEquals(result, range1.intersectionWith(range2));
assertEquals(result, range2.intersectionWith(range1));
}
@@ -96,35 +99,35 @@ public class VersionRangeTest {
public void testIntersectionWith() {
assertIntersectionWith(all(), all(), all());
assertIntersectionWith(all(), empty(), empty());
assertIntersectionWith(all(), between("10", "20"), between("10", "20"));
assertIntersectionWith(all(), atLeast("10"), atLeast("10"));
assertIntersectionWith(all(), atMost("10"), atMost("10"));
assertIntersectionWith(all(), VersionNumber.between("10", "20"), VersionNumber.between("10", "20"));
assertIntersectionWith(all(), VersionNumber.atLeast("10"), VersionNumber.atLeast("10"));
assertIntersectionWith(all(), VersionNumber.atMost("10"), VersionNumber.atMost("10"));
assertIntersectionWith(empty(), empty(), empty());
assertIntersectionWith(empty(), between("10", "20"), empty());
assertIntersectionWith(empty(), atLeast("10"), empty());
assertIntersectionWith(empty(), atMost("10"), empty());
assertIntersectionWith(empty(), VersionNumber.between("10", "20"), empty());
assertIntersectionWith(empty(), VersionNumber.atLeast("10"), empty());
assertIntersectionWith(empty(), VersionNumber.atMost("10"), empty());
assertIntersectionWith(between("10", "20"), between("10", "20"), between("10", "20"));
assertIntersectionWith(between("10", "20"), between("5", "20"), between("10", "20"));
assertIntersectionWith(between("10", "20"), between("10", "25"), between("10", "20"));
assertIntersectionWith(between("10", "20"), between("5", "25"), between("10", "20"));
assertIntersectionWith(between("10", "20"), between("15", "20"), between("15", "20"));
assertIntersectionWith(between("10", "20"), between("10", "15"), between("10", "15"));
assertIntersectionWith(between("10", "20"), between("14", "16"), between("14", "16"));
assertIntersectionWith(between("10", "20"), atLeast("5"), between("10", "20"));
assertIntersectionWith(between("10", "20"), atLeast("10"), between("10", "20"));
assertIntersectionWith(between("10", "20"), atLeast("15"), between("15", "20"));
assertIntersectionWith(between("10", "20"), atLeast("20"), between("20", "20"));
assertIntersectionWith(between("10", "20"), atLeast("25"), empty());
assertIntersectionWith(between("10", "20"), atMost("25"), between("10", "20"));
assertIntersectionWith(between("10", "20"), atMost("20"), between("10", "20"));
assertIntersectionWith(between("10", "20"), atMost("15"), between("10", "15"));
assertIntersectionWith(between("10", "20"), atMost("10"), between("10", "10"));
assertIntersectionWith(between("10", "20"), atMost("5"), empty());
assertIntersectionWith(VersionNumber.between("10", "20"), VersionNumber.between("10", "20"), VersionNumber.between("10", "20"));
assertIntersectionWith(VersionNumber.between("10", "20"), VersionNumber.between("5", "20"), VersionNumber.between("10", "20"));
assertIntersectionWith(VersionNumber.between("10", "20"), VersionNumber.between("10", "25"), VersionNumber.between("10", "20"));
assertIntersectionWith(VersionNumber.between("10", "20"), VersionNumber.between("5", "25"), VersionNumber.between("10", "20"));
assertIntersectionWith(VersionNumber.between("10", "20"), VersionNumber.between("15", "20"), VersionNumber.between("15", "20"));
assertIntersectionWith(VersionNumber.between("10", "20"), VersionNumber.between("10", "15"), VersionNumber.between("10", "15"));
assertIntersectionWith(VersionNumber.between("10", "20"), VersionNumber.between("14", "16"), VersionNumber.between("14", "16"));
assertIntersectionWith(VersionNumber.between("10", "20"), VersionNumber.atLeast("5"), VersionNumber.between("10", "20"));
assertIntersectionWith(VersionNumber.between("10", "20"), VersionNumber.atLeast("10"), VersionNumber.between("10", "20"));
assertIntersectionWith(VersionNumber.between("10", "20"), VersionNumber.atLeast("15"), VersionNumber.between("15", "20"));
assertIntersectionWith(VersionNumber.between("10", "20"), VersionNumber.atLeast("20"), VersionNumber.between("20", "20"));
assertIntersectionWith(VersionNumber.between("10", "20"), VersionNumber.atLeast("25"), empty());
assertIntersectionWith(VersionNumber.between("10", "20"), VersionNumber.atMost("25"), VersionNumber.between("10", "20"));
assertIntersectionWith(VersionNumber.between("10", "20"), VersionNumber.atMost("20"), VersionNumber.between("10", "20"));
assertIntersectionWith(VersionNumber.between("10", "20"), VersionNumber.atMost("15"), VersionNumber.between("10", "15"));
assertIntersectionWith(VersionNumber.between("10", "20"), VersionNumber.atMost("10"), VersionNumber.between("10", "10"));
assertIntersectionWith(VersionNumber.between("10", "20"), VersionNumber.atMost("5"), empty());
assertIntersectionWith(atLeast("10"), atMost("10"), between("10", "10"));
assertIntersectionWith(atLeast("10"), atMost("20"), between("10", "20"));
assertIntersectionWith(atLeast("10"), atMost("5"), empty());
assertIntersectionWith(VersionNumber.atLeast("10"), VersionNumber.atMost("10"), VersionNumber.between("10", "10"));
assertIntersectionWith(VersionNumber.atLeast("10"), VersionNumber.atMost("20"), VersionNumber.between("10", "20"));
assertIntersectionWith(VersionNumber.atLeast("10"), VersionNumber.atMost("5"), empty());
}
}