From 4b57c0f005271dcf9953edeb5089c77a0d86735e Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Fri, 24 Jan 2025 20:02:49 +0100 Subject: [PATCH 01/11] Add new methods to DisplayNameGenerator and call them with dummy values --- .../jupiter/api/DisplayNameGenerator.java | 109 +++++++++++++++--- .../engine/descriptor/DisplayNameUtils.java | 7 +- .../api/DisplayNameGenerationTests.java | 6 +- .../CustomDisplayNameGenerator.java | 6 +- .../descriptor/DisplayNameUtilsTests.java | 6 +- 5 files changed, 107 insertions(+), 27 deletions(-) diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java index 810d180e3da8..450caf240f04 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java @@ -10,11 +10,14 @@ package org.junit.jupiter.api; +import static org.apiguardian.api.API.Status.DEPRECATED; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.STABLE; import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; import static org.junit.platform.commons.support.ModifierSupport.isStatic; import java.lang.reflect.Method; +import java.util.List; import java.util.Optional; import java.util.function.Predicate; @@ -82,14 +85,64 @@ public interface DisplayNameGenerator { String generateDisplayNameForClass(Class testClass); /** - * Generate a display name for the given {@link Nested @Nested} inner test class. + * Generate a display name for the given {@link Nested @Nested} inner test + * class. * - *

If it returns {@code null}, the default display name generator will be used instead. + *

If it returns {@code null}, the default display name generator will be + * used instead. * * @param nestedClass the class to generate a name for; never {@code null} * @return the display name for the nested class; never blank + * @deprecated in favor of {@link #generateDisplayNameForNestedClass(List, Class)} + */ + @SuppressWarnings("DeprecatedIsStillUsed") + @API(status = DEPRECATED, since = "5.12") + @Deprecated + default String generateDisplayNameForNestedClass(@SuppressWarnings("unused") Class nestedClass) { + throw new UnsupportedOperationException( + "Implement generateDisplayNameForNestedClass(List>, Class) instead"); + } + + /** + * Generate a display name for the given {@link Nested @Nested} inner test + * class. + * + *

If it returns {@code null}, the default display name generator will be + * used instead. + * + * @param enclosingInstanceTypes the runtime types of the enclosing + * instances; never {@code null} + * @param nestedClass the class to generate a name for; never {@code null} + * @return the display name for the nested class; never blank + * @since 5.12 + */ + @API(status = EXPERIMENTAL, since = "5.12") + default String generateDisplayNameForNestedClass(List> enclosingInstanceTypes, Class nestedClass) { + return generateDisplayNameForNestedClass(nestedClass); + } + + /** + * Generate a display name for the given method. + * + *

If it returns {@code null}, the default display name generator will be used instead. + * + * @implNote The class instance supplied as {@code testClass} may differ from + * the class returned by {@code testMethod.getDeclaringClass()} — for + * example, when a test method is inherited from a superclass. + * + * @param testClass the class the test method is invoked on; never {@code null} + * @param testMethod method to generate a display name for; never {@code null} + * @return the display name for the test; never blank + * @deprecated in favor of {@link #generateDisplayNameForMethod(List, Class, Method)} */ - String generateDisplayNameForNestedClass(Class nestedClass); + @SuppressWarnings("DeprecatedIsStillUsed") + @API(status = DEPRECATED, since = "5.12") + @Deprecated + default String generateDisplayNameForMethod(@SuppressWarnings("unused") Class testClass, + @SuppressWarnings("unused") Method testMethod) { + throw new UnsupportedOperationException( + "Implement generateDisplayNameForMethod(List>, Class, Method) instead"); + } /** * Generate a display name for the given method. @@ -100,11 +153,18 @@ public interface DisplayNameGenerator { * the class returned by {@code testMethod.getDeclaringClass()} — for * example, when a test method is inherited from a superclass. * + * @param enclosingInstanceTypes the runtime types of the enclosing + * instances; never {@code null} * @param testClass the class the test method is invoked on; never {@code null} * @param testMethod method to generate a display name for; never {@code null} * @return the display name for the test; never blank + * @since 5.12 */ - String generateDisplayNameForMethod(Class testClass, Method testMethod); + @API(status = EXPERIMENTAL, since = "5.12") + default String generateDisplayNameForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { + return generateDisplayNameForMethod(testClass, testMethod); + } /** * Generate a string representation of the formal parameters of the supplied @@ -142,12 +202,13 @@ public String generateDisplayNameForClass(Class testClass) { } @Override - public String generateDisplayNameForNestedClass(Class nestedClass) { + public String generateDisplayNameForNestedClass(List> enclosingInstanceTypes, Class nestedClass) { return nestedClass.getSimpleName(); } @Override - public String generateDisplayNameForMethod(Class testClass, Method testMethod) { + public String generateDisplayNameForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { return testMethod.getName() + parameterTypesAsString(testMethod); } } @@ -168,7 +229,8 @@ public Simple() { } @Override - public String generateDisplayNameForMethod(Class testClass, Method testMethod) { + public String generateDisplayNameForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { String displayName = testMethod.getName(); if (hasParameters(testMethod)) { displayName += ' ' + parameterTypesAsString(testMethod); @@ -202,13 +264,15 @@ public String generateDisplayNameForClass(Class testClass) { } @Override - public String generateDisplayNameForNestedClass(Class nestedClass) { - return replaceUnderscores(super.generateDisplayNameForNestedClass(nestedClass)); + public String generateDisplayNameForNestedClass(List> enclosingInstanceTypes, Class nestedClass) { + return replaceUnderscores(super.generateDisplayNameForNestedClass(enclosingInstanceTypes, nestedClass)); } @Override - public String generateDisplayNameForMethod(Class testClass, Method testMethod) { - return replaceUnderscores(super.generateDisplayNameForMethod(testClass, testMethod)); + public String generateDisplayNameForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { + return replaceUnderscores( + super.generateDisplayNameForMethod(enclosingInstanceTypes, testClass, testMethod)); } private static String replaceUnderscores(String name) { @@ -243,17 +307,21 @@ public String generateDisplayNameForClass(Class testClass) { } @Override - public String generateDisplayNameForNestedClass(Class nestedClass) { - return getSentenceBeginning(nestedClass); + public String generateDisplayNameForNestedClass(List> enclosingInstanceTypes, Class nestedClass) { + return getSentenceBeginning(enclosingInstanceTypes, nestedClass); } @Override - public String generateDisplayNameForMethod(Class testClass, Method testMethod) { - return getSentenceBeginning(testClass) + getFragmentSeparator(testClass) - + getGeneratorFor(testClass).generateDisplayNameForMethod(testClass, testMethod); + public String generateDisplayNameForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { + // TODO Pass enclosingInstanceTypes to getSentenceBeginning() + return getSentenceBeginning(enclosingInstanceTypes, testClass) + getFragmentSeparator(testClass) + + getGeneratorFor(testClass).generateDisplayNameForMethod(enclosingInstanceTypes, testClass, + testMethod); } - private String getSentenceBeginning(Class testClass) { + private String getSentenceBeginning(List> enclosingInstanceTypes, Class testClass) { + // TODO Use last element of enclosingInstanceTypes and remove it for later calls Class enclosingClass = testClass.getEnclosingClass(); boolean topLevelTestClass = (enclosingClass == null || isStatic(testClass)); Optional displayName = findAnnotation(testClass, DisplayName.class)// @@ -280,10 +348,12 @@ private String getSentenceBeginning(Class testClass) { .filter(IndicativeSentences.class::equals)// .isPresent(); - String prefix = (buildPrefix ? getSentenceBeginning(enclosingClass) + getFragmentSeparator(testClass) : ""); + String prefix = (buildPrefix + ? getSentenceBeginning(enclosingInstanceTypes, enclosingClass) + getFragmentSeparator(testClass) + : ""); return prefix + displayName.orElseGet( - () -> getGeneratorFor(testClass).generateDisplayNameForNestedClass(testClass)); + () -> getGeneratorFor(testClass).generateDisplayNameForNestedClass(enclosingInstanceTypes, testClass)); } /** @@ -349,6 +419,7 @@ private static Optional findIndicativeSentencesGe SearchOption.INCLUDE_ENCLOSING_CLASSES); } + @SuppressWarnings("SameParameterValue") private static Predicate> not(Class clazz) { return ((Predicate>) clazz::equals).negate(); } diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DisplayNameUtils.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DisplayNameUtils.java index ebe3d127bf0c..71800b3a64c1 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DisplayNameUtils.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DisplayNameUtils.java @@ -10,6 +10,7 @@ package org.junit.jupiter.engine.descriptor; +import static java.util.Collections.emptyList; import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; import java.lang.reflect.AnnotatedElement; @@ -96,20 +97,22 @@ static String determineDisplayNameForMethod(Class testClass, Method testMetho } static Supplier createDisplayNameSupplierForClass(Class testClass, JupiterConfiguration configuration) { + // TODO Compute enclosing test classes return createDisplayNameSupplier(testClass, configuration, generator -> generator.generateDisplayNameForClass(testClass)); } static Supplier createDisplayNameSupplierForNestedClass(Class testClass, JupiterConfiguration configuration) { + // TODO Compute enclosing test classes return createDisplayNameSupplier(testClass, configuration, - generator -> generator.generateDisplayNameForNestedClass(testClass)); + generator -> generator.generateDisplayNameForNestedClass(emptyList(), testClass)); } private static Supplier createDisplayNameSupplierForMethod(Class testClass, Method testMethod, JupiterConfiguration configuration) { return createDisplayNameSupplier(testClass, configuration, - generator -> generator.generateDisplayNameForMethod(testClass, testMethod)); + generator -> generator.generateDisplayNameForMethod(emptyList(), testClass, testMethod)); } private static Supplier createDisplayNameSupplier(Class testClass, JupiterConfiguration configuration, diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/api/DisplayNameGenerationTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/api/DisplayNameGenerationTests.java index 8dbea0cdb42d..75127939ff50 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/api/DisplayNameGenerationTests.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/api/DisplayNameGenerationTests.java @@ -20,6 +20,7 @@ import java.lang.reflect.Method; import java.util.EmptyStackException; +import java.util.List; import java.util.Stack; import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; @@ -217,12 +218,13 @@ public String generateDisplayNameForClass(Class testClass) { } @Override - public String generateDisplayNameForNestedClass(Class nestedClass) { + public String generateDisplayNameForNestedClass(List> enclosingInstanceTypes, Class nestedClass) { return "nn"; } @Override - public String generateDisplayNameForMethod(Class testClass, Method testMethod) { + public String generateDisplayNameForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { return "nn"; } } diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/CustomDisplayNameGenerator.java b/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/CustomDisplayNameGenerator.java index f7b8afae102c..6b00ad5b9282 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/CustomDisplayNameGenerator.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/CustomDisplayNameGenerator.java @@ -11,6 +11,7 @@ package org.junit.jupiter.engine.descriptor; import java.lang.reflect.Method; +import java.util.List; import org.junit.jupiter.api.DisplayNameGenerator; @@ -22,12 +23,13 @@ public String generateDisplayNameForClass(Class testClass) { } @Override - public String generateDisplayNameForNestedClass(Class nestedClass) { + public String generateDisplayNameForNestedClass(List> enclosingInstanceTypes, Class nestedClass) { return "nested-class-display-name"; } @Override - public String generateDisplayNameForMethod(Class testClass, Method testMethod) { + public String generateDisplayNameForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { return "method-display-name"; } } diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/DisplayNameUtilsTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/DisplayNameUtilsTests.java index a5d019e1f95a..ddd477a43e82 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/DisplayNameUtilsTests.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/DisplayNameUtilsTests.java @@ -15,6 +15,7 @@ import static org.mockito.Mockito.when; import java.lang.reflect.Method; +import java.util.List; import java.util.function.Supplier; import java.util.logging.Level; import java.util.logging.LogRecord; @@ -238,12 +239,13 @@ public String generateDisplayNameForClass(Class testClass) { } @Override - public String generateDisplayNameForNestedClass(Class nestedClass) { + public String generateDisplayNameForNestedClass(List> enclosingInstanceTypes, Class nestedClass) { return null; } @Override - public String generateDisplayNameForMethod(Class testClass, Method testMethod) { + public String generateDisplayNameForMethod(List> enclosingInstanceTypes, Class testClass, + Method testMethod) { return null; } From 14110dc422f1dc63b60c4e2324f0b03ad0c8030f Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Fri, 24 Jan 2025 21:31:31 +0100 Subject: [PATCH 02/11] Determine and pass enclosing instance types Resolves #4130. --- .../jupiter/api/DisplayNameGenerator.java | 16 +++++---- .../engine/descriptor/DisplayNameUtils.java | 22 ++++++------- .../descriptor/MethodBasedTestDescriptor.java | 7 ++-- .../descriptor/NestedClassTestDescriptor.java | 13 ++++++-- .../descriptor/TestFactoryTestDescriptor.java | 5 +-- .../descriptor/TestMethodTestDescriptor.java | 6 ++-- .../TestTemplateTestDescriptor.java | 5 +-- .../discovery/ClassSelectorResolver.java | 7 ++-- .../discovery/MethodSelectorResolver.java | 26 ++++++++++----- .../api/DisplayNameGenerationTests.java | 17 ++++++++++ ...ntimeEnclosingTypeScenarioOneTestCase.java | 16 +++++++++ ...ntimeEnclosingTypeScenarioTwoTestCase.java | 16 +++++++++ ...SentencesRuntimeEnclosingTypeTestCase.java | 33 +++++++++++++++++++ .../parallel/ResourceLockAnnotationTests.java | 5 +-- .../descriptor/DisplayNameUtilsTests.java | 24 +++++++------- .../descriptor/ExtensionContextTests.java | 6 ++-- .../JupiterTestDescriptorTests.java | 24 +++++++------- .../TestFactoryTestDescriptorTests.java | 3 +- ...TemplateInvocationTestDescriptorTests.java | 3 +- .../TestTemplateTestDescriptorTests.java | 7 ++-- 20 files changed, 185 insertions(+), 76 deletions(-) create mode 100644 jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioOneTestCase.java create mode 100644 jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioTwoTestCase.java create mode 100644 jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeTestCase.java diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java index 450caf240f04..7140faa59b12 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java @@ -10,6 +10,7 @@ package org.junit.jupiter.api; +import static java.util.Collections.emptyList; import static org.apiguardian.api.API.Status.DEPRECATED; import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.STABLE; @@ -314,15 +315,14 @@ public String generateDisplayNameForNestedClass(List> enclosingInstance @Override public String generateDisplayNameForMethod(List> enclosingInstanceTypes, Class testClass, Method testMethod) { - // TODO Pass enclosingInstanceTypes to getSentenceBeginning() return getSentenceBeginning(enclosingInstanceTypes, testClass) + getFragmentSeparator(testClass) + getGeneratorFor(testClass).generateDisplayNameForMethod(enclosingInstanceTypes, testClass, testMethod); } private String getSentenceBeginning(List> enclosingInstanceTypes, Class testClass) { - // TODO Use last element of enclosingInstanceTypes and remove it for later calls - Class enclosingClass = testClass.getEnclosingClass(); + Class enclosingClass = enclosingInstanceTypes.isEmpty() ? null + : enclosingInstanceTypes.get(enclosingInstanceTypes.size() - 1); boolean topLevelTestClass = (enclosingClass == null || isStatic(testClass)); Optional displayName = findAnnotation(testClass, DisplayName.class)// .map(DisplayName::value).map(String::trim); @@ -348,12 +348,16 @@ private String getSentenceBeginning(List> enclosingInstanceTypes, Class .filter(IndicativeSentences.class::equals)// .isPresent(); + List> remainingEnclosingInstanceTypes = enclosingInstanceTypes.isEmpty() ? emptyList() + : enclosingInstanceTypes.subList(0, enclosingInstanceTypes.size() - 1); + String prefix = (buildPrefix - ? getSentenceBeginning(enclosingInstanceTypes, enclosingClass) + getFragmentSeparator(testClass) + ? getSentenceBeginning(remainingEnclosingInstanceTypes, enclosingClass) + + getFragmentSeparator(testClass) : ""); - return prefix + displayName.orElseGet( - () -> getGeneratorFor(testClass).generateDisplayNameForNestedClass(enclosingInstanceTypes, testClass)); + return prefix + displayName.orElseGet(() -> getGeneratorFor(testClass).generateDisplayNameForNestedClass( + remainingEnclosingInstanceTypes, testClass)); } /** diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DisplayNameUtils.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DisplayNameUtils.java index 71800b3a64c1..76b65ef5e49a 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DisplayNameUtils.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/DisplayNameUtils.java @@ -10,11 +10,11 @@ package org.junit.jupiter.engine.descriptor; -import static java.util.Collections.emptyList; import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; +import java.util.List; import java.util.Optional; import java.util.function.Function; import java.util.function.Supplier; @@ -90,29 +90,27 @@ static String determineDisplayName(AnnotatedElement element, Supplier di return displayNameSupplier.get(); } - static String determineDisplayNameForMethod(Class testClass, Method testMethod, - JupiterConfiguration configuration) { + static String determineDisplayNameForMethod(Supplier>> enclosingInstanceTypes, Class testClass, + Method testMethod, JupiterConfiguration configuration) { return determineDisplayName(testMethod, - createDisplayNameSupplierForMethod(testClass, testMethod, configuration)); + createDisplayNameSupplierForMethod(enclosingInstanceTypes, testClass, testMethod, configuration)); } static Supplier createDisplayNameSupplierForClass(Class testClass, JupiterConfiguration configuration) { - // TODO Compute enclosing test classes return createDisplayNameSupplier(testClass, configuration, generator -> generator.generateDisplayNameForClass(testClass)); } - static Supplier createDisplayNameSupplierForNestedClass(Class testClass, - JupiterConfiguration configuration) { - // TODO Compute enclosing test classes + static Supplier createDisplayNameSupplierForNestedClass(Supplier>> enclosingInstanceTypes, + Class testClass, JupiterConfiguration configuration) { return createDisplayNameSupplier(testClass, configuration, - generator -> generator.generateDisplayNameForNestedClass(emptyList(), testClass)); + generator -> generator.generateDisplayNameForNestedClass(enclosingInstanceTypes.get(), testClass)); } - private static Supplier createDisplayNameSupplierForMethod(Class testClass, Method testMethod, - JupiterConfiguration configuration) { + private static Supplier createDisplayNameSupplierForMethod(Supplier>> enclosingInstanceTypes, + Class testClass, Method testMethod, JupiterConfiguration configuration) { return createDisplayNameSupplier(testClass, configuration, - generator -> generator.generateDisplayNameForMethod(emptyList(), testClass, testMethod)); + generator -> generator.generateDisplayNameForMethod(enclosingInstanceTypes.get(), testClass, testMethod)); } private static Supplier createDisplayNameSupplier(Class testClass, JupiterConfiguration configuration, diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodBasedTestDescriptor.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodBasedTestDescriptor.java index 525b58293709..52bf3c4ef8b9 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodBasedTestDescriptor.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodBasedTestDescriptor.java @@ -21,6 +21,7 @@ import java.util.Optional; import java.util.Set; import java.util.function.Consumer; +import java.util.function.Supplier; import org.apiguardian.api.API; import org.junit.jupiter.api.extension.ExtensionContext; @@ -59,9 +60,9 @@ public abstract class MethodBasedTestDescriptor extends JupiterTestDescriptor im private final Set tags; MethodBasedTestDescriptor(UniqueId uniqueId, Class testClass, Method testMethod, - JupiterConfiguration configuration) { - this(uniqueId, determineDisplayNameForMethod(testClass, testMethod, configuration), testClass, testMethod, - configuration); + Supplier>> enclosingInstanceTypes, JupiterConfiguration configuration) { + this(uniqueId, determineDisplayNameForMethod(enclosingInstanceTypes, testClass, testMethod, configuration), + testClass, testMethod, configuration); } MethodBasedTestDescriptor(UniqueId uniqueId, String displayName, Class testClass, Method testMethod, diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/NestedClassTestDescriptor.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/NestedClassTestDescriptor.java index 6d4dc1e2d088..72d11ce5b09e 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/NestedClassTestDescriptor.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/NestedClassTestDescriptor.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.function.Supplier; import org.apiguardian.api.API; import org.junit.jupiter.api.extension.TestInstances; @@ -46,8 +47,10 @@ public class NestedClassTestDescriptor extends ClassBasedTestDescriptor { public static final String SEGMENT_TYPE = "nested-class"; - public NestedClassTestDescriptor(UniqueId uniqueId, Class testClass, JupiterConfiguration configuration) { - super(uniqueId, testClass, createDisplayNameSupplierForNestedClass(testClass, configuration), configuration); + public NestedClassTestDescriptor(UniqueId uniqueId, Class testClass, + Supplier>> enclosingInstanceTypes, JupiterConfiguration configuration) { + super(uniqueId, testClass, + createDisplayNameSupplierForNestedClass(enclosingInstanceTypes, testClass, configuration), configuration); } // --- TestDescriptor ------------------------------------------------------ @@ -62,7 +65,11 @@ public final Set getTags() { @Override public List> getEnclosingTestClasses() { - TestDescriptor parent = getParent().orElse(null); + return getEnclosingTestClasses(getParent().orElse(null)); + } + + @API(status = INTERNAL, since = "5.12") + public static List> getEnclosingTestClasses(TestDescriptor parent) { if (parent instanceof ClassBasedTestDescriptor) { ClassBasedTestDescriptor parentClassDescriptor = (ClassBasedTestDescriptor) parent; List> result = new ArrayList<>(parentClassDescriptor.getEnclosingTestClasses()); diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptor.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptor.java index e4643baa54de..f0d37814bbf2 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptor.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptor.java @@ -18,6 +18,7 @@ import java.lang.reflect.Method; import java.net.URI; import java.util.Iterator; +import java.util.List; import java.util.Optional; import java.util.function.Supplier; import java.util.stream.Stream; @@ -63,8 +64,8 @@ public class TestFactoryTestDescriptor extends TestMethodTestDescriptor implemen private final DynamicDescendantFilter dynamicDescendantFilter = new DynamicDescendantFilter(); public TestFactoryTestDescriptor(UniqueId uniqueId, Class testClass, Method testMethod, - JupiterConfiguration configuration) { - super(uniqueId, testClass, testMethod, configuration); + Supplier>> enclosingInstanceTypes, JupiterConfiguration configuration) { + super(uniqueId, testClass, testMethod, enclosingInstanceTypes, configuration); } // --- Filterable ---------------------------------------------------------- diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestMethodTestDescriptor.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestMethodTestDescriptor.java index 423f2e3b9013..67fa136a52d1 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestMethodTestDescriptor.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestMethodTestDescriptor.java @@ -17,6 +17,8 @@ import static org.junit.platform.commons.util.CollectionUtils.forEachInReverseOrder; import java.lang.reflect.Method; +import java.util.List; +import java.util.function.Supplier; import org.apiguardian.api.API; import org.junit.jupiter.api.TestInstance.Lifecycle; @@ -75,8 +77,8 @@ public class TestMethodTestDescriptor extends MethodBasedTestDescriptor { private final ReflectiveInterceptorCall interceptorCall; public TestMethodTestDescriptor(UniqueId uniqueId, Class testClass, Method testMethod, - JupiterConfiguration configuration) { - super(uniqueId, testClass, testMethod, configuration); + Supplier>> enclosingInstanceTypes, JupiterConfiguration configuration) { + super(uniqueId, testClass, testMethod, enclosingInstanceTypes, configuration); this.interceptorCall = defaultInterceptorCall; } diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptor.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptor.java index f89c17b26a32..e592ba3a6326 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptor.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptor.java @@ -18,6 +18,7 @@ import java.util.List; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; import java.util.stream.Stream; import org.apiguardian.api.API; @@ -46,8 +47,8 @@ public class TestTemplateTestDescriptor extends MethodBasedTestDescriptor implem private final DynamicDescendantFilter dynamicDescendantFilter = new DynamicDescendantFilter(); public TestTemplateTestDescriptor(UniqueId uniqueId, Class testClass, Method templateMethod, - JupiterConfiguration configuration) { - super(uniqueId, testClass, templateMethod, configuration); + Supplier>> enclosingInstanceTypes, JupiterConfiguration configuration) { + super(uniqueId, testClass, templateMethod, enclosingInstanceTypes, configuration); } // --- Filterable ---------------------------------------------------------- diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/ClassSelectorResolver.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/ClassSelectorResolver.java index 46d97088c358..0f809dcbde47 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/ClassSelectorResolver.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/ClassSelectorResolver.java @@ -12,6 +12,7 @@ import static java.util.function.Predicate.isEqual; import static java.util.stream.Collectors.toCollection; +import static org.junit.jupiter.engine.descriptor.NestedClassTestDescriptor.getEnclosingTestClasses; import static org.junit.jupiter.engine.discovery.predicates.IsTestClassWithTests.isTestOrTestFactoryOrTestTemplateMethod; import static org.junit.platform.commons.support.HierarchyTraversalMode.TOP_DOWN; import static org.junit.platform.commons.support.ReflectionSupport.findMethods; @@ -122,9 +123,9 @@ private ClassTestDescriptor newClassTestDescriptor(TestDescriptor parent, Class< } private NestedClassTestDescriptor newNestedClassTestDescriptor(TestDescriptor parent, Class testClass) { - return new NestedClassTestDescriptor( - parent.getUniqueId().append(NestedClassTestDescriptor.SEGMENT_TYPE, testClass.getSimpleName()), testClass, - configuration); + UniqueId uniqueId = parent.getUniqueId().append(NestedClassTestDescriptor.SEGMENT_TYPE, + testClass.getSimpleName()); + return new NestedClassTestDescriptor(uniqueId, testClass, () -> getEnclosingTestClasses(parent), configuration); } private Resolution toResolution(Optional testDescriptor) { diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodSelectorResolver.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodSelectorResolver.java index 7f76e2d30fce..9d5af96aa103 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodSelectorResolver.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodSelectorResolver.java @@ -166,8 +166,8 @@ private enum MethodType { TEST(new IsTestMethod(), TestMethodTestDescriptor.SEGMENT_TYPE) { @Override protected TestDescriptor createTestDescriptor(UniqueId uniqueId, Class testClass, Method method, - JupiterConfiguration configuration) { - return new TestMethodTestDescriptor(uniqueId, testClass, method, configuration); + Supplier>> enclosingInstanceTypes, JupiterConfiguration configuration) { + return new TestMethodTestDescriptor(uniqueId, testClass, method, enclosingInstanceTypes, configuration); } }, @@ -176,8 +176,9 @@ protected TestDescriptor createTestDescriptor(UniqueId uniqueId, Class testCl TestFactoryTestDescriptor.DYNAMIC_TEST_SEGMENT_TYPE) { @Override protected TestDescriptor createTestDescriptor(UniqueId uniqueId, Class testClass, Method method, - JupiterConfiguration configuration) { - return new TestFactoryTestDescriptor(uniqueId, testClass, method, configuration); + Supplier>> enclosingInstanceTypes, JupiterConfiguration configuration) { + return new TestFactoryTestDescriptor(uniqueId, testClass, method, enclosingInstanceTypes, + configuration); } }, @@ -185,8 +186,9 @@ protected TestDescriptor createTestDescriptor(UniqueId uniqueId, Class testCl TestTemplateInvocationTestDescriptor.SEGMENT_TYPE) { @Override protected TestDescriptor createTestDescriptor(UniqueId uniqueId, Class testClass, Method method, - JupiterConfiguration configuration) { - return new TestTemplateTestDescriptor(uniqueId, testClass, method, configuration); + Supplier>> enclosingInstanceTypes, JupiterConfiguration configuration) { + return new TestTemplateTestDescriptor(uniqueId, testClass, method, enclosingInstanceTypes, + configuration); } }; @@ -207,7 +209,7 @@ private Optional resolve(List> enclosingClasses, Class< } return context.addToParent(() -> selectClass(enclosingClasses, testClass), // parent -> Optional.of( - createTestDescriptor(createUniqueId(method, parent), testClass, method, configuration))); + createTestDescriptor((ClassBasedTestDescriptor) parent, testClass, method, configuration))); } private DiscoverySelector selectClass(List> enclosingClasses, Class testClass) { @@ -227,7 +229,7 @@ private Optional resolveUniqueIdIntoTestDescriptor(UniqueId uniq // @formatter:off return methodFinder.findMethod(methodSpecPart, testClass) .filter(methodPredicate) - .map(method -> createTestDescriptor(createUniqueId(method, parent), testClass, method, configuration)); + .map(method -> createTestDescriptor((ClassBasedTestDescriptor) parent, testClass, method, configuration)); // @formatter:on }); } @@ -237,6 +239,12 @@ private Optional resolveUniqueIdIntoTestDescriptor(UniqueId uniq return Optional.empty(); } + private TestDescriptor createTestDescriptor(ClassBasedTestDescriptor parent, Class testClass, Method method, + JupiterConfiguration configuration) { + UniqueId uniqueId = createUniqueId(method, parent); + return createTestDescriptor(uniqueId, testClass, method, parent::getEnclosingTestClasses, configuration); + } + private UniqueId createUniqueId(Method method, TestDescriptor parent) { String methodId = String.format("%s(%s)", method.getName(), ClassUtils.nullSafeToString(method.getParameterTypes())); @@ -244,7 +252,7 @@ private UniqueId createUniqueId(Method method, TestDescriptor parent) { } protected abstract TestDescriptor createTestDescriptor(UniqueId uniqueId, Class testClass, Method method, - JupiterConfiguration configuration); + Supplier>> enclosingInstanceTypes, JupiterConfiguration configuration); } diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/api/DisplayNameGenerationTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/api/DisplayNameGenerationTests.java index 75127939ff50..c7a1fe90efc6 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/api/DisplayNameGenerationTests.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/api/DisplayNameGenerationTests.java @@ -198,6 +198,23 @@ void indicativeSentencesGenerationInheritance() { ); } + @Test + void indicativeSentencesRuntimeEnclosingType() { + check(IndicativeSentencesRuntimeEnclosingTypeScenarioOneTestCase.class, // + "CONTAINER: Scenario 1", // + "CONTAINER: Scenario 1 -> Level 1", // + "CONTAINER: Scenario 1 -> Level 1 -> Level 2", // + "TEST: Scenario 1 -> Level 1 -> Level 2 -> this is a test"// + ); + + check(IndicativeSentencesRuntimeEnclosingTypeScenarioTwoTestCase.class, // + "CONTAINER: Scenario 2", // + "CONTAINER: Scenario 2 -> Level 1", // + "CONTAINER: Scenario 2 -> Level 1 -> Level 2", // + "TEST: Scenario 2 -> Level 1 -> Level 2 -> this is a test"// + ); + } + private void check(Class testClass, String... expectedDisplayNames) { var request = request().selectors(selectClass(testClass)).build(); var descriptors = discoverTests(request).getDescendants(); diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioOneTestCase.java b/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioOneTestCase.java new file mode 100644 index 000000000000..3657e82a2e65 --- /dev/null +++ b/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioOneTestCase.java @@ -0,0 +1,16 @@ +/* + * Copyright 2015-2025 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api; + +@DisplayName("Scenario 1") +class IndicativeSentencesRuntimeEnclosingTypeScenarioOneTestCase + extends IndicativeSentencesRuntimeEnclosingTypeTestCase { +} diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioTwoTestCase.java b/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioTwoTestCase.java new file mode 100644 index 000000000000..a2cebe5e02cd --- /dev/null +++ b/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioTwoTestCase.java @@ -0,0 +1,16 @@ +/* + * Copyright 2015-2025 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api; + +@DisplayName("Scenario 2") +class IndicativeSentencesRuntimeEnclosingTypeScenarioTwoTestCase + extends IndicativeSentencesRuntimeEnclosingTypeTestCase { +} diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeTestCase.java b/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeTestCase.java new file mode 100644 index 000000000000..c889b59278a0 --- /dev/null +++ b/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeTestCase.java @@ -0,0 +1,33 @@ +/* + * Copyright 2015-2025 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.jupiter.api; + +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; + +/** + * @since 5.8 + */ +@DisplayName("Base Scenario") +@IndicativeSentencesGeneration(separator = " -> ", generator = ReplaceUnderscores.class) +abstract class IndicativeSentencesRuntimeEnclosingTypeTestCase { + + @Nested + class Level_1 { + + @Nested + class Level_2 { + + @Test + void this_is_a_test() { + } + } + } +} diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/api/parallel/ResourceLockAnnotationTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/api/parallel/ResourceLockAnnotationTests.java index 2025c6e0ad49..b095a8d28e7c 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/api/parallel/ResourceLockAnnotationTests.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/api/parallel/ResourceLockAnnotationTests.java @@ -20,6 +20,7 @@ import static org.mockito.Mockito.when; import java.lang.reflect.Method; +import java.util.List; import java.util.Set; import java.util.stream.Stream; @@ -255,7 +256,7 @@ private ClassTestDescriptor getClassTestDescriptor(Class testClass) { private Set getMethodResources(Class testClass) { var descriptor = new TestMethodTestDescriptor( // - uniqueId, testClass, getDeclaredTestMethod(testClass), configuration // + uniqueId, testClass, getDeclaredTestMethod(testClass), List::of, configuration // ); descriptor.setParent(getClassTestDescriptor(testClass)); return descriptor.getExclusiveResources(); @@ -271,7 +272,7 @@ private static Method getDeclaredTestMethod(Class testClass) { } private Set getNestedClassResources(Class testClass) { - var descriptor = new NestedClassTestDescriptor(uniqueId, testClass, configuration); + var descriptor = new NestedClassTestDescriptor(uniqueId, testClass, List::of, configuration); descriptor.setParent(getClassTestDescriptor(testClass.getEnclosingClass())); return descriptor.getExclusiveResources(); } diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/DisplayNameUtilsTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/DisplayNameUtilsTests.java index ddd477a43e82..7a9ca9a4a165 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/DisplayNameUtilsTests.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/DisplayNameUtilsTests.java @@ -71,7 +71,7 @@ void shouldGetDisplayNameFromSupplierIfNoDisplayNameAnnotationPresent() { @Nested class ClassDisplayNameSupplierTests { - private JupiterConfiguration configuration = mock(); + private final JupiterConfiguration configuration = mock(); @Test void shouldGetDisplayNameFromDisplayNameGenerationAnnotation() { @@ -116,12 +116,12 @@ void shouldFallbackOnDefaultDisplayNameGeneratorWhenNullIsGenerated() { @Nested class NestedClassDisplayNameTests { - private JupiterConfiguration configuration = mock(); + private final JupiterConfiguration configuration = mock(); @Test void shouldGetDisplayNameFromDisplayNameGenerationAnnotation() { when(configuration.getDefaultDisplayNameGenerator()).thenReturn(new CustomDisplayNameGenerator()); - Supplier displayName = DisplayNameUtils.createDisplayNameSupplierForNestedClass( + Supplier displayName = DisplayNameUtils.createDisplayNameSupplierForNestedClass(List::of, StandardDisplayNameTestCase.class, configuration); assertThat(displayName.get()).isEqualTo(StandardDisplayNameTestCase.class.getSimpleName()); @@ -130,7 +130,7 @@ void shouldGetDisplayNameFromDisplayNameGenerationAnnotation() { @Test void shouldGetDisplayNameFromDefaultDisplayNameGenerator() { when(configuration.getDefaultDisplayNameGenerator()).thenReturn(new CustomDisplayNameGenerator()); - Supplier displayName = DisplayNameUtils.createDisplayNameSupplierForNestedClass( + Supplier displayName = DisplayNameUtils.createDisplayNameSupplierForNestedClass(List::of, NestedTestCase.class, configuration); assertThat(displayName.get()).isEqualTo("nested-class-display-name"); @@ -139,7 +139,7 @@ void shouldGetDisplayNameFromDefaultDisplayNameGenerator() { @Test void shouldFallbackOnDefaultDisplayNameGeneratorWhenNullIsGenerated() { when(configuration.getDefaultDisplayNameGenerator()).thenReturn(new CustomDisplayNameGenerator()); - Supplier displayName = DisplayNameUtils.createDisplayNameSupplierForNestedClass( + Supplier displayName = DisplayNameUtils.createDisplayNameSupplierForNestedClass(List::of, NullDisplayNameTestCase.NestedTestCase.class, configuration); assertThat(displayName.get()).isEqualTo("nested-class-display-name"); @@ -149,14 +149,14 @@ void shouldFallbackOnDefaultDisplayNameGeneratorWhenNullIsGenerated() { @Nested class MethodDisplayNameTests { - private JupiterConfiguration configuration = mock(); + private final JupiterConfiguration configuration = mock(); @Test void shouldGetDisplayNameFromDisplayNameGenerationAnnotation() throws Exception { when(configuration.getDefaultDisplayNameGenerator()).thenReturn(new CustomDisplayNameGenerator()); Method method = MyTestCase.class.getDeclaredMethod("test1"); - String displayName = DisplayNameUtils.determineDisplayNameForMethod(StandardDisplayNameTestCase.class, - method, configuration); + String displayName = DisplayNameUtils.determineDisplayNameForMethod(List::of, + StandardDisplayNameTestCase.class, method, configuration); assertThat(displayName).isEqualTo("test1()"); } @@ -166,8 +166,8 @@ void shouldGetDisplayNameFromDefaultNameGenerator() throws Exception { Method method = MyTestCase.class.getDeclaredMethod("test1"); when(configuration.getDefaultDisplayNameGenerator()).thenReturn(new CustomDisplayNameGenerator()); - String displayName = DisplayNameUtils.determineDisplayNameForMethod(NotDisplayNameTestCase.class, method, - configuration); + String displayName = DisplayNameUtils.determineDisplayNameForMethod(List::of, NotDisplayNameTestCase.class, + method, configuration); assertThat(displayName).isEqualTo("method-display-name"); } @@ -177,8 +177,8 @@ void shouldFallbackOnDefaultDisplayNameGeneratorWhenNullIsGenerated() throws Exc Method method = NullDisplayNameTestCase.class.getDeclaredMethod("test"); when(configuration.getDefaultDisplayNameGenerator()).thenReturn(new CustomDisplayNameGenerator()); - String displayName = DisplayNameUtils.determineDisplayNameForMethod(NullDisplayNameTestCase.class, method, - configuration); + String displayName = DisplayNameUtils.determineDisplayNameForMethod(List::of, NullDisplayNameTestCase.class, + method, configuration); assertThat(displayName).isEqualTo("method-display-name"); } diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/ExtensionContextTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/ExtensionContextTests.java index 482290a3c559..66796f302620 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/ExtensionContextTests.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/ExtensionContextTests.java @@ -418,7 +418,7 @@ void configurationParameter(Function { var method = ReflectionSupport.findMethod(testClass, "extensionContextFactories").orElseThrow(); var methodUniqueId = UniqueId.parse("[engine:junit-jupiter]/[class:MyClass]/[method:myMethod]"); - var methodTestDescriptor = new TestMethodTestDescriptor(methodUniqueId, testClass, method, + var methodTestDescriptor = new TestMethodTestDescriptor(methodUniqueId, testClass, method, List::of, configuration); return new MethodExtensionContext(null, null, methodTestDescriptor, configuration, extensionRegistry, null); @@ -428,7 +428,7 @@ void configurationParameter(Function testClass = TestCase.class; Method testMethod = testClass.getDeclaredMethod("test"); - TestMethodTestDescriptor descriptor = new TestMethodTestDescriptor(uniqueId, testClass, testMethod, + TestMethodTestDescriptor descriptor = new TestMethodTestDescriptor(uniqueId, testClass, testMethod, List::of, configuration); assertEquals(uniqueId, descriptor.getUniqueId()); @@ -127,7 +127,7 @@ void constructFromMethodWithAnnotations() throws Exception { JupiterTestDescriptor classDescriptor = new ClassTestDescriptor(uniqueId, TestCase.class, configuration); Method testMethod = TestCase.class.getDeclaredMethod("foo"); TestMethodTestDescriptor methodDescriptor = new TestMethodTestDescriptor(uniqueId, TestCase.class, testMethod, - configuration); + List::of, configuration); classDescriptor.addChild(methodDescriptor); assertEquals(testMethod, methodDescriptor.getTestMethod()); @@ -143,7 +143,7 @@ void constructFromMethodWithAnnotations() throws Exception { void constructFromMethodWithCustomTestAnnotation() throws Exception { Method testMethod = TestCase.class.getDeclaredMethod("customTestAnnotation"); TestMethodTestDescriptor descriptor = new TestMethodTestDescriptor(uniqueId, TestCase.class, testMethod, - configuration); + List::of, configuration); assertEquals(testMethod, descriptor.getTestMethod()); assertEquals("custom name", descriptor.getDisplayName(), "display name:"); @@ -155,7 +155,7 @@ void constructFromMethodWithCustomTestAnnotation() throws Exception { void constructFromMethodWithParameters() throws Exception { Method testMethod = TestCase.class.getDeclaredMethod("test", String.class, BigDecimal.class); TestMethodTestDescriptor descriptor = new TestMethodTestDescriptor(uniqueId, TestCase.class, testMethod, - configuration); + List::of, configuration); assertEquals(testMethod, descriptor.getTestMethod()); assertEquals("test(String, BigDecimal)", descriptor.getDisplayName(), "display name"); @@ -166,7 +166,7 @@ void constructFromMethodWithParameters() throws Exception { void constructFromMethodWithPrimitiveArrayParameter() throws Exception { Method testMethod = TestCase.class.getDeclaredMethod("test", int[].class); TestMethodTestDescriptor descriptor = new TestMethodTestDescriptor(uniqueId, TestCase.class, testMethod, - configuration); + List::of, configuration); assertEquals(testMethod, descriptor.getTestMethod()); assertEquals("test(int[])", descriptor.getDisplayName(), "display name"); @@ -177,7 +177,7 @@ void constructFromMethodWithPrimitiveArrayParameter() throws Exception { void constructFromMethodWithObjectArrayParameter() throws Exception { Method testMethod = TestCase.class.getDeclaredMethod("test", String[].class); TestMethodTestDescriptor descriptor = new TestMethodTestDescriptor(uniqueId, TestCase.class, testMethod, - configuration); + List::of, configuration); assertEquals(testMethod, descriptor.getTestMethod()); assertEquals("test(String[])", descriptor.getDisplayName(), "display name"); @@ -188,7 +188,7 @@ void constructFromMethodWithObjectArrayParameter() throws Exception { void constructFromMethodWithMultidimensionalPrimitiveArrayParameter() throws Exception { Method testMethod = TestCase.class.getDeclaredMethod("test", int[][][][][].class); TestMethodTestDescriptor descriptor = new TestMethodTestDescriptor(uniqueId, TestCase.class, testMethod, - configuration); + List::of, configuration); assertEquals(testMethod, descriptor.getTestMethod()); assertEquals("test(int[][][][][])", descriptor.getDisplayName(), "display name"); @@ -199,7 +199,7 @@ void constructFromMethodWithMultidimensionalPrimitiveArrayParameter() throws Exc void constructFromMethodWithMultidimensionalObjectArrayParameter() throws Exception { Method testMethod = TestCase.class.getDeclaredMethod("test", String[][][][][].class); TestMethodTestDescriptor descriptor = new TestMethodTestDescriptor(uniqueId, TestCase.class, testMethod, - configuration); + List::of, configuration); assertEquals(testMethod, descriptor.getTestMethod()); assertEquals("test(String[][][][][])", descriptor.getDisplayName(), "display name"); @@ -210,7 +210,7 @@ void constructFromMethodWithMultidimensionalObjectArrayParameter() throws Except void constructFromInheritedMethod() throws Exception { Method testMethod = ConcreteTestCase.class.getMethod("theTest"); TestMethodTestDescriptor descriptor = new TestMethodTestDescriptor(uniqueId, ConcreteTestCase.class, testMethod, - configuration); + List::of, configuration); assertEquals(testMethod, descriptor.getTestMethod()); @@ -230,7 +230,7 @@ void shouldTakeCustomMethodNameDescriptorFromConfigurationIfPresent() { assertEquals("class-display-name", descriptor.getDisplayName()); assertEquals(getClass().getName(), descriptor.getLegacyReportingName()); - descriptor = new NestedClassTestDescriptor(uniqueId, NestedTestCase.class, configuration); + descriptor = new NestedClassTestDescriptor(uniqueId, NestedTestCase.class, List::of, configuration); assertEquals("nested-class-display-name", descriptor.getDisplayName()); assertEquals(NestedTestCase.class.getName(), descriptor.getLegacyReportingName()); @@ -249,7 +249,7 @@ void defaultDisplayNamesForTestClasses() { assertEquals(getClass().getSimpleName(), descriptor.getDisplayName()); assertEquals(getClass().getName(), descriptor.getLegacyReportingName()); - descriptor = new NestedClassTestDescriptor(uniqueId, NestedTestCase.class, configuration); + descriptor = new NestedClassTestDescriptor(uniqueId, NestedTestCase.class, List::of, configuration); assertEquals(NestedTestCase.class.getSimpleName(), descriptor.getDisplayName()); assertEquals(NestedTestCase.class.getName(), descriptor.getLegacyReportingName()); @@ -269,7 +269,7 @@ void enclosingClassesAreDerivedFromParent() { ClassBasedTestDescriptor parentDescriptor = new ClassTestDescriptor(uniqueId, StaticTestCase.class, configuration); ClassBasedTestDescriptor nestedDescriptor = new NestedClassTestDescriptor(uniqueId, NestedTestCase.class, - configuration); + List::of, configuration); assertThat(parentDescriptor.getEnclosingTestClasses()).isEmpty(); assertThat(nestedDescriptor.getEnclosingTestClasses()).isEmpty(); diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptorTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptorTests.java index 618d290870d2..6ad584b728df 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptorTests.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptorTests.java @@ -18,6 +18,7 @@ import java.io.File; import java.lang.reflect.Method; import java.net.URI; +import java.util.List; import java.util.Optional; import java.util.stream.Stream; @@ -147,7 +148,7 @@ void before() throws Exception { Method testMethod = CustomStreamTestCase.class.getDeclaredMethod("customStream"); descriptor = new TestFactoryTestDescriptor(UniqueId.forEngine("engine"), CustomStreamTestCase.class, - testMethod, jupiterConfiguration); + testMethod, List::of, jupiterConfiguration); when(extensionContext.getTestMethod()).thenReturn(Optional.of(testMethod)); } diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateInvocationTestDescriptorTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateInvocationTestDescriptorTests.java index 0491150abb57..65b2bf268688 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateInvocationTestDescriptorTests.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateInvocationTestDescriptorTests.java @@ -16,6 +16,7 @@ import static org.mockito.Mockito.when; import java.lang.reflect.Method; +import java.util.List; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; @@ -34,7 +35,7 @@ void invocationsDoNotDeclareExclusiveResources() throws Exception { JupiterConfiguration configuration = mock(); when(configuration.getDefaultDisplayNameGenerator()).thenReturn(new DisplayNameGenerator.Standard()); TestTemplateTestDescriptor parent = new TestTemplateTestDescriptor(UniqueId.root("segment", "template"), - testClass, testTemplateMethod, configuration); + testClass, testTemplateMethod, List::of, configuration); TestTemplateInvocationContext invocationContext = mock(); when(invocationContext.getDisplayName(anyInt())).thenReturn("invocation"); diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptorTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptorTests.java index 1cd492db23ce..c0dab4d6a66e 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptorTests.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptorTests.java @@ -15,6 +15,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import java.util.List; import java.util.Set; import org.junit.jupiter.api.DisplayNameGenerator; @@ -45,7 +46,7 @@ void inheritsTagsFromParent() throws Exception { TestTemplateTestDescriptor testDescriptor = new TestTemplateTestDescriptor( parentUniqueId.append("tmp", "testTemplate()"), MyTestCase.class, - MyTestCase.class.getDeclaredMethod("testTemplate"), jupiterConfiguration); + MyTestCase.class.getDeclaredMethod("testTemplate"), List::of, jupiterConfiguration); parent.addChild(testDescriptor); assertThat(testDescriptor.getTags()).containsExactlyInAnyOrder(TestTag.create("foo"), TestTag.create("bar"), @@ -63,7 +64,7 @@ void shouldUseCustomDisplayNameGeneratorIfPresentFromConfiguration() throws Exce TestTemplateTestDescriptor testDescriptor = new TestTemplateTestDescriptor( parentUniqueId.append("tmp", "testTemplate()"), MyTestCase.class, - MyTestCase.class.getDeclaredMethod("testTemplate"), jupiterConfiguration); + MyTestCase.class.getDeclaredMethod("testTemplate"), List::of, jupiterConfiguration); parent.addChild(testDescriptor); assertThat(testDescriptor.getDisplayName()).isEqualTo("method-display-name"); @@ -80,7 +81,7 @@ void shouldUseStandardDisplayNameGeneratorIfConfigurationNotPresent() throws Exc TestTemplateTestDescriptor testDescriptor = new TestTemplateTestDescriptor( parentUniqueId.append("tmp", "testTemplate()"), MyTestCase.class, - MyTestCase.class.getDeclaredMethod("testTemplate"), jupiterConfiguration); + MyTestCase.class.getDeclaredMethod("testTemplate"), List::of, jupiterConfiguration); parent.addChild(testDescriptor); assertThat(testDescriptor.getDisplayName()).isEqualTo("testTemplate()"); From 90f96dc43c949b57301a9eb8e37673e8235e21e6 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sat, 25 Jan 2025 12:48:28 +0100 Subject: [PATCH 03/11] Add entry to release notes --- .../docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc index 5d6ceaea5dc0..9592ec0e5932 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc @@ -83,7 +83,10 @@ JUnit repository on GitHub. [[release-notes-5.12.0-M1-junit-jupiter-bug-fixes]] ==== Bug Fixes -* ❓ +* Provide _runtime_ enclosing types of `@Nested` test classes and contained test methods + to `DisplayNameGenerator` implementations. Prior to this change, such generators were + only able to access the enclosing class in which `@Nested` was declared, but they could + not access the concrete type of the enclosing instance. [[release-notes-5.12.0-M1-junit-jupiter-deprecations-and-breaking-changes]] ==== Deprecations and Breaking Changes From fa9ffb0f2fc41cbe95ee584f35d956ec05dd9005 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sat, 25 Jan 2025 18:08:01 +0100 Subject: [PATCH 04/11] Fix/add since annotations to test cases --- ...cativeSentencesRuntimeEnclosingTypeScenarioOneTestCase.java | 3 +++ ...cativeSentencesRuntimeEnclosingTypeScenarioTwoTestCase.java | 3 +++ .../api/IndicativeSentencesRuntimeEnclosingTypeTestCase.java | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioOneTestCase.java b/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioOneTestCase.java index 3657e82a2e65..927903c14612 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioOneTestCase.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioOneTestCase.java @@ -10,6 +10,9 @@ package org.junit.jupiter.api; +/** + * @since 5.12 + */ @DisplayName("Scenario 1") class IndicativeSentencesRuntimeEnclosingTypeScenarioOneTestCase extends IndicativeSentencesRuntimeEnclosingTypeTestCase { diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioTwoTestCase.java b/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioTwoTestCase.java index a2cebe5e02cd..c6e2f377db10 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioTwoTestCase.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeScenarioTwoTestCase.java @@ -10,6 +10,9 @@ package org.junit.jupiter.api; +/** + * @since 5.12 + */ @DisplayName("Scenario 2") class IndicativeSentencesRuntimeEnclosingTypeScenarioTwoTestCase extends IndicativeSentencesRuntimeEnclosingTypeTestCase { diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeTestCase.java b/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeTestCase.java index c889b59278a0..86244f4cbfcc 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeTestCase.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/api/IndicativeSentencesRuntimeEnclosingTypeTestCase.java @@ -13,7 +13,7 @@ import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; /** - * @since 5.8 + * @since 5.12 */ @DisplayName("Base Scenario") @IndicativeSentencesGeneration(separator = " -> ", generator = ReplaceUnderscores.class) From f37d4e447387275e0cd90dc1229c947d3f0cfd7e Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sat, 25 Jan 2025 18:14:42 +0100 Subject: [PATCH 05/11] Polish Javadoc Co-authored-by: Sam Brannen <104798+sbrannen@users.noreply.github.com> --- .../docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc | 2 +- .../java/org/junit/jupiter/api/DisplayNameGenerator.java | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc index 9592ec0e5932..0abbde8c9af2 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc @@ -86,7 +86,7 @@ JUnit repository on GitHub. * Provide _runtime_ enclosing types of `@Nested` test classes and contained test methods to `DisplayNameGenerator` implementations. Prior to this change, such generators were only able to access the enclosing class in which `@Nested` was declared, but they could - not access the concrete type of the enclosing instance. + not access the concrete runtime type of the enclosing instance. [[release-notes-5.12.0-M1-junit-jupiter-deprecations-and-breaking-changes]] ==== Deprecations and Breaking Changes diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java index 7140faa59b12..e1ab13567796 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java @@ -150,7 +150,10 @@ default String generateDisplayNameForMethod(@SuppressWarnings("unused") Class * *

If it returns {@code null}, the default display name generator will be used instead. * - * @implNote The class instance supplied as {@code testClass} may differ from + * @implNote The classes supplied as {@code enclosingInstanceTypes} may differ + * from the classes returned from invocations of {@link Class#getEnclosingClass()} + * — for example, when a nested test class is inherited from a superclass. + * Similarly, the class instance supplied as {@code testClass} may differ from * the class returned by {@code testMethod.getDeclaringClass()} — for * example, when a test method is inherited from a superclass. * From 939ec92b4251975e9744c779e7ad83642cdd493d Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sat, 25 Jan 2025 18:19:30 +0100 Subject: [PATCH 06/11] Remove IntelliJ-specific suppressions --- .../java/org/junit/jupiter/api/DisplayNameGenerator.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java index e1ab13567796..41fe488bb289 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java @@ -136,11 +136,9 @@ default String generateDisplayNameForNestedClass(List> enclosingInstanc * @return the display name for the test; never blank * @deprecated in favor of {@link #generateDisplayNameForMethod(List, Class, Method)} */ - @SuppressWarnings("DeprecatedIsStillUsed") @API(status = DEPRECATED, since = "5.12") @Deprecated - default String generateDisplayNameForMethod(@SuppressWarnings("unused") Class testClass, - @SuppressWarnings("unused") Method testMethod) { + default String generateDisplayNameForMethod(Class testClass, Method testMethod) { throw new UnsupportedOperationException( "Implement generateDisplayNameForMethod(List>, Class, Method) instead"); } @@ -426,7 +424,6 @@ private static Optional findIndicativeSentencesGe SearchOption.INCLUDE_ENCLOSING_CLASSES); } - @SuppressWarnings("SameParameterValue") private static Predicate> not(Class clazz) { return ((Predicate>) clazz::equals).negate(); } From 70dba48b29de9217bc60de8d65d092dfd9d13fb4 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sat, 25 Jan 2025 18:22:37 +0100 Subject: [PATCH 07/11] Use "this method" rather than "it" --- .../junit/jupiter/api/DisplayNameGenerator.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java index 41fe488bb289..b6e34253b98e 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java @@ -78,7 +78,8 @@ public interface DisplayNameGenerator { /** * Generate a display name for the given top-level or {@code static} nested test class. * - *

If it returns {@code null}, the default display name generator will be used instead. + *

If this method returns {@code null}, the default display name + * generator will be used instead. * * @param testClass the class to generate a name for; never {@code null} * @return the display name for the class; never blank @@ -89,8 +90,8 @@ public interface DisplayNameGenerator { * Generate a display name for the given {@link Nested @Nested} inner test * class. * - *

If it returns {@code null}, the default display name generator will be - * used instead. + *

If this method returns {@code null}, the default display name + * generator will be used instead. * * @param nestedClass the class to generate a name for; never {@code null} * @return the display name for the nested class; never blank @@ -108,8 +109,8 @@ default String generateDisplayNameForNestedClass(@SuppressWarnings("unused") Cla * Generate a display name for the given {@link Nested @Nested} inner test * class. * - *

If it returns {@code null}, the default display name generator will be - * used instead. + *

If this method returns {@code null}, the default display name + * generator will be used instead. * * @param enclosingInstanceTypes the runtime types of the enclosing * instances; never {@code null} @@ -125,7 +126,8 @@ default String generateDisplayNameForNestedClass(List> enclosingInstanc /** * Generate a display name for the given method. * - *

If it returns {@code null}, the default display name generator will be used instead. + *

If this method returns {@code null}, the default display name + * generator will be used instead. * * @implNote The class instance supplied as {@code testClass} may differ from * the class returned by {@code testMethod.getDeclaringClass()} — for @@ -146,7 +148,8 @@ default String generateDisplayNameForMethod(Class testClass, Method testMetho /** * Generate a display name for the given method. * - *

If it returns {@code null}, the default display name generator will be used instead. + *

If this method returns {@code null}, the default display name + * generator will be used instead. * * @implNote The classes supplied as {@code enclosingInstanceTypes} may differ * from the classes returned from invocations of {@link Class#getEnclosingClass()} From 346442e6783ffdbdadaef1764a8975d033a79fc2 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sat, 25 Jan 2025 18:27:41 +0100 Subject: [PATCH 08/11] Add implNote paragraphs --- .../jupiter/api/DisplayNameGenerator.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java index b6e34253b98e..1e1485a6bf61 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java @@ -112,6 +112,11 @@ default String generateDisplayNameForNestedClass(@SuppressWarnings("unused") Cla *

If this method returns {@code null}, the default display name * generator will be used instead. * + * @implNote The classes supplied as {@code enclosingInstanceTypes} may + * differ from the classes returned from invocations of + * {@link Class#getEnclosingClass()} — for example, when a nested test + * class is inherited from a superclass. + * * @param enclosingInstanceTypes the runtime types of the enclosing * instances; never {@code null} * @param nestedClass the class to generate a name for; never {@code null} @@ -151,12 +156,13 @@ default String generateDisplayNameForMethod(Class testClass, Method testMetho *

If this method returns {@code null}, the default display name * generator will be used instead. * - * @implNote The classes supplied as {@code enclosingInstanceTypes} may differ - * from the classes returned from invocations of {@link Class#getEnclosingClass()} - * — for example, when a nested test class is inherited from a superclass. - * Similarly, the class instance supplied as {@code testClass} may differ from - * the class returned by {@code testMethod.getDeclaringClass()} — for - * example, when a test method is inherited from a superclass. + * @implNote The classes supplied as {@code enclosingInstanceTypes} may + * differ from the classes returned from invocations of + * {@link Class#getEnclosingClass()} — for example, when a nested test + * class is inherited from a superclass. Similarly, the class instance + * supplied as {@code testClass} may differ from the class returned by + * {@code testMethod.getDeclaringClass()} — for example, when a test + * method is inherited from a superclass. * * @param enclosingInstanceTypes the runtime types of the enclosing * instances; never {@code null} From 100c3858458b47fe58d0b54aad01ef9971b2c57f Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sat, 25 Jan 2025 18:35:23 +0100 Subject: [PATCH 09/11] Document order and contents of enclosingInstanceTypes parameters --- .../java/org/junit/jupiter/api/DisplayNameGenerator.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java index 1e1485a6bf61..dce3c7856ae5 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java @@ -118,7 +118,8 @@ default String generateDisplayNameForNestedClass(@SuppressWarnings("unused") Cla * class is inherited from a superclass. * * @param enclosingInstanceTypes the runtime types of the enclosing - * instances; never {@code null} + * instances of {@code clazz}, ordered from outermost to innermost, + * excluding {@code class}; never {@code null} * @param nestedClass the class to generate a name for; never {@code null} * @return the display name for the nested class; never blank * @since 5.12 @@ -165,7 +166,8 @@ default String generateDisplayNameForMethod(Class testClass, Method testMetho * method is inherited from a superclass. * * @param enclosingInstanceTypes the runtime types of the enclosing - * instances; never {@code null} + * instances of {@code clazz}, ordered from outermost to innermost, + * excluding {@code class}; never {@code null} * @param testClass the class the test method is invoked on; never {@code null} * @param testMethod method to generate a display name for; never {@code null} * @return the display name for the test; never blank From 460bf0a19471482ca8fbac68bea2c884ec73a572 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sat, 25 Jan 2025 18:35:38 +0100 Subject: [PATCH 10/11] Remove more IDEA-specific warnings --- .../main/java/org/junit/jupiter/api/DisplayNameGenerator.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java index dce3c7856ae5..f7216746203b 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java @@ -97,10 +97,9 @@ public interface DisplayNameGenerator { * @return the display name for the nested class; never blank * @deprecated in favor of {@link #generateDisplayNameForNestedClass(List, Class)} */ - @SuppressWarnings("DeprecatedIsStillUsed") @API(status = DEPRECATED, since = "5.12") @Deprecated - default String generateDisplayNameForNestedClass(@SuppressWarnings("unused") Class nestedClass) { + default String generateDisplayNameForNestedClass(Class nestedClass) { throw new UnsupportedOperationException( "Implement generateDisplayNameForNestedClass(List>, Class) instead"); } From f9fe497d440f7c0f012c78d13370ade17b705474 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 26 Jan 2025 17:36:21 +0100 Subject: [PATCH 11/11] Improve Javadoc Co-authored-by: Sam Brannen <104798+sbrannen@users.noreply.github.com> --- .../java/org/junit/jupiter/api/DisplayNameGenerator.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java index f7216746203b..89f7784d8c57 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DisplayNameGenerator.java @@ -117,8 +117,8 @@ default String generateDisplayNameForNestedClass(Class nestedClass) { * class is inherited from a superclass. * * @param enclosingInstanceTypes the runtime types of the enclosing - * instances of {@code clazz}, ordered from outermost to innermost, - * excluding {@code class}; never {@code null} + * instances for the test class, ordered from outermost to innermost, + * excluding {@code nestedClass}; never {@code null} * @param nestedClass the class to generate a name for; never {@code null} * @return the display name for the nested class; never blank * @since 5.12 @@ -165,8 +165,8 @@ default String generateDisplayNameForMethod(Class testClass, Method testMetho * method is inherited from a superclass. * * @param enclosingInstanceTypes the runtime types of the enclosing - * instances of {@code clazz}, ordered from outermost to innermost, - * excluding {@code class}; never {@code null} + * instances for the test class, ordered from outermost to innermost, + * excluding {@code testClass}; never {@code null} * @param testClass the class the test method is invoked on; never {@code null} * @param testMethod method to generate a display name for; never {@code null} * @return the display name for the test; never blank