1 /* 2 * Copyright (c) 2015, 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 * @bug 8161906 8161596 27 * @summary tests for "requires static" 28 * @library /tools/lib 29 * @modules 30 * jdk.compiler/com.sun.tools.javac.api 31 * jdk.compiler/com.sun.tools.javac.main 32 * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase 33 * @run main RequiresStaticTest 34 */ 35 36 import java.io.File; 37 import java.nio.file.Files; 38 import java.nio.file.Path; 39 40 import toolbox.JavaTask; 41 import toolbox.JavacTask; 42 import toolbox.Task; 43 import toolbox.Task.OutputKind; 44 45 public class RequiresStaticTest extends ModuleTestBase { 46 47 public static void main(String... args) throws Exception { 48 RequiresStaticTest t = new RequiresStaticTest(); 49 t.runTests(); 50 } 51 52 @Test 53 public void testJavaSE_OK(Path base) throws Exception { 54 Path src = base.resolve("src"); 55 tb.writeJavaFiles(src, 56 "module m { requires static java.se; }", 57 "import java.awt.Frame;\n" // in java.se 58 + "class Test {\n" 59 + " Frame f;\n" 60 + "}"); 61 Path classes = base.resolve("classes"); 62 Files.createDirectories(classes); 63 64 new JavacTask(tb, Task.Mode.CMDLINE) 65 .files(findJavaFiles(src)) 66 .outdir(classes) 67 .run() 68 .writeAll(); 69 } 70 71 @Test 72 public void testJavaSE_Fail(Path base) throws Exception { 73 Path src = base.resolve("src"); 74 tb.writeJavaFiles(src, 75 "module m { requires static java.se; }", 76 "import com.sun.source.tree.Tree;\n" // not in java.se (in jdk.compiler) 77 + "class Test {\n" 78 + " Tree t;\n" 79 + "}"); 80 Path classes = base.resolve("classes"); 81 Files.createDirectories(classes); 82 83 String log = new JavacTask(tb, Task.Mode.CMDLINE) 84 .options("-XDrawDiagnostics") 85 .files(findJavaFiles(src)) 86 .outdir(classes) 87 .run(Task.Expect.FAIL) 88 .writeAll() 89 .getOutput(Task.OutputKind.DIRECT); 90 91 if (!log.contains("Test.java:1:27: compiler.err.doesnt.exist: com.sun.source.tree")) 92 throw new Exception("expected output not found"); 93 } 94 95 @Test 96 public void testComplex_OK(Path base) throws Exception { 97 Path src = getComplexSrc(base, "", ""); 98 Path classes = base.resolve("classes"); 99 Files.createDirectories(classes); 100 101 new JavacTask(tb, Task.Mode.CMDLINE) 102 .options("--module-source-path", src.toString()) 103 .files(findJavaFiles(src)) 104 .outdir(classes) 105 .run() 106 .writeAll(); 107 } 108 109 @Test 110 public void testComplex_Fail(Path base) throws Exception { 111 Path src = getComplexSrc(base, 112 "import p5.C5; import p6.C6; import p7.C7; import p8.C8;\n", 113 "C5 c5; C6 c6; C7 c7; C8 c8;\n"); 114 Path classes = base.resolve("classes"); 115 Files.createDirectories(classes); 116 117 String log = new JavacTask(tb, Task.Mode.CMDLINE) 118 .options("-XDrawDiagnostics", 119 "--module-source-path", src.toString()) 120 .files(findJavaFiles(src)) 121 .outdir(classes) 122 .run(Task.Expect.FAIL) 123 .writeAll() 124 .getOutput(Task.OutputKind.DIRECT); 125 126 String[] expect = { 127 "C1.java:5:10: compiler.err.not.def.access.package.cant.access: p5.C5, p5", 128 "C1.java:5:24: compiler.err.not.def.access.package.cant.access: p6.C6, p6", 129 "C1.java:5:38: compiler.err.not.def.access.package.cant.access: p7.C7, p7", 130 "C1.java:5:52: compiler.err.not.def.access.package.cant.access: p8.C8, p8", 131 "C1.java:8:1: compiler.err.cant.resolve.location: kindname.class, C5, , , " 132 + "(compiler.misc.location: kindname.class, p1.C1, null)", 133 "C1.java:8:8: compiler.err.cant.resolve.location: kindname.class, C6, , , " 134 + "(compiler.misc.location: kindname.class, p1.C1, null)", 135 "C1.java:8:15: compiler.err.cant.resolve.location: kindname.class, C7, , , " 136 + "(compiler.misc.location: kindname.class, p1.C1, null)", 137 "C1.java:8:22: compiler.err.cant.resolve.location: kindname.class, C8, , , " 138 + "(compiler.misc.location: kindname.class, p1.C1, null)" 139 }; 140 141 for (String e: expect) { 142 if (!log.contains(e)) 143 throw new Exception("expected output not found: " + e); 144 } 145 } 146 147 /* 148 * Set up the following module graph 149 * m1 -> m2 => m3 -=-> m4 --> m5 150 * \ / 151 * \ / 152 * v v 153 * m6 => m7 --> m8 154 * where -> is requires, => is requires transitive, --> is requires static, -=-> is requires transitive static 155 */ 156 Path getComplexSrc(Path base, String m1_extraImports, String m1_extraUses) throws Exception { 157 Path src = base.resolve("src"); 158 159 Path src_m1 = src.resolve("m1"); 160 tb.writeJavaFiles(src_m1, 161 "module m1 { requires m2; }", 162 "package p1;\n" 163 + "import p2.C2;\n" 164 + "import p3.C3;\n" 165 + "import p4.C4;\n" 166 + m1_extraImports 167 + "class C1 {\n" 168 + " C2 c2; C3 c3; C4 c4;\n" 169 + m1_extraUses 170 + "}\n"); 171 172 Path src_m2 = src.resolve("m2"); 173 tb.writeJavaFiles(src_m2, 174 "module m2 {\n" 175 + " requires transitive m3;\n" 176 + " requires static m6;\n" 177 + " exports p2;\n" 178 + "}", 179 "package p2;\n" 180 + "public class C2 {p7.C7 c7; p6.C6 c6; p4.C4 c4;}\n"); 181 182 Path src_m3 = src.resolve("m3"); 183 tb.writeJavaFiles(src_m3, 184 "module m3 { requires transitive static m4; exports p3; }", 185 "package p3;\n" 186 + "public class C3 { }\n"); 187 188 Path src_m4 = src.resolve("m4"); 189 tb.writeJavaFiles(src_m4, 190 "module m4 { requires m5; requires static m6; exports p4; }", 191 "package p4;\n" 192 + "public class C4 { p6.C6 c6; p7.C7 c7;}\n"); 193 194 Path src_m5 = src.resolve("m5"); 195 tb.writeJavaFiles(src_m5, 196 "module m5 { exports p5; }", 197 "package p5;\n" 198 + "public class C5 { }\n"); 199 200 Path src_m6 = src.resolve("m6"); 201 tb.writeJavaFiles(src_m6, 202 "module m6 { requires transitive m7; exports p6; }", 203 "package p6;\n" 204 + "public class C6 { p7.C7 c7; }\n"); 205 206 Path src_m7 = src.resolve("m7"); 207 tb.writeJavaFiles(src_m7, 208 "module m7 { requires static m8; exports p7; }", 209 "package p7;\n" 210 + "public class C7 { p8.C8 c8; }\n"); 211 212 Path src_m8 = src.resolve("m8"); 213 tb.writeJavaFiles(src_m8, 214 "module m8 { exports p8; }", 215 "package p8;\n" 216 + "public class C8 { }\n"); 217 218 return src; 219 } 220 221 @Test 222 public void testRequiresStatic(Path base) throws Exception { 223 Path src = base.resolve("src"); 224 Path m1 = src.resolve("m1"); 225 tb.writeJavaFiles(m1, 226 "module m1 { exports m1; }", 227 "package m1;" + 228 "public class Api { }\n"); 229 230 Path classes = base.resolve("classes"); 231 Path m1Classes = classes.resolve("m1"); 232 Files.createDirectories(m1Classes); 233 234 new JavacTask(tb, Task.Mode.CMDLINE) 235 .files(findJavaFiles(m1)) 236 .outdir(m1Classes) 237 .run() 238 .writeAll(); 239 240 Path m3 = src.resolve("m3"); 241 tb.writeJavaFiles(m3, 242 "module m3 { requires static m1; }", 243 "package m3;\n" + 244 "public class Test {\n" + 245 " public static void main(String... args) {\n" + 246 " try {\n" + 247 " Class.forName(\"m1.Api\");\n" + 248 " } catch (ClassNotFoundException e) {\n" + 249 " System.err.println(\"ok\");\n" + 250 " }\n" + 251 " }\n" + 252 "}", 253 "package m3;\n" + 254 "public class ApiUse{\n" + 255 " m1.Api api;\n" + 256 "}"); 257 258 Path m3Classes = classes.resolve("m3"); 259 Files.createDirectories(m3Classes); 260 261 new JavacTask(tb, Task.Mode.CMDLINE) 262 .options("--module-path", m1Classes.toString()) 263 .files(findJavaFiles(m3)) 264 .outdir(m3Classes) 265 .run() 266 .writeAll(); 267 268 String log = new JavaTask(tb) 269 .vmOptions("--module-path", m3Classes.toString(), "--add-modules", "m3") 270 .className("m3.Test") 271 .run() 272 .writeAll() 273 .getOutput(OutputKind.STDERR); 274 275 String expected = "ok" + System.getProperty("line.separator"); 276 277 if (!expected.equals(log)) { 278 throw new AssertionError("Unexpected output: " + log); 279 } 280 } 281 282 @Test 283 public void testRequiresTransitiveStatic(Path base) throws Exception { 284 Path src = base.resolve("src"); 285 Path m1 = src.resolve("m1"); 286 tb.writeJavaFiles(m1, 287 "module m1 { exports m1; }", 288 "package m1;" + 289 "public class Api { }\n"); 290 291 Path classes = base.resolve("classes"); 292 Path m1Classes = classes.resolve("m1"); 293 Files.createDirectories(m1Classes); 294 295 new JavacTask(tb, Task.Mode.CMDLINE) 296 .files(findJavaFiles(m1)) 297 .outdir(m1Classes) 298 .run() 299 .writeAll(); 300 301 Path m2 = src.resolve("m2"); 302 tb.writeJavaFiles(m2, 303 "module m2 { requires transitive static m1; }"); 304 305 Path m2Classes = classes.resolve("m2"); 306 Files.createDirectories(m2Classes); 307 308 new JavacTask(tb, Task.Mode.CMDLINE) 309 .options("--module-path", m1Classes.toString()) 310 .files(findJavaFiles(m2)) 311 .outdir(m2Classes) 312 .run() 313 .writeAll(); 314 315 Path m3 = src.resolve("m3"); 316 tb.writeJavaFiles(m3, 317 "module m3 { requires m2; }", 318 "package m3;\n" + 319 "public class Test {\n" + 320 " public static void main(String... args) {\n" + 321 " try {\n" + 322 " Class.forName(\"m1.Api\");\n" + 323 " } catch (ClassNotFoundException e) {\n" + 324 " System.err.println(\"ok\");\n" + 325 " }\n" + 326 " }\n" + 327 "}", 328 "package m3;\n" + 329 "public class ApiUse{\n" + 330 " m1.Api api;\n" + 331 "}"); 332 333 Path m3Classes = classes.resolve("m3"); 334 Files.createDirectories(m3Classes); 335 336 new JavacTask(tb, Task.Mode.CMDLINE) 337 .options("--module-path", m1Classes.toString() + File.pathSeparator + m2Classes.toString()) 338 .files(findJavaFiles(m3)) 339 .outdir(m3Classes) 340 .run() 341 .writeAll(); 342 343 String log = new JavaTask(tb) 344 .vmOptions("--module-path", m2Classes.toString() + File.pathSeparator + m3Classes.toString(), 345 "--add-modules", "m3") 346 .className("m3.Test") 347 .run() 348 .writeAll() 349 .getOutput(OutputKind.STDERR); 350 351 String expected = "ok" + System.getProperty("line.separator"); 352 353 if (!expected.equals(log)) { 354 throw new AssertionError("Unexpected output: " + log); 355 } 356 } 357 358 @Test 359 public void testRequiresStaticTransitive(Path base) throws Exception { 360 Path src = base.resolve("src"); 361 Path m1 = src.resolve("m1"); 362 tb.writeJavaFiles(m1, 363 "module m1 { exports m1; }", 364 "package m1;" + 365 "public class Api { }\n"); 366 367 Path classes = base.resolve("classes"); 368 Path m1Classes = classes.resolve("m1"); 369 Files.createDirectories(m1Classes); 370 371 new JavacTask(tb, Task.Mode.CMDLINE) 372 .files(findJavaFiles(m1)) 373 .outdir(m1Classes) 374 .run() 375 .writeAll(); 376 377 Path m2 = src.resolve("m2"); 378 tb.writeJavaFiles(m2, 379 "module m2 { requires transitive static m1; }"); 380 381 Path m2Classes = classes.resolve("m2"); 382 Files.createDirectories(m2Classes); 383 384 new JavacTask(tb, Task.Mode.CMDLINE) 385 .options("--module-path", m1Classes.toString()) 386 .files(findJavaFiles(m2)) 387 .outdir(m2Classes) 388 .run() 389 .writeAll(); 390 } 391 }