Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/issue 641 filtering env props #2

Draft
wants to merge 10 commits into
base: feature/issue-641-tooling-tests
Choose a base branch
from
Draft
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.lang.reflect.Field;

import com.tngtech.archunit.core.domain.JavaClasses;
import org.junit.AssumptionViolatedException;
import org.junit.runner.Description;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;
Expand Down Expand Up @@ -77,4 +78,19 @@ void notify(RunNotifier notifier) {
notifier.fireTestFailure(new Failure(description, failure));
}
}

static class AbortedResult extends Result {
private final Description description;
private final AssumptionViolatedException failedAssumption;

AbortedResult(Description description, AssumptionViolatedException failedAssumption) {
this.description = description;
this.failedAssumption = failedAssumption;
}

@Override
void notify(RunNotifier notifier) {
notifier.fireTestAssumptionFailed(new Failure(description, failedAssumption));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.junit.ArchTest;
import org.junit.AssumptionViolatedException;
import org.junit.runner.Description;

import static com.tngtech.archunit.junit.internal.DisplayNameResolver.determineDisplayName;
Expand All @@ -38,6 +39,8 @@ Result evaluateOn(JavaClasses classes) {
try {
executeTestMethod(classes);
return new PositiveResult();
} catch (AssumptionViolatedException failedAssumption) {
return new AbortedResult(describeSelf(), failedAssumption);
} catch (Throwable failure) {
return new NegativeResult(describeSelf(), failure);
}
Expand Down
10 changes: 6 additions & 4 deletions archunit-junit/junit5/engine/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
plugins {
id 'archunit.java-release-conventions'
id 'java-test-fixtures'
}

ext.moduleName = 'com.tngtech.archunit.junit5.engine'
Expand All @@ -10,14 +11,19 @@ dependencies {
api project(path: ':archunit')
api project(path: ':archunit-junit5-api')
api project(path: ':archunit-junit5-engine-api')

implementation project(path: ':archunit-junit')
dependency.addGuava { dependencyNotation, config -> implementation(dependencyNotation, config) }
implementation dependency.slf4j
implementation dependency.junitPlatformLauncher

compileOnly dependency.findBugsAnnotations

testImplementation project(path: ':archunit', configuration: 'tests')
testImplementation dependency.assertj
testImplementation dependency.mockito
testImplementation dependency.junit5JupiterApi
testImplementation dependency.junitJupiterParams

testRuntimeOnly dependency.junit5JupiterEngine
}
Expand Down Expand Up @@ -62,7 +68,3 @@ def configureDependencies = { deps ->
}
}
this.with project(':archunit-junit').configureJUnitArchive(configureDependencies)

singlePackageExport {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what to do about this one (should I just move everything from internal/filtering to internal? If the other PRs are merged there will be a lot more filtering stuff)

exportedPackage = 'com.tngtech.archunit.junit.internal'
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,30 @@
*/
package com.tngtech.archunit.junit.internal;

import java.util.Properties;

import com.tngtech.archunit.ArchConfiguration;
import com.tngtech.archunit.junit.internal.filtering.TestSourceFilter;
import org.junit.platform.engine.UniqueId;
import org.junit.platform.engine.support.descriptor.EngineDescriptor;
import org.junit.platform.engine.support.hierarchical.Node;

class ArchUnitEngineDescriptor extends EngineDescriptor implements Node<ArchUnitEngineExecutionContext> {
ArchUnitEngineDescriptor(UniqueId uniqueId) {
public class ArchUnitEngineDescriptor extends EngineDescriptor implements Node<ArchUnitEngineExecutionContext> {
public ArchUnitEngineDescriptor(UniqueId uniqueId) {
super(uniqueId, "ArchUnit JUnit 5");
}

private TestSourceFilter additionalFilter = TestSourceFilter.NOOP;

public void setAdditionalFilter(TestSourceFilter additionalFilter) {
this.additionalFilter = additionalFilter;
}

public TestSourceFilter getAdditionalFilter() {
return additionalFilter;
}

public Properties getConfiguration() {
return ArchConfiguration.get().getSubProperties(ArchConfiguration.JUNIT_PREFIX);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@
*/
package com.tngtech.archunit.junit.internal;

import com.tngtech.archunit.ArchConfiguration;
import org.junit.platform.engine.support.hierarchical.EngineExecutionContext;

class ArchUnitEngineExecutionContext implements EngineExecutionContext {

ArchConfiguration getConfiguration() {
return ArchConfiguration.get();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.tngtech.archunit.junit.CacheMode;
import com.tngtech.archunit.junit.LocationProvider;
import com.tngtech.archunit.junit.engine_api.FieldSource;
import com.tngtech.archunit.junit.internal.filtering.TestSourceFilter;
import com.tngtech.archunit.lang.ArchRule;
import org.junit.platform.engine.TestDescriptor;
import org.junit.platform.engine.UniqueId;
Expand Down Expand Up @@ -61,13 +62,14 @@ private ArchUnitTestDescriptor(ElementResolver resolver, Class<?> testClass, Cla
this.classCache = classCache;
}

static void resolve(TestDescriptor parent, ElementResolver resolver, ClassCache classCache) {
static void resolve(TestDescriptor parent, ElementResolver resolver, ClassCache classCache, TestSourceFilter additionalFilter) {
resolver.resolveClass()
.ifRequestedAndResolved(CreatesChildren::createChildren)
.ifRequestedButUnresolved((clazz, childResolver) -> createTestDescriptor(parent, classCache, clazz, childResolver));
.ifRequestedAndResolved((resolvedMember, childResolver) -> resolvedMember.createChildren(childResolver, additionalFilter))
.ifRequestedButUnresolved((clazz, childResolver) -> createTestDescriptor(parent, classCache, clazz, childResolver, additionalFilter));
}

private static void createTestDescriptor(TestDescriptor parent, ClassCache classCache, Class<?> clazz, ElementResolver childResolver) {
private static void createTestDescriptor(TestDescriptor parent, ClassCache classCache, Class<?> clazz, ElementResolver resolver,
TestSourceFilter additionalFilter) {
if (clazz.getAnnotation(AnalyzeClasses.class) == null) {
LOG.warn("Class {} is not annotated with @{} and thus cannot run as a top level test. "
+ "This warning can be ignored if {} is only used as part of a rules library included via {}.in({}.class).",
Expand All @@ -77,38 +79,46 @@ private static void createTestDescriptor(TestDescriptor parent, ClassCache class
return;
}

ArchUnitTestDescriptor classDescriptor = new ArchUnitTestDescriptor(childResolver, clazz, classCache);
ArchUnitTestDescriptor classDescriptor = new ArchUnitTestDescriptor(resolver, clazz, classCache);
parent.addChild(classDescriptor);
classDescriptor.createChildren(childResolver);
classDescriptor.createChildren(resolver, additionalFilter);
}

@Override
public void createChildren(ElementResolver resolver) {
public void createChildren(ElementResolver resolver, TestSourceFilter filter) {
Supplier<JavaClasses> classes = () -> classCache.getClassesToAnalyzeFor(testClass, new JUnit5ClassAnalysisRequest(testClass));

getAllFields(testClass, withAnnotation(ArchTest.class))
.forEach(field -> resolveField(resolver, classes, field));
.forEach(field -> resolveField(resolver, classes, field, filter));
getAllMethods(testClass, withAnnotation(ArchTest.class))
.forEach(method -> resolveMethod(resolver, classes, method));
.forEach(method -> resolveMethod(resolver, classes, method, filter));
}

private void resolveField(ElementResolver resolver, Supplier<JavaClasses> classes, Field field) {
private void resolveField(ElementResolver resolver, Supplier<JavaClasses> classes, Field field, TestSourceFilter filter) {
resolver.resolveField(field)
.ifUnresolved(childResolver -> resolveChildren(this, childResolver, field, classes));
.ifUnresolved(childResolver -> resolveChildren(this, childResolver, field, classes, filter));
}

private void resolveMethod(ElementResolver resolver, Supplier<JavaClasses> classes, Method method) {
private void resolveMethod(ElementResolver resolver, Supplier<JavaClasses> classes, Method method, TestSourceFilter filter) {
resolver.resolveMethod(method)
.ifUnresolved(childResolver -> addChild(new ArchUnitMethodDescriptor(getUniqueId(), method, classes)));
.ifUnresolved(childResolver -> {
ArchUnitMethodDescriptor descriptor = new ArchUnitMethodDescriptor(getUniqueId(), method, classes);
if (filter.shouldRun(descriptor)) {
addChild(descriptor);
}
});
}

private static void resolveChildren(
TestDescriptor parent, ElementResolver resolver, Field field, Supplier<JavaClasses> classes) {
TestDescriptor parent, ElementResolver resolver, Field field, Supplier<JavaClasses> classes, TestSourceFilter filter) {

if (ArchTests.class.isAssignableFrom(field.getType())) {
resolveArchRules(parent, resolver, field, classes);
resolveArchRules(parent, resolver, field, classes, filter);
} else {
parent.addChild(new ArchUnitRuleDescriptor(resolver.getUniqueId(), getValue(field), classes, field));
ArchUnitRuleDescriptor descriptor = new ArchUnitRuleDescriptor(resolver.getUniqueId(), getValue(field), classes, field);
if (filter.shouldRun(descriptor)) {
parent.addChild(descriptor);
}
}
}

Expand All @@ -117,16 +127,18 @@ private static <T> T getValue(Field field) {
}

private static void resolveArchRules(
TestDescriptor parent, ElementResolver resolver, Field field, Supplier<JavaClasses> classes) {
TestDescriptor parent, ElementResolver resolver, Field field, Supplier<JavaClasses> classes, TestSourceFilter filter) {

if (!filter.shouldRun(FieldSource.from(field))) {
return;
}
DeclaredArchTests archTests = getDeclaredArchTests(field);

resolver.resolveClass(archTests.getDefinitionLocation())
.ifRequestedAndResolved(CreatesChildren::createChildren)
.ifRequestedAndResolved((resolvedMember, childResolver) -> resolvedMember.createChildren(childResolver, TestSourceFilter.NOOP))
.ifRequestedButUnresolved((clazz, childResolver) -> {
ArchUnitArchTestsDescriptor rulesDescriptor = new ArchUnitArchTestsDescriptor(childResolver, archTests, classes, field);
parent.addChild(rulesDescriptor);
rulesDescriptor.createChildren(childResolver);
rulesDescriptor.createChildren(childResolver, TestSourceFilter.NOOP);
});
}

Expand Down Expand Up @@ -194,6 +206,7 @@ public Type getType() {

@Override
public ArchUnitEngineExecutionContext execute(ArchUnitEngineExecutionContext context, DynamicTestExecutor dynamicTestExecutor) {

invokeMethod(method, method.getDeclaringClass(), classes.get());
return context;
}
Expand All @@ -215,14 +228,18 @@ private static class ArchUnitArchTestsDescriptor extends AbstractArchUnitTestDes
}

@Override
public void createChildren(ElementResolver resolver) {
public void createChildren(ElementResolver resolver, TestSourceFilter filter) {
archTests.handleFields(field ->
resolver.resolve(FIELD_SEGMENT_TYPE, field.getName(), childResolver ->
resolveChildren(this, childResolver, field, classes)));
resolveChildren(this, childResolver, field, classes, filter)));

archTests.handleMethods(method ->
resolver.resolve(METHOD_SEGMENT_TYPE, method.getName(), childResolver ->
addChild(new ArchUnitMethodDescriptor(getUniqueId(), method, classes))));
resolver.resolve(METHOD_SEGMENT_TYPE, method.getName(), childResolver -> {
ArchUnitMethodDescriptor descriptor = new ArchUnitMethodDescriptor(getUniqueId(), method, classes);
if (filter.shouldRun(descriptor)) {
addChild(descriptor);
}
}));
}

@Override
Expand Down
Loading