From 73506081c00319dd8932d19b0464aecf7cad1967 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Fri, 9 Jul 2021 13:39:54 +0200 Subject: [PATCH] Fix exception when ClassSelectors contain interfaces (#2) + Avoid computing the entire class hierarchy unnecessarily Fixes #1. --- .../testng/engine/TestAnnotationUtils.java | 32 +++++++++++++------ .../engine/DiscoveryIntegrationTests.java | 23 +++++++++++++ 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/junit/support/testng/engine/TestAnnotationUtils.java b/src/main/java/org/junit/support/testng/engine/TestAnnotationUtils.java index d22eefe..88bb487 100644 --- a/src/main/java/org/junit/support/testng/engine/TestAnnotationUtils.java +++ b/src/main/java/org/junit/support/testng/engine/TestAnnotationUtils.java @@ -10,13 +10,16 @@ package org.junit.support.testng.engine; +import static java.util.Spliterators.spliteratorUnknownSize; + import java.lang.reflect.Method; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; +import java.util.Iterator; import java.util.Objects; import java.util.Optional; +import java.util.Spliterator; import java.util.stream.Stream; +import java.util.stream.StreamSupport; import org.testng.ITestNGMethod; import org.testng.annotations.Test; @@ -74,16 +77,27 @@ static Stream collectGroups(Class testClass) { } private static Stream collectTestAnnotations(Class testClass) { - return getClassHierarchy(testClass).stream() // + return getClassHierarchy(testClass) // .map(clazz -> clazz.getAnnotation(Test.class)) // .filter(Objects::nonNull); } - private static List> getClassHierarchy(Class testClass) { - List> result = new ArrayList<>(); - for (Class clazz = testClass; clazz != Object.class; clazz = clazz.getSuperclass()) { - result.add(clazz); - } - return result; + private static Stream> getClassHierarchy(Class testClass) { + Iterator> iterator = new Iterator>() { + Class next = testClass; + + @Override + public boolean hasNext() { + return next != Object.class && next != null; + } + + @Override + public Class next() { + Class result = next; + next = next.getSuperclass(); + return result; + } + }; + return StreamSupport.stream(spliteratorUnknownSize(iterator, Spliterator.ORDERED), false); } } diff --git a/src/test/java/org/junit/support/testng/engine/DiscoveryIntegrationTests.java b/src/test/java/org/junit/support/testng/engine/DiscoveryIntegrationTests.java index c7842d1..59699c9 100644 --- a/src/test/java/org/junit/support/testng/engine/DiscoveryIntegrationTests.java +++ b/src/test/java/org/junit/support/testng/engine/DiscoveryIntegrationTests.java @@ -261,4 +261,27 @@ void ignoresIgnoredTests() { TestDescriptor methodDescriptor = getOnlyElement(classDescriptor.getChildren()); assertThat(methodDescriptor.getDisplayName()).isEqualTo("test"); } + + @ParameterizedTest + @ValueSource(classes = { InterfaceTestCase.class, AbstractTestCase.class, RecordTestCase.class, + EnumTestCase.class }) + void doesNotThrowExceptionWhenNonExecutableTypeOfClassIsSelected(Class testClass) { + var request = request().selectors(selectClass(testClass)).build(); + + var rootDescriptor = testEngine.discover(request, engineId); + + assertThat(rootDescriptor.getChildren()).isEmpty(); + } + + interface InterfaceTestCase { + } + + static abstract class AbstractTestCase { + } + + record RecordTestCase() { + } + + enum EnumTestCase { + } }