ant-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bode...@apache.org
Subject [1/6] ant git commit: JDK9 modules support for JUnit by Tomáš Zezula
Date Sun, 11 Sep 2016 10:17:57 GMT
Repository: ant
Updated Branches:
  refs/heads/1.9.x 1d7b62415 -> bda488eaf


JDK9 modules support for JUnit by Tomáš Zezula

this is the combined patch or #18 which couldn't be applied via `git am`


Project: http://git-wip-us.apache.org/repos/asf/ant/repo
Commit: http://git-wip-us.apache.org/repos/asf/ant/commit/31cc48c6
Tree: http://git-wip-us.apache.org/repos/asf/ant/tree/31cc48c6
Diff: http://git-wip-us.apache.org/repos/asf/ant/diff/31cc48c6

Branch: refs/heads/1.9.x
Commit: 31cc48c6f70b8c24f79aa5f17f80c32f8480e2f9
Parents: 1d7b624
Author: Stefan Bodewig <bodewig@apache.org>
Authored: Wed Jul 13 20:28:32 2016 +0200
Committer: Stefan Bodewig <bodewig@apache.org>
Committed: Sun Sep 11 12:10:15 2016 +0200

----------------------------------------------------------------------
 manual/Tasks/junit.html                         |  59 +++++-
 .../ant/taskdefs/optional/junit/JUnitTask.java  | 135 +++++++++++-
 .../taskdefs/optional/junit/JUnitTaskTest.java  | 204 +++++++++++++++++++
 3 files changed, 389 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ant/blob/31cc48c6/manual/Tasks/junit.html
----------------------------------------------------------------------
diff --git a/manual/Tasks/junit.html b/manual/Tasks/junit.html
index 76df9ce..9f60512 100644
--- a/manual/Tasks/junit.html
+++ b/manual/Tasks/junit.html
@@ -371,6 +371,21 @@ subelement.</p>
 
 <p><em>since Ant 1.6.</em></p>
 
+<h4>modulepath</h4>
+
+<p>The location of modules can be specified using this <a href="../using.html#path">PATH
like structure</a>.<br/>
+The modulepath requires <i>fork</i> to be set to <code>true</code>.
+
+<p><em>since Ant 1.10</em></p>
+
+<h4>upgrademodulepath</h4>
+
+<p>The location of modules that replace upgradeable modules in the runtime image
+can be specified using this <a href="../using.html#path">PATH like structure</a>.<br/>
+The upgrademodulepath requires <i>fork</i> to be set to <code>true</code>.
+
+<p><em>since Ant 1.10</em></p>
+
 <h4>formatter</h4>
 
 <p>The results of the tests can be printed in different
@@ -796,7 +811,47 @@ the single <code>&lt;test/&gt;</code> will run. So
only the failing test cases a
 The two nested formatters are for displaying (for the user) and for updating the collector
 class.
 </p>
-
-
+<pre>
+    &lt;junit fork="true"
+        jvm="${platform.java}"&gt;
+        &lt;jvmarg value="-Xpatch:${module.name}=${build.test.classes}"/&gt;
+        &lt;jvmarg line="-addmods ${module.name}"/&gt;
+        &lt;jvmarg value="-XaddReads:${module.name}=ALL-UNNAMED"/&gt;
+        &lt;jvmarg value="-XaddExports:${module.name}/my.test=ALL-UNNAMED"/&gt;
+        &lt;classpath&gt;
+            &lt;pathelement path="${libs.junit}"/&gt;
+        &lt;/classpath&gt;
+        &lt;modulepath&gt;
+            &lt;pathelement path="${modules}:${build.classes}"/&gt;
+        &lt;/modulepath&gt;
+        &lt;formatter type="plain"/&gt;
+        &lt;test name="my.test.TestCase"/&gt;
+    &lt;/junit&gt;
+</pre>
+<p>Runs my.test.TestCase as a white-box test in the forked VM given by the <code>platform.java</code>
property.
+The junit library is a part of an unnamed module while the tested project and required modules
are on the module path. The tests
+do not have module-info file and are executed in the project module given by <code>module.name</code>
property.<br/>
+The <code>-Xpatch</code> java option executes the tests built into <code>${build.test.classes}</code>
in a module given
+by <code>module.name</code> property.<br/>
+The <code>-addmods</code> java option enables the tested module.<br/>
+The <code>-XaddReads</code> java option makes the unnamed module containing the
junit readable by tested module.<br/>
+The <code>-XaddExports</code> java option makes the non-exported test package
<code>my.test</code> accessible from the unnamed module containing the junit.<br/>
+<pre>
+    &lt;junit fork="true"
+        jvm="${platform.java}"&gt;
+        &lt;jvmarg line="-addmods ${test.module.name}"/&gt;
+        &lt;jvmarg value="-XaddExports:${test.module.name}/my.test=junit,ALL-UNNAMED"/&gt;
+        &lt;modulepath&gt;
+            &lt;pathelement path="${modules}:${build.classes}:${libs.junit}"/&gt;
+        &lt;/modulepath&gt;
+        &lt;formatter type="plain"/&gt;
+        &lt;test name="my.test.TestCase"/&gt;
+    &lt;/junit&gt;
+</pre>
+<p>Runs my.test.TestCase as a black-box test in the forked VM given by the <code>platform.java</code>
property.
+The junit library is used as an automatic module. The tests module-info requires the tested
module and junit.<br/>
+The <code>-addmods</code> java option enables the test module.<br/>
+The <code>-XaddExports</code> java option makes the non-exported test package
<code>my.test</code> accessible from the junit module and Ant's test runner.
+Another possibility is to export the test package in the tests module-info by <code>exports
my.test</code> directive.<br/>
 </body>
 </html>

http://git-wip-us.apache.org/repos/asf/ant/blob/31cc48c6/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java
----------------------------------------------------------------------
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java
index 459bd3d..08ae618 100644
--- a/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java
@@ -38,6 +38,7 @@ import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Vector;
@@ -511,6 +512,26 @@ public class JUnitTask extends Task {
     }
 
     /**
+     * Add a path to the modulepath.
+     *
+     * @return created modulepath.
+     * @since 1.10
+     */
+    public Path createModulepath() {
+        return getCommandline().createModulepath(getProject()).createPath();
+    }
+
+    /**
+     * Add a path to the upgrademodulepath.
+     *
+     * @return created upgrademodulepath.
+     * @since 1.10
+     */
+    public Path createUpgrademodulepath() {
+        return getCommandline().createUpgrademodulepath(getProject()).createPath();
+    }
+
+    /**
      * Adds an environment variable; used when forking.
      *
      * <p>Will be ignored if we are not forking a new VM.</p>
@@ -749,7 +770,7 @@ public class JUnitTask extends Task {
             loader.loadClass("junit.framework.Test"); // sanity check
         } catch (final ClassNotFoundException e) {
             throw new BuildException(
-                    "The <classpath> for <junit> must include junit.jar "
+                    "The <classpath> or <modulepath> for <junit> must include
junit.jar "
                     + "if not in Ant's own classpath",
                     e, task.getLocation());
         }
@@ -777,10 +798,14 @@ public class JUnitTask extends Task {
         if (splitJUnit) {
             final Path path = new Path(getProject());
             path.add(antRuntimeClasses);
-            final Path extra = getCommandline().getClasspath();
+            Path extra = getCommandline().getClasspath();
             if (extra != null) {
                 path.add(extra);
             }
+            extra = getCommandline().getModulepath();
+            if (extra != null && !hasJunit(path)) {
+                path.add(expandModulePath(extra));
+            }
             mirrorLoader = (ClassLoader) AccessController.doPrivileged(new PrivilegedAction()
{
                 public Object run() {
                     return new SplitClassLoader(myLoader, path, getProject(),
@@ -818,7 +843,7 @@ public class JUnitTask extends Task {
     @Override
     public void execute() throws BuildException {
         checkMethodLists();
-
+        checkModules();
         setupJUnitDelegate();
 
         final List<List> testLists = new ArrayList<List>();
@@ -1698,6 +1723,75 @@ public class JUnitTask extends Task {
     }
 
     /**
+     * Checks a validity of module specific options.
+     * @since 1.10
+     */
+    private void checkModules() {
+        if (hasPath(getCommandline().getModulepath()) ||
+            hasPath(getCommandline().getUpgrademodulepath())) {
+            for (int i = 0, count = batchTests.size(); i < count; i++) {
+                if(!batchTests.elementAt(i).getFork()) {
+                    throw new BuildException("The module path requires fork attribute to
be set to true.");
+                }
+            }
+            for (int i = 0, count = tests.size(); i < count; i++) {
+                if (!tests.elementAt(i).getFork()) {
+                    throw new BuildException("The module path requires fork attribute to
be set to true.");
+                }
+            }
+        }
+    }
+
+    /**
+     * Checks is a junit is on given path.
+     * @param path the {@link Path} to check
+     * @return true when given {@link Path} contains junit
+     * @since 1.10
+     */
+    private boolean hasJunit(final Path path) {
+        try (AntClassLoader loader = AntClassLoader.newAntClassLoader(
+                null,
+                getProject(),
+                path,
+                true)) {
+            try {
+                loader.loadClass("junit.framework.Test");
+                return true;
+            } catch (final Exception ex) {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Expands a module path to flat path of jars and root folders usable by classloader.
+     * @param modulePath to be expanded
+     * @return the expanded path
+     * @since 1.10
+     */
+    private Path expandModulePath(Path modulePath) {
+        final Path expanded = new Path(getProject());
+        for (String path : modulePath.list()) {
+            final File modulePathEntry = getProject().resolveFile(path);
+            if (modulePathEntry.isDirectory() && !hasModuleInfo(modulePathEntry))
{
+                final File[] modules = modulePathEntry.listFiles((dir,name)->name.toLowerCase(Locale.ENGLISH).endsWith(".jar"));
+                if (modules != null) {
+                    for (File module : modules) {
+                        expanded.add(new Path(getProject(), String.format(
+                                "%s%s%s",   //NOI18N
+                                path,
+                                File.separator,
+                                module.getName())));
+                    }
+                }
+            } else {
+                expanded.add(new Path(getProject(), path));
+            }
+        }
+        return expanded;
+    }
+
+    /**
      * return an enumeration listing each test, then each batchtest
      * @return enumeration
      * @since Ant 1.3
@@ -1892,16 +1986,23 @@ public class JUnitTask extends Task {
      */
     private void createClassLoader() {
         final Path userClasspath = getCommandline().getClasspath();
-        if (userClasspath != null) {
+        final Path userModulepath = getCommandline().getModulepath();
+        if (userClasspath != null || userModulepath != null) {
             if (reloading || classLoader == null) {
                 deleteClassLoader();
-                final Path classpath = (Path) userClasspath.clone();
+                final Path path = new Path(getProject());
+                if (userClasspath != null) {
+                    path.add((Path) userClasspath.clone());
+                }
+                if (userModulepath != null && !hasJunit(path)) {
+                    path.add(expandModulePath(userModulepath));
+                }
                 if (includeAntRuntime) {
                     log("Implicitly adding " + antRuntimeClasses
                         + " to CLASSPATH", Project.MSG_VERBOSE);
-                    classpath.append(antRuntimeClasses);
+                    path.append(antRuntimeClasses);
                 }
-                classLoader = getProject().createClassLoader(classpath);
+                classLoader = getProject().createClassLoader(path);
                 if (getClass().getClassLoader() != null
                     && getClass().getClassLoader() != Project.class.getClassLoader())
{
                     classLoader.setParent(getClass().getClassLoader());
@@ -2280,4 +2381,24 @@ public class JUnitTask extends Task {
         w.newLine();
         s.println(text);
     }
+
+    /**
+     * Checks if a path exists and is non empty.
+     * @param path to be checked
+     * @return true if the path is non <code>null</code> and non empty.
+     * @since 1.10
+     */
+    private static boolean hasPath(final Path path) {
+        return path != null && path.size() > 0;
+    }
+
+    /**
+     * Checks if a given folder is an unpacked module.
+     * @param root the fodler to be checked
+     * @return true if the root is an unpacked module
+     * @since 1.10
+     */
+    private static boolean hasModuleInfo(final File root) {
+        return new File(root, "module-info.class").exists();    //NOI18N
+    }
 }

http://git-wip-us.apache.org/repos/asf/ant/blob/31cc48c6/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskTest.java
----------------------------------------------------------------------
diff --git a/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskTest.java
b/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskTest.java
index 33fd3b0..f08860a 100644
--- a/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskTest.java
+++ b/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskTest.java
@@ -27,18 +27,33 @@ import static org.apache.tools.ant.AntAssert.assertNotContains;
 import static org.apache.tools.ant.AntAssert.assertContains;
 
 import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileReader;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+import java.util.TreeSet;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.xpath.XPath;
 import javax.xml.xpath.XPathConstants;
 import javax.xml.xpath.XPathFactory;
+import org.apache.tools.ant.BuildException;
 
 import org.apache.tools.ant.BuildFileRule;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.launcher.CommandLauncher;
+import org.apache.tools.ant.taskdefs.optional.junit.JUnitTask.ForkMode;
+import org.apache.tools.ant.types.Path;
 import org.apache.tools.ant.util.JavaEnvUtils;
+import org.apache.tools.ant.util.LoaderUtils;
 import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Rule;
@@ -395,4 +410,193 @@ public class JUnitTaskTest {
 
     }
 
+    @Test(expected = BuildException.class)
+    public void testModulePathNeedsFork() throws Exception {
+        final Project project = new Project();
+        project.init();
+        JUnitTask task = new JUnitTask();
+        task.setProject(project);
+        final Path p = new Path(project);
+        p.setPath("modules");
+        task.createModulepath().add(p);
+        task.addTest(new JUnitTest("org.apache.tools.ant.taskdefs.optional.junit.TestTest"));
+        task.execute();
+    }
+
+    @Test(expected = BuildException.class)
+    public void testUpgradeModulePathNeedsFork() throws Exception {
+        final Project project = new Project();
+        project.init();
+        JUnitTask task = new JUnitTask();
+        task.setProject(project);
+        final Path p = new Path(project);
+        p.setPath("modules");
+        task.createUpgrademodulepath().add(p);
+        task.addTest(new JUnitTest("org.apache.tools.ant.taskdefs.optional.junit.TestTest"));
+        task.execute();
+    }
+
+    @Test
+    public void testJunitOnCpArguments() throws Exception {
+        final File tmp = new File(System.getProperty("java.io.tmpdir"));    //NOI18N
+        final File workDir = new File(tmp, String.format("%s_testJCP%d",    //NOI18N
+                getClass().getName(),
+                System.currentTimeMillis()/1000));
+        workDir.mkdirs();
+        try {
+            final File modulesDir = new File(workDir,"modules");    //NOI18N
+            modulesDir.mkdirs();
+
+            final Project project = new Project();
+            project.init();
+            project.setBaseDir(workDir);
+            final MockCommandLauncher mockProcLauncher = new MockCommandLauncher();
+            project.addReference(
+                    MagicNames.ANT_VM_LAUNCHER_REF_ID,
+                    mockProcLauncher);
+            JUnitTask task = new JUnitTask();
+            task.setDir(workDir);
+            task.setFork(true);
+            task.setProject(project);
+            final File junit = LoaderUtils.getResourceSource(
+                    JUnitTask.class.getClassLoader(),
+                    "junit/framework/Test.class");    //NOI18N
+            final Path cp = new Path(project);
+            cp.setPath(junit.getAbsolutePath());
+            task.createClasspath().add(cp);
+            final Path mp = new Path(project);
+            mp.setPath(modulesDir.getName());
+            task.createModulepath().add(mp);
+            task.addTest(new JUnitTest("org.apache.tools.ant.taskdefs.optional.junit.TestTest"));
+            task.execute();
+            assertNotNull(mockProcLauncher.cmd);
+            String resCp = null;
+            String resMp = null;
+            Set<String> resExports = new TreeSet<>();
+            for (int i = 1; i< mockProcLauncher.cmd.length; i++) {
+                if ("-classpath".equals(mockProcLauncher.cmd[i])) { //NOI18N
+                    resCp = mockProcLauncher.cmd[++i];
+                } else if ("-modulepath".equals(mockProcLauncher.cmd[i])) { //NOI18N
+                    resMp = mockProcLauncher.cmd[++i];
+                } else if (mockProcLauncher.cmd[i].startsWith("-XaddExports:")) {   //NOI18N
+                    resExports.add(mockProcLauncher.cmd[i]);
+                } else if (JUnitTestRunner.class.getName().equals(mockProcLauncher.cmd[i]))
{
+                    break;
+                }
+            }
+            assertTrue("No exports", resExports.isEmpty());
+            assertEquals("Expected classpath", cp.toString(), resCp);
+            assertEquals("Expected modulepath", mp.toString(), resMp);
+        } finally {
+            delete(workDir);
+        }
+    }
+
+    @Test
+    public void testJunitOnMpArguments() throws Exception {
+        final File tmp = new File(System.getProperty("java.io.tmpdir"));    //NOI18N
+        final File workDir = new File(tmp, String.format("%s_testJMP%d",    //NOI18N
+                getClass().getName(),
+                System.currentTimeMillis()/1000));
+        workDir.mkdirs();
+        try {
+            final File modulesDir = new File(workDir,"modules");    //NOI18N
+            modulesDir.mkdirs();
+
+            final Project project = new Project();
+            project.init();
+            project.setBaseDir(workDir);
+            final MockCommandLauncher mockProcLauncher = new MockCommandLauncher();
+            project.addReference(
+                    MagicNames.ANT_VM_LAUNCHER_REF_ID,
+                    mockProcLauncher);
+            JUnitTask task = new JUnitTask();
+            task.setDir(workDir);
+            task.setFork(true);
+            task.setProject(project);
+            final File junit = LoaderUtils.getResourceSource(
+                    JUnitTask.class.getClassLoader(),
+                    "junit/framework/Test.class");    //NOI18N
+            final Path mp = new Path(project);
+            mp.add(new Path(project, junit.getAbsolutePath()));
+            mp.add(new Path(project, modulesDir.getName()));
+            task.createModulepath().add(mp);
+            task.addTest(new JUnitTest("org.apache.tools.ant.taskdefs.optional.junit.TestTest"));
      //NOI18N
+            task.execute();
+            assertNotNull(mockProcLauncher.cmd);
+            String resCp = null;
+            String resMp = null;
+            Set<String> resExports = new TreeSet<>();
+            for (int i = 1; i< mockProcLauncher.cmd.length; i++) {
+                if ("-classpath".equals(mockProcLauncher.cmd[i])) { //NOI18N
+                    resCp = mockProcLauncher.cmd[++i];
+                } else if ("-modulepath".equals(mockProcLauncher.cmd[i])) { //NOI18N
+                    resMp = mockProcLauncher.cmd[++i];
+                } else if (mockProcLauncher.cmd[i].startsWith("-XaddExports:")) {   //NOI18N
+                    resExports.add(mockProcLauncher.cmd[i]);
+                } else if (JUnitTestRunner.class.getName().equals(mockProcLauncher.cmd[i]))
{
+                    break;
+                }
+            }
+            assertTrue("No exports", resExports.isEmpty());
+            assertNull("No classpath", resCp);
+            assertEquals("Expected modulepath", mp.toString(), resMp);
+        } finally {
+            delete(workDir);
+        }
+    }
+
+    private void delete(File f) {
+        if (f.isDirectory()) {
+            final File[] clds = f.listFiles();
+            if (clds != null) {
+                for (File cld : clds) {
+                    delete(cld);
+                }
+            }
+        }
+        f.delete();
+    }
+
+    private static final class MockCommandLauncher extends CommandLauncher {
+        private String[] cmd;
+
+        @Override
+        public Process exec(Project project, String[] cmd, String[] env, File workingDir)
throws IOException {
+            this.cmd = Arrays.copyOf(cmd, cmd.length);
+            return new MockProcess();
+        }
+
+        private static class MockProcess extends Process {
+
+            @Override
+            public OutputStream getOutputStream() {
+                return new ByteArrayOutputStream();
+            }
+
+            @Override
+            public InputStream getInputStream() {
+                return new ByteArrayInputStream(new byte[0]);
+            }
+
+            @Override
+            public InputStream getErrorStream() {
+                return new ByteArrayInputStream(new byte[0]);
+            }
+
+            @Override
+            public int waitFor() throws InterruptedException {
+                return exitValue();
+            }
+
+            @Override
+            public int exitValue() {
+                return 0;
+            }
+
+            @Override
+            public void destroy() {
+            }
+        }
+    }
 }


Mime
View raw message