1 /* 2 * Copyright (c) 2016, 2019, 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 8146946 8176743 8200286 27 * @summary implement javac -m option 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 MOptionTest 34 */ 35 36 import java.nio.file.Files; 37 import java.nio.file.Path; 38 import java.nio.file.attribute.FileTime; 39 40 import toolbox.JavacTask; 41 import toolbox.Task; 42 43 public class MOptionTest extends ModuleTestBase { main(String... args)44 public static void main(String... args) throws Exception { 45 new MOptionTest().runTests(); 46 } 47 48 @Test testOneModule(Path base)49 public void testOneModule(Path base) throws Exception { 50 Path src = base.resolve("src"); 51 Path m1 = src.resolve("m1x"); 52 Path build = base.resolve("build"); 53 Files.createDirectories(build); 54 55 tb.writeJavaFiles(m1, 56 "module m1x {}", 57 "package test; public class Test {}"); 58 59 new JavacTask(tb) 60 .options("-m", "m1x", "--module-source-path", src.toString(), "-d", build.toString()) 61 .run(Task.Expect.SUCCESS) 62 .writeAll(); 63 64 Path moduleInfoClass = build.resolve("m1x/module-info.class"); 65 Path testTestClass = build.resolve("m1x/test/Test.class"); 66 67 FileTime moduleInfoTimeStamp = Files.getLastModifiedTime(moduleInfoClass); 68 FileTime testTestTimeStamp = Files.getLastModifiedTime(testTestClass); 69 70 Path moduleInfo = m1.resolve("module-info.java"); 71 if (moduleInfoTimeStamp.compareTo(Files.getLastModifiedTime(moduleInfo)) < 0) { 72 throw new AssertionError("Classfiles too old!"); 73 } 74 75 Path testTest = m1.resolve("test/Test.java"); 76 if (testTestTimeStamp.compareTo(Files.getLastModifiedTime(testTest)) < 0) { 77 throw new AssertionError("Classfiles too old!"); 78 } 79 80 Thread.sleep(2000); //timestamps 81 82 new JavacTask(tb) 83 .options("-m", "m1x", "--module-source-path", src.toString(), "-d", build.toString()) 84 .run(Task.Expect.SUCCESS) 85 .writeAll(); 86 87 if (!moduleInfoTimeStamp.equals(Files.getLastModifiedTime(moduleInfoClass))) { 88 throw new AssertionError("Classfile update!"); 89 } 90 91 if (!testTestTimeStamp.equals(Files.getLastModifiedTime(testTestClass))) { 92 throw new AssertionError("Classfile update!"); 93 } 94 95 // Date back the source file by one second compared to the current time. 96 // Cases have been observed where the resulting class file had an earlier 97 // timestamp than the java source. 98 Files.setLastModifiedTime(testTest, FileTime.fromMillis(System.currentTimeMillis() - 1000)); 99 100 new JavacTask(tb) 101 .options("-m", "m1x", "--module-source-path", src.toString(), "-d", build.toString()) 102 .run(Task.Expect.SUCCESS) 103 .writeAll(); 104 105 if (!moduleInfoTimeStamp.equals(Files.getLastModifiedTime(moduleInfoClass))) { 106 throw new AssertionError("Classfile update!"); 107 } 108 109 if (Files.getLastModifiedTime(testTestClass).compareTo(Files.getLastModifiedTime(testTest)) < 0) { 110 throw new AssertionError("Classfiles too old!"); 111 } 112 } 113 114 @Test testNoOutputDir(Path base)115 public void testNoOutputDir(Path base) throws Exception { 116 Path src = base.resolve("src"); 117 Path m1 = src.resolve("m1x"); 118 Path build = base.resolve("build"); 119 Files.createDirectories(build); 120 121 tb.writeJavaFiles(m1, 122 "module m1x {}", 123 "package test; public class Test {}"); 124 125 String log = new JavacTask(tb) 126 .options("-XDrawDiagnostics", 127 "-m", "m1x", 128 "--module-source-path", src.toString()) 129 .run(Task.Expect.FAIL) 130 .writeAll() 131 .getOutput(Task.OutputKind.DIRECT); 132 133 if (!log.contains("- compiler.err.output.dir.must.be.specified.with.dash.m.option")) 134 throw new Exception("expected output not found"); 135 } 136 137 @Test testNoModuleSourcePath(Path base)138 public void testNoModuleSourcePath(Path base) throws Exception { 139 Path src = base.resolve("src"); 140 Path m1 = src.resolve("m1x"); 141 Path build = base.resolve("build"); 142 Files.createDirectories(build); 143 144 tb.writeJavaFiles(m1, 145 "module m1x {}", 146 "package test; public class Test {}"); 147 148 String log = new JavacTask(tb) 149 .options("-XDrawDiagnostics", 150 "-m", "m1x", 151 "-d", build.toString()) 152 .run(Task.Expect.FAIL) 153 .writeAll() 154 .getOutput(Task.OutputKind.DIRECT); 155 156 if (!log.contains("- compiler.err.modulesourcepath.must.be.specified.with.dash.m.option")) 157 throw new Exception("expected output not found"); 158 } 159 160 @Test testMultiModule(Path base)161 public void testMultiModule(Path base) throws Exception { 162 Path src = base.resolve("src"); 163 Path m1 = src.resolve("m1x"); 164 Path m2 = src.resolve("m2x"); 165 Path build = base.resolve("build"); 166 Files.createDirectories(build); 167 168 tb.writeJavaFiles(m1, 169 "module m1x {}", 170 "package p1; public class C1 {}"); 171 172 tb.writeJavaFiles(m2, 173 "module m2x {}", 174 "package p2; public class C2 {}"); 175 176 new JavacTask(tb) 177 .options("-m", "m1x,m2x", "--module-source-path", src.toString(), "-d", build.toString()) 178 .run(Task.Expect.SUCCESS) 179 .writeAll(); 180 181 Path m1ModuleInfoClass = build.resolve("m1x/module-info.class"); 182 Path classC1 = build.resolve("m1x/p1/C1.class"); 183 184 Path m2ModuleInfoClass = build.resolve("m2x/module-info.class"); 185 Path classC2 = build.resolve("m2x/p2/C2.class"); 186 187 FileTime m1ModuleInfoTimeStamp = Files.getLastModifiedTime(m1ModuleInfoClass); 188 FileTime C1TimeStamp = Files.getLastModifiedTime(classC1); 189 190 FileTime m2ModuleInfoTimeStamp = Files.getLastModifiedTime(m2ModuleInfoClass); 191 FileTime C2TimeStamp = Files.getLastModifiedTime(classC2); 192 193 Path m1ModuleInfo = m1.resolve("module-info.java"); 194 Path m2ModuleInfo = m2.resolve("module-info.java"); 195 196 if (m1ModuleInfoTimeStamp.compareTo(Files.getLastModifiedTime(m1ModuleInfo)) < 0) { 197 throw new AssertionError("Classfiles too old!"); 198 } 199 200 if (m2ModuleInfoTimeStamp.compareTo(Files.getLastModifiedTime(m2ModuleInfo)) < 0) { 201 throw new AssertionError("Classfiles too old!"); 202 } 203 204 Path C1Source = m1.resolve("p1/C1.java"); 205 Path C2Source = m2.resolve("p2/C2.java"); 206 207 if (C1TimeStamp.compareTo(Files.getLastModifiedTime(C1Source)) < 0) { 208 throw new AssertionError("Classfiles too old!"); 209 } 210 211 if (C2TimeStamp.compareTo(Files.getLastModifiedTime(C2Source)) < 0) { 212 throw new AssertionError("Classfiles too old!"); 213 } 214 215 Thread.sleep(2000); //timestamps 216 217 new JavacTask(tb) 218 .options("-m", "m1x,m2x", "--module-source-path", src.toString(), "-d", build.toString()) 219 .run(Task.Expect.SUCCESS) 220 .writeAll(); 221 222 if (!m1ModuleInfoTimeStamp.equals(Files.getLastModifiedTime(m1ModuleInfoClass))) { 223 throw new AssertionError("Classfile update!"); 224 } 225 226 if (!m2ModuleInfoTimeStamp.equals(Files.getLastModifiedTime(m2ModuleInfoClass))) { 227 throw new AssertionError("Classfile update!"); 228 } 229 230 if (!C1TimeStamp.equals(Files.getLastModifiedTime(classC1))) { 231 throw new AssertionError("Classfile update!"); 232 } 233 234 if (!C2TimeStamp.equals(Files.getLastModifiedTime(classC2))) { 235 throw new AssertionError("Classfile update!"); 236 } 237 238 // Date back the source file by one second compared to the current time. 239 // Cases have been observed where the resulting class file had an earlier 240 // timestamp than the java source. 241 Files.setLastModifiedTime(C1Source, FileTime.fromMillis(System.currentTimeMillis() - 1000)); 242 Files.setLastModifiedTime(C2Source, FileTime.fromMillis(System.currentTimeMillis() - 1000)); 243 244 new JavacTask(tb) 245 .options("-m", "m1x,m2x", "--module-source-path", src.toString(), "-d", build.toString()) 246 .run(Task.Expect.SUCCESS) 247 .writeAll(); 248 249 if (!m1ModuleInfoTimeStamp.equals(Files.getLastModifiedTime(m1ModuleInfoClass))) { 250 throw new AssertionError("Classfile update!"); 251 } 252 253 if (!m2ModuleInfoTimeStamp.equals(Files.getLastModifiedTime(m2ModuleInfoClass))) { 254 throw new AssertionError("Classfile update!"); 255 } 256 257 if (Files.getLastModifiedTime(classC1).compareTo(Files.getLastModifiedTime(C1Source)) < 0) { 258 throw new AssertionError("Classfiles too old!"); 259 } 260 261 if (Files.getLastModifiedTime(classC2).compareTo(Files.getLastModifiedTime(C2Source)) < 0) { 262 throw new AssertionError("Classfiles too old!"); 263 } 264 } 265 } 266