Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@
* a rule checking for no accesses to classes assignable to C will not fail, since ArchUnit does not know about the details
* of class B, but only simple information like the fully qualified name. For information how to configure the import and
* resolution behavior of missing classes, compare {@link ClassFileImporter}.
* <br><br>
* Classes to be analyzed can be specified in different ways:
* <ul>
* <li>{@link #packages()} - specify package names as strings</li>
* <li>{@link #packagesOf()} - specify packages relative to classes</li>
* <li>{@link #classes()} - specify individual classes to analyze</li>
* <li>{@link #locations()} - specify custom locations via {@link LocationProvider}</li>
* <li>{@link #wholeClasspath()} - import all classes on the classpath</li>
* </ul>
* These options can be combined, whereby the final result is the union of all classes derived from each option,
* i.e. each option just adds more classes to be analyzed. If no option is specified, the package of the annotated
* test class will be imported.
*
* @see ArchUnitRunner
* @see ClassFileImporter
Expand Down Expand Up @@ -83,4 +95,9 @@
* @return The {@link CacheMode} to use for this test class.
*/
CacheMode cacheMode() default CacheMode.FOREVER;

/**
* @return Classes to be used for testing instead of packages
*/
Class<?>[] classes() default {};
}
Original file line number Diff line number Diff line change
Expand Up @@ -209,5 +209,10 @@ public CacheMode getCacheMode() {
public boolean scanWholeClasspath() {
return analyzeClasses.wholeClasspath();
}

@Override
public Class<?>[] getClassesToAnalyze() {
return analyzeClasses.classes();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ public class ArchUnitRunnerTest {
private ArchUnitRunnerInternal runnerOfMaxAnnotatedTest = newRunner(MaxAnnotatedTest.class);
@InjectMocks
private ArchUnitRunnerInternal runnerOfMetaAnnotatedTest = newRunner(MetaAnnotatedTest.class);
@InjectMocks
private ArchUnitRunnerInternal runnerOfAnalyzeClassesWithClassesPropertyTest = newRunner(AnalyzeClassesWithClassesPropertyTest.class);

@Before
public void setUp() {
Expand All @@ -73,6 +75,7 @@ public void runner_creates_correct_analysis_request() {
assertThat(analysisRequest.getLocationProviders()).isEqualTo(analyzeClasses.locations());
assertThat(analysisRequest.scanWholeClasspath()).as("scan whole classpath").isTrue();
assertThat(analysisRequest.getImportOptions()).isEqualTo(analyzeClasses.importOptions());
assertThat(analysisRequest.getClassesToAnalyze()).isEmpty();
}

@Test
Expand Down Expand Up @@ -114,6 +117,23 @@ public void runner_creates_correct_analysis_request_for_meta_annotated_class() {
assertThat(analysisRequest.getLocationProviders()).isEqualTo(analyzeClasses.locations());
assertThat(analysisRequest.scanWholeClasspath()).as("scan whole classpath").isTrue();
assertThat(analysisRequest.getImportOptions()).isEqualTo(analyzeClasses.importOptions());
assertThat(analysisRequest.getClassesToAnalyze()).isEmpty();
}

@Test
public void passes_AnalyzeClasses_with_classes_property_to_cache() {
runnerOfAnalyzeClassesWithClassesPropertyTest.run(new RunNotifier());

verify(cache).getClassesToAnalyzeFor(eq(AnalyzeClassesWithClassesPropertyTest.class), analysisRequestCaptor.capture());

AnalyzeClasses analyzeClasses = AnalyzeClassesWithClassesPropertyTest.class.getAnnotation(AnalyzeClasses.class);
ClassAnalysisRequest analysisRequest = analysisRequestCaptor.getValue();
assertThat(analysisRequest.getClassesToAnalyze()).isEqualTo(analyzeClasses.classes());
assertThat(analysisRequest.getImportOptions()).isEqualTo(analyzeClasses.importOptions());
assertThat(analysisRequest.getPackageNames()).isEqualTo(analyzeClasses.packages());
assertThat(analysisRequest.getPackageRoots()).isEqualTo(analyzeClasses.packagesOf());
assertThat(analysisRequest.getLocationProviders()).isEqualTo(analyzeClasses.locations());
assertThat(analysisRequest.scanWholeClasspath()).as("scan whole classpath").isFalse();
}

private ArchUnitRunnerInternal newRunner(Class<?> testClass) {
Expand Down Expand Up @@ -195,4 +215,14 @@ public static void someTest(JavaClasses classes) {
public @interface MetaAnalyzeClasses {
}
}

@AnalyzeClasses(
classes = {String.class, Rule.class},
importOptions = {DummyImportOption.class}
)
public static class AnalyzeClassesWithClassesPropertyTest {
@ArchTest
public static void someTest(JavaClasses classes) {
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@
* a rule checking for no accesses to classes assignable to C will not fail, since ArchUnit does not know about the details
* of class B, but only simple information like the fully qualified name. For information how to configure the import and
* resolution behavior of missing classes, compare {@link ClassFileImporter}.
* <br><br>
* Classes to be analyzed can be specified in different ways:
* <ul>
* <li>{@link #packages()} - specify package names as strings</li>
* <li>{@link #packagesOf()} - specify packages relative to classes</li>
* <li>{@link #classes()} - specify individual classes to analyze</li>
* <li>{@link #locations()} - specify custom locations via {@link LocationProvider}</li>
* <li>{@link #wholeClasspath()} - import all classes on the classpath</li>
* </ul>
* These options can be combined, whereby the final result is the union of all classes derived from each option,
* i.e. each option just adds more classes to be analyzed. If no option is specified, the package of the annotated
* test class will be imported.
*
* @see ClassFileImporter
*/
Expand Down Expand Up @@ -87,4 +99,9 @@
* @return The {@link CacheMode} to use for this test class.
*/
CacheMode cacheMode() default CacheMode.FOREVER;

/**
* @return Classes to be used for testing instead of packages
*/
Class<?>[] classes() default {};
}
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,11 @@ public CacheMode getCacheMode() {
public boolean scanWholeClasspath() {
return analyzeClasses.wholeClasspath();
}

@Override
public Class<?>[] getClassesToAnalyze() {
return analyzeClasses.classes();
}
}

private static class TestMember<MEMBER extends AccessibleObject & Member> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.tngtech.archunit.junit.engine_api.FieldSelector;
import com.tngtech.archunit.junit.engine_api.FieldSource;
import com.tngtech.archunit.junit.internal.ArchUnitTestEngine.SharedCache;
import com.tngtech.archunit.junit.internal.testexamples.AnalyzeClassesWithClassesProperty;
import com.tngtech.archunit.junit.internal.testexamples.ClassWithPrivateTests;
import com.tngtech.archunit.junit.internal.testexamples.ComplexMetaTags;
import com.tngtech.archunit.junit.internal.testexamples.ComplexRuleLibrary;
Expand Down Expand Up @@ -1079,6 +1080,7 @@ void passes_AnalyzeClasses_to_cache() {
assertThat(request.getLocationProviders()).isEqualTo(expected.locations());
assertThat(request.scanWholeClasspath()).as("scan whole classpath").isTrue();
assertThat(request.getImportOptions()).isEqualTo(expected.importOptions());
assertThat(request.getClassesToAnalyze()).isEmpty();
}

@Test
Expand All @@ -1104,6 +1106,21 @@ void a_class_with_analyze_classes_as_meta_annotation() {
assertThat(request.scanWholeClasspath()).as("scan whole classpath").isTrue();
assertThat(request.getImportOptions()).isEqualTo(expected.importOptions());
}

@Test
void passes_AnalyzeClasses_with_classes_property_to_cache() {
execute(createEngineId(), AnalyzeClassesWithClassesProperty.class);

verify(classCache).getClassesToAnalyzeFor(eq(AnalyzeClassesWithClassesProperty.class), classAnalysisRequestCaptor.capture());
ClassAnalysisRequest request = classAnalysisRequestCaptor.getValue();
AnalyzeClasses expected = AnalyzeClassesWithClassesProperty.class.getAnnotation(AnalyzeClasses.class);
assertThat(request.getClassesToAnalyze()).isEqualTo(expected.classes());
Comment thread
StefanGraeber marked this conversation as resolved.
assertThat(request.getImportOptions()).isEqualTo(expected.importOptions());
assertThat(request.getPackageNames()).isEqualTo(expected.packages());
assertThat(request.getPackageRoots()).isEqualTo(expected.packagesOf());
assertThat(request.getLocationProviders()).isEqualTo(expected.locations());
assertThat(request.scanWholeClasspath()).as("scan whole classpath").isFalse();
}
}

@Nested
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.tngtech.archunit.junit.internal.testexamples;

import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.importer.ImportOption;
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchCondition;
import com.tngtech.archunit.lang.ArchRule;
import com.tngtech.archunit.lang.ConditionEvents;
import com.tngtech.archunit.library.testclasses.coveringallclasses.first.First;
import com.tngtech.archunit.library.testclasses.coveringallclasses.second.Second;

import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;

@AnalyzeClasses(
classes = {First.class, Second.class},
importOptions = {ImportOption.DoNotIncludeTests.class, ImportOption.DoNotIncludeJars.class}
)
public class AnalyzeClassesWithClassesProperty {
@ArchTest
public static final ArchRule irrelevant = classes().should(new ArchCondition<JavaClass>("exist") {
@Override
public void check(JavaClass item, ConditionEvents events) {
}
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@
* a rule checking for no accesses to classes assignable to C will not fail, since ArchUnit does not know about the details
* of class B, but only simple information like the fully qualified name. For information how to configure the import and
* resolution behavior of missing classes, compare {@link ClassFileImporter}.
* <br><br>
* Classes to be analyzed can be specified in different ways:
* <ul>
* <li>{@link #packages()} - specify package names as strings</li>
* <li>{@link #packagesOf()} - specify packages relative to classes</li>
* <li>{@link #classes()} - specify individual classes to analyze</li>
* <li>{@link #locations()} - specify custom locations via {@link LocationProvider}</li>
* <li>{@link #wholeClasspath()} - import all classes on the classpath</li>
* </ul>
* These options can be combined, whereby the final result is the union of all classes derived from each option,
* i.e. each option just adds more classes to be analyzed. If no option is specified, the package of the annotated
* test class will be imported.
*
* @see ClassFileImporter
*/
Expand Down Expand Up @@ -87,4 +99,9 @@
* @return The {@link CacheMode} to use for this test class.
*/
CacheMode cacheMode() default CacheMode.FOREVER;

/**
* @return Classes to be used for testing instead of packages
*/
Class<?>[] classes() default {};
}
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,11 @@ public CacheMode getCacheMode() {
public boolean scanWholeClasspath() {
return analyzeClasses.wholeClasspath();
}

@Override
public Class<?>[] getClassesToAnalyze() {
return analyzeClasses.classes();
}
}

private static class TestMember<MEMBER extends AccessibleObject & Member> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.tngtech.archunit.junit.engine_api.FieldSelector;
import com.tngtech.archunit.junit.engine_api.FieldSource;
import com.tngtech.archunit.junit.internal.ArchUnitTestEngine.SharedCache;
import com.tngtech.archunit.junit.internal.testexamples.AnalyzeClassesWithClassesProperty;
import com.tngtech.archunit.junit.internal.testexamples.ClassWithPrivateTests;
import com.tngtech.archunit.junit.internal.testexamples.ComplexMetaTags;
import com.tngtech.archunit.junit.internal.testexamples.ComplexRuleLibrary;
Expand Down Expand Up @@ -1079,6 +1080,7 @@ void passes_AnalyzeClasses_to_cache() {
assertThat(request.getLocationProviders()).isEqualTo(expected.locations());
assertThat(request.scanWholeClasspath()).as("scan whole classpath").isTrue();
assertThat(request.getImportOptions()).isEqualTo(expected.importOptions());
assertThat(request.getClassesToAnalyze()).isEmpty();
}

@Test
Expand All @@ -1104,6 +1106,21 @@ void a_class_with_analyze_classes_as_meta_annotation() {
assertThat(request.scanWholeClasspath()).as("scan whole classpath").isTrue();
assertThat(request.getImportOptions()).isEqualTo(expected.importOptions());
}

@Test
void passes_AnalyzeClasses_with_classes_property_to_cache() {
execute(createEngineId(), AnalyzeClassesWithClassesProperty.class);

verify(classCache).getClassesToAnalyzeFor(eq(AnalyzeClassesWithClassesProperty.class), classAnalysisRequestCaptor.capture());
ClassAnalysisRequest request = classAnalysisRequestCaptor.getValue();
AnalyzeClasses expected = AnalyzeClassesWithClassesProperty.class.getAnnotation(AnalyzeClasses.class);
assertThat(request.getClassesToAnalyze()).isEqualTo(expected.classes());
assertThat(request.getImportOptions()).isEqualTo(expected.importOptions());
assertThat(request.getPackageNames()).isEqualTo(expected.packages());
assertThat(request.getPackageRoots()).isEqualTo(expected.packagesOf());
assertThat(request.getLocationProviders()).isEqualTo(expected.locations());
assertThat(request.scanWholeClasspath()).as("scan whole classpath").isFalse();
}
}

@Nested
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.tngtech.archunit.junit.internal.testexamples;

import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.importer.ImportOption;
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchCondition;
import com.tngtech.archunit.lang.ArchRule;
import com.tngtech.archunit.lang.ConditionEvents;
import com.tngtech.archunit.library.testclasses.coveringallclasses.first.First;
import com.tngtech.archunit.library.testclasses.coveringallclasses.second.Second;

import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;

@AnalyzeClasses(
classes = {First.class, Second.class},
importOptions = {ImportOption.DoNotIncludeTests.class, ImportOption.DoNotIncludeJars.class}
)
public class AnalyzeClassesWithClassesProperty {
@ArchTest
public static final ArchRule irrelevant = classes().should(new ArchCondition<JavaClass>("exist") {
@Override
public void check(JavaClass item, ConditionEvents events) {
}
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ interface ClassAnalysisRequest {
CacheMode getCacheMode();

boolean scanWholeClasspath();

Class<?>[] getClassesToAnalyze();
}
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ private Specific(ClassAnalysisRequest classAnalysisRequest, Class<?> testClass)
declaredLocations = ImmutableSet.<Location>builder()
.addAll(getLocationsOfPackages(classAnalysisRequest))
.addAll(getLocationsOfProviders(classAnalysisRequest, testClass))
.addAll(getLocationsOfClasses(classAnalysisRequest))
.addAll(classAnalysisRequest.scanWholeClasspath() ? Locations.inClassPath() : emptySet())
.build();
}
Expand All @@ -201,6 +202,12 @@ private Set<Location> getLocationsOfProviders(ClassAnalysisRequest classAnalysis
.collect(toSet());
}

private Set<Location> getLocationsOfClasses(ClassAnalysisRequest classAnalysisRequest) {
return stream(classAnalysisRequest.getClassesToAnalyze())
.flatMap(clazz -> Locations.ofClass(clazz).stream())
.collect(toSet());
}

private LocationProvider tryCreate(Class<? extends LocationProvider> providerClass) {
try {
return newInstanceOf(providerClass);
Expand Down Expand Up @@ -240,6 +247,7 @@ private static boolean noSpecificLocationRequested(ClassAnalysisRequest classAna
return classAnalysisRequest.getPackageNames().length == 0
&& classAnalysisRequest.getPackageRoots().length == 0
&& classAnalysisRequest.getLocationProviders().length == 0
&& classAnalysisRequest.getClassesToAnalyze().length == 0
&& !classAnalysisRequest.scanWholeClasspath();
}
}
Expand Down
Loading