1 /* 2 * Copyright (c) 2015, 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 * @library ../../lib /lib/testlibrary 27 * @modules java.base/jdk.internal.module 28 * @build OverlappingExportedPackagesTest CompilerUtils 29 * @build jdk.testlibrary.OutputAnalyzer jdk.testlibrary.ProcessTools 30 * @run testng OverlappingExportedPackagesTest 31 * @summary Test API and runtime behavior if two or more modules export 32 * the same package. 33 */ 34 35 import java.io.OutputStream; 36 import java.nio.file.Path; 37 import java.nio.file.Paths; 38 import java.nio.file.Files; 39 import java.util.Arrays; 40 import java.util.stream.Collectors; 41 42 import java.lang.module.Configuration; 43 import java.lang.module.ModuleDescriptor; 44 import java.lang.module.ModuleFinder; 45 import java.lang.module.ResolutionException; 46 47 import java.lang.reflect.Layer; 48 import java.util.Set; 49 import java.util.regex.Pattern; 50 import java.util.stream.Stream; 51 52 import jdk.testlibrary.OutputAnalyzer; 53 import static jdk.testlibrary.ProcessTools.*; 54 55 import jdk.internal.module.ModuleInfoWriter; 56 57 import org.testng.annotations.Test; 58 import static org.testng.Assert.*; 59 60 @Test 61 public class OverlappingExportedPackagesTest { 62 63 private static final String TEST_SRC = System.getProperty("test.src"); 64 65 private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); 66 67 private static final String DUP_2_MODULES = 68 "Modules m. and m. export package p to module test"; 69 70 //a package name 71 private static final String P = "p"; 72 //some module names 73 private static final String M1 = "m1", M2 = "m2", M3 = "m3", M4 = "m4", 74 TEST = "test"; 75 76 /** 77 * Duplicate package p. 78 */ 79 public void testOverlap() throws Exception { 80 Path root = Paths.get("overlap"); 81 write(root, init(M1).exports(P).build()); 82 write(root, init(M2).exports(P).build()); 83 assertTrue(CompilerUtils.compile(SRC_DIR.resolve(TEST), 84 root.resolve(TEST))); 85 write(root, init(TEST).requires(M1).requires(M2).build()); 86 87 String exceptionMessage = assertAPIFail(root); 88 assertMatches(DUP_2_MODULES, exceptionMessage); 89 90 OutputAnalyzer output = runCommandLine(root, M1, M2); 91 assertNotEquals(output.getExitValue(), 0); 92 assertMatches(DUP_2_MODULES, output.getStdout()); 93 } 94 95 /** 96 * Triplicate package p. 97 */ 98 public void testOverlap3() throws Exception { 99 Path root = Paths.get("overlap"); 100 write(root, init(M1).exports(P).build()); 101 write(root, init(M2).exports(P).build()); 102 write(root, init(M3).exports(P).build()); 103 assertTrue(CompilerUtils.compile(SRC_DIR.resolve(TEST), 104 root.resolve(TEST))); 105 write(root, init(TEST).requires(M1).requires(M2).requires(M3).build()); 106 107 String exceptionMessage = assertAPIFail(root); 108 assertMatches(DUP_2_MODULES, exceptionMessage); 109 110 OutputAnalyzer output = runCommandLine(root, M1, M2); 111 assertNotEquals(output.getExitValue(), 0); 112 assertMatches(DUP_2_MODULES, output.getStdout()); 113 } 114 115 /** 116 * Duplicate package p is available directly and through "requires public". 117 */ 118 public void testOverlapRequiresPublic() throws Exception { 119 Path root = Paths.get("overlap_requires_public"); 120 write(root, init(M1).exports(P).build()); 121 write(root, init(M2).exports(P).build()); 122 write(root, init(M3).requires(ModuleDescriptor.Requires.Modifier.PUBLIC, 123 M2).build()); 124 CompilerUtils.compile(SRC_DIR.resolve(TEST), root.resolve(TEST)); 125 write(root, init(TEST).requires(M1).requires(M3).build()); 126 127 String exceptionMessage = assertAPIFail(root); 128 assertMatches(DUP_2_MODULES, exceptionMessage); 129 130 OutputAnalyzer output = runCommandLine(root, M1, M2); 131 assertNotEquals(output.getExitValue(), 0); 132 assertMatches(DUP_2_MODULES, output.getStdout()); 133 } 134 135 /** 136 * Duplicate package p is available directly and through a qualified export. 137 */ 138 public void testOverlapExportsTo() throws Exception { 139 Path root = Paths.get("overlap_exports_to"); 140 write(root, init(M1).exports(P).build()); 141 write(root, init(M2).exports(P, TEST).build()); 142 CompilerUtils.compile(SRC_DIR.resolve(TEST), root.resolve(TEST)); 143 write(root, init(TEST).requires(M1).requires(M2).build()); 144 145 String exceptionMessage = assertAPIFail(root); 146 assertMatches(DUP_2_MODULES, exceptionMessage); 147 148 OutputAnalyzer output = runCommandLine(root, M1, M2); 149 assertNotEquals(output.getExitValue(), 0); 150 assertMatches(DUP_2_MODULES, output.getStdout()); 151 } 152 153 /** 154 * Duplicate package p is available from a required module and also present 155 * in the module. 156 */ 157 public void testOverlapSelf() throws Exception { 158 Path root = Paths.get("overlap_itself"); 159 write(root, init(M1).exports(P).build()); 160 CompilerUtils.compile(SRC_DIR.resolve(TEST), root.resolve(TEST)); 161 write(root, init(TEST).exports(P).requires(M1).build()); 162 163 String error = "Module test contains package p, "+ 164 "module m1 exports package p to test"; 165 String exceptionMessage = assertAPIFail(root); 166 assertEquals(error, exceptionMessage); 167 168 OutputAnalyzer output = runCommandLine(root, M1); 169 assertNotEquals(output.getExitValue(), 0); 170 assertTrue(output.getStdout().contains(error)); 171 } 172 173 /** 174 * Duplicate package p is exported to different modules. 175 */ 176 public void testOverlapQualified() throws Exception { 177 Path root = Paths.get("overlap_qualified"); 178 write(root, init(M1).exports(P, M3).build()); 179 write(root, init(M2).exports(P, M4).build()); 180 write(root, init(M3).requires(M1).build()); 181 write(root, init(M4).requires(M2).build()); 182 CompilerUtils.compile(SRC_DIR.resolve(TEST), root.resolve(TEST)); 183 write(root, init(TEST).requires(M3).requires(M4).build()); 184 185 assertAPIPass(root, M1, M2, M3, M4); 186 187 OutputAnalyzer output = runCommandLine(root, M1, M2, M3, M4); 188 assertNotEquals(output.getExitValue(), 0); 189 assertTrue(output.getStdout(). 190 contains("Package p in both module m2 and module m1")); 191 } 192 193 private Configuration doRunAPI(Path root) { 194 ModuleFinder finder = ModuleFinder.of(root); 195 return Configuration.resolve(ModuleFinder.empty(), 196 Layer.boot(), finder, TEST).bind(); 197 } 198 199 private void assertAPIPass(Path root, String... modules) { 200 Set<ModuleDescriptor> descriptors = doRunAPI(root).descriptors(); 201 assertTrue(Stream.of(modules). 202 allMatch(m -> descriptors.stream(). 203 anyMatch(d -> d.name().equals(m)))); 204 } 205 206 private String assertAPIFail(Path root) { 207 try { 208 doRunAPI(root); 209 throw new RuntimeException("No resolution exception"); 210 } catch(ResolutionException e) { 211 System.out.println("Exception as expected"); 212 e.printStackTrace(System.out); 213 return e.getMessage(); 214 } 215 } 216 217 private OutputAnalyzer runCommandLine(Path root, String... modules) 218 throws Exception { 219 return executeTestJava("-mp", root.toString(), 220 "-addmods", Arrays.stream(modules). 221 collect(Collectors.joining(",")), 222 "-m", "test/test.Main") 223 .outputTo(System.out) 224 .errorTo(System.err); 225 } 226 227 private static ModuleDescriptor.Builder init(String name) { 228 return new ModuleDescriptor.Builder(name).requires("java.base"); 229 } 230 231 private static void write(Path root, ModuleDescriptor descriptor) 232 throws Exception { 233 Path mRoot = root.resolve(descriptor.name()); 234 Files.createDirectories(mRoot); 235 Path mi = mRoot.resolve("module-info.class"); 236 try (OutputStream out = Files.newOutputStream(mi)) { 237 ModuleInfoWriter.write(descriptor, out); 238 } 239 } 240 241 private static void assertMatches(String regex, CharSequence text) { 242 if(!Pattern.compile(regex).matcher(text).find()) { 243 fail("Regex: \"" + regex + "\" is not matched by text: \n" + text); 244 } 245 } 246 }