This is an automated email from the ASF dual-hosted git repository.

olamy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git


The following commit(s) were added to refs/heads/master by this push:
     new fbff927de [Issue-3226] JUnit5Xml30StatelessReporter does not change 
class name in report (#3347)
fbff927de is described below

commit fbff927de16aa597d77e0128bfdd9727b58e2f2f
Author: Nils Christian Ehmke <[email protected]>
AuthorDate: Sun May 24 23:03:06 2026 +0200

    [Issue-3226] JUnit5Xml30StatelessReporter does not change class name in 
report (#3347)
    
    * Fix usePhrasedTestCaseClassName=false still using @DisplayName in XML 
classname attribute
    
    When phrasedClassName was false, the classname attribute in the XML report
    incorrectly used sourceText (the @DisplayName value) whenever it was 
non-null,
    making the flag effectively a no-op for classes annotated with @DisplayName.
    The false branch now consistently uses getSourceName(), matching the 
existing
    pattern for phrasedMethodName.
    
    Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
    
    * Closed the resources in StatelessXmlReporterTest.
    
    * Fixed the integration tests.
    
    * Replaced the original solution with a new field.
    
    ---------
    
    Co-authored-by: Claude Sonnet 4.6 <[email protected]>
---
 .../surefire/report/StatelessXmlReporter.java      |  2 +-
 .../plugin/surefire/report/WrappedReportEntry.java | 10 +++
 .../surefire/report/StatelessXmlReporterTest.java  | 77 +++++++++++++++++++---
 .../maven/surefire/api/report/ReportEntry.java     | 11 ++++
 .../surefire/api/report/SimpleReportEntry.java     | 34 ++++++++++
 .../surefire/junitplatform/RunListenerAdapter.java | 24 +++++--
 6 files changed, 141 insertions(+), 17 deletions(-)

diff --git 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java
 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java
index 20a577381..eb7554085 100644
--- 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java
+++ 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java
@@ -465,7 +465,7 @@ private void startTestElement(XMLWriter ppw, 
WrappedReportEntry report) throws I
 
         String className = phrasedClassName
                 ? report.getReportSourceName(reportNameSuffix)
-                : report.getSourceText() != null ? report.getSourceText() : 
report.getSourceName(reportNameSuffix);
+                : report.getSourceQualifiedName(reportNameSuffix);
         if (className != null) {
             ppw.addAttribute("classname", extraEscapeAttribute(className));
         }
diff --git 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java
 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java
index 4c5f7de21..ceb92b40e 100644
--- 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java
+++ 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java
@@ -181,6 +181,16 @@ String getSourceName(String suffix) {
         return isBlank(suffix) ? getSourceName() : getSourceName() + "(" + 
suffix + ")";
     }
 
+    String getSourceQualifiedName(String suffix) {
+        String qualifiedName = original.getSourceQualifiedName();
+        if (qualifiedName != null) {
+            return isBlank(suffix) ? qualifiedName : qualifiedName + "(" + 
suffix + ")";
+        }
+        // Fall back to pre-existing behaviour: sourceText if set, else 
sourceName (with suffix)
+        String sourceText = getSourceText();
+        return sourceText != null ? sourceText : getSourceName(suffix);
+    }
+
     String getReportName() {
         String name = getName();
         String nameText = getNameText();
diff --git 
a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporterTest.java
 
b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporterTest.java
index 7dadc62d0..994513339 100644
--- 
a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporterTest.java
+++ 
b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporterTest.java
@@ -29,6 +29,7 @@
 import java.nio.Buffer;
 import java.nio.ByteBuffer;
 import java.nio.file.Path;
+import java.util.Collections;
 import java.util.Deque;
 import java.util.HashMap;
 import java.util.concurrent.ConcurrentHashMap;
@@ -240,9 +241,11 @@ public void testAllFieldsSerialized() throws IOException {
                 false);
         reporter.testSetCompleted(testSetReportEntry, stats);
 
-        FileInputStream fileInputStream = new 
FileInputStream(expectedReportFile);
-
-        Xpp3Dom testSuite = Xpp3DomBuilder.build(new 
InputStreamReader(fileInputStream, UTF_8));
+        Xpp3Dom testSuite;
+        try (FileInputStream fileInputStream = new 
FileInputStream(expectedReportFile);
+                InputStreamReader reader = new 
InputStreamReader(fileInputStream, UTF_8)) {
+            testSuite = Xpp3DomBuilder.build(reader);
+        }
         assertEquals("testsuite", testSuite.getName());
         Xpp3Dom properties = testSuite.getChild("properties");
         assertEquals(System.getProperties().size(), 
properties.getChildCount());
@@ -353,9 +356,11 @@ public void testOutputRerunFlakyFailure() throws 
IOException {
         reporter.testSetCompleted(testSetReportEntry, stats);
         reporter.testSetCompleted(testSetReportEntry, rerunStats);
 
-        FileInputStream fileInputStream = new 
FileInputStream(expectedReportFile);
-
-        Xpp3Dom testSuite = Xpp3DomBuilder.build(new 
InputStreamReader(fileInputStream, UTF_8));
+        Xpp3Dom testSuite;
+        try (FileInputStream fileInputStream = new 
FileInputStream(expectedReportFile);
+                InputStreamReader reader = new 
InputStreamReader(fileInputStream, UTF_8)) {
+            testSuite = Xpp3DomBuilder.build(reader);
+        }
         assertEquals("testsuite", testSuite.getName());
         assertEquals("0.012", testSuite.getAttribute("time"));
         Xpp3Dom properties = testSuite.getChild("properties");
@@ -477,9 +482,11 @@ public void testOutputRerunFlakyAssumption() throws 
IOException {
         reporter.testSetCompleted(testSetReportEntry, stats);
         reporter.testSetCompleted(testSetReportEntry, rerunStats);
 
-        FileInputStream fileInputStream = new 
FileInputStream(expectedReportFile);
-
-        Xpp3Dom testSuite = Xpp3DomBuilder.build(new 
InputStreamReader(fileInputStream, UTF_8));
+        Xpp3Dom testSuite;
+        try (FileInputStream fileInputStream = new 
FileInputStream(expectedReportFile);
+                InputStreamReader reader = new 
InputStreamReader(fileInputStream, UTF_8)) {
+            testSuite = Xpp3DomBuilder.build(reader);
+        }
         assertEquals("testsuite", testSuite.getName());
         assertEquals("0.02", testSuite.getAttribute("time"));
 
@@ -654,6 +661,58 @@ public void 
testReporterHandlesATestWithoutMessageAndWithEmptyStackTrace() {
         reporter.testSetCompleted(testReport, stats);
     }
 
+    @Test
+    public void testClassnameUsesActualClassNameWhenPhrasedClassNameDisabled() 
throws IOException {
+        String actualClassName = "MyTest";
+        String displayName = "NewName";
+
+        ReportEntry reportEntry = new SimpleReportEntry(
+                NORMAL_RUN,
+                0L,
+                actualClassName,
+                displayName,
+                actualClassName,
+                TEST_ONE,
+                null,
+                null,
+                12,
+                null,
+                Collections.<String, String>emptyMap());
+        WrappedReportEntry testSetReportEntry =
+                new WrappedReportEntry(reportEntry, SUCCESS, 1771085631L, 12, 
null, null, systemProps());
+        expectedReportFile = new File(reportDir, "TEST-" + actualClassName + 
".xml");
+
+        stats.testSucceeded(testSetReportEntry);
+
+        StatelessXmlReporter reporter = new StatelessXmlReporter(
+                reportDir,
+                null,
+                false,
+                0,
+                new ConcurrentHashMap<>(),
+                XSD,
+                "3.0.2",
+                false,
+                false,
+                false, // phrasedClassName = false
+                false,
+                true,
+                true,
+                false);
+        reporter.testSetCompleted(testSetReportEntry, stats);
+
+        Xpp3Dom testSuite;
+        try (FileInputStream fileInputStream = new 
FileInputStream(expectedReportFile);
+                InputStreamReader reader = new 
InputStreamReader(fileInputStream, UTF_8)) {
+            testSuite = Xpp3DomBuilder.build(reader);
+        }
+        Xpp3Dom testcase = testSuite.getChildren("testcase")[0];
+        assertEquals(
+                actualClassName,
+                testcase.getAttribute("classname"),
+                "classname should be the actual class name, not the 
@DisplayName value");
+    }
+
     private boolean defaultCharsetSupportsSpecialChar() {
         // some charsets are not able to deal with \u0115 on both ways of the 
conversion
         return "\u0115\u00DC".equals(new String("\u0115\u00DC".getBytes()));
diff --git 
a/surefire-api/src/main/java/org/apache/maven/surefire/api/report/ReportEntry.java
 
b/surefire-api/src/main/java/org/apache/maven/surefire/api/report/ReportEntry.java
index cb08ae917..e1d5d272a 100644
--- 
a/surefire-api/src/main/java/org/apache/maven/surefire/api/report/ReportEntry.java
+++ 
b/surefire-api/src/main/java/org/apache/maven/surefire/api/report/ReportEntry.java
@@ -38,6 +38,17 @@ public interface ReportEntry {
      */
     String getSourceText();
 
+    /**
+     * The actual qualified Java class name of the test (e.g. including {@code 
$}-separated nested class names),
+     * independent of any display name. Returns {@code null} when the provider 
has not set this value, in which case
+     * consumers should fall back to {@link #getSourceText()} / {@link 
#getSourceName()}.
+     *
+     * @return qualified class name, or {@code null}
+     */
+    default String getSourceQualifiedName() {
+        return null;
+    }
+
     /**
      * The name of the test case.
      *
diff --git 
a/surefire-api/src/main/java/org/apache/maven/surefire/api/report/SimpleReportEntry.java
 
b/surefire-api/src/main/java/org/apache/maven/surefire/api/report/SimpleReportEntry.java
index 729ee9feb..f14d7f4ce 100644
--- 
a/surefire-api/src/main/java/org/apache/maven/surefire/api/report/SimpleReportEntry.java
+++ 
b/surefire-api/src/main/java/org/apache/maven/surefire/api/report/SimpleReportEntry.java
@@ -42,6 +42,8 @@ public class SimpleReportEntry implements TestSetReportEntry {
 
     private final String sourceText;
 
+    private final String sourceQualifiedName;
+
     private final String name;
 
     private final String nameText;
@@ -122,10 +124,37 @@ public SimpleReportEntry(
             Integer elapsed,
             String message,
             Map<String, String> systemProperties) {
+        this(
+                runMode,
+                testRunId,
+                source,
+                sourceText,
+                null,
+                name,
+                nameText,
+                stackTraceWriter,
+                elapsed,
+                message,
+                systemProperties);
+    }
+
+    public SimpleReportEntry(
+            @Nonnull RunMode runMode,
+            Long testRunId,
+            String source,
+            String sourceText,
+            String sourceQualifiedName,
+            String name,
+            String nameText,
+            StackTraceWriter stackTraceWriter,
+            Integer elapsed,
+            String message,
+            Map<String, String> systemProperties) {
         this.runMode = runMode;
         this.testRunId = testRunId;
         this.source = source;
         this.sourceText = sourceText;
+        this.sourceQualifiedName = sourceQualifiedName;
         this.name = name;
         this.nameText = nameText;
         this.stackTraceWriter = stackTraceWriter;
@@ -230,6 +259,11 @@ public String getSourceText() {
         return sourceText;
     }
 
+    @Override
+    public String getSourceQualifiedName() {
+        return sourceQualifiedName;
+    }
+
     @Override
     public String getName() {
         return name;
diff --git 
a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/RunListenerAdapter.java
 
b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/RunListenerAdapter.java
index 9c885e501..881a4a860 100644
--- 
a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/RunListenerAdapter.java
+++ 
b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/RunListenerAdapter.java
@@ -224,6 +224,7 @@ private SimpleReportEntry createReportEntry(
         ResultDisplay classMethodName = toClassMethodName(testIdentifier);
 
         String className = classMethodName.getClassName();
+        String qualifiedClassName = classMethodName.getQualifiedClassName();
 
         String classText = classMethodName.getDisplayName();
         if (Objects.equals(className, classText)) {
@@ -257,6 +258,7 @@ private SimpleReportEntry createReportEntry(
                 classMethodIndexer.indexClassMethod(className, methodName),
                 className,
                 classText,
+                qualifiedClassName,
                 methodName,
                 methodText,
                 stw,
@@ -395,8 +397,8 @@ private ResultDisplay toClassMethodName(TestIdentifier 
testIdentifier) {
                     .findFirst()
                     .map(this::toClassMethodName)
                     .map(s -> new ResultDisplay(
-                            s.getClassName(), s.getDisplayName(), null, null, 
s.getClassDisplayName()))
-                    .orElse(new ResultDisplay(realClassName, realClassName, 
null, null, classDisplayName));
+                            s.getClassName(), s.getDisplayName(), null, null, 
s.getClassDisplayName(), null))
+                    .orElse(new ResultDisplay(realClassName, realClassName, 
null, null, classDisplayName, null));
 
             String parentDisplay = 
collectAllTestIdentifiersInHierarchy(testIdentifier)
                     .filter(identifier -> identifier
@@ -444,7 +446,8 @@ private ResultDisplay toClassMethodName(TestIdentifier 
testIdentifier) {
                     source.getDisplayName(),
                     methodDesc,
                     methodDisp,
-                    classDisplayName);
+                    classDisplayName,
+                    realClassName);
         } else if 
(testSource.filter(ClassSource.class::isInstance).isPresent()) {
             ClassSource classSource = 
testSource.map(ClassSource.class::cast).get();
             String className = classSource.getClassName();
@@ -454,12 +457,13 @@ private ResultDisplay toClassMethodName(TestIdentifier 
testIdentifier) {
                     displayNameTagValue.orElse(className),
                     null,
                     null,
-                    classDisplayName); // != null ? classDisplayName : 
className);
+                    classDisplayName, // != null ? classDisplayName : 
className);
+                    className);
         } else {
             String source = testPlan.getParent(testIdentifier)
                     .map(TestIdentifier::getDisplayName)
                     .orElse(display);
-            return new ResultDisplay(classLevelName.orElse(source), source, 
display, display, classDisplayName);
+            return new ResultDisplay(classLevelName.orElse(source), source, 
display, display, classDisplayName, null);
         }
     }
 
@@ -489,19 +493,21 @@ private Optional<String> 
findDisplayNameTagValue(TestIdentifier testIdentifier)
     }
 
     private static class ResultDisplay {
-        private String className, displayName, methodSignature, 
methodDisplayName, classDisplayName;
+        private String className, displayName, methodSignature, 
methodDisplayName, classDisplayName, qualifiedClassName;
 
         ResultDisplay(
                 String className,
                 String displayName,
                 String methodSignature,
                 String methodDisplayName,
-                String classDisplayName) {
+                String classDisplayName,
+                String qualifiedClassName) {
             this.className = className;
             this.displayName = displayName;
             this.methodSignature = methodSignature;
             this.methodDisplayName = methodDisplayName;
             this.classDisplayName = classDisplayName;
+            this.qualifiedClassName = qualifiedClassName;
         }
 
         public String getClassName() {
@@ -523,6 +529,10 @@ public String getMethodDisplayName() {
         public String getClassDisplayName() {
             return classDisplayName;
         }
+
+        public String getQualifiedClassName() {
+            return qualifiedClassName;
+        }
     }
 
     /**

Reply via email to