From 26ce3f79f1f27f3cbe081711d0239b63fc8de3a0 Mon Sep 17 00:00:00 2001 From: Remco Westerhoud Date: Tue, 15 Mar 2022 11:22:16 +0100 Subject: [PATCH] refactor: use classgraph in ExtendAbstractTest Replace custom implementation with classgraph. This solution is easier to understand. --- pom.xml | 10 +- qa/pom.xml | 10 +- .../process/test/qa/ExtendAbstractsTest.java | 114 +++++++++--------- 3 files changed, 71 insertions(+), 63 deletions(-) diff --git a/pom.xml b/pom.xml index 88855f149..5e209f7f7 100644 --- a/pom.xml +++ b/pom.xml @@ -48,6 +48,7 @@ 1.14.0 3.22.0 4.2.0 + 4.8.141 3.12.0 2.11.0 0.6.0 @@ -278,13 +279,18 @@ ${dependency.testcontainers.version} + + io.github.classgraph + classgraph + ${dependency.classgraph.version} + + + com.google.guava guava ${dependency.guava.version} - - com.google.protobuf protobuf-java diff --git a/qa/pom.xml b/qa/pom.xml index ccf5995c6..6788213b0 100644 --- a/qa/pom.xml +++ b/qa/pom.xml @@ -90,8 +90,14 @@ - com.google.guava - guava + io.github.classgraph + classgraph + test + + + + org.junit.jupiter + junit-jupiter-params test diff --git a/qa/src/test/java/io/camunda/zeebe/process/test/qa/ExtendAbstractsTest.java b/qa/src/test/java/io/camunda/zeebe/process/test/qa/ExtendAbstractsTest.java index 8d4dba3fd..f51aeedc9 100644 --- a/qa/src/test/java/io/camunda/zeebe/process/test/qa/ExtendAbstractsTest.java +++ b/qa/src/test/java/io/camunda/zeebe/process/test/qa/ExtendAbstractsTest.java @@ -15,80 +15,76 @@ */ package io.camunda.zeebe.process.test.qa; -import com.google.common.reflect.ClassPath; import io.camunda.zeebe.process.test.extension.ZeebeProcessTest; -import java.io.IOException; -import java.lang.annotation.Annotation; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ClassInfo; +import io.github.classgraph.ClassInfoList; +import java.util.stream.Stream; import org.assertj.core.api.SoftAssertions; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; class ExtendAbstractsTest { - public static final String EMBEDDED = "embedded"; - public static final String TESTCONTAINER = "testcontainer"; public static final Class EMBEDDED_ANNOTATION = ZeebeProcessTest.class; public static final Class TESTCONTAINER_ANNOTATION = io.camunda.zeebe.process.test.extension.testcontainer.ZeebeProcessTest.class; - private static final String BASE_PACKAGE = "io.camunda.zeebe.process.test.qa"; - private static final String ABSTRACTS = "abstracts"; + private static final String ABSTRACT_PACKAGE = "io.camunda.zeebe.process.test.qa.abstracts"; + private static final String EMBEDDED_PACKAGE = "io.camunda.zeebe.process.test.qa.embedded"; + private static final String TESTCONTAINER_PACKAGE = + "io.camunda.zeebe.process.test.qa.testcontainer"; - @Test - void testAbstractClassesAreExtendedWithBothExtensions() throws IOException { - final Map>> classes = new HashMap<>(); - classes.put(ABSTRACTS, new ArrayList<>()); - classes.put(EMBEDDED, new ArrayList<>()); - classes.put(TESTCONTAINER, new ArrayList<>()); + private static final ClassInfoList EXTENDING_CLASSES = + new ClassGraph() + .acceptPackages(EMBEDDED_PACKAGE, TESTCONTAINER_PACKAGE) + .ignoreClassVisibility() + .enableAnnotationInfo() + .scan() + .getAllStandardClasses() + .filter(info -> !info.isInnerClass()); - ClassPath.from(ClassLoader.getSystemClassLoader()).getTopLevelClasses().stream() - .filter(clazz -> clazz.getPackageName().startsWith(BASE_PACKAGE)) - .forEach( - classInfo -> { - if (classInfo.getPackageName().contains(BASE_PACKAGE + "." + ABSTRACTS)) { - classes.get(ABSTRACTS).add(classInfo.load()); - } else if (classInfo.getPackageName().contains(BASE_PACKAGE + "." + EMBEDDED)) { - classes.get(EMBEDDED).add(classInfo.load()); - } else if (classInfo.getPackageName().contains(BASE_PACKAGE + "." + TESTCONTAINER)) { - classes.get(TESTCONTAINER).add(classInfo.load()); - } - }); + @ParameterizedTest(name = "{0}") + @MethodSource("provideAbstractClasses") + void testAbstractClassIsExtendedWithBothExtensions( + final String className, final Class abstractClass) { + final ClassInfoList embeddedClass = + EXTENDING_CLASSES + .filter(info -> info.getPackageName().contains("embedded")) + .filter(info -> info.extendsSuperclass(abstractClass)) + .filter(info -> info.hasAnnotation(EMBEDDED_ANNOTATION)); + + final ClassInfoList testcontainerClass = + EXTENDING_CLASSES + .filter(info -> info.getPackageName().contains("testcontainer")) + .filter(info -> info.extendsSuperclass(abstractClass)) + .filter(info -> info.hasAnnotation(TESTCONTAINER_ANNOTATION)); final SoftAssertions softly = new SoftAssertions(); - classes - .get(ABSTRACTS) - .forEach( - abstractClass -> { - assertExtendingClass( - abstractClass, classes.get(EMBEDDED), EMBEDDED, EMBEDDED_ANNOTATION, softly); - assertExtendingClass( - abstractClass, - classes.get(TESTCONTAINER), - TESTCONTAINER, - TESTCONTAINER_ANNOTATION, - softly); - }); + softly + .assertThat(embeddedClass) + .withFailMessage( + "Expected 1 embedded implementation of %s, but found %d: %s", + className, embeddedClass.size(), embeddedClass) + .hasSize(1); + softly + .assertThat(testcontainerClass) + .withFailMessage( + "Expected 1 testcontainer implementation of %s, but found %d: %s", + className, embeddedClass.size(), embeddedClass) + .hasSize(1); softly.assertAll(); } - private void assertExtendingClass( - final Class abstractClass, - final List> classes, - final String classPackage, - final Class annotation, - final SoftAssertions softly) { - final Optional> clazzOptional = - classes.stream().filter(abstractClass::isAssignableFrom).findFirst(); - softly - .assertThat(clazzOptional) - .withFailMessage( - "Package %s.%s does not contain a class extending %s", - BASE_PACKAGE, classPackage, abstractClass) - .isNotEmpty(); - clazzOptional.ifPresent(clazz -> softly.assertThat(clazz).hasAnnotation(annotation)); + private static Stream provideAbstractClasses() { + return new ClassGraph() + .acceptPackages(ABSTRACT_PACKAGE) + .scan() + .getAllStandardClasses() + .filter(ClassInfo::isAbstract) + .filter(info -> !info.isInnerClass()) + .stream() + .map(info -> Arguments.of(info.getSimpleName(), info.loadClass())); } }