diff --git a/archunit/src/main/java/com/tngtech/archunit/core/domain/AccessTarget.java b/archunit/src/main/java/com/tngtech/archunit/core/domain/AccessTarget.java index 7e2a3edb25..a3f1871f97 100644 --- a/archunit/src/main/java/com/tngtech/archunit/core/domain/AccessTarget.java +++ b/archunit/src/main/java/com/tngtech/archunit/core/domain/AccessTarget.java @@ -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() { diff --git a/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaClass.java b/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaClass.java index 25c4609b97..7cf2cdad97 100644 --- a/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaClass.java +++ b/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaClass.java @@ -109,6 +109,9 @@ public Set 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 getSource() { return source; @@ -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() { diff --git a/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaCodeUnit.java b/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaCodeUnit.java index f6441f4358..db00df07ad 100644 --- a/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaCodeUnit.java +++ b/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaCodeUnit.java @@ -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() { diff --git a/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaField.java b/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaField.java index d4ec5b65a2..c64cd3306a 100644 --- a/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaField.java +++ b/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaField.java @@ -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() { diff --git a/archunit/src/main/java/com/tngtech/archunit/core/domain/properties/HasName.java b/archunit/src/main/java/com/tngtech/archunit/core/domain/properties/HasName.java index 481a370977..fb152f9d4a 100644 --- a/archunit/src/main/java/com/tngtech/archunit/core/domain/properties/HasName.java +++ b/archunit/src/main/java/com/tngtech/archunit/core/domain/properties/HasName.java @@ -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 fullName(String fullName) { + return new FullNameEqualsPredicate(fullName); + } + + /** + * Matches full names against a regular expression. + */ + @PublicAPI(usage = ACCESS) + public static DescribedPredicate fullNameMatching(String regex) { + return new FullNameMatchingPredicate(regex); + } + + private static class FullNameEqualsPredicate extends DescribedPredicate { + 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 { + 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 GET_FULL_NAME = new ChainableFunction() { + @Override + public String apply(HasName.AndFullName input) { + return input.getFullName(); + } + }; + } } final class Predicates { private Predicates() { } + @PublicAPI(usage = ACCESS) + public static DescribedPredicate name(final String name) { + return new NameEqualsPredicate(name); + } + /** * Matches names against a regular expression. */ @@ -44,36 +111,31 @@ public static DescribedPredicate nameMatching(final String regex) { return new NameMatchingPredicate(regex); } - @PublicAPI(usage = ACCESS) - public static DescribedPredicate name(final String name) { - return new NameEqualsPredicate(name); - } - - private static class NameMatchingPredicate extends DescribedPredicate { - private final Pattern pattern; + private static class NameEqualsPredicate extends DescribedPredicate { + 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 { - private final String name; + private static class NameMatchingPredicate extends DescribedPredicate { + 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(); } } } diff --git a/archunit/src/main/java/com/tngtech/archunit/core/domain/properties/HasSourceCodeLocation.java b/archunit/src/main/java/com/tngtech/archunit/core/domain/properties/HasSourceCodeLocation.java index 8b242994e1..5547d93ce2 100644 --- a/archunit/src/main/java/com/tngtech/archunit/core/domain/properties/HasSourceCodeLocation.java +++ b/archunit/src/main/java/com/tngtech/archunit/core/domain/properties/HasSourceCodeLocation.java @@ -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(); } diff --git a/archunit/src/main/java/com/tngtech/archunit/lang/conditions/ArchConditions.java b/archunit/src/main/java/com/tngtech/archunit/lang/conditions/ArchConditions.java index b5899b877b..d699fbdb0e 100644 --- a/archunit/src/main/java/com/tngtech/archunit/lang/conditions/ArchConditions.java +++ b/archunit/src/main/java/com/tngtech/archunit/lang/conditions/ArchConditions.java @@ -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; @@ -451,6 +453,18 @@ public static haveName(name)); } + @PublicAPI(usage = ACCESS) + public static + ArchCondition haveFullName(String fullName) { + return new HaveConditionByPredicate<>(fullName(fullName)); + } + + @PublicAPI(usage = ACCESS) + public static + ArchCondition notHaveFullName(String fullName) { + return not(new HaveConditionByPredicate(fullName(fullName))); + } + @PublicAPI(usage = ACCESS) public static ArchCondition haveFullyQualifiedName(final String name) { return new HaveConditionByPredicate<>(fullyQualifiedName(name)); @@ -516,8 +530,8 @@ public static ArchCondition haveSimpleNameNotEndingWith(String suffix @PublicAPI(usage = ACCESS) public static ArchCondition haveNameMatching(final String regex) { - final DescribedPredicate haveNameMatching = have(nameMatching(regex)); - return new NameMatchingCondition<>(haveNameMatching, regex); + final DescribedPredicate haveNameMatching = have(nameMatching(regex)).forSubType(); + return new MatchingCondition<>(haveNameMatching, regex); } @PublicAPI(usage = ACCESS) @@ -525,6 +539,19 @@ public static haveNameMatching(regex)).as("have name not matching '%s'", regex); } + @PublicAPI(usage = ACCESS) + public static + ArchCondition haveFullNameMatching(String regex) { + final DescribedPredicate haveFullNameMatching = have(fullNameMatching(regex)).forSubType(); + return new MatchingCondition<>(haveFullNameMatching, regex); + } + + @PublicAPI(usage = ACCESS) + public static ArchCondition + haveFullNameNotMatching(String regex) { + return not(ArchConditions.haveFullNameMatching(regex)).as("have full name not matching '%s'", regex); + } + @PublicAPI(usage = ACCESS) public static ArchCondition resideInAPackage(final String packageIdentifier) { return new DoesConditionByPredicate<>(JavaClass.Predicates.resideInAPackage(packageIdentifier)); @@ -1095,22 +1122,22 @@ public void check(JavaClass javaClass, ConditionEvents events) { } } - private static class NameMatchingCondition extends ArchCondition { - private final DescribedPredicate haveNameMatching; + private static class MatchingCondition extends ArchCondition { + private final DescribedPredicate matcher; private final String regex; - NameMatchingCondition(DescribedPredicate haveNameMatching, String regex) { - super(haveNameMatching.getDescription()); - this.haveNameMatching = haveNameMatching; + MatchingCondition(DescribedPredicate 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)); } } diff --git a/archunit/src/main/java/com/tngtech/archunit/lang/syntax/AbstractMembersShouldInternal.java b/archunit/src/main/java/com/tngtech/archunit/lang/syntax/AbstractMembersShouldInternal.java index 0b5e6bb313..253fb94908 100644 --- a/archunit/src/main/java/com/tngtech/archunit/lang/syntax/AbstractMembersShouldInternal.java +++ b/archunit/src/main/java/com/tngtech/archunit/lang/syntax/AbstractMembersShouldInternal.java @@ -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()); diff --git a/archunit/src/main/java/com/tngtech/archunit/lang/syntax/MembersThatInternal.java b/archunit/src/main/java/com/tngtech/archunit/lang/syntax/MembersThatInternal.java index d4a35062f7..68368ec679 100644 --- a/archunit/src/main/java/com/tngtech/archunit/lang/syntax/MembersThatInternal.java +++ b/archunit/src/main/java/com/tngtech/archunit/lang/syntax/MembersThatInternal.java @@ -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; @@ -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()); diff --git a/archunit/src/main/java/com/tngtech/archunit/lang/syntax/elements/MembersShould.java b/archunit/src/main/java/com/tngtech/archunit/lang/syntax/elements/MembersShould.java index 065fd4fa36..74ce1e7ffd 100644 --- a/archunit/src/main/java/com/tngtech/archunit/lang/syntax/elements/MembersShould.java +++ b/archunit/src/main/java/com/tngtech/archunit/lang/syntax/elements/MembersShould.java @@ -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; @@ -67,6 +69,44 @@ public interface MembersShould> @PublicAPI(usage = ACCESS) CONJUNCTION haveNameNotMatching(String regex); + /** + * 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 + */ + @PublicAPI(usage = ACCESS) + CONJUNCTION haveFullName(String fullName); + + /** + * 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 + */ + @PublicAPI(usage = ACCESS) + CONJUNCTION notHaveFullName(String fullName); + + /** + * 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 + */ + @PublicAPI(usage = ACCESS) + CONJUNCTION haveFullNameMatching(String regex); + + /** + * 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 + */ + @PublicAPI(usage = ACCESS) + CONJUNCTION haveFullNameNotMatching(String regex); + /** * Asserts that members are public. * diff --git a/archunit/src/main/java/com/tngtech/archunit/lang/syntax/elements/MembersThat.java b/archunit/src/main/java/com/tngtech/archunit/lang/syntax/elements/MembersThat.java index 70e3d60cb1..6cbfe2a35d 100644 --- a/archunit/src/main/java/com/tngtech/archunit/lang/syntax/elements/MembersThat.java +++ b/archunit/src/main/java/com/tngtech/archunit/lang/syntax/elements/MembersThat.java @@ -67,6 +67,42 @@ public interface MembersThat> { @PublicAPI(usage = ACCESS) CONJUNCTION haveNameNotMatching(String regex); + /** + * Matches members by their full name. + * + * @param fullName The member's full name + * @return A syntax conjunction element, which can be completed to form a full rule + */ + @PublicAPI(usage = ACCESS) + CONJUNCTION haveFullName(String fullName); + + /** + * Matches members that do not have a certain full name. + * + * @param fullName The member's full name + * @return A syntax conjunction element, which can be completed to form a full rule + */ + @PublicAPI(usage = ACCESS) + CONJUNCTION doNotHaveFullName(String fullName); + + /** + * Matches members with a full name matching a given regular expression. + * + * @param regex A regular expression + * @return A syntax conjunction element, which can be completed to form a full rule + */ + @PublicAPI(usage = ACCESS) + CONJUNCTION haveFullNameMatching(String regex); + + /** + * Matches members with a full name not matching a given regular expression. + * + * @param regex A regular expression + * @return A syntax conjunction element, which can be completed to form a full rule + */ + @PublicAPI(usage = ACCESS) + CONJUNCTION haveFullNameNotMatching(String regex); + /** * Matches public members. * diff --git a/archunit/src/test/java/com/tngtech/archunit/core/domain/properties/HasNameTest.java b/archunit/src/test/java/com/tngtech/archunit/core/domain/properties/HasNameTest.java index 0c8aa8209c..ed9bc1d773 100644 --- a/archunit/src/test/java/com/tngtech/archunit/core/domain/properties/HasNameTest.java +++ b/archunit/src/test/java/com/tngtech/archunit/core/domain/properties/HasNameTest.java @@ -3,28 +3,32 @@ 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; public class HasNameTest { @Test - public void match_against_regex() { - assertMatches("Some.foobar", ".*foo.*").isTrue(); - assertMatches("Some.fobar", ".*foo.*").isFalse(); - assertMatches("Some.foobar", ".*fob?o*.*").isTrue(); - assertMatches("com.tngtech.SomeClass", ".*W.*").isFalse(); - assertMatches("com.tngtech.SomeClass", "com.*").isTrue(); - assertMatches("com.tngtech.SomeClass", "co\\..*").isFalse(); - assertMatches("com.tngtech.SomeClass", ".*Class").isTrue(); - assertMatches("com.tngtech.SomeClass", ".*Clas").isFalse(); - assertMatches("com.tngtech.SomeClass", ".*\\.S.*s").isTrue(); + public void nameMatching_predicate() { + assertNameMatches("Some.foobar", ".*foo.*").isTrue(); + assertNameMatches("Some.fobar", ".*foo.*").isFalse(); + assertNameMatches("Some.foobar", ".*fob?o*.*").isTrue(); + assertNameMatches("com.tngtech.SomeClass", ".*W.*").isFalse(); + assertNameMatches("com.tngtech.SomeClass", "com.*").isTrue(); + assertNameMatches("com.tngtech.SomeClass", "co\\..*").isFalse(); + assertNameMatches("com.tngtech.SomeClass", ".*Class").isTrue(); + assertNameMatches("com.tngtech.SomeClass", ".*Clas").isFalse(); + assertNameMatches("com.tngtech.SomeClass", ".*\\.S.*s").isTrue(); assertThat(nameMatching(".*foo")).hasDescription("name matching '.*foo'"); } @Test - public void match_against_name() { + public void name_predicate() { assertThat(name("some.Foo")) .accepts(newHasName("some.Foo")) .rejects(newHasName("some.Fo")) @@ -32,17 +36,52 @@ public void match_against_name() { assertThat(name("Foo")).rejects(newHasName("some.Foo")); } - private AbstractBooleanAssert assertMatches(String input, String regex) { + @Test + public void fullName_predicate() { + assertThat(fullName("some.Foo.field1")) + .accepts(newHasNameAndFullName("field1", "some.Foo.field1")) + .rejects(newHasNameAndFullName("field", "some.Foo.field")) + .rejects(newHasNameAndFullName("field12", "some.Foo.field12")) + .rejects(newHasNameAndFullName("some.Foo.field1", "some.Foo.field1.property")) + .hasDescription("full name 'some.Foo.field1'"); + } + + @Test + public void fullNameMatching_predicate() { + assertThat(fullNameMatching(".*method\\(.*\\)")) + .accepts(newHasNameAndFullName("method", "some.Foo.method(int)")) + .accepts(newHasNameAndFullName("method", "some.Foo.method()")) + .rejects(newHasNameAndFullName("method", "some.Foo.method")) + .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); } private HasName newHasName(final String name) { - return new HasName() { + return newHasNameAndFullName(name, "full " + name); + } + + private HasName.AndFullName newHasNameAndFullName(final String name, final String fullName) { + return new HasName.AndFullName() { @Override public String getName() { return name; } + + @Override + public String getFullName() { + return fullName; + } }; } } \ No newline at end of file diff --git a/archunit/src/test/java/com/tngtech/archunit/lang/syntax/elements/FieldsShouldTest.java b/archunit/src/test/java/com/tngtech/archunit/lang/syntax/elements/FieldsShouldTest.java index 89093112a0..8e4d38b15b 100644 --- a/archunit/src/test/java/com/tngtech/archunit/lang/syntax/elements/FieldsShouldTest.java +++ b/archunit/src/test/java/com/tngtech/archunit/lang/syntax/elements/FieldsShouldTest.java @@ -5,7 +5,6 @@ import java.util.Map; import java.util.Set; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList; import com.tngtech.archunit.lang.ArchRule; import com.tngtech.archunit.lang.EvaluationResult; diff --git a/archunit/src/test/java/com/tngtech/archunit/lang/syntax/elements/GivenMembersTest.java b/archunit/src/test/java/com/tngtech/archunit/lang/syntax/elements/GivenMembersTest.java index 3d1c76e1a5..e83e127d72 100644 --- a/archunit/src/test/java/com/tngtech/archunit/lang/syntax/elements/GivenMembersTest.java +++ b/archunit/src/test/java/com/tngtech/archunit/lang/syntax/elements/GivenMembersTest.java @@ -52,6 +52,7 @@ import static com.tngtech.java.junit.dataprovider.DataProviders.$$; import static java.util.Collections.emptySet; import static java.util.Collections.singleton; +import static java.util.regex.Pattern.quote; import static org.assertj.core.api.Assertions.assertThat; @RunWith(DataProviderRunner.class) @@ -147,6 +148,7 @@ public void complex_members_syntax() { @DataProvider public static Object[][] restricted_property_rule_starts() { + String classNameDot = ClassWithVariousMembers.class.getName() + "."; ImmutableList.Builder data = ImmutableList.builder().add( $(described(members().that().haveName(FIELD_A)), ImmutableSet.of(FIELD_A)), $(described(codeUnits().that().haveName(FIELD_A)), ImmutableSet.of()), @@ -186,6 +188,32 @@ public static Object[][] restricted_property_rule_starts() { $(described(codeUnits().that().haveNameNotMatching(".*init.*")), ALL_METHOD_DESCRIPTIONS), $(described(constructors().that().haveNameNotMatching(".*init.*")), emptySet()), + $(described(members().that().haveFullName(classNameDot + FIELD_A)), ImmutableSet.of(FIELD_A)), + $(described(codeUnits().that().haveFullName(classNameDot + METHOD_A)), ImmutableSet.of(METHOD_A)), + $(described(methods().that().haveFullName(classNameDot + METHOD_A)), ImmutableSet.of(METHOD_A)), + $(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 + 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(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(quote(classNameDot) + ".*init.*String\\)")), + allConstructorsExcept(CONSTRUCTOR_ONE_ARG)), + $(described(fields().that().haveFullNameNotMatching(quote(classNameDot) + ".*A.*")), allFieldsExcept(FIELD_A)), + $(described(members().that().arePublic()), ImmutableSet.of( FIELD_PUBLIC, METHOD_PUBLIC, CONSTRUCTOR_PUBLIC)), $(described(fields().that().arePublic()), ImmutableSet.of(FIELD_C)), diff --git a/archunit/src/test/java/com/tngtech/archunit/lang/syntax/elements/MembersShouldTest.java b/archunit/src/test/java/com/tngtech/archunit/lang/syntax/elements/MembersShouldTest.java index 54d8a9a8ef..3725b15664 100644 --- a/archunit/src/test/java/com/tngtech/archunit/lang/syntax/elements/MembersShouldTest.java +++ b/archunit/src/test/java/com/tngtech/archunit/lang/syntax/elements/MembersShouldTest.java @@ -46,6 +46,7 @@ import static com.tngtech.archunit.lang.syntax.elements.GivenMembersTest.ALL_OTHER_MEMBER_DESCRIPTIONS; import static com.tngtech.archunit.lang.syntax.elements.GivenMembersTest.ALL_OTHER_METHOD_DESCRIPTIONS; import static com.tngtech.archunit.lang.syntax.elements.GivenMembersTest.CONSTRUCTOR_ANNOTATED_WITH_A; +import static com.tngtech.archunit.lang.syntax.elements.GivenMembersTest.CONSTRUCTOR_ONE_ARG; import static com.tngtech.archunit.lang.syntax.elements.GivenMembersTest.CONSTRUCTOR_PACKAGE_PRIVATE; import static com.tngtech.archunit.lang.syntax.elements.GivenMembersTest.CONSTRUCTOR_PRIVATE; import static com.tngtech.archunit.lang.syntax.elements.GivenMembersTest.CONSTRUCTOR_PROTECTED; @@ -100,6 +101,7 @@ public void complex_members_syntax() { @DataProvider public static Object[][] restricted_property_rule_ends() { + String classNameDot = ClassWithVariousMembers.class.getName() + "."; ImmutableList.Builder data = ImmutableList.builder().add( $(members().should().haveName(FIELD_A), allMembersExcept(FIELD_A)), $(codeUnits().should().haveName(FIELD_A), ALL_CODE_UNIT_DESCRIPTIONS), @@ -131,6 +133,33 @@ public static Object[][] restricted_property_rule_ends() { $(codeUnits().should().haveNameNotMatching(".*init.*"), ALL_CONSTRUCTOR_DESCRIPTIONS), $(constructors().should().haveNameNotMatching(".*init.*"), ALL_CONSTRUCTOR_DESCRIPTIONS), + $(members().should().haveFullName(classNameDot + FIELD_A), allMembersExcept(FIELD_A)), + $(fields().should().haveFullName(classNameDot + FIELD_A), allFieldsExcept(FIELD_A)), + $(codeUnits().should().haveFullName(classNameDot + FIELD_A), ALL_CODE_UNIT_DESCRIPTIONS), + $(methods().should().haveFullName(classNameDot + METHOD_A), allMethodsExcept(METHOD_A)), + $(codeUnits().should().haveFullName(classNameDot + METHOD_A), allCodeUnitsExcept(METHOD_A)), + $(members().should().notHaveFullName(classNameDot + FIELD_A), ImmutableSet.of(FIELD_A)), + $(fields().should().notHaveFullName(classNameDot + FIELD_A), ImmutableSet.of(FIELD_A)), + $(codeUnits().should().notHaveFullName(classNameDot + FIELD_A), emptySet()), + $(methods().should().notHaveFullName(classNameDot + METHOD_A), ImmutableSet.of(METHOD_A)), + $(codeUnits().should().notHaveFullName(classNameDot + METHOD_A), ImmutableSet.of(METHOD_A)), + + $(members().should().haveFullNameMatching(quote(classNameDot) + ".*A\\(?\\)?"), allMembersExcept(FIELD_A, METHOD_A)), + $(codeUnits().should().haveFullNameMatching(quote(classNameDot) + ".*A"), ALL_CODE_UNIT_DESCRIPTIONS), + $(fields().should().haveFullNameMatching(quote(classNameDot) + ".*A"), allFieldsExcept(FIELD_A)), + $(codeUnits().should().haveFullNameMatching(quote(classNameDot) + ".*A" + quote("()")), allCodeUnitsExcept(METHOD_A)), + $(methods().should().haveFullNameMatching(quote(classNameDot) + ".*A" + quote("()")), allMethodsExcept(METHOD_A)), + $(codeUnits().should().haveFullNameMatching(quote(classNameDot) + "..*init.*"), ALL_METHOD_DESCRIPTIONS), + $(constructors().should().haveFullNameMatching(quote(classNameDot) + ".*init.*String\\)"), + allConstructorsExcept(CONSTRUCTOR_ONE_ARG)), + $(members().should().haveFullNameNotMatching(quote(classNameDot) + ".*A\\(?\\)?"), ImmutableSet.of(FIELD_A, METHOD_A)), + $(codeUnits().should().haveFullNameNotMatching(quote(classNameDot) + ".*A"), emptySet()), + $(fields().should().haveFullNameNotMatching(quote(classNameDot) + ".*A"), ImmutableSet.of(FIELD_A)), + $(codeUnits().should().haveFullNameNotMatching(quote(classNameDot) + ".*A" + quote("()")), ImmutableSet.of(METHOD_A)), + $(methods().should().haveFullNameNotMatching(quote(classNameDot) + ".*A" + quote("()")), ImmutableSet.of(METHOD_A)), + $(codeUnits().should().haveFullNameNotMatching(quote(classNameDot) + ".*init.*"), ALL_CONSTRUCTOR_DESCRIPTIONS), + $(constructors().should().haveFullNameNotMatching(quote(classNameDot) + ".*init.*String\\)"), ImmutableSet.of(CONSTRUCTOR_ONE_ARG)), + $(members().should().bePublic(), allMembersExcept( FIELD_PUBLIC, METHOD_PUBLIC, CONSTRUCTOR_PUBLIC)), $(fields().should().bePublic(), allFieldsExcept(FIELD_PUBLIC)),