diff --git a/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteTestDescriptor.java b/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteTestDescriptor.java index 0edf9c1eefbe..1b00b886b823 100644 --- a/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteTestDescriptor.java +++ b/junit-platform-suite-engine/src/main/java/org/junit/platform/suite/engine/SuiteTestDescriptor.java @@ -80,7 +80,7 @@ final class SuiteTestDescriptor extends AbstractTestDescriptor { SuiteTestDescriptor(UniqueId id, Class suiteClass, ConfigurationParameters configurationParameters, OutputDirectoryProvider outputDirectoryProvider, EngineDiscoveryListener discoveryListener, DiscoveryIssueReporter issueReporter) { - super(id, getSuiteDisplayName(suiteClass), ClassSource.from(suiteClass)); + super(id, getSuiteDisplayName(suiteClass, issueReporter), ClassSource.from(suiteClass)); this.configurationParameters = configurationParameters; this.outputDirectoryProvider = outputDirectoryProvider; this.failIfNoTests = getFailIfNoTests(suiteClass); @@ -140,12 +140,20 @@ public Type getType() { return Type.CONTAINER; } - private static String getSuiteDisplayName(Class testClass) { + private static String getSuiteDisplayName(Class suiteClass, DiscoveryIssueReporter issueReporter) { // @formatter:off - return findAnnotation(testClass, SuiteDisplayName.class) + var nonBlank = issueReporter.createReportingCondition(StringUtils::isNotBlank, __ -> { + String message = "@SuiteDisplayName on %s must be declared with a non-blank value.".formatted( + suiteClass.getName()); + return DiscoveryIssue.builder(DiscoveryIssue.Severity.WARNING, message) + .source(ClassSource.from(suiteClass)) + .build(); + }).toPredicate(); + + return findAnnotation(suiteClass, SuiteDisplayName.class) .map(SuiteDisplayName::value) - .filter(StringUtils::isNotBlank) - .orElse(testClass.getSimpleName()); + .filter(nonBlank) + .orElse(suiteClass.getSimpleName()); // @formatter:on } diff --git a/platform-tests/src/test/java/org/junit/platform/suite/engine/SuiteEngineTests.java b/platform-tests/src/test/java/org/junit/platform/suite/engine/SuiteEngineTests.java index 12cb46e6d928..a3bcf91afd94 100644 --- a/platform-tests/src/test/java/org/junit/platform/suite/engine/SuiteEngineTests.java +++ b/platform-tests/src/test/java/org/junit/platform/suite/engine/SuiteEngineTests.java @@ -68,6 +68,7 @@ import org.junit.platform.suite.engine.testcases.SingleTestTestCase; import org.junit.platform.suite.engine.testcases.TaggedTestTestCase; import org.junit.platform.suite.engine.testsuites.AbstractSuite; +import org.junit.platform.suite.engine.testsuites.BlankSuiteDisplayNameSuite; import org.junit.platform.suite.engine.testsuites.ConfigurationSuite; import org.junit.platform.suite.engine.testsuites.CyclicSuite; import org.junit.platform.suite.engine.testsuites.DynamicSuite; @@ -88,6 +89,7 @@ import org.junit.platform.suite.engine.testsuites.SuiteSuite; import org.junit.platform.suite.engine.testsuites.SuiteWithErroneousTestSuite; import org.junit.platform.suite.engine.testsuites.ThreePartCyclicSuite; +import org.junit.platform.suite.engine.testsuites.WhitespaceSuiteDisplayNameSuite; import org.junit.platform.testkit.engine.EngineTestKit; /** @@ -705,6 +707,38 @@ void reportsChildrenOfEnginesInSuiteAsSkippedWhenCancelledDuringExecution() { } } + @Test + void blankSuiteDisplayNameGeneratesWarning() { + var expectedMessage = "@SuiteDisplayName on %s must be declared with a non-blank value.".formatted( + BlankSuiteDisplayNameSuite.class.getName()); + var expectedIssue = DiscoveryIssue.builder(Severity.WARNING, expectedMessage).source( + ClassSource.from(BlankSuiteDisplayNameSuite.class)).build(); + + var testKit = EngineTestKit.engine(ENGINE_ID).selectors(selectClass(BlankSuiteDisplayNameSuite.class)); + + assertThat(testKit.discover().getDiscoveryIssues()).contains(expectedIssue); + } + + @Test + void whitespaceSuiteDisplayNameGeneratesWarning() { + var expectedMessage = "@SuiteDisplayName on %s must be declared with a non-blank value.".formatted( + WhitespaceSuiteDisplayNameSuite.class.getName()); + var expectedIssue = DiscoveryIssue.builder(Severity.WARNING, expectedMessage).source( + ClassSource.from(WhitespaceSuiteDisplayNameSuite.class)).build(); + + var testKit = EngineTestKit.engine(ENGINE_ID).selectors(selectClass(WhitespaceSuiteDisplayNameSuite.class)); + + assertThat(testKit.discover().getDiscoveryIssues()).contains(expectedIssue); + } + + @Test + void validSuiteDisplayNameGeneratesNoWarning() { + var testKit = EngineTestKit.engine(ENGINE_ID).selectors(selectClass(SuiteDisplayNameSuite.class)); + + assertThat(testKit.discover().getDiscoveryIssues()) // + .noneMatch(issue -> issue.message().contains("@SuiteDisplayName")); + } + // ----------------------------------------------------------------------------------------------------------------- static class CancellingSuite extends SelectClassesSuite { diff --git a/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/BlankSuiteDisplayNameSuite.java b/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/BlankSuiteDisplayNameSuite.java new file mode 100644 index 000000000000..65a6ae3c67de --- /dev/null +++ b/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/BlankSuiteDisplayNameSuite.java @@ -0,0 +1,27 @@ +/* + * 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.platform.suite.engine.testsuites; + +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite; +import org.junit.platform.suite.api.SuiteDisplayName; +import org.junit.platform.suite.engine.testcases.SingleTestTestCase; + +/** + * Test suite with blank @SuiteDisplayName to verify validation. + * + * @since 6.0 + */ +@Suite +@SelectClasses(SingleTestTestCase.class) +@SuiteDisplayName("") +public class BlankSuiteDisplayNameSuite { +} diff --git a/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/WhitespaceSuiteDisplayNameSuite.java b/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/WhitespaceSuiteDisplayNameSuite.java new file mode 100644 index 000000000000..4bfc36a1eac1 --- /dev/null +++ b/platform-tests/src/test/java/org/junit/platform/suite/engine/testsuites/WhitespaceSuiteDisplayNameSuite.java @@ -0,0 +1,27 @@ +/* + * 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.platform.suite.engine.testsuites; + +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite; +import org.junit.platform.suite.api.SuiteDisplayName; +import org.junit.platform.suite.engine.testcases.SingleTestTestCase; + +/** + * Test suite with whitespace-only @SuiteDisplayName to verify validation. + * + * @since 6.0 + */ +@Suite +@SelectClasses(SingleTestTestCase.class) +@SuiteDisplayName(" ") +public class WhitespaceSuiteDisplayNameSuite { +}