This is an automated email from the ASF dual-hosted git repository. jamesbognar pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/juneau.git
commit 309fcb5981a702280137ee97ed8853b8ea987c44 Author: James Bognar <[email protected]> AuthorDate: Wed Dec 3 16:46:16 2025 -0800 Unit tests --- .../org/apache/juneau/commons/utils/IoUtils.java | 24 +-- .../org/apache/juneau/commons/utils/Utils.java | 27 +++ .../juneau/commons/reflect/ClassInfo_Test.java | 156 +++++++------- .../juneau/commons/reflect/ElementInfo_Test.java | 2 +- .../juneau/commons/reflect/ParameterInfo_Test.java | 14 +- .../juneau/commons/utils/AnnotationUtils_Test.java | 84 ++++---- .../juneau/commons/utils/CollectionUtils_Test.java | 2 +- .../apache/juneau/commons/utils/IoUtils_Test.java | 227 ++++++++++++++++++++- 8 files changed, 380 insertions(+), 156 deletions(-) diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/IoUtils.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/IoUtils.java index 9df7b6430f..98e04a091a 100644 --- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/IoUtils.java +++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/IoUtils.java @@ -113,10 +113,8 @@ public class IoUtils { * @param is The input stream to close. */ public static void closeQuietly(InputStream is) { - try { - if (nn(is)) - is.close(); - } catch (@SuppressWarnings("unused") IOException e) { /* ignore */ } + if (nn(is)) + safe(() -> is.close()); } /** @@ -146,10 +144,8 @@ public class IoUtils { * @param os The output stream to close. */ public static void closeQuietly(OutputStream os) { - try { - if (nn(os)) - os.close(); - } catch (@SuppressWarnings("unused") IOException e) { /* ignore */ } + if (nn(os)) + quiet(() -> os.close()); } /** @@ -161,10 +157,8 @@ public class IoUtils { * @param r The reader to close. */ public static void closeQuietly(Reader r) { - try { - if (nn(r)) - r.close(); - } catch (@SuppressWarnings("unused") IOException e) { /* ignore */ } + if (nn(r)) + quiet(() -> r.close()); } /** @@ -176,10 +170,8 @@ public class IoUtils { * @param w The writer to close. */ public static void closeQuietly(Writer w) { - try { - if (nn(w)) - w.close(); - } catch (@SuppressWarnings("unused") IOException e) { /* ignore */ } + if (nn(w)) + quiet(() -> w.close()); } /** diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Utils.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Utils.java index be1109d3bb..73c7422fc6 100644 --- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Utils.java +++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Utils.java @@ -1376,6 +1376,33 @@ public class Utils { } } + /** + * Runs a snippet of code and silently ignores any exceptions. + * + * <p> + * This method is useful for operations that may fail but where you want to handle the failure + * gracefully by ignoring it. This is commonly used for "quietly" closing resources where + * exceptions during close operations are not critical. + * + * <h5 class='section'>Example:</h5> + * <p class='bjava'> + * <jc>// Quietly close a stream, ignoring any exceptions</jc> + * Utils.<jsm>quiet</jsm>(() -> stream.close()); + * </p> + * + * <p> + * This is different from {@link #safe(Snippet)} which wraps exceptions in a {@link RuntimeException}. + * + * @param snippet The snippet of code to run. + * @see #safe(Snippet) + * @see #safeOpt(ThrowingSupplier) + */ + public static void quiet(Snippet snippet) { + try { + snippet.run(); + } catch (Throwable t) { /* Ignore */ } + } + /** * Runs a snippet of code with a custom exception mapper. * diff --git a/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ClassInfo_Test.java b/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ClassInfo_Test.java index fca9fedad2..6b04833296 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ClassInfo_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ClassInfo_Test.java @@ -558,13 +558,13 @@ public class ClassInfo_Test extends TestBase { // To test the at == null branch, we need inner != null but inner.arrayType() == null // This is difficult to achieve with normal Java classes, but we can verify the non-null branch works // The non-null branch (at != null) is already covered above with String.class and String[].class - + // Verify that the non-null branch works correctly (at != null -> return of(at)) var ci4 = ClassInfo.of(Integer.class); var arrayType3 = ci4.arrayType(); assertNotNull(arrayType3); assertEquals(Integer[].class, arrayType3.inner()); - + // Note: The at == null branch at line 391 is a defensive check that may be unreachable // in practice with normal Java classes, but the code includes it for safety } @@ -617,7 +617,7 @@ public class ClassInfo_Test extends TestBase { check("CI2.i2a(),CI2.i2b(),CI1.i1a(),CI1.i1b(),CC1.c1a(),CC1.c1b(),CC1.i1a(),CC2.c2a(),CC2.c2b(),CC2.i1b(),CC2.i2a(),CC2.i2b(),CC3.c3a(),CC3.c3b(),CC3.i2b()", cc3.getAllMethodsTopDown()); // Test twice to verify caching check("CI2.i2a(),CI2.i2b(),CI1.i1a(),CI1.i1b(),CC1.c1a(),CC1.c1b(),CC1.i1a(),CC2.c2a(),CC2.c2b(),CC2.i1b(),CC2.i2a(),CC2.i2b(),CC3.c3a(),CC3.c3b(),CC3.i2b()", cc3.getAllMethodsTopDown()); - + // Test line 248/590/615: getAllMethodsTopDown() initialization and method call // Test with class that has no methods var objectCi = ClassInfo.of(Object.class); @@ -626,7 +626,7 @@ public class ClassInfo_Test extends TestBase { // Object class has methods, but we filter out Object.class methods in publicMethods // getAllMethodsTopDown includes all methods from all parents, so it should have methods // Actually, getAllMethodsTopDown uses getAllParents() which includes Object, so it should have methods - + // Test with interface that has no methods var emptyInterface = ClassInfo.of(EmptyInterface.class); var emptyMethods = emptyInterface.getAllMethodsTopDown(); @@ -634,7 +634,7 @@ public class ClassInfo_Test extends TestBase { // Empty interface should have no methods assertTrue(emptyMethods.isEmpty() || emptyMethods.size() >= 0); // May have Object methods } - + // Helper interface for testing interface EmptyInterface {} @@ -775,12 +775,12 @@ public class ClassInfo_Test extends TestBase { // Number can accept int (parent type) assertTrue(ClassInfo.of(Number.class).canAcceptArg(42)); assertTrue(ClassInfo.of(Number.class).canAcceptArg(Integer.valueOf(42))); - + // Test line 434: all 4 branches of if (this.isPrimitive() || child.getClass().isPrimitive()) // Branch 1: this.isPrimitive() == true && child.getClass().isPrimitive() == true // Note: When you pass a primitive value like 42, it gets autoboxed to Integer, so child.getClass() returns Integer.class (not primitive) // This branch is likely unreachable in practice since primitive values are always autoboxed - + // Branch 2: this.isPrimitive() == true && child.getClass().isPrimitive() == false (already covered above at line 707) // Branch 3: this.isPrimitive() == false && child.getClass().isPrimitive() == true (already covered above at line 710) // Branch 4: this.isPrimitive() == false && child.getClass().isPrimitive() == false @@ -788,7 +788,7 @@ public class ClassInfo_Test extends TestBase { // This is the missing branch - need to test when condition is false (both false), so we skip the if and return false assertFalse(ClassInfo.of(String.class).canAcceptArg(new Object())); // Both non-primitive, isInstance false, condition false, returns false assertFalse(ClassInfo.of(String.class).canAcceptArg(42)); // String is not primitive, Integer is not primitive, isInstance false, condition false, returns false - + // Test case where this is primitive but child is not (branch 2) - different primitive types that don't match assertFalse(ClassInfo.of(int.class).canAcceptArg(Long.valueOf(42L))); // int is primitive, Long is not primitive, different types, condition true, returns false from isParentOf } @@ -838,7 +838,7 @@ public class ClassInfo_Test extends TestBase { // For types without inner class, should return null (line 474-475) var ci = ClassInfo.of((Class<?>)null, pType); assertNull(ci.componentType()); - + // Test line 476-477: componentType() method // For non-array types, inner.componentType() returns null, so ct == null branch is taken var nonArray = ClassInfo.of(String.class); @@ -846,7 +846,7 @@ public class ClassInfo_Test extends TestBase { // String.class.componentType() returns null for non-array types // So the ternary at line 477: ct == null ? null : of(ct) takes the null branch assertNull(ct); - + // For array types, inner.componentType() returns non-null, so ct != null branch is taken var array = ClassInfo.of(String[].class); var ct2 = array.componentType(); @@ -907,7 +907,7 @@ public class ClassInfo_Test extends TestBase { // G4 has no declared annotations (inherits from G3) var declared2 = g4.getDeclaredAnnotations(); assertTrue(declared2.isEmpty()); - + // Test with null inner (line 231: opt(inner) returns empty when inner is null) var ci = ClassInfo.of((Class<?>)null, pType); var declared3 = ci.getDeclaredAnnotations(); @@ -990,7 +990,7 @@ public class ClassInfo_Test extends TestBase { check("", pTypeDimensionalInfo.getDeclaredInterfaces()); check("Map", pTypeGenericInfo.getDeclaredInterfaces()); check("", pTypeGenericArgInfo.getDeclaredInterfaces()); - + // Test line 190/235: inner == null case // When inner is null, opt(inner) returns empty, so orElse(liste()) returns empty list var ci = ClassInfo.of((Class<?>)null, pType); @@ -1141,7 +1141,7 @@ public class ClassInfo_Test extends TestBase { var local = ClassInfo.of(LocalClass.class); var constructor = local.getEnclosingConstructor(); assertNull(constructor); - + // Test line 952: ec != null branch - class declared inside constructor // Create an instance to trigger the constructor and capture the local class new EnclosingConstructorTestClass(); @@ -1306,7 +1306,7 @@ public class ClassInfo_Test extends TestBase { assertNull(pTypeInfo.getNameCanonical()); assertNull(pTypeDimensionalInfo.getNameCanonical()); assertNull(pTypeGenericInfo.getNameCanonical()); - + // Test line 1112: inner == null && ! isParameterizedType (branch 3) // Create a ClassInfo with inner == null and innerType being a TypeVariable (not ParameterizedType) // aType is a TypeVariable from A2 extends Value<A1> @@ -1421,22 +1421,22 @@ public class ClassInfo_Test extends TestBase { assertNotNull(formatted2); // When inner is null but isParameterizedType is true, code extracts raw type and uses its simple name assertEquals("Map", formatted2); - + // Test line 326: FULL format separator replacement (4 branches) // Branch 1: separator != '$' && sb.indexOf("$") != -1 (true, true) - should replace '$' with separator var ci12 = ClassInfo.of(Map.Entry.class); assertEquals("java.util.Map.Entry", ci12.getNameFormatted(FULL, false, '.', BRACKETS)); - + // Branch 2: separator != '$' && sb.indexOf("$") == -1 (true, false) - no '$' in name, no replacement needed var ci13 = ClassInfo.of(String.class); assertEquals("java.lang.String", ci13.getNameFormatted(FULL, false, '.', BRACKETS)); - + // Branch 3: separator == '$' && sb.indexOf("$") != -1 (false, true) - separator is '$', no replacement assertEquals("java.util.Map$Entry", ci12.getNameFormatted(FULL, false, '$', BRACKETS)); - + // Branch 4: separator == '$' && sb.indexOf("$") == -1 (false, false) - separator is '$', no '$' in name assertEquals("java.lang.String", ci13.getNameFormatted(FULL, false, '$', BRACKETS)); - + // Test line 360: SIMPLE format with null class (not ParameterizedType) - should use innerType.getTypeName() // Use an existing TypeVariable from MC class which has type parameters var typeVar = MC.class.getTypeParameters()[0]; // MC<K,E> has K as first type parameter @@ -1656,16 +1656,16 @@ public class ClassInfo_Test extends TestBase { check("java.util", pTypeDimensionalInfo.getPackage()); check("java.util", pTypeGenericInfo.getPackage()); check(null, pTypeGenericArgInfo.getPackage()); - + // Test line 229: packageInfo memoization with null inner // When inner is null, opt(inner) is empty, so should return null var ci = ClassInfo.of((Class<?>)null, pType); assertNull(ci.getPackage()); - + // Test with primitive types (getPackage() returns null) var intCi = ClassInfo.of(int.class); assertNull(intCi.getPackage()); // Primitives have no package - + // Test with arrays of primitives (getPackage() returns null) var intArrayCi = ClassInfo.of(int[].class); assertNull(intArrayCi.getPackage()); // Arrays of primitives have no package @@ -1741,7 +1741,7 @@ public class ClassInfo_Test extends TestBase { // Nested type check("MM", mn.getParameterType(1, HashMap.class)); - + // Note: Line 1375 (actualType3 = (TypeVariable<?>)entry.getValue()) is executed when // resolving a type variable in a nested inner class where the value in the outer type map // is itself a TypeVariable (not a Class). This requires a complex nested generic scenario @@ -1793,21 +1793,17 @@ public class ClassInfo_Test extends TestBase { // Sealed class for testing getPermittedSubclasses (Java 17+) // Only compile if sealed classes are available - @SuppressWarnings("unused") public static sealed class SealedTestClass permits SealedSubclass1, SealedSubclass2 { } - - @SuppressWarnings("unused") + public static final class SealedSubclass1 extends SealedTestClass { } - - @SuppressWarnings("unused") + public static final class SealedSubclass2 extends SealedTestClass { } - + // Record class for testing isRecord (Java 14+) // Only compile if records are available - @SuppressWarnings("unused") public static record TestRecord(String name, int value) { } @@ -1826,7 +1822,7 @@ public class ClassInfo_Test extends TestBase { var empty = ci.getPermittedSubclasses(); assertNotNull(empty); assertTrue(empty.isEmpty()); - + // Test line 1465: inner != null && inner.isSealed() - sealed class with permitted subclasses // Only test if sealed classes are available (Java 17+) try { @@ -1946,7 +1942,7 @@ public class ClassInfo_Test extends TestBase { // Test on types check("", aTypeInfo.getPublicFields()); check("", pTypeGenericArgInfo.getPublicFields()); - + // Test line 249: publicFields memoization // This line uses parents.get().stream() which requires inner to be non-null // When inner is null, parents.get() will return empty list, so publicFields should be empty @@ -2032,12 +2028,12 @@ public class ClassInfo_Test extends TestBase { // Records not available, skip test assertTrue(cc3.getRecordComponents().isEmpty()); } - + // Test line 240: recordComponents memoization // When inner is null, opt(inner) is empty, so should return empty list var ci = ClassInfo.of((Class<?>)null, pType); assertTrue(ci.getRecordComponents().isEmpty()); - + // When inner is not null but isRecord() is false, filter should return empty, so should return empty list assertTrue(aClass.getRecordComponents().isEmpty()); } @@ -2052,11 +2048,11 @@ public class ClassInfo_Test extends TestBase { var method = repeatable.getRepeatedAnnotationMethod(); // @Repeatable itself is not repeatable, so should return null assertNull(method); - + // Test isRepeatedAnnotation() (line 2135) // When getRepeatedAnnotationMethod() returns null, isRepeatedAnnotation() should return false assertFalse(repeatable.isRepeatedAnnotation()); - + // Test with a class that has a repeatable annotation method // TestRepeatableContainer is the container annotation for TestRepeatable // It has a value() method that returns TestRepeatable[], and TestRepeatable is marked with @Repeatable(TestRepeatableContainer.class) @@ -2064,23 +2060,23 @@ public class ClassInfo_Test extends TestBase { var containerMethod = container.getRepeatedAnnotationMethod(); assertNotNull(containerMethod); // Should find the value() method assertTrue(container.isRepeatedAnnotation()); // Line 2135: getRepeatedAnnotationMethod() != null returns true - + // Test line 2364 branches: return r != null && r.value().equals(inner); // Branch 1: r != null is false (r is null) - when component type doesn't have @Repeatable // This is covered by NonRepeatableArrayContainer which has value() returning String[], but String is not a repeatable annotation var nonRepeatableContainer = ClassInfo.of(NonRepeatableArrayContainer.class); assertNull(nonRepeatableContainer.getRepeatedAnnotationMethod()); // Should return null because String is not repeatable - + // Branch 2: r != null is true, r.value().equals(inner) is true - covered by TestRepeatableContainer above // TestRepeatableContainer has value() returning TestRepeatable[], and TestRepeatable is marked with @Repeatable(TestRepeatableContainer.class) // So when checking TestRepeatableContainer, r.value() equals TestRepeatableContainer.class (inner) - + // Branch 3: r != null is true, r.value().equals(inner) is false - when @Repeatable points to a different container // WrongContainer has value() returning TestRepeatable[], but TestRepeatable's @Repeatable points to TestRepeatableContainer, not WrongContainer // So when checking WrongContainer, r.value() would be TestRepeatableContainer.class, not WrongContainer.class, so equals(inner) is false var wrongContainer = ClassInfo.of(WrongContainer.class); assertNull(wrongContainer.getRepeatedAnnotationMethod()); // Should return null because the @Repeatable points to a different container - + // Test that non-repeatable classes return false assertFalse(aClass.isRepeatedAnnotation()); } @@ -2094,12 +2090,12 @@ public class ClassInfo_Test extends TestBase { assertNotNull(signers); // Most classes won't have signers unless from a signed JAR assertTrue(signers.isEmpty() || !signers.isEmpty()); - + // Test line 244: signers memoization // When inner is null, opt(inner) is empty, so should return empty list var ci = ClassInfo.of((Class<?>)null, pType); assertTrue(ci.getSigners().isEmpty()); - + // When inner is not null but getSigners() returns null, map should handle null and return empty list // Most classes return null from getSigners(), which is then wrapped in u(l(x)) to create empty list // This is already tested above with aClass.getSigners() @@ -2255,18 +2251,18 @@ public class ClassInfo_Test extends TestBase { assertTrue(aClass.is(NOT_RECORD)); assertTrue(aClass.is(NOT_SEALED)); assertTrue(aClass.is(NOT_SYNTHETIC)); - + // Test positive ElementFlag cases (lines 1772, 1774, 1775, 1776, 1781, 1783, 1787, 1789, 1791, 1793) // ANNOTATION (line 1772) assertTrue(ClassInfo.of(A.class).is(ANNOTATION)); assertFalse(aClass.is(ANNOTATION)); - + // NOT_ANNOTATION (line 1773) - test both branches // Branch 1: isAnnotation() returns false, so NOT_ANNOTATION returns true assertTrue(aClass.is(NOT_ANNOTATION)); // Branch 2: isAnnotation() returns true, so NOT_ANNOTATION returns false assertFalse(ClassInfo.of(A.class).is(NOT_ANNOTATION)); - + // ANONYMOUS and NOT_ANONYMOUS (lines 1774, 1775) // Anonymous classes are created dynamically, so we test NOT_ANONYMOUS assertTrue(aClass.is(NOT_ANONYMOUS)); @@ -2277,27 +2273,27 @@ public class ClassInfo_Test extends TestBase { assertTrue(anonymousInfo.is(ANONYMOUS)); assertFalse(anonymousInfo.is(NOT_ANONYMOUS)); } - + // ARRAY (line 1776) assertTrue(ClassInfo.of(String[].class).is(ARRAY)); assertFalse(aClass.is(ARRAY)); - + // NOT_ARRAY (line 1777) - test both branches // Branch 1: isArray() returns false, so NOT_ARRAY returns true assertTrue(aClass.is(NOT_ARRAY)); // Branch 2: isArray() returns true, so NOT_ARRAY returns false assertFalse(ClassInfo.of(String[].class).is(NOT_ARRAY)); - + // ENUM (line 1781) assertTrue(ClassInfo.of(ClassArrayFormat.class).is(ENUM)); assertFalse(aClass.is(ENUM)); - + // NOT_ENUM (line 1782) - test both branches // Branch 1: isEnum() returns false, so NOT_ENUM returns true assertTrue(aClass.is(NOT_ENUM)); // Branch 2: isEnum() returns true, so NOT_ENUM returns false assertFalse(ClassInfo.of(ClassArrayFormat.class).is(NOT_ENUM)); - + // LOCAL and NOT_LOCAL (line 1783) // Local class class LocalTestClass {} @@ -2306,7 +2302,7 @@ public class ClassInfo_Test extends TestBase { assertFalse(localInfo.is(NOT_LOCAL)); assertTrue(aClass.is(NOT_LOCAL)); assertFalse(aClass.is(LOCAL)); - + // NON_STATIC_MEMBER (line 1787) // H_PublicMember is a non-static member class var nonStaticMember = ClassInfo.of(H_PublicMember.class); @@ -2314,15 +2310,15 @@ public class ClassInfo_Test extends TestBase { assertFalse(nonStaticMember.is(NOT_NON_STATIC_MEMBER)); assertTrue(aClass.is(NOT_NON_STATIC_MEMBER)); assertFalse(aClass.is(NON_STATIC_MEMBER)); - + // PRIMITIVE (line 1789) assertTrue(ClassInfo.of(int.class).is(PRIMITIVE)); assertFalse(aClass.is(PRIMITIVE)); - + // NOT_PRIMITIVE (line 1790) assertTrue(aClass.is(NOT_PRIMITIVE)); assertFalse(ClassInfo.of(int.class).is(NOT_PRIMITIVE)); - + // RECORD (line 1791) - test if records are available try { Class.forName("java.lang.Record"); @@ -2332,7 +2328,7 @@ public class ClassInfo_Test extends TestBase { } catch (ClassNotFoundException e) { // Records not available, skip } - + // NOT_RECORD (line 1792) - test both branches // Branch 1: isRecord() returns false, so NOT_RECORD returns true assertTrue(aClass.is(NOT_RECORD)); @@ -2346,7 +2342,7 @@ public class ClassInfo_Test extends TestBase { } catch (ClassNotFoundException e) { // Records not available, skip } - + // SEALED (line 1793) - test if sealed classes are available try { Class.forName("java.lang.constant.Constable"); @@ -2359,7 +2355,7 @@ public class ClassInfo_Test extends TestBase { } catch (ClassNotFoundException e) { // Sealed classes not available, skip } - + // NOT_SEALED (line 1794) - test both branches // Branch 1: isSealed() returns false, so NOT_SEALED returns true assertTrue(aClass.is(NOT_SEALED)); @@ -2372,7 +2368,7 @@ public class ClassInfo_Test extends TestBase { } catch (ClassNotFoundException e) { // Sealed classes not available, skip } - + // SYNTHETIC (line 1795) - synthetic classes are compiler-generated // Most regular classes are not synthetic assertFalse(aClass.is(SYNTHETIC)); @@ -2383,7 +2379,7 @@ public class ClassInfo_Test extends TestBase { // Just verify the method doesn't throw anonymousInfo.is(SYNTHETIC); } - + // NOT_SYNTHETIC (line 1796) assertTrue(aClass.is(NOT_SYNTHETIC)); } @@ -2451,7 +2447,7 @@ public class ClassInfo_Test extends TestBase { assertTrue(ClassInfo.of(A.class).isAnnotation()); assertTrue(ClassInfo.of(B.class).isAnnotation()); assertFalse(aClass.isAnnotation()); - + // Test with null inner (line 1811) var ci = ClassInfo.of((Class<?>)null, pType); assertFalse(ci.isAnnotation()); @@ -2509,16 +2505,16 @@ public class ClassInfo_Test extends TestBase { // Test with array assertTrue(ClassInfo.of(String[].class).isCollectionOrArray()); assertTrue(ClassInfo.of(int[].class).isCollectionOrArray()); - + // Test with Collection assertTrue(ClassInfo.of(java.util.List.class).isCollectionOrArray()); assertTrue(ClassInfo.of(java.util.Set.class).isCollectionOrArray()); assertTrue(ClassInfo.of(java.util.Collection.class).isCollectionOrArray()); - + // Test with non-collection, non-array assertFalse(aClass.isCollectionOrArray()); assertFalse(ClassInfo.of(String.class).isCollectionOrArray()); - + // Test with null inner (line 1905) var ci = ClassInfo.of((Class<?>)null, pType); assertFalse(ci.isCollectionOrArray()); @@ -2615,7 +2611,7 @@ public class ClassInfo_Test extends TestBase { void a081_isEnum() { assertTrue(ClassInfo.of(ClassArrayFormat.class).isEnum()); assertFalse(aClass.isEnum()); - + // Test with null inner (line 1919) var ci = ClassInfo.of((Class<?>)null, pType); assertFalse(ci.isEnum()); @@ -2894,10 +2890,10 @@ public class ClassInfo_Test extends TestBase { assertFalse(kc.isParentOf(ka)); assertFalse(kc.isParentOf(kb)); assertTrue(kc.isParentOf(kc)); - + // Test with null child (line 2029) assertFalse(ka.isParentOf((ClassInfo)null)); - + // Test with null inner var nullInnerCi = ClassInfo.of((Class<?>)null, pType); assertFalse(nullInnerCi.isParentOf(ka)); @@ -2933,7 +2929,7 @@ public class ClassInfo_Test extends TestBase { assertFalse(ClassInfo.of(String.class).isParentOfLenient((ClassInfo)null)); var nullInnerCi = ClassInfo.of((Class<?>)null, pType); assertFalse(nullInnerCi.isParentOfLenient(ClassInfo.of(String.class))); - + // Test all branches of line 2087: if (this.isPrimitive() || child.isPrimitive()) // Branch 1: this.isPrimitive() == true, child.isPrimitive() == false (already covered above) // Branch 2: this.isPrimitive() == false, child.isPrimitive() == true (already covered above) @@ -3024,7 +3020,7 @@ public class ClassInfo_Test extends TestBase { // Records not available, skip test assertFalse(cc3.isRecord()); } - + // Test with null inner (line 2120) var ci = ClassInfo.of((Class<?>)null, pType); assertFalse(ci.isRecord()); @@ -3097,7 +3093,7 @@ public class ClassInfo_Test extends TestBase { var anonymousInfo = ClassInfo.of(anonymous); // Anonymous classes are typically synthetic assertTrue(anonymousInfo.isSynthetic() || !anonymousInfo.isSynthetic()); - + // Test with null inner (line 2169) var ci = ClassInfo.of((Class<?>)null, pType); assertFalse(ci.isSynthetic()); @@ -3111,7 +3107,7 @@ public class ClassInfo_Test extends TestBase { // Test with null inner (line 2149) var ci = ClassInfo.of((Class<?>)null, pType); assertFalse(ci.isSealed()); - + // Test with regular classes (most are not sealed) assertFalse(aClass.isSealed()); } @@ -3203,13 +3199,13 @@ public class ClassInfo_Test extends TestBase { assertNotNull(info); assertNull(info.inner()); assertNotNull(info.innerType()); - + // Test line 226: isParameterizedType initialization // When innerType is null, isParameterizedType should be false - var nonParamType = ClassInfo.of(String.class); // String.class is not a ParameterizedType, so isParameterizedType should be false // We can't directly access isParameterizedType, but we can infer it from behavior - + ClassInfo.of(String.class); // Exercise the code path + // When innerType is a ParameterizedType, isParameterizedType should be true // pTypeInfo has a ParameterizedType, so isParameterizedType should be true // We can verify this indirectly by checking that it behaves as a parameterized type @@ -3226,7 +3222,7 @@ public class ClassInfo_Test extends TestBase { var info = ClassInfo.ofProxy(obj); assertNotNull(info); assertEquals(A1.class, info.inner()); - + // Test line 175: when getProxyFor returns null, should call ClassInfo.of(object) // Most objects are not proxies, so getProxyFor should return null // This tests the branch: inner == null ? ClassInfo.of(object) : ClassInfo.of(inner) @@ -3267,7 +3263,7 @@ public class ClassInfo_Test extends TestBase { mi2 = ClassInfo.of(A6.class).getPublicMethod(x -> x.hasName("m2")).get(); check("A1", mi2.getParameter(0).getParameterType().unwrap(Value.class)); check("A1", mi2.getReturnType().unwrap(Value.class)); - + // Test unwrap with ParameterizedType (line 2382) // Create a ParameterizedType directly var pTypeOptional = new java.lang.reflect.ParameterizedType() { @@ -3286,7 +3282,7 @@ public class ClassInfo_Test extends TestBase { }; var ciOptional = ClassInfo.of((Class<?>)null, pTypeOptional); check("A1", ciOptional.unwrap(Optional.class)); - + // Test unwrap with ParameterizedType that has no type arguments (line 2383) var pTypeEmpty = new java.lang.reflect.ParameterizedType() { @Override @@ -3305,22 +3301,22 @@ public class ClassInfo_Test extends TestBase { var ciEmpty = ClassInfo.of((Class<?>)null, pTypeEmpty); // Should return itself since there are no type arguments assertSame(ciEmpty, ciEmpty.unwrap(Optional.class)); - + // Test unwrap with Class that extends wrapper (line 2387, 2388) // A2 extends Value<A1>, so unwrap should work // This covers: innerType instanceof Class<?> is true, innerType3 != parameterizedType is true, isAssignableFrom is true check("A1", of(A2.class).unwrap(Value.class)); - + // Test unwrap with Class that doesn't extend wrapper (line 2388 - false branch) // A1 doesn't extend Value, so unwrap should return itself // This covers: innerType instanceof Class<?> is true, innerType3 != parameterizedType is true, isAssignableFrom is false assertSame(of(A1.class), of(A1.class).unwrap(Value.class)); - + // Test unwrap when innerType3 == parameterizedType (line 2388 - false branch of !=) // When unwrapping Value.class from Value.class itself, innerType3 == parameterizedType, so should return itself // This covers: innerType instanceof Class<?> is true, innerType3 != parameterizedType is false (short-circuit) assertSame(of(Value.class), of(Value.class).unwrap(Value.class)); - + // Test unwrap when innerType is not a Class<?> (line 2387 - false branch) // When innerType is a ParameterizedType, the else if branch is not entered // This is already covered by the ParameterizedType tests above, but let's verify diff --git a/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ElementInfo_Test.java b/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ElementInfo_Test.java index a6dbcc83a1..6eb9b99cef 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ElementInfo_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ElementInfo_Test.java @@ -83,7 +83,7 @@ class ElementInfo_Test extends TestBase { } public static class StrictClass { - public strictfp void strictMethod() {} + public void strictMethod() {} } public static class TransientClass { diff --git a/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ParameterInfo_Test.java b/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ParameterInfo_Test.java index 30c9da3eaa..61bb047168 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ParameterInfo_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ParameterInfo_Test.java @@ -636,13 +636,13 @@ class ParameterInfo_Test extends TestBase { // 1. !DISABLE_PARAM_NAME_DETECTION.get() is true (flag is false) // 2. inner.isNamePresent() is true (bytecode names available) if (paramWithoutName.inner().isNamePresent()) { - // If bytecode names are available, try to get resolved name - // This will execute line 632 if the flag is actually false - var resolvedName = paramWithoutName.getResolvedName(); - // Note: If resolvedName is null, it means the condition on line 631 was false - // (either flag is still true, or there's a caching issue) - // In that case, line 632 won't be covered, which is acceptable - // We don't assert here because the flag might not have reset properly + // If bytecode names are available, try to get resolved name + // This will execute line 632 if the flag is actually false + paramWithoutName.getResolvedName(); // Exercise the code path + // Note: If the result is null, it means the condition on line 631 was false + // (either flag is still true, or there's a caching issue) + // In that case, line 632 won't be covered, which is acceptable + // We don't assert here because the flag might not have reset properly } // If bytecode names are not available, line 632 won't be executed // This is expected if the code wasn't compiled with -parameters flag diff --git a/juneau-utest/src/test/java/org/apache/juneau/commons/utils/AnnotationUtils_Test.java b/juneau-utest/src/test/java/org/apache/juneau/commons/utils/AnnotationUtils_Test.java index 8dfefcc743..d8c9dba6cb 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/commons/utils/AnnotationUtils_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/commons/utils/AnnotationUtils_Test.java @@ -20,8 +20,6 @@ import static org.apache.juneau.commons.utils.AnnotationUtils.hash; import static org.apache.juneau.commons.utils.AnnotationUtils.streamRepeated; import static org.junit.jupiter.api.Assertions.*; -import org.apache.juneau.commons.utils.AnnotationUtils; - import java.lang.annotation.*; import java.util.List; import java.util.stream.Collectors; @@ -238,107 +236,107 @@ class AnnotationUtils_Test { // Same instance var a1 = TestClass1.class.getAnnotation(SimpleAnnotation.class); assertTrue(AnnotationUtils.equals(a1, a1)); - + // Same value var a2 = TestClass2.class.getAnnotation(SimpleAnnotation.class); assertTrue(AnnotationUtils.equals(a1, a2)); - + // Different value var a3 = TestClass3.class.getAnnotation(SimpleAnnotation.class); assertFalse(AnnotationUtils.equals(a1, a3)); - + // Both null assertTrue(AnnotationUtils.equals(null, null)); - + // First null assertFalse(AnnotationUtils.equals(null, a1)); - + // Second null assertFalse(AnnotationUtils.equals(a1, null)); - + // Different types var a4 = TestClass4.class.getAnnotation(DifferentAnnotation.class); assertFalse(AnnotationUtils.equals(a1, a4)); - + // Multiple members - same var a5 = TestClass5.class.getAnnotation(MultiMemberAnnotation.class); var a6 = TestClass6.class.getAnnotation(MultiMemberAnnotation.class); assertTrue(AnnotationUtils.equals(a5, a6)); - + // Multiple members - different boolean var a7 = TestClass7.class.getAnnotation(MultiMemberAnnotation.class); assertFalse(AnnotationUtils.equals(a5, a7)); - + // Multiple members - different string var a8 = TestClass8.class.getAnnotation(MultiMemberAnnotation.class); assertFalse(AnnotationUtils.equals(a5, a8)); - + // Multiple members - different int var a9 = TestClass9.class.getAnnotation(MultiMemberAnnotation.class); assertFalse(AnnotationUtils.equals(a5, a9)); - + // Array members - same var a10 = TestClass10.class.getAnnotation(ArrayAnnotation.class); var a11 = TestClass11.class.getAnnotation(ArrayAnnotation.class); assertTrue(AnnotationUtils.equals(a10, a11)); - + // Array members - different length var a12 = TestClass12.class.getAnnotation(ArrayAnnotation.class); assertFalse(AnnotationUtils.equals(a10, a12)); - + // Array members - different int array length var a13 = TestClass13.class.getAnnotation(ArrayAnnotation.class); assertFalse(AnnotationUtils.equals(a10, a13)); - + // Array members - different string values var a14 = TestClass14.class.getAnnotation(ArrayAnnotation.class); assertFalse(AnnotationUtils.equals(a10, a14)); - + // Array members - different int values var a15 = TestClass15.class.getAnnotation(ArrayAnnotation.class); assertFalse(AnnotationUtils.equals(a10, a15)); - + // Array members - empty arrays var a16 = TestClass16.class.getAnnotation(ArrayAnnotation.class); var a16b = TestClass16.class.getAnnotation(ArrayAnnotation.class); assertTrue(AnnotationUtils.equals(a16, a16b)); - + // Primitive arrays - same var a17 = TestClass17.class.getAnnotation(PrimitiveArrayAnnotation.class); var a18 = TestClass18.class.getAnnotation(PrimitiveArrayAnnotation.class); assertTrue(AnnotationUtils.equals(a17, a18)); - + // Primitive arrays - different var a19 = TestClass19.class.getAnnotation(PrimitiveArrayAnnotation.class); assertFalse(AnnotationUtils.equals(a17, a19)); - + // Nested annotation - same var a20 = TestClass20.class.getAnnotation(NestedAnnotation.class); var a21 = TestClass21.class.getAnnotation(NestedAnnotation.class); assertTrue(AnnotationUtils.equals(a20, a21)); - + // Nested annotation - different var a22 = TestClass22.class.getAnnotation(NestedAnnotation.class); assertFalse(AnnotationUtils.equals(a20, a22)); - + // Nested annotation array - same var a23 = TestClass23.class.getAnnotation(NestedArrayAnnotation.class); var a24 = TestClass24.class.getAnnotation(NestedArrayAnnotation.class); assertTrue(AnnotationUtils.equals(a23, a24)); - + // Nested annotation array - different var a25 = TestClass25.class.getAnnotation(NestedArrayAnnotation.class); assertFalse(AnnotationUtils.equals(a23, a25)); - + // Default values var a27 = TestClass27.class.getAnnotation(DefaultValueAnnotation.class); var a28 = TestClass28.class.getAnnotation(DefaultValueAnnotation.class); assertTrue(AnnotationUtils.equals(a27, a28)); - + // Null member values - test line 169 try { var a29 = TestClass29.class.getAnnotation(NullableMemberAnnotation.class); - + // Create annotation proxy with null member Annotation nullMember1 = (Annotation) java.lang.reflect.Proxy.newProxyInstance( MemberEqualsTestAnnotation.class.getClassLoader(), @@ -362,7 +360,7 @@ class AnnotationUtils_Test { return method.invoke(a29, args); } ); - + // Create another annotation proxy with non-null member Annotation nonNullMember = (Annotation) java.lang.reflect.Proxy.newProxyInstance( MemberEqualsTestAnnotation.class.getClassLoader(), @@ -386,7 +384,7 @@ class AnnotationUtils_Test { return method.invoke(a29, args); } ); - + // Test line 169: memberEquals when o1 == null || o2 == null assertFalse(AnnotationUtils.equals(nullMember1, nonNullMember)); assertFalse(AnnotationUtils.equals(nonNullMember, nullMember1)); @@ -404,36 +402,36 @@ class AnnotationUtils_Test { var a1 = TestClass1.class.getAnnotation(SimpleAnnotation.class); var a2 = TestClass2.class.getAnnotation(SimpleAnnotation.class); assertEquals(hash(a1), hash(a2)); - + // Different values var a3 = TestClass3.class.getAnnotation(SimpleAnnotation.class); assertNotEquals(hash(a1), hash(a3)); - + // Multiple members var a5 = TestClass5.class.getAnnotation(MultiMemberAnnotation.class); var a6 = TestClass6.class.getAnnotation(MultiMemberAnnotation.class); assertEquals(hash(a5), hash(a6)); - + // Array members var a10 = TestClass10.class.getAnnotation(ArrayAnnotation.class); var a11 = TestClass11.class.getAnnotation(ArrayAnnotation.class); assertEquals(hash(a10), hash(a11)); - + // Primitive arrays var a17 = TestClass17.class.getAnnotation(PrimitiveArrayAnnotation.class); var a18 = TestClass18.class.getAnnotation(PrimitiveArrayAnnotation.class); assertEquals(hash(a17), hash(a18)); - + // Nested annotation var a20 = TestClass20.class.getAnnotation(NestedAnnotation.class); var a21 = TestClass21.class.getAnnotation(NestedAnnotation.class); assertEquals(hash(a20), hash(a21)); - + // Nested annotation array var a23 = TestClass23.class.getAnnotation(NestedArrayAnnotation.class); var a24 = TestClass24.class.getAnnotation(NestedArrayAnnotation.class); assertEquals(hash(a23), hash(a24)); - + // Consistency with equals assertTrue(AnnotationUtils.equals(a1, a2)); assertEquals(hash(a1), hash(a2)); @@ -441,22 +439,22 @@ class AnnotationUtils_Test { assertEquals(hash(a5), hash(a6)); assertTrue(AnnotationUtils.equals(a10, a11)); assertEquals(hash(a10), hash(a11)); - + // Empty annotation var a26 = TestClass26.class.getAnnotation(EmptyAnnotation.class); int hashCode = hash(a26); assertTrue(hashCode >= 0 || hashCode < 0); // Just verify it returns a value - + // Default values var a27 = TestClass27.class.getAnnotation(DefaultValueAnnotation.class); var a28 = TestClass28.class.getAnnotation(DefaultValueAnnotation.class); assertTrue(AnnotationUtils.equals(a27, a28)); assertEquals(hash(a27), hash(a28)); - + // Null member values - test line 157 try { var a29 = TestClass29.class.getAnnotation(NullableMemberAnnotation.class); - + // Create a custom annotation proxy that returns null for the value() method Annotation nullMemberAnnotation = (Annotation) java.lang.reflect.Proxy.newProxyInstance( NullableMemberAnnotation.class.getClassLoader(), @@ -480,7 +478,7 @@ class AnnotationUtils_Test { return method.invoke(a29, args); } ); - + // Test that hash() handles null member values correctly (line 157) int hashNull = hash(nullMemberAnnotation); // Should not throw, and should return a hash code based on part1 (name.hashCode() * 127) @@ -500,13 +498,13 @@ class AnnotationUtils_Test { List<Annotation> result1 = streamRepeated(a1).collect(Collectors.toList()); assertEquals(1, result1.size()); assertSame(a1, result1.get(0)); - + // Test with empty annotation var a26 = TestClass26.class.getAnnotation(EmptyAnnotation.class); List<Annotation> result2 = streamRepeated(a26).collect(Collectors.toList()); assertEquals(1, result2.size()); assertSame(a26, result2.get(0)); - + // Test with multi-member annotation var a5 = TestClass5.class.getAnnotation(MultiMemberAnnotation.class); List<Annotation> result3 = streamRepeated(a5).collect(Collectors.toList()); diff --git a/juneau-utest/src/test/java/org/apache/juneau/commons/utils/CollectionUtils_Test.java b/juneau-utest/src/test/java/org/apache/juneau/commons/utils/CollectionUtils_Test.java index 31bec0d685..c463bb23b6 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/commons/utils/CollectionUtils_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/commons/utils/CollectionUtils_Test.java @@ -1297,6 +1297,7 @@ class CollectionUtils_Test extends TestBase { ArrayList<String> arrayList = new ArrayList<>(); arrayList.add("a"); arrayList.add("b"); + @SuppressWarnings("cast") List<?> result1 = toList((Object)arrayList); assertSame(arrayList, result1); @@ -1446,7 +1447,6 @@ class CollectionUtils_Test extends TestBase { assertTrue(nestedResult.get(0) instanceof List); assertTrue(nestedResult.get(1) instanceof List); - String[] arr2 = {"a", "b", "c"}; List<Object> result = toObjectList(arr); assertNotNull(result); assertEquals(3, result.size()); diff --git a/juneau-utest/src/test/java/org/apache/juneau/commons/utils/IoUtils_Test.java b/juneau-utest/src/test/java/org/apache/juneau/commons/utils/IoUtils_Test.java index 95bbbd88cd..3f4e23f850 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/commons/utils/IoUtils_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/commons/utils/IoUtils_Test.java @@ -68,6 +68,13 @@ class IoUtils_Test extends TestBase { // Test with empty array close(); + + // Test with IOException (line 100) + var throwingIs = new ThrowingTestInputStream("test"); + var throwingOs = new ThrowingTestOutputStream(); + var throwingR = new ThrowingTestReader(); + var throwingW = new ThrowingTestWriter(); + assertThrows(IOException.class, () -> close(throwingIs, throwingOs, throwingR, throwingW)); } //==================================================================================================== @@ -199,6 +206,11 @@ class IoUtils_Test extends TestBase { // Test with empty array flush(); + + // Test with IOException (line 245) + var throwingOs = new ThrowingTestOutputStream(); + var throwingW = new ThrowingTestWriter(); + assertThrows(IOException.class, () -> flush(throwingOs, throwingW)); } //==================================================================================================== @@ -213,6 +225,12 @@ class IoUtils_Test extends TestBase { assertNotNull(loadSystemResourceAsString("test3.txt", ".")); assertNotNull(loadSystemResourceAsString("test4.txt", ".", "sub")); assertNotNull(loadSystemResourceAsString("test4.txt", "sub")); + + // Test system resource path (line 280) + // Try to load a resource that exists in the system classloader + loadSystemResourceAsString("java/lang/String.class", "."); // Exercise the code path + // This may or may not return null depending on whether the resource is accessible + // The important thing is that line 280 is executed } //==================================================================================================== @@ -268,6 +286,18 @@ class IoUtils_Test extends TestBase { assertEquals(data.length(), count); assertEquals(data, os.toString()); assertFalse(exceptionCaught.get()); + + // Test with IOException (line 355) + var throwingIs = new ThrowingTestInputStream(data); + exceptionCaught.set(false); + var exception = new AtomicReference<IOException>(); + count = pipe(throwingIs, os, e -> { + exceptionCaught.set(true); + exception.set(e); + }); + assertTrue(exceptionCaught.get()); + assertNotNull(exception.get()); + assertEquals(-1, count); } //==================================================================================================== @@ -292,6 +322,13 @@ class IoUtils_Test extends TestBase { // Test with null assertEquals(0, pipe((InputStream)null, os, -1)); assertEquals(0, pipe(is, null, -1)); + + // Test with end of stream (read returns -1) (line 395) + var emptyIs = new ByteArrayInputStream(new byte[0]); + os = new ByteArrayOutputStream(); + count = pipe(emptyIs, os, 100); + assertEquals(0, count); + assertEquals(0, os.size()); } //==================================================================================================== @@ -324,6 +361,22 @@ class IoUtils_Test extends TestBase { assertEquals(data.length(), count); assertEquals(data, w.toString()); assertFalse(exceptionCaught.get()); + + // Test with null (line 444) + assertEquals(0, pipe((InputStream)null, w, e -> exceptionCaught.set(true))); + assertEquals(0, pipe(is, (Writer)null, e -> exceptionCaught.set(true))); + + // Test with IOException (line 447) + var throwingIs = new ThrowingTestInputStream(data); + exceptionCaught.set(false); + var exception = new AtomicReference<IOException>(); + count = pipe(throwingIs, w, e -> { + exceptionCaught.set(true); + exception.set(e); + }); + assertTrue(exceptionCaught.get()); + assertNotNull(exception.get()); + assertEquals(-2, count); } //==================================================================================================== @@ -378,6 +431,23 @@ class IoUtils_Test extends TestBase { assertEquals(data.length(), count); assertEquals(data, os.toString()); assertFalse(exceptionCaught.get()); + + // Test with IOException (line 523) + var throwingR = new StringReader(data) { + @Override + public int read(char[] cbuf, int off, int len) throws IOException { + throw new IOException("Test exception"); + } + }; + exceptionCaught.set(false); + var exception = new AtomicReference<IOException>(); + count = pipe(throwingR, os, e -> { + exceptionCaught.set(true); + exception.set(e); + }); + assertTrue(exceptionCaught.get()); + assertNotNull(exception.get()); + assertEquals(-1, count); } //==================================================================================================== @@ -413,6 +483,23 @@ class IoUtils_Test extends TestBase { assertEquals(data.length(), count); assertEquals(data, w.toString()); assertFalse(exceptionCaught.get()); + + // Test with IOException (line 578) + var throwingR = new StringReader(data) { + @Override + public int read(char[] cbuf, int off, int len) throws IOException { + throw new IOException("Test exception"); + } + }; + exceptionCaught.set(false); + var exception = new AtomicReference<IOException>(); + count = pipe(throwingR, w, e -> { + exceptionCaught.set(true); + exception.set(e); + }); + assertTrue(exceptionCaught.get()); + assertNotNull(exception.get()); + assertEquals(-1, count); } //==================================================================================================== @@ -526,6 +613,18 @@ class IoUtils_Test extends TestBase { // Test with null assertNull(read((InputStream)null, StandardCharsets.UTF_8, e -> exceptionCaught.set(true))); + + // Test with IOException (line 727) + var throwingIs = new ThrowingTestInputStream(data); + exceptionCaught.set(false); + var exception = new AtomicReference<IOException>(); + result = read(throwingIs, StandardCharsets.UTF_8, e -> { + exceptionCaught.set(true); + exception.set(e); + }); + assertTrue(exceptionCaught.get()); + assertNotNull(exception.get()); + assertNull(result); } //==================================================================================================== @@ -601,28 +700,32 @@ class IoUtils_Test extends TestBase { void a033_read_Object() throws IOException { var data = "Hello World"; - // Test with Reader + // Test with Reader (line 827) var r = new StringReader(data); - assertEquals(data, read(r)); + Object readerObj = r; // Explicitly cast to Object to ensure read(Object) is called + assertEquals(data, read(readerObj)); - // Test with InputStream + // Test with InputStream (line 829) var is = new ByteArrayInputStream(data.getBytes()); - assertEquals(data, read(is)); + Object inputStreamObj = is; // Explicitly cast to Object to ensure read(Object) is called + assertEquals(data, read(inputStreamObj)); - // Test with File + // Test with File (line 831) var file = File.createTempFile("test", ".txt"); try { try (var w = new FileWriter(file)) { w.write(data); } - assertEquals(data, read(file)); + Object fileObj = file; // Explicitly cast to Object to ensure read(Object) is called + assertEquals(data, read(fileObj)); } finally { file.delete(); } - // Test with byte[] + // Test with byte[] (line 833) var bytes = data.getBytes(); - assertEquals(data, read(bytes)); + Object bytesObj = bytes; // Explicitly cast to Object to ensure read(Object) is called + assertEquals(data, read(bytesObj)); // Test with null assertNull(read((Object)null)); @@ -676,6 +779,18 @@ class IoUtils_Test extends TestBase { // Test with null assertNull(read((Reader)null, e -> exceptionCaught.set(true))); + + // Test with IOException (line 900) + var throwingR = new ThrowingTestReader(); + exceptionCaught.set(false); + var exception = new AtomicReference<IOException>(); + result = read(throwingR, e -> { + exceptionCaught.set(true); + exception.set(e); + }); + assertTrue(exceptionCaught.get()); + assertNotNull(exception.get()); + assertNull(result); } //==================================================================================================== @@ -823,6 +938,28 @@ class IoUtils_Test extends TestBase { assertNull(toBufferedReader(null)); } + //==================================================================================================== + // EMPTY_INPUT_STREAM and EMPTY_READER tests + //==================================================================================================== + @Test + void a044_emptyInputStream() throws IOException { + // Test line 44: EMPTY_INPUT_STREAM.read() + assertEquals(-1, EMPTY_INPUT_STREAM.read()); + } + + @Test + void a045_emptyReader() throws IOException { + // Test line 65: EMPTY_READER.close() + EMPTY_READER.close(); // Should not throw + + // Test line 69: EMPTY_READER.read() + assertEquals(-1, EMPTY_READER.read()); + + // Test line 74: EMPTY_READER.read(char[], int, int) + var buf = new char[10]; + assertEquals(-1, EMPTY_READER.read(buf, 0, 10)); + } + //==================================================================================================== // Test helper classes //==================================================================================================== @@ -880,5 +1017,79 @@ class IoUtils_Test extends TestBase { return new String(this.toByteArray(), UTF8); } } + + public static class ThrowingTestInputStream extends InputStream { + private final byte[] data; + private int pos = 0; + + public ThrowingTestInputStream(String s) { + this.data = s.getBytes(); + } + + @Override + public int read() throws IOException { + if (pos >= data.length) + return -1; + return data[pos++] & 0xFF; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + throw new IOException("Test exception"); + } + } + + public static class ThrowingTestOutputStream extends OutputStream { + private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + @Override + public void write(int b) throws IOException { + baos.write(b); + } + + @Override + public void flush() throws IOException { + throw new IOException("Test exception"); + } + + @Override + public void close() throws IOException { + throw new IOException("Test exception"); + } + } + + public static class ThrowingTestReader extends Reader { + public ThrowingTestReader() { + } + + @Override + public int read(char[] cbuf, int off, int len) throws IOException { + throw new IOException("Test exception"); + } + + @Override + public void close() throws IOException { + throw new IOException("Test exception"); + } + } + + public static class ThrowingTestWriter extends Writer { + private final StringWriter sw = new StringWriter(); + + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + sw.write(cbuf, off, len); + } + + @Override + public void flush() throws IOException { + throw new IOException("Test exception"); + } + + @Override + public void close() throws IOException { + throw new IOException("Test exception"); + } + } }
