-
Notifications
You must be signed in to change notification settings - Fork 299
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
How to: Forbid a method call only from specific methods, not whole classes? #1152
Comments
I believe that you're right; such a You can however define it as a custom importsimport com.tngtech.archunit.core.domain.JavaCodeUnit;
import com.tngtech.archunit.lang.ArchCondition;
import com.tngtech.archunit.lang.ConditionEvents;
import com.tngtech.archunit.lang.SimpleConditionEvent;
import static com.tngtech.archunit.core.domain.Formatters.formatMethod;
import static com.tngtech.archunit.core.domain.JavaCall.Predicates.target;
import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.name;
import static com.tngtech.archunit.core.domain.properties.HasOwner.Predicates.With.owner;
import static com.tngtech.archunit.core.domain.properties.HasParameterTypes.Predicates.rawParameterTypes;
import static com.tngtech.archunit.lang.ConditionEvent.createMessage;
import static java.lang.String.format;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toList; static ArchCondition<? super JavaCodeUnit> callMethod(Class<?> methodOwner, String methodName, Class<?>... rawParameterTypes) {
String methodDescription = format("method <%s>",
formatMethod(methodOwner.getName(), methodName, stream(rawParameterTypes).map(Class::getName).collect(toList()))
);
return new ArchCondition<>("call " + methodDescription) {
@Override
public void check(JavaCodeUnit codeUnit, ConditionEvents events) {
boolean satisfied = codeUnit.getMethodCallsFromSelf().stream().anyMatch(call ->
target(
owner(name(methodOwner.getName()))
.and(name(methodName))
.and(rawParameterTypes(rawParameterTypes))
).test(call)
);
String message = createMessage(codeUnit, (satisfied ? "calls " : "does not call ") + methodDescription);
events.add(new SimpleConditionEvent(codeUnit, satisfied, message));
}
};
} To use it, you only have to change your code a little: noMethods()
.that()
.areAnnotatedWith(Test.class)
.should(callMethod(DBManager.class, "createAnimal", String.class, String.class)); |
For some reason this check always triggered. Fortunately I was able to adapt this code to adapt this code:
@hankem Your response was very helpful regardless as it showed me the right way. This could also be used to imitate the callMethodWhere-method. Thank you very much. |
Hm, I'll double check that later; I was convinced that it worked in my version of your example. 🤔 But anyways, one suggestion for your version: |
It seems that the following solution using the static importsimport com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.JavaCodeUnit;
import com.tngtech.archunit.lang.ArchCondition;
import com.tngtech.archunit.lang.ConditionEvents;
import com.tngtech.archunit.lang.SimpleConditionEvent;
import static com.tngtech.archunit.core.domain.Formatters.formatMethod;
import static com.tngtech.archunit.core.domain.JavaCall.Predicates.target;
import static com.tngtech.archunit.core.domain.JavaClass.Predicates.equivalentTo;
import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.name;
import static com.tngtech.archunit.core.domain.properties.HasOwner.Predicates.With.owner;
import static com.tngtech.archunit.core.domain.properties.HasParameterTypes.Predicates.rawParameterTypes;
import static com.tngtech.archunit.lang.ConditionEvent.createMessage;
import static java.lang.String.format;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toList; static ArchCondition<? super JavaCodeUnit> callMethod(Class<?> methodOwner, String methodName, Class<?>... rawParameterTypes) {
String methodDescription = format("method <%s>",
formatMethod(methodOwner.getName(), methodName, stream(rawParameterTypes).map(Class::getName).collect(toList()))
);
return new ArchCondition<>("call " + methodDescription) {
@Override
public void check(JavaCodeUnit codeUnit, ConditionEvents events) {
boolean satisfied = codeUnit.getMethodCallsFromSelf().stream().anyMatch(
target(DescribedPredicate.and(
owner(equivalentTo(methodOwner)),
name(methodName),
rawParameterTypes(rawParameterTypes)
))
);
String message = createMessage(codeUnit, (satisfied ? "calls " : "does not call ") + methodDescription);
events.add(new SimpleConditionEvent(codeUnit, satisfied, message));
}
};
} |
Oooh... I've just realized that the owner(name(methodOwner.getName()))
.and(name(methodName))
.and(rawParameterTypes(rawParameterTypes)) actually resolve to the static DescribedPredicates
.and(rawParameterTypes(rawParameterTypes)) i.e. |
To show what I mean, let's look at this example. I want to prevent that someone creates test objects within a method that is annotated with
@Test
. However, if the method is called within a method that does not have this annotation, it should be fine.I've seen this option, but it doesn't work here. The class should be able to call this method, just not within specific methods.
So how can I make this work? There seems to be no option to just do this:
The text was updated successfully, but these errors were encountered: