Skip to content

Commit

Permalink
fix resideInSamePackage rule fails for multiple implementations, but …
Browse files Browse the repository at this point in the history
…not all with tests

Signed-off-by: krzysztof-owczarek <[email protected]>
  • Loading branch information
krzysztof-owczarek committed Oct 25, 2024
1 parent f8f80de commit bbf78cc
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -452,12 +452,16 @@ public static ArchRule testClassesShouldResideInTheSamePackageAsImplementation(S
private static ArchCondition<JavaClass> resideInTheSamePackageAsTheirTestClasses(String testClassSuffix) {
return new ArchCondition<JavaClass>("reside in the same package as their test classes") {
Map<String, List<JavaClass>> testClassesBySimpleClassName = new HashMap<>();
Map<String, List<JavaClass>> classesByPackageName = new HashMap<>();

@Override
public void init(Collection<JavaClass> allClasses) {
testClassesBySimpleClassName = allClasses.stream()
.filter(clazz -> clazz.getName().endsWith(testClassSuffix))
.collect(groupingBy(JavaClass::getSimpleName));

classesByPackageName = allClasses.stream()
.collect(groupingBy(JavaClass::getPackageName));
}

@Override
Expand All @@ -468,7 +472,8 @@ public void check(JavaClass implementationClass, ConditionEvents events) {
List<JavaClass> possibleTestClasses = testClassesBySimpleClassName.getOrDefault(possibleTestClassName, emptyList());

boolean isTestClassInWrongPackage = !possibleTestClasses.isEmpty()
&& possibleTestClasses.stream().noneMatch(clazz -> clazz.getPackageName().equals(implementationClassPackageName));
&& possibleTestClasses.stream().noneMatch(clazz -> clazz.getPackageName().equals(implementationClassPackageName))
&& !allPossibleTestClassesHaveImplementationInRightPackage(possibleTestClasses);

if (isTestClassInWrongPackage) {
possibleTestClasses.forEach(wrongTestClass -> {
Expand All @@ -478,6 +483,14 @@ public void check(JavaClass implementationClass, ConditionEvents events) {
});
}
}

private boolean allPossibleTestClassesHaveImplementationInRightPackage(List<JavaClass> possibleTestClasses) {
return possibleTestClasses.stream()
.allMatch(testClazz -> classesByPackageName.getOrDefault(testClazz.getPackageName(), emptyList())
.stream()
.filter(clazz -> !testClazz.getSimpleName().equals(clazz.getSimpleName()))
.anyMatch(clazz -> testClazz.getSimpleName().startsWith(clazz.getSimpleName())));
}
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.tngtech.archunit.library.testclasses.packages.correct.defaultsuffix.ImplementationClassWithCorrectPackage;
import com.tngtech.archunit.library.testclasses.packages.correct.notest.ImplementationClassWithoutTestClass;
import com.tngtech.archunit.library.testclasses.packages.correct.onedirmatching.ImplementationClassWithOneTestPackageMatchingOutOfTwo;
import com.tngtech.archunit.library.testclasses.packages.correct.twoimplementationsonetestdir1.MultipleImplementationsWithOnlyOneTestAndInRightPackage;
import com.tngtech.archunit.library.testclasses.packages.incorrect.nodirmatching.ImplementationClassWithMultipleTestsNotMatchingImplementationClassPackage;
import com.tngtech.archunit.library.testclasses.packages.incorrect.wrongsubdir.customsuffix.ImplementationClassWithWrongTestClassPackageCustomSuffix;
import com.tngtech.archunit.library.testclasses.packages.incorrect.wrongsubdir.customsuffix.subdir.ImplementationClassWithWrongTestClassPackageCustomSuffixTestingScenario;
Expand Down Expand Up @@ -83,6 +84,16 @@ public void should_not_pass_when_none_of_multiple_matching_test_classes_resides_
);
}

@Test
public void should_pass_when_only_one_of_two_implementations_have_test_class_and_it_is_in_implementation_package() {
assertThatRule(testClassesShouldResideInTheSamePackageAsImplementation())
.checking(new ClassFileImporter().importPackagesOf(
MultipleImplementationsWithOnlyOneTestAndInRightPackage.class,
com.tngtech.archunit.library.testclasses.packages.incorrect.twoimplementationsonetestdir2.MultipleImplementationsWithOnlyOneTestAndInRightPackage.class
))
.hasNoViolation();
}

@Test
public void ASSERTIONS_SHOULD_HAVE_DETAIL_MESSAGE_should_fail_on_assert_without_detail_message() {
@SuppressWarnings("unused")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.tngtech.archunit.library.testclasses.packages.correct.twoimplementationsonetestdir1;

public class MultipleImplementationsWithOnlyOneTestAndInRightPackage {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.tngtech.archunit.library.testclasses.packages.correct.twoimplementationsonetestdir1;

public class OnlyOneImplementationHaveTestAndItIsMatchingImplPackageTest {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.tngtech.archunit.library.testclasses.packages.incorrect.twoimplementationsonetestdir2;

public class MultipleImplementationsWithOnlyOneTestAndInRightPackage {
}

0 comments on commit bbf78cc

Please sign in to comment.