From e4e62da7405f53288d64416d2835ac69cc11986f Mon Sep 17 00:00:00 2001 From: Ulli Hafner Date: Wed, 7 Apr 2021 17:44:18 +0200 Subject: [PATCH] Add an architecture test that checks exception raising. When a new exception is raised then the no-arg constructor of the exception must never be called. Otherwise the context of the failure is missing. --- .../edu/hm/hafner/util/ArchitectureRules.java | 21 +++++++++++++++++++ .../edu/hm/hafner/util/ArchitectureTest.java | 3 +++ 2 files changed, 24 insertions(+) diff --git a/src/test/java/edu/hm/hafner/util/ArchitectureRules.java b/src/test/java/edu/hm/hafner/util/ArchitectureRules.java index c081d3c2..45a4494c 100644 --- a/src/test/java/edu/hm/hafner/util/ArchitectureRules.java +++ b/src/test/java/edu/hm/hafner/util/ArchitectureRules.java @@ -8,7 +8,9 @@ import org.junit.jupiter.params.ParameterizedTest; 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.JavaConstructorCall; import com.tngtech.archunit.core.domain.JavaModifier; import com.tngtech.archunit.core.domain.properties.CanBeAnnotated; import com.tngtech.archunit.junit.ArchTest; @@ -27,6 +29,10 @@ 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()); + /** Junit 5 test classes should not be public. */ public static final ArchRule NO_PUBLIC_TEST_CLASSES = noClasses().that().haveSimpleNameEndingWith("Test") @@ -124,4 +130,19 @@ public boolean apply(final JavaCall input) { && !"assertTimeoutPreemptively".equals(input.getName()); } } + + private static class ExceptionHasNoContext extends DescribedPredicate { + ExceptionHasNoContext() { + super("exception context is missing"); + } + + @Override + public boolean apply(final JavaConstructorCall javaConstructorCall) { + ConstructorCallTarget target = javaConstructorCall.getTarget(); + if (target.getRawParameterTypes().size() > 0) { + return false; + } + return target.getOwner().isAssignableTo(Throwable.class); + } + } } diff --git a/src/test/java/edu/hm/hafner/util/ArchitectureTest.java b/src/test/java/edu/hm/hafner/util/ArchitectureTest.java index 7af1d4e5..ec37de92 100644 --- a/src/test/java/edu/hm/hafner/util/ArchitectureTest.java +++ b/src/test/java/edu/hm/hafner/util/ArchitectureTest.java @@ -32,4 +32,7 @@ class ArchitectureTest { @ArchTest static final ArchRule NO_FORBIDDEN_ANNOTATION_USED = ArchitectureRules.NO_FORBIDDEN_ANNOTATION_USED; + + @ArchTest + static final ArchRule NO_EXCEPTIONS_WITH_NO_ARG_CONSTRUCTOR = ArchitectureRules.NO_EXCEPTIONS_WITH_NO_ARG_CONSTRUCTOR; }