Skip to content
Open
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
11 changes: 10 additions & 1 deletion archunit-example/example-junit4/build.gradle
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
plugins {
id 'archunit.java-examples-conventions'
id 'archunit.self-test-conventions'
}

ext.moduleName = 'com.tngtech.archunit.example.junit4'

dependencies {
testImplementation project(path: ':archunit-junit4')
testImplementation project(path: ':archunit-example:example-plain')

// The ArchUnit self-tests use JUnit5 features, so we self-test this example subproject using JUnit5.
// The JUnit versions only need to match for the archunit-junit* subprojects.
archTestImplementation project(path: ':archunit-junit5')
archTestImplementation libs.junit5Platform
archTestRuntimeOnly libs.junit5PlatformLauncher
// We want to run the architecture self-tests on the `test` sourceSet of this subproject
archTestRuntimeOnly sourceSets.test.output
}

test {
Expand All @@ -15,4 +24,4 @@ test {
excludeCategories 'com.tngtech.archunit.exampletest.junit4.Example'
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.tngtech.archunit.exampletest.junit4;

import com.tngtech.archunit.ArchUnitExampleArchitectureRules;
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.junit.ArchTests;

@AnalyzeClasses(packages = "com.tngtech.archunit.exampletest.junit4")
class ArchUnitExampleJUnit4ArchitectureTest {

@ArchTest
static final ArchTests example_rules = ArchTests.in(ArchUnitExampleArchitectureRules.class);
}
6 changes: 6 additions & 0 deletions archunit-example/example-junit5/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
plugins {
id 'archunit.java-examples-conventions'
id 'archunit.self-test-conventions'
}

ext.moduleName = 'com.tngtech.archunit.example.junit5'
Expand All @@ -8,6 +9,11 @@ ext.minimumJavaVersion = JavaVersion.VERSION_1_8
dependencies {
testImplementation project(path: ':archunit-junit5')
testImplementation project(path: ':archunit-example:example-plain')

archTestImplementation project(path: ':archunit-junit5')
archTestRuntimeOnly libs.junit5PlatformLauncher
// We want to run the architecture self-tests on the `test` sourceSet of this subproject
archTestRuntimeOnly sourceSets.test.output
}

test {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.tngtech.archunit.exampletest.junit5;

import com.tngtech.archunit.ArchUnitExampleArchitectureRules;
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.junit.ArchTests;

@AnalyzeClasses(packages = "com.tngtech.archunit.exampletest.junit5")
class ArchUnitExampleJUnit5ArchitectureTest {

@ArchTest
static final ArchTests example_rules = ArchTests.in(ArchUnitExampleArchitectureRules.class);
}
25 changes: 25 additions & 0 deletions archunit-example/example-junit6/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
plugins {
id 'archunit.java-examples-conventions'
id 'archunit.self-test-conventions'
}

ext.moduleName = 'com.tngtech.archunit.example.junit6'
ext.minimumJavaVersion = JavaVersion.VERSION_17

dependencies {
testImplementation project(path: ':archunit-junit6')
testImplementation project(path: ':archunit-example:example-plain')

archTestImplementation project(path: ':archunit-junit6')
archTestRuntimeOnly libs.junit6PlatformLauncher
// We want to run the architecture self-tests on the `test` sourceSet of this subproject
archTestRuntimeOnly sourceSets.test.output
}

test {
useJUnitPlatform {
if (!project.hasProperty('example')) {
excludeTags 'example'
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.tngtech.archunit.exampletest.junit6;

import com.tngtech.archunit.ArchUnitExampleArchitectureRules;
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.junit.ArchTests;

@AnalyzeClasses(packages = "com.tngtech.archunit.exampletest.junit6")
class ArchUnitExampleJUnit6ArchitectureTest {

@ArchTest
static final ArchTests example_rules = ArchTests.in(ArchUnitExampleArchitectureRules.class);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.tngtech.archunit.exampletest.junit6;

import java.util.logging.Logger;

import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTag;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;
import com.tngtech.archunit.lang.CompositeArchRule;

import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.fields;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
import static com.tngtech.archunit.library.GeneralCodingRules.ACCESS_STANDARD_STREAMS;
import static com.tngtech.archunit.library.GeneralCodingRules.NO_CLASSES_SHOULD_ACCESS_STANDARD_STREAMS;
import static com.tngtech.archunit.library.GeneralCodingRules.NO_CLASSES_SHOULD_THROW_GENERIC_EXCEPTIONS;
import static com.tngtech.archunit.library.GeneralCodingRules.NO_CLASSES_SHOULD_USE_FIELD_INJECTION;
import static com.tngtech.archunit.library.GeneralCodingRules.NO_CLASSES_SHOULD_USE_JAVA_UTIL_LOGGING;
import static com.tngtech.archunit.library.GeneralCodingRules.NO_CLASSES_SHOULD_USE_JODATIME;

@ArchTag("example")
@AnalyzeClasses(packages = "com.tngtech.archunit.example.layers")
public class CodingRulesTest {

@ArchTest
private final ArchRule no_access_to_standard_streams = NO_CLASSES_SHOULD_ACCESS_STANDARD_STREAMS;

@ArchTest
private void no_access_to_standard_streams_as_method(JavaClasses classes) {
noClasses().should(ACCESS_STANDARD_STREAMS).check(classes);
}

@ArchTest
private final ArchRule no_generic_exceptions = NO_CLASSES_SHOULD_THROW_GENERIC_EXCEPTIONS;

@ArchTest
private final ArchRule no_java_util_logging = NO_CLASSES_SHOULD_USE_JAVA_UTIL_LOGGING;

@ArchTest
private final ArchRule loggers_should_be_private_static_final =
fields().that().haveRawType(Logger.class)
.should().bePrivate()
.andShould().beStatic()
.andShould().beFinal()
.because("we agreed on this convention");

@ArchTest
private final ArchRule no_jodatime = NO_CLASSES_SHOULD_USE_JODATIME;

@ArchTest
private final ArchRule no_field_injection = NO_CLASSES_SHOULD_USE_FIELD_INJECTION;

@ArchTest
static final ArchRule no_classes_should_access_standard_streams_or_throw_generic_exceptions =
CompositeArchRule.of(NO_CLASSES_SHOULD_ACCESS_STANDARD_STREAMS)
.and(NO_CLASSES_SHOULD_THROW_GENERIC_EXCEPTIONS);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.tngtech.archunit.exampletest.junit6;

import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.domain.JavaMember;
import com.tngtech.archunit.core.domain.PackageMatchers;
import com.tngtech.archunit.example.layers.security.Secured;
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTag;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;

import static com.tngtech.archunit.core.domain.JavaClass.Functions.GET_PACKAGE_NAME;
import static com.tngtech.archunit.core.domain.JavaMember.Predicates.declaredIn;
import static com.tngtech.archunit.core.domain.properties.CanBeAnnotated.Predicates.annotatedWith;
import static com.tngtech.archunit.lang.conditions.ArchPredicates.are;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;

@ArchTag("example")
@AnalyzeClasses(packages = "com.tngtech.archunit.example.layers")
public class ControllerRulesTest {

@ArchTest
static final ArchRule controllers_should_only_call_secured_methods =
classes().that().resideInAPackage("..controller..")
.should().onlyCallMethodsThat(areDeclaredInController().or(are(annotatedWith(Secured.class))));

@ArchTest
static final ArchRule controllers_should_only_call_secured_constructors =
classes()
.that().resideInAPackage("..controller..")
.should().onlyCallConstructorsThat(areDeclaredInController().or(are(annotatedWith(Secured.class))));

@ArchTest
static final ArchRule controllers_should_only_call_secured_code_units =
classes()
.that().resideInAPackage("..controller..")
.should().onlyCallCodeUnitsThat(areDeclaredInController().or(are(annotatedWith(Secured.class))));

@ArchTest
static final ArchRule controllers_should_only_access_secured_fields =
classes()
.that().resideInAPackage("..controller..")
.should().onlyAccessFieldsThat(areDeclaredInController().or(are(annotatedWith(Secured.class))));

@ArchTest
static final ArchRule controllers_should_only_access_secured_members =
classes()
.that().resideInAPackage("..controller..")
.should().onlyAccessMembersThat(areDeclaredInController().or(are(annotatedWith(Secured.class))));

private static DescribedPredicate<JavaMember> areDeclaredInController() {
DescribedPredicate<JavaClass> aPackageController = GET_PACKAGE_NAME.is(PackageMatchers.of("..controller..", "java.."))
.as("a package '..controller..'");
return are(declaredIn(aPackageController));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.tngtech.archunit.exampletest.junit6;

import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.example.cycles.complexcycles.slice1.SliceOneCallingConstructorInSliceTwoAndMethodInSliceThree;
import com.tngtech.archunit.example.cycles.complexcycles.slice3.ClassCallingConstructorInSliceFive;
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTag;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;
import com.tngtech.archunit.library.dependencies.SliceAssignment;
import com.tngtech.archunit.library.dependencies.SliceIdentifier;

import static com.tngtech.archunit.base.DescribedPredicate.alwaysTrue;
import static com.tngtech.archunit.core.domain.JavaClass.Predicates.resideInAPackage;
import static com.tngtech.archunit.library.dependencies.SlicesRuleDefinition.slices;

@ArchTag("example")
@AnalyzeClasses(packages = "com.tngtech.archunit.example.cycles")
public class CyclicDependencyRulesTest {

@ArchTest
static final ArchRule no_cycles_by_method_calls_between_slices =
slices().matching("..(simplecycle).(*)..").namingSlices("$2 of $1").should().beFreeOfCycles();

@ArchTest
static final ArchRule no_cycles_by_constructor_calls_between_slices =
slices().matching("..(constructorcycle).(*)..").namingSlices("$2 of $1").should().beFreeOfCycles();

@ArchTest
static final ArchRule no_cycles_by_inheritance_between_slices =
slices().matching("..(inheritancecycle).(*)..").namingSlices("$2 of $1").should().beFreeOfCycles();

@ArchTest
static final ArchRule no_cycles_by_field_access_between_slices =
slices().matching("..(fieldaccesscycle).(*)..").namingSlices("$2 of $1").should().beFreeOfCycles();

@ArchTest
static final ArchRule no_cycles_by_member_dependencies_between_slices =
slices().matching("..(membercycle).(*)..").namingSlices("$2 of $1").should().beFreeOfCycles();

@ArchTest
static final ArchRule no_cycles_in_simple_scenario =
slices().matching("..simplescenario.(*)..").namingSlices("$1").should().beFreeOfCycles();

@ArchTest
static final ArchRule no_cycles_in_complex_scenario =
slices().matching("..(complexcycles).(*)..").namingSlices("$2 of $1").should().beFreeOfCycles();

@ArchTest
static final ArchRule no_cycles_in_complex_scenario_with_custom_ignore =
slices().matching("..(complexcycles).(*)..").namingSlices("$2 of $1")
.as("Slices of complex scenario ignoring some violations")
.should().beFreeOfCycles()
.ignoreDependency(SliceOneCallingConstructorInSliceTwoAndMethodInSliceThree.class, ClassCallingConstructorInSliceFive.class)
.ignoreDependency(resideInAPackage("..slice4.."), alwaysTrue());

@ArchTest
static final ArchRule no_cycles_in_freely_customized_slices =
slices().assignedFrom(inComplexSliceOneOrTwo())
.namingSlices("$1[$2]")
.should().beFreeOfCycles();

private static SliceAssignment inComplexSliceOneOrTwo() {
return new SliceAssignment() {
@Override
public String getDescription() {
return "complex slice one or two";
}

@Override
public SliceIdentifier getIdentifierOf(JavaClass javaClass) {
if (javaClass.getPackageName().contains("complexcycles.slice1")) {
return SliceIdentifier.of("Complex-Cycle", "One");
}
if (javaClass.getPackageName().contains("complexcycles.slice2")) {
return SliceIdentifier.of("Complex-Cycle", "Two");
}
return SliceIdentifier.ignore();
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.tngtech.archunit.exampletest.junit6;

import java.sql.SQLException;

import javax.persistence.Entity;
import javax.persistence.EntityManager;

import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTag;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;

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

@ArchTag("example")
@AnalyzeClasses(packages = "com.tngtech.archunit.example.layers")
public class DaoRulesTest {
@ArchTest
static final ArchRule DAOs_must_reside_in_a_dao_package =
classes().that().haveNameMatching(".*Dao").should().resideInAPackage("..dao..")
.as("DAOs should reside in a package '..dao..'");

@ArchTest
static final ArchRule entities_must_reside_in_a_domain_package =
classes().that().areAnnotatedWith(Entity.class).should().resideInAPackage("..domain..")
.as("Entities should reside in a package '..domain..'");

@ArchTest
static final ArchRule only_DAOs_may_use_the_EntityManager =
noClasses().that().resideOutsideOfPackage("..dao..")
.should().accessClassesThat().areAssignableTo(EntityManager.class)
.as("Only DAOs may use the " + EntityManager.class.getSimpleName());


@ArchTest
static final ArchRule DAOs_must_not_throw_SQLException =
noMethods().that().areDeclaredInClassesThat().haveNameMatching(".*Dao")
.should().declareThrowableOfType(SQLException.class);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.tngtech.archunit.exampletest.junit6;

import com.tngtech.archunit.example.layers.ClassViolatingCodingRules;
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTag;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;

import static com.tngtech.archunit.library.DependencyRules.NO_CLASSES_SHOULD_DEPEND_UPPER_PACKAGES;

@ArchTag("example")
@AnalyzeClasses(packagesOf = ClassViolatingCodingRules.class)
public class DependencyRulesTest {

@ArchTest
static final ArchRule no_accesses_to_upper_package = NO_CLASSES_SHOULD_DEPEND_UPPER_PACKAGES;
}
Loading
Loading