Skip to content

Commit 455475a

Browse files
committed
New versioning API
To be used in server version detection and version specific handlers
1 parent 6f8d1d3 commit 455475a

File tree

3 files changed

+283
-0
lines changed

3 files changed

+283
-0
lines changed

common/build.gradle.kts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,18 @@ dependencies {
1212

1313
// Use it for contracts and unmodifiability annotations
1414
api("org.jetbrains:annotations:26.0.2")
15+
16+
// Testing dependencies
17+
testImplementation("org.junit.jupiter:junit-jupiter:6.0.2")
18+
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
19+
}
20+
21+
tasks.named<Test>("test") {
22+
useJUnitPlatform()
23+
24+
maxHeapSize = "1G"
25+
26+
testLogging {
27+
events("passed")
28+
}
1529
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package com.leonardobishop.quests.common.versioning;
2+
3+
import org.jspecify.annotations.NullMarked;
4+
import org.jspecify.annotations.Nullable;
5+
6+
import java.util.Arrays;
7+
import java.util.Objects;
8+
9+
@NullMarked
10+
public final class Version implements Comparable<Version> {
11+
12+
private final @Nullable String preRelease;
13+
private final @Nullable String buildMetaData;
14+
private final int[] versionParts;
15+
16+
public Version(final @Nullable String preRelease, final @Nullable String buildMetaData, final int... versionParts) {
17+
this.preRelease = preRelease;
18+
this.buildMetaData = buildMetaData;
19+
this.versionParts = versionParts;
20+
}
21+
22+
public static Version fromString(final String str) {
23+
final int minusIndex = str.indexOf('-');
24+
final int plusIndex = str.indexOf('+', minusIndex + 1);
25+
26+
final String preRelease = minusIndex != -1
27+
? str.substring(minusIndex + 1, plusIndex != -1 ? plusIndex : str.length())
28+
: null;
29+
30+
final String buildMetaData = plusIndex != -1
31+
? str.substring(plusIndex + 1)
32+
: null;
33+
34+
final int optionalIndex = minusIndex != -1 ? minusIndex : plusIndex;
35+
final String versionCore = optionalIndex != -1 ? str.substring(0, optionalIndex) : str;
36+
final String[] stringVersionParts = versionCore.split("\\.");
37+
final int[] versionParts = new int[stringVersionParts.length];
38+
39+
for (int i = 0; i < stringVersionParts.length; i++) {
40+
final String stringVersionPart = stringVersionParts[i];
41+
final int versionPart;
42+
43+
try {
44+
versionPart = Integer.parseUnsignedInt(stringVersionPart);
45+
} catch (final NumberFormatException e) {
46+
throw new IllegalArgumentException("Unparsable version part: '" + stringVersionPart + "'");
47+
}
48+
49+
versionParts[i] = versionPart;
50+
}
51+
52+
return new Version(preRelease, buildMetaData, versionParts);
53+
}
54+
55+
@SuppressWarnings("PointlessArithmeticExpression")
56+
@Override
57+
public int compareTo(final Version other) {
58+
final int commonLength = Math.min(this.versionParts.length, other.versionParts.length);
59+
60+
for (int i = 0; i < commonLength; i++) {
61+
final int diff = this.versionParts[i] - other.versionParts[i];
62+
63+
if (diff != 0) {
64+
return diff;
65+
}
66+
}
67+
68+
for (int i = commonLength; i < this.versionParts.length; i++) {
69+
final int diff = this.versionParts[i] - 0;
70+
71+
if (diff != 0) {
72+
return diff;
73+
}
74+
}
75+
76+
for (int i = commonLength; i < other.versionParts.length; i++) {
77+
final int diff = 0 - other.versionParts[i];
78+
79+
if (diff != 0) {
80+
return diff;
81+
}
82+
}
83+
84+
return 0;
85+
}
86+
87+
@Override
88+
public int hashCode() {
89+
return Objects.hash(this.preRelease, this.buildMetaData, Arrays.hashCode(this.versionParts));
90+
}
91+
92+
@Override
93+
public boolean equals(final Object other) {
94+
if (other == null || this.getClass() != other.getClass()) {
95+
return false;
96+
}
97+
98+
final Version otherVersion = (Version) other;
99+
100+
return Objects.equals(this.preRelease, otherVersion.preRelease)
101+
&& Objects.equals(this.buildMetaData, otherVersion.buildMetaData)
102+
&& Objects.deepEquals(this.versionParts, otherVersion.versionParts);
103+
}
104+
105+
@Override
106+
public String toString() {
107+
final StringBuilder builder = new StringBuilder();
108+
109+
for (int i = 0; i < this.versionParts.length; i++) {
110+
builder.append(this.versionParts[i]);
111+
112+
if (i != this.versionParts.length - 1) {
113+
builder.append('.');
114+
}
115+
}
116+
117+
if (this.preRelease != null) {
118+
builder.append('-');
119+
builder.append(this.preRelease);
120+
}
121+
122+
if (this.buildMetaData != null) {
123+
builder.append('+');
124+
builder.append(this.buildMetaData);
125+
}
126+
127+
return builder.toString();
128+
}
129+
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import com.leonardobishop.quests.common.versioning.Version;
2+
import org.junit.jupiter.api.Test;
3+
4+
import static org.junit.jupiter.api.Assertions.assertEquals;
5+
6+
public final class VersionTest {
7+
8+
@Test
9+
public void oldVersioning() {
10+
assertEquals("1.8-R0.1-SNAPSHOT", Version.fromString("1.8-R0.1-SNAPSHOT").toString());
11+
assertEquals("1.8.3-R0.1-SNAPSHOT", Version.fromString("1.8.3-R0.1-SNAPSHOT").toString());
12+
assertEquals("1.8.4-R0.1-SNAPSHOT", Version.fromString("1.8.4-R0.1-SNAPSHOT").toString());
13+
assertEquals("1.8.5-R0.1-SNAPSHOT", Version.fromString("1.8.5-R0.1-SNAPSHOT").toString());
14+
assertEquals("1.8.6-R0.1-SNAPSHOT", Version.fromString("1.8.6-R0.1-SNAPSHOT").toString());
15+
assertEquals("1.8.7-R0.1-SNAPSHOT", Version.fromString("1.8.7-R0.1-SNAPSHOT").toString());
16+
assertEquals("1.8.8-R0.1-SNAPSHOT", Version.fromString("1.8.8-R0.1-SNAPSHOT").toString());
17+
assertEquals("1.9-R0.1-SNAPSHOT", Version.fromString("1.9-R0.1-SNAPSHOT").toString());
18+
assertEquals("1.9.2-R0.1-SNAPSHOT", Version.fromString("1.9.2-R0.1-SNAPSHOT").toString());
19+
assertEquals("1.9.4-R0.1-SNAPSHOT", Version.fromString("1.9.4-R0.1-SNAPSHOT").toString());
20+
assertEquals("1.10-R0.1-SNAPSHOT", Version.fromString("1.10-R0.1-SNAPSHOT").toString());
21+
assertEquals("1.10.2-R0.1-SNAPSHOT", Version.fromString("1.10.2-R0.1-SNAPSHOT").toString());
22+
assertEquals("1.11-R0.1-SNAPSHOT", Version.fromString("1.11-R0.1-SNAPSHOT").toString());
23+
assertEquals("1.11.1-R0.1-SNAPSHOT", Version.fromString("1.11.1-R0.1-SNAPSHOT").toString());
24+
assertEquals("1.11.2-R0.1-SNAPSHOT", Version.fromString("1.11.2-R0.1-SNAPSHOT").toString());
25+
assertEquals("1.12-pre2-SNAPSHOT", Version.fromString("1.12-pre2-SNAPSHOT").toString());
26+
assertEquals("1.12-pre5-SNAPSHOT", Version.fromString("1.12-pre5-SNAPSHOT").toString());
27+
assertEquals("1.12-pre6-SNAPSHOT", Version.fromString("1.12-pre6-SNAPSHOT").toString());
28+
assertEquals("1.12-R0.1-SNAPSHOT", Version.fromString("1.12-R0.1-SNAPSHOT").toString());
29+
assertEquals("1.12.1-R0.1-SNAPSHOT", Version.fromString("1.12.1-R0.1-SNAPSHOT").toString());
30+
assertEquals("1.12.2-R0.1-SNAPSHOT", Version.fromString("1.12.2-R0.1-SNAPSHOT").toString());
31+
assertEquals("1.13-pre7-R0.1-SNAPSHOT", Version.fromString("1.13-pre7-R0.1-SNAPSHOT").toString());
32+
assertEquals("1.13-R0.1-SNAPSHOT", Version.fromString("1.13-R0.1-SNAPSHOT").toString());
33+
assertEquals("1.13.1-R0.1-SNAPSHOT", Version.fromString("1.13.1-R0.1-SNAPSHOT").toString());
34+
assertEquals("1.13.2-R0.1-SNAPSHOT", Version.fromString("1.13.2-R0.1-SNAPSHOT").toString());
35+
assertEquals("1.14-pre5-SNAPSHOT", Version.fromString("1.14-pre5-SNAPSHOT").toString());
36+
assertEquals("1.14-R0.1-SNAPSHOT", Version.fromString("1.14-R0.1-SNAPSHOT").toString());
37+
assertEquals("1.14.1-R0.1-SNAPSHOT", Version.fromString("1.14.1-R0.1-SNAPSHOT").toString());
38+
assertEquals("1.14.2-R0.1-SNAPSHOT", Version.fromString("1.14.2-R0.1-SNAPSHOT").toString());
39+
assertEquals("1.14.3-SNAPSHOT", Version.fromString("1.14.3-SNAPSHOT").toString());
40+
assertEquals("1.14.3-pre4-SNAPSHOT", Version.fromString("1.14.3-pre4-SNAPSHOT").toString());
41+
assertEquals("1.14.3-R0.1-SNAPSHOT", Version.fromString("1.14.3-R0.1-SNAPSHOT").toString());
42+
assertEquals("1.14.4-R0.1-SNAPSHOT", Version.fromString("1.14.4-R0.1-SNAPSHOT").toString());
43+
assertEquals("1.15-R0.1-SNAPSHOT", Version.fromString("1.15-R0.1-SNAPSHOT").toString());
44+
assertEquals("1.15.1-R0.1-SNAPSHOT", Version.fromString("1.15.1-R0.1-SNAPSHOT").toString());
45+
assertEquals("1.15.2-R0.1-SNAPSHOT", Version.fromString("1.15.2-R0.1-SNAPSHOT").toString());
46+
assertEquals("1.16.1-R0.1-SNAPSHOT", Version.fromString("1.16.1-R0.1-SNAPSHOT").toString());
47+
assertEquals("1.16.2-R0.1-SNAPSHOT", Version.fromString("1.16.2-R0.1-SNAPSHOT").toString());
48+
assertEquals("1.16.3-R0.1-SNAPSHOT", Version.fromString("1.16.3-R0.1-SNAPSHOT").toString());
49+
assertEquals("1.16.4-R0.1-SNAPSHOT", Version.fromString("1.16.4-R0.1-SNAPSHOT").toString());
50+
assertEquals("1.16.5-R0.1-SNAPSHOT", Version.fromString("1.16.5-R0.1-SNAPSHOT").toString());
51+
assertEquals("1.17-R0.1-SNAPSHOT", Version.fromString("1.17-R0.1-SNAPSHOT").toString());
52+
assertEquals("1.17.1-R0.1-SNAPSHOT", Version.fromString("1.17.1-R0.1-SNAPSHOT").toString());
53+
assertEquals("1.18-rc3-R0.1-SNAPSHOT", Version.fromString("1.18-rc3-R0.1-SNAPSHOT").toString());
54+
assertEquals("1.18-pre5-R0.1-SNAPSHOT", Version.fromString("1.18-pre5-R0.1-SNAPSHOT").toString());
55+
assertEquals("1.18-pre8-R0.1-SNAPSHOT", Version.fromString("1.18-pre8-R0.1-SNAPSHOT").toString());
56+
assertEquals("1.18-R0.1-SNAPSHOT", Version.fromString("1.18-R0.1-SNAPSHOT").toString());
57+
assertEquals("1.18.1-R0.1-SNAPSHOT", Version.fromString("1.18.1-R0.1-SNAPSHOT").toString());
58+
assertEquals("1.18.2-R0.1-SNAPSHOT", Version.fromString("1.18.2-R0.1-SNAPSHOT").toString());
59+
assertEquals("1.19-R0.1-SNAPSHOT", Version.fromString("1.19-R0.1-SNAPSHOT").toString());
60+
assertEquals("1.19.1-R0.1-SNAPSHOT", Version.fromString("1.19.1-R0.1-SNAPSHOT").toString());
61+
assertEquals("1.19.2-R0.1-SNAPSHOT", Version.fromString("1.19.2-R0.1-SNAPSHOT").toString());
62+
assertEquals("1.19.3-R0.1-SNAPSHOT", Version.fromString("1.19.3-R0.1-SNAPSHOT").toString());
63+
assertEquals("1.19.4-R0.1-SNAPSHOT", Version.fromString("1.19.4-R0.1-SNAPSHOT").toString());
64+
assertEquals("1.20-R0.1-SNAPSHOT", Version.fromString("1.20-R0.1-SNAPSHOT").toString());
65+
assertEquals("1.20.1-experimental-SNAPSHOT", Version.fromString("1.20.1-experimental-SNAPSHOT").toString());
66+
assertEquals("1.20.1-R0.1-SNAPSHOT", Version.fromString("1.20.1-R0.1-SNAPSHOT").toString());
67+
assertEquals("1.20.2-experimental-SNAPSHOT", Version.fromString("1.20.2-experimental-SNAPSHOT").toString());
68+
assertEquals("1.20.2-R0.1-SNAPSHOT", Version.fromString("1.20.2-R0.1-SNAPSHOT").toString());
69+
assertEquals("1.20.3-R0.1-SNAPSHOT", Version.fromString("1.20.3-R0.1-SNAPSHOT").toString());
70+
assertEquals("1.20.4-experimental-SNAPSHOT", Version.fromString("1.20.4-experimental-SNAPSHOT").toString());
71+
assertEquals("1.20.4-R0.1-SNAPSHOT", Version.fromString("1.20.4-R0.1-SNAPSHOT").toString());
72+
assertEquals("1.20.5-R0.1-SNAPSHOT", Version.fromString("1.20.5-R0.1-SNAPSHOT").toString());
73+
assertEquals("1.20.6-experimental-SNAPSHOT", Version.fromString("1.20.6-experimental-SNAPSHOT").toString());
74+
assertEquals("1.20.6-R0.1-SNAPSHOT", Version.fromString("1.20.6-R0.1-SNAPSHOT").toString());
75+
assertEquals("1.21-R0.1-SNAPSHOT", Version.fromString("1.21-R0.1-SNAPSHOT").toString());
76+
assertEquals("1.21.1-R0.1-SNAPSHOT", Version.fromString("1.21.1-R0.1-SNAPSHOT").toString());
77+
assertEquals("1.21.2-R0.1-SNAPSHOT", Version.fromString("1.21.2-R0.1-SNAPSHOT").toString());
78+
assertEquals("1.21.3-R0.1-SNAPSHOT", Version.fromString("1.21.3-R0.1-SNAPSHOT").toString());
79+
assertEquals("1.21.4-R0.1-SNAPSHOT", Version.fromString("1.21.4-R0.1-SNAPSHOT").toString());
80+
assertEquals("1.21.5-no-moonrise-SNAPSHOT", Version.fromString("1.21.5-no-moonrise-SNAPSHOT").toString());
81+
assertEquals("1.21.5-R0.1-SNAPSHOT", Version.fromString("1.21.5-R0.1-SNAPSHOT").toString());
82+
assertEquals("1.21.6-R0.1-SNAPSHOT", Version.fromString("1.21.6-R0.1-SNAPSHOT").toString());
83+
assertEquals("1.21.7-R0.1-SNAPSHOT", Version.fromString("1.21.7-R0.1-SNAPSHOT").toString());
84+
assertEquals("1.21.8-R0.1-SNAPSHOT", Version.fromString("1.21.8-R0.1-SNAPSHOT").toString());
85+
assertEquals("1.21.9-pre2-R0.1-SNAPSHOT", Version.fromString("1.21.9-pre2-R0.1-SNAPSHOT").toString());
86+
assertEquals("1.21.9-pre3-R0.1-SNAPSHOT", Version.fromString("1.21.9-pre3-R0.1-SNAPSHOT").toString());
87+
assertEquals("1.21.9-pre4-R0.1-SNAPSHOT", Version.fromString("1.21.9-pre4-R0.1-SNAPSHOT").toString());
88+
assertEquals("1.21.9-rc1-R0.1-SNAPSHOT", Version.fromString("1.21.9-rc1-R0.1-SNAPSHOT").toString());
89+
assertEquals("1.21.9-R0.1-SNAPSHOT", Version.fromString("1.21.9-R0.1-SNAPSHOT").toString());
90+
assertEquals("1.21.10-R0.1-SNAPSHOT", Version.fromString("1.21.10-R0.1-SNAPSHOT").toString());
91+
assertEquals("1.21.11-pre3-R0.1-SNAPSHOT", Version.fromString("1.21.11-pre3-R0.1-SNAPSHOT").toString());
92+
assertEquals("1.21.11-pre4-R0.1-SNAPSHOT", Version.fromString("1.21.11-pre4-R0.1-SNAPSHOT").toString());
93+
assertEquals("1.21.11-pre5-R0.1-SNAPSHOT", Version.fromString("1.21.11-pre5-R0.1-SNAPSHOT").toString());
94+
assertEquals("1.21.11-rc1-R0.1-SNAPSHOT", Version.fromString("1.21.11-rc1-R0.1-SNAPSHOT").toString());
95+
assertEquals("1.21.11-rc2-R0.1-SNAPSHOT", Version.fromString("1.21.11-rc2-R0.1-SNAPSHOT").toString());
96+
assertEquals("1.21.11-rc3-R0.1-SNAPSHOT", Version.fromString("1.21.11-rc3-R0.1-SNAPSHOT").toString());
97+
assertEquals("1.21.11-R0.1-SNAPSHOT", Version.fromString("1.21.11-R0.1-SNAPSHOT").toString());
98+
}
99+
100+
@Test
101+
void weirdVersioning() {
102+
// To ensure future compatibility no matter what monster the come up with
103+
104+
assertEquals("26", Version.fromString("26").toString());
105+
assertEquals("26-SNAPSHOT", Version.fromString("26-SNAPSHOT").toString());
106+
assertEquals("26-R0.1-SNAPSHOT", Version.fromString("26-R0.1-SNAPSHOT").toString());
107+
108+
assertEquals("26.0", Version.fromString("26.0").toString());
109+
assertEquals("26.0-SNAPSHOT", Version.fromString("26.0-SNAPSHOT").toString());
110+
assertEquals("26.0-R0.1-SNAPSHOT", Version.fromString("26.0-R0.1-SNAPSHOT").toString());
111+
112+
assertEquals("26.1", Version.fromString("26.1").toString());
113+
assertEquals("26.1-SNAPSHOT", Version.fromString("26.1-SNAPSHOT").toString());
114+
assertEquals("26.1-R0.1-SNAPSHOT", Version.fromString("26.1-R0.1-SNAPSHOT").toString());
115+
116+
assertEquals("26.1.0", Version.fromString("26.1.0").toString());
117+
assertEquals("26.1.0-SNAPSHOT", Version.fromString("26.1.0-SNAPSHOT").toString());
118+
assertEquals("26.1.0-R0.1-SNAPSHOT", Version.fromString("26.1.0-R0.1-SNAPSHOT").toString());
119+
120+
assertEquals("26.1.1", Version.fromString("26.1.1").toString());
121+
assertEquals("26.1.1-SNAPSHOT", Version.fromString("26.1.1-SNAPSHOT").toString());
122+
assertEquals("26.1.1-R0.1-SNAPSHOT", Version.fromString("26.1.1-R0.1-SNAPSHOT").toString());
123+
124+
assertEquals("26.1.1.0", Version.fromString("26.1.1.0").toString());
125+
assertEquals("26.1.1.0-SNAPSHOT", Version.fromString("26.1.1.0-SNAPSHOT").toString());
126+
assertEquals("26.1.1.0-R0.1-SNAPSHOT", Version.fromString("26.1.1.0-R0.1-SNAPSHOT").toString());
127+
128+
assertEquals("26.1.1.1", Version.fromString("26.1.1.1").toString());
129+
assertEquals("26.1.1.1-SNAPSHOT", Version.fromString("26.1.1.1-SNAPSHOT").toString());
130+
assertEquals("26.1.1.1-R0.1-SNAPSHOT", Version.fromString("26.1.1.1-R0.1-SNAPSHOT").toString());
131+
}
132+
133+
@Test
134+
void compareTo() {
135+
assertEquals(0, Version.fromString("26.1.2.3.000.0.00000.0").compareTo(Version.fromString("26.1.2.3")));
136+
assertEquals(-1, Version.fromString("26.0.0").compareTo(Version.fromString("26.1")));
137+
assertEquals(3, Version.fromString("26.3.0").compareTo(Version.fromString("26")));
138+
assertEquals(-5, Version.fromString("26.0.5").compareTo(Version.fromString("26.5.0")));
139+
}
140+
}

0 commit comments

Comments
 (0)