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

jaikiran pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ant.git


The following commit(s) were added to refs/heads/master by this push:
     new 2d4414817 fix legacy-xml reporting in junitlauncher task, when jupiter 
dynamic tests are involved.
2d4414817 is described below

commit 2d4414817a8e366b2c38cae5ace9fe5206677790
Author: Jaikiran Pai <[email protected]>
AuthorDate: Sun Aug 13 21:42:57 2023 +0530

    fix legacy-xml reporting in junitlauncher task, when jupiter dynamic tests 
are involved.
    
    Thanks to Marc Guillemot for raising the issue and proposing a patch
    
    This closes #122 pull request on github
---
 WHATSNEW                                           |  5 ++
 .../testcases/taskdefs/optional/junitlauncher.xml  | 18 +++++++
 .../junitlauncher/LegacyXmlResultFormatter.java    | 23 ++++++--
 .../junitlauncher/JUnitLauncherTaskTest.java       | 61 +++++++++++++++++----
 .../junitlauncher/jupiter/JupiterDynamicTests.java | 63 ++++++++++++++++++++++
 5 files changed, 156 insertions(+), 14 deletions(-)

diff --git a/WHATSNEW b/WHATSNEW
index c07344b42..52be5c754 100644
--- a/WHATSNEW
+++ b/WHATSNEW
@@ -50,6 +50,11 @@ Fixed bugs:
    a CEN extra field data for the entry.
    Bugzilla Report 66873
 
+ * legacy-xml listener of junitlauncher task wouldn't report certain
+   failures involving junit jupiter dynamic tests. This has now been
+   fixed.
+   Github Pull Request #122
+
 Other changes:
 --------------
 
diff --git a/src/etc/testcases/taskdefs/optional/junitlauncher.xml 
b/src/etc/testcases/taskdefs/optional/junitlauncher.xml
index 0a736d714..c3e4b5651 100644
--- a/src/etc/testcases/taskdefs/optional/junitlauncher.xml
+++ b/src/etc/testcases/taskdefs/optional/junitlauncher.xml
@@ -484,5 +484,23 @@
             </test>
         </junitlauncher>
     </target>
+
+    <target name="test-jupiter-dynamic-tests" depends="init">
+        <property name="junitlauncher.test.tracker.append.file"
+                  value="${output.dir}/${test-jupiter-dynamic-tests.tracker}"/>
+        <junitlauncher>
+            <classpath refid="test.classpath"/>
+            <test name="org.example.junitlauncher.jupiter.JupiterDynamicTests"
+                  outputdir="${output.dir}">
+                <fork>
+                    <sysproperty key="junitlauncher.test.failBeforeEach" 
value="true"/>
+                </fork>
+                <listener classname="org.example.junitlauncher.Tracker"
+                          if="test-jupiter-dynamic-tests.tracker"/>
+                <listener type="legacy-xml" sendSysErr="true" sendSysOut="true"
+                          resultFile="JupiterDynamicTests.xml"/>
+            </test>
+        </junitlauncher>
+    </target>
 </project>
 
diff --git 
a/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/LegacyXmlResultFormatter.java
 
b/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/LegacyXmlResultFormatter.java
index 3db122791..f72822d38 100644
--- 
a/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/LegacyXmlResultFormatter.java
+++ 
b/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/LegacyXmlResultFormatter.java
@@ -24,6 +24,7 @@ import org.junit.platform.engine.TestExecutionResult;
 import org.junit.platform.engine.TestSource;
 import org.junit.platform.engine.reporting.ReportEntry;
 import org.junit.platform.engine.support.descriptor.ClassSource;
+import org.junit.platform.engine.support.descriptor.MethodSource;
 import org.junit.platform.launcher.TestIdentifier;
 import org.junit.platform.launcher.TestPlan;
 
@@ -244,6 +245,7 @@ class LegacyXmlResultFormatter extends 
AbstractJUnitResultFormatter implements T
                     // (https://bz.apache.org/bugzilla/show_bug.cgi?id=63850)
                     continue;
                 }
+                String classname = null;
                 // find the associated class of this test
                 final Optional<ClassSource> parentClassSource;
                 if (testId.isTest()) {
@@ -252,10 +254,25 @@ class LegacyXmlResultFormatter extends 
AbstractJUnitResultFormatter implements T
                 else {
                     parentClassSource = findFirstClassSource(testId);
                 }
-                if (!parentClassSource.isPresent()) {
-                    continue;
+                if (parentClassSource.isPresent()) {
+                    classname = parentClassSource.get().getClassName();
+                } else {
+                    if (testId.getSource().isPresent()) {
+                        final TestSource testSource = testId.getSource().get();
+                        if (testSource instanceof MethodSource) {
+                            // this can happen for the case where the test is 
generated dynamically
+                            // through the use of 
@org.junit.jupiter.api.TestFactory. In such cases
+                            // the method having that annotation is considered 
a test and its
+                            // source is reported as a MethodSource
+                            classname = ((MethodSource) 
testSource).getClassName();
+                        }
+                    }
+                }
+                if (classname == null) {
+                    // as a last resort, use the test id as the classname,
+                    // so that the failure does get reported instead of being 
ignored/invisible
+                    classname = testId.getUniqueIdObject().toString();
                 }
-                final String classname = 
(parentClassSource.get()).getClassName();
                 writer.writeStartElement(ELEM_TESTCASE);
                 writeAttribute(writer, ATTR_CLASSNAME, classname);
                 writeAttribute(writer, ATTR_NAME, useLegacyReportingName ? 
testId.getLegacyReportingName()
diff --git 
a/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junitlauncher/JUnitLauncherTaskTest.java
 
b/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junitlauncher/JUnitLauncherTaskTest.java
index 051c23eef..8d6455311 100644
--- 
a/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junitlauncher/JUnitLauncherTaskTest.java
+++ 
b/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junitlauncher/JUnitLauncherTaskTest.java
@@ -40,6 +40,7 @@ import org.apache.tools.ant.Project;
 import org.apache.tools.ant.taskdefs.condition.Os;
 import 
org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.JUnitLauncherTask;
 import org.apache.tools.ant.util.LoaderUtils;
+import org.example.junitlauncher.jupiter.JupiterDynamicTests;
 import org.example.junitlauncher.jupiter.JupiterSampleTest;
 import org.example.junitlauncher.jupiter.JupiterSampleTestFailingBeforeAll;
 import org.example.junitlauncher.jupiter.JupiterTagSampleTest;
@@ -184,17 +185,8 @@ public class JUnitLauncherTaskTest {
                 JupiterSampleTest.class.getName(), "testSkipped"));
         assertFalse("ForkedTest wasn't expected to be run", 
wasTestRun(trackerFile, ForkedTest.class.getName()));
 
-        
verifyLegacyXMLFile("TEST-org.example.junitlauncher.jupiter.JupiterSampleTestFailingBeforeAll.xml",
 "<failure message=\"Intentional failure\" 
type=\"java.lang.RuntimeException\">");
-        
verifyLegacyXMLFile("TEST-org.example.junitlauncher.jupiter.JupiterSampleTestFailingStatic.xml",
 "Caused by: java.lang.RuntimeException: Intentional exception from static init 
block");
-    }
-
-    private void verifyLegacyXMLFile(final String fileName, final String 
expectedContentExtract) throws IOException {
-        final String outputDir = 
buildRule.getProject().getProperty("output.dir");
-        final Path xmlFile = Paths.get(outputDir, fileName);
-
-        assertTrue("XML file doesn't exist: " + xmlFile, 
Files.exists(xmlFile));
-        final String content = new String(Files.readAllBytes(xmlFile), 
StandardCharsets.UTF_8);
-        assertTrue(fileName + " doesn't contain " + expectedContentExtract, 
content.contains(expectedContentExtract));
+        
assertPresentInLegacyXMLFile("TEST-org.example.junitlauncher.jupiter.JupiterSampleTestFailingBeforeAll.xml",
 "<failure message=\"Intentional failure\" 
type=\"java.lang.RuntimeException\">");
+        
assertPresentInLegacyXMLFile("TEST-org.example.junitlauncher.jupiter.JupiterSampleTestFailingStatic.xml",
 "Caused by: java.lang.RuntimeException: Intentional exception from static init 
block");
     }
 
     /**
@@ -562,6 +554,53 @@ public class JUnitLauncherTaskTest {
                 wasTestRun(trackerFile, 
SharedDataAccessorTest1.class.getName()));
     }
 
+    /**
+     * Tests that dynamically generated jupiter tests, when they fail, are 
reported
+     * correctly by the legacy-xml reporter
+     */
+    @Test
+    public void testJupiterDynamicTests() throws Exception {
+        final String targetName = "test-jupiter-dynamic-tests";
+        final Path trackerFile = setupTrackerProperty(targetName);
+        buildRule.executeTarget(targetName);
+
+        assertTrue("JupiterDynamicTests was expected to be run",
+                wasTestRun(trackerFile, JupiterDynamicTests.class.getName()));
+        final String xmlReportFile = "JupiterDynamicTests.xml";
+        final String testClassName = JupiterDynamicTests.class.getName();
+        assertPresentInLegacyXMLFile(xmlReportFile, "@BeforeEach called on " + 
testClassName);
+        assertAbsentInLegacyXMLFile(xmlReportFile, "@TestFactory called");
+        assertPresentInLegacyXMLFile(xmlReportFile,
+                "<failure message=\"Intentionally failing in @BeforeEach of " 
+ testClassName);
+    }
+
+    private void assertPresentInLegacyXMLFile(final String fileName,
+                                              final String expectedContent) 
throws IOException {
+        assertInLegacyXMLFile(fileName, expectedContent, true);
+    }
+
+    private void assertAbsentInLegacyXMLFile(final String fileName,
+                                             final String unexpectedContent) 
throws IOException {
+        assertInLegacyXMLFile(fileName, unexpectedContent, false);
+    }
+
+    private void assertInLegacyXMLFile(final String fileName, final String 
content,
+                                       final boolean expected) throws 
IOException {
+        final String outputDir = 
buildRule.getProject().getProperty("output.dir");
+        final Path xmlFile = Paths.get(outputDir, fileName);
+
+        assertTrue("XML file doesn't exist: " + xmlFile, 
Files.exists(xmlFile));
+        final String actualContent = new String(Files.readAllBytes(xmlFile), 
StandardCharsets.UTF_8);
+        if (expected) {
+            assertTrue(fileName + " doesn't contain " + content,
+                    actualContent.contains(content));
+        } else {
+            assertFalse(fileName + " unexpectedly contains " + content,
+                    actualContent.contains(content));
+        }
+
+    }
+
     private Path setupTrackerProperty(final String targetName) {
         final String filename = targetName + "-tracker.txt";
         buildRule.getProject().setProperty(targetName + ".tracker", filename);
diff --git 
a/src/tests/junit/org/example/junitlauncher/jupiter/JupiterDynamicTests.java 
b/src/tests/junit/org/example/junitlauncher/jupiter/JupiterDynamicTests.java
new file mode 100644
index 000000000..0413b795c
--- /dev/null
+++ b/src/tests/junit/org/example/junitlauncher/jupiter/JupiterDynamicTests.java
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.example.junitlauncher.jupiter;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DynamicContainer;
+import org.junit.jupiter.api.DynamicTest;
+import org.junit.jupiter.api.TestFactory;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class JupiterDynamicTests {
+
+    @TestFactory
+    Collection<DynamicContainer> generateTests() {
+        System.out.println("@TestFactory called on " + this);
+        final DynamicTest test1 = DynamicTest.dynamicTest(
+                "Dynamic test1",
+                () -> {
+                    System.out.println("Dynamic test1 being executed on " + 
this);
+                    assertEquals("foo", "foo");
+                });
+        final DynamicTest test2 = DynamicTest.dynamicTest(
+                "Dynamic test2",
+                () -> {
+                    System.out.println("Dynamic test2 being executed on " + 
this);
+                    assertEquals("bar", "bar");
+                });
+        final List<DynamicTest> tests = new ArrayList<>();
+        tests.add(test1);
+        tests.add(test2);
+        return Collections.singleton(DynamicContainer.dynamicContainer(
+                "Dynamic test container", tests));
+    }
+
+    @BeforeEach
+    void beforeEach() {
+        System.out.println("@BeforeEach called on " + this);
+        final boolean shouldFail = 
Boolean.getBoolean("junitlauncher.test.failBeforeEach");
+        if (shouldFail) {
+            throw new RuntimeException("Intentionally failing in @BeforeEach 
of " + this);
+        }
+    }
+}

Reply via email to