1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @summary Tests jdeps --gen-module-info option 27 * @library ../lib 28 * @build CompilerUtils JdepsUtil 29 * @modules jdk.jdeps/com.sun.tools.jdeps 30 * @run testng GenModuleInfo 31 */ 32 33 import java.io.*; 34 import java.lang.module.ModuleDescriptor; 35 36 import java.nio.file.Files; 37 import java.nio.file.Path; 38 import java.nio.file.Paths; 39 40 import java.util.Arrays; 41 import java.util.Set; 42 import java.util.stream.Collectors; 43 import java.util.stream.Stream; 44 45 import org.testng.annotations.BeforeTest; 46 import org.testng.annotations.Test; 47 48 import static org.testng.Assert.assertEquals; 49 import static org.testng.Assert.assertTrue; 50 51 public class GenModuleInfo { 52 private static final String MODULE_INFO = "module-info.class"; 53 private static final String TEST_SRC = System.getProperty("test.src"); 54 private static final String TEST_CLASSES = System.getProperty("test.classes"); 55 56 private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); 57 private static final Path MODS_DIR = Paths.get("mods"); 58 private static final Path LIBS_DIR = Paths.get("libs"); 59 private static final Path DEST_DIR = Paths.get("moduleinfosrc"); 60 private static final Path NEW_MODS_DIR = Paths.get("new_mods"); 61 62 // the names of the modules in this test 63 private static final String UNSUPPORTED = "unsupported"; 64 private static String[] modules = new String[] {"m1", "m2", "m3", UNSUPPORTED}; 65 /** 66 * Compiles all modules used by the test 67 */ 68 @BeforeTest 69 public void compileAll() throws Exception { 70 CompilerUtils.cleanDir(MODS_DIR); 71 CompilerUtils.cleanDir(LIBS_DIR); 72 CompilerUtils.cleanDir(DEST_DIR); 73 CompilerUtils.cleanDir(NEW_MODS_DIR); 74 75 assertTrue(CompilerUtils.compileModule(SRC_DIR, MODS_DIR, UNSUPPORTED, 76 "--add-exports", "java.base/jdk.internal.perf=" + UNSUPPORTED)); 77 Arrays.asList("m1", "m2", "m3") 78 .forEach(mn -> assertTrue(CompilerUtils.compileModule(SRC_DIR, MODS_DIR, mn))); 79 80 Files.createDirectory(LIBS_DIR); 81 Files.createDirectory(DEST_DIR); 82 83 for (String mn : modules) { 84 Path root = MODS_DIR.resolve(mn); 85 try (Stream<Path> stream = Files.walk(root, Integer.MAX_VALUE)) { 86 Stream<Path> entries = stream.filter(f -> { 87 String fn = f.getFileName().toString(); 88 return fn.endsWith(".class") && !fn.equals("module-info.class"); 89 }); 90 JdepsUtil.createJar(LIBS_DIR.resolve(mn + ".jar"), root, entries); 91 } 92 } 93 } 94 95 @Test 96 public void jdeps() throws IOException { 97 Stream<String> files = Arrays.stream(modules) 98 .map(mn -> LIBS_DIR.resolve(mn + ".jar")) 99 .map(Path::toString); 100 JdepsUtil.jdeps(Stream.concat(Stream.of("-cp"), files).toArray(String[]::new)); 101 } 102 103 @Test 104 public void test() throws IOException { 105 Stream<String> files = Arrays.stream(modules) 106 .map(mn -> LIBS_DIR.resolve(mn + ".jar")) 107 .map(Path::toString); 108 109 JdepsUtil.jdeps(Stream.concat(Stream.of("--gen-module-info", DEST_DIR.toString()), 110 files).toArray(String[]::new)); 111 112 // check file exists 113 Arrays.stream(modules) 114 .map(mn -> DEST_DIR.resolve(mn).resolve("module-info.java")) 115 .forEach(f -> assertTrue(Files.exists(f))); 116 117 // copy classes except the original module-info.class 118 try (Stream<Path> stream = Files.walk(MODS_DIR, Integer.MAX_VALUE)) { 119 stream.filter(path -> !path.getFileName().toString().equals(MODULE_INFO) && 120 path.getFileName().toString().endsWith(".class")) 121 .map(path -> MODS_DIR.relativize(path)) 122 .forEach(path -> { 123 try { 124 Path newFile = NEW_MODS_DIR.resolve(path); 125 Files.createDirectories(newFile.getParent()); 126 Files.copy(MODS_DIR.resolve(path), newFile); 127 } catch (IOException e) { 128 throw new UncheckedIOException(e); 129 } 130 }); 131 } 132 133 // compile new module-info.java 134 assertTrue(CompilerUtils.compileModule(DEST_DIR, NEW_MODS_DIR, UNSUPPORTED, 135 "-p", NEW_MODS_DIR.toString(), "-verbose", 136 "--add-exports", "java.base/jdk.internal.perf=" + UNSUPPORTED)); 137 Arrays.asList("m1", "m2", "m3") 138 .forEach(mn -> assertTrue(CompilerUtils.compileModule(DEST_DIR, NEW_MODS_DIR, 139 mn, "-p", NEW_MODS_DIR.toString()))); 140 141 for (String mn : modules) { 142 Path p1 = NEW_MODS_DIR.resolve(mn).resolve(MODULE_INFO); 143 Path p2 = MODS_DIR.resolve(mn).resolve(MODULE_INFO); 144 145 try (InputStream in1 = Files.newInputStream(p1); 146 InputStream in2 = Files.newInputStream(p2)) { 147 verify(ModuleDescriptor.read(in1), 148 ModuleDescriptor.read(in2, () -> packages(MODS_DIR.resolve(mn)))); 149 } 150 } 151 } 152 153 private void verify(ModuleDescriptor md1, ModuleDescriptor md2) { 154 System.out.println("verifying: " + md1.name()); 155 assertEquals(md1.name(), md2.name()); 156 assertEquals(md1.requires(), md2.requires()); 157 // all packages are exported 158 assertEquals(md1.exports().stream() 159 .map(ModuleDescriptor.Exports::source) 160 .collect(Collectors.toSet()), md2.packages()); 161 } 162 163 private Set<String> packages(Path dir) { 164 try (Stream<Path> stream = Files.find(dir, Integer.MAX_VALUE, 165 ((path, attrs) -> attrs.isRegularFile() && 166 path.toString().endsWith(".class")))) { 167 return stream.map(path -> toPackageName(dir.relativize(path))) 168 .filter(pkg -> pkg.length() > 0) // module-info 169 .distinct() 170 .collect(Collectors.toSet()); 171 } catch (IOException x) { 172 throw new UncheckedIOException(x); 173 } 174 } 175 176 private String toPackageName(Path path) { 177 String name = path.toString(); 178 assert name.endsWith(".class"); 179 int index = name.lastIndexOf(File.separatorChar); 180 if (index != -1) { 181 return name.substring(0, index).replace(File.separatorChar, '.'); 182 } else { 183 return ""; 184 } 185 } 186 187 }