package com.tngtech.archunit.lang.conditions; import java.util.HashSet; import java.util.Set; import com.tngtech.archunit.core.domain.JavaAccess; import com.tngtech.archunit.core.domain.JavaClass; import com.tngtech.archunit.lang.ConditionEvents; import com.tngtech.archunit.testutil.Assertions; import org.junit.Test; import static com.tngtech.archunit.base.DescribedPredicate.alwaysFalse; import static com.tngtech.archunit.base.DescribedPredicate.alwaysTrue; import static com.tngtech.archunit.core.domain.JavaConstructor.CONSTRUCTOR_NAME; import static com.tngtech.archunit.core.domain.TestUtils.importClasses; import static com.tngtech.archunit.testutil.Assertions.assertThat; public class AccessTargetConditionTest { @Test public void matches_field_access() { JavaClass clazz = importToCheck(ClassAccessingField.class); assertThatOnlyAccessToSomeClassFor(clazz, new AccessTargetCondition(alwaysTrue())) .containNoViolation(); assertThatOnlyAccessToSomeClassFor(clazz, new AccessTargetCondition(alwaysFalse())) .haveOneViolationMessageContaining(ClassAccessingField.class.getSimpleName() + ".access()") .haveOneViolationMessageContaining(SomeClass.class.getSimpleName() + ".field"); } @Test public void matches_constructor_call() { JavaClass clazz = importToCheck(ClassCallingConstructor.class); assertThatOnlyAccessToSomeClassFor(clazz, new AccessTargetCondition(alwaysTrue())) .containNoViolation(); assertThatOnlyAccessToSomeClassFor(clazz, new AccessTargetCondition(alwaysFalse())) .haveOneViolationMessageContaining(ClassCallingConstructor.class.getSimpleName() + ".call()") .haveOneViolationMessageContaining(SomeClass.class.getSimpleName() + "." + CONSTRUCTOR_NAME); } @Test public void matches_method_call() { JavaClass clazz = importToCheck(ClassCallingMethod.class); assertThatOnlyAccessToSomeClassFor(clazz, new AccessTargetCondition(alwaysTrue())) .containNoViolation(); assertThatOnlyAccessToSomeClassFor(clazz, new AccessTargetCondition(alwaysFalse())) .haveOneViolationMessageContaining(ClassCallingMethod.class.getSimpleName() + ".call()") .haveOneViolationMessageContaining(SomeClass.class.getSimpleName() + ".method"); } @Test public void description_is_correct() { AccessTargetCondition condition = new AccessTargetCondition(alwaysTrue().as("some description")); assertThat(condition.getDescription()).isEqualTo("access target where some description"); } private Assertions.ConditionEventsAssert assertThatOnlyAccessToSomeClassFor(JavaClass clazz, AccessTargetCondition condition) { Set<JavaAccess<?>> accesses = filterByTarget(clazz.getAccessesFromSelf(), SomeClass.class); ConditionEvents events = new ConditionEvents(); for (JavaAccess<?> access : accesses) { condition.check(access, events); } return assertThat(events); } private <T extends JavaAccess<?>> Set<T> filterByTarget(Set<T> accesses, Class<?> targetOwner) { Set<T> result = new HashSet<>(); for (T access : accesses) { if (access.getTargetOwner().isEquivalentTo(targetOwner)) { result.add(access); } } return result; } private JavaClass importToCheck(Class<?> clazz) { return importClasses(SomeClass.class, clazz).get(clazz); } private static class SomeClass { String field; SomeClass() { } void method() { } } private static class ClassAccessingField { SomeClass someClass; void access() { someClass.field = "foo"; } } private static class ClassCallingConstructor { void call() { new SomeClass(); } } private static class ClassCallingMethod { SomeClass someClass; void call() { someClass.method(); } } }