Skip to content

Commit

Permalink
Junit4-support for ArchRules.in {class with [(instance fields or non-…
Browse files Browse the repository at this point in the history
…static methods) in abstract base class]}

Issue: #104

Signed-off-by: Manfred Hanke <[email protected]>
  • Loading branch information
hankem committed Aug 28, 2018
1 parent 625c3d6 commit 59f8c4d
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,24 @@
abstract class ArchRuleDeclaration<T extends AnnotatedElement> {
private final Class<?> testClass;
final T declaration;
final Class<?> owner;
private final boolean forceIgnore;

ArchRuleDeclaration(Class<?> testClass, T declaration, boolean forceIgnore) {
ArchRuleDeclaration(Class<?> testClass, T declaration, Class<?> owner, boolean forceIgnore) {
this.testClass = testClass;
this.declaration = declaration;
this.owner = owner;
this.forceIgnore = forceIgnore;
}

abstract void handleWith(Handler handler);

private static ArchRuleDeclaration<Method> from(Class<?> testClass, Method method, boolean forceIgnore) {
return new AsMethod(testClass, method, forceIgnore);
private static ArchRuleDeclaration<Method> from(Class<?> testClass, Method method, Class<?> methodOwner, boolean forceIgnore) {
return new AsMethod(testClass, method, methodOwner, forceIgnore);
}

private static ArchRuleDeclaration<Field> from(Class<?> testClass, Field field, boolean forceIgnore) {
return new AsField(testClass, field, forceIgnore);
private static ArchRuleDeclaration<Field> from(Class<?> testClass, Field field, Class<?> fieldOwner, boolean forceIgnore) {
return new AsField(testClass, field, fieldOwner, forceIgnore);
}

static <T extends AnnotatedElement & Member> boolean elementShouldBeIgnored(T member) {
Expand All @@ -69,54 +71,54 @@ static Set<ArchRuleDeclaration<?>> toDeclarations(
ArchRules rules, Class<?> testClass, Class<? extends Annotation> archTestAnnotationType, boolean forceIgnore) {

ImmutableSet.Builder<ArchRuleDeclaration<?>> result = ImmutableSet.builder();
for (Field field : getAllFields(rules.getDefinitionLocation(), withAnnotation(archTestAnnotationType))) {
result.addAll(archRuleDeclarationsFrom(testClass, field, archTestAnnotationType, forceIgnore));
Class<?> definitionLocation = rules.getDefinitionLocation();
for (Field field : getAllFields(definitionLocation, withAnnotation(archTestAnnotationType))) {
result.addAll(archRuleDeclarationsFrom(testClass, field, definitionLocation, archTestAnnotationType, forceIgnore));
}
for (Method method : getAllMethods(rules.getDefinitionLocation(), withAnnotation(archTestAnnotationType))) {
result.add(ArchRuleDeclaration.from(testClass, method, forceIgnore));
for (Method method : getAllMethods(definitionLocation, withAnnotation(archTestAnnotationType))) {
result.add(ArchRuleDeclaration.from(testClass, method, definitionLocation, forceIgnore));
}
return result.build();
}

private static Set<ArchRuleDeclaration<?>> archRuleDeclarationsFrom(Class<?> testClass, Field field,
private static Set<ArchRuleDeclaration<?>> archRuleDeclarationsFrom(Class<?> testClass, Field field, Class<?> fieldOwner,
Class<? extends Annotation> archTestAnnotationType, boolean forceIgnore) {

return ArchRules.class.isAssignableFrom(field.getType()) ?
toDeclarations(getArchRulesIn(field), testClass, archTestAnnotationType, forceIgnore || elementShouldBeIgnored(field)) :
Collections.<ArchRuleDeclaration<?>>singleton(ArchRuleDeclaration.from(testClass, field, forceIgnore));
toDeclarations(getArchRulesIn(field, fieldOwner), testClass, archTestAnnotationType, forceIgnore || elementShouldBeIgnored(field)) :
Collections.<ArchRuleDeclaration<?>>singleton(ArchRuleDeclaration.from(testClass, field, fieldOwner, forceIgnore));
}

private static ArchRules getArchRulesIn(Field field) {
ArchRules value = getValue(field, field.getDeclaringClass());
return checkNotNull(value, "Field %s.%s is not initialized",
field.getDeclaringClass().getName(), field.getName());
private static ArchRules getArchRulesIn(Field field, Class<?> fieldOwner) {
ArchRules value = getValue(field, fieldOwner);
return checkNotNull(value, "Field %s.%s is not initialized", fieldOwner.getName(), field.getName());
}

private static class AsMethod extends ArchRuleDeclaration<Method> {
AsMethod(Class<?> testClass, Method method, boolean forceIgnore) {
super(testClass, method, forceIgnore);
AsMethod(Class<?> testClass, Method method, Class<?> methodOwner, boolean forceIgnore) {
super(testClass, method, methodOwner, forceIgnore);
}

@Override
void handleWith(Handler handler) {
handler.handleMethodDeclaration(declaration, shouldBeIgnored());
handler.handleMethodDeclaration(declaration, owner, shouldBeIgnored());
}
}

private static class AsField extends ArchRuleDeclaration<Field> {
AsField(Class<?> testClass, Field field, boolean forceIgnore) {
super(testClass, field, forceIgnore);
AsField(Class<?> testClass, Field field, Class<?> fieldOwner, boolean forceIgnore) {
super(testClass, field, fieldOwner, forceIgnore);
}

@Override
void handleWith(Handler handler) {
handler.handleFieldDeclaration(declaration, shouldBeIgnored());
handler.handleFieldDeclaration(declaration, owner, shouldBeIgnored());
}
}

interface Handler {
void handleFieldDeclaration(Field field, boolean ignore);
void handleFieldDeclaration(Field field, Class<?> fieldOwner, boolean ignore);

void handleMethodDeclaration(Method method, boolean ignore);
void handleMethodDeclaration(Method method, Class<?> methodOwner, boolean ignore);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -172,13 +172,13 @@ private static class ExecutionTransformer implements ArchRuleDeclaration.Handler
private final ImmutableSet.Builder<ArchTestExecution> executions = ImmutableSet.builder();

@Override
public void handleFieldDeclaration(Field field, boolean ignore) {
executions.add(new ArchRuleExecution(field.getDeclaringClass(), field, ignore));
public void handleFieldDeclaration(Field field, Class<?> fieldOwner, boolean ignore) {
executions.add(new ArchRuleExecution(fieldOwner, field, ignore));
}

@Override
public void handleMethodDeclaration(Method method, boolean ignore) {
executions.add(new ArchTestMethodExecution(method.getDeclaringClass(), method, ignore));
public void handleMethodDeclaration(Method method, Class<?> methodOwner, boolean ignore) {
executions.add(new ArchTestMethodExecution(methodOwner, method, ignore));
}

Set<ArchTestExecution> getExecutions() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,24 @@ public void should_allow_non_static_method_in_abstract_base_class() {
verifyTestFinishedSuccessfully(AbstractBaseClass.NON_STATIC_METHOD_NAME);
}

@Test
public void should_allow_ArchRules_in_class_with_instance_field_in_abstract_base_class() {
ArchUnitRunner runner = newRunnerFor(ArchTestWithRulesWithAbstractBaseClass.class, cache);

runner.runChild(ArchUnitRunnerTestUtils.getRule(AbstractBaseClass.INSTANCE_FIELD_NAME, runner), runNotifier);

verifyTestFinishedSuccessfully(AbstractBaseClass.INSTANCE_FIELD_NAME);
}

@Test
public void should_allow_ArchRules_in_class_with_non_static_method_in_abstract_base_class() {
ArchUnitRunner runner = newRunnerFor(ArchTestWithRulesWithAbstractBaseClass.class, cache);

runner.runChild(ArchUnitRunnerTestUtils.getRule(AbstractBaseClass.NON_STATIC_METHOD_NAME, runner), runNotifier);

verifyTestFinishedSuccessfully(AbstractBaseClass.NON_STATIC_METHOD_NAME);
}

@Test
public void should_fail_on_wrong_field_type() {
ArchUnitRunner runner = newRunnerFor(WrongArchTestWrongFieldType.class, cache);
Expand Down Expand Up @@ -203,6 +221,12 @@ public static class ArchTestWithPrivateInstanceField {
private ArchRule privateField = all(classes()).should(BE_SATISFIED);
}

@AnalyzeClasses(packages = "some.pkg")
public static class ArchTestWithRulesWithAbstractBaseClass {
@ArchTest
ArchRules rules = ArchRules.in(ArchTestWithAbstractBaseClass.class);
}

@AnalyzeClasses(packages = "some.pkg")
public static class ArchTestWithAbstractBaseClass extends AbstractBaseClass {
}
Expand Down

0 comments on commit 59f8c4d

Please sign in to comment.