1 /*
  2  * Copyright (c) 2016, 2018, 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 8168836
 27  * @summary Basic argument validation for --patch-module
 28  * @library /test/lib
 29  * @modules jdk.compiler
 30  * @build PatchTestWarningError
 31  *        jdk.test.lib.compiler.CompilerUtils
 32  *        jdk.test.lib.util.JarUtils
 33  * @run testng PatchTestWarningError
 34  */
 35 
 36 import java.io.File;
 37 import java.nio.file.Files;
 38 import java.nio.file.Path;
 39 import java.nio.file.Paths;
 40 import java.util.stream.Collectors;
 41 import java.util.stream.Stream;
 42 
 43 import jdk.test.lib.compiler.CompilerUtils;
 44 import jdk.test.lib.util.JarUtils;
 45 import static jdk.test.lib.process.ProcessTools.*;
 46 
 47 import org.testng.annotations.BeforeTest;
 48 import org.testng.annotations.DataProvider;
 49 import org.testng.annotations.Test;
 50 import static org.testng.Assert.*;
 51 
 52 
 53 /**
 54  * This test
 55  * See PatchTestWarningError for test description.
 56  */
 57 
 58 @Test
 59 public class PatchTestWarningError {
 60 
 61     // top-level source directory
 62     private static final String TEST_SRC = System.getProperty("test.src");
 63 
 64     // source/destination tree for the test module
 65     private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
 66     private static final Path MODS_DIR = Paths.get("mods");
 67 
 68     // source/destination tree for patch tree 1
 69     private static final Path SRC1_DIR = Paths.get(TEST_SRC, "src1");
 70     private static final Path PATCHES1_DIR = Paths.get("patches1");
 71 
 72     // source/destination tree for patch tree 2
 73     private static final Path SRC2_DIR = Paths.get(TEST_SRC, "src2");
 74     private static final Path PATCHES2_DIR = Paths.get("patches2");
 75 
 76     // patch path for java.base
 77     private static final String PATCHES_PATH =
 78         PATCHES1_DIR.resolve("java.base") + File.pathSeparator +
 79             PATCHES2_DIR.resolve("java.base");
 80 
 81     // the classes overridden or added with --patch-module
 82     private static final String[] CLASSES = {
 83 
 84         // java.base = boot loader
 85         "java.base/java.text.Annotation",           // override class
 86         "java.base/java.text.AnnotationBuddy",      // add class to package
 87         "java.base/java.lang2.Object",              // new package
 88 
 89     };
 90 
 91 
 92     @BeforeTest
 93     public void setup() throws Exception {
 94 
 95         // javac -d mods/test src/test/**
 96         boolean compiled= CompilerUtils.compile(SRC_DIR.resolve("test"),
 97                                                 MODS_DIR.resolve("test"));
 98         assertTrue(compiled, "classes did not compile");
 99 
100         // javac --patch-module $MODULE=patches1/$MODULE -d patches1/$MODULE patches1/$MODULE/**
101         Path src = SRC1_DIR.resolve("java.base");
102         Path output = PATCHES1_DIR.resolve(src.getFileName());
103         Files.createDirectories(output);
104         String mn = src.getFileName().toString();
105         compiled  = CompilerUtils.compile(src, output,
106                                           "--patch-module", mn + "=" + src.toString());
107         assertTrue(compiled, "classes did not compile");
108 
109         // javac --patch-module $MODULE=patches2/$MODULE -d patches2/$MODULE patches2/$MODULE/**
110         src = SRC2_DIR.resolve("java.base");
111         output = PATCHES2_DIR.resolve(src.getFileName());
112         Files.createDirectories(output);
113         mn = src.getFileName().toString();
114         compiled  = CompilerUtils.compile(src, output,
115                                           "--patch-module", mn + "=" + src.toString());
116         assertTrue(compiled, "classes did not compile");
117 
118     }
119 
120     /**
121      * Test with --patch-module options patching the same module
122      */
123     public void testDuplicateModule() throws Exception {
124         int exitValue =
125             executeTestJava("--patch-module", "java.base=" + PATCHES1_DIR.resolve("java.base"),
126                             "--patch-module", "java.base=" + PATCHES2_DIR.resolve("java.base"),
127                             "--module-path", MODS_DIR.toString(),
128                             "-m", "test/jdk.test.Main")
129                 .outputTo(System.out)
130                 .errorTo(System.out)
131                 // error output by VM
132                 .shouldContain("Cannot specify java.base more than once to --patch-module")
133                 .getExitValue();
134 
135         assertTrue(exitValue != 0);
136     }
137 
138     /**
139      * Test with --patch-module options patching the same module (not java.base).
140      *
141      */
142     public void testDuplicateModuleLogging() throws Exception {
143         int exitValue =
144             executeTestJava("--patch-module", "java.logging=" + PATCHES1_DIR.resolve("java.base"),
145                             "--patch-module", "java.logging=" + PATCHES2_DIR.resolve("java.base"),
146                             "--module-path", MODS_DIR.toString(),
147                             "-m", "test/jdk.test.Main")
148                 .outputTo(System.out)
149                 .errorTo(System.out)
150                 // error output by VM
151                 .shouldContain("Cannot specify a module more than once to --patch-module: java.logging")
152                 .getExitValue();
153 
154         assertTrue(exitValue != 0);
155     }
156 
157     @DataProvider(name = "emptyItem")
158     public Object[][] emptyItems() {
159         String patch1 = PATCHES1_DIR.resolve("java.base").toString();
160         String patch2 = PATCHES2_DIR.resolve("java.base").toString();
161         String pathSep = File.pathSeparator;
162         return new Object[][]{
163 
164             { "java.base="+ pathSep + patch1 + pathSep + patch2,            null },
165             { "java.base="+ patch1 + pathSep + pathSep + patch2,            null },
166             { "java.base="+ patch1 + pathSep + patch2 + pathSep + pathSep,  null },
167         };
168     }
169 
170     /**
171      * Empty item in a non-empty path list
172      */
173     @Test(dataProvider = "emptyItem")
174     public void testEmptyItem(String value, String msg) throws Exception {
175         // the argument to the test is the list of classes overridden or added
176         String arg = Stream.of(CLASSES).collect(Collectors.joining(","));
177 
178         int exitValue =
179             executeTestJava("--patch-module", value,
180                             "--add-exports", "java.base/java.lang2=test",
181                             "--module-path", MODS_DIR.toString(),
182                             "-m", "test/jdk.test.Main", arg)
183                 .outputTo(System.out)
184                 .errorTo(System.out)
185                 .getExitValue();
186 
187         assertTrue(exitValue == 0);
188     }
189 
190     /**
191      * Test bad module name that should emit a warning
192      */
193     public void testBadName() throws Exception {
194         // the argument to the test is the list of classes overridden or added
195         String arg = Stream.of(CLASSES).collect(Collectors.joining(","));
196 
197         int exitValue =
198             executeTestJava("--patch-module", "DoesNotExist=tmp",
199                             "--patch-module", "java.base=" + PATCHES_PATH,
200                             "--add-exports", "java.base/java.lang2=test",
201                             "--module-path", MODS_DIR.toString(),
202                             "-m", "test/jdk.test.Main", arg)
203                 .outputTo(System.out)
204                 .errorTo(System.out)
205                 .shouldContain("WARNING: Unknown module: DoesNotExist specified to --patch-module")
206                 .getExitValue();
207 
208         assertTrue(exitValue == 0);
209     }
210 
211     @DataProvider(name = "badArguments")
212     public Object[][] badArguments() {
213         return new Object[][]{
214 
215             // source not found
216             { "=tmp",            "Unable to parse --patch-module <module>=<value>: =tmp" },
217 
218             // target not found: check by VM
219             { "java.base",       "Missing '=' in --patch-module specification" },
220             { "foo",             "Missing '=' in --patch-module specification" },
221 
222             // target not found
223             { "java.base=",      "Unable to parse --patch-module <module>=<value>: java.base="  },
224             { "java.base=" + File.pathSeparator,
225               "Target must be specified: --patch-module java.base=" + File.pathSeparator }
226         };
227     }
228 
229     /**
230      * Test ill-formed argument to --patch-module
231      */
232     @Test(dataProvider = "badArguments")
233     public void testBadArgument(String value, String msg) throws Exception {
234         int exitValue =
235             executeTestJava("--patch-module", value,
236                             "--module-path", MODS_DIR.toString(),
237                             "-m", "test/jdk.test.Main")
238                 .outputTo(System.out)
239                 .errorTo(System.out)
240                 .shouldContain(msg)
241                 .getExitValue();
242 
243         assertTrue(exitValue != 0);
244     }
245 }