Skip to content

Commit

Permalink
Merge pull request #205 from hankem/fullName
Browse files Browse the repository at this point in the history
add full name restrictions/assertions to members API
  • Loading branch information
codecholeric authored Jul 29, 2019
2 parents d01365f + 71a524e commit d8c9e90
Show file tree
Hide file tree
Showing 15 changed files with 365 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ public JavaClass getOwner() {
return owner;
}

/**
* @return The full name of this {@link AccessTarget}, i.e. a string containing {@code ${declaringClass}.${name}} for a field and
* {@code ${declaringClass}.${name}(${parameterTypes})} for a code unit
*/
@Override
@PublicAPI(usage = ACCESS)
public String getFullName() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ public Set<JavaMember> get() {
javaPackage = JavaPackage.simple(this);
}

/**
* @return The {@link Source} of this {@link JavaClass}, i.e. where this class has been imported from
*/
@PublicAPI(usage = ACCESS)
public Optional<Source> getSource() {
return source;
Expand All @@ -126,12 +129,18 @@ public String getDescription() {
return "Class <" + getName() + ">";
}

/**
* @return The fully qualified name of this {@link JavaClass}, compare {@link Class#getName()} of the Reflection API
*/
@Override
@PublicAPI(usage = ACCESS)
public String getName() {
return javaType.getName();
}

/**
* @return The fully qualified name of this {@link JavaClass}, i.e. the result is the same as invoking {@link #getName()}
*/
@Override
@PublicAPI(usage = ACCESS)
public String getFullName() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ public abstract class JavaCodeUnit extends JavaMember implements HasParameterTyp
fullName = formatMethod(getOwner().getName(), getName(), getRawParameterTypes());
}

/**
* @return The full name of this {@link JavaCodeUnit}, i.e. a string containing {@code ${declaringClass}.${name}(${parameterTypes})}
*/
@Override
@PublicAPI(usage = ACCESS)
public String getFullName() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ public class JavaField extends JavaMember implements HasType {
fieldSupplier = Suppliers.memoize(new ReflectFieldSupplier());
}

/**
* @return The full name of this {@link JavaField}, i.e. a string containing {@code ${declaringClass}.${name}}
*/
@Override
@PublicAPI(usage = ACCESS)
public String getFullName() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,81 @@ public interface HasName {
String getName();

interface AndFullName extends HasName {
/**
* @return The full name of the given object. Varies by context, for details consult Javadoc of the concrete subclass.
*/
@PublicAPI(usage = ACCESS)
String getFullName();

final class Predicates {
private Predicates() {
}

@PublicAPI(usage = ACCESS)
public static DescribedPredicate<HasName.AndFullName> fullName(String fullName) {
return new FullNameEqualsPredicate(fullName);
}

/**
* Matches full names against a regular expression.
*/
@PublicAPI(usage = ACCESS)
public static DescribedPredicate<HasName.AndFullName> fullNameMatching(String regex) {
return new FullNameMatchingPredicate(regex);
}

private static class FullNameEqualsPredicate extends DescribedPredicate<HasName.AndFullName> {
private final String fullName;

FullNameEqualsPredicate(String fullName) {
super(String.format("full name '%s'", fullName));
this.fullName = fullName;
}

@Override
public boolean apply(HasName.AndFullName input) {
return input.getFullName().equals(fullName);
}
}

private static class FullNameMatchingPredicate extends DescribedPredicate<HasName.AndFullName> {
private final Pattern pattern;

FullNameMatchingPredicate(String regex) {
super(String.format("full name matching '%s'", regex));
this.pattern = Pattern.compile(regex);
}

@Override
public boolean apply(HasName.AndFullName input) {
return pattern.matcher(input.getFullName()).matches();
}
}
}

final class Functions {
private Functions() {
}

@PublicAPI(usage = ACCESS)
public static final ChainableFunction<HasName.AndFullName, String> GET_FULL_NAME = new ChainableFunction<HasName.AndFullName, String>() {
@Override
public String apply(HasName.AndFullName input) {
return input.getFullName();
}
};
}
}

final class Predicates {
private Predicates() {
}

@PublicAPI(usage = ACCESS)
public static DescribedPredicate<HasName> name(final String name) {
return new NameEqualsPredicate(name);
}

/**
* Matches names against a regular expression.
*/
Expand All @@ -44,36 +111,31 @@ public static DescribedPredicate<HasName> nameMatching(final String regex) {
return new NameMatchingPredicate(regex);
}

@PublicAPI(usage = ACCESS)
public static DescribedPredicate<HasName> name(final String name) {
return new NameEqualsPredicate(name);
}

private static class NameMatchingPredicate extends DescribedPredicate<HasName> {
private final Pattern pattern;
private static class NameEqualsPredicate extends DescribedPredicate<HasName> {
private final String name;

NameMatchingPredicate(String regex) {
super(String.format("name matching '%s'", regex));
this.pattern = Pattern.compile(regex);
NameEqualsPredicate(String name) {
super(String.format("name '%s'", name));
this.name = name;
}

@Override
public boolean apply(HasName input) {
return pattern.matcher(input.getName()).matches();
return input.getName().equals(name);
}
}

private static class NameEqualsPredicate extends DescribedPredicate<HasName> {
private final String name;
private static class NameMatchingPredicate extends DescribedPredicate<HasName> {
private final Pattern pattern;

NameEqualsPredicate(String name) {
super(String.format("name '%s'", name));
this.name = name;
NameMatchingPredicate(String regex) {
super(String.format("name matching '%s'", regex));
this.pattern = Pattern.compile(regex);
}

@Override
public boolean apply(HasName input) {
return input.getName().equals(name);
return pattern.matcher(input.getName()).matches();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;

public interface HasSourceCodeLocation {
/**
* @return The {@link SourceCodeLocation} of this object, i.e. how to locate the respective object within the set of source files.
*/
@PublicAPI(usage = ACCESS)
SourceCodeLocation getSourceCodeLocation();
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@
import static com.tngtech.archunit.core.domain.properties.CanBeAnnotated.Predicates.annotatedWith;
import static com.tngtech.archunit.core.domain.properties.CanBeAnnotated.Predicates.metaAnnotatedWith;
import static com.tngtech.archunit.core.domain.properties.HasModifiers.Predicates.modifier;
import static com.tngtech.archunit.core.domain.properties.HasName.AndFullName.Predicates.fullName;
import static com.tngtech.archunit.core.domain.properties.HasName.AndFullName.Predicates.fullNameMatching;
import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.name;
import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.nameMatching;
import static com.tngtech.archunit.core.domain.properties.HasOwner.Predicates.With.owner;
Expand Down Expand Up @@ -451,6 +453,18 @@ public static <HAS_NAME extends HasName & HasDescription & HasSourceCodeLocation
return not(ArchConditions.<HAS_NAME>haveName(name));
}

@PublicAPI(usage = ACCESS)
public static <HAS_FULL_NAME extends HasName.AndFullName & HasDescription & HasSourceCodeLocation>
ArchCondition<HAS_FULL_NAME> haveFullName(String fullName) {
return new HaveConditionByPredicate<>(fullName(fullName));
}

@PublicAPI(usage = ACCESS)
public static <HAS_FULL_NAME extends HasName.AndFullName & HasDescription & HasSourceCodeLocation>
ArchCondition<HAS_FULL_NAME> notHaveFullName(String fullName) {
return not(new HaveConditionByPredicate<HAS_FULL_NAME>(fullName(fullName)));
}

@PublicAPI(usage = ACCESS)
public static ArchCondition<JavaClass> haveFullyQualifiedName(final String name) {
return new HaveConditionByPredicate<>(fullyQualifiedName(name));
Expand Down Expand Up @@ -516,15 +530,28 @@ public static ArchCondition<JavaClass> haveSimpleNameNotEndingWith(String suffix

@PublicAPI(usage = ACCESS)
public static <HAS_NAME extends HasName & HasDescription & HasSourceCodeLocation> ArchCondition<HAS_NAME> haveNameMatching(final String regex) {
final DescribedPredicate<HasName> haveNameMatching = have(nameMatching(regex));
return new NameMatchingCondition<>(haveNameMatching, regex);
final DescribedPredicate<HAS_NAME> haveNameMatching = have(nameMatching(regex)).forSubType();
return new MatchingCondition<>(haveNameMatching, regex);
}

@PublicAPI(usage = ACCESS)
public static <HAS_NAME extends HasName & HasDescription & HasSourceCodeLocation> ArchCondition<HAS_NAME> haveNameNotMatching(String regex) {
return not(ArchConditions.<HAS_NAME>haveNameMatching(regex)).as("have name not matching '%s'", regex);
}

@PublicAPI(usage = ACCESS)
public static <HAS_FULL_NAME extends HasName.AndFullName & HasDescription & HasSourceCodeLocation>
ArchCondition<HAS_FULL_NAME> haveFullNameMatching(String regex) {
final DescribedPredicate<HAS_FULL_NAME> haveFullNameMatching = have(fullNameMatching(regex)).forSubType();
return new MatchingCondition<>(haveFullNameMatching, regex);
}

@PublicAPI(usage = ACCESS)
public static <HAS_FULL_NAME extends HasName.AndFullName & HasDescription & HasSourceCodeLocation> ArchCondition<HAS_FULL_NAME>
haveFullNameNotMatching(String regex) {
return not(ArchConditions.<HAS_FULL_NAME>haveFullNameMatching(regex)).as("have full name not matching '%s'", regex);
}

@PublicAPI(usage = ACCESS)
public static ArchCondition<JavaClass> resideInAPackage(final String packageIdentifier) {
return new DoesConditionByPredicate<>(JavaClass.Predicates.resideInAPackage(packageIdentifier));
Expand Down Expand Up @@ -1095,22 +1122,22 @@ public void check(JavaClass javaClass, ConditionEvents events) {
}
}

private static class NameMatchingCondition<HAS_NAME extends HasName & HasDescription & HasSourceCodeLocation> extends ArchCondition<HAS_NAME> {
private final DescribedPredicate<HasName> haveNameMatching;
private static class MatchingCondition<T extends HasDescription & HasSourceCodeLocation> extends ArchCondition<T> {
private final DescribedPredicate<T> matcher;
private final String regex;

NameMatchingCondition(DescribedPredicate<HasName> haveNameMatching, String regex) {
super(haveNameMatching.getDescription());
this.haveNameMatching = haveNameMatching;
MatchingCondition(DescribedPredicate<T> matcher, String regex) {
super(matcher.getDescription());
this.matcher = matcher;
this.regex = regex;
}

@Override
public void check(HAS_NAME hasName, ConditionEvents events) {
boolean satisfied = haveNameMatching.apply(hasName);
String message = createMessage(hasName,
public void check(T item, ConditionEvents events) {
boolean satisfied = matcher.apply(item);
String message = createMessage(item,
String.format("%s '%s'", satisfied ? "matches" : "does not match", regex));
events.add(new SimpleConditionEvent(hasName, satisfied, message));
events.add(new SimpleConditionEvent(item, satisfied, message));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,25 @@ public SELF haveNameNotMatching(String regex) {
return addCondition(ArchConditions.haveNameNotMatching(regex));
}

@Override
public SELF haveFullName(String fullName) {
return addCondition(ArchConditions.haveFullName(fullName));
}

@Override
public SELF notHaveFullName(String fullName) {
return addCondition(ArchConditions.notHaveFullName(fullName));
}

@Override
public SELF haveFullNameMatching(String regex) {
return addCondition(ArchConditions.haveFullNameMatching(regex));
}

@Override
public SELF haveFullNameNotMatching(String regex) {
return addCondition(ArchConditions.haveFullNameNotMatching(regex));
}
@Override
public SELF bePublic() {
return addCondition(ArchConditions.bePublic());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
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.core.domain.properties.CanBeAnnotated.Predicates.metaAnnotatedWith;
import static com.tngtech.archunit.core.domain.properties.HasName.AndFullName.Predicates.fullName;
import static com.tngtech.archunit.core.domain.properties.HasName.AndFullName.Predicates.fullNameMatching;
import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.name;
import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.nameMatching;
import static com.tngtech.archunit.lang.conditions.ArchPredicates.are;
Expand Down Expand Up @@ -71,6 +73,26 @@ public CONJUNCTION haveNameNotMatching(String regex) {
return givenWith(SyntaxPredicates.haveNameNotMatching(regex));
}

@Override
public CONJUNCTION haveFullName(String fullName) {
return givenWith(have(fullName(fullName)));
}

@Override
public CONJUNCTION doNotHaveFullName(String fullName) {
return givenWith(doNot(have(fullName(fullName))));
}

@Override
public CONJUNCTION haveFullNameMatching(String regex) {
return givenWith(have(fullNameMatching(regex)));
}

@Override
public CONJUNCTION haveFullNameNotMatching(String regex) {
return givenWith(have(not(fullNameMatching(regex)).as("full name not matching '%s'", regex)));
}

@Override
public CONJUNCTION arePublic() {
return givenWith(SyntaxPredicates.arePublic());
Expand Down
Loading

0 comments on commit d8c9e90

Please sign in to comment.