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     @DataProvider(name = "emptyItem")
139     public Object[][] emptyItems() {
140         String patch1 = PATCHES1_DIR.resolve("java.base").toString();
141         String patch2 = PATCHES2_DIR.resolve("java.base").toString();
142         String pathSep = File.pathSeparator;
143         return new Object[][]{
144 
145             { "java.base="+ pathSep + patch1 + pathSep + patch2,            null },
146             { "java.base="+ patch1 + pathSep + pathSep + patch2,            null },
147             { "java.base="+ patch1 + pathSep + patch2 + pathSep + pathSep,  null },
148         };
149     }
150 
151     /**
152      * Empty item in a non-empty path list
153      */
154     @Test(dataProvider = "emptyItem")
155     public void testEmptyItem(String value, String msg) throws Exception {
156         // the argument to the test is the list of classes overridden or added
157         String arg = Stream.of(CLASSES).collect(Collectors.joining(","));
158 
159         int exitValue =
160             executeTestJava("--patch-module", value,
161                             "--add-exports", "java.base/java.lang2=test",
162                             "--module-path", MODS_DIR.toString(),
163                             "-m", "test/jdk.test.Main", arg)
164                 .outputTo(System.out)
165                 .errorTo(System.out)
166                 .getExitValue();
167 
168         assertTrue(exitValue == 0);
169     }
170 
171     /**
172      * Test bad module name that should emit a warning
173      */
174     public void testBadName() 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", "DoesNotExist=tmp",
180                             "--patch-module", "java.base=" + PATCHES_PATH,
181                             "--add-exports", "java.base/java.lang2=test",
182                             "--module-path", MODS_DIR.toString(),
183                             "-m", "test/jdk.test.Main", arg)
184                 .outputTo(System.out)
185                 .errorTo(System.out)
186                 .shouldContain("WARNING: Unknown module: DoesNotExist specified to --patch-module")
187                 .getExitValue();
188 
189         assertTrue(exitValue == 0);
190     }
191 
192     @DataProvider(name = "badArguments")
193     public Object[][] badArguments() {
194         return new Object[][]{
195 
196             // source not found
197             { "=tmp",            "Unable to parse --patch-module <module>=<value>: =tmp" },
198 
199             // target not found: check by VM
200             { "java.base",       "Missing '=' in --patch-module specification" },
201             { "foo",             "Missing '=' in --patch-module specification" },
202 
203             // target not found
204             { "java.base=",      "Unable to parse --patch-module <module>=<value>: java.base="  },
205             { "java.base=" + File.pathSeparator,
206               "Target must be specified: --patch-module java.base=" + File.pathSeparator }
207         };
208     }
209 
210     /**
211      * Test ill-formed argument to --patch-module
212      */
213     @Test(dataProvider = "badArguments")
214     public void testBadArgument(String value, String msg) throws Exception {
215         int exitValue =
216             executeTestJava("--patch-module", value,
217                             "--module-path", MODS_DIR.toString(),
218                             "-m", "test/jdk.test.Main")
219                 .outputTo(System.out)
220                 .errorTo(System.out)
221                 .shouldContain(msg)
222                 .getExitValue();
223 
224         assertTrue(exitValue != 0);
225     }
226 }