1 /*
   2  * Copyright (c) 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package jdk.incubator.jpackage.internal;
  26 
  27 import java.io.IOException;
  28 import java.nio.file.Files;
  29 import java.nio.file.Path;
  30 import java.util.*;
  31 import java.util.function.Consumer;
  32 import java.util.function.Predicate;
  33 import java.util.function.UnaryOperator;
  34 import java.util.stream.Collectors;
  35 import java.util.stream.Stream;
  36 import static org.hamcrest.CoreMatchers.equalTo;
  37 import static org.hamcrest.CoreMatchers.not;
  38 import static org.junit.Assert.*;
  39 import org.junit.Rule;
  40 import org.junit.Test;
  41 import org.junit.rules.TemporaryFolder;
  42 
  43 
  44 public class PathGroupTest {
  45 
  46     @Rule
  47     public final TemporaryFolder tempFolder = new TemporaryFolder();
  48 
  49     @Test(expected = NullPointerException.class)
  50     public void testNullId() {
  51          new PathGroup(Map.of()).getPath(null);
  52     }
  53 
  54     @Test
  55     public void testEmptyPathGroup() {
  56         PathGroup pg = new PathGroup(Map.of());
  57 
  58         assertNull(pg.getPath("foo"));
  59 
  60         assertEquals(0, pg.paths().size());
  61         assertEquals(0, pg.roots().size());
  62     }
  63 
  64     @Test
  65     public void testRootsSinglePath() {
  66         final PathGroup pg = new PathGroup(Map.of("main", PATH_FOO));
  67 
  68         List<Path> paths = pg.paths();
  69         assertEquals(1, paths.size());
  70         assertEquals(PATH_FOO, paths.iterator().next());
  71 
  72         List<Path> roots = pg.roots();
  73         assertEquals(1, roots.size());
  74         assertEquals(PATH_FOO, roots.iterator().next());
  75     }
  76 
  77     @Test
  78     public void testDuplicatedRoots() {
  79         final PathGroup pg = new PathGroup(Map.of("main", PATH_FOO, "another",
  80                 PATH_FOO, "root", PATH_EMPTY));
  81 
  82         List<Path> paths = pg.paths();
  83         Collections.sort(paths);
  84 
  85         assertEquals(3, paths.size());
  86         assertEquals(PATH_EMPTY, paths.get(0));
  87         assertEquals(PATH_FOO, paths.get(1));
  88         assertEquals(PATH_FOO, paths.get(2));
  89 
  90         List<Path> roots = pg.roots();
  91         assertEquals(1, roots.size());
  92         assertEquals(PATH_EMPTY, roots.get(0));
  93     }
  94 
  95     @Test
  96     public void testRoots() {
  97         final PathGroup pg = new PathGroup(Map.of(1, Path.of("foo"), 2, Path.of(
  98                 "foo", "bar"), 3, Path.of("foo", "bar", "buz")));
  99 
 100         List<Path> paths = pg.paths();
 101         assertEquals(3, paths.size());
 102         assertTrue(paths.contains(Path.of("foo")));
 103         assertTrue(paths.contains(Path.of("foo", "bar")));
 104         assertTrue(paths.contains(Path.of("foo", "bar", "buz")));
 105 
 106         List<Path> roots = pg.roots();
 107         assertEquals(1, roots.size());
 108         assertEquals(Path.of("foo"), roots.get(0));
 109     }
 110 
 111     @Test
 112     public void testResolveAt() {
 113         final PathGroup pg = new PathGroup(Map.of(0, PATH_FOO, 1, PATH_BAR, 2,
 114                 PATH_EMPTY));
 115 
 116         final Path aPath = Path.of("a");
 117 
 118         final PathGroup pg2 = pg.resolveAt(aPath);
 119         assertThat(pg, not(equalTo(pg2)));
 120 
 121         List<Path> paths = pg.paths();
 122         assertEquals(3, paths.size());
 123         assertTrue(paths.contains(PATH_EMPTY));
 124         assertTrue(paths.contains(PATH_FOO));
 125         assertTrue(paths.contains(PATH_BAR));
 126         assertEquals(PATH_EMPTY, pg.roots().get(0));
 127 
 128         paths = pg2.paths();
 129         assertEquals(3, paths.size());
 130         assertTrue(paths.contains(aPath.resolve(PATH_EMPTY)));
 131         assertTrue(paths.contains(aPath.resolve(PATH_FOO)));
 132         assertTrue(paths.contains(aPath.resolve(PATH_BAR)));
 133         assertEquals(aPath, pg2.roots().get(0));
 134     }
 135 
 136     @Test
 137     public void testTransform() throws IOException {
 138         for (var transform : TransformType.values()) {
 139             testTransform(false, transform);
 140         }
 141     }
 142 
 143     @Test
 144     public void testTransformWithExcludes() throws IOException {
 145         for (var transform : TransformType.values()) {
 146             testTransform(true, transform);
 147         }
 148     }
 149 
 150     enum TransformType { Copy, Move, Handler };
 151 
 152     private void testTransform(boolean withExcludes, TransformType transform)
 153             throws IOException {
 154         final PathGroup pg = new PathGroup(Map.of(0, PATH_FOO, 1, PATH_BAR, 2,
 155                 PATH_EMPTY, 3, PATH_BAZ));
 156 
 157         final Path srcDir = tempFolder.newFolder().toPath();
 158         final Path dstDir = tempFolder.newFolder().toPath();
 159 
 160         Files.createDirectories(srcDir.resolve(PATH_FOO).resolve("a/b/c/d"));
 161         Files.createFile(srcDir.resolve(PATH_FOO).resolve("a/b/c/file1"));
 162         Files.createFile(srcDir.resolve(PATH_FOO).resolve("a/b/file2"));
 163         Files.createFile(srcDir.resolve(PATH_FOO).resolve("a/b/file3"));
 164         Files.createFile(srcDir.resolve(PATH_BAR));
 165         Files.createFile(srcDir.resolve(PATH_EMPTY).resolve("file4"));
 166         Files.createDirectories(srcDir.resolve(PATH_BAZ).resolve("1/2/3"));
 167 
 168         var dst = pg.resolveAt(dstDir);
 169         var src = pg.resolveAt(srcDir);
 170         if (withExcludes) {
 171             // Exclude from transformation.
 172             src.setPath(new Object(), srcDir.resolve(PATH_FOO).resolve("a/b/c"));
 173             src.setPath(new Object(), srcDir.resolve(PATH_EMPTY).resolve("file4"));
 174         }
 175 
 176         var srcFilesBeforeTransform = walkFiles(srcDir);
 177 
 178         if (transform == TransformType.Handler) {
 179             List<Map.Entry<Path, Path>> copyFile = new ArrayList<>();
 180             List<Path> createDirectory = new ArrayList<>();
 181             src.transform(dst, new PathGroup.TransformHandler() {
 182                 @Override
 183                 public void copyFile(Path src, Path dst) throws IOException {
 184                     copyFile.add(Map.entry(src, dst));
 185                 }
 186 
 187                 @Override
 188                 public void createDirectory(Path dir) throws IOException {
 189                     createDirectory.add(dir);
 190                 }
 191             });
 192 
 193             Consumer<Path> assertFile = path -> {
 194                 var entry = Map.entry(srcDir.resolve(path), dstDir.resolve(path));
 195                 assertTrue(copyFile.contains(entry));
 196             };
 197 
 198             Consumer<Path> assertDir = path -> {
 199                 assertTrue(createDirectory.contains(dstDir.resolve(path)));
 200             };
 201 
 202             assertEquals(withExcludes ? 3 : 5, copyFile.size());
 203             assertEquals(withExcludes ? 8 : 10, createDirectory.size());
 204 
 205             assertFile.accept(PATH_FOO.resolve("a/b/file2"));
 206             assertFile.accept(PATH_FOO.resolve("a/b/file3"));
 207             assertFile.accept(PATH_BAR);
 208             assertDir.accept(PATH_FOO.resolve("a/b"));
 209             assertDir.accept(PATH_FOO.resolve("a"));
 210             assertDir.accept(PATH_FOO);
 211             assertDir.accept(PATH_BAZ);
 212             assertDir.accept(PATH_BAZ.resolve("1"));
 213             assertDir.accept(PATH_BAZ.resolve("1/2"));
 214             assertDir.accept(PATH_BAZ.resolve("1/2/3"));
 215             assertDir.accept(PATH_EMPTY);
 216 
 217             if (!withExcludes) {
 218                 assertFile.accept(PATH_FOO.resolve("a/b/c/file1"));
 219                 assertFile.accept(PATH_EMPTY.resolve("file4"));
 220                 assertDir.accept(PATH_FOO.resolve("a/b/c/d"));
 221                 assertDir.accept(PATH_FOO.resolve("a/b/c"));
 222             }
 223 
 224             assertArrayEquals(new Path[] { Path.of("") }, walkFiles(dstDir));
 225             return;
 226         }
 227 
 228         if (transform == TransformType.Copy) {
 229             src.copy(dst);
 230         } else if (transform == TransformType.Move) {
 231             src.move(dst);
 232         }
 233 
 234         final List<Path> excludedPaths;
 235         if (withExcludes) {
 236             excludedPaths = List.of(
 237                 PATH_EMPTY.resolve("file4"),
 238                 PATH_FOO.resolve("a/b/c")
 239             );
 240         } else {
 241             excludedPaths = Collections.emptyList();
 242         }
 243         UnaryOperator<Path[]> removeExcludes = paths -> {
 244             return Stream.of(paths)
 245                     .filter(path -> !excludedPaths.stream().anyMatch(
 246                             path::startsWith))
 247                     .collect(Collectors.toList()).toArray(Path[]::new);
 248         };
 249 
 250         var dstFiles = walkFiles(dstDir);
 251         assertArrayEquals(removeExcludes.apply(srcFilesBeforeTransform), dstFiles);
 252 
 253         if (transform == TransformType.Copy) {
 254             assertArrayEquals(dstFiles, removeExcludes.apply(walkFiles(srcDir)));
 255         } else if (transform == TransformType.Move) {
 256             assertFalse(Files.exists(srcDir));
 257         }
 258     }
 259 
 260     private static Path[] walkFiles(Path root) throws IOException {
 261         try (var files = Files.walk(root)) {
 262             return files.map(root::relativize).sorted().collect(
 263                     Collectors.toList()).toArray(Path[]::new);
 264         }
 265     }
 266 
 267     private final static Path PATH_FOO = Path.of("foo");
 268     private final static Path PATH_BAR = Path.of("bar");
 269     private final static Path PATH_BAZ = Path.of("baz");
 270     private final static Path PATH_EMPTY = Path.of("");
 271 }