GenModuleInfo.java revision 3294:9adfb22ff08f
199193Sjmallett/*
299193Sjmallett * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
399193Sjmallett * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
499193Sjmallett *
599193Sjmallett * This code is free software; you can redistribute it and/or modify it
699193Sjmallett * under the terms of the GNU General Public License version 2 only, as
799193Sjmallett * published by the Free Software Foundation.
899193Sjmallett *
999193Sjmallett * This code is distributed in the hope that it will be useful, but WITHOUT
1099193Sjmallett * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1199193Sjmallett * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1299193Sjmallett * version 2 for more details (a copy is included in the LICENSE file that
1399193Sjmallett * accompanied this code).
1499193Sjmallett *
1599193Sjmallett * You should have received a copy of the GNU General Public License version
1699193Sjmallett * 2 along with this work; if not, write to the Free Software Foundation,
1799193Sjmallett * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1899193Sjmallett *
1999193Sjmallett * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2099193Sjmallett * or visit www.oracle.com if you need additional information or have any
2199193Sjmallett * questions.
2299193Sjmallett */
2399193Sjmallett
2499193Sjmallett/*
2599193Sjmallett * @test
2699193Sjmallett * @summary Tests jdeps -genmoduleinfo option
2799193Sjmallett * @library ..
2899193Sjmallett * @build CompilerUtils
2999193Sjmallett * @modules jdk.jdeps/com.sun.tools.jdeps
3099193Sjmallett * @run testng GenModuleInfo
3199193Sjmallett */
3299193Sjmallett
3399193Sjmallettimport java.io.*;
3499193Sjmallettimport java.lang.module.ModuleDescriptor;
3599193Sjmallett
3699193Sjmallettimport java.nio.file.Files;
3799193Sjmallettimport java.nio.file.Path;
3899193Sjmallettimport java.nio.file.Paths;
3999193Sjmallett
4099193Sjmallettimport java.util.Arrays;
4199193Sjmallettimport java.util.Set;
42109506Sjmallettimport java.util.jar.JarEntry;
43109506Sjmallettimport java.util.jar.JarOutputStream;
4499193Sjmallettimport java.util.stream.Collectors;
4599193Sjmallettimport java.util.stream.Stream;
4699193Sjmallett
4799193Sjmallettimport org.testng.annotations.DataProvider;
4899193Sjmallettimport org.testng.annotations.BeforeTest;
4999193Sjmallettimport org.testng.annotations.Test;
5099193Sjmallett
51109506Sjmallett
52109506Sjmallettimport static org.testng.Assert.assertEquals;
53109506Sjmallettimport static org.testng.Assert.assertTrue;
5499193Sjmallett
5599193Sjmallettpublic class GenModuleInfo {
5699193Sjmallett    private static final String MODULE_INFO = "module-info.class";
5799193Sjmallett    private static final String TEST_SRC = System.getProperty("test.src");
5899193Sjmallett    private static final String TEST_CLASSES = System.getProperty("test.classes");
59109462Sjmallett
6099193Sjmallett    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
61109462Sjmallett    private static final Path MODS_DIR = Paths.get("mods");
62109462Sjmallett    private static final Path LIBS_DIR = Paths.get("libs");
6399193Sjmallett    private static final Path DEST_DIR = Paths.get("moduleinfosrc");
6499193Sjmallett    private static final Path NEW_MODS_DIR = Paths.get("new_mods");
65109462Sjmallett
6699193Sjmallett    // the names of the modules in this test
6799193Sjmallett    private static final String UNSUPPORTED = "unsupported";
6899193Sjmallett    private static String[] modules = new String[] {"m1", "m2", "m3", UNSUPPORTED};
6999193Sjmallett    /**
70109462Sjmallett     * Compiles all modules used by the test
7199193Sjmallett     */
7299193Sjmallett    @BeforeTest
7399193Sjmallett    public void compileAll() throws Exception {
7499193Sjmallett        CompilerUtils.cleanDir(MODS_DIR);
7599193Sjmallett        CompilerUtils.cleanDir(LIBS_DIR);
7699193Sjmallett        CompilerUtils.cleanDir(DEST_DIR);
7799193Sjmallett        CompilerUtils.cleanDir(NEW_MODS_DIR);
7899193Sjmallett
79109462Sjmallett        assertTrue(CompilerUtils.compileModule(SRC_DIR, MODS_DIR, UNSUPPORTED,
8099193Sjmallett                                               "-XaddExports:java.base/jdk.internal.perf=" + UNSUPPORTED));
81109462Sjmallett        Arrays.asList("m1", "m2", "m3")
82109462Sjmallett              .forEach(mn -> assertTrue(CompilerUtils.compileModule(SRC_DIR, MODS_DIR, mn)));
83109462Sjmallett
84109462Sjmallett        Files.createDirectory(LIBS_DIR);
85109462Sjmallett        Files.createDirectory(DEST_DIR);
86109462Sjmallett
87109462Sjmallett        for (String mn : modules) {
88109462Sjmallett            Path root = MODS_DIR.resolve(mn);
89109462Sjmallett            createJar(LIBS_DIR.resolve(mn + ".jar"), root,
90109462Sjmallett                      Files.walk(root, Integer.MAX_VALUE)
91109462Sjmallett                           .filter(f -> {
92109462Sjmallett                                String fn = f.getFileName().toString();
9399193Sjmallett                                return fn.endsWith(".class") && !fn.equals("module-info.class");
9499193Sjmallett                           }));
9599193Sjmallett        }
9699193Sjmallett    }
9799193Sjmallett
98109462Sjmallett    @Test
9999193Sjmallett    public void jdeps() throws IOException {
10099193Sjmallett        Stream<String> files = Arrays.stream(modules)
10199193Sjmallett                .map(mn -> LIBS_DIR.resolve(mn + ".jar"))
10299193Sjmallett                .map(Path::toString);
10399193Sjmallett        jdeps(Stream.concat(Stream.of("-cp"), files).toArray(String[]::new));
104109506Sjmallett    }
105109506Sjmallett
106109506Sjmallett    @Test
107109506Sjmallett    public void test() throws IOException {
10899193Sjmallett        Stream<String> files = Arrays.stream(modules)
10999193Sjmallett                .map(mn -> LIBS_DIR.resolve(mn + ".jar"))
11099193Sjmallett                .map(Path::toString);
11199193Sjmallett
11299193Sjmallett        jdeps(Stream.concat(Stream.of("-genmoduleinfo", DEST_DIR.toString()),
11399193Sjmallett                            files)
114109506Sjmallett                    .toArray(String[]::new));
115109506Sjmallett
116109506Sjmallett        // check file exists
117109506Sjmallett        Arrays.stream(modules)
11899193Sjmallett                .map(mn -> DEST_DIR.resolve(mn).resolve("module-info.java"))
11999193Sjmallett                .forEach(f -> assertTrue(Files.exists(f)));
120109462Sjmallett
12199222Sjmallett        // copy classes except the original module-info.class
122109506Sjmallett        Files.walk(MODS_DIR, Integer.MAX_VALUE)
123109506Sjmallett                .filter(path -> !path.getFileName().toString().equals(MODULE_INFO) &&
124109506Sjmallett                                path.getFileName().toString().endsWith(".class"))
125109506Sjmallett                .map(path -> MODS_DIR.relativize(path))
126109506Sjmallett                .forEach(path -> {
127109506Sjmallett                    try {
128109506Sjmallett                        Path newFile = NEW_MODS_DIR.resolve(path);
129109506Sjmallett                        Files.createDirectories(newFile.getParent());
130109506Sjmallett                        Files.copy(MODS_DIR.resolve(path), newFile);
131109506Sjmallett                    } catch (IOException e) {
132109506Sjmallett                        throw new UncheckedIOException(e);
133109506Sjmallett                    }
134109506Sjmallett                });
135109506Sjmallett
136109506Sjmallett        // compile new module-info.java
13799193Sjmallett        assertTrue(CompilerUtils.compileModule(DEST_DIR, NEW_MODS_DIR, UNSUPPORTED,
13899193Sjmallett                        "-mp", NEW_MODS_DIR.toString(), "-verbose",
139109506Sjmallett                        "-XaddExports:java.base/jdk.internal.perf=" + UNSUPPORTED));
14099193Sjmallett        Arrays.asList("m1", "m2", "m3")
14199193Sjmallett              .forEach(mn -> assertTrue(CompilerUtils.compileModule(DEST_DIR, NEW_MODS_DIR,
14299193Sjmallett                                        mn, "-mp", NEW_MODS_DIR.toString())));
14399193Sjmallett
14499193Sjmallett        for (String mn : modules) {
14599193Sjmallett            Path p1 = NEW_MODS_DIR.resolve(mn).resolve(MODULE_INFO);
14699823Sjmallett            Path p2 = MODS_DIR.resolve(mn).resolve(MODULE_INFO);
14799823Sjmallett
148109506Sjmallett            try (InputStream in1 = Files.newInputStream(p1);
149101687Sjmallett                 InputStream in2 = Files.newInputStream(p2)) {
150105737Sjmallett                verify(ModuleDescriptor.read(in1),
15199193Sjmallett                        ModuleDescriptor.read(in2, () -> packages(MODS_DIR.resolve(mn))));
152109506Sjmallett            }
153109506Sjmallett        }
154109506Sjmallett    }
155109506Sjmallett
156109506Sjmallett    private void verify(ModuleDescriptor md1, ModuleDescriptor md2) {
157109506Sjmallett        System.out.println("verifying: " + md1.name());
158109506Sjmallett        assertEquals(md1.name(), md2.name());
159109506Sjmallett        assertEquals(md1.requires(), md2.requires());
160109506Sjmallett        // all packages are exported
161109506Sjmallett        assertEquals(md1.exports().stream()
16299193Sjmallett                                  .map(ModuleDescriptor.Exports::source)
163109462Sjmallett                                  .collect(Collectors.toSet()), md2.packages());
16499193Sjmallett    }
16599193Sjmallett
16699193Sjmallett    private Set<String> packages(Path dir) {
16799193Sjmallett        try {
16899193Sjmallett            return Files.find(dir, Integer.MAX_VALUE,
169                             ((path, attrs) -> attrs.isRegularFile() &&
170                                               path.toString().endsWith(".class")))
171                        .map(path -> toPackageName(dir.relativize(path)))
172                        .filter(pkg -> pkg.length() > 0)   // module-info
173                        .distinct()
174                        .collect(Collectors.toSet());
175        } catch (IOException x) {
176            throw new UncheckedIOException(x);
177        }
178    }
179
180    private String toPackageName(Path path) {
181        String name = path.toString();
182        assert name.endsWith(".class");
183        int index = name.lastIndexOf(File.separatorChar);
184        if (index != -1) {
185            return name.substring(0, index).replace(File.separatorChar, '.');
186        } else {
187            return "";
188        }
189    }
190
191    /*
192     * Runs jdeps with the given arguments
193     */
194    public static String[] jdeps(String... args) {
195        String lineSep =     System.getProperty("line.separator");
196        StringWriter sw = new StringWriter();
197        PrintWriter pw = new PrintWriter(sw);
198        System.err.println("jdeps " + Arrays.toString(args));
199        int rc = com.sun.tools.jdeps.Main.run(args, pw);
200        pw.close();
201        String out = sw.toString();
202        if (!out.isEmpty())
203            System.err.println(out);
204        if (rc != 0)
205            throw new Error("jdeps failed: rc=" + rc);
206        return out.split(lineSep);
207    }
208
209    /**
210     * Create a jar file using the list of files provided.
211     */
212    public static void createJar(Path jarfile, Path root, Stream<Path> files)
213            throws IOException {
214        try (JarOutputStream target = new JarOutputStream(
215                Files.newOutputStream(jarfile))) {
216           files.forEach(file -> add(root.relativize(file), file, target));
217        }
218    }
219
220    private static void add(Path path, Path source, JarOutputStream target) {
221        try {
222            String name = path.toString().replace(File.separatorChar, '/');
223            JarEntry entry = new JarEntry(name);
224            entry.setTime(source.toFile().lastModified());
225            target.putNextEntry(entry);
226            Files.copy(source, target);
227            target.closeEntry();
228        } catch (IOException e) {
229            throw new UncheckedIOException(e);
230        }
231    }
232
233}
234