1 /*
   2  * Copyright (c) 2010, 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 6948144
  27  * @summary jpkg throws NPE if input directory does not exist
  28  */
  29 
  30 import java.io.*;
  31 import java.security.*;
  32 import java.util.*;
  33 import org.openjdk.jigsaw.*;
  34 import org.openjdk.jigsaw.cli.*;
  35 
  36 public class JpkgArgsTest {
  37     final String MNAME = "hello";
  38     final String MVER = "0.1";
  39     String moduleinfo = "module " + MNAME + " @ " + MVER + " {}";
  40 
  41     public static void main(String[] args) throws Exception {
  42         new JpkgArgsTest().run();
  43     }
  44 
  45     private void run() throws Exception {
  46         try {
  47             test();
  48         } catch (Throwable t) {
  49             t.printStackTrace();
  50             errors++;
  51         }
  52 
  53 
  54         if (errors == 0)
  55             System.out.println(count + " tests passed");
  56         else
  57             throw new Exception(errors + "/" + count + " tests failed");
  58     }
  59 
  60     private void setUp(String name) throws IOException {
  61         System.err.println("Test: " + name);
  62         count++;
  63         reset();
  64         List<File> files = new ArrayList<File>();
  65         addFile(files, createFile("module-info.java", moduleinfo));
  66         compile(files);
  67     }
  68 
  69     private void testIfFileArgExists(boolean natlib,
  70                                      boolean natcmd, boolean config)
  71         throws Exception {
  72         setUp("NPE if file argument does not exist: "
  73               + (natlib? " --natlib " : "")
  74               + (natcmd? " --natcmd " : "")
  75               + (config? " --config" : ""));
  76 
  77         try {
  78             compress(natlib, natcmd, config);
  79         }
  80         // The bug resulted in a NPE being thrown
  81         catch (NullPointerException e) {
  82             // Rethrow the NPE if it ever occurs again.
  83             throw (Exception) new Exception().initCause(e);
  84         }
  85         // Technically, we want to catch Command.Exception here,
  86         // but it's package private, so let's catch the next best thing.
  87         catch (Exception e) {
  88             // yay! test passed.
  89         }
  90     }
  91 
  92     private void testIfFileArgIsNotADirectory(boolean natlib,
  93                                               boolean natcmd, boolean config)
  94         throws Exception {
  95         setUp("NPE if file argument is not a directory: "
  96               + (natlib? " --natlib " : "")
  97               + (natcmd? " --natcmd " : "")
  98               + (config? " --config" : ""));
  99 
 100         // Create files rather then directories to get the exception
 101         natlibDir.createNewFile();
 102         natcmdDir.createNewFile();
 103         configDir.createNewFile();
 104 
 105         try {
 106             compress(natlib, natcmd, config);
 107         }
 108         // The bug resulted in a NPE being thrown
 109         catch (NullPointerException e) {
 110             // Rethrow the NPE if it ever occurs again.
 111             throw (Exception) new Exception().initCause(e);
 112         }
 113         // Technically, we want to catch Command.Exception here,
 114         // but it's package private, so let's catch the next best thing.
 115         catch (Exception e) {
 116             // yay! test passed.
 117         }
 118     }
 119 
 120     private void testIfFileArgIsNotReadable(boolean natlib,
 121                                             boolean natcmd, boolean config)
 122         throws Exception {
 123         // File readability cannot be set to false in Windows
 124         if (System.getProperty("os.name").startsWith("Windows")) {
 125             return;
 126         }
 127 
 128         setUp("NPE if file argument is not readable: "
 129               + (natlib? " --natlib " : "")
 130               + (natcmd? " --natcmd " : "")
 131               + (config? " --config" : ""));
 132 
 133         // Create directories and mark then non-readable to get the exception
 134         if (! (natlibDir.mkdir() && natlibDir.setReadable(false) &&
 135                natcmdDir.mkdir() && natcmdDir.setReadable(false) &&
 136                configDir.mkdir() && configDir.setReadable(false)))
 137             throw new Exception("Can't set up test");
 138 
 139         try {
 140             compress(natlib, natcmd, config);
 141         }
 142         // The bug resulted in a NPE being thrown
 143         catch (NullPointerException e) {
 144             // Rethrow the NPE if it ever occurs again.
 145             throw (Exception) new Exception().initCause(e);
 146         }
 147         // Technically, we want to catch Command.Exception here,
 148         // but it's package private, so let's catch the next best thing.
 149         catch (Exception e) {
 150             // yay! test passed.
 151         }
 152         finally {
 153             natlibDir.setReadable(true);
 154             natcmdDir.setReadable(true);
 155             configDir.setReadable(true);
 156         }
 157     }
 158 
 159     private void testIfFileArgIsEmpty(boolean natlib,
 160                                       boolean natcmd, boolean config)
 161         throws Exception {
 162         setUp("IOException if file argument is an empty directory: "
 163               + (natlib? " --natlib " : "")
 164               + (natcmd? " --natcmd " : "")
 165               + (config? " --config" : ""));
 166 
 167         // Create empty directories for jpkg to ignore
 168         if (! (natlibDir.mkdir() && natcmdDir.mkdir() && configDir.mkdir()))
 169             throw new Exception("Can't set up test");
 170 
 171         compress(natlib, natcmd, config);
 172     }
 173 
 174     private void testIfModulePathArgIsNotADirectory()
 175         throws Exception {
 176         setUp("Check if module path argument is not a directory");
 177 
 178         File aFile = new File(testDir, "aFile");
 179         aFile.createNewFile();
 180         try {
 181             String [] args = {"-m", aFile.toString(), "jmod", "hello"};
 182             Packager.run(args);
 183         }
 184         // The bug resulted in a NPE being thrown
 185         catch (NullPointerException e) {
 186             // Rethrow the NPE if it ever occurs again.
 187             throw (Exception) new Exception().initCause(e);
 188         }
 189         // Technically, we want to catch Command.Exception here,
 190         // but it's package private, so let's catch the next best thing.
 191         catch (Exception e) {
 192             // yay! test passed.
 193             return;
 194         }
 195         finally {
 196             aFile.delete();
 197         }
 198         throw new Exception("Should have caught an exception");
 199     }
 200 
 201     private void testIfModulePathArgExists()
 202         throws Exception {
 203         setUp("Check if module path argument exists");
 204 
 205         try {
 206             String [] args = {"-m", "no such path", "jmod", "hello"};
 207             Packager.run(args);
 208         }
 209         // The bug resulted in a NPE being thrown
 210         catch (NullPointerException e) {
 211             // Rethrow the NPE if it ever occurs again.
 212             throw (Exception) new Exception().initCause(e);
 213         }
 214         // Technically, we want to catch Command.Exception here,
 215         // but it's package private, so let's catch the next best thing.
 216         catch (Exception e) {
 217             // yay! test passed.
 218             return;
 219         }
 220         throw new Exception("Should have caught an exception");
 221     }
 222 
 223     private void testIfModulePathArgIsNotReadable()
 224         throws Exception {
 225         // File readability cannot be set to false in Windows
 226         if (System.getProperty("os.name").startsWith("Windows")) {
 227             return;
 228         }
 229         setUp("Check if module path argument is not readable");
 230 
 231         File dir = new File(testDir, "notReadableDir");
 232         if (! (dir.mkdir() && dir.setReadable(false)))
 233             throw new Exception("Can't set up test");
 234         try {
 235             String [] args = {"-m", dir.toString(), "jmod", "hello"};
 236             Packager.run(args);
 237         }
 238         // The bug resulted in a NPE being thrown
 239         catch (NullPointerException e) {
 240             // Rethrow the NPE if it ever occurs again.
 241             throw (Exception) new Exception().initCause(e);
 242         }
 243         // Technically, we want to catch Command.Exception here,
 244         // but it's package private, so let's catch the next best thing.
 245         catch (Exception e) {
 246             // yay! test passed.
 247             return;
 248         }
 249         finally {
 250             dir.setReadable(true);
 251             dir.delete();
 252         }
 253         throw new Exception("Should have caught an exception");
 254     }
 255 
 256     private void testAbsolutePathArg()
 257         throws Exception {
 258         setUp("Check if absolute module path argument is accepted");
 259 
 260         File testfile = new File(classesDir, "test");
 261         try {
 262             testfile.createNewFile();
 263             String [] args = {"-m", classesDir.getAbsolutePath(),
 264                               "jmod", "hello"};
 265             Packager.run(args);
 266         }
 267         // The bug resulted in an exception being thrown
 268         catch (Exception e) {
 269             // Rethrow the exception if it ever occurs again.
 270             throw (Exception) new Exception().initCause(e);
 271         }
 272         finally {
 273             testfile.delete();
 274         }
 275     }
 276 
 277     private void testModulePathArg() throws Exception {
 278         testIfModulePathArgExists();
 279         testIfModulePathArgIsNotADirectory();
 280         testIfModulePathArgIsNotReadable();
 281     }
 282 
 283     private void test() throws Exception {
 284         testModulePathArg();
 285         testAbsolutePathArg();
 286         boolean a, b, c, d;
 287         for (boolean aloop = a = false; !aloop; a = true) {
 288             aloop = a;
 289             for (boolean bloop = b = false; !bloop; b = true) {
 290                 bloop = b;
 291                 for (boolean cloop = c = false; !cloop; c = true) {
 292                     cloop = c;
 293                     testIfFileArgExists(a, b, c);
 294                     testIfFileArgIsNotADirectory(a, b, c);
 295                     testIfFileArgIsNotReadable(a, b, c);
 296                     testIfFileArgIsEmpty(a, b, c);
 297                 }
 298             }
 299         }
 300     }
 301 
 302     /**
 303      * Compress a module.
 304      */
 305     private void compress() throws Exception {
 306         compress(false);
 307     }
 308 
 309     private void compress(boolean haveNatLibs)
 310         throws Exception {
 311         compress(haveNatLibs, false);
 312     }
 313 
 314     private void compress(boolean haveNatLibs,
 315                           boolean haveNatCmds) throws Exception {
 316         compress(haveNatLibs, haveNatCmds, false);
 317     }
 318 
 319     private void compress(boolean haveNatLibs,
 320                           boolean haveNatCmds, boolean haveConfig)
 321         throws Exception {
 322         List<String> args = new ArrayList<String>();
 323         args.add("-m");
 324         args.add(classesDir.getAbsolutePath());
 325         args.add("-d");
 326         args.add(moduleDir.getAbsolutePath());
 327         if (haveNatLibs) {
 328             args.add("--natlib");
 329             args.add(natlibDir.toString());
 330         }
 331         if (haveNatCmds) {
 332             args.add("--natcmd");
 333             args.add(natcmdDir.toString());
 334         }
 335         if (haveConfig) {
 336             args.add("--config");
 337             args.add(configDir.toString());
 338         }
 339         args.add("jmod");
 340         args.add("hello");
 341         Packager.run(args.toArray(new String[0]));
 342     }
 343 
 344     /**
 345      * Compile a list of files.
 346      */
 347     private void compile(List<File> files) {
 348         List<String> options = new ArrayList<String>();
 349         options.addAll(Arrays.asList("-source", "8", "-d", classesDir.getPath()));
 350         for (File f: files)
 351             options.add(f.getPath());
 352 
 353         String[] opts = options.toArray(new String[options.size()]);
 354         StringWriter sw = new StringWriter();
 355         PrintWriter pw = new PrintWriter(sw);
 356         int rc = com.sun.tools.javac.Main.compile(opts, pw);
 357         pw.close();
 358 
 359         String out = sw.toString();
 360         if (out.trim().length() > 0)
 361             System.err.println(out);
 362         if (rc != 0)
 363             throw new Error("compilation failed: rc=" + rc);
 364     }
 365 
 366     /**
 367      * Add a file to a list if the file is not null.
 368      */
 369     private void addFile(List<File> files, File file) {
 370         if (file != null)
 371             files.add(file);
 372     }
 373 
 374 
 375     /**
 376      * Create a test file with given content if the content is not null.
 377      */
 378     private File createFile(String path, String body) throws IOException {
 379         if (body == null)
 380             return null;
 381         File file = new File(srcDir, path);
 382         file.getAbsoluteFile().getParentFile().mkdirs();
 383         FileWriter out = new FileWriter(file);
 384         out.write(body);
 385         out.close();
 386         return file;
 387     }
 388 
 389     /**
 390      * Set up empty src and classes directories for a test.
 391      */
 392     private void reset() {
 393         resetDir(srcDir);
 394         resetDir(classesDir);
 395         resetDir(moduleDir);
 396         resetDir(new File(MNAME));
 397     }
 398 
 399     /**
 400      * Set up an empty directory.
 401      */
 402     private void resetDir(File dir) {
 403         if (dir.exists())
 404             deleteAll(dir);
 405         dir.mkdirs();
 406     }
 407 
 408     /**
 409      * Delete a file or a directory (including all its contents).
 410      */
 411     private boolean deleteAll(File file) {
 412         if (file.isDirectory()) {
 413             for (File f: file.listFiles())
 414                 deleteAll(f);
 415         }
 416         return file.delete();
 417     }
 418 
 419     /**
 420      * Report an error.
 421      */
 422     private void error(String msg, String... more) {
 423         System.err.println("error: " + msg);
 424         for (String s: more)
 425             System.err.println(s);
 426         errors++;
 427     }
 428 
 429     private int count;
 430     private int errors;
 431     private File testDir = new File(System.getProperty("test.dir", "tmp"));
 432     private File srcDir = new File(testDir, "src");
 433     private File classesDir = new File(testDir, "classes");
 434     private File moduleDir = new File(testDir, "modules");
 435     private File natlibDir = new File(srcDir, "natlib");
 436     private File natcmdDir = new File(srcDir, "natcmd");
 437     private File configDir = new File(srcDir, "config");
 438 }