Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add (not)haveFullyQualifiedNameAnyOf to API #1114

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added tests to the best of my knowledge, and as ClassesThatTestsExistTest instructed me. Please let me know if there are any tests missing, I'm not sure this is enough. (feel free to just fix them yourself if it's easier that way 👍)

The tests added are trivial since I could just copy existing single-haveFullyQualifiedName tests.

@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