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.apache.juneau.commons.lang.Version.*;
20  import static org.apache.juneau.commons.utils.CollectionUtils.*;
21  import static org.apache.juneau.junit.bct.BctAssertions.*;
22  import static org.junit.jupiter.api.Assertions.*;
23  
24  import java.util.*;
25  
26  import org.apache.juneau.*;
27  import org.junit.jupiter.api.*;
28  
29  class Version_Test extends TestBase {
30  
31  	@Test void a01_basic() {
32  		assertNull(of(null));
33  		assertString("0", of(""));
34  
35  		var x = of("1.2.3");
36  		assertEquals(1, x.getMajor().orElse(null));
37  		assertEquals(2, x.getMinor().orElse(null));
38  		assertEquals(3, x.getMaintenance().orElse(null));
39  		assertEquals(1, x.getPart(0).orElse(null));
40  		assertEquals(2, x.getPart(1).orElse(null));
41  		assertEquals(3, x.getPart(2).orElse(null));
42  		assertNull(x.getPart(-1).orElse(null));
43  		assertNull(x.getPart(3).orElse(null));
44  
45  		x = of("1..x");
46  		assertString("1.0.2147483647", x);
47  	}
48  
49  	@Test void a02_isAtLeast() {
50  		var x = of("1.2.3");
51  
52  		assertTrue(x.isAtLeast(of("1.2.2")));
53  		assertTrue(x.isAtLeast(of("1.2.3")));
54  		assertFalse(x.isAtLeast(of("1.2.4")));
55  		assertTrue(x.isAtLeast(of("1.2.2"), true));
56  		assertFalse(x.isAtLeast(of("1.2.3"), true));
57  		assertFalse(x.isAtLeast(of("1.2.4"), true));
58  		assertTrue(x.isAtLeast(of("1.2")));
59  		assertFalse(x.isAtLeast(of("1.3")));
60  		assertTrue(x.isAtLeast(of("1.1.3.1")));
61  		assertFalse(x.isAtLeast(of("1.2.3.1")));
62  		assertTrue(x.isAtLeast(of("1.2.3.0")));
63  		assertFalse(x.isAtLeast(of("1.3.0.1")));
64  
65  		// Test that versions with more parts are greater than versions with fewer parts (exclusive)
66  		var y = of("1.0.1");
67  		assertTrue(y.isAtLeast(of("1.0"), true));  // "1.0.1" > "1.0" (exclusive)
68  		assertTrue(y.isAtLeast(of("1.0"), false)); // "1.0.1" >= "1.0" (inclusive)
69  	}
70  
71  	@Test void a03_isAtMost() {
72  		var x = of("1.2.3");
73  
74  		assertFalse(x.isAtMost(of("1.2.2")));
75  		assertTrue(x.isAtMost(of("1.2.3")));
76  		assertTrue(x.isAtMost(of("1.2.4")));
77  		assertFalse(x.isAtMost(of("1.2.2"), true));
78  		assertFalse(x.isAtMost(of("1.2.3"), true));
79  		assertTrue(x.isAtMost(of("1.2.4"), true));
80  		assertTrue(x.isAtMost(of("1.2")));
81  		assertTrue(x.isAtMost(of("1.3")));
82  		assertFalse(x.isAtMost(of("1.1.3.1")));
83  		assertTrue(x.isAtMost(of("1.2.3.1")));
84  		assertTrue(x.isAtMost(of("1.2.3.0")));
85  		assertTrue(x.isAtMost(of("1.3.0.1")));
86  	}
87  
88  	@Test void a04_isEqualsTo() {
89  		var x = of("1.2.3");
90  
91  		assertTrue(x.equals(of("1.2.3")));
92  		assertTrue(x.equals(of("1.2")));
93  		assertTrue(x.equals(of("1.2.3.4")));
94  		assertFalse(x.equals(of("1.2.4")));
95  	}
96  
97  	@Test void a05_compareTo() {
98  		var l = l(
99  			of("1.2.3"),
100 			of("1.2"),
101 			of(""),
102 			of("1.2.3.4"),
103 			of("2.0"),
104 			of("2")
105 		);
106 		Collections.sort(l);
107 		assertList(l, "0", "1.2", "1.2.3", "1.2.3.4", "2", "2.0");
108 		Collections.reverse(l);
109 		assertList(l, "2.0", "2", "1.2.3.4", "1.2.3", "1.2", "0");
110 	}
111 
112 	//====================================================================================================
113 	// equals(Object) tests
114 	//====================================================================================================
115 
116 	@Test
117 	void b01_equalsObject_sameInstance() {
118 		var v1 = of("1.2.3");
119 		assertTrue(v1.equals(v1));
120 	}
121 
122 	@Test
123 	void b02_equalsObject_sameVersion() {
124 		var v1 = of("1.2.3");
125 		var v2 = of("1.2.3");
126 		assertTrue(v1.equals(v2));
127 		assertTrue(v2.equals(v1));
128 	}
129 
130 	@Test
131 	void b03_equalsObject_differentVersions() {
132 		var v1 = of("1.2.3");
133 		var v2 = of("1.2.4");
134 		assertFalse(v1.equals(v2));
135 		assertFalse(v2.equals(v1));
136 	}
137 
138 	@Test
139 	void b04_equalsObject_null() {
140 		var v1 = of("1.2.3");
141 		// equals(Object) should return false for null
142 		// The instanceof check should prevent any null access
143 		try {
144 			assertFalse(v1.equals((Object)null));
145 		} catch (NullPointerException e) {
146 			// If there's a bug in the implementation, we'll catch it here
147 			// But ideally this should not throw
148 			fail("equals(Object) should handle null without throwing NullPointerException");
149 		}
150 	}
151 
152 	@SuppressWarnings("unlikely-arg-type")
153 	@Test
154 	void b05_equalsObject_differentType() {
155 		var v1 = of("1.2.3");
156 		assertFalse(v1.equals("1.2.3"));
157 		assertFalse(v1.equals(123));
158 		assertFalse(v1.equals(new Object()));
159 	}
160 
161 	@Test
162 	void b06_equalsObject_versionsWithDifferentLengths() {
163 		var v1 = of("1.2");
164 		var v2 = of("1.2.0");
165 		// equals(Version) compares only common parts, so these should be equal
166 		assertTrue(v1.equals(v2));
167 		assertTrue(v2.equals(v1));
168 	}
169 
170 	@Test
171 	void b07_equalsObject_versionsWithTrailingZeros() {
172 		var v1 = of("1.2.3");
173 		var v2 = of("1.2.3.0");
174 		// equals(Version) compares only common parts, so these should be equal
175 		assertTrue(v1.equals(v2));
176 		assertTrue(v2.equals(v1));
177 	}
178 
179 	@Test
180 	void b08_equalsObject_singlePartVersions() {
181 		var v1 = of("1");
182 		var v2 = of("1");
183 		assertTrue(v1.equals(v2));
184 	}
185 
186 	@Test
187 	void b09_equalsObject_emptyVersions() {
188 		var v1 = of("");
189 		var v2 = of("");
190 		assertTrue(v1.equals(v2));
191 	}
192 
193 	@Test
194 	void b10_equalsObject_symmetry() {
195 		var v1 = of("1.2.3");
196 		var v2 = of("1.2.3");
197 		assertEquals(v1.equals(v2), v2.equals(v1));
198 	}
199 
200 	@Test
201 	void b11_equalsObject_transitivity() {
202 		var v1 = of("1.2.3");
203 		var v2 = of("1.2.3");
204 		var v3 = of("1.2.3");
205 		assertTrue(v1.equals(v2));
206 		assertTrue(v2.equals(v3));
207 		assertTrue(v1.equals(v3));
208 	}
209 
210 	@Test
211 	void b12_equalsObject_reflexivity() {
212 		var v1 = of("1.2.3");
213 		assertTrue(v1.equals(v1));
214 	}
215 
216 	//====================================================================================================
217 	// hashCode() tests
218 	//====================================================================================================
219 
220 	@Test
221 	void c01_hashCode_consistency() {
222 		var v1 = of("1.2.3");
223 		var hashCode1 = v1.hashCode();
224 		var hashCode2 = v1.hashCode();
225 		assertEquals(hashCode1, hashCode2);
226 	}
227 
228 	@Test
229 	void c02_hashCode_sameVersion() {
230 		var v1 = of("1.2.3");
231 		var v2 = of("1.2.3");
232 		assertEquals(v1.hashCode(), v2.hashCode());
233 	}
234 
235 	@Test
236 	void c03_hashCode_differentVersions() {
237 		var v1 = of("1.2.3");
238 		var v2 = of("1.2.4");
239 		// Different versions may have same hashcode (collision), but usually different
240 		// We just verify both produce valid hashcodes
241 		assertNotNull(v1.hashCode());
242 		assertNotNull(v2.hashCode());
243 	}
244 
245 	@Test
246 	void c04_hashCode_equalsContract() {
247 		var v1 = of("1.2.3");
248 		var v2 = of("1.2.3");
249 		// If two objects are equal, they must have the same hashcode
250 		if (v1.equals(v2)) {
251 			assertEquals(v1.hashCode(), v2.hashCode());
252 		}
253 	}
254 
255 	@Test
256 	void c05_hashCode_differentLengths() {
257 		var v1 = of("1.2");
258 		var v2 = of("1.2.0");
259 		// These are equal according to equals(Version), so should have same hashcode
260 		// But hashCode uses Arrays.hashCode which considers length, so they may differ
261 		// We just verify both produce valid hashcodes
262 		assertNotNull(v1.hashCode());
263 		assertNotNull(v2.hashCode());
264 	}
265 
266 	@Test
267 	void c06_hashCode_singlePart() {
268 		var v1 = of("1");
269 		var v2 = of("1");
270 		assertEquals(v1.hashCode(), v2.hashCode());
271 	}
272 
273 	@Test
274 	void c07_hashCode_emptyVersion() {
275 		var v1 = of("");
276 		var v2 = of("");
277 		assertEquals(v1.hashCode(), v2.hashCode());
278 	}
279 
280 	@Test
281 	void c08_hashCode_multipleVersions() {
282 		var v1 = of("1.2.3");
283 		var v2 = of("2.3.4");
284 		var v3 = of("3.4.5");
285 		// All should produce valid hashcodes
286 		assertNotNull(v1.hashCode());
287 		assertNotNull(v2.hashCode());
288 		assertNotNull(v3.hashCode());
289 	}
290 
291 	@Test
292 	void c09_hashCode_largeVersions() {
293 		var v1 = of("1.2.3.4.5.6.7.8.9.10");
294 		var v2 = of("1.2.3.4.5.6.7.8.9.10");
295 		assertEquals(v1.hashCode(), v2.hashCode());
296 	}
297 
298 	@Test
299 	void c10_hashCode_withZeros() {
300 		var v1 = of("1.0.0");
301 		var v2 = of("1.0.0");
302 		assertEquals(v1.hashCode(), v2.hashCode());
303 	}
304 
305 	@Test
306 	void c11_hashCode_withMaxValue() {
307 		var v1 = of("1.x");
308 		var v2 = of("1.x");
309 		// Non-numeric parts become Integer.MAX_VALUE
310 		assertEquals(v1.hashCode(), v2.hashCode());
311 	}
312 
313 	@Test
314 	void c12_hashCode_consistencyAcrossCalls() {
315 		var v1 = of("1.2.3");
316 		var hash1 = v1.hashCode();
317 		var hash2 = v1.hashCode();
318 		var hash3 = v1.hashCode();
319 		assertEquals(hash1, hash2);
320 		assertEquals(hash2, hash3);
321 		assertEquals(hash1, hash3);
322 	}
323 }