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