Skip to content

Commit

Permalink
Review:
Browse files Browse the repository at this point in the history
- Added some Javadoc (since I'm not sure if 'full name' can be immediately understood by every user)
- Removed the generic return type from the predicates in HasName and HasName.AndFullName since the caller should be responsible to map to the subtype (or it would have to be consistently changed in many other places)
- Tried to make some tests more decisive by matching at least some element of the passed collection
- Unrelated: Added HasName.AndFullName.Functions.GET_FULL_NAME to be consistent with HasName

Signed-off-by: Peter Gafert <peter.gafert@tngtech.com>
  • Loading branch information
codecholeric committed Jul 29, 2019
1 parent 5879c48 commit 71a524e
Show file tree
Hide file tree
Showing 11 changed files with 99 additions and 39 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,6 +28,9 @@ 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();

Expand All @@ -44,8 +47,8 @@ public static DescribedPredicate<HasName.AndFullName> fullName(String fullName)
* Matches full names against a regular expression.
*/
@PublicAPI(usage = ACCESS)
public static <HAS_FULL_NAME extends HasName.AndFullName> DescribedPredicate<HAS_FULL_NAME> fullNameMatching(String regex) {
return new FullNameMatchingPredicate<>(regex);
public static DescribedPredicate<HasName.AndFullName> fullNameMatching(String regex) {
return new FullNameMatchingPredicate(regex);
}

private static class FullNameEqualsPredicate extends DescribedPredicate<HasName.AndFullName> {
Expand All @@ -62,7 +65,7 @@ public boolean apply(HasName.AndFullName input) {
}
}

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

FullNameMatchingPredicate(String regex) {
Expand All @@ -76,50 +79,63 @@ public boolean apply(HasName.AndFullName input) {
}
}
}

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() {
}

/**
* Matches names against a regular expression.
*/
@PublicAPI(usage = ACCESS)
public static <HAS_NAME extends HasName> DescribedPredicate<HAS_NAME> nameMatching(final String regex) {
return new NameMatchingPredicate<>(regex);
public static DescribedPredicate<HasName> name(final String name) {
return new NameEqualsPredicate(name);
}

/**
* Matches names against a regular expression.
*/
@PublicAPI(usage = ACCESS)
public static DescribedPredicate<HasName> name(final String name) {
return new NameEqualsPredicate(name);
public static DescribedPredicate<HasName> nameMatching(final String regex) {
return new NameMatchingPredicate(regex);
}

private static class NameMatchingPredicate<HAS_NAME extends HasName> extends DescribedPredicate<HAS_NAME> {
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 @@ -99,7 +99,9 @@
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;
import static com.tngtech.archunit.core.domain.properties.HasParameterTypes.Predicates.rawParameterTypes;
import static com.tngtech.archunit.core.domain.properties.HasReturnType.Predicates.rawReturnType;
Expand Down Expand Up @@ -452,12 +454,14 @@ public static <HAS_NAME extends HasName & HasDescription & HasSourceCodeLocation
}

@PublicAPI(usage = ACCESS)
public static <HAS_FULL_NAME extends HasName.AndFullName & HasDescription & HasSourceCodeLocation> ArchCondition<HAS_FULL_NAME> haveFullName(String fullName) {
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) {
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)));
}

Expand Down Expand Up @@ -526,7 +530,7 @@ 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<HAS_NAME> haveNameMatching = have(HasName.Predicates.<HAS_NAME>nameMatching(regex));
final DescribedPredicate<HAS_NAME> haveNameMatching = have(nameMatching(regex)).forSubType();
return new MatchingCondition<>(haveNameMatching, regex);
}

Expand All @@ -536,13 +540,15 @@ public static <HAS_NAME extends HasName & HasDescription & HasSourceCodeLocation
}

@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(HasName.AndFullName.Predicates.<HAS_FULL_NAME>fullNameMatching(regex));
return new MatchingCondition<HAS_FULL_NAME>(haveFullNameMatching, regex);
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) {
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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.JavaAnnotation;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.domain.JavaCodeUnit;
import com.tngtech.archunit.core.domain.JavaConstructor;
import com.tngtech.archunit.core.domain.JavaField;
import com.tngtech.archunit.core.domain.JavaModifier;
import com.tngtech.archunit.lang.syntax.ArchRuleDefinition;

Expand Down Expand Up @@ -68,7 +70,7 @@ public interface MembersShould<CONJUNCTION extends MembersShouldConjunction<?>>
CONJUNCTION haveNameNotMatching(String regex);

/**
* Asserts that members have a certain full name.
* Asserts that members have a certain full name (compare {@link JavaField#getFullName()} and {@link JavaCodeUnit#getFullName()}).
*
* @param fullName The member's full name
* @return A syntax element that can either be used as working rule, or to continue specifying a more complex rule
Expand All @@ -77,7 +79,7 @@ public interface MembersShould<CONJUNCTION extends MembersShouldConjunction<?>>
CONJUNCTION haveFullName(String fullName);

/**
* Asserts that members do not have a certain full name.
* Asserts that members do not have a certain full name (compare {@link JavaField#getFullName()} and {@link JavaCodeUnit#getFullName()}).
*
* @param fullName The member's full name
* @return A syntax element that can either be used as working rule, or to continue specifying a more complex rule
Expand All @@ -86,7 +88,8 @@ public interface MembersShould<CONJUNCTION extends MembersShouldConjunction<?>>
CONJUNCTION notHaveFullName(String fullName);

/**
* Asserts that members have a full name matching a given regular expression.
* Asserts that members have a full name matching a given regular expression (compare {@link JavaField#getFullName()}
* and {@link JavaCodeUnit#getFullName()}).
*
* @param regex A regular expression
* @return A syntax element that can either be used as working rule, or to continue specifying a more complex rule
Expand All @@ -95,7 +98,8 @@ public interface MembersShould<CONJUNCTION extends MembersShouldConjunction<?>>
CONJUNCTION haveFullNameMatching(String regex);

/**
* Asserts that members have a full name not matching a given regular expression.
* Asserts that members have a full name not matching a given regular expression (compare {@link JavaField#getFullName()}
* and {@link JavaCodeUnit#getFullName()}).
*
* @param regex A regular expression
* @return A syntax element that can either be used as working rule, or to continue specifying a more complex rule
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import org.assertj.core.api.AbstractBooleanAssert;
import org.junit.Test;

import static com.tngtech.archunit.core.domain.properties.HasName.AndFullName.Functions.GET_FULL_NAME;
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.Functions.GET_NAME;
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.testutil.Assertions.assertThat;
Expand Down Expand Up @@ -53,6 +55,13 @@ public void fullNameMatching_predicate() {
.hasDescription("full name matching '.*method\\(.*\\)'");
}

@Test
public void functions() {
HasName.AndFullName test = newHasNameAndFullName("simple", "full");
assertThat(GET_NAME.apply(test)).isEqualTo("simple");
assertThat(GET_FULL_NAME.apply(test)).isEqualTo("full");
}

private AbstractBooleanAssert assertNameMatches(String input, String regex) {
return assertThat(nameMatching(regex).apply(newHasName(input)))
.as(input + " =~ " + regex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
Expand Down Expand Up @@ -195,22 +194,24 @@ public static Object[][] restricted_property_rule_starts() {
$(described(constructors().that().haveFullName(classNameDot + CONSTRUCTOR_ONE_ARG)), ImmutableSet.of(CONSTRUCTOR_ONE_ARG)),
$(described(fields().that().haveFullName(classNameDot + FIELD_A)), ImmutableSet.of(FIELD_A)),
$(described(members().that().doNotHaveFullName(classNameDot + FIELD_A)), union(allFieldsExcept(FIELD_A), ALL_CODE_UNIT_DESCRIPTIONS)),
$(described(codeUnits().that().doNotHaveFullName(classNameDot + FIELD_A)), ALL_CODE_UNIT_DESCRIPTIONS),
$(described(codeUnits().that().doNotHaveFullName(classNameDot + METHOD_A)), allCodeUnitsExcept(METHOD_A)),
$(described(methods().that().doNotHaveFullName(classNameDot + METHOD_A)), allMethodsExcept(METHOD_A)),
$(described(constructors().that().doNotHaveFullName(classNameDot + CONSTRUCTOR_ONE_ARG)), allConstructorsExcept(CONSTRUCTOR_ONE_ARG)),
$(described(fields().that().doNotHaveFullName(classNameDot + FIELD_A)), allFieldsExcept(FIELD_A)),

$(described(members().that().haveFullNameMatching(quote(classNameDot) + ".*A.*")), ImmutableSet.of(FIELD_A, METHOD_A)),
$(described(codeUnits().that().haveFullNameMatching(quote(classNameDot) + ".*A.*")), ImmutableSet.of(METHOD_A)),
$(described(methods().that().haveFullNameMatching(quote(classNameDot) + ".*A.*")), ImmutableSet.of(METHOD_A)),
$(described(constructors().that().haveFullNameMatching(".*init.*")), ALL_CONSTRUCTOR_DESCRIPTIONS),
$(described(constructors().that().haveFullNameMatching(quote(classNameDot) + ".*init.*String\\)")),
ImmutableSet.of(CONSTRUCTOR_ONE_ARG)),
$(described(fields().that().haveFullNameMatching(quote(classNameDot) + ".*A.*")), ImmutableSet.of(FIELD_A)),
$(described(members().that().haveFullNameNotMatching(quote(classNameDot) + "f.*A.*")), union(
allFieldsExcept(FIELD_A),
ALL_CODE_UNIT_DESCRIPTIONS)),
$(described(codeUnits().that().haveFullNameNotMatching(quote(classNameDot) + "f.*A.*")), ALL_CODE_UNIT_DESCRIPTIONS),
$(described(methods().that().haveFullNameNotMatching(quote(classNameDot) + ".*A.*")), allMethodsExcept(METHOD_A)),
$(described(constructors().that().haveFullNameNotMatching(".*init.*")), emptySet()),
$(described(constructors().that().haveFullNameNotMatching(quote(classNameDot) + ".*init.*String\\)")),
allConstructorsExcept(CONSTRUCTOR_ONE_ARG)),
$(described(fields().that().haveFullNameNotMatching(quote(classNameDot) + ".*A.*")), allFieldsExcept(FIELD_A)),

$(described(members().that().arePublic()), ImmutableSet.of(
Expand Down
Loading

0 comments on commit 71a524e

Please sign in to comment.