jdk/test/tools/jar/modularJar/Basic.java
changeset 42338 a60f280f803c
parent 40261 86a49ba76f52
child 42345 cead5ce4ca27
--- a/jdk/test/tools/jar/modularJar/Basic.java	Wed Nov 23 16:16:35 2016 +0000
+++ b/jdk/test/tools/jar/modularJar/Basic.java	Thu Dec 01 08:57:53 2016 +0000
@@ -22,19 +22,18 @@
  */
 
 import java.io.*;
+import java.lang.module.ModuleDescriptor;
 import java.lang.reflect.Method;
-import java.nio.file.FileVisitResult;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.SimpleFileVisitor;
+import java.nio.file.*;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.util.*;
 import java.util.function.Consumer;
 import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
 import java.util.jar.JarInputStream;
 import java.util.jar.Manifest;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import jdk.testlibrary.FileUtils;
@@ -76,7 +75,8 @@
                                                    Set.of("jdk.test.foo"),
                                                    null, // no uses
                                                    null, // no provides
-                                                   Set.of("jdk.test.foo.internal"));
+                                                   Set.of("jdk.test.foo.internal",
+                                                          "jdk.test.foo.resources"));
     static TestModuleData BAR = new TestModuleData("bar",
                                                    "4.5.6.7",
                                                    "jdk.test.bar.Bar",
@@ -99,17 +99,18 @@
         final String version;
         final String message;
         final String hashes;
-        final Set<String> conceals;
+        final Set<String> packages;
 
         TestModuleData(String mn, String v, String mc, String m, String h,
                        Set<String> requires, Set<String> exports, Set<String> uses,
-                       Set<String> provides, Set<String> conceals) {
+                       Set<String> provides, Set<String> contains) {
             moduleName = mn; mainClass = mc; version = v; message = m; hashes = h;
-            this.requires = requires;
-            this.exports = exports;
-            this.uses = uses;
-            this.provides = provides;
-            this.conceals = conceals;
+            this.requires = requires != null ? requires : Collections.emptySet();
+            this.exports = exports != null ? exports : Collections.emptySet();
+            this.uses = uses != null ? uses : Collections.emptySet();;
+            this.provides = provides != null ? provides : Collections.emptySet();
+            this.packages = Stream.concat(this.exports.stream(), contains.stream())
+                                  .collect(Collectors.toSet());
         }
         static TestModuleData from(String s) {
             try {
@@ -148,8 +149,8 @@
                         provides = stringToSet(line);
                     } else if (line.startsWith("hashes:")) {
                         hashes = line.substring("hashes:".length());
-                    } else if (line.startsWith("conceals:")) {
-                        line = line.substring("conceals:".length());
+                    } else if (line.startsWith("contains:")) {
+                        line = line.substring("contains:".length());
                         conceals = stringToSet(line);
                     } else {
                         throw new AssertionError("Unknown value " + line);
@@ -192,16 +193,14 @@
         assertSetsEqual(expected.exports, received.exports);
         assertSetsEqual(expected.uses, received.uses);
         assertSetsEqual(expected.provides, received.provides);
-        assertSetsEqual(expected.conceals, received.conceals);
+        assertSetsEqual(expected.packages, received.packages);
     }
 
     static void assertSetsEqual(Set<String> s1, Set<String> s2) {
-        if (s1 == null && s2 == null) // none expected, or received
-            return;
-        assertTrue(s1.size() == s2.size(),
-                   "Unexpected set size difference: ", s1.size(), ", ", s2.size());
-        s1.forEach(p -> assertTrue(s2.contains(p), "Expected ", p, ", in ", s2));
-    }
+        if (!s1.equals(s2)) {
+            org.testng.Assert.assertTrue(false, s1 + " vs " + s2);
+        }
+     }
 
     @BeforeTest
     public void compileModules() throws Exception {
@@ -209,6 +208,11 @@
         compileModule(BAR.moduleName, MODULE_CLASSES);
         compileModule("baz");  // for service provider consistency checking
 
+        // copy resources
+        copyResource(TEST_SRC.resolve("src").resolve(FOO.moduleName),
+                     MODULE_CLASSES.resolve(FOO.moduleName),
+                     "jdk/test/foo/resources/foo.properties");
+
         setupMRJARModuleInfo(FOO.moduleName);
         setupMRJARModuleInfo(BAR.moduleName);
         setupMRJARModuleInfo("baz");
@@ -228,6 +232,12 @@
             "--no-manifest",
             "-C", modClasses.toString(), ".")
             .assertSuccess();
+
+        assertSetsEqual(readPackagesAttribute(modularJar),
+                        Set.of("jdk.test.foo",
+                               "jdk.test.foo.resources",
+                               "jdk.test.foo.internal"));
+
         java(mp, FOO.moduleName + "/" + FOO.mainClass)
             .assertSuccess()
             .resultChecker(r -> assertModuleData(r, FOO));
@@ -375,7 +385,8 @@
             "--file=" + modularJar.toString(),
             "--no-manifest",
             "-C", modClasses.toString(), "module-info.class",
-            "-C", modClasses.toString(), "jdk/test/foo/Foo.class")
+            "-C", modClasses.toString(), "jdk/test/foo/Foo.class",
+            "-C", modClasses.toString(), "jdk/test/foo/resources/foo.properties")
             .assertSuccess();
         jar("--update",
             "--file=" + modularJar.toString(),
@@ -471,13 +482,63 @@
                            "Expecting to find \"bar, requires foo,...\"",
                            "in output, but did not: [" + r.output + "]");
                 p = Pattern.compile(
-                        "conceals\\s+jdk.test.foo\\s+conceals\\s+jdk.test.foo.internal");
+                        "contains\\s+jdk.test.foo\\s+contains\\s+jdk.test.foo.internal");
                 assertTrue(p.matcher(r.output).find(),
-                           "Expecting to find \"conceals jdk.test.foo,...\"",
+                           "Expecting to find \"contains jdk.test.foo,...\"",
                            "in output, but did not: [" + r.output + "]");
             });
     }
 
+
+    @Test
+    public void partialUpdateFooPackagesAttribute() throws IOException {
+        Path mp = Paths.get("partialUpdateFooPackagesAttribute");
+        createTestDir(mp);
+        Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
+        Path modularJar = mp.resolve(FOO.moduleName + ".jar");
+
+        // Not all files, and none from non-exported packages,
+        // i.e. no concealed list in first create
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "--no-manifest",
+            "-C", modClasses.toString(), "module-info.class",
+            "-C", modClasses.toString(), "jdk/test/foo/Foo.class")
+            .assertSuccess();
+
+        assertSetsEqual(readPackagesAttribute(modularJar),
+                        Set.of("jdk.test.foo"));
+
+        jar("--update",
+            "--file=" + modularJar.toString(),
+            "-C", modClasses.toString(), "jdk/test/foo/resources/foo.properties")
+            .assertSuccess();
+
+        assertSetsEqual(readPackagesAttribute(modularJar),
+                        Set.of("jdk.test.foo", "jdk.test.foo.resources"));
+
+        jar("--update",
+            "--file=" + modularJar.toString(),
+            "--main-class=" + FOO.mainClass,
+            "--module-version=" + FOO.version,
+            "--no-manifest",
+            "-C", modClasses.toString(), "jdk/test/foo/internal/Message.class")
+            .assertSuccess();
+
+        assertSetsEqual(readPackagesAttribute(modularJar),
+                        Set.of("jdk.test.foo",
+                               "jdk.test.foo.resources",
+                               "jdk.test.foo.internal"));
+
+        java(mp, FOO.moduleName + "/" + FOO.mainClass)
+            .assertSuccess()
+            .resultChecker(r -> assertModuleData(r, FOO));
+    }
+
+    private Set<String> readPackagesAttribute(Path jar) {
+        return getModuleDescriptor(jar).packages();
+    }
+
     @Test
     public void hashBarInFooModule() throws IOException {
         Path mp = Paths.get("dependencesFooBar");
@@ -506,6 +567,7 @@
             .assertSuccess();
 
         java(mp, BAR.moduleName + "/" + BAR.mainClass,
+             "--add-exports", "java.base/jdk.internal.misc=bar",
              "--add-exports", "java.base/jdk.internal.module=bar")
             .assertSuccess()
             .resultChecker(r -> {
@@ -550,6 +612,7 @@
             "-C", barClasses.toString(), ".").assertSuccess();
 
         java(mp, BAR.moduleName + "/" + BAR.mainClass,
+             "--add-exports", "java.base/jdk.internal.misc=bar",
              "--add-exports", "java.base/jdk.internal.module=bar")
             .assertFailure()
             .resultChecker(r -> {
@@ -750,12 +813,22 @@
     static Path compileModule(String mn, Path mp)
         throws IOException
     {
-        Path fooSourcePath = TEST_SRC.resolve("src").resolve(mn);
+        Path sourcePath = TEST_SRC.resolve("src").resolve(mn);
         Path build = Files.createDirectories(MODULE_CLASSES.resolve(mn));
-        javac(build, mp, fileList(fooSourcePath));
+        javac(build, mp, sourceList(sourcePath));
         return build;
     }
 
+    static void copyResource(Path srcDir, Path dir, String resource)
+        throws IOException
+    {
+        Path dest = dir.resolve(resource);
+        Files.deleteIfExists(dest);
+
+        Files.createDirectories(dest.getParent());
+        Files.copy(srcDir.resolve(resource), dest);
+    }
+
     static void setupMRJARModuleInfo(String moduleName) throws IOException {
         Path modClasses = MODULE_CLASSES.resolve(moduleName);
         Path metaInfDir = MRJAR_DIR.resolve(moduleName).resolve("META-INF");
@@ -774,6 +847,18 @@
         }
     }
 
+    static ModuleDescriptor getModuleDescriptor(Path jar) {
+        ClassLoader cl = ClassLoader.getSystemClassLoader();
+        try (JarFile jf = new JarFile(jar.toFile())) {
+            JarEntry entry = jf.getJarEntry("module-info.class");
+            try (InputStream in = jf.getInputStream(entry)) {
+                return ModuleDescriptor.read(in);
+            }
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+    }
+
     // Re-enable when there is support in javax.tools for module path
 //    static void javac(Path dest, Path... sourceFiles) throws IOException {
 //        out.printf("Compiling %d source files %s%n", sourceFiles.length,
@@ -817,6 +902,8 @@
         commands.add(dest.toString());
         if (dest.toString().contains("bar")) {
             commands.add("--add-exports");
+            commands.add("java.base/jdk.internal.misc=bar");
+            commands.add("--add-exports");
             commands.add("java.base/jdk.internal.module=bar");
         }
         if (modulePath != null) {
@@ -848,17 +935,10 @@
         return run(new ProcessBuilder(commands));
     }
 
-    static Path[] fileList(Path directory) throws IOException {
-        final List<Path> filePaths = new ArrayList<>();
-        Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
-            @Override
-            public FileVisitResult visitFile(Path file,
-                                             BasicFileAttributes attrs) {
-                filePaths.add(file);
-                return FileVisitResult.CONTINUE;
-            }
-        });
-        return filePaths.toArray(new Path[filePaths.size()]);
+    static Path[] sourceList(Path directory) throws IOException {
+        return Files.find(directory, Integer.MAX_VALUE,
+                          (file, attrs) -> (file.toString().endsWith(".java")))
+                    .toArray(Path[]::new);
     }
 
     static void createTestDir(Path p) throws IOException{