From e65479f2da176fb98d707855bc34a061ae2e22e2 Mon Sep 17 00:00:00 2001 From: Leonard Husmann Date: Tue, 30 May 2023 14:41:24 +0200 Subject: [PATCH] add test cases This commit adds test cases for getAllInvolvedRawTypes() of JavaClass, JavaTypeVariable and JavaWildcardType. This also adds a test case for getAllInvolvedRawTypesInSignature() of JavaCodeUnit. Issue: #723 Signed-off-by: Leonard Husmann --- .../archunit/core/domain/JavaClassTest.java | 232 ++++++++++-------- .../core/domain/JavaCodeUnitTest.java | 33 ++- .../core/domain/JavaTypeVariableTest.java | 36 ++- .../core/domain/JavaWildcardTypeTest.java | 76 ++++++ 4 files changed, 271 insertions(+), 106 deletions(-) diff --git a/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaClassTest.java b/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaClassTest.java index 6654d5e962..ca5bc5ec61 100644 --- a/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaClassTest.java +++ b/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaClassTest.java @@ -108,6 +108,7 @@ import static java.util.regex.Pattern.quote; import static java.util.stream.Collectors.toSet; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.Assert.assertEquals; @RunWith(DataProviderRunner.class) @SuppressWarnings("SameParameterValue") @@ -152,7 +153,8 @@ Object notAnArray() { @Test public void finds_multidimensional_array_type() { - JavaClasses classes = importClassesWithContext(ClassUsedInArray.class, ClassAccessingOneDimensionalArray.class, ClassAccessingTwoDimensionalArray.class); + JavaClasses classes = + importClassesWithContext(ClassUsedInArray.class, ClassAccessingOneDimensionalArray.class, ClassAccessingTwoDimensionalArray.class); JavaClass type = classes.get(ClassUsedInArray.class); JavaClass oneDimArray = classes.get(ClassAccessingOneDimensionalArray.class).getField("array").getRawType(); JavaClass twoDimArray = classes.get(ClassAccessingTwoDimensionalArray.class).getField("array").getRawType(); @@ -174,6 +176,23 @@ class SimpleClass { assertThat(type.toErasure()).isEqualTo(type); } + @Test + public void get_all_involved_raw_types_of_self() { + class SimpleClass { + public SimpleClass method() { + return this; + } + } + + JavaClass clazz = new ClassFileImporter().importClass(SimpleClass.class); + JavaMethod method = clazz.getMethod("method"); + + Set involvedRawTypes = method.getReturnType().getAllInvolvedRawTypes(); + + Set expected = ImmutableSet.of(clazz); + assertEquals(expected, involvedRawTypes); + } + @Test public void finds_component_type_chain_of_otherwise_unreferenced_component_type() { @SuppressWarnings("unused") @@ -556,7 +575,8 @@ class Child extends Base< .withExpectedDescriptionPatternTemplate( ".*has generic superclass <" + quote(Base.class.getName()) + ".+> with type argument depending on <#target>.*") - .to(Comparable.class, Map.class, Map.Entry.class, String.class, BufferedInputStream[][].class, Serializable.class, List.class, Set.class, Iterable.class, File.class) + .to(Comparable.class, Map.class, Map.Entry.class, String.class, BufferedInputStream[][].class, Serializable.class, List.class, + Set.class, Iterable.class, File.class) .from(Child.class).to(BufferedInputStream.class).inLocation(getClass(), 0) .withDescriptionContaining("depends on component type <%s>", BufferedInputStream.class.getName()) @@ -583,7 +603,8 @@ class Child implements InterfaceWithTwoTypeParameters< .withExpectedDescriptionPatternTemplate( ".*has generic interface <" + quote(InterfaceWithTwoTypeParameters.class.getName()) + ".+> with type argument depending on <#target>.*") - .to(Comparable.class, Map.class, Map.Entry.class, String.class, BufferedInputStream[][].class, Serializable.class, List.class, Set.class, Iterable.class, File.class) + .to(Comparable.class, Map.class, Map.Entry.class, String.class, BufferedInputStream[][].class, Serializable.class, List.class, + Set.class, Iterable.class, File.class) .from(Child.class).to(BufferedInputStream.class).inLocation(getClass(), 0) .withDescriptionContaining("depends on component type <%s>", BufferedInputStream.class.getName()) @@ -599,18 +620,18 @@ class SomeGenericType { class SomeClass { // @formatter:off SomeGenericType< - Comparable>, - Map< - Map.Entry>, - Map< - ? extends BufferedInputStream[][], - Map< - ? extends Serializable, - List>>>> - > - > - > - > field; + Comparable>, + Map< + Map.Entry>, + Map< + ? extends BufferedInputStream[][], + Map< + ? extends Serializable, + List>>>> + > + > + > + > field; // @formatter:on } @@ -624,7 +645,8 @@ class SomeClass { .withExpectedDescriptionPatternTemplate( ".*has generic type <" + quote(SomeGenericType.class.getName()) + ".+> with type argument depending on <#target>.*") - .to(Comparable.class, Map.class, Map.Entry.class, String.class, BufferedInputStream[][].class, Serializable.class, List.class, Set.class, Iterable.class, File.class) + .to(Comparable.class, Map.class, Map.Entry.class, String.class, BufferedInputStream[][].class, Serializable.class, List.class, + Set.class, Iterable.class, File.class) .from(SomeClass.class).to(BufferedInputStream.class).inLocation(getClass(), 0) .withDescriptionContaining("depends on component type <%s>", BufferedInputStream.class.getName()) @@ -640,19 +662,19 @@ class SomeGenericType { class SomeClass { // @formatter:off SomeGenericType< - Comparable>, - Map< - Map.Entry>, - Map< - ? extends BufferedInputStream[][], - Map< - ? extends Serializable, - List>>>> - > - > - > - > method() { - return null; + Comparable>, + Map< + Map.Entry>, + Map< + ? extends BufferedInputStream[][], + Map< + ? extends Serializable, + List>>>> + > + > + > + > method() { + return null; } // @formatter:on } @@ -661,13 +683,15 @@ > method() { assertThatDependencies(javaClass.getDirectDependenciesFromSelf()) .contain(from(SomeClass.class).to(SomeGenericType.class).inLocation(getClass(), 0) - .withDescriptionContaining("Method <%s.method()> has return type <%s>", SomeClass.class.getName(), SomeGenericType.class.getName()) + .withDescriptionContaining("Method <%s.method()> has return type <%s>", SomeClass.class.getName(), + SomeGenericType.class.getName()) .from(SomeClass.class) .withExpectedDescriptionPatternTemplate( ".*has generic return type <" + quote(SomeGenericType.class.getName()) + ".+> with type argument depending on <#target>.*") - .to(Comparable.class, Map.class, Map.Entry.class, String.class, BufferedInputStream[][].class, Serializable.class, List.class, Set.class, Iterable.class, File.class) + .to(Comparable.class, Map.class, Map.Entry.class, String.class, BufferedInputStream[][].class, Serializable.class, List.class, + Set.class, Iterable.class, File.class) .from(SomeClass.class).to(BufferedInputStream.class).inLocation(getClass(), 0) .withDescriptionContaining("depends on component type <%s>", BufferedInputStream.class.getName()) @@ -683,20 +707,20 @@ class SomeGenericType { class SomeClass { // @formatter:off void method( - SomeGenericType< - Comparable>, - Map< - Map.Entry>, - Map< - ? extends BufferedInputStream[][], - Map< - ? extends Serializable, - List>>>> - > - > - > - > firstParam, - List secondParam) { + SomeGenericType< + Comparable>, + Map< + Map.Entry>, + Map< + ? extends BufferedInputStream[][], + Map< + ? extends Serializable, + List>>>> + > + > + > + > firstParam, + List secondParam) { } // @formatter:on } @@ -716,7 +740,8 @@ void method( .withExpectedDescriptionPatternTemplate( ".*has generic parameter type <" + quote(SomeGenericType.class.getName()) + ".+> with type argument depending on <#target>.*") - .to(Comparable.class, Map.class, Map.Entry.class, String.class, BufferedInputStream[][].class, Serializable.class, List.class, Set.class, Iterable.class, File.class) + .to(Comparable.class, Map.class, Map.Entry.class, String.class, BufferedInputStream[][].class, Serializable.class, List.class, + Set.class, Iterable.class, File.class) .from(SomeClass.class) .withExpectedDescriptionPatternTemplate( @@ -805,12 +830,14 @@ public void finds_array_component_types_as_dependencies_from_self() { from(ArrayComponentTypeDependencies.class).to(ComponentTypeDependency.class) .withDescriptionContaining("Constructor <%s.(%s)> depends on component type <%s>", - ArrayComponentTypeDependencies.class.getName(), ComponentTypeDependency[].class.getName(), ComponentTypeDependency.class.getName()) + ArrayComponentTypeDependencies.class.getName(), ComponentTypeDependency[].class.getName(), + ComponentTypeDependency.class.getName()) .inLocation(ArrayComponentTypeDependencies.class, 0). from(ArrayComponentTypeDependencies.class).to(ComponentTypeDependency.class) .withDescriptionContaining("Method <%s.asMethodParameter(%s)> depends on component type <%s>", - ArrayComponentTypeDependencies.class.getName(), ComponentTypeDependency[].class.getName(), ComponentTypeDependency.class.getName()) + ArrayComponentTypeDependencies.class.getName(), ComponentTypeDependency[].class.getName(), + ComponentTypeDependency.class.getName()) .inLocation(ArrayComponentTypeDependencies.class, 0). from(ArrayComponentTypeDependencies.class).to(ComponentTypeDependency.class) @@ -846,7 +873,8 @@ class ClassWithTypeParameters< .from(ClassWithTypeParameters.class) .withExpectedDescriptionTemplate("type parameter 'SECOND' depending on") - .to(Map.class, Map.Entry.class, String.class, BufferedInputStream[][].class, Serializable.class, List.class, Set.class, Iterable.class, File.class) + .to(Map.class, Map.Entry.class, String.class, BufferedInputStream[][].class, Serializable.class, List.class, Set.class, + Iterable.class, File.class) .inLocation(getClass(), 0) .from(ClassWithTypeParameters.class).to(BufferedInputStream.class).inLocation(getClass(), 0) @@ -897,7 +925,8 @@ public void test_direct_dependencies_from_self_by_code_unit_type_parameters(Java .from(javaClass) .withExpectedDescriptionTemplate("type parameter 'SECOND' depending on") - .to(Map.class, Map.Entry.class, String.class, BufferedInputStream[][].class, Serializable.class, List.class, Set.class, Iterable.class, File.class) + .to(Map.class, Map.Entry.class, String.class, BufferedInputStream[][].class, Serializable.class, List.class, Set.class, + Iterable.class, File.class) .inLocation(getClass(), 0) .from(javaClass).to(BufferedInputStream.class).inLocation(getClass(), 0) @@ -1063,18 +1092,18 @@ class FirstGenericType { class FirstClass { // @formatter:off FirstGenericType< - Comparable, - Map< - Map.Entry>, - Map< - ? extends BufferedInputStream[][], - Map< - ? extends Serializable, - List>>>> - > - > - > - > field; + Comparable, + Map< + Map.Entry>, + Map< + ? extends BufferedInputStream[][], + Map< + ? extends Serializable, + List>>>> + > + > + > + > field; // @formatter:on } @SuppressWarnings("unused") @@ -1112,19 +1141,19 @@ class FirstGenericType { class FirstClass { // @formatter:off FirstGenericType< - Comparable, - Map< - Map.Entry>, - Map< - ? extends BufferedInputStream[][], - Map< - ? extends Serializable, - List>>>> - > - > - > - > method() { - return null; + Comparable, + Map< + Map.Entry>, + Map< + ? extends BufferedInputStream[][], + Map< + ? extends Serializable, + List>>>> + > + > + > + > method() { + return null; } // @formatter:on } @@ -1165,19 +1194,19 @@ class FirstGenericType { class FirstClass { // @formatter:off void method( - FirstGenericType< - Comparable, - Map< - Map.Entry>, - Map< - ? extends BufferedInputStream[][], - Map< - ? extends Serializable, - List>>>> - > - > - > - > param) { + FirstGenericType< + Comparable, + Map< + Map.Entry>, + Map< + ? extends BufferedInputStream[][], + Map< + ? extends Serializable, + List>>>> + > + > + > + > param) { } // @formatter:on } @@ -1194,11 +1223,13 @@ void method(List irrelevant, SecondGenericType> par assertThatDependencies(javaClasses.get(File.class).getDirectDependenciesToSelf()) .contain(from(FirstClass.class).to(File.class).inLocation(getClass(), 0) - .withDescriptionMatching("Method <%s.method\\([^)]+\\)> has generic parameter type <%s.+> with type argument depending on <%s>.*", + .withDescriptionMatching( + "Method <%s.method\\([^)]+\\)> has generic parameter type <%s.+> with type argument depending on <%s>.*", FirstClass.class.getName(), FirstGenericType.class.getName(), File.class.getName()) .from(SecondChild.class).to(File.class).inLocation(getClass(), 0) - .withDescriptionMatching("Method <%s.method\\([^)]+\\)> has generic parameter type <%s.+> with type argument depending on <%s>.*", + .withDescriptionMatching( + "Method <%s.method\\([^)]+\\)> has generic parameter type <%s.+> with type argument depending on <%s>.*", SecondChild.class.getName(), SecondGenericType.class.getName(), File.class.getName()) ); @@ -1343,12 +1374,14 @@ public void finds_array_component_types_as_dependencies_to_self() { from(ArrayComponentTypeDependencies.class).to(ComponentTypeDependency.class) .withDescriptionContaining("Constructor <%s.(%s)> depends on component type <%s>", - ArrayComponentTypeDependencies.class.getName(), ComponentTypeDependency[].class.getName(), ComponentTypeDependency.class.getName()) + ArrayComponentTypeDependencies.class.getName(), ComponentTypeDependency[].class.getName(), + ComponentTypeDependency.class.getName()) .inLocation(ArrayComponentTypeDependencies.class, 0). from(ArrayComponentTypeDependencies.class).to(ComponentTypeDependency.class) .withDescriptionContaining("Method <%s.asMethodParameter(%s)> depends on component type <%s>", - ArrayComponentTypeDependencies.class.getName(), ComponentTypeDependency[].class.getName(), ComponentTypeDependency.class.getName()) + ArrayComponentTypeDependencies.class.getName(), ComponentTypeDependency[].class.getName(), + ComponentTypeDependency.class.getName()) .inLocation(ArrayComponentTypeDependencies.class, 0). from(ArrayComponentTypeDependencies.class).to(ComponentTypeDependency.class) @@ -1375,7 +1408,8 @@ class SecondDependingOnOtherThroughTypeParameter< V extends Map> { } - JavaClass someClass = importClasses(ClassOtherTypeSignaturesDependOn.class, FirstDependingOnOtherThroughTypeParameter.class, SecondDependingOnOtherThroughTypeParameter.class) + JavaClass someClass = importClasses(ClassOtherTypeSignaturesDependOn.class, FirstDependingOnOtherThroughTypeParameter.class, + SecondDependingOnOtherThroughTypeParameter.class) .get(ClassOtherTypeSignaturesDependOn.class); assertThatDependencies(someClass.getDirectDependenciesToSelf()) @@ -1450,7 +1484,8 @@ > void secondDependingOnOtherThroughMethodTypeParameter() { @Test @UseDataProvider - public void test_direct_dependencies_to_self_by_code_unit_type_parameters(JavaClass firstOrigin, JavaClass secondOrigin, JavaClass expectedTarget) { + public void test_direct_dependencies_to_self_by_code_unit_type_parameters(JavaClass firstOrigin, JavaClass secondOrigin, + JavaClass expectedTarget) { assertThatDependencies(expectedTarget.getDirectDependenciesToSelf()) .contain(from(firstOrigin).to(expectedTarget).inLocation(getClass(), 0) .withDescriptionContaining("type parameter 'T' depending on") @@ -1551,7 +1586,8 @@ Consumer origin() { } } - JavaClass javaClass = new ClassFileImporter().importClasses(Origin.class, Data_function_get_code_unit_references.Target.class).get(Origin.class); + JavaClass javaClass = + new ClassFileImporter().importClasses(Origin.class, Data_function_get_code_unit_references.Target.class).get(Origin.class); assertThat(JavaClass.Functions.GET_CODE_UNIT_REFERENCES_FROM_SELF.apply(javaClass)).isEqualTo(javaClass.getCodeUnitReferencesFromSelf()); assertThat(JavaClass.Functions.GET_METHOD_REFERENCES_FROM_SELF.apply(javaClass)).isEqualTo(javaClass.getMethodReferencesFromSelf()); @@ -1829,7 +1865,8 @@ public static Object[][] data_predicate_belong_to() { belongToAnyOf(Object.class, ClassWithNamedAndAnonymousInnerClasses.class), belongTo(describe( String.format("any of [%s, %s]", Object.class.getName(), ClassWithNamedAndAnonymousInnerClasses.class.getName()), - javaClass -> javaClass.isEquivalentTo(Object.class) || javaClass.isEquivalentTo(ClassWithNamedAndAnonymousInnerClasses.class))) + javaClass -> javaClass.isEquivalentTo(Object.class) || javaClass.isEquivalentTo( + ClassWithNamedAndAnonymousInnerClasses.class))) ); } @@ -2487,7 +2524,8 @@ void method(@OnMethodParam String param) { WithOtherEnum annotationWithDefault() default @WithOtherEnum( someEnum = SomeOtherEnumAsAnnotationParameter.OTHER_ANNOTATION_PARAMETER, - enumArray = {SomeOtherEnumAsAnnotationArrayParameter.OTHER_ANNOTATION_ARRAY_PARAMETER, SomeOtherEnumAsAnnotationArrayParameter.OTHER_ANNOTATION_ARRAY_PARAMETER}); + enumArray = {SomeOtherEnumAsAnnotationArrayParameter.OTHER_ANNOTATION_ARRAY_PARAMETER, + SomeOtherEnumAsAnnotationArrayParameter.OTHER_ANNOTATION_ARRAY_PARAMETER}); } @Retention(RUNTIME) diff --git a/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaCodeUnitTest.java b/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaCodeUnitTest.java index e2b61efd45..0e8410087d 100644 --- a/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaCodeUnitTest.java +++ b/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaCodeUnitTest.java @@ -1,10 +1,13 @@ package com.tngtech.archunit.core.domain; import java.io.File; +import java.io.Serializable; import java.util.List; import java.util.Map; +import java.util.Set; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import com.tngtech.archunit.core.importer.ClassFileImporter; import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.DataProviderRunner; @@ -22,10 +25,28 @@ import static com.tngtech.archunit.testutil.Assertions.assertThatAnnotation; import static com.tngtech.java.junit.dataprovider.DataProviders.testForEach; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.Assert.assertEquals; @RunWith(DataProviderRunner.class) public class JavaCodeUnitTest { + @Test + public void returns_all_involved_raw_types_in_signature() { + class SampleClass { + @SuppressWarnings("unused") + T method(List input) { + return null; + } + } + JavaClasses classes = new ClassFileImporter().importClasses(SampleClass.class, Serializable.class, List.class, String.class); + JavaMethod method = classes.get(SampleClass.class).getMethod("method", List.class); + + Set involvedRawTypesInSignature = method.getAllRawTypesInvolvedInSignature(); + + Set expected = ImmutableSet.of(classes.get(Serializable.class), classes.get(List.class), classes.get(String.class)); + assertEquals(expected, involvedRawTypesInSignature); + } + @Test public void offers_all_calls_from_Self() { JavaMethod method = importClassWithContext(ClassAccessingOtherClass.class).getMethod("access", ClassBeingAccessed.class); @@ -120,7 +141,8 @@ public void falls_back_to_creating_parameters_with_only_generic_types_if_match_b class LocalClassReferencingNonConstantFromOuterScope { @SuppressWarnings("unused") LocalClassReferencingNonConstantFromOuterScope(List someParameterizedType) { - System.out.println("Using " + nonConstant + " which causes another synthetic List parameter to be appended to the constructor"); + System.out.println( + "Using " + nonConstant + " which causes another synthetic List parameter to be appended to the constructor"); } } @@ -159,10 +181,13 @@ void method(List first, T second, String third, int fourth) { public void adds_description_to_parameters_of_code_unit(JavaCodeUnit codeUnit) { List parameters = codeUnit.getParameters(); - assertThat(parameters.get(0).getDescription()).isEqualTo("Parameter <" + List.class.getName() + "<" + String.class.getName() + ">> of " + startWithLowercase(codeUnit.getDescription())); + assertThat(parameters.get(0).getDescription()).isEqualTo( + "Parameter <" + List.class.getName() + "<" + String.class.getName() + ">> of " + startWithLowercase(codeUnit.getDescription())); assertThat(parameters.get(1).getDescription()).isEqualTo("Parameter of " + startWithLowercase(codeUnit.getDescription())); - assertThat(parameters.get(2).getDescription()).isEqualTo("Parameter <" + String.class.getName() + "> of " + startWithLowercase(codeUnit.getDescription())); - assertThat(parameters.get(3).getDescription()).isEqualTo("Parameter <" + int.class.getName() + "> of " + startWithLowercase(codeUnit.getDescription())); + assertThat(parameters.get(2).getDescription()).isEqualTo( + "Parameter <" + String.class.getName() + "> of " + startWithLowercase(codeUnit.getDescription())); + assertThat(parameters.get(3).getDescription()).isEqualTo( + "Parameter <" + int.class.getName() + "> of " + startWithLowercase(codeUnit.getDescription())); } @Test diff --git a/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaTypeVariableTest.java b/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaTypeVariableTest.java index 88e8bd8c19..ba6bb26abf 100644 --- a/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaTypeVariableTest.java +++ b/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaTypeVariableTest.java @@ -3,13 +3,16 @@ import java.io.Serializable; import java.util.HashMap; import java.util.List; +import java.util.Set; +import com.google.common.collect.ImmutableSet; import com.tngtech.archunit.core.importer.ClassFileImporter; import org.junit.Test; import static com.tngtech.archunit.testutil.Assertions.assertThat; import static com.tngtech.archunit.testutil.Assertions.assertThatType; import static com.tngtech.archunit.testutil.Assertions.assertThatTypeErasuresOf; +import static org.junit.Assert.assertEquals; public class JavaTypeVariableTest { @@ -66,7 +69,8 @@ public void erased_type_variable_bound_by_single_class_is_this_class() { class ClassWithBoundTypeParameterWithSingleClassBound { } - JavaTypeVariable type = new ClassFileImporter().importClass(ClassWithBoundTypeParameterWithSingleClassBound.class).getTypeParameters().get(0); + JavaTypeVariable type = + new ClassFileImporter().importClass(ClassWithBoundTypeParameterWithSingleClassBound.class).getTypeParameters().get(0); assertThatType(type.toErasure()).matches(Serializable.class); } @@ -77,7 +81,8 @@ public void erased_type_variable_bound_by_single_generic_class_is_the_erasure_of class ClassWithBoundTypeParameterWithSingleGenericClassBound> { } - JavaTypeVariable type = new ClassFileImporter().importClass(ClassWithBoundTypeParameterWithSingleGenericClassBound.class).getTypeParameters().get(0); + JavaTypeVariable type = + new ClassFileImporter().importClass(ClassWithBoundTypeParameterWithSingleGenericClassBound.class).getTypeParameters().get(0); assertThatType(type.toErasure()).matches(List.class); } @@ -88,7 +93,9 @@ public void erased_type_variable_bound_by_multiple_generic_classes_and_interface class ClassWithBoundTypeParameterWithMultipleGenericClassAndInterfaceBounds & Iterable & Serializable> { } - JavaTypeVariable type = new ClassFileImporter().importClass(ClassWithBoundTypeParameterWithMultipleGenericClassAndInterfaceBounds.class).getTypeParameters().get(0); + JavaTypeVariable type = + new ClassFileImporter().importClass(ClassWithBoundTypeParameterWithMultipleGenericClassAndInterfaceBounds.class).getTypeParameters() + .get(0); assertThatType(type.toErasure()).matches(HashMap.class); } @@ -99,7 +106,8 @@ public void erased_type_variable_bound_by_concrete_array_type_is_array_type() { class ClassWithBoundTypeParameterWithSingleGenericArrayBound, U extends List, V extends List[][][]>> { } - List> typeParameters = new ClassFileImporter().importClass(ClassWithBoundTypeParameterWithSingleGenericArrayBound.class).getTypeParameters(); + List> typeParameters = + new ClassFileImporter().importClass(ClassWithBoundTypeParameterWithSingleGenericArrayBound.class).getTypeParameters(); assertThatType(getTypeArgumentOfFirstBound(typeParameters.get(0)).toErasure()).matches(Object[].class); assertThatType(getTypeArgumentOfFirstBound(typeParameters.get(1)).toErasure()).matches(String[][].class); @@ -112,13 +120,31 @@ public void erased_type_variable_bound_by_generic_array_type_is_array_with_erasu class ClassWithBoundTypeParameterWithGenericArrayBounds, T extends List, U extends List, V extends List> { } - List> typeParameters = new ClassFileImporter().importClass(ClassWithBoundTypeParameterWithGenericArrayBounds.class).getTypeParameters(); + List> typeParameters = + new ClassFileImporter().importClass(ClassWithBoundTypeParameterWithGenericArrayBounds.class).getTypeParameters(); assertThatType(getTypeArgumentOfFirstBound(typeParameters.get(3)).toErasure()).matches(Object[].class); assertThatType(getTypeArgumentOfFirstBound(typeParameters.get(4)).toErasure()).matches(String[][].class); assertThatType(getTypeArgumentOfFirstBound(typeParameters.get(5)).toErasure()).matches(List[][][].class); } + @Test + public void all_involved_raw_types() { + class SampleClass { + @SuppressWarnings("unused") + private SampleClass method() { + return null; + } + } + JavaClasses classes = new ClassFileImporter().importClasses(SampleClass.class, String.class, Serializable.class); + JavaMethod method = classes.get(SampleClass.class).getMethod("method"); + + Set involvedRawTypes = method.getReturnType().getAllInvolvedRawTypes(); + + Set expected = ImmutableSet.of(classes.get(SampleClass.class), classes.get(String.class), classes.get(Serializable.class)); + assertEquals(expected, involvedRawTypes); + } + @Test public void toString_unbounded() { @SuppressWarnings("unused") diff --git a/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaWildcardTypeTest.java b/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaWildcardTypeTest.java index 4a7c5c6dc7..921da85eba 100644 --- a/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaWildcardTypeTest.java +++ b/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaWildcardTypeTest.java @@ -2,13 +2,17 @@ import java.io.Serializable; import java.util.List; +import java.util.Map; +import java.util.Set; +import com.google.common.collect.ImmutableSet; import com.tngtech.archunit.core.importer.ClassFileImporter; import org.junit.Test; import static com.tngtech.archunit.testutil.Assertions.assertThat; import static com.tngtech.archunit.testutil.Assertions.assertThatType; import static com.tngtech.archunit.testutil.Assertions.assertThatTypes; +import static org.junit.Assert.assertEquals; public class JavaWildcardTypeTest { @@ -154,6 +158,78 @@ class ClassWithBoundTypeParameterWithGenericArrayBounds method() { + return null; + } + } + + JavaClasses classes = new ClassFileImporter().importClasses(SampleClass.class, List.class); + JavaMethod method = classes.get(SampleClass.class).getMethod("method"); + + Set involvedRawTypes = method.getReturnType().getAllInvolvedRawTypes(); + + Set expected = ImmutableSet.of(classes.get(List.class)); + + assertEquals(expected, involvedRawTypes); + } + + @Test + public void allInvolvedRawTypes_lower_bounds() { + class SampleClass { + public List method() { + return null; + } + } + + JavaClasses classes = new ClassFileImporter().importClasses(SampleClass.class, List.class, String.class); + JavaMethod method = classes.get(SampleClass.class).getMethod("method"); + + Set involvedRawTypes = method.getReturnType().getAllInvolvedRawTypes(); + + Set expected = ImmutableSet.of(classes.get(List.class), classes.get(String.class)); + + assertEquals(expected, involvedRawTypes); + } + + @Test + public void allInvolvedRawTypes_upper_bounds() { + class SampleClass { + public List method() { + return null; + } + } + + JavaClasses classes = new ClassFileImporter().importClasses(SampleClass.class, List.class, String.class); + JavaMethod method = classes.get(SampleClass.class).getMethod("method"); + + Set involvedRawTypes = method.getReturnType().getAllInvolvedRawTypes(); + + Set expected = ImmutableSet.of(classes.get(List.class), classes.get(String.class)); + + assertEquals(expected, involvedRawTypes); + } + + @Test + public void allInvolvedRawTypes_combined() { + class SampleClass { + public Map method() { + return null; + } + } + + JavaClasses classes = new ClassFileImporter().importClasses(SampleClass.class, Map.class, String.class, Object.class); + JavaMethod method = classes.get(SampleClass.class).getMethod("method"); + + Set involvedRawTypes = method.getReturnType().getAllInvolvedRawTypes(); + + Set expected = ImmutableSet.of(classes.get(Map.class), classes.get(String.class), classes.get(Object.class)); + + assertEquals(expected, involvedRawTypes); + } + @Test public void toString_unbounded() { @SuppressWarnings("unused")