diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/DefaultMethodInterface.java b/integration-tests/main/src/test/java/io/quarkus/it/main/DefaultMethodInterface.java new file mode 100644 index 0000000000000..d360a3f85068a --- /dev/null +++ b/integration-tests/main/src/test/java/io/quarkus/it/main/DefaultMethodInterface.java @@ -0,0 +1,10 @@ +package io.quarkus.it.main; + +import org.junit.jupiter.api.Test; + +public interface DefaultMethodInterface { + + @Test + default void doTest() { + } +} diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/DefaultMethodTestCase.java b/integration-tests/main/src/test/java/io/quarkus/it/main/DefaultMethodTestCase.java new file mode 100644 index 0000000000000..ddfc4ce0533c7 --- /dev/null +++ b/integration-tests/main/src/test/java/io/quarkus/it/main/DefaultMethodTestCase.java @@ -0,0 +1,67 @@ +package io.quarkus.it.main; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +public class DefaultMethodTestCase implements DefaultMethodInterface { + + @Nested + class NestedTestClass implements DefaultMethodInterface { + } + + interface InnerTestInterface { + @Test + default void testInnerTestInterface() { + + } + } + + @Nested + class InnerTestInterfaceTest implements InnerTestInterface { + + } + + @Nested + class SomeTestInterfaceTest implements DefaultMethodInterface, InnerTestInterface { + + } + + interface NonTestInterface { + default void simpleMethod() { + + } + + void abstractMethod(); + } + + @Nested + class NonTestInterfaceTest implements NonTestInterface { + + @Override + public void abstractMethod() { + + } + } + + interface SuperTestInterface { + @Test + default void superTestMethod() { + + } + } + + interface ChildTestInterface extends SuperTestInterface { + @Test + default void childTestMethod() { + + } + } + + @Nested + class HierarchyTest implements ChildTestInterface { + + } +} diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java index ec56c02a6bd3e..7110a05cd2f2b 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java @@ -476,7 +476,7 @@ public void afterEach(ExtensionContext context) throws Exception { Method actualTestMethod = null; // go up the class hierarchy to fetch the proper test method - Class c = actualTestClass; + Class c = resolveDeclaringClass(originalTestMethod, actualTestClass); List> parameterTypesFromTccl = new ArrayList<>(originalParameterTypes.length); for (Class type : originalParameterTypes) { if (type.isPrimitive()) { @@ -487,14 +487,12 @@ public void afterEach(ExtensionContext context) throws Exception { } } Class[] parameterTypes = parameterTypesFromTccl.toArray(new Class[0]); - while (c != Object.class) { - try { + try { + if (c != null) { actualTestMethod = c.getDeclaredMethod(originalTestMethod.getName(), parameterTypes); - break; - } catch (NoSuchMethodException ignored) { - } - c = c.getSuperclass(); + } catch (NoSuchMethodException ignored) { + } if (actualTestMethod == null) { throw new RuntimeException("Could not find method " + originalTestMethod + " on test class"); @@ -932,32 +930,50 @@ private Object runExtensionMethod(ReflectiveInvocationContext invocation private Method determineTCCLExtensionMethod(Method originalMethod, Class c) throws ClassNotFoundException { + Class declaringClass = resolveDeclaringClass(originalMethod, c); + if (declaringClass == null) { + return null; + } + try { + Class[] originalParameterTypes = originalMethod.getParameterTypes(); + List> parameterTypesFromTccl = new ArrayList<>(originalParameterTypes.length); + for (Class type : originalParameterTypes) { + if (type.isPrimitive()) { + parameterTypesFromTccl.add(type); + } else { + parameterTypesFromTccl + .add(Class.forName(type.getName(), true, + Thread.currentThread().getContextClassLoader())); + } + } + return declaringClass.getDeclaredMethod(originalMethod.getName(), + parameterTypesFromTccl.toArray(new Class[0])); + } catch (NoSuchMethodException ignored) { - Method newMethod = null; - while (c != Object.class) { - if (c.getName().equals(originalMethod.getDeclaringClass().getName())) { - try { - Class[] originalParameterTypes = originalMethod.getParameterTypes(); - List> parameterTypesFromTccl = new ArrayList<>(originalParameterTypes.length); - for (Class type : originalParameterTypes) { - if (type.isPrimitive()) { - parameterTypesFromTccl.add(type); - } else { - parameterTypesFromTccl - .add(Class.forName(type.getName(), true, - Thread.currentThread().getContextClassLoader())); - } - } - newMethod = c.getDeclaredMethod(originalMethod.getName(), - parameterTypesFromTccl.toArray(new Class[0])); - break; - } catch (NoSuchMethodException ignored) { + } - } + return null; + } + + private Class resolveDeclaringClass(Method method, Class c) { + if (c == Object.class || c == null) { + return null; + } + + if (c.getName().equals(method.getDeclaringClass().getName())) { + return c; + } + Class declaringClass = resolveDeclaringClass(method, c.getSuperclass()); + if (declaringClass != null) { + return declaringClass; + } + for (Class anInterface : c.getInterfaces()) { + declaringClass = resolveDeclaringClass(method, anInterface); + if (declaringClass != null) { + return declaringClass; } - c = c.getSuperclass(); } - return newMethod; + return null; } @Override