Skip to content

Commit 3af8373

Browse files
committed
Support empty lower and upper bounds in P2 VersionRange
This enables support for version range specifications where the lower or upper bound is not specified and the delimiting bracket is directly next to the separating colon. For example '[1,)' or '(,1]' but also '(,)' can then be parsed successfully. The type of supported brackets for an empty or unspecified bound is something that's not inherently obvious. From a mathematical perspective an empty bound can be considered equivalent to infinity. And in math may not say inclusive infinity. From that perspective only '[1,infinity)' respectively '[1,)' would be permitted, but not '[1,]'. But technically infinity has a specific value for P2 versions, i.e. Version.MAX_VERSION. So if one really wants to cover all possible values, the upper bound still has to be inclusive, i.e. ']'. For the lower bound the situation is similar, where '0.0.0' or the 'empty'-version is the smallest one possible.
1 parent 3388118 commit 3af8373

File tree

4 files changed

+86
-10
lines changed

4 files changed

+86
-10
lines changed

bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/VersionRange.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,11 @@ public VersionRange(String versionRange) {
157157
} else {
158158
fmt = VersionFormat.OSGI_FORMAT;
159159
}
160-
String minStr;
161-
String maxStr;
160+
final String minStr;
161+
final String maxStr;
162162
StringBuilder sb = new StringBuilder();
163163
if (c == '[' || c == '(') {
164-
includeMin = (c == '[');
164+
boolean isClosedBound = c == '[';
165165
pos = copyEscaped(versionRange, ++pos, ",)]", sb); //$NON-NLS-1$
166166
if (pos >= top) {
167167
throw new IllegalArgumentException(NLS.bind(Messages.premature_EOS_0, versionRange));
@@ -171,6 +171,7 @@ public VersionRange(String versionRange) {
171171
throw new IllegalArgumentException(NLS.bind(Messages.missing_comma_in_range_0, versionRange));
172172
}
173173
minStr = sb.toString();
174+
includeMin = isClosedBound || minStr.isEmpty();
174175
sb.setLength(0);
175176
pos = copyEscaped(versionRange, pos, ")]", sb); //$NON-NLS-1$
176177
if (pos >= top) {
@@ -179,7 +180,7 @@ public VersionRange(String versionRange) {
179180
maxStr = sb.toString();
180181

181182
c = versionRange.charAt(pos++);
182-
includeMax = (c == ']');
183+
includeMax = c == ']' || maxStr.isEmpty();
183184
} else {
184185
StringBuilder sbMin = new StringBuilder();
185186
pos = copyEscaped(versionRange, pos, rawPrefix ? "/" : null, sbMin); //$NON-NLS-1$
@@ -248,9 +249,11 @@ public VersionRange(String versionRange) {
248249
}
249250
}
250251
}
251-
minVersion = VersionFormat.parseRaw(minStr, fmt, origMin);
252+
minVersion = minStr.isEmpty() ? Version.emptyVersion : VersionFormat.parseRaw(minStr, fmt, origMin);
252253
if (maxStr != null) {
253-
if (maxStr.equals(minStr)) {
254+
if (maxStr.isEmpty()) {
255+
maxVersion = Version.MAX_VERSION;
256+
} else if (maxStr.equals(minStr)) {
254257
maxVersion = minVersion;
255258
} else {
256259
maxVersion = VersionFormat.parseRaw(maxStr, fmt, origMax);
@@ -262,9 +265,11 @@ public VersionRange(String versionRange) {
262265
if (fmt == null) {
263266
fmt = VersionFormat.OSGI_FORMAT;
264267
}
265-
minVersion = fmt.parse(minStr);
268+
minVersion = minStr.isEmpty() ? Version.emptyVersion : fmt.parse(minStr);
266269
if (maxStr != null) {
267-
if (maxStr.equals(minStr)) {
270+
if (maxStr.isEmpty()) {
271+
maxVersion = Version.MAX_VERSION;
272+
} else if (maxStr.equals(minStr)) {
268273
maxVersion = minVersion;
269274
} else {
270275
maxVersion = fmt.parse(maxStr);

bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/omniVersion/OSGiRangeTest.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2009, 2010 Cloudsmith Inc. and others.
2+
* Copyright (c) 2009, 2024 Cloudsmith Inc. and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -27,6 +27,10 @@
2727
* Tests ranges of versions specified with osgi (default) version format.
2828
*/
2929
public class OSGiRangeTest extends VersionTesting {
30+
31+
private static Version ONE = Version.parseVersion("1");
32+
private static Version TWO = Version.parseVersion("2");
33+
3034
@Test
3135
public void testSingleVersionRange() {
3236
VersionRange range;
@@ -100,6 +104,35 @@ public void testRangeStrings() {
100104
assertEquals("(1.0.0.abcdef,2.0.0.abcdef)", v.toString());
101105
}
102106

107+
@Test
108+
public void testEmptyRange() {
109+
assertBounds("", true, Version.emptyVersion, Version.MAX_VERSION, true);
110+
}
111+
112+
@Test
113+
public void testExplicitLowerAndUpperBound() {
114+
assertBounds("[1,2)", true, ONE, TWO, false);
115+
assertBounds("[1,2]", true, ONE, TWO, true);
116+
}
117+
118+
@Test
119+
public void testNoLowerBound() {
120+
assertBounds("(,1)", true, Version.emptyVersion, ONE, false);
121+
assertBounds("[,1)", true, Version.emptyVersion, ONE, false);
122+
}
123+
124+
@Test
125+
public void testNoUpperBound() {
126+
assertBounds("[1,)", true, ONE, Version.MAX_VERSION, true);
127+
assertBounds("[1,]", true, ONE, Version.MAX_VERSION, true);
128+
}
129+
130+
@Test
131+
public void testNoLowerAndUpperBound() {
132+
assertBounds("(,)", true, Version.emptyVersion, Version.MAX_VERSION, true);
133+
assertBounds("[,]", true, Version.emptyVersion, Version.MAX_VERSION, true);
134+
}
135+
103136
/**
104137
* Tests that null values passed to the {@link VersionRange} constructor are not
105138
* interpreted as MIN/MAX versions.

bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/omniVersion/RawRangeTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
* Tests version ranges specified using raw.
2626
*/
2727
public class RawRangeTest extends VersionTesting {
28+
29+
private static Version ONE = Version.parseVersion("raw:1");
30+
private static Version TWO = Version.parseVersion("raw:2");
31+
2832
@Test
2933
public void testEmptyRange() {
3034
VersionRange range = new VersionRange("raw:''");
@@ -112,6 +116,30 @@ public void testLowerThan() {
112116
assertNotIncludedInRange("1.5", upperBound, "raw:2.1");
113117
}
114118

119+
@Test
120+
public void testExplicitLowerAndUpperBound() {
121+
assertBounds("raw:[1,2)", true, ONE, TWO, false);
122+
assertBounds("raw:[1,2]", true, ONE, TWO, true);
123+
}
124+
125+
@Test
126+
public void testNoLowerBound() {
127+
assertBounds("raw:(,1)", true, Version.emptyVersion, ONE, false);
128+
assertBounds("raw:[,1)", true, Version.emptyVersion, ONE, false);
129+
}
130+
131+
@Test
132+
public void testNoUpperBound() {
133+
assertBounds("raw:[1,)", true, ONE, Version.MAX_VERSION, true);
134+
assertBounds("raw:[1,]", true, ONE, Version.MAX_VERSION, true);
135+
}
136+
137+
@Test
138+
public void testNoLowerAndUpperBound() {
139+
assertBounds("raw:(,)", true, Version.emptyVersion, Version.MAX_VERSION, true);
140+
assertBounds("raw:[,]", true, Version.emptyVersion, Version.MAX_VERSION, true);
141+
}
142+
115143
@Test
116144
public void testSerialize() {
117145
VersionRange v = null;

bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/omniVersion/VersionTesting.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2009, 2017 Cloudsmith Inc. and others.
2+
* Copyright (c) 2009, 2024 Cloudsmith Inc. and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -33,6 +33,7 @@
3333
* Base class for version testing. Adds useful assert methods.
3434
*/
3535
public class VersionTesting {
36+
3637
/**
3738
* Asserts that the versionString version is included in the range.
3839
*/
@@ -47,6 +48,15 @@ public void assertNotIncludedInRange(String message, VersionRange range, String
4748
assertFalse(message, range.isIncluded(Version.parseVersion(versionString)));
4849
}
4950

51+
public void assertBounds(String rangeSpecification, boolean includeMin, Version lowerBound, Version upperBound,
52+
boolean includeMax) {
53+
VersionRange range = new VersionRange(rangeSpecification);
54+
assertEquals(includeMin, range.getIncludeMinimum());
55+
assertEquals(includeMax, range.getIncludeMaximum());
56+
assertEquals(lowerBound, range.getMinimum());
57+
assertEquals(upperBound, range.getMaximum());
58+
}
59+
5060
/**
5161
* A strict assertion of order. asserts that b > a, a < b, a !=b, b != a
5262
*/

0 commit comments

Comments
 (0)