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.reflect;
18  
19  import static java.lang.annotation.ElementType.*;
20  import static java.lang.annotation.RetentionPolicy.*;
21  import static org.junit.jupiter.api.Assertions.*;
22  
23  import java.lang.annotation.*;
24  import java.net.*;
25  
26  import org.apache.juneau.*;
27  import org.junit.jupiter.api.*;
28  
29  class PackageInfo_Test extends TestBase {
30  
31  	@Target(PACKAGE)
32  	@Retention(RUNTIME)
33  	public static @interface TestPackageAnnotation {
34  		String value() default "";
35  	}
36  
37  	// Test classes in different packages
38  	public static class TestClass1 {}
39  	public static class TestClass2 {}
40  
41  	//====================================================================================================
42  	// equals(Object)
43  	//====================================================================================================
44  	@Test
45  	void a001_equals() {
46  		var pi1 = PackageInfo.of(TestClass1.class);
47  		var pi2 = PackageInfo.of(TestClass2.class);
48  		var pi3 = PackageInfo.of(TestClass1.class);
49  
50  		// Same package should be equal
51  		assertEquals(pi1, pi3);
52  		assertEquals(pi1.hashCode(), pi3.hashCode());
53  
54  		// Different packages should not be equal
55  		if (!pi1.getName().equals(pi2.getName())) {
56  			assertNotEquals(pi1, pi2);
57  		}
58  
59  		// Should equal the underlying Package
60  		assertEquals(pi1, pi1.inner());
61  	}
62  
63  	//====================================================================================================
64  	// getAnnotatableType()
65  	//====================================================================================================
66  	@Test
67  	void a002_getAnnotatableType() {
68  		var pi = PackageInfo.of(TestClass1.class);
69  		assertEquals(AnnotatableType.PACKAGE_TYPE, pi.getAnnotatableType());
70  	}
71  
72  	//====================================================================================================
73  	// getAnnotations()
74  	//====================================================================================================
75  	@Test
76  	void a003_getAnnotations() {
77  		var pi = PackageInfo.of(TestClass1.class);
78  		var annotations = pi.getAnnotations();
79  		assertNotNull(annotations);
80  		// May or may not have annotations depending on package-info.java
81  	}
82  
83  	//====================================================================================================
84  	// getAnnotations(Class<A>)
85  	//====================================================================================================
86  	@Test
87  	void a004_getAnnotations_typed() {
88  		var pi = PackageInfo.of(TestClass1.class);
89  		var annotations = pi.getAnnotations(TestPackageAnnotation.class);
90  		assertNotNull(annotations);
91  		// May or may not have annotations depending on package-info.java
92  		var count = annotations.count();
93  		assertTrue(count >= 0);
94  	}
95  
96  	//====================================================================================================
97  	// getImplementationTitle()
98  	//====================================================================================================
99  	@Test
100 	void a005_getImplementationTitle() {
101 		var pi = PackageInfo.of(String.class);
102 		// May be null if not specified in manifest
103 		// Just verify the method doesn't throw
104 		assertDoesNotThrow(() -> pi.getImplementationTitle());
105 	}
106 
107 	//====================================================================================================
108 	// getImplementationVendor()
109 	//====================================================================================================
110 	@Test
111 	void a006_getImplementationVendor() {
112 		var pi = PackageInfo.of(String.class);
113 		// May be null if not specified in manifest
114 		// Just verify the method doesn't throw
115 		assertDoesNotThrow(() -> pi.getImplementationVendor());
116 	}
117 
118 	//====================================================================================================
119 	// getImplementationVersion()
120 	//====================================================================================================
121 	@Test
122 	void a007_getImplementationVersion() {
123 		var pi = PackageInfo.of(String.class);
124 		// May be null if not specified in manifest
125 		// Just verify the method doesn't throw
126 		assertDoesNotThrow(() -> pi.getImplementationVersion());
127 	}
128 
129 	//====================================================================================================
130 	// getLabel()
131 	//====================================================================================================
132 	@Test
133 	void a008_getLabel() {
134 		var pi = PackageInfo.of(TestClass1.class);
135 		var label = pi.getLabel();
136 		assertNotNull(label);
137 		assertEquals(pi.getName(), label);
138 	}
139 
140 	//====================================================================================================
141 	// getName()
142 	//====================================================================================================
143 	@Test
144 	void a009_getName() {
145 		var pi = PackageInfo.of(TestClass1.class);
146 		var name = pi.getName();
147 		assertNotNull(name);
148 		assertEquals("org.apache.juneau.commons.reflect", name);
149 
150 		// Test with String.class
151 		var pi2 = PackageInfo.of(String.class);
152 		assertEquals("java.lang", pi2.getName());
153 	}
154 
155 	//====================================================================================================
156 	// getSpecificationTitle()
157 	//====================================================================================================
158 	@Test
159 	void a010_getSpecificationTitle() {
160 		var pi = PackageInfo.of(String.class);
161 		// May be null if not specified in manifest
162 		// Just verify the method doesn't throw
163 		assertDoesNotThrow(() -> pi.getSpecificationTitle());
164 	}
165 
166 	//====================================================================================================
167 	// getSpecificationVendor()
168 	//====================================================================================================
169 	@Test
170 	void a011_getSpecificationVendor() {
171 		var pi = PackageInfo.of(String.class);
172 		// May be null if not specified in manifest
173 		// Just verify the method doesn't throw
174 		assertDoesNotThrow(() -> pi.getSpecificationVendor());
175 	}
176 
177 	//====================================================================================================
178 	// getSpecificationVersion()
179 	//====================================================================================================
180 	@Test
181 	void a012_getSpecificationVersion() {
182 		var pi = PackageInfo.of(String.class);
183 		// May be null if not specified in manifest
184 		// Just verify the method doesn't throw
185 		assertDoesNotThrow(() -> pi.getSpecificationVersion());
186 	}
187 
188 	//====================================================================================================
189 	// hashCode()
190 	//====================================================================================================
191 	@Test
192 	void a013_hashCode() {
193 		var pi1 = PackageInfo.of(TestClass1.class);
194 		var pi2 = PackageInfo.of(TestClass1.class);
195 		var pi3 = PackageInfo.of(TestClass2.class);
196 
197 		// Same package should have same hash code
198 		assertEquals(pi1.hashCode(), pi2.hashCode());
199 
200 		// Should match underlying Package hash code
201 		assertEquals(pi1.hashCode(), pi1.inner().hashCode());
202 
203 		// Different packages may or may not have different hash codes
204 		if (!pi1.getName().equals(pi3.getName())) {
205 			// Hash codes might still be equal (collision), but usually different
206 		}
207 	}
208 
209 	//====================================================================================================
210 	// inner()
211 	//====================================================================================================
212 	@Test
213 	void a014_inner() {
214 		var pi = PackageInfo.of(TestClass1.class);
215 		var pkg = pi.inner();
216 		assertNotNull(pkg);
217 		assertEquals("org.apache.juneau.commons.reflect", pkg.getName());
218 	}
219 
220 	//====================================================================================================
221 	// isCompatibleWith(String)
222 	//====================================================================================================
223 	@Test
224 	void a015_isCompatibleWith() {
225 		var pi = PackageInfo.of(String.class);
226 
227 		// Test line 309: ensure inner.isCompatibleWith(desired) is called
228 		// Package versions come from JAR manifest (Specification-Version header)
229 		// Most test packages don't have versions, so isCompatibleWith throws NumberFormatException
230 		// However, line 309 is still executed - the exception is thrown FROM that line
231 		
232 		// Try to find a package with a version (e.g., from standard library or a dependency)
233 		// If found, test the normal return path
234 		var specVersion = pi.getSpecificationVersion();
235 		if (specVersion != null && !specVersion.isEmpty()) {
236 			// Line 309: normal return path when package has a version
237 			var compatible = pi.isCompatibleWith("1.0");
238 			assertNotNull(compatible);
239 			
240 			// Test with another version
241 			var compatible2 = pi.isCompatibleWith("2.0");
242 			assertNotNull(compatible2);
243 		} else {
244 			// Package doesn't have a version - isCompatibleWith will throw NumberFormatException
245 			// Line 309 is still executed, exception is thrown from inner.isCompatibleWith
246 			assertThrows(NumberFormatException.class, () -> pi.isCompatibleWith("1.0"));
247 		}
248 
249 		// Test with invalid version - should throw NumberFormatException
250 		// Line 309 is executed, then exception is thrown from inner.isCompatibleWith
251 		assertThrows(NumberFormatException.class, () -> pi.isCompatibleWith("invalid"));
252 
253 		// Test with null - Package.isCompatibleWith(null) throws NumberFormatException
254 		// Line 309 is executed, then exception is thrown from inner.isCompatibleWith
255 		assertThrows(NumberFormatException.class, () -> pi.isCompatibleWith(null));
256 	}
257 
258 	//====================================================================================================
259 	// isSealed()
260 	//====================================================================================================
261 	@Test
262 	void a016_isSealed() {
263 		var pi = PackageInfo.of(TestClass1.class);
264 		var sealed = pi.isSealed();
265 		// Most packages are not sealed
266 		assertNotNull(sealed);
267 	}
268 
269 	//====================================================================================================
270 	// isSealed(URL)
271 	//====================================================================================================
272 	@Test
273 	void a017_isSealed_withUrl() throws Exception {
274 		var pi = PackageInfo.of(TestClass1.class);
275 		var url = new URL("file:///test.jar");
276 		var sealed = pi.isSealed(url);
277 		// Most packages are not sealed with respect to a specific URL
278 		assertNotNull(sealed);
279 	}
280 
281 	//====================================================================================================
282 	// of(Class<?>)
283 	//====================================================================================================
284 	@Test
285 	void a018_of_withClass() {
286 		var pi = PackageInfo.of(TestClass1.class);
287 		assertNotNull(pi);
288 		assertEquals("org.apache.juneau.commons.reflect", pi.getName());
289 
290 		// Test with null - should throw
291 		assertThrows(NullPointerException.class, () -> PackageInfo.of((Class<?>)null));
292 	}
293 
294 	//====================================================================================================
295 	// of(ClassInfo)
296 	//====================================================================================================
297 	@Test
298 	void a019_of_withClassInfo() {
299 		var ci = ClassInfo.of(TestClass1.class);
300 		var pi = PackageInfo.of(ci);
301 		assertNotNull(pi);
302 		assertEquals("org.apache.juneau.commons.reflect", pi.getName());
303 	}
304 
305 	//====================================================================================================
306 	// of(Package)
307 	//====================================================================================================
308 	@Test
309 	void a020_of_withPackage() {
310 		var pkg = TestClass1.class.getPackage();
311 		var pi = PackageInfo.of(pkg);
312 		assertNotNull(pi);
313 		assertEquals("org.apache.juneau.commons.reflect", pi.getName());
314 
315 		// Test caching - should return same instance
316 		var pi2 = PackageInfo.of(pkg);
317 		assertSame(pi, pi2);
318 
319 		// Test with null - should throw
320 		assertThrows(IllegalArgumentException.class, () -> PackageInfo.of((Package)null));
321 	}
322 
323 	//====================================================================================================
324 	// toString()
325 	//====================================================================================================
326 	@Test
327 	void a021_toString() {
328 		var pi = PackageInfo.of(TestClass1.class);
329 		var str = pi.toString();
330 		assertNotNull(str);
331 		assertTrue(str.contains("package"));
332 		assertTrue(str.contains("org.apache.juneau.commons.reflect"));
333 
334 		// Should match underlying Package toString
335 		assertEquals(pi.inner().toString(), str);
336 	}
337 }
338