1 /*
   2  * Copyright (c) 2016, 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 8165944
  27  * @summary test several jar tool input file scenarios with variations on -C
  28  *          options with/without a --release option.  Some input files are
  29  *          duplicates that sometimes cause exceptions and other times do not,
  30  *          demonstrating identical behavior to JDK 8 jar tool.
  31  * @library /lib/testlibrary
  32  * @modules jdk.jartool
  33  * @build jdk.testlibrary.FileUtils
  34  * @run testng InputFilesTest
  35  */
  36 
  37 import org.testng.Assert;
  38 import org.testng.annotations.AfterMethod;
  39 import org.testng.annotations.BeforeMethod;
  40 import org.testng.annotations.Test;
  41 
  42 import java.io.ByteArrayOutputStream;
  43 import java.io.IOException;
  44 import java.io.PrintStream;
  45 import java.io.UncheckedIOException;
  46 import java.nio.file.Files;
  47 import java.nio.file.Path;
  48 import java.nio.file.Paths;
  49 import java.util.Arrays;
  50 import java.util.spi.ToolProvider;
  51 import java.util.stream.Stream;
  52 import java.util.zip.ZipException;
  53 
  54 import jdk.testlibrary.FileUtils;
  55 
  56 public class InputFilesTest {
  57     private static final ToolProvider JAR_TOOL =
  58         ToolProvider.findFirst("jar").get();
  59 
  60     private final String nl = System.lineSeparator();
  61     private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
  62     private final PrintStream out = new PrintStream(baos);
  63     private Runnable onCompletion;
  64 
  65     @BeforeMethod
  66     public void reset() {
  67         onCompletion = null;
  68     }
  69 
  70     @AfterMethod
  71     public void run() {
  72         if (onCompletion != null) {
  73             onCompletion.run();
  74         }
  75     }
  76 
  77     @Test
  78     public void test1() throws IOException {
  79         mkdir("test1 test2");
  80         touch("test1/testfile1 test2/testfile2");
  81         jar("cf test.jar -C test1 . -C test2 .");
  82         jar("tf test.jar");
  83         println();
  84         String output = "META-INF/" + nl +
  85                 "META-INF/MANIFEST.MF" + nl +
  86                 "testfile1" + nl +
  87                 "testfile2" + nl;
  88         rm("test.jar test1 test2");
  89         Assert.assertEquals(baos.toByteArray(), output.getBytes());
  90     }
  91 
  92     @Test
  93     public void test2() throws IOException {
  94         mkdir("test1 test2 test3 test4");
  95         touch("test1/testfile1 test2/testfile2 test3/testfile3 test4/testfile4");
  96         jar("cf test.jar -C test1 . -C test2 . --release 9 -C test3 . -C test4 .");
  97         jar("tf test.jar");
  98         println();
  99         String output = "META-INF/" + nl +
 100                 "META-INF/MANIFEST.MF" + nl +
 101                 "testfile1" + nl +
 102                 "testfile2" + nl +
 103                 "META-INF/versions/9/testfile3" + nl +
 104                 "META-INF/versions/9/testfile4" + nl;
 105         rm("test.jar test1 test2 test3 test4");
 106         Assert.assertEquals(baos.toByteArray(), output.getBytes());
 107     }
 108 
 109     @Test
 110     public void test3() throws IOException {
 111         touch("test");
 112         jar("cf test.jar test test");
 113         jar("tf test.jar");
 114         println();
 115         String output = "META-INF/" + nl +
 116                 "META-INF/MANIFEST.MF" + nl +
 117                 "test" + nl;
 118         rm("test.jar test");
 119         Assert.assertEquals(baos.toByteArray(), output.getBytes());
 120     }
 121 
 122     @Test
 123     public void test4() throws IOException {
 124         mkdir("a");
 125         touch("a/test");
 126         jar("cf test.jar -C a test -C a test");
 127         jar("tf test.jar");
 128         println();
 129         String output = "META-INF/" + nl +
 130                 "META-INF/MANIFEST.MF" + nl +
 131                 "test" + nl;
 132         rm("test.jar a");
 133         Assert.assertEquals(baos.toByteArray(), output.getBytes());
 134     }
 135 
 136     @Test(expectedExceptions = {ZipException.class})
 137     public void test5() throws IOException {
 138         mkdir("a");
 139         touch("test a/test");
 140         onCompletion = () -> rm("test a");
 141         jar("cf test.jar -C a test test");
 142     }
 143 
 144     @Test(expectedExceptions = {ZipException.class})
 145     public void test6() throws IOException {
 146         mkdir("test1 test2");
 147         touch("test1/a test2/a");
 148         onCompletion = () -> rm("test1 test2");
 149         jar("cf test.jar --release 9 -C test1 a -C test2 a");
 150     }
 151 
 152     private Stream<Path> mkpath(String... args) {
 153         return Arrays.stream(args).map(d -> Paths.get(".", d.split("/")));
 154     }
 155 
 156     private void mkdir(String cmdline) {
 157         System.out.println("mkdir -p " + cmdline);
 158         mkpath(cmdline.split(" +")).forEach(p -> {
 159             try {
 160                 Files.createDirectories(p);
 161             } catch (IOException x) {
 162                 throw new UncheckedIOException(x);
 163             }
 164         });
 165     }
 166 
 167     private void touch(String cmdline) {
 168         System.out.println("touch " + cmdline);
 169         mkpath(cmdline.split(" +")).forEach(p -> {
 170             try {
 171                 Files.createFile(p);
 172             } catch (IOException x) {
 173                 throw new UncheckedIOException(x);
 174             }
 175         });
 176     }
 177 
 178     private void rm(String cmdline) {
 179         System.out.println("rm -rf " + cmdline);
 180         mkpath(cmdline.split(" +")).forEach(p -> {
 181             try {
 182                 if (Files.isDirectory(p)) {
 183                     FileUtils.deleteFileTreeWithRetry(p);
 184                 } else {
 185                     FileUtils.deleteFileIfExistsWithRetry(p);
 186                 }
 187             } catch (IOException x) {
 188                 throw new UncheckedIOException(x);
 189             }
 190         });
 191     }
 192 
 193     private void jar(String cmdline) throws IOException {
 194         System.out.println("jar " + cmdline);
 195         baos.reset();
 196 
 197         // the run method catches IOExceptions, we need to expose them
 198         ByteArrayOutputStream baes = new ByteArrayOutputStream();
 199         PrintStream err = new PrintStream(baes);
 200         PrintStream saveErr = System.err;
 201         System.setErr(err);
 202         int rc = JAR_TOOL.run(out, err, cmdline.split(" +"));
 203         System.setErr(saveErr);
 204         if (rc != 0) {
 205             String s = baes.toString();
 206             if (s.startsWith("java.util.zip.ZipException: duplicate entry: ")) {
 207                 throw new ZipException(s);
 208             }
 209             throw new IOException(s);
 210         }
 211     }
 212 
 213     private void println() throws IOException {
 214         System.out.println(new String(baos.toByteArray()));
 215     }
 216 }