IncludeExcludePatterns.java revision 3219:aacc4ceb35c9
1/*
2 * Copyright (c) 2014, 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 8037085
27 * @summary Ensures that sjavac can handle various exclusion patterns.
28 *
29 * @modules jdk.compiler/com.sun.tools.sjavac
30 * @library /tools/lib
31 * @build Wrapper ToolBox
32 * @run main Wrapper IncludeExcludePatterns
33 */
34
35import com.sun.tools.javac.util.Assert;
36import com.sun.tools.sjavac.server.Sjavac;
37
38import java.io.File;
39import java.io.IOException;
40import java.nio.file.Files;
41import java.nio.file.Path;
42import java.nio.file.Paths;
43import java.util.Arrays;
44import java.util.Collection;
45import java.util.HashSet;
46import java.util.Set;
47import java.util.stream.Collectors;
48import java.util.stream.Stream;
49
50public class IncludeExcludePatterns extends SjavacBase {
51
52    final Path SRC = Paths.get("src");
53    final Path BIN = Paths.get("bin");
54    final Path STATE_DIR = Paths.get("state-dir");
55
56    // An arbitrarily but sufficiently complicated source tree.
57    final Path A = Paths.get("pkga/A.java");
58    final Path X1 = Paths.get("pkga/subpkg/Xx.java");
59    final Path Y = Paths.get("pkga/subpkg/subsubpkg/Y.java");
60    final Path B = Paths.get("pkgb/B.java");
61    final Path C = Paths.get("pkgc/C.java");
62    final Path X2 = Paths.get("pkgc/Xx.java");
63
64    final Path[] ALL_PATHS = {A, X1, Y, B, C, X2};
65
66    public static void main(String[] ignore) throws Exception {
67        new IncludeExcludePatterns().runTest();
68    }
69
70    public void runTest() throws IOException, ReflectiveOperationException {
71        Files.createDirectories(BIN);
72        Files.createDirectories(STATE_DIR);
73        for (Path p : ALL_PATHS) {
74            writeDummyClass(p);
75        }
76
77        // Single file
78        testPattern("pkga/A.java", A);
79
80        // Leading wild cards
81        testPattern("*/A.java", A);
82        testPattern("**/Xx.java", X1, X2);
83        testPattern("**x.java", X1, X2);
84
85        // Wild card in middle of path
86        testPattern("pkga/*/Xx.java", X1);
87        testPattern("pkga/**/Y.java", Y);
88
89        // Trailing wild cards
90        testPattern("pkga/*", A);
91        testPattern("pkga/**", A, X1, Y);
92
93        // Multiple wildcards
94        testPattern("pkga/*/*/Y.java", Y);
95        testPattern("**/*/**", X1, Y);
96
97    }
98
99    // Given "src/pkg/subpkg/A.java" this method returns "A"
100    String classNameOf(Path javaFile) {
101        return javaFile.getFileName()
102                       .toString()
103                       .replace(".java", "");
104    }
105
106    // Puts an empty (dummy) class definition in the given path.
107    void writeDummyClass(Path javaFile) throws IOException {
108        String pkg = javaFile.getParent().toString().replace(File.separatorChar, '.');
109        String cls = javaFile.getFileName().toString().replace(".java", "");
110        toolbox.writeFile(SRC.resolve(javaFile), "package " + pkg + "; class " + cls + " {}");
111    }
112
113    void testPattern(String filterArgs, Path... sourcesExpectedToBeVisible)
114            throws ReflectiveOperationException, IOException {
115        testFilter("-i " + filterArgs, Arrays.asList(sourcesExpectedToBeVisible));
116
117        Set<Path> complement = new HashSet<>(Arrays.asList(ALL_PATHS));
118        complement.removeAll(Arrays.asList(sourcesExpectedToBeVisible));
119        testFilter("-x " + filterArgs, complement);
120    }
121
122    void testFilter(String filterArgs, Collection<Path> sourcesExpectedToBeVisible)
123            throws IOException, ReflectiveOperationException {
124        System.out.println("Testing filter: " + filterArgs);
125        toolbox.cleanDirectory(BIN);
126        toolbox.cleanDirectory(STATE_DIR);
127        String args = filterArgs + " " + SRC
128                + " -d " + BIN
129                + " --state-dir=" + STATE_DIR;
130        int rc = compile((Object[]) args.split(" "));
131
132        // Compilation should always pass in these tests
133        Assert.check(rc == Sjavac.RC_OK, "Compilation failed unexpectedly.");
134
135        // The resulting .class files should correspond to the visible source files
136        Set<Path> result = allFilesInDir(BIN);
137        Set<Path> expected = correspondingClassFiles(sourcesExpectedToBeVisible);
138        if (!result.equals(expected)) {
139            System.out.println("Result:");
140            printPaths(result);
141            System.out.println("Expected:");
142            printPaths(expected);
143            Assert.error("Test case failed: " + filterArgs);
144        }
145    }
146
147    void printPaths(Collection<Path> paths) {
148        paths.stream()
149             .sorted()
150             .forEachOrdered(p -> System.out.println("    " + p));
151    }
152
153    // Given "pkg/A.java, pkg/B.java" this method returns "bin/pkg/A.class, bin/pkg/B.class"
154    Set<Path> correspondingClassFiles(Collection<Path> javaFiles) {
155        return javaFiles.stream()
156                        .map(javaFile -> javaFile.resolveSibling(classNameOf(javaFile) + ".class"))
157                        .map(BIN::resolve)
158                        .collect(Collectors.toSet());
159    }
160
161    Set<Path> allFilesInDir(Path p) throws IOException {
162        try (Stream<Path> files = Files.walk(p).filter(Files::isRegularFile)) {
163            return files.collect(Collectors.toSet());
164        }
165    }
166}
167