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

Add more forbidden packages in architecture tests #520

Merged
merged 2 commits into from
Mar 11, 2022
Merged
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
53 changes: 40 additions & 13 deletions src/test/java/edu/hm/hafner/util/ArchitectureRules.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.Serializable;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.Test;
Expand All @@ -10,6 +11,7 @@
import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.AccessTarget.ConstructorCallTarget;
import com.tngtech.archunit.core.domain.JavaCall;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.domain.JavaConstructorCall;
import com.tngtech.archunit.core.domain.JavaModifier;
import com.tngtech.archunit.core.domain.properties.CanBeAnnotated;
Expand All @@ -25,13 +27,10 @@
* @author Ullrich Hafner
*/
public final class ArchitectureRules {
private ArchitectureRules() {
// prevents instantiation
}

/** Never create exception without any context. */
public static final ArchRule NO_EXCEPTIONS_WITH_NO_ARG_CONSTRUCTOR =
noClasses().should().callConstructorWhere(new ExceptionHasNoContext());
noClasses().that().haveSimpleNameNotContaining("Benchmark")
.should().callConstructorWhere(new ExceptionHasNoContext());

/** Junit 5 test classes should not be public. */
public static final ArchRule NO_PUBLIC_TEST_CLASSES =
Expand All @@ -40,7 +39,7 @@ private ArchitectureRules() {
.and().doNotHaveModifier(JavaModifier.ABSTRACT)
.should().bePublic();

/** Junit 5 test methods should be package private. */
/** Junit 5 test methods should not be public. */
public static final ArchRule ONLY_PACKAGE_PRIVATE_TEST_METHODS =
methods().that().areAnnotatedWith(Test.class)
.or().areAnnotatedWith(ParameterizedTest.class)
Expand Down Expand Up @@ -68,8 +67,13 @@ private ArchitectureRules() {
"org.apache.commons.lang..",
"org.joda.time..",
"javax.xml.bind..",
"net.jcip.annotations..",
"javax.annotation..",
"net.jcip.annotations.."));
"junit..",
"org.hamcrest..",
"com.google.common..",
"org.junit"
));

/** Prevents that classes use visible but forbidden API. */
public static final ArchRule NO_FORBIDDEN_ANNOTATION_USED =
Expand All @@ -81,15 +85,19 @@ private ArchitectureRules() {
.should().callCodeUnitWhere(new TargetIsForbiddenClass(
"org.junit.jupiter.api.Assertions", "org.junit.Assert"));

/** Ensures that the {@code readResolve} methods are protected so sub classes can call the parent method. */
/** Ensures that the {@code readResolve} methods are protected so subclasses can call the parent method. */
public static final ArchRule READ_RESOLVE_SHOULD_BE_PROTECTED =
methods().that().haveName("readResolve").and().haveRawReturnType(Object.class)
.should().beDeclaredInClassesThat().implement(Serializable.class)
.andShould().beProtected();

private ArchitectureRules() {
// prevents instantiation
}

/**
* Matches if a call from outside the defining class uses a method or constructor annotated with {@link
* VisibleForTesting}. There are two exceptions:
* Matches if a call from outside the defining class uses a method or constructor annotated with
* {@link VisibleForTesting}. There are two exceptions:
* <ul>
* <li>The method is called on the same class</li>
* <li>The method is called in a method also annotated with {@link VisibleForTesting}</li>
Expand Down Expand Up @@ -131,9 +139,23 @@ public boolean apply(final JavaCall<?> input) {
}
}

private static class ExceptionHasNoContext extends DescribedPredicate<JavaConstructorCall> {
ExceptionHasNoContext() {
/**
* Predicate to match exception constructor calls without contexts.
*/
public static class ExceptionHasNoContext extends DescribedPredicate<JavaConstructorCall> {
private final List<Class<? extends Throwable>> allowedExceptions;

/**
* Creates a new predicate.
*
* @param allowedExceptions
* exceptions that are allowed to be instantiated without arguments
*/
@SafeVarargs
public ExceptionHasNoContext(final Class<? extends Throwable>... allowedExceptions) {
super("exception context is missing");

this.allowedExceptions = Arrays.asList(allowedExceptions);
}

@Override
Expand All @@ -142,7 +164,12 @@ public boolean apply(final JavaConstructorCall javaConstructorCall) {
if (target.getRawParameterTypes().size() > 0) {
return false;
}
return target.getOwner().isAssignableTo(Throwable.class);
return target.getOwner().isAssignableTo(Throwable.class)
&& !isPermittedException(target.getOwner());
}

private boolean isPermittedException(final JavaClass owner) {
return allowedExceptions.stream().anyMatch(owner::isAssignableTo);
}
}
}