View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau.commons.lang;
18  
19  import static org.junit.jupiter.api.Assertions.*;
20  
21  import org.apache.juneau.*;
22  import org.junit.jupiter.api.*;
23  import org.junit.jupiter.params.*;
24  import org.junit.jupiter.params.provider.*;
25  
26  class VersionRange_Test extends TestBase {
27  
28  	private static final Input[] INPUT = {
29  		/* 00 */ input("1.1", "1.1.3", true),
30  		/* 01 */ input("1.1", "1.1", true),
31  		/* 02 */ input("1.1", "1.1.0", true),
32  		/* 03 */ input("1.1", "1.0", false),
33  		/* 04 */ input("1.1", "1.0.9", false),
34  		/* 05 */ input("[1.0,2.0)", ".9", false),
35  		/* 06 */ input("[1.0,2.0)", "1", true),
36  		/* 07 */ input("[1.0,2.0)", "1.0", true),
37  		/* 08 */ input("[1.0,2.0)", "1.0.0", true),
38  		/* 09 */ input("[1.0,2.0)", "1.1", true),
39  		/* 10 */ input("[1.0,2.0)", "2.0", false),
40  		/* 11 */ input("[1.0,2.0)", "2", false),
41  		/* 12 */ input("(1.0,2.0]", "2", true),
42  		/* 13 */ input("(1.0,2.0]", "2.0", true),
43  		/* 14 */ input("(1.0,2.0]", "2.0.1", true),
44  		/* 15 */ input("(1.0,2.0]", "2.1", false),
45  		/* 16 */ input("(.5.0,.6]", ".5", false),
46  		/* 17 */ input("(.5.0,.6]", ".5.1", true),
47  		/* 18 */ input("(.5.0,.6]", ".6", true),
48  		/* 19 */ input("(.5.0,.6]", ".6.1", true),
49  		/* 20 */ input("(.5.0,.6]", ".7", false),
50  		/* 21 */ input("[1.1,2.0)", "1", false)
51  	};
52  
53  	private static Input input(String range, String version, boolean shouldMatch) {
54  		return new Input(range, version, shouldMatch);
55  	}
56  
57  	private static class Input {
58  		VersionRange range;
59  		String version;
60  		boolean shouldMatch;
61  
62  		public Input(String range, String version, boolean shouldMatch) {
63  			this.version = version;
64  			this.range = new VersionRange(range);
65  			this.shouldMatch = shouldMatch;
66  		}
67  	}
68  
69  	static Input[] input() {
70  		return INPUT;
71  	}
72  
73  	@ParameterizedTest
74  	@MethodSource("input")
75  	void a01_basic(Input input) {
76  		assertEquals(input.shouldMatch, input.range.matches(input.version));
77  	}
78  
79  	//------------------------------------------------------------------------------------------------------------------
80  	// Edge cases - empty strings and whitespace
81  	//------------------------------------------------------------------------------------------------------------------
82  
83  	@Test
84  	void a02_emptyRange() {
85  		var range = new VersionRange("");
86  		assertTrue(range.matches(""));
87  		// Empty range matches everything (both minVersion and maxVersion are null)
88  		assertTrue(range.matches("1.0"));
89  	}
90  
91  	@Test
92  	void a03_whitespaceTrimming() {
93  		var range1 = new VersionRange("  1.0  ");
94  		var range2 = new VersionRange("1.0");
95  		assertTrue(range1.matches("1.0"));
96  		assertTrue(range2.matches("1.0"));
97  		assertTrue(range1.matches("1.1"));
98  		assertTrue(range2.matches("1.1"));
99  
100 		var range3 = new VersionRange("  [1.0,2.0)  ");
101 		assertTrue(range3.matches("1.5"));
102 		assertFalse(range3.matches("2.0"));
103 	}
104 
105 	@Test
106 	void a04_emptyVersionString() {
107 		var range1 = new VersionRange("");
108 		assertTrue(range1.matches(""));
109 		assertTrue(range1.matches(null));  // Empty range matches null (both versions are null)
110 
111 		var range2 = new VersionRange("1.0");
112 		// Empty string is converted to "0" by Version constructor, and "0" is less than "1.0"
113 		assertFalse(range2.matches(""));
114 		assertFalse(range2.matches(null));
115 	}
116 
117 	//------------------------------------------------------------------------------------------------------------------
118 	// Additional range format combinations
119 	//------------------------------------------------------------------------------------------------------------------
120 
121 	@Test
122 	void a05_closedRange() {
123 		var range = new VersionRange("[1.0,2.0]");
124 		assertTrue(range.matches("1.0"));
125 		assertTrue(range.matches("1.5"));
126 		assertTrue(range.matches("2.0"));
127 		assertTrue(range.matches("2.0.1"));
128 		assertFalse(range.matches("0.9"));
129 		assertFalse(range.matches("2.1"));
130 	}
131 
132 	@Test
133 	void a06_openRange() {
134 		var range = new VersionRange("(1.0,2.0)");
135 		assertFalse(range.matches("1.0"));
136 		assertTrue(range.matches("1.5"));
137 		assertFalse(range.matches("2.0"));
138 		assertFalse(range.matches("0.9"));
139 		assertFalse(range.matches("2.1"));
140 	}
141 
142 	@Test
143 	void a07_mixedBrackets() {
144 		var range1 = new VersionRange("[1.0,2.0)");
145 		assertTrue(range1.matches("1.0"));
146 		assertTrue(range1.matches("1.5"));
147 		assertFalse(range1.matches("2.0"));
148 
149 		var range2 = new VersionRange("(1.0,2.0]");
150 		assertFalse(range2.matches("1.0"));
151 		assertTrue(range2.matches("1.5"));
152 		assertTrue(range2.matches("2.0"));
153 	}
154 
155 	@Test
156 	void a08_singleVersionRange() {
157 		var range = new VersionRange("2.0");
158 		assertTrue(range.matches("2.0"));
159 		assertTrue(range.matches("2.1"));
160 		assertTrue(range.matches("3.0"));
161 		assertFalse(range.matches("1.9"));
162 		assertFalse(range.matches("1.9.9"));
163 	}
164 
165 	@Test
166 	void a09_versionWithLeadingDot() {
167 		var range = new VersionRange("[.5,.6]");
168 		assertTrue(range.matches(".5"));
169 		assertTrue(range.matches(".5.1"));
170 		assertTrue(range.matches(".6"));
171 		assertFalse(range.matches(".4"));
172 		assertFalse(range.matches(".7"));
173 	}
174 
175 	//------------------------------------------------------------------------------------------------------------------
176 	// toString() method tests
177 	//------------------------------------------------------------------------------------------------------------------
178 
179 	@Test
180 	void a10_toString() {
181 		// Range format
182 		var range1 = new VersionRange("[1.0,2.0)");
183 		var str1 = range1.toString();
184 		assertTrue(str1.contains("1.0"));
185 		assertTrue(str1.contains("2.0"));
186 		assertTrue(str1.startsWith("["));
187 		assertTrue(str1.endsWith(")"));
188 
189 		var range2 = new VersionRange("(1.0,2.0]");
190 		var str2 = range2.toString();
191 		assertTrue(str2.contains("1.0"));
192 		assertTrue(str2.contains("2.0"));
193 		assertTrue(str2.startsWith("("));
194 		assertTrue(str2.endsWith("]"));
195 
196 		// Single version format (note: toString may have issues with null maxVersion)
197 		var range3 = new VersionRange("1.0");
198 		var str3 = range3.toString();
199 		assertNotNull(str3);
200 	}
201 
202 	//------------------------------------------------------------------------------------------------------------------
203 	// Boundary conditions
204 	//------------------------------------------------------------------------------------------------------------------
205 
206 	@Test
207 	void a11_boundaryConditions() {
208 		// Exactly at minimum (inclusive)
209 		var range1 = new VersionRange("[1.0,2.0)");
210 		assertTrue(range1.matches("1.0"));
211 		assertTrue(range1.matches("1.0.0"));
212 
213 		// Exactly at minimum (exclusive)
214 		var range2 = new VersionRange("(1.0,2.0)");
215 		assertFalse(range2.matches("1.0"));
216 		assertFalse(range2.matches("1.0.0"));
217 		// "1.0.1" should be > "1.0" (exclusive), so it should match
218 		assertTrue(range2.matches("1.0.1"));
219 		assertTrue(range2.matches("1.1"));
220 
221 		// Exactly at maximum (inclusive)
222 		var range3 = new VersionRange("[1.0,2.0]");
223 		assertTrue(range3.matches("2.0"));
224 		// "2.0.0" is considered greater than "2.0" in Version comparison
225 		assertTrue(range3.matches("2.0.0"));
226 		assertTrue(range3.matches("2.0.1"));
227 
228 		// Exactly at maximum (exclusive)
229 		var range4 = new VersionRange("[1.0,2.0)");
230 		assertFalse(range4.matches("2.0"));
231 		assertFalse(range4.matches("2.0.0"));
232 		assertTrue(range4.matches("1.9.9"));
233 	}
234 
235 	@Test
236 	void a12_singleDigitVersions() {
237 		var range = new VersionRange("[1,2)");
238 		assertTrue(range.matches("1"));
239 		assertTrue(range.matches("1.0"));
240 		assertTrue(range.matches("1.9"));
241 		assertFalse(range.matches("2"));
242 		assertFalse(range.matches("2.0"));
243 	}
244 
245 	@Test
246 	void a13_versionComparisons() {
247 		// Test that version comparison works correctly
248 		var range = new VersionRange("[1.2.3,2.0.0)");
249 		assertFalse(range.matches("1.2.2"));
250 		assertTrue(range.matches("1.2.3"));
251 		assertTrue(range.matches("1.2.4"));
252 		assertTrue(range.matches("1.9.9"));
253 		assertFalse(range.matches("2.0.0"));
254 		assertFalse(range.matches("2.0.1"));
255 	}
256 }