From 5879c48909dc1f3e3b8212ba7ca8fdd1b1265cf3 Mon Sep 17 00:00:00 2001 From: Manfred Hanke Date: Mon, 22 Jul 2019 12:18:41 +0200 Subject: [PATCH] add members().should().{have,notHave}FullName[Not][Matching] syntax Signed-off-by: Manfred Hanke --- .../core/domain/properties/HasName.java | 12 ++--- .../lang/conditions/ArchConditions.java | 45 ++++++++++++++----- .../syntax/AbstractMembersShouldInternal.java | 19 ++++++++ .../lang/syntax/elements/MembersShould.java | 36 +++++++++++++++ .../syntax/elements/MembersShouldTest.java | 27 +++++++++++ 5 files changed, 121 insertions(+), 18 deletions(-) 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 796db3d7b4..fba3042730 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 @@ -44,8 +44,8 @@ public static DescribedPredicate fullName(String fullName) * Matches full names against a regular expression. */ @PublicAPI(usage = ACCESS) - public static DescribedPredicate fullNameMatching(String regex) { - return new FullNameMatchingPredicate(regex); + public static DescribedPredicate fullNameMatching(String regex) { + return new FullNameMatchingPredicate<>(regex); } private static class FullNameEqualsPredicate extends DescribedPredicate { @@ -62,7 +62,7 @@ public boolean apply(HasName.AndFullName input) { } } - private static class FullNameMatchingPredicate extends DescribedPredicate { + private static class FullNameMatchingPredicate extends DescribedPredicate { private final Pattern pattern; FullNameMatchingPredicate(String regex) { @@ -86,8 +86,8 @@ private Predicates() { * Matches names against a regular expression. */ @PublicAPI(usage = ACCESS) - public static DescribedPredicate nameMatching(final String regex) { - return new NameMatchingPredicate(regex); + public static DescribedPredicate nameMatching(final String regex) { + return new NameMatchingPredicate<>(regex); } @PublicAPI(usage = ACCESS) @@ -95,7 +95,7 @@ public static DescribedPredicate name(final String name) { return new NameEqualsPredicate(name); } - private static class NameMatchingPredicate extends DescribedPredicate { + private static class NameMatchingPredicate extends DescribedPredicate { private final Pattern pattern; NameMatchingPredicate(String regex) { 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..a5cb97159a 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,8 +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.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; @@ -451,6 +451,16 @@ 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 +526,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(HasName.Predicates.nameMatching(regex)); + return new MatchingCondition<>(haveNameMatching, regex); } @PublicAPI(usage = ACCESS) @@ -525,6 +535,17 @@ public static haveNameMatching(regex)).as("have name not matching '%s'", regex); } + @PublicAPI(usage = ACCESS) + public static ArchCondition haveFullNameMatching(String regex) { + final DescribedPredicate haveFullNameMatching = have(HasName.AndFullName.Predicates.fullNameMatching(regex)); + 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 +1116,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/elements/MembersShould.java b/archunit/src/main/java/com/tngtech/archunit/lang/syntax/elements/MembersShould.java index 065fd4fa36..5aca2f0fcf 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 @@ -67,6 +67,42 @@ public interface MembersShould> @PublicAPI(usage = ACCESS) CONJUNCTION haveNameNotMatching(String regex); + /** + * Asserts that members have a certain full name. + * + * @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. + * + * @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. + * + * @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. + * + * @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/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..235f782806 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 @@ -100,6 +100,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 +132,32 @@ 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.*"), emptySet()), + $(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.*"), ALL_CONSTRUCTOR_DESCRIPTIONS), + $(members().should().bePublic(), allMembersExcept( FIELD_PUBLIC, METHOD_PUBLIC, CONSTRUCTOR_PUBLIC)), $(fields().should().bePublic(), allFieldsExcept(FIELD_PUBLIC)),