diff --git a/allure-java-commons/src/main/java/io/qameta/allure/util/ResultsUtils.java b/allure-java-commons/src/main/java/io/qameta/allure/util/ResultsUtils.java index 2704eac5f..e4f2f6a3b 100644 --- a/allure-java-commons/src/main/java/io/qameta/allure/util/ResultsUtils.java +++ b/allure-java-commons/src/main/java/io/qameta/allure/util/ResultsUtils.java @@ -348,7 +348,10 @@ public static List createTitlePath(final Collection values) { */ public static List createTitlePathFromPackageAndClass(final String packageName, final String className) { final List result = createTitlePathFromPackage(packageName); - getClassTitle(packageName, className).ifPresent(result::add); + if (result.isEmpty()) { + return createTitlePathFromQualifiedClassName(className); + } + getClassTitle(String.join(DOT, result), className).ifPresent(result::add); return result; } @@ -991,14 +994,18 @@ private static Optional getPackageName(final String className) { } private static Optional getClassTitle(final String packageName, final String className) { - if (Objects.isNull(className) || className.isEmpty()) { + if (Objects.isNull(className)) { + return Optional.empty(); + } + final String trimmedClassName = className.trim(); + if (trimmedClassName.isEmpty()) { return Optional.empty(); } final String prefix = packageName + DOT; - if (!packageName.isEmpty() && className.startsWith(prefix)) { - return Optional.of(className.substring(prefix.length())); + if (!packageName.isEmpty() && trimmedClassName.startsWith(prefix)) { + return Optional.of(trimmedClassName.substring(prefix.length())); } - return Optional.of(className); + return Optional.of(trimmedClassName); } private static List split(final String value, final String delimiter) { diff --git a/allure-java-commons/src/test/java/io/qameta/allure/ResultsUtilsTest.java b/allure-java-commons/src/test/java/io/qameta/allure/ResultsUtilsTest.java index b42278ac6..f7ee2eb91 100644 --- a/allure-java-commons/src/test/java/io/qameta/allure/ResultsUtilsTest.java +++ b/allure-java-commons/src/test/java/io/qameta/allure/ResultsUtilsTest.java @@ -29,15 +29,18 @@ import java.io.Serializable; import java.lang.annotation.Annotation; +import java.util.List; import java.util.Objects; import java.util.function.Function; import java.util.stream.Stream; +import static io.qameta.allure.Allure.step; import static io.qameta.allure.util.ResultsUtils.ISSUE_LINK_TYPE; import static io.qameta.allure.util.ResultsUtils.TMS_LINK_TYPE; import static io.qameta.allure.util.ResultsUtils.createIssueLink; import static io.qameta.allure.util.ResultsUtils.createLink; import static io.qameta.allure.util.ResultsUtils.createTitlePath; +import static io.qameta.allure.util.ResultsUtils.createTitlePathFromPackageAndClass; import static io.qameta.allure.util.ResultsUtils.createTitlePathFromQualifiedClassName; import static io.qameta.allure.util.ResultsUtils.createTitlePathFromSourcePath; import static io.qameta.allure.util.ResultsUtils.createTmsLink; @@ -58,6 +61,89 @@ void shouldCreateTitlePathFromQualifiedClassName() { .containsExactly("io", "qameta", "allure", "samples", "MyTest"); } + @ParameterizedTest(name = "{0}") + @MethodSource("packageAndClassTitlePathData") + void shouldCreateTitlePathFromPackageAndClass(final String scenario, + final String packageName, + final String className, + final List expected) { + step("Verify " + scenario, () -> { + assertThat(createTitlePathFromPackageAndClass(packageName, className)) + .containsExactlyElementsOf(expected); + }); + } + + static Stream packageAndClassTitlePathData() { + return Stream.of( + Arguments.of( + "null package and null class produce an empty title path", + null, + null, + List.of() + ), + Arguments.of( + "blank package and blank class produce an empty title path", + " ", + " ", + List.of() + ), + Arguments.of( + "empty package preserves a simple class name", + "", + "MyTest", + List.of("MyTest") + ), + Arguments.of( + "empty package splits a qualified name into segments", + "", + "io.qameta.allure", + List.of("io", "qameta", "allure") + ), + Arguments.of( + "null package splits a qualified class name into package and class segments", + null, + "io.qameta.allure.samples.MyTest", + List.of("io", "qameta", "allure", "samples", "MyTest") + ), + Arguments.of( + "package and null class produce package segments only", + "io.qameta.allure.samples", + null, + List.of("io", "qameta", "allure", "samples") + ), + Arguments.of( + "package and blank class produce package segments only", + "io.qameta.allure.samples", + " ", + List.of("io", "qameta", "allure", "samples") + ), + Arguments.of( + "package and simple class append the class segment", + "io.qameta.allure.samples", + "MyTest", + List.of("io", "qameta", "allure", "samples", "MyTest") + ), + Arguments.of( + "package and qualified class avoid duplicating package segments", + "io.qameta.allure.samples", + "io.qameta.allure.samples.MyTest", + List.of("io", "qameta", "allure", "samples", "MyTest") + ), + Arguments.of( + "package and class names are trimmed", + " io . qameta . allure . samples ", + " io.qameta.allure.samples.MyTest ", + List.of("io", "qameta", "allure", "samples", "MyTest") + ), + Arguments.of( + "empty package segments are ignored", + "io..qameta.allure.", + "MyTest", + List.of("io", "qameta", "allure", "MyTest") + ) + ); + } + @Test void shouldCreateTitlePathFromSourcePath() { assertThat(createTitlePathFromSourcePath("features/nested/my.test.feature")) diff --git a/allurerc.mjs b/allurerc.mjs index cb9002702..8f37bad0c 100644 --- a/allurerc.mjs +++ b/allurerc.mjs @@ -12,7 +12,8 @@ export default { plugins: { awesome: { options: { - groupBy: ["module", "parentSuite", "suite", "subSuite"], + groupBy: ["module"], + appendTitlePath: true, publish: true, }, },