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