Skip to content

Commit

Permalink
Add (not)haveFullyQualifiedNameAnyOf to API
Browse files Browse the repository at this point in the history
  • Loading branch information
perlun committed May 26, 2023
1 parent c09534c commit 024ac91
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.tngtech.archunit.PublicAPI;
import com.tngtech.archunit.base.ChainableFunction;
import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.Formatters;

import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;
import static com.tngtech.archunit.core.domain.properties.HasName.Utils.namesOf;
Expand Down Expand Up @@ -117,6 +118,11 @@ public static DescribedPredicate<HasName> name(String name) {
return new NameEqualsPredicate(name);
}

@PublicAPI(usage = ACCESS)
public static DescribedPredicate<HasName> nameAnyOf(String... classNames) {
return new NameEqualsAnyOfPredicate(classNames);
}

/**
* Matches names against a regular expression.
*/
Expand Down Expand Up @@ -154,6 +160,26 @@ public boolean test(HasName input) {
}
}

private static class NameEqualsAnyOfPredicate extends DescribedPredicate<HasName> {
private final String[] names;

NameEqualsAnyOfPredicate(String[] names) {
super(String.format("name '%s'", Formatters.joinSingleQuoted(names)));
this.names = names;
}

@Override
public boolean test(HasName input) {
for (String name : names) {
if (input.getName().equals(name)) {
return true;
}
}

return false;
}
}

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
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.nameAnyOf;
import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.nameContaining;
import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.nameEndingWith;
import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.nameMatching;
Expand Down Expand Up @@ -518,6 +519,22 @@ public static ArchCondition<JavaClass> notHaveFullyQualifiedName(String name) {
return not(haveFullyQualifiedName(name));
}

@PublicAPI(usage = ACCESS)
public static ArchCondition<JavaClass> haveFullyQualifiedNameAnyOf(String... classNames) {
return have(fullyQualifiedNameAnyOf(classNames));
}

@Internal
public static DescribedPredicate<HasName> fullyQualifiedNameAnyOf(String[] classNames) {
DescribedPredicate<HasName> predicate = nameAnyOf(classNames);
return predicate.as("fully qualified " + predicate.getDescription());
}

@PublicAPI(usage = ACCESS)
public static ArchCondition<JavaClass> notHaveFullyQualifiedNameAnyOf(String... classNames) {
return not(haveFullyQualifiedNameAnyOf(classNames));
}

@PublicAPI(usage = ACCESS)
public static ArchCondition<JavaClass> haveSimpleName(String name) {
return have(simpleName(name));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,16 @@ public CONJUNCTION doNotHaveFullyQualifiedName(String name) {
return givenWith(SyntaxPredicates.doNotHaveFullyQualifiedName(name));
}

@Override
public CONJUNCTION haveFullyQualifiedNameAnyOf(String... classNames) {
return givenWith(SyntaxPredicates.haveFullyQualifiedNameAnyOf(classNames));
}

@Override
public CONJUNCTION doNotHaveFullyQualifiedNameAnyOf(String... classNames) {
return givenWith(SyntaxPredicates.doNotHaveFullyQualifiedNameAnyOf(classNames));
}

@Override
public CONJUNCTION haveSimpleName(String name) {
return givenWith(SyntaxPredicates.haveSimpleName(name));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@ public CONJUNCTION doNotHaveFullyQualifiedName(String name) {
return givenWith(SyntaxPredicates.doNotHaveFullyQualifiedName(name));
}

@Override
public CONJUNCTION haveFullyQualifiedNameAnyOf(String... classNames) {
return givenWith(SyntaxPredicates.haveFullyQualifiedNameAnyOf(classNames));
}

@Override
public CONJUNCTION doNotHaveFullyQualifiedNameAnyOf(String... classNames) {
return givenWith(SyntaxPredicates.doNotHaveFullyQualifiedNameAnyOf(classNames));
}

@Override
public CONJUNCTION haveSimpleName(String name) {
return givenWith(SyntaxPredicates.haveSimpleName(name));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import static com.tngtech.archunit.core.domain.properties.HasModifiers.Predicates.modifier;
import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.nameMatching;
import static com.tngtech.archunit.lang.conditions.ArchConditions.fullyQualifiedName;
import static com.tngtech.archunit.lang.conditions.ArchConditions.fullyQualifiedNameAnyOf;
import static com.tngtech.archunit.lang.conditions.ArchPredicates.have;

class SyntaxPredicates {
Expand Down Expand Up @@ -110,6 +111,14 @@ static DescribedPredicate<HasName> doNotHaveFullyQualifiedName(String name) {
return doNot(have(fullyQualifiedName(name)));
}

static DescribedPredicate<HasName> haveFullyQualifiedNameAnyOf(String[] classNames) {
return have(fullyQualifiedNameAnyOf(classNames));
}

static DescribedPredicate<HasName> doNotHaveFullyQualifiedNameAnyOf(String[] classNames) {
return doNot(have(fullyQualifiedNameAnyOf(classNames)));
}

static DescribedPredicate<JavaClass> haveSimpleName(String name) {
return have(simpleName(name));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,24 @@ public interface ClassesThat<CONJUNCTION> {
@PublicAPI(usage = ACCESS)
CONJUNCTION doNotHaveFullyQualifiedName(String name);

/**
* Matches classes by their fully qualified class name.
*
* @param classNames One or more fully qualified class names
* @return A syntax conjunction element, which can be completed to form a full rule
*/
@PublicAPI(usage = ACCESS)
CONJUNCTION haveFullyQualifiedNameAnyOf(String... classNames);

/**
* Matches classes that do not have a certain fully qualified class name.
*
* @param classNames One or more fully qualified class names
* @return A syntax conjunction element, which can be completed to form a full rule
*/
@PublicAPI(usage = ACCESS)
CONJUNCTION doNotHaveFullyQualifiedNameAnyOf(String... classNames);

/**
* Matches classes by their simple class name.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,22 @@ public void doNotHaveFullyQualifiedName() {
assertThatTypes(classes).matchInAnyOrder(String.class, Iterable.class);
}

@Test
public void haveFullyQualifiedNameAnyOf() {
List<JavaClass> classes = filterResultOf(classes().that().haveFullyQualifiedNameAnyOf(List.class.getName()))
.on(List.class, String.class, Iterable.class);

assertThatType(getOnlyElement(classes)).matches(List.class);
}

@Test
public void doNotHaveFullyQualifiedNameAnyOf() {
List<JavaClass> classes = filterResultOf(classes().that().doNotHaveFullyQualifiedNameAnyOf(List.class.getName()))
.on(List.class, String.class, Iterable.class);

assertThatTypes(classes).matchInAnyOrder(String.class, Iterable.class);
}

@Test
public void haveSimpleName() {
List<JavaClass> classes = filterResultOf(classes().that().haveSimpleName(List.class.getSimpleName()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,22 @@ public void doNotHaveFullyQualifiedName() {
assertThatMembers(members).matchInAnyOrderMembersOf(String.class, Iterable.class);
}

@Test
public void haveFullyQualifiedNameAnyOf() {
List<JavaMember> members = filterResultOf(members().that().areDeclaredInClassesThat().haveFullyQualifiedNameAnyOf(List.class.getName()))
.on(List.class, String.class, Iterable.class);

assertThatMembers(members).matchInAnyOrderMembersOf(List.class);
}

@Test
public void doNotHaveFullyQualifiedNameAnyOf() {
List<JavaMember> members = filterResultOf(members().that().areDeclaredInClassesThat().doNotHaveFullyQualifiedNameAnyOf(List.class.getName()))
.on(List.class, String.class, Iterable.class);

assertThatMembers(members).matchInAnyOrderMembersOf(String.class, Iterable.class);
}

@Test
public void haveSimpleName() {
List<JavaMember> members = filterResultOf(members().that().areDeclaredInClassesThat().haveSimpleName(List.class.getSimpleName()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,26 @@ public void doNotHaveFullyQualifiedName(ClassesThat<ClassesShouldConjunction> no
assertThatTypes(classes).matchInAnyOrder(ClassAccessingString.class, ClassAccessingIterable.class);
}

@Test
@UseDataProvider("no_classes_should_that_rule_starts")
public void haveFullyQualifiedNameAnyOf(ClassesThat<ClassesShouldConjunction> noClassesShouldThatRuleStart) {
Set<JavaClass> classes = filterClassesAppearingInFailureReport(
noClassesShouldThatRuleStart.haveFullyQualifiedNameAnyOf(List.class.getName()))
.on(ClassAccessingList.class, ClassAccessingString.class, ClassAccessingIterable.class);

assertThatType(getOnlyElement(classes)).matches(ClassAccessingList.class);
}

@Test
@UseDataProvider("no_classes_should_that_rule_starts")
public void doNotHaveFullyQualifiedNameAnyOf(ClassesThat<ClassesShouldConjunction> noClassesShouldThatRuleStart) {
Set<JavaClass> classes = filterClassesAppearingInFailureReport(
noClassesShouldThatRuleStart.doNotHaveFullyQualifiedNameAnyOf(List.class.getName()))
.on(ClassAccessingList.class, ClassAccessingString.class, ClassAccessingIterable.class);

assertThatTypes(classes).matchInAnyOrder(ClassAccessingString.class, ClassAccessingIterable.class);
}

@Test
@UseDataProvider("no_classes_should_that_rule_starts")
public void haveSimpleName(ClassesThat<ClassesShouldConjunction> noClassesShouldThatRuleStart) {
Expand Down Expand Up @@ -1735,7 +1755,7 @@ static class DirectlyDependentClass3 {

@SuppressWarnings("unused")
static class Level1TransitivelyDependentClass1 {
Level2TransitivelyDependentClass1 transitiveDependency1;
Level2TransitivelyDependentClass1 transitiveDependency1;
}

static class Level2TransitivelyDependentClass1 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,32 @@ public void doNotHaveFullyQualifiedName(ClassesThat<ClassesShouldConjunction> cl
assertThatTypes(classes).matchInAnyOrder(ClassAccessedByFoo.class, Foo.class);
}

@Test
@UseDataProvider("should_only_be_by_rule_starts")
public void haveFullyQualifiedNameAnyOf(ClassesThat<ClassesShouldConjunction> classesShouldOnlyBeBy) {
Set<JavaClass> classes = filterClassesAppearingInFailureReport(
classesShouldOnlyBeBy.haveFullyQualifiedNameAnyOf(Foo.class.getName()))
.on(ClassAccessedByFoo.class, Foo.class,
ClassAccessedByBar.class, Bar.class,
ClassAccessedByBaz.class, Baz.class);

assertThatTypes(classes).matchInAnyOrder(
ClassAccessedByBar.class, Bar.class,
ClassAccessedByBaz.class, Baz.class);
}

@Test
@UseDataProvider("should_only_be_by_rule_starts")
public void doNotHaveFullyQualifiedNameAnyOf(ClassesThat<ClassesShouldConjunction> classesShouldOnlyBeBy) {
Set<JavaClass> classes = filterClassesAppearingInFailureReport(
classesShouldOnlyBeBy.doNotHaveFullyQualifiedNameAnyOf(Foo.class.getName()))
.on(ClassAccessedByFoo.class, Foo.class,
ClassAccessedByBar.class, Bar.class,
ClassAccessedByBaz.class, Baz.class);

assertThatTypes(classes).matchInAnyOrder(ClassAccessedByFoo.class, Foo.class);
}

@Test
@UseDataProvider("should_only_be_by_rule_starts")
public void haveSimpleName(ClassesThat<ClassesShouldConjunction> classesShouldOnlyBeBy) {
Expand Down Expand Up @@ -1422,6 +1448,7 @@ private static class StaticNestedClassBeingAccessed {

// This must be loaded via Reflection, otherwise the test will be tainted by the dependency on the class object
private static final Class<?> ClassAccessingAnonymousClass_Reference = classForName("com.tngtech.archunit.lang.syntax.elements.ShouldOnlyByClassesThatTest$ClassAccessingAnonymousClass");

private static class ClassAccessingAnonymousClass {
@SuppressWarnings("unused")
void access() {
Expand Down

0 comments on commit 024ac91

Please sign in to comment.